@kimbho/kimbho-cli 0.1.16 → 0.1.19

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/dist/index.cjs CHANGED
@@ -10612,7 +10612,7 @@ var {
10612
10612
  // package.json
10613
10613
  var package_default = {
10614
10614
  name: "@kimbho/kimbho-cli",
10615
- version: "0.1.16",
10615
+ version: "0.1.19",
10616
10616
  description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
10617
10617
  type: "module",
10618
10618
  engines: {
@@ -15029,7 +15029,9 @@ var PlanTaskSchema = external_exports.object({
15029
15029
  swarmDepth: external_exports.number().int().nonnegative().optional(),
15030
15030
  customAgentId: external_exports.string().min(1).optional(),
15031
15031
  teamId: external_exports.string().min(1).optional(),
15032
- teamMemberIds: external_exports.array(external_exports.string()).optional()
15032
+ teamMemberIds: external_exports.array(external_exports.string()).optional(),
15033
+ subagentLabel: external_exports.string().min(1).optional(),
15034
+ subagentInstructions: external_exports.string().min(1).optional()
15033
15035
  });
15034
15036
  var PlanMilestoneSchema = external_exports.object({
15035
15037
  id: external_exports.string().min(1),
@@ -16122,6 +16124,10 @@ async function loadCustomAgents(cwd) {
16122
16124
  ];
16123
16125
  });
16124
16126
  }
16127
+ async function loadCustomAgentById(cwd, id) {
16128
+ const agents = await loadCustomAgents(cwd);
16129
+ return agents.find((agent) => agent.id === id) ?? null;
16130
+ }
16125
16131
  async function loadAgentTeams(cwd) {
16126
16132
  const records = await loadMarkdownRecords(resolveAgentTeamDir(cwd));
16127
16133
  return records.map(({ filePath, source }) => {
@@ -16140,6 +16146,10 @@ async function loadAgentTeams(cwd) {
16140
16146
  };
16141
16147
  });
16142
16148
  }
16149
+ async function loadAgentTeamById(cwd, id) {
16150
+ const teams = await loadAgentTeams(cwd);
16151
+ return teams.find((team) => team.id === id) ?? null;
16152
+ }
16143
16153
  async function createCustomAgentFile(cwd, id, baseRole, options = {}) {
16144
16154
  const directory = resolveCustomAgentDir(cwd);
16145
16155
  const filePath = import_node_path5.default.join(directory, `${id}.md`);
@@ -16174,6 +16184,11 @@ async function createCustomAgentFile(cwd, id, baseRole, options = {}) {
16174
16184
  `, "utf8");
16175
16185
  return filePath;
16176
16186
  }
16187
+ async function deleteCustomAgentFile(cwd, id) {
16188
+ const filePath = import_node_path5.default.join(resolveCustomAgentDir(cwd), `${id}.md`);
16189
+ await (0, import_promises5.rm)(filePath);
16190
+ return filePath;
16191
+ }
16177
16192
  async function createAgentTeamFile(cwd, id, agentIds, label) {
16178
16193
  const directory = resolveAgentTeamDir(cwd);
16179
16194
  const filePath = import_node_path5.default.join(directory, `${id}.md`);
@@ -16197,6 +16212,11 @@ async function createAgentTeamFile(cwd, id, agentIds, label) {
16197
16212
  `, "utf8");
16198
16213
  return filePath;
16199
16214
  }
16215
+ async function deleteAgentTeamFile(cwd, id) {
16216
+ const filePath = import_node_path5.default.join(resolveAgentTeamDir(cwd), `${id}.md`);
16217
+ await (0, import_promises5.rm)(filePath);
16218
+ return filePath;
16219
+ }
16200
16220
  function scoreCustomAgentMatch(definition, task, request) {
16201
16221
  if (definition.baseRole !== task.agentRole) {
16202
16222
  return -1;
@@ -18288,6 +18308,46 @@ var KNOWN_SCAFFOLD_PRESETS = [
18288
18308
  "static-landing",
18289
18309
  "kimbho-cli-monorepo"
18290
18310
  ];
18311
+ function inferVisualAdjustment(goal) {
18312
+ const normalized = goal.toLowerCase();
18313
+ if (!normalized.includes("background") && !normalized.includes("gradient") && !normalized.includes("theme")) {
18314
+ return null;
18315
+ }
18316
+ if (normalized.includes("green")) {
18317
+ return {
18318
+ summaryLabel: "green background",
18319
+ background: "linear-gradient(180deg, #f4fff6 0%, #d8f3dc 100%)"
18320
+ };
18321
+ }
18322
+ if (normalized.includes("amber") || normalized.includes("gold") || normalized.includes("orange")) {
18323
+ return {
18324
+ summaryLabel: "amber background",
18325
+ background: "linear-gradient(180deg, #fff8e7 0%, #f7d08a 100%)"
18326
+ };
18327
+ }
18328
+ if (normalized.includes("blue")) {
18329
+ return {
18330
+ summaryLabel: "blue background",
18331
+ background: "linear-gradient(180deg, #eef6ff 0%, #cfe3ff 100%)"
18332
+ };
18333
+ }
18334
+ if (normalized.includes("pink") || normalized.includes("rose")) {
18335
+ return {
18336
+ summaryLabel: "rose background",
18337
+ background: "linear-gradient(180deg, #fff3f8 0%, #ffd6e7 100%)"
18338
+ };
18339
+ }
18340
+ if (normalized.includes("purple") || normalized.includes("violet")) {
18341
+ return {
18342
+ summaryLabel: "violet background",
18343
+ background: "linear-gradient(180deg, #f6f2ff 0%, #ddd1ff 100%)"
18344
+ };
18345
+ }
18346
+ return null;
18347
+ }
18348
+ function looksLikeVisualAdjustmentGoal(value) {
18349
+ return inferVisualAdjustment(value) !== null;
18350
+ }
18291
18351
  function looksLikeStaticLandingGoal(value) {
18292
18352
  const normalized = value.toLowerCase();
18293
18353
  const backendSignals = [
@@ -18346,6 +18406,9 @@ function looksLikeStaticLandingGoal(value) {
18346
18406
  if (normalized.includes("blog") && (normalized.includes("make") || normalized.includes("improve") || normalized.includes("enhance") || normalized.includes("redesign")) && !backendSignals.some((signal) => normalized.includes(signal))) {
18347
18407
  return true;
18348
18408
  }
18409
+ if (looksLikeVisualAdjustmentGoal(normalized) && !backendSignals.some((signal) => normalized.includes(signal))) {
18410
+ return true;
18411
+ }
18349
18412
  return false;
18350
18413
  }
18351
18414
  function sanitizeName(value) {
@@ -18573,7 +18636,76 @@ async function detectExistingStaticTarget(cwd) {
18573
18636
  }
18574
18637
  return null;
18575
18638
  }
18639
+ function rewriteBackgroundInSource(source, background) {
18640
+ const inlinePatterns = [
18641
+ [/background:\s*'[^']*'/, `background: '${background}'`],
18642
+ [/background:\s*"[^"]*"/, `background: "${background}"`],
18643
+ [/background:\s*`[^`]*`/, `background: \`${background}\``]
18644
+ ];
18645
+ for (const [pattern, replacement] of inlinePatterns) {
18646
+ if (pattern.test(source)) {
18647
+ return source.replace(pattern, replacement);
18648
+ }
18649
+ }
18650
+ const cssPatterns = [
18651
+ [/background:\s*[^;]+;/, `background: ${background};`],
18652
+ [/background-color:\s*[^;]+;/, `background: ${background};`]
18653
+ ];
18654
+ for (const [pattern, replacement] of cssPatterns) {
18655
+ if (pattern.test(source)) {
18656
+ return source.replace(pattern, replacement);
18657
+ }
18658
+ }
18659
+ return source;
18660
+ }
18661
+ async function applyExistingStaticVisualAdjustment(cwd, goal, target) {
18662
+ const adjustment = inferVisualAdjustment(goal);
18663
+ if (!adjustment) {
18664
+ return null;
18665
+ }
18666
+ const candidatePaths = [
18667
+ target.pagePath,
18668
+ target.kind === "next-app" ? "src/app/globals.css" : null,
18669
+ target.kind === "next-pages" ? "styles.css" : null,
18670
+ target.kind === "static-html" ? "styles.css" : null
18671
+ ].filter((value) => Boolean(value));
18672
+ for (const relativePath of candidatePaths) {
18673
+ const absolutePath = import_node_path10.default.join(cwd, relativePath);
18674
+ if (!await pathExists(absolutePath)) {
18675
+ continue;
18676
+ }
18677
+ const currentSource = await (0, import_promises10.readFile)(absolutePath, "utf8");
18678
+ if (currentSource.includes(adjustment.background)) {
18679
+ return {
18680
+ preset: "static-landing",
18681
+ projectName: inferProjectName(goal, cwd),
18682
+ summary: `${relativePath} already uses the requested ${adjustment.summaryLabel}.`,
18683
+ artifacts: [
18684
+ absolutePath
18685
+ ]
18686
+ };
18687
+ }
18688
+ const nextSource = rewriteBackgroundInSource(currentSource, adjustment.background);
18689
+ if (nextSource === currentSource) {
18690
+ continue;
18691
+ }
18692
+ const artifacts = await writeFiles(cwd, {
18693
+ [relativePath]: nextSource
18694
+ });
18695
+ return {
18696
+ preset: "static-landing",
18697
+ projectName: inferProjectName(goal, cwd),
18698
+ summary: `Updated ${relativePath} with a ${adjustment.summaryLabel}.`,
18699
+ artifacts
18700
+ };
18701
+ }
18702
+ return null;
18703
+ }
18576
18704
  async function adaptExistingStaticLanding(cwd, projectName, goal, target) {
18705
+ const adjustedResult = await applyExistingStaticVisualAdjustment(cwd, goal, target);
18706
+ if (adjustedResult) {
18707
+ return adjustedResult;
18708
+ }
18577
18709
  const title = inferLandingTitle(goal, projectName);
18578
18710
  const content = buildLandingContent(title, inferLandingKind(goal));
18579
18711
  const files = {};
@@ -19362,6 +19494,9 @@ function isVerificationShellCommand(command) {
19362
19494
  const normalized = command.trim().toLowerCase();
19363
19495
  return VERIFICATION_SHELL_PREFIXES.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix} `));
19364
19496
  }
19497
+ function isLowRiskScaffoldRequest(input) {
19498
+ return input.preset === "static-landing" && typeof input.goal === "string" && looksLikeVisualAdjustmentGoal(input.goal);
19499
+ }
19365
19500
  function isDestructiveShellCommand(command) {
19366
19501
  return DESTRUCTIVE_SHELL_PATTERNS.some((pattern) => pattern.test(command));
19367
19502
  }
@@ -19430,8 +19565,9 @@ function enforceToolPolicy(toolId, input, descriptor, context) {
19430
19565
  const sandboxMode = context.sandboxMode ?? "workspace-write";
19431
19566
  const approvalMode = context.approvalMode ?? "manual";
19432
19567
  const command = typeof input.command === "string" ? input.command : "";
19568
+ const isVerificationCommand2 = isVerificationShellCommand(command);
19433
19569
  if (sandboxMode === "read-only") {
19434
- if (toolId === "shell.exec" && (isReadOnlyShellCommand(command) || isVerificationShellCommand(command))) {
19570
+ if ((toolId === "shell.exec" || toolId === "tests.run") && (isReadOnlyShellCommand(command) || isVerificationCommand2)) {
19435
19571
  return null;
19436
19572
  }
19437
19573
  if (descriptor.permission !== "safe") {
@@ -19443,7 +19579,10 @@ function enforceToolPolicy(toolId, input, descriptor, context) {
19443
19579
  return new ToolApprovalRequiredError(createApprovalRequest(toolId, input, descriptor, context, `Approval required for destructive shell command: ${command}`));
19444
19580
  }
19445
19581
  }
19446
- if (toolId === "shell.exec" && isVerificationShellCommand(command)) {
19582
+ if ((toolId === "shell.exec" || toolId === "tests.run") && isVerificationCommand2) {
19583
+ return null;
19584
+ }
19585
+ if (toolId === "scaffold.generate" && isLowRiskScaffoldRequest(input)) {
19447
19586
  return null;
19448
19587
  }
19449
19588
  if ((toolId === "file.write" || toolId === "file.patch") && sandboxMode === "workspace-write") {
@@ -27624,6 +27763,37 @@ var MCP_INVENTORY_TIMEOUT_MS = 8e3;
27624
27763
  function toMcpToolId(serverName, toolName) {
27625
27764
  return `mcp.${serverName}.${toolName}`;
27626
27765
  }
27766
+ function normalizeMcpCommandSegment(value) {
27767
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
27768
+ }
27769
+ async function resolveMcpServerInventoryByReference(cwd, serverReference) {
27770
+ const inventory = await loadMcpServerInventory(cwd);
27771
+ const normalizedReference = normalizeMcpCommandSegment(serverReference);
27772
+ const server = inventory.find((candidate) => candidate.name === serverReference || normalizeMcpCommandSegment(candidate.name) === normalizedReference);
27773
+ if (!server) {
27774
+ throw new Error(`MCP server ${serverReference} is not configured or did not respond.`);
27775
+ }
27776
+ if (server.warning) {
27777
+ throw new Error(`MCP server ${server.name} is unavailable: ${server.warning}`);
27778
+ }
27779
+ return server;
27780
+ }
27781
+ async function resolveMcpPromptReference(cwd, serverReference, promptReference) {
27782
+ const server = await resolveMcpServerInventoryByReference(cwd, serverReference);
27783
+ const normalizedPromptReference = normalizeMcpCommandSegment(promptReference);
27784
+ const prompt = server.prompts.find((candidate) => candidate.name === promptReference || normalizeMcpCommandSegment(candidate.name) === normalizedPromptReference);
27785
+ if (!prompt) {
27786
+ throw new Error(`MCP prompt ${promptReference} was not found on server ${server.name}.`);
27787
+ }
27788
+ return {
27789
+ serverName: server.name,
27790
+ promptName: prompt.name
27791
+ };
27792
+ }
27793
+ async function resolveMcpServerName(cwd, serverReference) {
27794
+ const server = await resolveMcpServerInventoryByReference(cwd, serverReference);
27795
+ return server.name;
27796
+ }
27627
27797
  function permissionFromAnnotations(annotations) {
27628
27798
  if (annotations?.destructiveHint) {
27629
27799
  return "destructive";
@@ -27783,23 +27953,24 @@ async function discoverMcpTools(cwd) {
27783
27953
  }
27784
27954
  async function callMcpTool(cwd, serverName, toolName, input) {
27785
27955
  const config2 = await loadMcpConfig(cwd);
27786
- const server = config2.mcpServers[serverName];
27956
+ const resolvedServerName = await resolveMcpServerName(cwd, serverName).catch(() => serverName);
27957
+ const server = config2.mcpServers[resolvedServerName];
27787
27958
  if (!server || server.enabled === false) {
27788
27959
  return {
27789
- toolId: toMcpToolId(serverName, toolName),
27960
+ toolId: toMcpToolId(resolvedServerName, toolName),
27790
27961
  success: false,
27791
- summary: `MCP server ${serverName} is not configured or is disabled.`,
27962
+ summary: `MCP server ${resolvedServerName} is not configured or is disabled.`,
27792
27963
  artifacts: []
27793
27964
  };
27794
27965
  }
27795
- const result = await withMcpClient(cwd, serverName, server, async (client) => client.callTool({
27966
+ const result = await withMcpClient(cwd, resolvedServerName, server, async (client) => client.callTool({
27796
27967
  name: toolName,
27797
27968
  arguments: Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0))
27798
27969
  }));
27799
27970
  return {
27800
- toolId: toMcpToolId(serverName, toolName),
27971
+ toolId: toMcpToolId(resolvedServerName, toolName),
27801
27972
  success: !result.isError,
27802
- summary: result.isError ? `MCP tool ${serverName}/${toolName} reported an error.` : `Ran MCP tool ${serverName}/${toolName}.`,
27973
+ summary: result.isError ? `MCP tool ${resolvedServerName}/${toolName} reported an error.` : `Ran MCP tool ${resolvedServerName}/${toolName}.`,
27803
27974
  stdout: renderMcpContent(result),
27804
27975
  artifacts: []
27805
27976
  };
@@ -27821,18 +27992,19 @@ ${"text" in resource ? resource.text : `[binary ${resource.mimeType ?? "resource
27821
27992
  }).join("\n\n");
27822
27993
  }
27823
27994
  async function invokeMcpPrompt(cwd, serverName, promptName, args) {
27995
+ const { serverName: resolvedServerName, promptName: resolvedPromptName } = await resolveMcpPromptReference(cwd, serverName, promptName);
27824
27996
  const config2 = await loadMcpConfig(cwd);
27825
- const server = config2.mcpServers[serverName];
27997
+ const server = config2.mcpServers[resolvedServerName];
27826
27998
  if (!server || server.enabled === false) {
27827
- throw new Error(`MCP server ${serverName} is not configured or is disabled.`);
27999
+ throw new Error(`MCP server ${resolvedServerName} is not configured or is disabled.`);
27828
28000
  }
27829
- const result = await withMcpClient(cwd, serverName, server, async (client) => client.getPrompt({
27830
- name: promptName,
28001
+ const result = await withMcpClient(cwd, resolvedServerName, server, async (client) => client.getPrompt({
28002
+ name: resolvedPromptName,
27831
28003
  arguments: args
27832
28004
  }));
27833
28005
  return {
27834
- serverName,
27835
- promptName,
28006
+ serverName: resolvedServerName,
28007
+ promptName: resolvedPromptName,
27836
28008
  ...result.description ? {
27837
28009
  description: result.description
27838
28010
  } : {},
@@ -27840,19 +28012,20 @@ async function invokeMcpPrompt(cwd, serverName, promptName, args) {
27840
28012
  };
27841
28013
  }
27842
28014
  async function readMcpResource(cwd, serverName, uri) {
28015
+ const resolvedServerName = await resolveMcpServerName(cwd, serverName);
27843
28016
  const config2 = await loadMcpConfig(cwd);
27844
- const server = config2.mcpServers[serverName];
28017
+ const server = config2.mcpServers[resolvedServerName];
27845
28018
  if (!server || server.enabled === false) {
27846
- throw new Error(`MCP server ${serverName} is not configured or is disabled.`);
28019
+ throw new Error(`MCP server ${resolvedServerName} is not configured or is disabled.`);
27847
28020
  }
27848
- const result = await withMcpClient(cwd, serverName, server, async (client) => client.readResource({
28021
+ const result = await withMcpClient(cwd, resolvedServerName, server, async (client) => client.readResource({
27849
28022
  uri
27850
28023
  }));
27851
28024
  const content = result.contents.map((item) => "text" in item ? `resource: ${item.uri}
27852
28025
  ${item.text}` : `resource: ${item.uri}
27853
28026
  [binary ${item.mimeType ?? "resource"}]`).join("\n\n");
27854
28027
  return {
27855
- serverName,
28028
+ serverName: resolvedServerName,
27856
28029
  uri,
27857
28030
  content
27858
28031
  };
@@ -28070,6 +28243,9 @@ function buildSystemPrompt(agent, task, request, allowedTools, plan, extraInstru
28070
28243
  return [
28071
28244
  `You are Kimbho's ${agent.role}.`,
28072
28245
  `Purpose: ${agent.purpose}`,
28246
+ ...task.subagentLabel ? [
28247
+ `Delegated worker: ${task.subagentLabel}`
28248
+ ] : [],
28073
28249
  `Goal: ${request.goal}`,
28074
28250
  `Current task: ${task.id} - ${task.title}`,
28075
28251
  `Task description: ${task.description}`,
@@ -28103,6 +28279,10 @@ function buildSystemPrompt(agent, task, request, allowedTools, plan, extraInstru
28103
28279
  `- After changing code, run verification with tests.run or shell.exec when appropriate.`,
28104
28280
  `- Do not claim success unless the task acceptance criteria are satisfied.`,
28105
28281
  `- If the task is underspecified, make a pragmatic implementation choice and continue.`,
28282
+ ...task.subagentInstructions ? [
28283
+ `Delegation instructions:`,
28284
+ task.subagentInstructions
28285
+ ] : [],
28106
28286
  ...extraInstructions ? [
28107
28287
  `Custom instructions:`,
28108
28288
  extraInstructions
@@ -29168,6 +29348,66 @@ var import_node_path14 = __toESM(require("node:path"), 1);
29168
29348
  function normalizeGoal(goal) {
29169
29349
  return goal.trim().replace(/\s+/g, " ");
29170
29350
  }
29351
+ function looksLikeVisualAdjustmentGoal2(goal) {
29352
+ const lower = goal.toLowerCase();
29353
+ const backendSignals = [
29354
+ "api",
29355
+ "database",
29356
+ "backend",
29357
+ "server",
29358
+ "migration",
29359
+ "schema",
29360
+ "prisma",
29361
+ "postgres",
29362
+ "sqlite",
29363
+ "auth",
29364
+ "billing",
29365
+ "webhook"
29366
+ ];
29367
+ const editSignals = [
29368
+ "make",
29369
+ "change",
29370
+ "update",
29371
+ "turn",
29372
+ "switch",
29373
+ "set",
29374
+ "use",
29375
+ "refresh",
29376
+ "restyle",
29377
+ "redesign"
29378
+ ];
29379
+ const visualSignals = [
29380
+ "background",
29381
+ "color",
29382
+ "green",
29383
+ "amber",
29384
+ "blue",
29385
+ "pink",
29386
+ "purple",
29387
+ "gradient",
29388
+ "theme",
29389
+ "palette",
29390
+ "styling",
29391
+ "style",
29392
+ "look",
29393
+ "visual",
29394
+ "hero"
29395
+ ];
29396
+ const pageContextSignals = [
29397
+ "page",
29398
+ "landing",
29399
+ "lnding",
29400
+ "homepage",
29401
+ "home page",
29402
+ "site",
29403
+ "website",
29404
+ "blog"
29405
+ ];
29406
+ if (backendSignals.some((signal) => lower.includes(signal))) {
29407
+ return false;
29408
+ }
29409
+ return editSignals.some((signal) => lower.includes(signal)) && visualSignals.some((signal) => lower.includes(signal)) && (pageContextSignals.some((signal) => lower.includes(signal)) || lower.includes("background"));
29410
+ }
29171
29411
  function looksLikeStaticSiteGoal(goal) {
29172
29412
  const lower = goal.toLowerCase();
29173
29413
  const backendSignals = [
@@ -29226,6 +29466,9 @@ function looksLikeStaticSiteGoal(goal) {
29226
29466
  if (lower.includes("blog") && (lower.includes("make") || lower.includes("improve") || lower.includes("enhance") || lower.includes("redesign")) && !backendSignals.some((signal) => lower.includes(signal))) {
29227
29467
  return true;
29228
29468
  }
29469
+ if (looksLikeVisualAdjustmentGoal2(lower)) {
29470
+ return true;
29471
+ }
29229
29472
  return false;
29230
29473
  }
29231
29474
  function inferProjectShape(goal) {
@@ -31142,6 +31385,330 @@ function isStaticSiteTask(task, request) {
31142
31385
  }
31143
31386
  return task.filesLikelyTouched.some((filePath) => filePath === "src/app/page.tsx" || filePath === "src/app/layout.tsx" || filePath === "src/pages/index.tsx" || filePath === "index.html" || filePath === "styles.css");
31144
31387
  }
31388
+ function shouldDelegateTask(task, request) {
31389
+ if (looksLikeVisualAdjustmentGoal(request.goal) && isStaticSiteTask(task, request)) {
31390
+ return false;
31391
+ }
31392
+ return (task.swarmDepth ?? 0) === 0 && task.type === "implementation" && ![
31393
+ "repo-analyst",
31394
+ "planner",
31395
+ "reviewer",
31396
+ "integrator",
31397
+ "test-debugger",
31398
+ "session-orchestrator",
31399
+ "execution-manager"
31400
+ ].includes(task.agentRole);
31401
+ }
31402
+ function terminalExpansionTaskIds(tasks) {
31403
+ const referencedIds = new Set(tasks.flatMap((task) => task.dependsOn));
31404
+ const terminalIds = tasks.filter((task) => !referencedIds.has(task.id)).map((task) => task.id);
31405
+ return terminalIds.length > 0 ? terminalIds : tasks.map((task) => task.id);
31406
+ }
31407
+ function createDefaultDelegationPlan(task, request) {
31408
+ if (!shouldDelegateTask(task, request)) {
31409
+ return null;
31410
+ }
31411
+ if (task.agentRole === "frontend-specialist" || isStaticSiteTask(task, request)) {
31412
+ return {
31413
+ label: "auto-frontend-swarm",
31414
+ strategy: "parallel",
31415
+ members: [
31416
+ {
31417
+ id: "content-architect",
31418
+ label: "content-architect",
31419
+ agentRole: "frontend-specialist",
31420
+ description: "Own information architecture, page composition, navigation, copy structure, and section flow.",
31421
+ instructions: "Prioritize semantic layout, page structure, routes, content hierarchy, and component composition. Leave purely visual polish to the visual worker unless structure blocks it.",
31422
+ acceptanceCriteria: [
31423
+ "The page structure, sections, and navigation flow are clear and coherent.",
31424
+ "Content hierarchy reflects the requested product, brand, or venue."
31425
+ ],
31426
+ outputs: [
31427
+ "Structured page/content update"
31428
+ ]
31429
+ },
31430
+ {
31431
+ id: "visual-polisher",
31432
+ label: "visual-polisher",
31433
+ agentRole: "frontend-specialist",
31434
+ description: "Own styling, gradients, motion, responsiveness, spacing, and visual finishing.",
31435
+ instructions: "Focus on visual quality, gradients, motion, responsiveness, spacing, and interaction polish after inspecting the current structure. Keep edits aligned with the existing design language when present.",
31436
+ acceptanceCriteria: [
31437
+ "Visual styling and responsiveness are meaningfully improved.",
31438
+ "Motion and polish remain consistent with the requested UI direction."
31439
+ ],
31440
+ outputs: [
31441
+ "Visual polish update"
31442
+ ]
31443
+ }
31444
+ ]
31445
+ };
31446
+ }
31447
+ if (task.agentRole === "backend-specialist") {
31448
+ return {
31449
+ label: "auto-backend-swarm",
31450
+ strategy: "sequential",
31451
+ members: [
31452
+ {
31453
+ id: "contract-architect",
31454
+ label: "contract-architect",
31455
+ agentRole: "backend-specialist",
31456
+ description: "Define the API/service surface, request-response shapes, and failure behavior.",
31457
+ instructions: "Focus on service and API contracts, input/output shapes, handlers, and edge cases before broad implementation changes.",
31458
+ acceptanceCriteria: [
31459
+ "Contracts and failure cases are explicit.",
31460
+ "The implementation path is narrowed to concrete handlers or services."
31461
+ ],
31462
+ outputs: [
31463
+ "Backend contract design"
31464
+ ]
31465
+ },
31466
+ {
31467
+ id: "service-implementer",
31468
+ label: "service-implementer",
31469
+ agentRole: "backend-specialist",
31470
+ description: "Implement handlers, services, and domain logic against the agreed contract.",
31471
+ instructions: "Implement the core backend behavior against the established contract. Prefer targeted file edits and verification over broad rewrites.",
31472
+ acceptanceCriteria: [
31473
+ "Business logic is implemented against the contract.",
31474
+ "The backend behavior satisfies the task acceptance criteria."
31475
+ ],
31476
+ outputs: [
31477
+ "Backend implementation"
31478
+ ]
31479
+ }
31480
+ ]
31481
+ };
31482
+ }
31483
+ if (task.agentRole === "database-specialist") {
31484
+ return {
31485
+ label: "auto-database-swarm",
31486
+ strategy: "sequential",
31487
+ members: [
31488
+ {
31489
+ id: "schema-designer",
31490
+ label: "schema-designer",
31491
+ agentRole: "database-specialist",
31492
+ description: "Design models, fields, relations, constraints, and persistence boundaries.",
31493
+ instructions: "Focus on schema structure, data modeling, constraints, and identifiers. Keep the migration path safe and explicit.",
31494
+ acceptanceCriteria: [
31495
+ "Schema design reflects the requested domain.",
31496
+ "Constraints and data relationships are explicit."
31497
+ ],
31498
+ outputs: [
31499
+ "Schema design"
31500
+ ]
31501
+ },
31502
+ {
31503
+ id: "migration-planner",
31504
+ label: "migration-planner",
31505
+ agentRole: "database-specialist",
31506
+ description: "Apply or prepare migrations and persistence wiring around the approved schema.",
31507
+ instructions: "Translate the schema design into migrations or persistence updates. Keep destructive changes obvious and verification-friendly.",
31508
+ acceptanceCriteria: [
31509
+ "Persistence updates align with the intended schema.",
31510
+ "Migration risk and verification needs are explicit."
31511
+ ],
31512
+ outputs: [
31513
+ "Migration/persistence update"
31514
+ ]
31515
+ }
31516
+ ]
31517
+ };
31518
+ }
31519
+ if (task.agentRole === "infra-specialist") {
31520
+ return {
31521
+ label: "auto-infra-swarm",
31522
+ strategy: "sequential",
31523
+ members: [
31524
+ {
31525
+ id: "workspace-scaffolder",
31526
+ label: "workspace-scaffolder",
31527
+ agentRole: "infra-specialist",
31528
+ description: "Set up required files, scripts, package wiring, and environment plumbing.",
31529
+ instructions: "Focus on scaffolding, package manifests, scripts, environment wiring, and local runtime setup. Keep the workspace runnable.",
31530
+ acceptanceCriteria: [
31531
+ "Required scaffolding and environment wiring are in place.",
31532
+ "The workspace can proceed into implementation or verification."
31533
+ ],
31534
+ outputs: [
31535
+ "Workspace scaffolding"
31536
+ ]
31537
+ },
31538
+ {
31539
+ id: "runtime-verifier",
31540
+ label: "runtime-verifier",
31541
+ agentRole: "infra-specialist",
31542
+ description: "Verify build/runtime setup and tighten any configuration or tooling gaps.",
31543
+ instructions: "Focus on runtime, toolchain, script, and build verification after the initial setup work has landed.",
31544
+ acceptanceCriteria: [
31545
+ "The environment or app can be verified locally.",
31546
+ "Tooling and configuration gaps are closed."
31547
+ ],
31548
+ outputs: [
31549
+ "Runtime/config verification"
31550
+ ]
31551
+ }
31552
+ ]
31553
+ };
31554
+ }
31555
+ return null;
31556
+ }
31557
+ async function detectAppliedVisualAdjustment(cwd, request) {
31558
+ const adjustment = inferVisualAdjustment(request.goal);
31559
+ if (!adjustment) {
31560
+ return null;
31561
+ }
31562
+ const candidates = [
31563
+ "src/app/page.tsx",
31564
+ "src/pages/index.tsx",
31565
+ "src/app/globals.css",
31566
+ "styles.css",
31567
+ "index.html"
31568
+ ];
31569
+ for (const relativePath of candidates) {
31570
+ const absolutePath = import_node_path14.default.join(cwd, relativePath);
31571
+ try {
31572
+ await (0, import_promises14.access)(absolutePath);
31573
+ const contents = await (0, import_promises14.readFile)(absolutePath, "utf8");
31574
+ if (contents.includes(adjustment.background)) {
31575
+ return absolutePath;
31576
+ }
31577
+ } catch {
31578
+ }
31579
+ }
31580
+ return null;
31581
+ }
31582
+ async function detectPreferredVerificationCommand(cwd) {
31583
+ const packagePath = import_node_path14.default.join(cwd, "package.json");
31584
+ try {
31585
+ await (0, import_promises14.access)(packagePath);
31586
+ const raw = await (0, import_promises14.readFile)(packagePath, "utf8");
31587
+ const parsed = JSON.parse(raw);
31588
+ const scripts = parsed.scripts ?? {};
31589
+ const packageManager = parsed.packageManager?.startsWith("pnpm") ? "pnpm" : parsed.packageManager?.startsWith("yarn") ? "yarn" : "npm";
31590
+ if (scripts.build) {
31591
+ return packageManager === "yarn" ? "yarn build" : `${packageManager} run build`;
31592
+ }
31593
+ if (scripts.lint) {
31594
+ return packageManager === "yarn" ? "yarn lint" : `${packageManager} run lint`;
31595
+ }
31596
+ if (scripts.test) {
31597
+ return packageManager === "yarn" ? "yarn test" : `${packageManager} run test`;
31598
+ }
31599
+ } catch {
31600
+ return null;
31601
+ }
31602
+ return null;
31603
+ }
31604
+ function materializeDelegatedTasks(plan, task, label, strategy, members) {
31605
+ const existingIds = new Set(flattenPlanTasks(plan).filter((candidate) => candidate.id !== task.id).map((candidate) => candidate.id));
31606
+ const teamMemberIds = members.map((member) => member.id);
31607
+ const generatedTaskIds = members.map((member, index) => createUniqueTaskId2(`${task.id}-${slugify2(member.id) || `worker-${index + 1}`}`, existingIds));
31608
+ return members.map((member, index) => {
31609
+ const taskId = generatedTaskIds[index];
31610
+ const dependsOn = strategy === "parallel" ? [
31611
+ ...task.dependsOn
31612
+ ] : index === 0 ? [
31613
+ ...task.dependsOn
31614
+ ] : [
31615
+ generatedTaskIds[index - 1]
31616
+ ];
31617
+ return {
31618
+ ...task,
31619
+ id: taskId,
31620
+ title: `${task.title} (${member.label})`,
31621
+ description: [
31622
+ task.description,
31623
+ `Delegated worker: ${member.label}.`,
31624
+ member.description
31625
+ ].join("\n\n"),
31626
+ agentRole: member.agentRole,
31627
+ dependsOn,
31628
+ acceptanceCriteria: member.acceptanceCriteria?.length ? member.acceptanceCriteria : index === members.length - 1 ? task.acceptanceCriteria : [
31629
+ `Advance ${task.title.toLowerCase()} from the ${member.label} perspective.`,
31630
+ "Leave concrete implementation evidence for the next worker."
31631
+ ],
31632
+ outputs: member.outputs?.length ? member.outputs : index === members.length - 1 ? task.outputs : [
31633
+ `Delegated handoff from ${member.id}`
31634
+ ],
31635
+ filesLikelyTouched: member.filesLikelyTouched?.length ? member.filesLikelyTouched : task.filesLikelyTouched,
31636
+ originTaskId: task.id,
31637
+ swarmDepth: (task.swarmDepth ?? 0) + 1,
31638
+ teamId: label,
31639
+ teamMemberIds,
31640
+ subagentLabel: member.label,
31641
+ subagentInstructions: member.instructions
31642
+ };
31643
+ });
31644
+ }
31645
+ function appendReviewAndIntegrationTasks(plan, originalTask, expandedTasks, delegationLabel) {
31646
+ const existingIds = new Set(flattenPlanTasks(plan).filter((candidate) => candidate.id !== originalTask.id).map((candidate) => candidate.id));
31647
+ for (const task of expandedTasks) {
31648
+ existingIds.add(task.id);
31649
+ }
31650
+ const terminalIds = terminalExpansionTaskIds(expandedTasks);
31651
+ const reviewerId = createUniqueTaskId2(`${originalTask.id}-review`, existingIds);
31652
+ const integratorId = createUniqueTaskId2(`${originalTask.id}-integrate`, existingIds);
31653
+ const reviewerTask = {
31654
+ ...originalTask,
31655
+ id: reviewerId,
31656
+ title: `Review ${originalTask.title.toLowerCase()}`,
31657
+ description: `Inspect delegated worker output from ${delegationLabel} before integration and call out correctness or verification risk.`,
31658
+ type: "verification",
31659
+ agentRole: "reviewer",
31660
+ dependsOn: terminalIds,
31661
+ acceptanceCriteria: [
31662
+ "Inspect the delegated changes for regressions or missing coverage.",
31663
+ "Confirm whether the worker output is ready for integration."
31664
+ ],
31665
+ outputs: [
31666
+ "Review summary"
31667
+ ],
31668
+ originTaskId: originalTask.id,
31669
+ swarmDepth: (originalTask.swarmDepth ?? 0) + 1,
31670
+ teamId: delegationLabel,
31671
+ teamMemberIds: [
31672
+ ...originalTask.teamMemberIds ?? [],
31673
+ "reviewer"
31674
+ ],
31675
+ subagentLabel: "reviewer",
31676
+ subagentInstructions: "Inspect the delegated changes, diff, and verification evidence. Surface concrete risks before integration."
31677
+ };
31678
+ const integratorTask = {
31679
+ ...originalTask,
31680
+ id: integratorId,
31681
+ title: `Integrate ${originalTask.title.toLowerCase()}`,
31682
+ description: `Finalize and integrate delegated worker output after reviewer sign-off for ${delegationLabel}.`,
31683
+ type: "integration",
31684
+ agentRole: "integrator",
31685
+ dependsOn: [
31686
+ reviewerId
31687
+ ],
31688
+ acceptanceCriteria: originalTask.acceptanceCriteria,
31689
+ outputs: mergeUnique([
31690
+ ...originalTask.outputs,
31691
+ "Integrated change set"
31692
+ ]),
31693
+ originTaskId: originalTask.id,
31694
+ swarmDepth: (originalTask.swarmDepth ?? 0) + 1,
31695
+ teamId: delegationLabel,
31696
+ teamMemberIds: [
31697
+ ...originalTask.teamMemberIds ?? [],
31698
+ "integrator"
31699
+ ],
31700
+ subagentLabel: "integrator",
31701
+ subagentInstructions: "Finalize the accepted worker output, preserve repository consistency, and leave the workspace ready for downstream verification."
31702
+ };
31703
+ return {
31704
+ tasks: [
31705
+ ...expandedTasks,
31706
+ reviewerTask,
31707
+ integratorTask
31708
+ ],
31709
+ noteSuffix: `review tail ${reviewerId} -> integration tail ${integratorId}`
31710
+ };
31711
+ }
31145
31712
  function renderToolResultSection(results) {
31146
31713
  return results.map((result) => {
31147
31714
  const lines = [
@@ -31669,6 +32236,9 @@ var ExecutionOrchestrator = class {
31669
32236
  if (request.workspaceState === "existing" && isStaticSiteTask(task, request) && (task.type === "scaffold" || task.type === "implementation")) {
31670
32237
  return this.executeDeterministicStaticSiteTask(sessionId, task, request, resolvedApproval, options, emitProgress);
31671
32238
  }
32239
+ if (request.workspaceState === "existing" && looksLikeStaticLandingGoal(request.goal) && task.type === "verification") {
32240
+ return this.executeDeterministicVerificationTask(sessionId, task, request, emitProgress, options.signal);
32241
+ }
31672
32242
  if (task.type === "scaffold") {
31673
32243
  return this.executeScaffoldTask(sessionId, task, request, plan, resolvedApproval, options, emitProgress);
31674
32244
  }
@@ -31803,7 +32373,69 @@ var ExecutionOrchestrator = class {
31803
32373
  ]))
31804
32374
  };
31805
32375
  }
32376
+ async executeDeterministicVerificationTask(sessionId, task, request, emitProgress, signal) {
32377
+ const command = await detectPreferredVerificationCommand(request.cwd);
32378
+ if (!command) {
32379
+ return {
32380
+ status: "completed",
32381
+ summary: "No build, lint, or test script was found; verification was recorded as not applicable.",
32382
+ toolResults: [],
32383
+ artifacts: []
32384
+ };
32385
+ }
32386
+ const input = {
32387
+ command
32388
+ };
32389
+ if (emitProgress) {
32390
+ await emitProgress({
32391
+ type: "tool-started",
32392
+ sessionId,
32393
+ taskId: task.id,
32394
+ agentRole: task.agentRole,
32395
+ toolId: "tests.run",
32396
+ input
32397
+ });
32398
+ }
32399
+ const result = await this.safeRunTool("tests.run", input, {
32400
+ cwd: request.cwd,
32401
+ taskId: task.id,
32402
+ agentRole: task.agentRole,
32403
+ ...signal ? {
32404
+ signal
32405
+ } : {}
32406
+ });
32407
+ if (emitProgress) {
32408
+ await emitProgress({
32409
+ type: "tool-finished",
32410
+ sessionId,
32411
+ taskId: task.id,
32412
+ agentRole: task.agentRole,
32413
+ toolResult: result
32414
+ });
32415
+ }
32416
+ return {
32417
+ status: result.success ? "completed" : "blocked",
32418
+ summary: result.success ? `Verification passed via ${command}.` : `Verification failed via ${command}.`,
32419
+ toolResults: [
32420
+ result
32421
+ ],
32422
+ artifacts: result.artifacts
32423
+ };
32424
+ }
31806
32425
  async executeDeterministicStaticSiteTask(sessionId, task, request, resolvedApproval, options, emitProgress) {
32426
+ if (looksLikeVisualAdjustmentGoal(request.goal)) {
32427
+ const appliedArtifact = await detectAppliedVisualAdjustment(request.cwd, request);
32428
+ if (appliedArtifact) {
32429
+ return {
32430
+ status: "completed",
32431
+ summary: `Confirmed the requested visual adjustment in ${import_node_path14.default.relative(request.cwd, appliedArtifact) || appliedArtifact}.`,
32432
+ toolResults: [],
32433
+ artifacts: [
32434
+ appliedArtifact
32435
+ ]
32436
+ };
32437
+ }
32438
+ }
31807
32439
  const config2 = await loadConfig(request.cwd);
31808
32440
  const scaffoldInput = {
31809
32441
  goal: request.goal,
@@ -32199,15 +32831,7 @@ var ExecutionOrchestrator = class {
32199
32831
  }
32200
32832
  async maybeExpandReadyTaskGraph(sessionId, request, plan, events, emitProgress) {
32201
32833
  const envelope = this.buildEnvelope(request, plan, sessionId);
32202
- const candidate = envelope.readyTasks.find((task) => (task.swarmDepth ?? 0) === 0 && task.type === "implementation" && ![
32203
- "repo-analyst",
32204
- "planner",
32205
- "reviewer",
32206
- "integrator",
32207
- "test-debugger",
32208
- "session-orchestrator",
32209
- "execution-manager"
32210
- ].includes(task.agentRole));
32834
+ const candidate = envelope.readyTasks.find((task) => shouldDelegateTask(task, request));
32211
32835
  if (!candidate) {
32212
32836
  return {
32213
32837
  plan
@@ -32215,47 +32839,37 @@ var ExecutionOrchestrator = class {
32215
32839
  }
32216
32840
  const matchedTeam = await selectAgentTeam(request.cwd, candidate, request);
32217
32841
  if (matchedTeam && matchedTeam.members.length > 1) {
32218
- const existingIds = new Set(flattenPlanTasks(plan).filter((task) => task.id !== candidate.id).map((task) => task.id));
32219
- const teamMemberIds = matchedTeam.members.map((member) => member.id);
32220
- const generatedTaskIds = matchedTeam.members.map((member, index) => createUniqueTaskId2(`${candidate.id}-${slugify2(member.id) || `member-${index + 1}`}`, existingIds));
32221
- const teamTasks = matchedTeam.members.map((member, index) => {
32222
- const taskId = generatedTaskIds[index];
32223
- const dependsOn = matchedTeam.team.strategy === "parallel" ? [
32224
- ...candidate.dependsOn
32225
- ] : index === 0 ? [
32226
- ...candidate.dependsOn
32227
- ] : [
32228
- generatedTaskIds[index - 1] ?? candidate.dependsOn[0] ?? ""
32229
- ].filter((value) => value.length > 0);
32230
- return {
32231
- ...candidate,
32232
- id: taskId,
32233
- title: `${candidate.title} (${member.label})`,
32234
- description: [
32235
- candidate.description,
32236
- `Assigned team member: ${member.label} (${member.id}).`,
32237
- member.purpose ? `Purpose: ${member.purpose}` : "",
32238
- matchedTeam.team.description ? `Team context: ${matchedTeam.team.description}` : ""
32239
- ].filter((part) => part.length > 0).join("\n\n"),
32240
- agentRole: member.baseRole,
32241
- dependsOn,
32242
- acceptanceCriteria: index === matchedTeam.members.length - 1 ? candidate.acceptanceCriteria : [
32243
- `Advance ${candidate.title.toLowerCase()} from the ${member.label} perspective.`,
32244
- "Leave clear handoff notes and concrete changed-file intent for the next team member."
32245
- ],
32246
- outputs: index === matchedTeam.members.length - 1 ? candidate.outputs : [
32247
- `Team handoff from ${member.id}`
32248
- ],
32249
- originTaskId: candidate.id,
32250
- swarmDepth: (candidate.swarmDepth ?? 0) + 1,
32251
- customAgentId: member.id,
32252
- teamId: matchedTeam.team.id,
32253
- teamMemberIds
32254
- };
32255
- });
32256
- const note = `Agent team ${matchedTeam.team.label} expanded ${candidate.id} into ${teamTasks.length} ${matchedTeam.team.strategy} subtasks: ${teamTasks.map((task) => task.id).join(", ")}.`;
32842
+ const teamTasks = materializeDelegatedTasks(plan, candidate, matchedTeam.team.id, matchedTeam.team.strategy, matchedTeam.members.map((member) => ({
32843
+ id: member.id,
32844
+ label: member.label,
32845
+ agentRole: member.baseRole,
32846
+ description: [
32847
+ `Assigned team member: ${member.label} (${member.id}).`,
32848
+ member.purpose ? `Purpose: ${member.purpose}` : "",
32849
+ matchedTeam.team.description ? `Team context: ${matchedTeam.team.description}` : ""
32850
+ ].filter((part) => part.length > 0).join("\n\n"),
32851
+ instructions: member.instructions
32852
+ }))).map((task) => ({
32853
+ ...task,
32854
+ customAgentId: task.customAgentId ?? task.subagentLabel ? matchedTeam.members.find((member) => member.label === task.subagentLabel)?.id : void 0,
32855
+ teamId: matchedTeam.team.id,
32856
+ teamMemberIds: matchedTeam.members.map((member) => member.id)
32857
+ }));
32858
+ const augmented = appendReviewAndIntegrationTasks(plan, candidate, teamTasks, matchedTeam.team.label);
32859
+ const note = `Agent team ${matchedTeam.team.label} expanded ${candidate.id} into ${teamTasks.length} worker subtasks with reviewer/integrator follow-through: ${augmented.tasks.map((task) => task.id).join(", ")}.`;
32860
+ return {
32861
+ plan: integratePlanTaskExpansion(plan, candidate.id, augmented.tasks, note),
32862
+ note,
32863
+ expandedTaskId: candidate.id
32864
+ };
32865
+ }
32866
+ const defaultDelegation = createDefaultDelegationPlan(candidate, request);
32867
+ if (defaultDelegation && defaultDelegation.members.length > 1) {
32868
+ const delegatedTasks = materializeDelegatedTasks(plan, candidate, defaultDelegation.label, defaultDelegation.strategy, defaultDelegation.members);
32869
+ const augmented = appendReviewAndIntegrationTasks(plan, candidate, delegatedTasks, defaultDelegation.label);
32870
+ const note = `Execution manager delegated ${candidate.id} into ${delegatedTasks.length} subagents plus reviewer/integrator: ${augmented.tasks.map((task) => task.id).join(", ")}.`;
32257
32871
  return {
32258
- plan: integratePlanTaskExpansion(plan, candidate.id, teamTasks, note),
32872
+ plan: integratePlanTaskExpansion(plan, candidate.id, augmented.tasks, note),
32259
32873
  note,
32260
32874
  expandedTaskId: candidate.id
32261
32875
  };
@@ -32317,12 +32931,14 @@ var ExecutionOrchestrator = class {
32317
32931
  plan
32318
32932
  };
32319
32933
  }
32934
+ const expandedTasks = flattenPlanTasks(result.plan).filter((task) => result.createdTaskIds.includes(task.id));
32935
+ const augmented = appendReviewAndIntegrationTasks(plan, candidate, expandedTasks, "planner-swarm");
32320
32936
  const noteParts = [
32321
- result.note,
32937
+ result.note ? `${result.note} | Added reviewer/integrator pass: ${augmented.noteSuffix}.` : `Added reviewer/integrator pass: ${augmented.noteSuffix}.`,
32322
32938
  result.warning && result.source !== "model" ? `expander note: ${result.warning}` : ""
32323
32939
  ].filter(Boolean);
32324
32940
  return {
32325
- plan: result.plan,
32941
+ plan: integratePlanTaskExpansion(plan, candidate.id, augmented.tasks, noteParts.join(" | ")),
32326
32942
  ...noteParts.length > 0 ? {
32327
32943
  note: noteParts.join(" | ")
32328
32944
  } : {},
@@ -32436,10 +33052,69 @@ function createAgentsCommand() {
32436
33052
  });
32437
33053
  console.log(`Created ${outputPath}`);
32438
33054
  });
33055
+ command.command("show").description("Show one custom agent or team.").argument("<id>", "Agent or team id").option("--team", "Show a team instead of an agent", false).action(async (id, options) => {
33056
+ if (options.team) {
33057
+ const team = await loadAgentTeamById(process.cwd(), id);
33058
+ if (!team) {
33059
+ throw new Error(`Unknown team "${id}".`);
33060
+ }
33061
+ console.log(team.id);
33062
+ console.log(` label: ${team.label}`);
33063
+ console.log(` agents: ${team.agents.join(", ") || "-"}`);
33064
+ console.log(` match: ${team.match.join(", ") || "-"}`);
33065
+ console.log(` strategy: ${team.strategy}`);
33066
+ console.log(` file: ${team.filePath}`);
33067
+ if (team.description) {
33068
+ console.log("");
33069
+ console.log(team.description);
33070
+ }
33071
+ return;
33072
+ }
33073
+ const agent = await loadCustomAgentById(process.cwd(), id);
33074
+ if (!agent) {
33075
+ throw new Error(`Unknown custom agent "${id}".`);
33076
+ }
33077
+ console.log(agent.id);
33078
+ console.log(` label: ${agent.label}`);
33079
+ console.log(` baseRole: ${agent.baseRole}`);
33080
+ console.log(` brainRole: ${agent.brainRole ?? "-"}`);
33081
+ console.log(` purpose: ${agent.purpose ?? "-"}`);
33082
+ console.log(` match: ${agent.match.join(", ") || "-"}`);
33083
+ console.log(` tools: ${agent.tools.join(", ") || "(inherits base role tools)"}`);
33084
+ console.log(` file: ${agent.filePath}`);
33085
+ if (agent.instructions.trim()) {
33086
+ console.log("");
33087
+ console.log(agent.instructions.trim());
33088
+ }
33089
+ });
33090
+ command.command("delete").description("Delete a custom agent or team markdown file.").argument("<id>", "Agent or team id").option("--team", "Delete a team instead of an agent", false).action(async (id, options) => {
33091
+ const outputPath = options.team ? await deleteAgentTeamFile(process.cwd(), id) : await deleteCustomAgentFile(process.cwd(), id);
33092
+ console.log(`Deleted ${outputPath}`);
33093
+ });
32439
33094
  command.command("team-create").description("Create a markdown-backed agent team definition.").argument("<id>", "Team id").argument("<agents...>", "Member agent ids").option("--label <label>", "Human-readable label").action(async (id, agents, options) => {
32440
33095
  const outputPath = await createAgentTeamFile(process.cwd(), id, agents, options.label);
32441
33096
  console.log(`Created ${outputPath}`);
32442
33097
  });
33098
+ command.command("team-show").description("Show one markdown-backed team definition.").argument("<id>", "Team id").action(async (id) => {
33099
+ const team = await loadAgentTeamById(process.cwd(), id);
33100
+ if (!team) {
33101
+ throw new Error(`Unknown team "${id}".`);
33102
+ }
33103
+ console.log(team.id);
33104
+ console.log(` label: ${team.label}`);
33105
+ console.log(` agents: ${team.agents.join(", ") || "-"}`);
33106
+ console.log(` match: ${team.match.join(", ") || "-"}`);
33107
+ console.log(` strategy: ${team.strategy}`);
33108
+ console.log(` file: ${team.filePath}`);
33109
+ if (team.description) {
33110
+ console.log("");
33111
+ console.log(team.description);
33112
+ }
33113
+ });
33114
+ command.command("team-delete").description("Delete one markdown-backed team definition.").argument("<id>", "Team id").action(async (id) => {
33115
+ const outputPath = await deleteAgentTeamFile(process.cwd(), id);
33116
+ console.log(`Deleted ${outputPath}`);
33117
+ });
32443
33118
  return command;
32444
33119
  }
32445
33120
 
@@ -32877,7 +33552,15 @@ async function generateProjectInitFile(cwd, outputFileName = "kimbho_init.md") {
32877
33552
  return {
32878
33553
  outputPath,
32879
33554
  indexArtifactPath: artifactPath,
32880
- summary: `Generated ${outputFileName} with indexed project context for ${import_node_path15.default.basename(cwd)}.`
33555
+ summary: `Generated ${outputFileName} with indexed project context for ${import_node_path15.default.basename(cwd)}.`,
33556
+ purpose,
33557
+ frameworks,
33558
+ entrypoints,
33559
+ verificationCommands,
33560
+ indexedFiles: index.summary.totalFiles,
33561
+ sourceFiles: index.summary.sourceFiles,
33562
+ routes: index.summary.routes,
33563
+ schemas: index.summary.schemas
32881
33564
  };
32882
33565
  }
32883
33566
 
@@ -32934,7 +33617,15 @@ async function refreshMemoryFiles(cwd) {
32934
33617
  initFilePath: init.outputPath,
32935
33618
  projectMemoryPath,
32936
33619
  userMemoryPath,
32937
- summary: `Refreshed project bootstrap and memory files for ${import_node_path16.default.basename(cwd)}.`
33620
+ summary: `Refreshed project bootstrap and memory files for ${import_node_path16.default.basename(cwd)}.`,
33621
+ purpose: init.purpose,
33622
+ frameworks: init.frameworks,
33623
+ entrypoints: init.entrypoints,
33624
+ verificationCommands: init.verificationCommands,
33625
+ indexedFiles: init.indexedFiles,
33626
+ sourceFiles: init.sourceFiles,
33627
+ routes: init.routes,
33628
+ schemas: init.schemas
32938
33629
  };
32939
33630
  }
32940
33631
  async function appendMemoryNote(cwd, scope, text, agentId) {
@@ -33076,6 +33767,22 @@ function createDoctorCommand() {
33076
33767
 
33077
33768
  // src/commands/init.ts
33078
33769
  var import_node_process7 = __toESM(require("node:process"), 1);
33770
+ function printProjectUnderstanding(result) {
33771
+ console.log(result.summary);
33772
+ console.log("Now I have a durable understanding of the current project structure.");
33773
+ console.log(`Purpose: ${result.purpose}`);
33774
+ console.log(`Indexed: ${result.indexedFiles} files (${result.sourceFiles} source files), ${result.routes} routes, ${result.schemas} schemas`);
33775
+ console.log(`Frameworks: ${result.frameworks.length > 0 ? result.frameworks.join(", ") : "unknown"}`);
33776
+ if (result.entrypoints.length > 0) {
33777
+ console.log(`Entrypoints: ${result.entrypoints.slice(0, 5).join(", ")}`);
33778
+ }
33779
+ if (result.verificationCommands.length > 0) {
33780
+ console.log(`Verification: ${result.verificationCommands.join(" -> ")}`);
33781
+ }
33782
+ console.log(`Wrote ${result.initFilePath}`);
33783
+ console.log(`Wrote ${result.projectMemoryPath}`);
33784
+ console.log(`Wrote ${result.userMemoryPath}`);
33785
+ }
33079
33786
  function createInitCommand() {
33080
33787
  return new Command("init").description("Create or refresh local Kimbho config and project bootstrap memory.").option("--template <template>", "Provider template to use for the initial provider").option("--provider-id <id>", "Identifier for the initial provider").option("--driver <driver>", "Provider driver to use when no template is supplied").option("--label <label>", "Human-readable provider label").option("--model <model>", "Default model to use for planner/coder/reviewer brains").option("--fast-model <model>", "Model to use for the fast utility brain").option("--api-key-env <env>", "Environment variable that stores the provider API key").option("--base-url <url>", "Base URL or endpoint for the provider driver").option("--module-path <path>", "Module path for a custom provider driver").option("--config-only", "Only write .kimbho/config.json and skip project memory generation", false).option("--memory-only", "Only generate kimbho_init.md and keep the existing config untouched", false).option("--memory-file <file>", "Project memory file to write", "kimbho_init.md").option("--force", "Overwrite an existing config file", false).action(async (options) => {
33081
33788
  const existing = await loadConfig(import_node_process7.default.cwd());
@@ -33141,10 +33848,7 @@ function createInitCommand() {
33141
33848
  }
33142
33849
  if (!options.configOnly) {
33143
33850
  const result = await refreshMemoryFiles(import_node_process7.default.cwd());
33144
- console.log(result.summary);
33145
- console.log(`Wrote ${result.initFilePath}`);
33146
- console.log(`Wrote ${result.projectMemoryPath}`);
33147
- console.log(`Wrote ${result.userMemoryPath}`);
33851
+ printProjectUnderstanding(result);
33148
33852
  }
33149
33853
  });
33150
33854
  }
@@ -33227,7 +33931,7 @@ async function renderMcpInventory(cwd, name) {
33227
33931
  ` prompts: ${server.prompts.length}`,
33228
33932
  ...server.prompts.slice(0, 10).flatMap((prompt) => [
33229
33933
  ` - ${prompt.name}${prompt.arguments.length > 0 ? ` (${prompt.arguments.map((argument) => `${argument.name}${argument.required ? "*" : ""}`).join(", ")})` : ""}`,
33230
- ` command: /mcp__${server.name}__${prompt.name}`
33934
+ ` command: /mcp__${normalizeMcpCommandSegment(server.name)}__${normalizeMcpCommandSegment(prompt.name)}`
33231
33935
  ]),
33232
33936
  ` resources: ${server.resources.length}`,
33233
33937
  ...server.resources.slice(0, 10).flatMap((resource) => [
@@ -33253,7 +33957,7 @@ async function renderMcpPromptList(cwd, name) {
33253
33957
  ] : [],
33254
33958
  ...server.prompts.length > 0 ? server.prompts.flatMap((prompt) => [
33255
33959
  ` - ${prompt.name}${prompt.arguments.length > 0 ? ` (${prompt.arguments.map((argument) => `${argument.name}${argument.required ? "*" : ""}`).join(", ")})` : ""}`,
33256
- ` command: /mcp__${server.name}__${prompt.name}`
33960
+ ` command: /mcp__${normalizeMcpCommandSegment(server.name)}__${normalizeMcpCommandSegment(prompt.name)}`
33257
33961
  ]) : [
33258
33962
  " - no prompts"
33259
33963
  ]
@@ -34889,6 +35593,9 @@ var PLAN_PREFIXES = [
34889
35593
  "outline ",
34890
35594
  "propose "
34891
35595
  ];
35596
+ function looksLikeExecutionRequest(input) {
35597
+ return /\b(build|create|make|scaffold|implement|fix|refactor|setup|set up|generate|add|change|update|edit|rewrite|restyle|redesign|improve|enhance)\b/.test(input);
35598
+ }
34892
35599
  function color(code, value) {
34893
35600
  return `${code}${value}${RESET}`;
34894
35601
  }
@@ -35191,53 +35898,65 @@ function renderBox(lines) {
35191
35898
  function renderHelp() {
35192
35899
  return [
35193
35900
  `${color(DIM, "Commands")}`,
35194
- "/status Show the active role, provider, and workspace state.",
35195
- "/ask <prompt> Send a prompt to the active model without running the agent.",
35196
- "/chat <prompt> Alias for /ask <prompt>.",
35197
- "/reset-chat Clear the active model conversation history.",
35198
- "/model Show current model, provider, and role state.",
35901
+ `${color(BOLD, "Core")}`,
35902
+ "/status Show active model, workspace, approvals, and sandbox state.",
35903
+ "/ask <prompt> Chat with the focused model without running the agent.",
35904
+ "/plan <goal> Create a structured plan only.",
35905
+ "/run <goal> Execute a goal immediately.",
35906
+ "/resume Continue the latest paused or awaiting-approval session.",
35907
+ "/review Review the current git diff and summarize risk.",
35908
+ "/clear Redraw the shell.",
35909
+ "/quit, /exit Leave the shell.",
35910
+ "",
35911
+ `${color(BOLD, "Model")}`,
35912
+ "/model Show current provider/model state.",
35199
35913
  "/model providers List configured providers.",
35200
35914
  "/model add <tpl> [id] Add a provider template.",
35201
35915
  "/model use <provider> [model] Switch provider/model for all roles.",
35202
35916
  "/model find [search] Discover models for the active provider.",
35203
- "/model select <n> Pick a model from the last numbered list.",
35204
- "/model focus <role> Change shell focus to planner, coder, reviewer, or fast.",
35205
- "/permissions Show approval, sandbox, and trusted directory settings.",
35917
+ "/model select <n> Pick from the last numbered model list.",
35918
+ "/model focus <role> Change focus to planner, coder, reviewer, or fast.",
35919
+ "",
35920
+ `${color(BOLD, "Permissions")}`,
35921
+ "/permissions Show layered approval, sandbox, and trust settings.",
35206
35922
  "/permissions auto|manual Change approval mode.",
35207
35923
  "/permissions sandbox <mode> Set read-only, workspace-write, or full.",
35208
35924
  "/permissions trust <path> Add a trusted directory.",
35209
35925
  "/permissions untrust <path> Remove a trusted directory.",
35210
- "/memory Show project, user, and agent memory paths.",
35211
- "/memory refresh Refresh kimbho_init.md and project memory.",
35926
+ "/approve [id] Approve a pending risky action and continue.",
35927
+ "/approve-all Approve every pending action in the current session.",
35928
+ "/deny [id] Deny a pending risky action.",
35929
+ "",
35930
+ `${color(BOLD, "Memory")}`,
35931
+ "/init [--memory-only] Build config and durable project understanding files.",
35932
+ "/memory Show init/project/user/agent memory paths.",
35933
+ "/memory refresh Re-scan the project and refresh markdown memory.",
35212
35934
  "/memory show <scope> Print init, project, user, or agent memory.",
35213
- "/memory add <scope> <text> Append a markdown memory note.",
35935
+ "/memory add <scope> ... Append a markdown memory note.",
35214
35936
  "/config Show config, memory, and MCP file locations.",
35937
+ "",
35938
+ `${color(BOLD, "MCP")}`,
35215
35939
  "/mcp List configured MCP servers.",
35940
+ "/mcp discover [server] Show MCP tools, prompts-as-commands, and resources.",
35941
+ "/mcp prompt <server> <prompt> [key=value ...] Render one MCP prompt.",
35942
+ "/mcp read <server> <uri> Read one MCP resource.",
35216
35943
  "/mcp add <name> --command <cmd> [--arg <value>] [--env KEY=VALUE]",
35217
35944
  " Add an MCP stdio server to .mcp.json.",
35218
- "/mcp tools [server] Discover tools/prompts/resources from MCP servers.",
35219
- "/mcp prompts [server] List MCP prompts.",
35220
- "/mcp resources [server] List MCP resources and templates.",
35221
- "/mcp prompt <server> <prompt> [key=value ...]",
35222
- " Render an MCP prompt.",
35223
- "/mcp read <server> <uri> Read one MCP resource.",
35945
+ "/mcp__server__prompt ... Invoke an MCP prompt directly from the shell.",
35946
+ "@server:uri Attach an MCP resource inside /ask, /plan, or /run prompts.",
35947
+ "",
35948
+ `${color(BOLD, "Agents")}`,
35224
35949
  "/agents List custom agents and teams.",
35950
+ "/agents show <id> Show one custom agent definition.",
35951
+ "/agents delete <id> Delete one custom agent definition.",
35225
35952
  "/agents create <id> --base <role> Create a markdown custom agent.",
35226
35953
  "/agents team create <id> <agent...> Create a markdown team file.",
35227
- "/init [--memory-only] Create or refresh config and markdown memory files.",
35228
- "/plan <goal> Create a structured implementation plan.",
35229
- "/run <goal> Start a Kimbho execution session for a goal.",
35230
- "/resume Show the latest saved session.",
35231
- "/approve [id] Approve a pending risky action and continue the session.",
35232
- "/approve-all Approve all pending actions in the current session.",
35233
- "/deny [id] Deny a pending risky action.",
35234
- "/review Review the current git diff and summarize risk.",
35235
- "/doctor Check local environment and config.",
35236
- "/clear Redraw the shell.",
35237
- "/quit, /exit Leave the shell.",
35954
+ "/agents team show <id> Show one team definition.",
35955
+ "/agents team delete <id> Delete one team definition.",
35238
35956
  "",
35239
35957
  `${color(DIM, "Tip")}`,
35240
35958
  "Type build/change requests directly to run the agent. Type plan/design prompts for planning. Use /ask when you want plain chat.",
35959
+ "MCP prompts behave like slash commands, and MCP resources can be attached inline with @server:uri.",
35241
35960
  "Legacy aliases like /providers, /models, /select, /use-model, /brain, and /approval still work.",
35242
35961
  "Press Ctrl+C during an active run to pause it and return to the shell, then use /resume to continue."
35243
35962
  ].join("\n");
@@ -35282,20 +36001,20 @@ function inferPromptIntent(input) {
35282
36001
  if (/^(hi|hello|hey|yo|sup)\b/.test(normalized)) {
35283
36002
  return "chat";
35284
36003
  }
35285
- if (normalized.endsWith("?")) {
35286
- return "chat";
35287
- }
35288
36004
  if (PLAN_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
35289
36005
  return "plan";
35290
36006
  }
35291
36007
  if (EXECUTION_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
35292
36008
  return "run";
35293
36009
  }
35294
- if (CHAT_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
36010
+ if (looksLikeExecutionRequest(normalized)) {
36011
+ return "run";
36012
+ }
36013
+ if (normalized.endsWith("?")) {
35295
36014
  return "chat";
35296
36015
  }
35297
- if (/\b(build|create|make|scaffold|implement|fix|refactor|setup|set up|generate)\b/.test(normalized)) {
35298
- return "run";
36016
+ if (CHAT_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
36017
+ return "chat";
35299
36018
  }
35300
36019
  return normalized.split(/\s+/).length >= 4 ? "plan" : "chat";
35301
36020
  }
@@ -36377,6 +37096,16 @@ async function handleMemoryCommand(cwd, tokens) {
36377
37096
  if (subcommand === "refresh") {
36378
37097
  const result = await refreshMemoryFiles(cwd);
36379
37098
  console.log(result.summary);
37099
+ console.log("Now I have a durable understanding of the current project structure.");
37100
+ console.log(`Purpose: ${result.purpose}`);
37101
+ console.log(`Indexed: ${result.indexedFiles} files (${result.sourceFiles} source files), ${result.routes} routes, ${result.schemas} schemas`);
37102
+ console.log(`Frameworks: ${result.frameworks.length > 0 ? result.frameworks.join(", ") : "unknown"}`);
37103
+ if (result.entrypoints.length > 0) {
37104
+ console.log(`Entrypoints: ${result.entrypoints.slice(0, 5).join(", ")}`);
37105
+ }
37106
+ if (result.verificationCommands.length > 0) {
37107
+ console.log(`Verification: ${result.verificationCommands.join(" -> ")}`);
37108
+ }
36380
37109
  console.log(`Wrote ${result.initFilePath}`);
36381
37110
  console.log(`Wrote ${result.projectMemoryPath}`);
36382
37111
  console.log(`Wrote ${result.userMemoryPath}`);
@@ -36460,7 +37189,7 @@ async function handleMcpCommand(cwd, tokens) {
36460
37189
  }
36461
37190
  return;
36462
37191
  }
36463
- if (subcommand === "tools" || subcommand === "inspect") {
37192
+ if (subcommand === "tools" || subcommand === "inspect" || subcommand === "discover") {
36464
37193
  const name = tokens[2]?.trim();
36465
37194
  for (const line of await renderMcpInventory(cwd, name)) {
36466
37195
  console.log(line);
@@ -36496,10 +37225,12 @@ async function handleMcpCommand(cwd, tokens) {
36496
37225
  return;
36497
37226
  }
36498
37227
  if (subcommand === "read") {
36499
- const serverName = tokens[2]?.trim();
36500
- const uri = tokens.slice(3).join(" ").trim();
37228
+ const shorthand = tokens[2]?.trim();
37229
+ const shorthandMatch = shorthand?.match(/^@([^:\s]+):(.+)$/);
37230
+ const serverName = shorthandMatch ? shorthandMatch[1] : tokens[2]?.trim();
37231
+ const uri = shorthandMatch ? shorthandMatch[2] : tokens.slice(3).join(" ").trim();
36501
37232
  if (!serverName || !uri) {
36502
- throw new Error("Usage: /mcp read <server> <uri>");
37233
+ throw new Error("Usage: /mcp read <server> <uri> | /mcp read @server:uri");
36503
37234
  }
36504
37235
  for (const line of await renderMcpResourceRead(cwd, serverName, uri)) {
36505
37236
  console.log(line);
@@ -36569,7 +37300,7 @@ async function handleMcpCommand(cwd, tokens) {
36569
37300
  console.log(`Added MCP server ${name}`);
36570
37301
  return;
36571
37302
  }
36572
- throw new Error("Usage: /mcp [list|tools [server]|prompts [server]|resources [server]|prompt <server> <prompt>|read <server> <uri>|add <name> --command <cmd>|remove <name>|enable <name>|disable <name>]");
37303
+ throw new Error("Usage: /mcp [list|discover [server]|prompts [server]|resources [server]|prompt <server> <prompt>|read <server> <uri>|read @server:uri|add <name> --command <cmd>|remove <name>|enable <name>|disable <name>]");
36573
37304
  }
36574
37305
  async function handleAgentsCommand(cwd, tokens) {
36575
37306
  const subcommand = tokens[1]?.trim().toLowerCase();
@@ -36614,6 +37345,38 @@ async function handleAgentsCommand(cwd, tokens) {
36614
37345
  console.log(`Created ${outputPath}`);
36615
37346
  return;
36616
37347
  }
37348
+ if (subcommand === "show") {
37349
+ const id = tokens[2]?.trim();
37350
+ if (!id) {
37351
+ throw new Error("Usage: /agents show <id>");
37352
+ }
37353
+ const agent = await loadCustomAgentById(cwd, id);
37354
+ if (!agent) {
37355
+ throw new Error(`Unknown custom agent "${id}".`);
37356
+ }
37357
+ console.log(`${agent.id}`);
37358
+ console.log(` label: ${agent.label}`);
37359
+ console.log(` baseRole: ${agent.baseRole}`);
37360
+ console.log(` brainRole: ${agent.brainRole ?? "-"}`);
37361
+ console.log(` purpose: ${agent.purpose ?? "-"}`);
37362
+ console.log(` match: ${agent.match.join(", ") || "-"}`);
37363
+ console.log(` tools: ${agent.tools.join(", ") || "(inherits base role tools)"}`);
37364
+ console.log(` file: ${agent.filePath}`);
37365
+ if (agent.instructions.trim()) {
37366
+ console.log("");
37367
+ console.log(agent.instructions.trim());
37368
+ }
37369
+ return;
37370
+ }
37371
+ if (subcommand === "delete") {
37372
+ const id = tokens[2]?.trim();
37373
+ if (!id) {
37374
+ throw new Error("Usage: /agents delete <id>");
37375
+ }
37376
+ const outputPath = await deleteCustomAgentFile(cwd, id);
37377
+ console.log(`Deleted ${outputPath}`);
37378
+ return;
37379
+ }
36617
37380
  if (subcommand === "team" && tokens[2]?.trim().toLowerCase() === "create") {
36618
37381
  const id = tokens[3]?.trim();
36619
37382
  const agentIds = tokens.slice(4).filter((token) => !token.startsWith("--"));
@@ -36626,7 +37389,37 @@ async function handleAgentsCommand(cwd, tokens) {
36626
37389
  console.log(`Created ${outputPath}`);
36627
37390
  return;
36628
37391
  }
36629
- throw new Error("Usage: /agents [list|create <id> --base <role>|team create <id> <agent...>]");
37392
+ if (subcommand === "team" && tokens[2]?.trim().toLowerCase() === "show") {
37393
+ const id = tokens[3]?.trim();
37394
+ if (!id) {
37395
+ throw new Error("Usage: /agents team show <id>");
37396
+ }
37397
+ const team = await loadAgentTeamById(cwd, id);
37398
+ if (!team) {
37399
+ throw new Error(`Unknown team "${id}".`);
37400
+ }
37401
+ console.log(`${team.id}`);
37402
+ console.log(` label: ${team.label}`);
37403
+ console.log(` agents: ${team.agents.join(", ") || "-"}`);
37404
+ console.log(` match: ${team.match.join(", ") || "-"}`);
37405
+ console.log(` strategy: ${team.strategy}`);
37406
+ console.log(` file: ${team.filePath}`);
37407
+ if (team.description) {
37408
+ console.log("");
37409
+ console.log(team.description);
37410
+ }
37411
+ return;
37412
+ }
37413
+ if (subcommand === "team" && tokens[2]?.trim().toLowerCase() === "delete") {
37414
+ const id = tokens[3]?.trim();
37415
+ if (!id) {
37416
+ throw new Error("Usage: /agents team delete <id>");
37417
+ }
37418
+ const outputPath = await deleteAgentTeamFile(cwd, id);
37419
+ console.log(`Deleted ${outputPath}`);
37420
+ return;
37421
+ }
37422
+ throw new Error("Usage: /agents [list|show <id>|delete <id>|create <id> --base <role>|team create <id> <agent...>|team show <id>|team delete <id>]");
36630
37423
  }
36631
37424
  async function handleModelSurfaceCommand(cwd, tokens, runtime) {
36632
37425
  const subcommand = tokens[1]?.trim().toLowerCase();