@aibridge/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,7 +28,7 @@ npx skills add ycmjason/aibridge
28
28
  That's it. The skill runs the CLI on demand via `npx -y @aibridge/cli` — nothing else to install. Ask your agent to "use aibridge", or try it yourself:
29
29
 
30
30
  ```bash
31
- npx -y @aibridge/cli subagent "summarize the architecture of this repo"
31
+ npx -y @aibridge/cli subagent --model xai-grok/grok-4.5 "summarize the architecture of this repo"
32
32
  ```
33
33
 
34
34
  <sup>Want the `aibridge` command on your PATH for manual use? `npm i -g @aibridge/cli` (optional).</sup>
@@ -37,21 +37,21 @@ npx -y @aibridge/cli subagent "summarize the architecture of this repo"
37
37
 
38
38
  | Command | Use when |
39
39
  |---|---|
40
- | `aibridge plan "<task>"` | You want a delegate model to study the repo and expand a task into a detailed, reviewable **plan file** before any code is written |
41
- | `aibridge implement <plan.md>` | You have an approved plan file and want it executed in place — with your project's **real typecheck and tests** run until green |
42
- | `aibridge review [--plan <plan.md>]` | You want a **different model** to pressure-test the working-tree diff against the plan contract (over-reach is a finding) — or to review the plan itself before implementing |
43
- | `aibridge subagent "<task>"` | A self-contained task deserves a concurrent delegate, a cross-model second opinion, or a red-team pass |
44
- | `aibridge image-gen "<prompt>" --out out.png` | You need a real raster image — on a Codex (default), Antigravity, or Grok seat, with render verification |
40
+ | `aibridge plan --model xai-grok/grok-4.5 --out plan.md "<task>"` | You want a delegate model to study the repo and expand a task into a detailed, reviewable **plan file** before any code is written |
41
+ | `aibridge implement --model google-antigravity/gemini-3.6-flash <plan.md>` | You have an approved plan file and want it executed in place — with your project's **real typecheck and tests** run until green |
42
+ | `aibridge review --model xai-grok/grok-4.5 --out review.md [--plan <plan.md>]` | You want a **different model** to pressure-test the working-tree diff against the plan contract (over-reach is a finding) — or to review the plan itself before implementing |
43
+ | `aibridge subagent --model xai-grok/grok-4.5 "<task>"` | A self-contained task deserves a concurrent delegate, a cross-model second opinion, or a red-team pass |
44
+ | `aibridge image-gen --model openai-codex/gpt-5.6-sol --out out.png "<prompt>"` | You need a real raster image — on a Codex, Antigravity, or Grok seat, with render verification |
45
45
  | `aibridge quota` | Two-second check of every backend's remaining quota before you pipeline work |
46
46
  | `aibridge runs` | Inspect or watch past delegation runs (`~/.aibridge/runs`) |
47
47
 
48
48
  The three verbs compose into an orchestrator-driven loop your agent stays in charge of:
49
49
 
50
50
  ```
51
- aibridge plan "add rate limiting to the API" # delegate writes plan.md
51
+ aibridge plan --model xai-grok/grok-4.5 --out plan.md "add rate limiting to the API" # delegate writes plan.md
52
52
  # → your agent reads, edits, approves the plan
53
- aibridge implement plan.md # another model executes it, runs your gates
54
- aibridge review --plan plan.md # a third seat cross-checks the diff
53
+ aibridge implement --model google-antigravity/gemini-3.6-flash plan.md # another model executes it, runs your gates
54
+ aibridge review --model xai-grok/grok-4.5 --out review.md --plan plan.md # a third seat cross-checks the diff
55
55
  ```
56
56
 
57
57
  Plan files — not their contents — travel between stages, so the loop is nearly free on your agent's context.
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as runCli, t as buildContext } from "./context-DQxvMUd2.mjs";
2
+ import { r as runCli, t as buildContext } from "./context-B6I4QI9z.mjs";
3
3
  //#region src/cli.ts
4
4
  await runCli(buildContext(process), process.argv.slice(2));
5
5
  //#endregion
@@ -112,9 +112,6 @@ const MODELS = {
112
112
  brief: "Claude Opus 5, 1M context via claude CLI — long-context work; bills subscription"
113
113
  }
114
114
  };
