@kimbho/kimbho-cli 0.1.25 → 0.1.28

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
@@ -12718,7 +12718,7 @@ function createCompletionRuntimeCommand(program2) {
12718
12718
  // package.json
12719
12719
  var package_default = {
12720
12720
  name: "@kimbho/kimbho-cli",
12721
- version: "0.1.25",
12721
+ version: "0.1.28",
12722
12722
  description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
12723
12723
  type: "module",
12724
12724
  engines: {
@@ -13080,11 +13080,11 @@ var AGENT_CATALOG = {
13080
13080
  "Design-system mismatch",
13081
13081
  "Frontend contract drift"
13082
13082
  ],
13083
- maxConcurrentTasks: 2,
13083
+ maxConcurrentTasks: 3,
13084
13084
  policy: {
13085
13085
  sandboxMode: "workspace-write",
13086
13086
  canSpawnSubagents: true,
13087
- maxSubagentDepth: 1
13087
+ maxSubagentDepth: 2
13088
13088
  }
13089
13089
  },
13090
13090
  "backend-specialist": {
@@ -13110,11 +13110,11 @@ var AGENT_CATALOG = {
13110
13110
  "Schema drift",
13111
13111
  "Unclear domain contract"
13112
13112
  ],
13113
- maxConcurrentTasks: 2,
13113
+ maxConcurrentTasks: 3,
13114
13114
  policy: {
13115
13115
  sandboxMode: "workspace-write",
13116
13116
  canSpawnSubagents: true,
13117
- maxSubagentDepth: 1
13117
+ maxSubagentDepth: 2
13118
13118
  }
13119
13119
  },
13120
13120
  "database-specialist": {
@@ -13140,7 +13140,7 @@ var AGENT_CATALOG = {
13140
13140
  "Data-destructive migration",
13141
13141
  "Unclear persistence requirements"
13142
13142
  ],
13143
- maxConcurrentTasks: 1,
13143
+ maxConcurrentTasks: 2,
13144
13144
  policy: {
13145
13145
  sandboxMode: "workspace-write",
13146
13146
  requireApprovalPatterns: [
@@ -13149,7 +13149,7 @@ var AGENT_CATALOG = {
13149
13149
  "\\bdrop\\s+database\\b"
13150
13150
  ],
13151
13151
  canSpawnSubagents: true,
13152
- maxSubagentDepth: 1
13152
+ maxSubagentDepth: 2
13153
13153
  }
13154
13154
  },
13155
13155
  "infra-specialist": {
@@ -13180,7 +13180,7 @@ var AGENT_CATALOG = {
13180
13180
  "Dependency installation",
13181
13181
  "External environment changes"
13182
13182
  ],
13183
- maxConcurrentTasks: 1,
13183
+ maxConcurrentTasks: 2,
13184
13184
  policy: {
13185
13185
  sandboxMode: "workspace-write",
13186
13186
  requireApprovalPatterns: [
@@ -13192,7 +13192,7 @@ var AGENT_CATALOG = {
13192
13192
  "\\bapt(-get)?\\s+install\\b"
13193
13193
  ],
13194
13194
  canSpawnSubagents: true,
13195
- maxSubagentDepth: 1
13195
+ maxSubagentDepth: 2
13196
13196
  }
13197
13197
  },
13198
13198
  "test-debugger": {
@@ -33341,17 +33341,6 @@ function inferFallbackActionFromResponse(raw, task, request, allowedTools) {
33341
33341
  };
33342
33342
  }
33343
33343
  }
33344
- if (allowedTools.includes("scaffold.generate") && looksLikeStaticLandingGoal(request.goal) && 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")) {
33345
- return {
33346
- type: "tool",
33347
- tool: "scaffold.generate",
33348
- input: {
33349
- goal: request.goal,
33350
- preset: "static-landing"
33351
- },
33352
- reason: "Use the deterministic static-site adapter because the model stayed out of structured mode."
33353
- };
33354
- }
33355
33344
  if (!allowedTools.includes("file.write")) {
33356
33345
  return null;
33357
33346
  }
@@ -35036,6 +35025,26 @@ function buildSummary(shape, goal) {
35036
35025
  }
35037
35026
  return `Deliver "${goal}" through structured analysis, implementation, and verification milestones.`;
35038
35027
  }
35028
+ function buildPlanningSeedSummary(goal) {
35029
+ return `Create the best executable task graph for "${goal}" with dynamically chosen milestones, task count, and verification.`;
35030
+ }
35031
+ function planningSeedMilestone() {
35032
+ return {
35033
+ id: "m1-planning-seed",
35034
+ title: "Planning Seed",
35035
+ objective: "Schema-valid placeholder context for the planner model. Replace this seed with a real executable plan.",
35036
+ tasks: [
35037
+ buildTask("seed-plan-task", "Replace this planning seed with the real task graph", "This placeholder exists only so the planner model receives a schema-valid example. The final plan should replace it with concrete milestones and executable tasks tailored to the goal.", "planner", "documentation", [], [
35038
+ "The final plan removes the placeholder task.",
35039
+ "The final plan contains executable tasks with explicit dependencies and verification."
35040
+ ], [
35041
+ "Executable task graph"
35042
+ ], [
35043
+ "."
35044
+ ], "low")
35045
+ ]
35046
+ };
35047
+ }
35039
35048
  function createPlan(input) {
35040
35049
  const request = PlanRequestSchema.parse({
35041
35050
  ...input,
@@ -35065,6 +35074,33 @@ function createPlan(input) {
35065
35074
  ]
35066
35075
  });
35067
35076
  }
35077
+ function createPlanningSeed(input) {
35078
+ const request = PlanRequestSchema.parse({
35079
+ ...input,
35080
+ goal: normalizeGoal(input.goal)
35081
+ });
35082
+ const shape = inferProjectShape(request.goal);
35083
+ return KimbhoPlanSchema.parse({
35084
+ goal: request.goal,
35085
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
35086
+ summary: buildPlanningSeedSummary(request.goal),
35087
+ repoStrategy: {
35088
+ mode: request.workspaceState === "empty" ? "greenfield" : "existing-repo",
35089
+ reasoning: request.workspaceState === "empty" ? "No meaningful workspace contents were detected, so the planner can choose an opinionated greenfield graph." : "Existing workspace state should be analyzed and preserved while the planner chooses the execution graph."
35090
+ },
35091
+ assumptions: deriveAssumptions(shape, request),
35092
+ openQuestions: deriveOpenQuestions(shape),
35093
+ milestones: [
35094
+ planningSeedMilestone()
35095
+ ],
35096
+ verificationChecklist: deriveVerificationChecklist(shape),
35097
+ executionNotes: [
35098
+ "Replace the placeholder seed milestone with the real execution graph.",
35099
+ "Choose milestone count, task count, and dependencies dynamically from the goal.",
35100
+ "Keep deterministic fallback available only if model planning fails."
35101
+ ]
35102
+ });
35103
+ }
35068
35104
 
35069
35105
  // ../planner/dist/model-planner.js
35070
35106
  var DEFAULT_PLANNER_TEMPERATURE = 0.1;
@@ -35148,8 +35184,8 @@ function buildPlannerSystemPrompt() {
35148
35184
  "You are Kimbho's planner brain.",
35149
35185
  "Return one JSON object only. Do not use markdown fences or prose outside the JSON.",
35150
35186
  "The JSON must satisfy the KimbhoPlan schema used by Kimbho's runtime.",
35151
- "Prefer refining the provided seed plan instead of inventing a totally different graph.",
35152
- "Keep task ids stable and machine-friendly.",
35187
+ "For initial planning, choose the milestone count, task count, and task graph shape that best fits the request instead of mirroring the fallback plan.",
35188
+ "Keep task ids machine-friendly and stable within the returned plan.",
35153
35189
  "Use only these agent roles:",
35154
35190
  "- session-orchestrator",
35155
35191
  "- repo-analyst",
@@ -35180,8 +35216,9 @@ ${request.constraints.map((constraint) => `- ${constraint}`).join("\n")}` : "",
35180
35216
  "Seed plan JSON:",
35181
35217
  JSON.stringify(seedPlan, null, 2),
35182
35218
  "Instructions:",
35183
- "- Refine the seed plan into the best executable plan for this goal.",
35184
- "- Preserve the seed task ids unless there is a compelling execution reason not to.",
35219
+ "- Use the seed plan only as a fallback reference, not as a task-count template.",
35220
+ "- Produce the best executable plan for this goal, choosing milestone count and task count dynamically.",
35221
+ "- You may replace the seed task ids for the initial plan if a different graph is materially better.",
35185
35222
  "- Keep the plan concise, practical, and tool-executable."
35186
35223
  ].filter(Boolean).join("\n\n");
35187
35224
  }
@@ -35205,7 +35242,7 @@ ${request.constraints.map((constraint) => `- ${constraint}`).join("\n")}` : "",
35205
35242
  "- Adjust milestone wording, task descriptions, acceptance criteria, files, and dependencies only when the repo evidence justifies it."
35206
35243
  ].filter(Boolean).join("\n\n");
35207
35244
  }
35208
- async function generatePlannerPlan(request, seedPlan, invocation, userPrompt, preserveStatusesFrom) {
35245
+ async function generatePlannerPlan(request, seedPlan, fallbackPlan, invocation, userPrompt, preserveStatusesFrom, requireStableTaskIds = true) {
35209
35246
  try {
35210
35247
  const response = await invocation.generate({
35211
35248
  systemPrompt: buildPlannerSystemPrompt(),
@@ -35215,7 +35252,7 @@ async function generatePlannerPlan(request, seedPlan, invocation, userPrompt, pr
35215
35252
  });
35216
35253
  const parsed = extractJsonObjectish(response.text, "planner response");
35217
35254
  const candidatePlan = KimbhoPlanSchema.parse(parsed);
35218
- const normalized = normalizeCandidatePlan(request, seedPlan, candidatePlan, true, preserveStatusesFrom);
35255
+ const normalized = normalizeCandidatePlan(request, fallbackPlan, candidatePlan, requireStableTaskIds, preserveStatusesFrom);
35219
35256
  return {
35220
35257
  plan: normalized,
35221
35258
  source: "model",
@@ -35229,7 +35266,7 @@ async function generatePlannerPlan(request, seedPlan, invocation, userPrompt, pr
35229
35266
  };
35230
35267
  } catch (error2) {
35231
35268
  return {
35232
- plan: preserveStatusesFrom ? preserveTaskStatuses(preserveStatusesFrom, seedPlan) : seedPlan,
35269
+ plan: preserveStatusesFrom ? preserveTaskStatuses(preserveStatusesFrom, fallbackPlan) : fallbackPlan,
35233
35270
  source: "fallback",
35234
35271
  warning: summarizeStructuredOutputError("Planner", error2),
35235
35272
  ...invocation.modelLabel ? {
@@ -35239,18 +35276,19 @@ async function generatePlannerPlan(request, seedPlan, invocation, userPrompt, pr
35239
35276
  }
35240
35277
  }
35241
35278
  async function createPlanWithModel(request, invocation) {
35242
- const seedPlan = createPlan(request);
35243
- return generatePlannerPlan(request, seedPlan, invocation, buildInitialPlannerPrompt(request, seedPlan));
35279
+ const fallbackPlan = createPlan(request);
35280
+ const seedPlan = createPlanningSeed(request);
35281
+ return generatePlannerPlan(request, seedPlan, fallbackPlan, invocation, buildInitialPlannerPrompt(request, seedPlan), void 0, false);
35244
35282
  }
35245
35283
  async function revisePlanWithModel(request, currentPlan, repoSummary, invocation) {
35246
- return generatePlannerPlan(request, currentPlan, invocation, buildReplanPrompt(request, currentPlan, repoSummary), currentPlan);
35284
+ return generatePlannerPlan(request, currentPlan, currentPlan, invocation, buildReplanPrompt(request, currentPlan, repoSummary), currentPlan);
35247
35285
  }
35248
35286
 
35249
35287
  // ../planner/dist/task-expander.js
35250
35288
  var DEFAULT_EXPANDER_TEMPERATURE = 0.1;
35251
35289
  var DEFAULT_EXPANDER_MAX_TOKENS = 1600;
35252
35290
  var MAX_EXPANSION_CONTEXT_CHARS = 6e3;
35253
- var MAX_EXPANDED_SUBTASKS = 4;
35291
+ var MAX_EXPANDED_SUBTASKS = 6;
35254
35292
  var ExpansionCandidateTaskSchema = external_exports.object({
35255
35293
  id: external_exports.string().min(1).optional(),
35256
35294
  title: external_exports.string().min(1),
@@ -35310,7 +35348,7 @@ function createEntrySubtask(task, suffix, title, description) {
35310
35348
  };
35311
35349
  }
35312
35350
  function fallbackExpandedTasks(task) {
35313
- if ((task.swarmDepth ?? 0) >= 1) {
35351
+ if ((task.swarmDepth ?? 0) >= 2) {
35314
35352
  return null;
35315
35353
  }
35316
35354
  if (task.agentRole === "frontend-specialist" && task.type === "implementation") {
@@ -35326,10 +35364,24 @@ function fallbackExpandedTasks(task) {
35326
35364
  ]
35327
35365
  },
35328
35366
  {
35329
- ...createEntrySubtask(task, "polish", `Polish ${task.title.toLowerCase()} visuals and responsiveness`, `Refine styling, responsiveness, and interaction details after the content structure is in place.`),
35367
+ ...createEntrySubtask(task, "interaction", `Design ${task.title.toLowerCase()} interaction and motion`, `Define animation, scroll behavior, and interaction states once the content structure is clear.`),
35330
35368
  dependsOn: [
35331
35369
  `${task.id}-content`
35332
35370
  ],
35371
+ acceptanceCriteria: [
35372
+ "Interaction patterns and motion direction are explicit.",
35373
+ "Primary calls to action and navigation states feel intentional."
35374
+ ],
35375
+ outputs: [
35376
+ "Interaction and motion direction"
35377
+ ]
35378
+ },
35379
+ {
35380
+ ...createEntrySubtask(task, "polish", `Polish ${task.title.toLowerCase()} visuals and responsiveness`, `Refine styling, responsiveness, and interaction details after the content structure is in place.`),
35381
+ dependsOn: [
35382
+ `${task.id}-content`,
35383
+ `${task.id}-interaction`
35384
+ ],
35333
35385
  acceptanceCriteria: [
35334
35386
  ...task.acceptanceCriteria,
35335
35387
  "Responsive behavior and visual polish are verified."
@@ -35532,9 +35584,10 @@ function buildExpansionPrompt(request, plan, task, repoSummary) {
35532
35584
  "Repo context:",
35533
35585
  truncate2(repoSummary),
35534
35586
  "Instructions:",
35535
- "- Replace the target task with 2-4 narrower subtasks.",
35587
+ `- Replace the target task with 2-${MAX_EXPANDED_SUBTASKS} narrower subtasks.`,
35536
35588
  "- Preserve the target task's overall intent, but make execution more parallel-friendly when safe.",
35537
35589
  "- Keep dependencies explicit and machine-valid.",
35590
+ "- Prefer at least 3 subtasks for broad frontend or product-surface work when the task can be split safely.",
35538
35591
  "- Prefer roles like frontend-specialist, backend-specialist, database-specialist, infra-specialist, reviewer, and test-debugger when they fit."
35539
35592
  ].join("\n\n");
35540
35593
  }
@@ -35551,7 +35604,7 @@ ${task.acceptanceCriteria.map((criterion) => `- ${criterion}`).join("\n") || "-
35551
35604
  ].filter(Boolean).join("\n\n");
35552
35605
  }
35553
35606
  function shouldExpandTask(task) {
35554
- if ((task.swarmDepth ?? 0) >= 1) {
35607
+ if ((task.swarmDepth ?? 0) >= 2) {
35555
35608
  return false;
35556
35609
  }
35557
35610
  if (task.type !== "implementation") {
@@ -36673,9 +36726,6 @@ function shouldDelegateTask(task, request) {
36673
36726
  if (!canSpawnSubagents) {
36674
36727
  return false;
36675
36728
  }
36676
- if ((looksLikeVisualAdjustmentGoal(request.goal) || looksLikePageExpansionGoal(request.goal)) && isStaticSiteTask(task, request)) {
36677
- return false;
36678
- }
36679
36729
  return (task.swarmDepth ?? 0) < maxSubagentDepth && task.type === "implementation" && ![
36680
36730
  "repo-analyst",
36681
36731
  "planner",
@@ -36714,6 +36764,20 @@ function createDefaultDelegationPlan(task, request) {
36714
36764
  "Structured page/content update"
36715
36765
  ]
36716
36766
  },
36767
+ {
36768
+ id: "interaction-designer",
36769
+ label: "interaction-designer",
36770
+ agentRole: "frontend-specialist",
36771
+ description: "Own motion design, interaction states, scroll behavior, and narrative pacing.",
36772
+ instructions: "Focus on animation, interaction states, scroll rhythm, and motion hierarchy. Keep motion purposeful and aligned with the requested design direction.",
36773
+ acceptanceCriteria: [
36774
+ "Interaction patterns and motion choices are explicit.",
36775
+ "The page has a coherent motion system without distracting from the content."
36776
+ ],
36777
+ outputs: [
36778
+ "Interaction and motion design update"
36779
+ ]
36780
+ },
36717
36781
  {
36718
36782
  id: "visual-polisher",
36719
36783
  label: "visual-polisher",
@@ -37323,8 +37387,8 @@ var ExecutionOrchestrator = class {
37323
37387
  let pendingApprovals = [
37324
37388
  ...session.pendingApprovals
37325
37389
  ];
37326
- const maxAutoTasks = options.maxAutoTasks ?? 2;
37327
- const maxParallelTasks = Math.max(1, options.maxParallelTasks ?? 2);
37390
+ const maxAutoTasks = options.maxAutoTasks ?? 4;
37391
+ const maxParallelTasks = Math.max(1, options.maxParallelTasks ?? 4);
37328
37392
  let executedTasks = 0;
37329
37393
  for (const approval of session.pendingApprovals) {
37330
37394
  const decision = decisionByApprovalId.get(approval.id);
@@ -37640,7 +37704,8 @@ var ExecutionOrchestrator = class {
37640
37704
  }
37641
37705
  const profile = AGENT_CATALOG[task.agentRole];
37642
37706
  const currentRoleCount = roleCounts.get(task.agentRole) ?? 0;
37643
- if (currentRoleCount >= profile.maxConcurrentTasks) {
37707
+ const effectiveConcurrency = Math.max(profile.maxConcurrentTasks, task.agentRole === "frontend-specialist" || task.agentRole === "backend-specialist" ? 3 : profile.maxConcurrentTasks);
37708
+ if (currentRoleCount >= effectiveConcurrency) {
37644
37709
  continue;
37645
37710
  }
37646
37711
  selected.push(task);
@@ -37660,9 +37725,6 @@ var ExecutionOrchestrator = class {
37660
37725
  if (task.agentRole === "planner") {
37661
37726
  return this.executePlannerTask(sessionId, task, request, plan, emitProgress);
37662
37727
  }
37663
- if (request.workspaceState === "existing" && isStaticSiteTask(task, request) && (task.type === "scaffold" || task.type === "implementation")) {
37664
- return this.executeDeterministicStaticSiteTask(sessionId, task, request, resolvedApproval, options, emitProgress);
37665
- }
37666
37728
  if (request.workspaceState === "existing" && looksLikeStaticLandingGoal(request.goal) && task.type === "verification") {
37667
37729
  return this.executeDeterministicVerificationTask(sessionId, task, request, emitProgress, options.signal);
37668
37730
  }
@@ -39693,7 +39755,7 @@ async function executePromptByIntent(cwd, input, options = {}) {
39693
39755
  }
39694
39756
  return executeRunPrompt(cwd, input, options.outputFormat ?? "json", {
39695
39757
  ephemeral: options.ephemeral ?? false,
39696
- maxAutoTasks: options.maxAutoTasks ?? 3,
39758
+ maxAutoTasks: options.maxAutoTasks ?? 4,
39697
39759
  maxAgentSteps: options.maxAgentSteps ?? 8,
39698
39760
  maxRepairAttempts: options.maxRepairAttempts ?? 2,
39699
39761
  ...options.sessionId ? {
@@ -39714,7 +39776,7 @@ function createExecCommand() {
39714
39776
  ], []).option("--image <pathOrUrl>", "Attach an image to the prompt", (value, previous = []) => [
39715
39777
  ...previous,
39716
39778
  value
39717
- ], []).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount, 3).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount, 2).action(async (rawPrompt, options) => {
39779
+ ], []).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount, 2).action(async (rawPrompt, options) => {
39718
39780
  const cwd = import_node_process5.default.cwd();
39719
39781
  const format = options.json ? "json" : options.outputFormat;
39720
39782
  const agentSelection = await resolveAgentSelection(cwd, {
@@ -42190,7 +42252,7 @@ async function resolveSourceSession(cwd, sessionId, last = false, search) {
42190
42252
  return loadSessionById(sessionId, cwd);
42191
42253
  }
42192
42254
  function createForkCommand() {
42193
- return new Command("fork").description("Fork a saved session into a new session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--last", "Fork the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--json", "Print the forked snapshot as JSON", false).option("--execute", "Continue auto-executing the forked session", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount3, 3).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount3, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount3, 2).action(async (sessionId, options) => {
42255
+ return new Command("fork").description("Fork a saved session into a new session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--last", "Fork the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--json", "Print the forked snapshot as JSON", false).option("--execute", "Continue auto-executing the forked session", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount3, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount3, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount3, 2).action(async (sessionId, options) => {
42194
42256
  const cwd = import_node_process12.default.cwd();
42195
42257
  if (options.list) {
42196
42258
  const sessions = options.search ? await searchSessions(options.search, cwd) : await listSessions(cwd);
@@ -43360,7 +43422,7 @@ function parseCount4(value) {
43360
43422
  return parsed;
43361
43423
  }
43362
43424
  function createResumeCommand() {
43363
- return new Command("resume").alias("continue").description("Resume the latest saved Kimbho session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--json", "Print the latest session as JSON", false).option("--last", "Resume the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--execute", "Continue auto-executing the ready-task frontier", false).option("--approve <approvalId>", "Approve a pending action before continuing").option("--deny <approvalId>", "Deny a pending action before continuing").option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount4, 3).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount4, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount4, 2).action(async (sessionId, options) => {
43425
+ return new Command("resume").alias("continue").description("Resume the latest saved Kimbho session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--json", "Print the latest session as JSON", false).option("--last", "Resume the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--execute", "Continue auto-executing the ready-task frontier", false).option("--approve <approvalId>", "Approve a pending action before continuing").option("--deny <approvalId>", "Deny a pending action before continuing").option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount4, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount4, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount4, 2).action(async (sessionId, options) => {
43364
43426
  const cwd = import_node_process23.default.cwd();
43365
43427
  const firstSearchMatch = options.search ? (await searchSessions(options.search, cwd, 1)).at(0) ?? null : null;
43366
43428
  if (options.list) {
@@ -43439,7 +43501,7 @@ function createRunCommand() {
43439
43501
  "Explicit execution constraint; can be provided multiple times",
43440
43502
  (value, previous = []) => [...previous, value],
43441
43503
  []
43442
- ).option("--json", "Print the session snapshot as JSON", false).option("--snapshot-only", "Create the session without auto-executing ready tasks", false).option("--agent <id>", "Prefer one custom or plugin agent id for this session").option("--agents <jsonOrPath>", "Inline agent definitions as JSON or a path to a JSON file").option("--session-id <id>", "Use an explicit session id").option("--ephemeral", "Do not persist plans or sessions for this invocation", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount5, 3).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount5, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount5, 2).action(async (goal, options) => {
43504
+ ).option("--json", "Print the session snapshot as JSON", false).option("--snapshot-only", "Create the session without auto-executing ready tasks", false).option("--agent <id>", "Prefer one custom or plugin agent id for this session").option("--agents <jsonOrPath>", "Inline agent definitions as JSON or a path to a JSON file").option("--session-id <id>", "Use an explicit session id").option("--ephemeral", "Do not persist plans or sessions for this invocation", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount5, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount5, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount5, 2).action(async (goal, options) => {
43443
43505
  const cwd = import_node_process24.default.cwd();
43444
43506
  const orchestrator = new ExecutionOrchestrator();
43445
43507
  const agentSelection = await resolveAgentSelection(cwd, {
@@ -44084,6 +44146,11 @@ function shouldAutoStartApprovedRuns(runtime) {
44084
44146
  const approvalMode = resolveRuntimeOverrideApprovalMode(runtime);
44085
44147
  return approvalMode === "auto" || approvalMode === "dontAsk" || approvalMode === "acceptEdits" || approvalMode === "bypassPermissions";
44086
44148
  }
44149
+ function shouldAutoStartProposal(runtime, proposal) {
44150
+ return Boolean(
44151
+ proposal && shouldAutoStartApprovedRuns(runtime) && !planRequiresOperatorReview(proposal.plan)
44152
+ );
44153
+ }
44087
44154
  function resolveShellMaxAutoTasks(runtime) {
44088
44155
  return shouldAutoStartApprovedRuns(runtime) ? UNBOUNDED_MAX_AUTO_TASKS : DEFAULT_MAX_AUTO_TASKS;
44089
44156
  }
@@ -44681,6 +44748,21 @@ function pickStatusLabel(message) {
44681
44748
  function pickIdleStatusLabel(seed) {
44682
44749
  return IDLE_STATUS_LABELS[hashString(seed) % IDLE_STATUS_LABELS.length];
44683
44750
  }
44751
+ function statusLabelForToolStart(event) {
44752
+ if (event.toolId === "shell.exec" || event.toolId === "tests.run") {
44753
+ const command = typeof event.input?.command === "string" ? event.input.command.trim().toLowerCase() : "";
44754
+ if (command.includes("build") || command.includes("lint") || command.includes("test")) {
44755
+ return "verifying";
44756
+ }
44757
+ if (command.includes("dev") || command.includes("start")) {
44758
+ return "serving";
44759
+ }
44760
+ if (command.length > 0) {
44761
+ return pickStatusLabel(command);
44762
+ }
44763
+ }
44764
+ return pickStatusLabel(event.reason ?? event.toolId);
44765
+ }
44684
44766
  function statusLabelForEvent(event) {
44685
44767
  switch (event.type) {
44686
44768
  case "task-note":
@@ -44688,7 +44770,7 @@ function statusLabelForEvent(event) {
44688
44770
  case "task-started":
44689
44771
  return pickStatusLabel(event.task.title);
44690
44772
  case "tool-started":
44691
- return pickStatusLabel(event.reason ?? event.toolId);
44773
+ return statusLabelForToolStart(event);
44692
44774
  case "model-usage":
44693
44775
  return "thinking";
44694
44776
  case "approval-requested":
@@ -44798,14 +44880,67 @@ function renderShellPlanSummary(plan) {
44798
44880
  }
44799
44881
  return lines;
44800
44882
  }
44883
+ function inferRecommendedPlanAnswer(question, plan) {
44884
+ const lower = question.toLowerCase();
44885
+ const goal = plan.goal.toLowerCase();
44886
+ if (lower.includes("brand voice") || lower.includes("visual direction")) {
44887
+ if (goal.includes("blog") || goal.includes("post")) {
44888
+ return "Use a premium editorial direction: clean typography, strong whitespace, restrained motion, and a polished reading-first layout.";
44889
+ }
44890
+ return "Use a restrained premium product direction: crisp typography, strong whitespace, subtle motion, and a clear call to action.";
44891
+ }
44892
+ if (lower.includes("which sections")) {
44893
+ if (goal.includes("blog") || goal.includes("post")) {
44894
+ return "Start with navigation, hero, featured posts, topic/category grid, newsletter CTA, and a compact footer.";
44895
+ }
44896
+ return "Start with navigation, hero, key benefits, proof/examples, primary CTA, and footer.";
44897
+ }
44898
+ if (lower.includes("primary call to action")) {
44899
+ if (goal.includes("blog") || goal.includes("post")) {
44900
+ return "Drive readers to featured posts first, with newsletter signup as the secondary CTA.";
44901
+ }
44902
+ return "Drive the main product action with one clear primary CTA and keep secondary actions minimal.";
44903
+ }
44904
+ if (lower.includes("which stack") || lower.includes("deployment target")) {
44905
+ return "Stay with the current repo stack and existing deployment shape unless the user asks for a migration.";
44906
+ }
44907
+ if (lower.includes("authentication model")) {
44908
+ return "Assume no authentication in the first version unless the request explicitly needs gated user flows.";
44909
+ }
44910
+ if (lower.includes("external services") || lower.includes("apis")) {
44911
+ return "Assume no new external integrations beyond what already exists in the repository.";
44912
+ }
44913
+ return "Proceed with the most pragmatic default that preserves the current repo and keeps the first version focused.";
44914
+ }
44915
+ function extractPlanReviewPrompts(plan) {
44916
+ return plan.openQuestions.slice(0, 3).map((question) => ({
44917
+ question,
44918
+ recommendation: inferRecommendedPlanAnswer(question, plan)
44919
+ }));
44920
+ }
44921
+ function planRequiresOperatorReview(plan) {
44922
+ return extractPlanReviewPrompts(plan).length > 0;
44923
+ }
44801
44924
  function renderPendingRunProposal(proposal, options = {}) {
44925
+ const reviewPrompts = extractPlanReviewPrompts(proposal.plan);
44926
+ const requiresReview = reviewPrompts.length > 0;
44802
44927
  const lines = [
44803
44928
  `${color(BOLD, proposal.source === "queued" ? "Queued Plan Ready" : "Ready To Run")}`,
44804
- ...renderShellPlanSummary(proposal.plan),
44805
- "",
44806
- color(DIM, `saved plan: ${proposal.planPath}`),
44807
- options.autoStart ? color(DIM, "next: auto-starting in the current permission mode") : "next: /approve to start, /run revise <feedback> to adjust, /run cancel to drop it"
44929
+ ...renderShellPlanSummary(proposal.plan)
44808
44930
  ];
44931
+ if (requiresReview) {
44932
+ lines.push("");
44933
+ lines.push(color(BOLD, "Recommended Defaults"));
44934
+ for (const prompt of reviewPrompts) {
44935
+ lines.push(`\u2022 ${prompt.question}`);
44936
+ lines.push(color(DIM, ` recommended: ${prompt.recommendation}`));
44937
+ }
44938
+ }
44939
+ lines.push("");
44940
+ lines.push(color(DIM, `saved plan: ${proposal.planPath}`));
44941
+ lines.push(
44942
+ requiresReview ? "next: /run approve to accept the recommended defaults, /run revise <feedback> to adjust, /run cancel to drop it" : options.autoStart ? color(DIM, "next: auto-starting in the current permission mode") : "next: /approve to start, /run revise <feedback> to adjust, /run cancel to drop it"
44943
+ );
44809
44944
  if (proposal.source === "queued") {
44810
44945
  lines.splice(1, 0, color(DIM, "The next queued request has been planned and is waiting for your approval."));
44811
44946
  }
@@ -44903,6 +45038,24 @@ function renderConciseProgress(board, startedAt) {
44903
45038
  ] : []
44904
45039
  ];
44905
45040
  }
45041
+ function summarizeToolStart(event) {
45042
+ if (event.toolId === "shell.exec" || event.toolId === "tests.run") {
45043
+ const command = typeof event.input?.command === "string" ? event.input.command.trim() : "";
45044
+ if (command) {
45045
+ return `Running ${shortenMiddle(command, 90)}`;
45046
+ }
45047
+ }
45048
+ if (event.toolId === "http.fetch" && typeof event.input?.url === "string") {
45049
+ return `Checking ${shortenMiddle(event.input.url, 90)}`;
45050
+ }
45051
+ if (event.toolId === "process.start" && typeof event.input?.command === "string") {
45052
+ return `Starting ${shortenMiddle(event.input.command, 90)}`;
45053
+ }
45054
+ if (event.toolId === "browser.open" && typeof event.input?.url === "string") {
45055
+ return `Opening ${shortenMiddle(event.input.url, 90)}`;
45056
+ }
45057
+ return null;
45058
+ }
44906
45059
  function renderLiveExecutionEvent(event, board, startedAt) {
44907
45060
  switch (event.type) {
44908
45061
  case "task-started":
@@ -44918,6 +45071,13 @@ function renderLiveExecutionEvent(event, board, startedAt) {
44918
45071
  )} ${simplifyExecutionSummary(event.summary) || event.taskId}`,
44919
45072
  ...renderConciseProgress(board, startedAt)
44920
45073
  ];
45074
+ case "tool-started": {
45075
+ const summary = summarizeToolStart(event);
45076
+ return summary ? [
45077
+ `${color(DIM, "working")} ${summary}`,
45078
+ ...renderConciseProgress(board, startedAt)
45079
+ ] : [];
45080
+ }
44921
45081
  case "task-note":
44922
45082
  return isUserVisibleTaskNote(event.message) ? [
44923
45083
  `${color(DIM, "note")} ${simplifyTaskNote(event.message)}`
@@ -45096,7 +45256,7 @@ async function drainQueuedWork(runtime) {
45096
45256
  source: "queued"
45097
45257
  });
45098
45258
  runtime.currentCwd = nextCwd;
45099
- if (shouldAutoStartApprovedRuns(runtime)) {
45259
+ if (shouldAutoStartProposal(runtime, runtime.pendingRunProposal)) {
45100
45260
  console.log(color(DIM, "Auto-starting queued request in the current permission mode."));
45101
45261
  startPendingRunExecution(runtime);
45102
45262
  }
@@ -45269,7 +45429,7 @@ async function prepareRunProposal(cwd, goal, runtime, options = {}) {
45269
45429
  console.log(renderPendingRunProposal(
45270
45430
  runtime.pendingRunProposal,
45271
45431
  {
45272
- autoStart: shouldAutoStartApprovedRuns(runtime)
45432
+ autoStart: shouldAutoStartProposal(runtime, runtime.pendingRunProposal)
45273
45433
  }
45274
45434
  ).join("\n"));
45275
45435
  return request.cwd;
@@ -46679,7 +46839,7 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
46679
46839
  const nextCwd = await prepareRunProposal(cwd, trimmed, runtime, {
46680
46840
  source: "direct"
46681
46841
  });
46682
- if (shouldAutoStartApprovedRuns(runtime)) {
46842
+ if (shouldAutoStartProposal(runtime, runtime.pendingRunProposal)) {
46683
46843
  console.log(color(DIM, "Auto-starting in the current permission mode."));
46684
46844
  startPendingRunExecution(runtime);
46685
46845
  }
@@ -46809,7 +46969,7 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
46809
46969
  console.log(renderPendingRunProposal(
46810
46970
  runtime.pendingRunProposal,
46811
46971
  {
46812
- autoStart: shouldAutoStartApprovedRuns(runtime)
46972
+ autoStart: shouldAutoStartProposal(runtime, runtime.pendingRunProposal)
46813
46973
  }
46814
46974
  ).join("\n"));
46815
46975
  return cwd;
@@ -46846,7 +47006,7 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
46846
47006
  const nextCwd = await prepareRunProposal(cwd, goal, runtime, {
46847
47007
  source: "direct"
46848
47008
  });
46849
- if (shouldAutoStartApprovedRuns(runtime)) {
47009
+ if (shouldAutoStartProposal(runtime, runtime.pendingRunProposal)) {
46850
47010
  console.log(color(DIM, "Auto-starting in the current permission mode."));
46851
47011
  startPendingRunExecution(runtime);
46852
47012
  }