opencode-matrixx 2.6.4 → 2.6.5

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.
Files changed (50) hide show
  1. package/dist/cli/setup/index.d.ts +1 -0
  2. package/dist/cli/setup/preset-wizard.d.ts +36 -0
  3. package/dist/cli/setup/types.d.ts +5 -0
  4. package/dist/cli.js +486 -59
  5. package/dist/config/index.d.ts +0 -1
  6. package/dist/config/migrations/model-migration.d.ts +1 -2
  7. package/dist/config/preset-applier.d.ts +17 -0
  8. package/dist/config/schema/agent-overrides.d.ts +0 -133
  9. package/dist/config/schema/categories.d.ts +0 -14
  10. package/dist/config/schema/commands.d.ts +1 -1
  11. package/dist/config/schema/matrixx-config.d.ts +28 -144
  12. package/dist/config/schema/model-config.d.ts +0 -22
  13. package/dist/config/schema/model-presets.d.ts +40 -0
  14. package/dist/config/schema/task.d.ts +6 -0
  15. package/dist/config/schema/tasks.d.ts +25 -0
  16. package/dist/config/schema.d.ts +3 -0
  17. package/dist/features/builtin-commands/templates/preset.d.ts +1 -0
  18. package/dist/features/builtin-commands/types.d.ts +1 -1
  19. package/dist/features/preset-state/index.d.ts +1 -0
  20. package/dist/features/preset-state/manager.d.ts +5 -0
  21. package/dist/features/session-state/state.d.ts +6 -0
  22. package/dist/features/task-storage/types.d.ts +2 -0
  23. package/dist/hooks/json-error-recovery/hook.d.ts +1 -1
  24. package/dist/hooks/task-continuation-enforcer/continuation-injection.test.d.ts +1 -0
  25. package/dist/hooks/task-continuation-enforcer/staleness.d.ts +7 -1
  26. package/dist/hooks/task-continuation-enforcer/todo.d.ts +8 -0
  27. package/dist/hooks/task-continuation-enforcer/todo.test.d.ts +1 -0
  28. package/dist/hooks/tasks-todowrite-disabler/constants.d.ts +1 -1
  29. package/dist/index.js +673 -598
  30. package/dist/matrixx.schema.json +113 -244
  31. package/dist/mcp/types.d.ts +1 -1
  32. package/dist/mcp/{grep-app.d.ts → white-rabbit.d.ts} +1 -1
  33. package/dist/shared/config-errors.d.ts +3 -0
  34. package/dist/shared/merge-categories.d.ts +1 -16
  35. package/dist/shared/task-system-gating.d.ts +10 -0
  36. package/dist/tools/delegate-task/categories.d.ts +3 -18
  37. package/dist/tools/delegate-task/complexity-constants.d.ts +2 -7
  38. package/dist/tools/delegate-task/executor-types.d.ts +7 -2
  39. package/dist/tools/delegate-task/timing.d.ts +5 -0
  40. package/dist/tools/delegate-task/types.d.ts +5 -2
  41. package/dist/tools/index.d.ts +1 -0
  42. package/dist/tools/preset/index.d.ts +1 -0
  43. package/dist/tools/preset/tools.d.ts +7 -0
  44. package/dist/tools/task/constants.d.ts +1 -0
  45. package/package.json +1 -1
  46. package/dist/config/presets.d.ts +0 -4
  47. package/dist/config/resolve-tiers.d.ts +0 -32
  48. package/dist/features/builtin-commands/templates/profile.d.ts +0 -1
  49. package/dist/shared/model-tiers.d.ts +0 -44
  50. package/dist/shared/tier-resolver.d.ts +0 -26
package/dist/cli.js CHANGED
@@ -107,8 +107,8 @@ var require_src = __commonJS(function(exports, module) {
107
107
  });
108
108
 
109
109
  // src/cli/index.ts
110
- import { readFileSync as readFileSync15 } from "fs";
111
- import { dirname as dirname3, join as join17 } from "path";
110
+ import { readFileSync as readFileSync16 } from "fs";
111
+ import { dirname as dirname3, join as join18 } from "path";
112
112
  import { fileURLToPath } from "url";
113
113
 
114
114
  // src/cli/doctor/checks/auth.ts