115
- const DEFAULT_MODEL = "xai-grok/grok-4.5";
116
- const DEFAULT_IMPLEMENTER = "google-antigravity/gemini-3.6-flash";
117
- const DEFAULT_IMAGE_GEN = "openai-codex/gpt-5.6-sol";
118
115
  const IMAGE_GEN_FORMATS = /* @__PURE__ */ new Map([
119
116
  ["agy", "jpg"],
120
117
  ["codex", "png"],
@@ -240,11 +237,11 @@ async function imageGen$1(flags, prompt) {
240
237
  this.process.stderr.write(`aibridge image-gen: ${msg}\n`);
241
238
  this.process.exitCode = 1;
242
239
  };
243
- const inputSlug = flags.model ?? "openai-codex/gpt-5.6-sol";
240
+ const inputSlug = flags.model;
244
241
  const model = resolveModel(inputSlug);
245
242
  if (!model) return fail(formatUnknownModelError(inputSlug));
246
243
  if (!supportsImageGen(model)) return fail(formatImageGenModelError(inputSlug, model));
247
- if (model.spec.backend === "codex" && model.effort) return fail(`effort "-${model.effort}" has no effect on image-gen (the image tool renders, not the seat model); use ${DEFAULT_IMAGE_GEN}.`);
244
+ if (model.spec.backend === "codex" && model.effort) return fail(`effort "-${model.effort}" has no effect on image-gen (the image tool renders, not the seat model); pass the un-suffixed slug "${model.spec.slug}" instead.`);
248
245
  const expected = imageFormatFor(model);
249
246
  if (expected === void 0) return fail(formatImageGenModelError(inputSlug, model));
250
247
  const label = expected === "png" ? "PNG" : "JPEG";
@@ -378,7 +375,7 @@ const fullDescription$6 = [
378
375
  "",
379
376
  "Image-gen seats (canonical slug):",
380
377
  ...listModelHelpLines({ imageOnly: true }),
381
- `Default: ${DEFAULT_IMAGE_GEN}.`
378
+ "Recommended seat: openai-codex/gpt-5.6-sol."
382
379
  ].join("\n");
383
380
  const imageGen = buildCommand({
384
381
  func: imageGen$1,
@@ -387,8 +384,7 @@ const imageGen = buildCommand({
387
384
  model: {
388
385
  kind: "parsed",
389
386
  parse: String,
390
- optional: true,
391
- brief: `Model slug (default: ${DEFAULT_IMAGE_GEN})`
387
+ brief: "Model slug (required) — see the seat list above"
392
388
  },
393
389
  out: {
394
390
  kind: "parsed",
@@ -649,7 +645,7 @@ function readRunLogs(id) {
649
645
  //#endregion
650
646
  //#region src/commands/implement/impl.ts
651
647
  async function implement$1(flags, planFile) {
652
- const inputSlug = flags.model ?? "google-antigravity/gemini-3.6-flash";
648
+ const inputSlug = flags.model;
653
649
  const model = resolveModel(inputSlug);
654
650
  if (!model) {
655
651
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -719,8 +715,7 @@ const implement = buildCommand({
719
715
  model: {
720
716
  kind: "parsed",
721
717
  parse: String,
722
- optional: true,
723
- brief: `Model slug (default: ${DEFAULT_IMPLEMENTER})`
718
+ brief: "Model slug (required) — see the seat list above"
724
719
  },
725
720
  timeout: {
726
721
  kind: "parsed",
@@ -781,7 +776,7 @@ function extractPathFromPorcelainLine(line) {
781
776
  return content;
782
777
  }
783
778
  async function plan$1(flags, taskPrompt) {
784
- const inputSlug = flags.model ?? "xai-grok/grok-4.5";
779
+ const inputSlug = flags.model;
785
780
  const model = resolveModel(inputSlug);
786
781
  if (!model) {
787
782
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -801,7 +796,7 @@ async function plan$1(flags, taskPrompt) {
801
796
  const cwd = this.process.cwd();
802
797
  const promptSnippet = taskPrompt.replace(/\r?\n/g, " ").slice(0, 80);
803
798
  const run = startRun("plan", `${model.spec.slug}: ${promptSnippet}`);
804
- const absOutPath = flags.out ? isAbsolute(flags.out) ? flags.out : resolve(cwd, flags.out) : resolve(run.dir, "plan.md");
799
+ const absOutPath = isAbsolute(flags.out) ? flags.out : resolve(cwd, flags.out);
805
800
  const beforePorcelain = await getPorcelainStatus(cwd);
806
801
  const outcome = await delegate({
807
802
  model,
@@ -866,14 +861,12 @@ const plan = buildCommand({
866
861
  model: {
867
862
  kind: "parsed",
868
863
  parse: String,
869
- optional: true,
870
- brief: `Model slug (default: ${DEFAULT_MODEL})`
864
+ brief: "Model slug (required) — see the seat list above"
871
865
  },
872
866
  out: {
873
867
  kind: "parsed",
874
868
  parse: String,
875
- optional: true,
876
- brief: "Where to write the plan (default: <run.dir>/plan.md)"
869
+ brief: "Where to write the plan file (required)"
877
870
  },
878
871
  timeout: {
879
872
  kind: "parsed",
@@ -1032,7 +1025,7 @@ function parseReviewVerdict(response) {
1032
1025
  };
1033
1026
  }
1034
1027
  async function review$1(flags) {
1035
- const inputSlug = flags.model ?? "xai-grok/grok-4.5";
1028
+ const inputSlug = flags.model;
1036
1029
  const model = resolveModel(inputSlug);
1037
1030
  if (!model) {
1038
1031
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -1082,7 +1075,7 @@ async function review$1(flags) {
1082
1075
  const timeoutSec = flags.timeout ?? 1200;
1083
1076
  const modeDetail = isDirty ? absPlanPath ? `diff + plan (${absPlanPath})` : `diff (${baseRef})` : `plan-only (${absPlanPath})`;
1084
1077
  const run = startRun("review", `${model.spec.slug}: ${modeDetail}`);
1085
- const absOutPath = flags.out ? isAbsolute(flags.out) ? flags.out : resolve(cwd, flags.out) : resolve(run.dir, "review.md");
1078
+ const absOutPath = isAbsolute(flags.out) ? flags.out : resolve(cwd, flags.out);
1086
1079
  let reviewPrompt;
1087
1080
  if (isDirty) reviewPrompt = `You are an expert code reviewer. Inspect the working tree diff against base '${baseRef}' and untracked files at ${cwd}.\n` + (absPlanPath ? `Compare the implementation against the plan contract at ${absPlanPath}. Any file modified or feature added outside the plan contract counts as over-reach (severity: major unless harmful, then critical).\n` : "") + `Write your detailed review report to the file ${absOutPath}. For each finding, include file:line, severity (critical|major|minor), and rationale.\nYour final answer (last message) must consist of EXACTLY ONE VERDICT LINE:\nEither: "PASS"\nOr: "FINDINGS: <c> critical, <m> major, <n> minor"`;
1088
1081
  else reviewPrompt = `You are an expert architecture reviewer. Inspect the plan contract file at ${absPlanPath}.\nReview the plan for soundness, missing edge cases, safety, and feasibility.\nWrite your detailed review report to the file ${absOutPath}. For each finding, include severity (critical|major|minor) and rationale.\nYour final answer (last message) must consist of EXACTLY ONE VERDICT LINE:\nEither: "PASS"\nOr: "FINDINGS: <c> critical, <m> major, <n> minor"`;
@@ -1134,8 +1127,7 @@ const review = buildCommand({
1134
1127
  model: {
1135
1128
  kind: "parsed",
1136
1129
  parse: String,
1137
- optional: true,
1138
- brief: `Model slug (default: ${DEFAULT_MODEL})`
1130
+ brief: "Model slug (required) — see the seat list above"
1139
1131
  },
1140
1132
  plan: {
1141
1133
  kind: "parsed",
@@ -1152,8 +1144,7 @@ const review = buildCommand({
1152
1144
  out: {
1153
1145
  kind: "parsed",
1154
1146
  parse: String,
1155
- optional: true,
1156
- brief: "Where to write the review report (default: <run.dir>/review.md)"
1147
+ brief: "Where to write the review report (required)"
1157
1148
  },
1158
1149
  timeout: {
1159
1150
  kind: "parsed",
@@ -1345,7 +1336,7 @@ const runs = buildCommand({
1345
1336
  //#endregion
1346
1337
  //#region src/commands/subagent/impl.ts
1347
1338
  async function subagent$1(flags, prompt) {
1348
- const inputSlug = flags.model ?? "xai-grok/grok-4.5";
1339
+ const inputSlug = flags.model;
1349
1340
  const model = resolveModel(inputSlug);
1350
1341
  if (!model) {
1351
1342
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -1399,7 +1390,7 @@ const fullDescription = [
1399
1390
  "",
1400
1391
  "Available models (canonical slug):",
1401
1392
  ...listModelHelpLines(),
1402
- `Default: ${DEFAULT_MODEL} (off-budget). The claude-backend slugs are FALLBACKS for`,
1393
+ "Recommended first choice: xai-grok/grok-4.5 (off-budget). The claude-backend slugs are FALLBACKS for",
1403
1394
  "when the off-budget CLIs are quota-exhausted — they bill your Claude subscription."
1404
1395
  ].join("\n");
1405
1396
  const subagent = buildCommand({
@@ -1409,8 +1400,7 @@ const subagent = buildCommand({
1409
1400
  model: {
1410
1401
  kind: "parsed",
1411
1402
  parse: String,
1412
- optional: true,
1413
- brief: `Model slug to delegate to (default: ${DEFAULT_MODEL})`
1403
+ brief: "Model slug (required) — see the seat list above"
1414
1404
  },
1415
1405
  timeout: {
1416
1406
  kind: "parsed",
@@ -1494,4 +1484,4 @@ function buildContext(process) {
1494
1484
  return { process };
1495
1485
  }
1496
1486
  //#endregion
1497
- export { listModelHelpLines as C, formatUnknownModelError as S, supportsImageGen as T, DEFAULT_IMPLEMENTER as _, readRunLogs as a, backendModelId as b, evaluateCodexPreflight as c, renderPreflightRefusal as d, delegate as f, DEFAULT_IMAGE_GEN as g, positiveIntSeconds as h, listRuns as i, preflightCodex as l, nonEmptyPrompt as m, app as n, startRun as o, getDriver as p, runCli as r, evaluateAgyPreflight as s, buildContext as t, preflightModel as u, DEFAULT_MODEL as v, resolveModel as w, formatImageGenModelError as x, MODELS as y };
1487
+ export { supportsImageGen as S, backendModelId as _, readRunLogs as a, listModelHelpLines as b, evaluateCodexPreflight as c, renderPreflightRefusal as d, delegate as f, MODELS as g, positiveIntSeconds as h, listRuns as i, preflightCodex as l, nonEmptyPrompt as m, app as n, startRun as o, getDriver as p, runCli as r, evaluateAgyPreflight as s, buildContext as t, preflightModel as u, formatImageGenModelError as v, resolveModel as x, formatUnknownModelError as y };
package/dist/index.d.mts CHANGED
@@ -39,9 +39,6 @@ interface ResolvedModel {
39
39
  readonly effort: Effort | undefined;
40
40
  }
41
41
  declare const MODELS: Record<string, ModelSpec>;
42
- declare const DEFAULT_MODEL = "xai-grok/grok-4.5";
43
- declare const DEFAULT_IMPLEMENTER = "google-antigravity/gemini-3.6-flash";
44
- declare const DEFAULT_IMAGE_GEN = "openai-codex/gpt-5.6-sol";
45
42
  declare function supportsImageGen(resolved: ResolvedModel): boolean;
46
43
  declare function resolveModel(input: string): ResolvedModel | undefined;
47
44
  declare function backendModelId(resolved: ResolvedModel): string;
@@ -179,4 +176,4 @@ declare function renderPreflightRefusal(cmd: string, verdict: {
179
176
  resetAt: string | undefined;
180
177
  }): string;
181
178
  //#endregion
182
- export { type AgentCliDriver, type Backend, DEFAULT_IMAGE_GEN, DEFAULT_IMPLEMENTER, DEFAULT_MODEL, type DelegateOptions, type DelegateOutcome, type DelegationResult, type DelegationTask, type Effort, type LocalContext, MODELS, type ModelSpec, type PreflightVerdict, type ResolvedModel, type RunLog, type RunMeta, app, backendModelId, buildContext, delegate, evaluateAgyPreflight, evaluateCodexPreflight, formatImageGenModelError, formatUnknownModelError, getDriver, listModelHelpLines, listRuns, nonEmptyPrompt, positiveIntSeconds, preflightCodex, preflightModel, readRunLogs, renderPreflightRefusal, resolveModel, runCli, startRun, supportsImageGen };
179
+ export { type AgentCliDriver, type Backend, type DelegateOptions, type DelegateOutcome, type DelegationResult, type DelegationTask, type Effort, type LocalContext, MODELS, type ModelSpec, type PreflightVerdict, type ResolvedModel, type RunLog, type RunMeta, app, backendModelId, buildContext, delegate, evaluateAgyPreflight, evaluateCodexPreflight, formatImageGenModelError, formatUnknownModelError, getDriver, listModelHelpLines, listRuns, nonEmptyPrompt, positiveIntSeconds, preflightCodex, preflightModel, readRunLogs, renderPreflightRefusal, resolveModel, runCli, startRun, supportsImageGen };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { C as listModelHelpLines, S as formatUnknownModelError, T as supportsImageGen, _ as DEFAULT_IMPLEMENTER, a as readRunLogs, b as backendModelId, c as evaluateCodexPreflight, d as renderPreflightRefusal, f as delegate, g as DEFAULT_IMAGE_GEN, h as positiveIntSeconds, i as listRuns, l as preflightCodex, m as nonEmptyPrompt, n as app, o as startRun, p as getDriver, r as runCli, s as evaluateAgyPreflight, t as buildContext, u as preflightModel, v as DEFAULT_MODEL, w as resolveModel, x as formatImageGenModelError, y as MODELS } from "./context-DQxvMUd2.mjs";
2
- export { DEFAULT_IMAGE_GEN, DEFAULT_IMPLEMENTER, DEFAULT_MODEL, MODELS, app, backendModelId, buildContext, delegate, evaluateAgyPreflight, evaluateCodexPreflight, formatImageGenModelError, formatUnknownModelError, getDriver, listModelHelpLines, listRuns, nonEmptyPrompt, positiveIntSeconds, preflightCodex, preflightModel, readRunLogs, renderPreflightRefusal, resolveModel, runCli, startRun, supportsImageGen };
1
+ import { S as supportsImageGen, _ as backendModelId, a as readRunLogs, b as listModelHelpLines, c as evaluateCodexPreflight, d as renderPreflightRefusal, f as delegate, g as MODELS, h as positiveIntSeconds, i as listRuns, l as preflightCodex, m as nonEmptyPrompt, n as app, o as startRun, p as getDriver, r as runCli, s as evaluateAgyPreflight, t as buildContext, u as preflightModel, v as formatImageGenModelError, x as resolveModel, y as formatUnknownModelError } from "./context-B6I4QI9z.mjs";
2
+ export { MODELS, app, backendModelId, buildContext, delegate, evaluateAgyPreflight, evaluateCodexPreflight, formatImageGenModelError, formatUnknownModelError, getDriver, listModelHelpLines, listRuns, nonEmptyPrompt, positiveIntSeconds, preflightCodex, preflightModel, readRunLogs, renderPreflightRefusal, resolveModel, runCli, startRun, supportsImageGen };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aibridge/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI that bridges tasks to AI CLIs on your machine (plan / implement / review / subagent / image-gen)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -35,11 +35,11 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@stricli/core": "1.3.0",
38
- "@aibridge/proc": "0.2.0",
39
- "@aibridge/driver-codex": "0.2.0",
40
- "@aibridge/driver-grok": "0.2.0",
41
- "@aibridge/driver-claude": "0.2.0",
42
- "@aibridge/driver-agy": "0.2.0"
38
+ "@aibridge/proc": "0.3.0",
39
+ "@aibridge/driver-agy": "0.3.0",
40
+ "@aibridge/driver-grok": "0.3.0",
41
+ "@aibridge/driver-codex": "0.3.0",
42
+ "@aibridge/driver-claude": "0.3.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "tsdown": "0.22.14"
@@ -1,5 +1,5 @@
1
1
  import { buildCommand } from '@stricli/core';
2
- import { DEFAULT_IMAGE_GEN, listModelHelpLines } from '../../models.ts';
2
+ import { listModelHelpLines } from '../../models.ts';
3
3
  import { nonEmptyPrompt, positiveIntSeconds } from '../../parsers.ts';
4
4
  import imageGenImpl from './impl.ts';
5
5
 
@@ -9,7 +9,7 @@ const fullDescription = [
9
9
  '',
10
10
  'Image-gen seats (canonical slug):',
11
11
  ...listModelHelpLines({ imageOnly: true }),
12
- `Default: ${DEFAULT_IMAGE_GEN}.`,
12
+ 'Recommended seat: openai-codex/gpt-5.6-sol.',
13
13
  ].join('\n');
14
14
 
15
15
  export const imageGen = buildCommand({
@@ -19,8 +19,7 @@ export const imageGen = buildCommand({
19
19
  model: {
20
20
  kind: 'parsed',
21
21
  parse: String,
22
- optional: true,
23
- brief: `Model slug (default: ${DEFAULT_IMAGE_GEN})`,
22
+ brief: 'Model slug (required) — see the seat list above',
24
23
  },
25
24
  out: {
26
25
  kind: 'parsed',
@@ -15,7 +15,6 @@ import type { ImageResult } from '../../driver.ts';
15
15
  import { getDriver } from '../../drivers.ts';
16
16
  import {
17
17
  backendModelId,
18
- DEFAULT_IMAGE_GEN,
19
18
  formatImageGenModelError,
20
19
  formatUnknownModelError,
21
20
  imageFormatFor,
@@ -24,7 +23,7 @@ import {
24
23
  } from '../../models.ts';
25
24
 
26
25
  export interface ImageGenFlags {
27
- readonly model?: string;
26
+ readonly model: string;
28
27
  readonly out: string;
29
28
  readonly aspectRatio?: string;
30
29
  readonly image?: string;
@@ -45,14 +44,14 @@ export default async function imageGen(
45
44
  this.process.exitCode = 1;
46
45
  };
47
46
 
48
- const inputSlug = flags.model ?? DEFAULT_IMAGE_GEN;
47
+ const inputSlug = flags.model;
49
48
  const model = resolveModel(inputSlug);
50
49
  if (!model) return fail(formatUnknownModelError(inputSlug));
51
50
  if (!supportsImageGen(model)) return fail(formatImageGenModelError(inputSlug, model));
52
51
 
53
52
  if (model.spec.backend === 'codex' && model.effort) {
54
53
  return fail(
55
- `effort "-${model.effort}" has no effect on image-gen (the image tool renders, not the seat model); use ${DEFAULT_IMAGE_GEN}.`,
54
+ `effort "-${model.effort}" has no effect on image-gen (the image tool renders, not the seat model); pass the un-suffixed slug "${model.spec.slug}" instead.`,
56
55
  );
57
56
  }
58
57
 
@@ -1,5 +1,5 @@
1
1
  import { buildCommand } from '@stricli/core';
2
- import { DEFAULT_IMPLEMENTER, listModelHelpLines } from '../../models.ts';
2
+ import { listModelHelpLines } from '../../models.ts';
3
3
  import { positiveIntSeconds } from '../../parsers.ts';
4
4
  import implementImpl from './impl.ts';
5
5
 
@@ -17,8 +17,7 @@ export const implement = buildCommand({
17
17
  model: {
18
18
  kind: 'parsed',
19
19
  parse: String,
20
- optional: true,
21
- brief: `Model slug (default: ${DEFAULT_IMPLEMENTER})`,
20
+ brief: 'Model slug (required) — see the seat list above',
22
21
  },
23
22
  timeout: {
24
23
  kind: 'parsed',
@@ -3,12 +3,12 @@ import { isAbsolute, resolve } from 'node:path';
3
3
  import { runCaptured } from '@aibridge/proc';
4
4
  import type { LocalContext } from '../../context.ts';
5
5
  import { delegate } from '../../delegate.ts';
6
- import { DEFAULT_IMPLEMENTER, formatUnknownModelError, resolveModel } from '../../models.ts';
6
+ import { formatUnknownModelError, resolveModel } from '../../models.ts';
7
7
  import { preflightModel, renderPreflightRefusal } from '../../quotaPreflight.ts';
8
8
  import { startRun } from '../../runlog.ts';
9
9
 
10
10
  export interface ImplementFlags {
11
- readonly model?: string;
11
+ readonly model: string;
12
12
  readonly timeout?: number;
13
13
  readonly preflight: boolean;
14
14
  }
@@ -18,7 +18,7 @@ export default async function implement(
18
18
  flags: ImplementFlags,
19
19
  planFile: string,
20
20
  ): Promise<void> {
21
- const inputSlug = flags.model ?? DEFAULT_IMPLEMENTER;
21
+ const inputSlug = flags.model;
22
22
  const model = resolveModel(inputSlug);
23
23
  if (!model) {
24
24
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -1,5 +1,5 @@
1
1
  import { buildCommand } from '@stricli/core';
2
- import { DEFAULT_MODEL, listModelHelpLines } from '../../models.ts';
2
+ import { listModelHelpLines } from '../../models.ts';
3
3
  import { nonEmptyPrompt, positiveIntSeconds } from '../../parsers.ts';
4
4
  import planImpl from './impl.ts';
5
5
 
@@ -17,14 +17,12 @@ export const plan = buildCommand({
17
17
  model: {
18
18
  kind: 'parsed',
19
19
  parse: String,
20
- optional: true,
21
- brief: `Model slug (default: ${DEFAULT_MODEL})`,
20
+ brief: 'Model slug (required) — see the seat list above',
22
21
  },
23
22
  out: {
24
23
  kind: 'parsed',
25
24
  parse: String,
26
- optional: true,
27
- brief: 'Where to write the plan (default: <run.dir>/plan.md)',
25
+ brief: 'Where to write the plan file (required)',
28
26
  },
29
27
  timeout: {
30
28
  kind: 'parsed',
@@ -3,13 +3,13 @@ import { isAbsolute, resolve } from 'node:path';
3
3
  import { runCaptured } from '@aibridge/proc';
4
4
  import type { LocalContext } from '../../context.ts';
5
5
  import { delegate } from '../../delegate.ts';
6
- import { DEFAULT_MODEL, formatUnknownModelError, resolveModel } from '../../models.ts';
6
+ import { formatUnknownModelError, resolveModel } from '../../models.ts';
7
7
  import { preflightModel, renderPreflightRefusal } from '../../quotaPreflight.ts';
8
8
  import { startRun } from '../../runlog.ts';
9
9
 
10
10
  export interface PlanFlags {
11
- readonly model?: string;
12
- readonly out?: string;
11
+ readonly model: string;
12
+ readonly out: string;
13
13
  readonly timeout?: number;
14
14
  readonly preflight: boolean;
15
15
  }
@@ -63,7 +63,7 @@ export default async function plan(
63
63
  flags: PlanFlags,
64
64
  taskPrompt: string,
65
65
  ): Promise<void> {
66
- const inputSlug = flags.model ?? DEFAULT_MODEL;
66
+ const inputSlug = flags.model;
67
67
  const model = resolveModel(inputSlug);
68
68
  if (!model) {
69
69
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -86,11 +86,7 @@ export default async function plan(
86
86
  const promptSnippet = taskPrompt.replace(/\r?\n/g, ' ').slice(0, 80);
87
87
  const run = startRun('plan', `${model.spec.slug}: ${promptSnippet}`);
88
88
 
89
- const absOutPath = flags.out
90
- ? isAbsolute(flags.out)
91
- ? flags.out
92
- : resolve(cwd, flags.out)
93
- : resolve(run.dir, 'plan.md');
89
+ const absOutPath = isAbsolute(flags.out) ? flags.out : resolve(cwd, flags.out);
94
90
 
95
91
  const beforePorcelain = await getPorcelainStatus(cwd);
96
92
 
@@ -1,5 +1,5 @@
1
1
  import { buildCommand } from '@stricli/core';
2
- import { DEFAULT_MODEL, listModelHelpLines } from '../../models.ts';
2
+ import { listModelHelpLines } from '../../models.ts';
3
3
  import { positiveIntSeconds } from '../../parsers.ts';
4
4
  import reviewImpl from './impl.ts';
5
5
 
@@ -17,8 +17,7 @@ export const review = buildCommand({
17
17
  model: {
18
18
  kind: 'parsed',
19
19
  parse: String,
20
- optional: true,
21
- brief: `Model slug (default: ${DEFAULT_MODEL})`,
20
+ brief: 'Model slug (required) — see the seat list above',
22
21
  },
23
22
  plan: {
24
23
  kind: 'parsed',
@@ -35,8 +34,7 @@ export const review = buildCommand({
35
34
  out: {
36
35
  kind: 'parsed',
37
36
  parse: String,
38
- optional: true,
39
- brief: 'Where to write the review report (default: <run.dir>/review.md)',
37
+ brief: 'Where to write the review report (required)',
40
38
  },
41
39
  timeout: {
42
40
  kind: 'parsed',
@@ -3,15 +3,15 @@ import { isAbsolute, resolve } from 'node:path';
3
3
  import { runCaptured } from '@aibridge/proc';
4
4
  import type { LocalContext } from '../../context.ts';
5
5
  import { delegate } from '../../delegate.ts';
6
- import { DEFAULT_MODEL, formatUnknownModelError, resolveModel } from '../../models.ts';
6
+ import { formatUnknownModelError, resolveModel } from '../../models.ts';
7
7
  import { preflightModel, renderPreflightRefusal } from '../../quotaPreflight.ts';
8
8
  import { startRun } from '../../runlog.ts';
9
9
 
10
10
  export interface ReviewFlags {
11
- readonly model?: string;
11
+ readonly model: string;
12
12
  readonly plan?: string;
13
13
  readonly base?: string;
14
- readonly out?: string;
14
+ readonly out: string;
15
15
  readonly timeout?: number;
16
16
  readonly preflight: boolean;
17
17
  }
@@ -78,7 +78,7 @@ export function parseReviewVerdict(response: string): ReviewVerdictResult {
78
78
  }
79
79
 
80
80
  export default async function review(this: LocalContext, flags: ReviewFlags): Promise<void> {
81
- const inputSlug = flags.model ?? DEFAULT_MODEL;
81
+ const inputSlug = flags.model;
82
82
  const model = resolveModel(inputSlug);
83
83
  if (!model) {
84
84
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -140,11 +140,7 @@ export default async function review(this: LocalContext, flags: ReviewFlags): Pr
140
140
 
141
141
  const run = startRun('review', `${model.spec.slug}: ${modeDetail}`);
142
142
 
143
- const absOutPath = flags.out
144
- ? isAbsolute(flags.out)
145
- ? flags.out
146
- : resolve(cwd, flags.out)
147
- : resolve(run.dir, 'review.md');
143
+ const absOutPath = isAbsolute(flags.out) ? flags.out : resolve(cwd, flags.out);
148
144
 
149
145
  let reviewPrompt: string;
150
146
  if (isDirty) {
@@ -1,5 +1,5 @@
1
1
  import { buildCommand } from '@stricli/core';
2
- import { DEFAULT_MODEL, listModelHelpLines } from '../../models.ts';
2
+ import { listModelHelpLines } from '../../models.ts';
3
3
  import { nonEmptyPrompt, positiveIntSeconds } from '../../parsers.ts';
4
4
  import subagentImpl from './impl.ts';
5
5
 
@@ -8,7 +8,7 @@ const fullDescription = [
8
8
  '',
9
9
  'Available models (canonical slug):',
10
10
  ...listModelHelpLines(),
11
- `Default: ${DEFAULT_MODEL} (off-budget). The claude-backend slugs are FALLBACKS for`,
11
+ 'Recommended first choice: xai-grok/grok-4.5 (off-budget). The claude-backend slugs are FALLBACKS for',
12
12
  'when the off-budget CLIs are quota-exhausted — they bill your Claude subscription.',
13
13
  ].join('\n');
14
14
 
@@ -19,8 +19,7 @@ export const subagent = buildCommand({
19
19
  model: {
20
20
  kind: 'parsed',
21
21
  parse: String,
22
- optional: true,
23
- brief: `Model slug to delegate to (default: ${DEFAULT_MODEL})`,
22
+ brief: 'Model slug (required) — see the seat list above',
24
23
  },
25
24
  timeout: {
26
25
  kind: 'parsed',
@@ -1,16 +1,11 @@
1
1
  import type { LocalContext } from '../../context.ts';
2
2
  import { delegate } from '../../delegate.ts';
3
- import {
4
- backendModelId,
5
- DEFAULT_MODEL,
6
- formatUnknownModelError,
7
- resolveModel,
8
- } from '../../models.ts';
3
+ import { backendModelId, formatUnknownModelError, resolveModel } from '../../models.ts';
9
4
  import { preflightModel, renderPreflightRefusal } from '../../quotaPreflight.ts';
10
5
  import { startRun } from '../../runlog.ts';
11
6
 
12
7
  export interface SubagentFlags {
13
- readonly model?: string;
8
+ readonly model: string;
14
9
  readonly timeout?: number;
15
10
  readonly tools: boolean;
16
11
  readonly preflight: boolean;
@@ -22,7 +17,7 @@ export default async function subagent(
22
17
  flags: SubagentFlags,
23
18
  prompt: string,
24
19
  ): Promise<void> {
25
- const inputSlug = flags.model ?? DEFAULT_MODEL;
20
+ const inputSlug = flags.model;
26
21
  const model = resolveModel(inputSlug);
27
22
  if (!model) {
28
23
  this.process.stderr.write(`${formatUnknownModelError(inputSlug)}\n`);
@@ -35,7 +35,7 @@ describe('flag mapping & defaults lock', () => {
35
35
  it('plan command maps defaults correctly', async () => {
36
36
  mockPlanImpl.mockReset();
37
37
  const ctx = fakeCtx();
38
- await runCli(ctx, ['plan', 'do something']);
38
+ await runCli(ctx, ['plan', '--model', 'xai-grok/grok-4.5', '--out', 'plan.md', 'do something']);
39
39
  expect(mockPlanImpl).toHaveBeenCalledTimes(1);
40
40
  const [call] = mockPlanImpl.mock.calls;
41
41
  expect(call).toBeDefined();
@@ -43,6 +43,8 @@ describe('flag mapping & defaults lock', () => {
43
43
  const [flags, prompt] = call;
44
44
  expect(prompt).toBe('do something');
45
45
  expect(flags).toEqual({
46
+ model: 'xai-grok/grok-4.5',
47
+ out: 'plan.md',
46
48
  preflight: true,
47
49
  });
48
50
  });
@@ -50,7 +52,17 @@ describe('flag mapping & defaults lock', () => {
50
52
  it('plan command handles --no-preflight and --timeout', async () => {
51
53
  mockPlanImpl.mockReset();
52
54
  const ctx = fakeCtx();
53
- await runCli(ctx, ['plan', '--no-preflight', '--timeout', '120', 'task']);
55
+ await runCli(ctx, [
56
+ 'plan',
57
+ '--model',
58
+ 'xai-grok/grok-4.5',
59
+ '--out',
60
+ 'plan.md',
61
+ '--no-preflight',
62
+ '--timeout',
63
+ '120',
64
+ 'task',
65
+ ]);
54
66
  expect(mockPlanImpl).toHaveBeenCalledTimes(1);
55
67
  const [call] = mockPlanImpl.mock.calls;
56
68
  expect(call).toBeDefined();
@@ -58,6 +70,8 @@ describe('flag mapping & defaults lock', () => {
58
70
  const [flags, prompt] = call;
59
71
  expect(prompt).toBe('task');
60
72
  expect(flags).toEqual({
73
+ model: 'xai-grok/grok-4.5',
74
+ out: 'plan.md',
61
75
  preflight: false,
62
76
  timeout: 120,
63
77
  });
@@ -66,7 +80,7 @@ describe('flag mapping & defaults lock', () => {
66
80
  it('subagent command maps defaults correctly', async () => {
67
81
  mockSubagentImpl.mockReset();
68
82
  const ctx = fakeCtx();
69
- await runCli(ctx, ['subagent', 'hello agent']);
83
+ await runCli(ctx, ['subagent', '--model', 'xai-grok/grok-4.5', 'hello agent']);
70
84
  expect(mockSubagentImpl).toHaveBeenCalledTimes(1);
71
85
  const [call] = mockSubagentImpl.mock.calls;
72
86
  expect(call).toBeDefined();
@@ -74,6 +88,7 @@ describe('flag mapping & defaults lock', () => {
74
88
  const [flags, prompt] = call;
75
89
  expect(prompt).toBe('hello agent');
76
90
  expect(flags).toEqual({
91
+ model: 'xai-grok/grok-4.5',
77
92
  tools: true,
78
93
  preflight: true,
79
94
  json: false,
@@ -83,7 +98,14 @@ describe('flag mapping & defaults lock', () => {
83
98
  it('subagent command handles --no-tools and --no-preflight', async () => {
84
99
  mockSubagentImpl.mockReset();
85
100
  const ctx = fakeCtx();
86
- await runCli(ctx, ['subagent', '--no-tools', '--no-preflight', 'hello agent']);
101
+ await runCli(ctx, [
102
+ 'subagent',
103
+ '--model',
104
+ 'xai-grok/grok-4.5',
105
+ '--no-tools',
106
+ '--no-preflight',
107
+ 'hello agent',
108
+ ]);
87
109
  expect(mockSubagentImpl).toHaveBeenCalledTimes(1);
88
110
  const [call] = mockSubagentImpl.mock.calls;
89
111
  expect(call).toBeDefined();
@@ -91,6 +113,7 @@ describe('flag mapping & defaults lock', () => {
91
113
  const [flags, prompt] = call;
92
114
  expect(prompt).toBe('hello agent');
93
115
  expect(flags).toEqual({
116
+ model: 'xai-grok/grok-4.5',
94
117
  tools: false,
95
118
  preflight: false,
96
119
  json: false,
package/src/index.ts CHANGED
@@ -6,9 +6,6 @@ export { getDriver } from './drivers.ts';
6
6
  export {
7
7
  type Backend,
8
8
  backendModelId,
9
- DEFAULT_IMAGE_GEN,
10
- DEFAULT_IMPLEMENTER,
11
- DEFAULT_MODEL,
12
9
  type Effort,
13
10
  formatImageGenModelError,
14
11
  formatUnknownModelError,
package/src/models.ts CHANGED
@@ -95,10 +95,6 @@ export const MODELS: Record<string, ModelSpec> = {
95
95
  },
96
96
  } as const satisfies Record<string, ModelSpec>;
97
97
 
98
- export const DEFAULT_MODEL = 'xai-grok/grok-4.5';
99
- export const DEFAULT_IMPLEMENTER = 'google-antigravity/gemini-3.6-flash';
100
- export const DEFAULT_IMAGE_GEN = 'openai-codex/gpt-5.6-sol';
101
-
102
98
  export type ImageFormat = 'jpg' | 'png';
103
99
 
104
100
  const IMAGE_GEN_FORMATS: ReadonlyMap<Backend, ImageFormat> = new Map([