fix(copilot): a model value must start with a letter or digit

Like resumeSessionId, model follows a flag, so --model --yolo made --yolo its own flag and bypassed the allowAll clamp. New model-plain token pattern, the same rule in the create schema, and golden and schema tests.
This commit is contained in:
Devvyn committed 2026-10-18 00:47:54 +08:00
1 parent 68af012845
commit 6cca5465a9
5 files changed
+45 -2

No files matched your search

+4
View File
@@ -20,6 +20,7 @@
export type TokenPattern =
| 'model'
| 'model-claude'
| 'model-plain'
| 'model-pi'
| 'id'
| 'id-dotted'
@@ -43,6 +44,9 @@ const PATTERNS: Record<TokenPattern, RegExp> = {
model: /^[a-zA-Z0-9._\-/]+$/,
// buildSpawnCommand's claude branch — `[` and `]` for bracketed model aliases
'model-claude': /^[a-zA-Z0-9._\-[\]]+$/,
// copilot --model. Same characters as `model`, but a leading alphanumeric: the value follows a
// flag, so `--yolo` must not pass as a model id and become its own flag (the allowAll clamp bypass).
'model-plain': /^[a-zA-Z0-9][a-zA-Z0-9._\-/]*$/,
// buildPiCommand — `:` for a thinking suffix (`sonnet:high`), `/` for `provider/id`
'model-pi': /^[a-zA-Z0-9._\-/:]+$/,
// opencode --session, codex resume
+2 -1
View File
@@ -1691,7 +1691,8 @@ const COPILOT: CliEntry = {
launch: {
params: {
allowAll: { type: 'bool' },
model: { type: 'token', pattern: 'model' },
// `model-plain`, not `model`: the leading alphanumeric keeps a flag-shaped value out.
model: { type: 'token', pattern: 'model-plain' },
// `path-segment`, not `id-dotted`: the leading alphanumeric keeps a flag-shaped value out.
resumeId: { type: 'token', pattern: 'path-segment' },
continueSession: { type: 'bool' },
+3 -1
View File
@@ -441,10 +441,12 @@ const GrokConfigSchema = z
const CopilotConfigSchema = z
.object({
// A leading alphanumeric, like resumeSessionId below: a value like `--yolo` would otherwise be read
// as its own flag after `--model` (bypassing the allowAll clamp). `/` stays for provider/id.
model: z
.string()
.max(100)
.regex(/^[a-zA-Z0-9._\-/]+$/)
.regex(/^[a-zA-Z0-9][a-zA-Z0-9._\-/]*$/)
.optional(),
allowAll: z.boolean().optional(),
continueSession: z.boolean().optional(),