@@ -15635,7 +15635,7 @@ function date4(params) {
15635
15635
  // node_modules/zod/v4/classic/external.js
15636
15636
  config(en_default());
15637
15637
  // src/mcp/types.ts
15638
- var McpNameSchema = exports_external.enum(["websearch", "context7", "grep_app", "document_reader"]);
15638
+ var McpNameSchema = exports_external.enum(["websearch", "context7", "white_rabbit", "document_reader"]);
15639
15639
  var AnyMcpNameSchema = exports_external.string().min(1);
15640
15640
 
15641
15641
  // src/config/schema/agent-definitions.ts
@@ -15715,10 +15715,8 @@ var AgentPermissionSchema = exports_external.object({
15715
15715
  });
15716
15716
 
15717
15717
  // src/config/schema/agent-overrides.ts
15718
- var TierNameSchema = exports_external.enum(["free", "fast", "standard", "premium", "frontier"]);
15719
15718
  var AgentOverrideConfigSchema = exports_external.object({
15720
15719
  model: exports_external.string().optional(),
15721
- tier: TierNameSchema.optional(),
15722
15720
  variant: exports_external.string().optional(),
15723
15721
  category: exports_external.string().optional(),
15724
15722
  skills: exports_external.array(exports_external.string()).optional(),
@@ -15814,7 +15812,6 @@ var BrowserAutomationConfigSchema = exports_external.object({
15814
15812
  var CategoryConfigSchema = exports_external.object({
15815
15813
  description: exports_external.string().optional(),
15816
15814
  model: exports_external.string().optional(),
15817
- tier: TierNameSchema.optional(),
15818
15815
  variant: exports_external.string().optional(),
15819
15816
  temperature: exports_external.number().min(0).max(2).optional(),
15820
15817
  top_p: exports_external.number().min(0).max(1).optional(),
@@ -15853,7 +15850,7 @@ var BuiltinCommandNameSchema = exports_external.enum([
15853
15850
  "refactor",
15854
15851
  "start-work",
15855
15852
  "stop-continuation",
15856
- "profile",
15853
+ "preset",
15857
15854
  "end-ultrawork",
15858
15855
  "handoff",
15859
15856
  "research",
@@ -16235,31 +16232,13 @@ var ModelFallbackEntrySchema = exports_external.object({
16235
16232
  model: exports_external.string().min(1),
16236
16233
  variant: exports_external.string().optional()
16237
16234
  });
16238
- var TierSpecSchema = exports_external.object({
16239
- providerPriority: exports_external.array(exports_external.string()),
16240
- modelPattern: exports_external.string().refine((s) => {
16241
- try {
16242
- new RegExp(s);
16243
- return true;
16244
- } catch {
16245
- return false;
16246
- }
16247
- }, { message: "Invalid regex pattern" }),
16248
- fallbackTier: exports_external.string().optional(),
16249
- fallback: exports_external.array(ModelFallbackEntrySchema).optional()
16250
- });
16251
- var TiersSchema = exports_external.record(exports_external.string(), TierSpecSchema);
16252
16235
  var complexityDowngradeValueSchema = exports_external.string().refine((s) => {
16253
- if (s.startsWith("tier:")) {
16254
- const name = s.slice(5);
16255
- return name.length > 0;
16256
- }
16257
16236
  if (s.includes("/")) {
16258
16237
  const parts = s.split("/");
16259
16238
  return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
16260
16239
  }
16261
16240
  return false;
16262
- }, { message: "Must be tier:<name> or <provider>/<model>" });
16241
+ }, { message: "Must be <provider>/<model>" });
16263
16242
  var ComplexityDowngradesSchema = exports_external.record(exports_external.string(), exports_external.record(exports_external.string(), complexityDowngradeValueSchema));
16264
16243
  var AgentModelRequirementsSchema = exports_external.object({
16265
16244
  fallbackChain: exports_external.array(ModelFallbackEntrySchema),
@@ -16280,6 +16259,25 @@ var ModelRequirementsSchema = exports_external.object({
16280
16259
  categories: exports_external.record(exports_external.string(), CategoryModelRequirementsSchema).optional()
16281
16260
  });
16282
16261
 
16262
+ // src/config/schema/model-presets.ts
16263
+ var providerModelSchema = exports_external.string().refine((s) => {
16264
+ if (!s.includes("/"))
16265
+ return false;
16266
+ const parts = s.split("/");
16267
+ return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
16268
+ }, { message: "Must be <provider>/<model>" });
16269
+ var ModelPresetEntrySchema = exports_external.object({
16270
+ model: providerModelSchema,
16271
+ variant: exports_external.string().optional()
16272
+ });
16273
+ var ModelPresetSchema = exports_external.object({
16274
+ default_model: providerModelSchema.optional(),
16275
+ agents: exports_external.record(exports_external.string(), ModelPresetEntrySchema).optional(),
16276
+ categories: exports_external.record(exports_external.string(), ModelPresetEntrySchema).optional()
16277
+ });
16278
+ var ModelPresetsSchema = exports_external.record(exports_external.string(), ModelPresetSchema);
16279
+ var ActivePresetSchema = exports_external.string().min(1);
16280
+
16283
16281
  // src/config/schema/morpheus.ts
16284
16282
  var MorpheusTasksConfigSchema = exports_external.object({
16285
16283
  storage_path: exports_external.string().optional(),
@@ -16406,6 +16404,22 @@ var SkillsConfigSchema = exports_external.union([
16406
16404
  }).catchall(SkillEntrySchema)
16407
16405
  ]);
16408
16406
 
16407
+ // src/config/schema/task.ts
16408
+ var TaskConfigSchema = exports_external.object({
16409
+ pollTimeoutMs: exports_external.number().min(60000).optional()
16410
+ });
16411
+
16412
+ // src/config/schema/tasks.ts
16413
+ var TasksConfigSchema = exports_external.object({
16414
+ enabled: exports_external.boolean().optional().default(true),
16415
+ scope: exports_external.enum(["global", "project"]).default("project").optional().describe("Task storage scope: project \u2192 .matrixx/tasks per project (default), global \u2192 <opencode-config>/tasks/{listId}"),
16416
+ storage_path: exports_external.string().optional(),
16417
+ task_list_id: exports_external.string().optional(),
16418
+ stale_after_hours: exports_external.number().int().min(1).optional().describe("Pending tasks with no file activity for this many hours are considered stale (default: 24). Stale tasks are excluded from task-continuation directives."),
16419
+ session_scoped: exports_external.boolean().default(true).optional().describe("When true, the task-continuation-enforcer only considers tasks created by the current session (or its subagent sessions). When false, all project tasks are considered regardless of session origin."),
16420
+ pollTimeoutMs: exports_external.number().min(60000).optional()
16421
+ });
16422
+
16409
16423
  // src/config/schema/tdd-enforcer.ts
16410
16424
  var TddEnforcerConfigSchema = exports_external.object({
16411
16425
  enabled: exports_external.boolean().default(false)
@@ -16437,7 +16451,8 @@ var WebsearchConfigSchema = exports_external.object({
16437
16451
  var MatrixxConfigSchema = exports_external.object({
16438
16452
  $schema: exports_external.string().optional(),
16439
16453
  global_model: exports_external.string().optional(),
16440
- default_tier: TierNameSchema.optional(),
16454
+ model_presets: ModelPresetsSchema.optional(),
16455
+ active_preset: ActivePresetSchema.optional(),
16441
16456
  new_task_system_enabled: exports_external.boolean().optional(),
16442
16457
  default_run_agent: exports_external.string().optional(),
16443
16458
  disabled_mcps: exports_external.array(AnyMcpNameSchema).optional(),
@@ -16459,6 +16474,8 @@ var MatrixxConfigSchema = exports_external.object({
16459
16474
  background_task: BackgroundTaskConfigSchema.optional(),
16460
16475
  notification: NotificationConfigSchema.optional(),
16461
16476
  babysitting: BabysittingConfigSchema.optional(),
16477
+ tasks: TasksConfigSchema.optional(),
16478
+ task: TaskConfigSchema.optional(),
16462
16479
  tdd_enforcer: TddEnforcerConfigSchema.optional(),
16463
16480
  browser_automation_engine: BrowserAutomationConfigSchema.optional(),
16464
16481
  websearch: WebsearchConfigSchema.optional(),
@@ -16474,7 +16491,6 @@ var MatrixxConfigSchema = exports_external.object({
16474
16491
  rtk: RtkConfigSchema.optional(),
16475
16492
  evolution: EvolutionConfigSchema.optional(),
16476
16493
  _migrations: exports_external.array(exports_external.string()).optional(),
16477
- tiers: TiersSchema.optional(),
16478
16494
  modelRequirements: ModelRequirementsSchema.optional(),
16479
16495
  complexityDowngrades: ComplexityDowngradesSchema.optional()
16480
16496
  });
@@ -18112,6 +18128,12 @@ function wrapAnsi(string4, columns, options) {
18112
18128
 
18113
18129
  // node_modules/@clack/core/dist/index.mjs
18114
18130
  var import_sisteransi = __toESM(require_src(), 1);
18131
+ function findCursor(s, o, l) {
18132
+ if (!l.some((r) => !r.disabled))
18133
+ return s;
18134
+ const t = s + o, n = Math.max(l.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
18135
+ return l[e]?.disabled ? findCursor(e, o < 0 ? -1 : 1, l) : e;
18136
+ }
18115
18137
  var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
18116
18138
  var t = [
18117
18139
  "January",
@@ -18365,7 +18387,35 @@ class r extends V {
18365
18387
  });
18366
18388
  }
18367
18389
  }
18368
- class n extends V {
18390
+ var n$1 = class n extends V {
18391
+ options;
18392
+ cursor = 0;
18393
+ get _selectedValue() {
18394
+ return this.options[this.cursor];
18395
+ }
18396
+ changeValue() {
18397
+ const e = this._selectedValue;
18398
+ this.value = e === undefined ? undefined : e.value;
18399
+ }
18400
+ constructor(e) {
18401
+ super(e, false), this.options = e.options;
18402
+ const o = this.options.findIndex(({ value: s }) => s === e.initialValue), t2 = o === -1 ? 0 : o;
18403
+ this.cursor = this.options[t2]?.disabled ? findCursor(t2, 1, this.options) : t2, this.changeValue(), this.on("cursor", (s) => {
18404
+ switch (s) {
18405
+ case "left":
18406
+ case "up":
18407
+ this.cursor = findCursor(this.cursor, -1, this.options);
18408
+ break;
18409
+ case "down":
18410
+ case "right":
18411
+ this.cursor = findCursor(this.cursor, 1, this.options);
18412
+ break;
18413
+ }
18414
+ this.changeValue();
18415
+ });
18416
+ }
18417
+ };
18418
+ class n2 extends V {
18369
18419
  get userInputWithCursor() {
18370
18420
  if (this.state === "submit")
18371
18421
  return this.userInput;
@@ -18440,6 +18490,78 @@ var symbol2 = (o) => {
18440
18490
  return styleText2("green", S_STEP_SUBMIT);
18441
18491
  }
18442
18492
  };
18493
+ var symbolBar = (o) => {
18494
+ switch (o) {
18495
+ case "initial":
18496
+ case "active":
18497
+ return styleText2("cyan", S_BAR);
18498
+ case "cancel":
18499
+ return styleText2("red", S_BAR);
18500
+ case "error":
18501
+ return styleText2("yellow", S_BAR);
18502
+ case "submit":
18503
+ return styleText2("green", S_BAR);
18504
+ }
18505
+ };
18506
+ function formatInstructionFooter(o, e) {
18507
+ const r2 = [`${e ? `${styleText2("cyan", S_BAR)} ` : ""}${o.join(" \u2022 ")}`];
18508
+ return e && r2.push(styleText2("cyan", S_BAR_END)), r2;
18509
+ }
18510
+ var I = (l, e, w, p, b, C = false) => {
18511
+ let r2 = e, O = 0;
18512
+ if (C)
18513
+ for (let i = p - 1;i >= w; i--) {
18514
+ const m = l[i];
18515
+ if (m && (r2 -= m.length), O++, r2 <= b)
18516
+ break;
18517
+ }
18518
+ else
18519
+ for (let i = w;i < p; i++) {
18520
+ const m = l[i];
18521
+ if (m && (r2 -= m.length), O++, r2 <= b)
18522
+ break;
18523
+ }
18524
+ return { lineCount: r2, removals: O };
18525
+ };
18526
+ var limitOptions = ({
18527
+ cursor: l,
18528
+ options: e,
18529
+ style: w,
18530
+ output: p = process.stdout,
18531
+ maxItems: b = Number.POSITIVE_INFINITY,
18532
+ columnPadding: C = 0,
18533
+ rowPadding: r2 = 4
18534
+ }) => {
18535
+ const i = getColumns(p) - C, m = getRows(p), M = styleText2("dim", "..."), v = Math.max(m - r2, 0), a2 = Math.max(Math.min(b, v), 5);
18536
+ let f = 0;
18537
+ l >= a2 - 3 && (f = Math.max(Math.min(l - a2 + 3, e.length - a2), 0));
18538
+ let d = a2 < e.length && f > 0, c = a2 < e.length && f + a2 < e.length;
18539
+ const W = Math.min(f + a2, e.length), s = [];
18540
+ let g = 0;
18541
+ d && g++, c && g++;
18542
+ const T = f + (d ? 1 : 0), y = W - (c ? 1 : 0);
18543
+ for (let t2 = T;t2 < y; t2++) {
18544
+ const n3 = e[t2], o = n3 ? w(n3, t2 === l) : "", h2 = wrapAnsi(o, i, {
18545
+ hard: true,
18546
+ trim: false
18547
+ }).split(`
18548
+ `);
18549
+ s.push(h2), g += h2.length;
18550
+ }
18551
+ if (g > v) {
18552
+ let t2 = 0, n3 = 0, o = g;
18553
+ const h2 = l - T;
18554
+ let u2 = v;
18555
+ const L = () => I(s, o, 0, h2, u2), E = () => I(s, o, h2 + 1, s.length, u2, true);
18556
+ d ? ({ lineCount: o, removals: t2 } = L(), o > u2 && (c || (u2 -= 1), { lineCount: o, removals: n3 } = E())) : (c || (u2 -= 1), { lineCount: o, removals: n3 } = E(), o > u2 && (u2 -= 1, { lineCount: o, removals: t2 } = L())), t2 > 0 && (d = true, s.splice(0, t2)), n3 > 0 && (c = true, s.splice(s.length - n3, n3));
18557
+ }
18558
+ const x = [];
18559
+ d && x.push(M);
18560
+ for (const t2 of s)
18561
+ for (const n3 of t2)
18562
+ x.push(n3);
18563
+ return c && x.push(M), x;
18564
+ };
18443
18565
  var confirm = (i) => {
18444
18566
  const a2 = i.active ?? "Yes", s = i.inactive ?? "No";
18445
18567
  return new r({
@@ -18504,18 +18626,18 @@ var C = (o, e, s) => {
18504
18626
  hard: true,
18505
18627
  trim: false
18506
18628
  }, i = wrapAnsi(o, e, a2).split(`
18507
- `), c = i.reduce((n2, t2) => Math.max(dist_default2(t2), n2), 0), u2 = i.map(s).reduce((n2, t2) => Math.max(dist_default2(t2), n2), 0), g = e - (u2 - c);
18629
+ `), c = i.reduce((n3, t2) => Math.max(dist_default2(t2), n3), 0), u2 = i.map(s).reduce((n3, t2) => Math.max(dist_default2(t2), n3), 0), g = e - (u2 - c);
18508
18630
  return wrapAnsi(o, g, a2);
18509
18631
  };
18510
18632
  var note = (o = "", e = "", s) => {
18511
18633
  const a2 = s?.output ?? process$1.stdout, i = s?.withGuide ?? settings.withGuide, c = s?.format ?? W$1, g = ["", ...C(o, getColumns(a2) - 6, c).split(`
18512
- `).map(c), ""], n2 = dist_default2(e), t2 = Math.max(g.reduce((m, F) => {
18634
+ `).map(c), ""], n3 = dist_default2(e), t2 = Math.max(g.reduce((m, F) => {
18513
18635
  const O = dist_default2(F);
18514
18636
  return O > m ? O : m;
18515
- }, 0), n2) + 2, h2 = g.map((m) => `${styleText2("gray", S_BAR)} ${m}${" ".repeat(t2 - dist_default2(m))}${styleText2("gray", S_BAR)}`).join(`
18637
+ }, 0), n3) + 2, h2 = g.map((m) => `${styleText2("gray", S_BAR)} ${m}${" ".repeat(t2 - dist_default2(m))}${styleText2("gray", S_BAR)}`).join(`
18516
18638
  `), T = i ? `${styleText2("gray", S_BAR)}
18517
18639
  ` : "", l$1 = i ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;
18518
- a2.write(`${T}${styleText2("green", S_STEP_SUBMIT)} ${styleText2("reset", e)} ${styleText2("gray", S_BAR_H.repeat(Math.max(t2 - n2 - 1, 1)) + S_CORNER_TOP_RIGHT)}
18640
+ a2.write(`${T}${styleText2("green", S_STEP_SUBMIT)} ${styleText2("reset", e)} ${styleText2("gray", S_BAR_H.repeat(Math.max(t2 - n3 - 1, 1)) + S_CORNER_TOP_RIGHT)}
18519
18641
  ${h2}
18520
18642
  ${styleText2("gray", l$1 + S_BAR_H.repeat(t2 + 2) + S_CORNER_BOTTOM_RIGHT)}
18521
18643
  `);
@@ -18529,8 +18651,71 @@ var SELECT_INSTRUCTIONS = [
18529
18651
  `${styleText2("dim", "\u2191/\u2193")} to navigate`,
18530
18652
  `${styleText2("dim", "Enter:")} confirm`
18531
18653
  ];
18654
+ var c = (t2, o) => t2.includes(`
18655
+ `) ? t2.split(`
18656
+ `).map((d) => o(d)).join(`
18657
+ `) : o(t2);
18658
+ var select = (t2) => {
18659
+ const o = (n3, m) => {
18660
+ if (n3 === undefined)
18661
+ return "";
18662
+ const s = n3.label ?? String(n3.value);
18663
+ switch (m) {
18664
+ case "disabled":
18665
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c(s, (i) => styleText2("gray", i))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
18666
+ case "selected":
18667
+ return `${c(s, (i) => styleText2("dim", i))}`;
18668
+ case "active":
18669
+ return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n3.hint ? ` ${styleText2("dim", `(${n3.hint})`)}` : ""}`;
18670
+ case "cancelled":
18671
+ return `${c(s, (i) => styleText2(["strikethrough", "dim"], i))}`;
18672
+ default:
18673
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c(s, (i) => styleText2("dim", i))}`;
18674
+ }
18675
+ }, d = t2.showInstructions ?? true;
18676
+ return new n$1({
18677
+ options: t2.options,
18678
+ signal: t2.signal,
18679
+ input: t2.input,
18680
+ output: t2.output,
18681
+ initialValue: t2.initialValue,
18682
+ render() {
18683
+ const n3 = t2.withGuide ?? settings.withGuide, m = `${symbol2(this.state)} `, s = `${symbolBar(this.state)} `, i = wrapTextWithPrefix(t2.output, t2.message, s, m), u3 = `${n3 ? `${styleText2("gray", S_BAR)}
18684
+ ` : ""}${i}
18685
+ `;
18686
+ switch (this.state) {
18687
+ case "submit": {
18688
+ const r2 = n3 ? `${styleText2("gray", S_BAR)} ` : "", a2 = wrapTextWithPrefix(t2.output, o(this.options[this.cursor], "selected"), r2);
18689
+ return `${u3}${a2}`;
18690
+ }
18691
+ case "cancel": {
18692
+ const r2 = n3 ? `${styleText2("gray", S_BAR)} ` : "", a2 = wrapTextWithPrefix(t2.output, o(this.options[this.cursor], "cancelled"), r2);
18693
+ return `${u3}${a2}${n3 ? `
18694
+ ${styleText2("gray", S_BAR)}` : ""}`;
18695
+ }
18696
+ default: {
18697
+ const r2 = n3 ? `${styleText2("cyan", S_BAR)} ` : "", a2 = u3.split(`
18698
+ `).length, p = d ? formatInstructionFooter(SELECT_INSTRUCTIONS, n3) : n3 ? [styleText2("cyan", S_BAR_END)] : [], b = p.join(`
18699
+ `), f = p.length + 1;
18700
+ return `${u3}${r2}${limitOptions({
18701
+ output: t2.output,
18702
+ cursor: this.cursor,
18703
+ options: this.options,
18704
+ maxItems: t2.maxItems,
18705
+ columnPadding: r2.length,
18706
+ rowPadding: a2 + f,
18707
+ style: (g, x) => o(g, g.disabled ? "disabled" : x ? "active" : "inactive")
18708
+ }).join(`
18709
+ ${r2}`)}
18710
+ ${b}
18711
+ `;
18712
+ }
18713
+ }
18714
+ }
18715
+ }).prompt();
18716
+ };
18532
18717
  var i = `${styleText2("gray", S_BAR)} `;
18533
- var text = (e) => new n({
18718
+ var text = (e) => new n2({
18534
18719
  validate: e.validate,
18535
18720
  placeholder: e.placeholder,
18536
18721
  defaultValue: e.defaultValue,
@@ -18541,27 +18726,27 @@ var text = (e) => new n({
18541
18726
  render() {
18542
18727
  const i2 = e?.withGuide ?? settings.withGuide, s = `${`${i2 ? `${styleText2("gray", S_BAR)}
18543
18728
  ` : ""}${symbol2(this.state)} `}${e.message}
18544
- `, c = e.placeholder && e.placeholder.length > 0 ? styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor : c, l = this.value ?? "";
18729
+ `, c2 = e.placeholder && e.placeholder.length > 0 ? styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor : c2, l = this.value ?? "";
18545
18730
  switch (this.state) {
18546
18731
  case "error": {
18547
- const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
18732
+ const n3 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
18548
18733
  return `${s.trim()}
18549
18734
  ${r2}${o}
18550
- ${d}${n2}
18735
+ ${d}${n3}
18551
18736
  `;
18552
18737
  }
18553
18738
  case "submit": {
18554
- const n2 = l ? ` ${styleText2("dim", l)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
18555
- return `${s}${r2}${n2}`;
18739
+ const n3 = l ? ` ${styleText2("dim", l)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
18740
+ return `${s}${r2}${n3}`;
18556
18741
  }
18557
18742
  case "cancel": {
18558
- const n2 = l ? ` ${styleText2(["strikethrough", "dim"], l)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
18559
- return `${s}${r2}${n2}${l.trim() ? `
18743
+ const n3 = l ? ` ${styleText2(["strikethrough", "dim"], l)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
18744
+ return `${s}${r2}${n3}${l.trim() ? `
18560
18745
  ${r2}` : ""}`;
18561
18746
  }
18562
18747
  default: {
18563
- const n2 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
18564
- return `${s}${n2}${o}
18748
+ const n3 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
18749
+ return `${s}${n3}${o}
18565
18750
  ${r2}
18566
18751
  `;
18567
18752
  }
@@ -18597,7 +18782,7 @@ async function runSetupPrompts(deps, opts) {
18597
18782
  }
18598
18783
  }
18599
18784
  const taskSystemAns = await confirm({
18600
- message: "Enable new task system (experimental.task_system)?",
18785
+ message: "Enable task system (tasks.enabled)?",
18601
18786
  initialValue: true
18602
18787
  });
18603
18788
  if (isCancel(taskSystemAns)) {
@@ -18698,7 +18883,7 @@ async function runSetupPrompts(deps, opts) {
18698
18883
  }
18699
18884
 
18700
18885
  // src/cli/setup/index.ts
18701
- import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
18886
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
18702
18887
 
18703
18888
  // src/cli/setup/config-writer.ts
18704
18889
  import { existsSync as existsSync14, mkdirSync as mkdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync3 } from "fs";
@@ -18743,9 +18928,9 @@ function resolveMatrixxConfigPath() {
18743
18928
  }
18744
18929
  function buildMatrixxConfig(state, existing) {
18745
18930
  const next = { ...existing ?? {} };
18746
- next.experimental = {
18747
- ...existing?.experimental ?? {},
18748
- task_system: state.taskSystem
18931
+ next.tasks = {
18932
+ ...existing?.tasks ?? {},
18933
+ enabled: state.taskSystem
18749
18934
  };
18750
18935
  next.headroom = {
18751
18936
  enabled: state.headroom.enabled,
@@ -18761,6 +18946,13 @@ function buildMatrixxConfig(state, existing) {
18761
18946
  ...existing?.dcp ?? {},
18762
18947
  enabled: state.dcp.enabled
18763
18948
  };
18949
+ if (state.preset) {
18950
+ next.model_presets = {
18951
+ ...existing?.model_presets ?? {},
18952
+ [state.preset.name]: state.preset.preset
18953
+ };
18954
+ next.active_preset = state.preset.name;
18955
+ }
18764
18956
  const parsed = MatrixxConfigSchema.safeParse(next);
18765
18957
  if (parsed.success)
18766
18958
  return parsed.data;
@@ -18861,8 +19053,8 @@ async function syncOpencodePlugins(state, opts) {
18861
19053
  } else {
18862
19054
  const fallback = join16(dir, "opencode.jsonc");
18863
19055
  if (existsSync15(fallback)) {
18864
- const c = readFileSync13(fallback, "utf-8");
18865
- const p = parseJsoncSafe(c);
19056
+ const c2 = readFileSync13(fallback, "utf-8");
19057
+ const p = parseJsoncSafe(c2);
18866
19058
  if (p.data)
18867
19059
  raw = p.data;
18868
19060
  }
@@ -18887,6 +19079,229 @@ async function syncOpencodePlugins(state, opts) {
18887
19079
  `);
18888
19080
  }
18889
19081
 
19082
+ // src/shared/model-availability.ts
19083
+ import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
19084
+ import { join as join17 } from "path";
19085
+
19086
+ // src/shared/normalize-sdk-response.ts
19087
+ function normalizeSDKResponse(response, fallback, options) {
19088
+ if (response === null || response === undefined) {
19089
+ return fallback;
19090
+ }
19091
+ if (Array.isArray(response)) {
19092
+ return response;
19093
+ }
19094
+ if (typeof response === "object" && "data" in response) {
19095
+ const data = response.data;
19096
+ if (data !== null && data !== undefined) {
19097
+ return data;
19098
+ }
19099
+ if (options?.preferResponseOnMissingData === true) {
19100
+ return response;
19101
+ }
19102
+ return fallback;
19103
+ }
19104
+ if (options?.preferResponseOnMissingData === true) {
19105
+ return response;
19106
+ }
19107
+ return fallback;
19108
+ }
19109
+
19110
+ // src/shared/model-availability.ts
19111
+ async function getConnectedProviders(client) {
19112
+ if (!client?.provider?.list) {
19113
+ log("[getConnectedProviders] client.provider.list not available");
19114
+ return [];
19115
+ }
19116
+ try {
19117
+ const result = await client.provider.list();
19118
+ const connected = result.data?.connected ?? [];
19119
+ log("[getConnectedProviders] connected providers", { count: connected.length, providers: connected });
19120
+ return connected;
19121
+ } catch (err) {
19122
+ log("[getConnectedProviders] SDK error", { error: String(err) });
19123
+ return [];
19124
+ }
19125
+ }
19126
+ async function fetchAvailableModels(client, options) {
19127
+ let connectedProviders = options?.connectedProviders ?? null;
19128
+ let connectedProvidersUnknown = connectedProviders === null;
19129
+ log("[fetchAvailableModels] CALLED", {
19130
+ connectedProvidersUnknown,
19131
+ connectedProviders: options?.connectedProviders
19132
+ });
19133
+ if (connectedProvidersUnknown && client) {
19134
+ const liveConnected = await getConnectedProviders(client);
19135
+ if (liveConnected.length > 0) {
19136
+ connectedProviders = liveConnected;
19137
+ connectedProvidersUnknown = false;
19138
+ log("[fetchAvailableModels] connected providers fetched from client", { count: liveConnected.length });
19139
+ }
19140
+ }
19141
+ if (connectedProvidersUnknown) {
19142
+ if (client?.model?.list) {
19143
+ const modelSet2 = new Set;
19144
+ try {
19145
+ const modelsResult = await client.model.list();
19146
+ const models = normalizeSDKResponse(modelsResult, []);
19147
+ for (const model of models) {
19148
+ if (model?.provider && model?.id) {
19149
+ modelSet2.add(`${model.provider}/${model.id}`);
19150
+ }
19151
+ }
19152
+ log("[fetchAvailableModels] fetched models from client without provider filter", {
19153
+ count: modelSet2.size
19154
+ });
19155
+ return modelSet2;
19156
+ } catch (err) {
19157
+ log("[fetchAvailableModels] client.model.list error", { error: String(err) });
19158
+ }
19159
+ }
19160
+ log("[fetchAvailableModels] connected providers unknown, returning empty set for fallback resolution");
19161
+ return new Set;
19162
+ }
19163
+ const connectedProvidersList = connectedProviders ?? [];
19164
+ const connectedSet = new Set(connectedProvidersList);
19165
+ const modelSet = new Set;
19166
+ const providerModelsCache = readProviderModelsCache();
19167
+ if (providerModelsCache) {
19168
+ const providerCount = Object.keys(providerModelsCache.models).length;
19169
+ if (providerCount === 0) {
19170
+ log("[fetchAvailableModels] provider-models cache empty, falling back to models.json");
19171
+ } else {
19172
+ log("[fetchAvailableModels] using provider-models cache (whitelist-filtered)");
19173
+ const modelsByProvider = providerModelsCache.models;
19174
+ for (const [providerId, modelIds] of Object.entries(modelsByProvider)) {
19175
+ if (!connectedSet.has(providerId)) {
19176
+ continue;
19177
+ }
19178
+ for (const modelItem of modelIds) {
19179
+ const modelId = typeof modelItem === "string" ? modelItem : modelItem?.id;
19180
+ if (modelId) {
19181
+ modelSet.add(`${providerId}/${modelId}`);
19182
+ }
19183
+ }
19184
+ }
19185
+ log("[fetchAvailableModels] parsed from provider-models cache", {
19186
+ count: modelSet.size,
19187
+ connectedProviders: connectedProvidersList.slice(0, 5)
19188
+ });
19189
+ if (modelSet.size > 0) {
19190
+ return modelSet;
19191
+ }
19192
+ log("[fetchAvailableModels] provider-models cache produced no models for connected providers, falling back to models.json");
19193
+ }
19194
+ }
19195
+ log("[fetchAvailableModels] provider-models cache not found, falling back to models.json");
19196
+ const cacheFile = join17(getOpenCodeCacheDir(), "models.json");
19197
+ if (!existsSync16(cacheFile)) {
19198
+ log("[fetchAvailableModels] models.json cache file not found, falling back to client");
19199
+ } else {
19200
+ try {
19201
+ const content = readFileSync14(cacheFile, "utf-8");
19202
+ const data = JSON.parse(content);
19203
+ const providerIds = Object.keys(data);
19204
+ log("[fetchAvailableModels] providers found in models.json", { count: providerIds.length, providers: providerIds.slice(0, 10) });
19205
+ for (const providerId of providerIds) {
19206
+ if (!connectedSet.has(providerId)) {
19207
+ continue;
19208
+ }
19209
+ const provider = data[providerId];
19210
+ const models = provider?.models;
19211
+ if (!models || typeof models !== "object")
19212
+ continue;
19213
+ for (const modelKey of Object.keys(models)) {
19214
+ modelSet.add(`${providerId}/${modelKey}`);
19215
+ }
19216
+ }
19217
+ log("[fetchAvailableModels] parsed models from models.json (NO whitelist filtering)", {
19218
+ count: modelSet.size,
19219
+ connectedProviders: connectedProvidersList.slice(0, 5)
19220
+ });
19221
+ if (modelSet.size > 0) {
19222
+ return modelSet;
19223
+ }
19224
+ } catch (err) {
19225
+ log("[fetchAvailableModels] error", { error: String(err) });
19226
+ }
19227
+ }
19228
+ if (client?.model?.list) {
19229
+ try {
19230
+ const modelsResult = await client.model.list();
19231
+ const models = normalizeSDKResponse(modelsResult, []);
19232
+ for (const model of models) {
19233
+ if (!model?.provider || !model?.id)
19234
+ continue;
19235
+ if (connectedSet.has(model.provider)) {
19236
+ modelSet.add(`${model.provider}/${model.id}`);
19237
+ }
19238
+ }
19239
+ log("[fetchAvailableModels] fetched models from client (filtered)", {
19240
+ count: modelSet.size,
19241
+ connectedProviders: connectedProvidersList.slice(0, 5)
19242
+ });
19243
+ } catch (err) {
19244
+ log("[fetchAvailableModels] client.model.list error", { error: String(err) });
19245
+ }
19246
+ }
19247
+ return modelSet;
19248
+ }
19249
+
19250
+ // src/cli/setup/preset-wizard.ts
19251
+ var NO_CONNECTED_PROVIDERS_ERROR = "No connected providers detected. Configure at least one provider in OpenCode (opencode auth login), then re-run: bunx opencode-matrixx setup";
19252
+ function buildDefaultPreset(model, agentNames, categoryNames) {
19253
+ return {
19254
+ default_model: model,
19255
+ agents: Object.fromEntries(agentNames.map((name) => [name, { model }])),
19256
+ categories: Object.fromEntries(categoryNames.map((name) => [name, { model }]))
19257
+ };
19258
+ }
19259
+ async function detectAvailableModels() {
19260
+ const connected = readConnectedProvidersCache();
19261
+ return fetchAvailableModels(undefined, {
19262
+ connectedProviders: connected && connected.length > 0 ? connected : undefined
19263
+ });
19264
+ }
19265
+ async function runPresetWizard(opts) {
19266
+ if (opts.skip)
19267
+ return { status: "skipped" };
19268
+ const models = await detectAvailableModels();
19269
+ if (models.size === 0) {
19270
+ return { status: "no-providers", error: NO_CONNECTED_PROVIDERS_ERROR };
19271
+ }
19272
+ const generate = await confirm({
19273
+ message: "Generate a default model preset from your connected providers?",
19274
+ initialValue: true
19275
+ });
19276
+ if (isCancel(generate)) {
19277
+ cancel("Cancelled");
19278
+ process.exit(130);
19279
+ }
19280
+ if (!generate)
19281
+ return { status: "skipped" };
19282
+ const nameAns = await text({
19283
+ message: "Preset name?",
19284
+ initialValue: "default"
19285
+ });
19286
+ if (isCancel(nameAns)) {
19287
+ cancel("Cancelled");
19288
+ process.exit(130);
19289
+ }
19290
+ const name = nameAns.trim() || "default";
19291
+ const modelOptions = [...models].sort().map((model) => ({ value: model, label: model }));
19292
+ const modelAns = await select({
19293
+ message: "Default model for all agents and categories?",
19294
+ options: modelOptions,
19295
+ initialValue: modelOptions[0]?.value
19296
+ });
19297
+ if (isCancel(modelAns)) {
19298
+ cancel("Cancelled");
19299
+ process.exit(130);
19300
+ }
19301
+ const preset = buildDefaultPreset(modelAns, BuiltinAgentNameSchema.options, BuiltinCategoryNameSchema.options);
19302
+ return { status: "generated", name, preset };
19303
+ }
19304
+
18890
19305
  // src/cli/setup/index.ts
18891
19306
  async function executeSetup(opts) {
18892
19307
  const required2 = checkRequiredDeps();
@@ -18909,14 +19324,21 @@ Install them and re-run: bunx opencode-matrixx setup`;
18909
19324
  } catch {}
18910
19325
  if (!existing) {
18911
19326
  try {
18912
- const raw = readFileSync14(matrixxPath, "utf-8");
19327
+ const raw = readFileSync15(matrixxPath, "utf-8");
18913
19328
  if (raw.trim())
18914
19329
  existing = JSON.parse(raw);
18915
19330
  } catch {}
18916
19331
  }
18917
- const nextConfig = buildMatrixxConfig(state, existing);
18918
- if (existing && !opts.yes && !opts.dryRun && existsSync16(matrixxPath)) {
18919
- const existingContent = readFileSync14(matrixxPath, "utf-8");
19332
+ const presetResult = await runPresetWizard({
19333
+ skip: (opts.skipPresets ?? false) || opts.yes || Boolean(existing?.model_presets)
19334
+ });
19335
+ if (presetResult.status === "no-providers") {
19336
+ return presetResult.error;
19337
+ }
19338
+ const stateWithPreset = presetResult.status === "generated" ? { ...state, preset: { name: presetResult.name, preset: presetResult.preset } } : state;
19339
+ const nextConfig = buildMatrixxConfig(stateWithPreset, existing);
19340
+ if (existing && !opts.yes && !opts.dryRun && existsSync17(matrixxPath)) {
19341
+ const existingContent = readFileSync15(matrixxPath, "utf-8");
18920
19342
  const nextContent = `${JSON.stringify(nextConfig, null, 2)}
18921
19343
  `;
18922
19344
  note(previewDiff(existingContent, nextContent).slice(0, 2000), "Diff preview (existing \u2192 new)");
@@ -18943,7 +19365,8 @@ Run with --yes to overwrite without prompt.`;
18943
19365
  report,
18944
19366
  "",
18945
19367
  `\u2713 matrixx.jsonc \u2192 ${matrixxPath}${opts.dryRun ? " (preview)" : ""}`,
18946
- ` task_system: ${state.taskSystem}, headroom: ${state.headroom.enabled}, rtk: ${state.rtk.enabled}, dcp: ${state.dcp.enabled}, context-mode: ${state.contextMode}`,
19368
+ ` tasks.enabled: ${state.taskSystem}, headroom: ${state.headroom.enabled}, rtk: ${state.rtk.enabled}, dcp: ${state.dcp.enabled}, context-mode: ${state.contextMode}`,
19369
+ stateWithPreset.preset ? ` model preset: ${stateWithPreset.preset.name} (active_preset)` : "",
18947
19370
  "",
18948
19371
  "Next steps:",
18949
19372
  " 1. Restart OpenCode to load new config",
@@ -18961,13 +19384,13 @@ function getVersion() {
18961
19384
  try {
18962
19385
  const thisDir = dirname3(fileURLToPath(import.meta.url));
18963
19386
  const candidates = [
18964
- join17(thisDir, "../../package.json"),
18965
- join17(thisDir, "../package.json"),
19387
+ join18(thisDir, "../../package.json"),
19388
+ join18(thisDir, "../package.json"),
18966
19389
  "package.json"
18967
19390
  ];
18968
19391
  for (const p of candidates) {
18969
19392
  try {
18970
- const raw = readFileSync15(p, "utf-8");
19393
+ const raw = readFileSync16(p, "utf-8");
18971
19394
  const pkg = JSON.parse(raw);
18972
19395
  if (pkg.version && typeof pkg.version === "string")
18973
19396
  return pkg.version;
@@ -18999,6 +19422,7 @@ Options:
18999
19422
  --verbose (install) Display detailed logs
19000
19423
  --yes, -y (setup) Non-interactive defaults (no prompts)
19001
19424
  --dry-run (setup) Preview changes without writing
19425
+ --skip-presets (setup) Skip model preset generation (headless/CI)
19002
19426
 
19003
19427
  Doctor categories:
19004
19428
  installation Plugin registration and OpenCode version
@@ -19026,6 +19450,7 @@ function parseArgs(argv) {
19026
19450
  local: false,
19027
19451
  yes: false,
19028
19452
  dryRun: false,
19453
+ skipPresets: false,
19029
19454
  extra: []
19030
19455
  };
19031
19456
  let args = argv.slice(2);
@@ -19045,6 +19470,8 @@ function parseArgs(argv) {
19045
19470
  result.yes = true;
19046
19471
  } else if (a2 === "--dry-run") {
19047
19472
  result.dryRun = true;
19473
+ } else if (a2 === "--skip-presets") {
19474
+ result.skipPresets = true;
19048
19475
  } else if (a2 === "--no-tui") {
19049
19476
  result.noTui = true;
19050
19477
  } else if (a2 === "--local") {
@@ -19119,7 +19546,7 @@ async function main() {
19119
19546
  return;
19120
19547
  }
19121
19548
  if (args.command === "setup") {
19122
- const output = await executeSetup({ dryRun: args.dryRun, yes: args.yes });
19549
+ const output = await executeSetup({ dryRun: args.dryRun, yes: args.yes, skipPresets: args.skipPresets });
19123
19550
  console.log(output);
19124
19551
  return;
19125
19552
  }