@kimbho/kimbho-cli 0.1.16 → 0.1.18

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.18",
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),
@@ -28070,6 +28072,9 @@ function buildSystemPrompt(agent, task, request, allowedTools, plan, extraInstru
28070
28072
  return [
28071
28073
  `You are Kimbho's ${agent.role}.`,
28072
28074
  `Purpose: ${agent.purpose}`,
28075
+ ...task.subagentLabel ? [
28076
+ `Delegated worker: ${task.subagentLabel}`
28077
+ ] : [],
28073
28078
  `Goal: ${request.goal}`,
28074
28079
  `Current task: ${task.id} - ${task.title}`,
28075
28080
  `Task description: ${task.description}`,
@@ -28103,6 +28108,10 @@ function buildSystemPrompt(agent, task, request, allowedTools, plan, extraInstru
28103
28108
  `- After changing code, run verification with tests.run or shell.exec when appropriate.`,
28104
28109
  `- Do not claim success unless the task acceptance criteria are satisfied.`,
28105
28110
  `- If the task is underspecified, make a pragmatic implementation choice and continue.`,
28111
+ ...task.subagentInstructions ? [
28112
+ `Delegation instructions:`,
28113
+ task.subagentInstructions
28114
+ ] : [],
28106
28115
  ...extraInstructions ? [
28107
28116
  `Custom instructions:`,
28108
28117
  extraInstructions
@@ -31142,6 +31151,280 @@ function isStaticSiteTask(task, request) {
31142
31151
  }
31143
31152
  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
31153
  }
31154
+ function shouldDelegateTask(task) {
31155
+ return (task.swarmDepth ?? 0) === 0 && task.type === "implementation" && ![
31156
+ "repo-analyst",
31157
+ "planner",
31158
+ "reviewer",
31159
+ "integrator",
31160
+ "test-debugger",
31161
+ "session-orchestrator",
31162
+ "execution-manager"
31163
+ ].includes(task.agentRole);
31164
+ }
31165
+ function terminalExpansionTaskIds(tasks) {
31166
+ const referencedIds = new Set(tasks.flatMap((task) => task.dependsOn));
31167
+ const terminalIds = tasks.filter((task) => !referencedIds.has(task.id)).map((task) => task.id);
31168
+ return terminalIds.length > 0 ? terminalIds : tasks.map((task) => task.id);
31169
+ }
31170
+ function createDefaultDelegationPlan(task, request) {
31171
+ if (!shouldDelegateTask(task)) {
31172
+ return null;
31173
+ }
31174
+ if (task.agentRole === "frontend-specialist" || isStaticSiteTask(task, request)) {
31175
+ return {
31176
+ label: "auto-frontend-swarm",
31177
+ strategy: "parallel",
31178
+ members: [
31179
+ {
31180
+ id: "content-architect",
31181
+ label: "content-architect",
31182
+ agentRole: "frontend-specialist",
31183
+ description: "Own information architecture, page composition, navigation, copy structure, and section flow.",
31184
+ instructions: "Prioritize semantic layout, page structure, routes, content hierarchy, and component composition. Leave purely visual polish to the visual worker unless structure blocks it.",
31185
+ acceptanceCriteria: [
31186
+ "The page structure, sections, and navigation flow are clear and coherent.",
31187
+ "Content hierarchy reflects the requested product, brand, or venue."
31188
+ ],
31189
+ outputs: [
31190
+ "Structured page/content update"
31191
+ ]
31192
+ },
31193
+ {
31194
+ id: "visual-polisher",
31195
+ label: "visual-polisher",
31196
+ agentRole: "frontend-specialist",
31197
+ description: "Own styling, gradients, motion, responsiveness, spacing, and visual finishing.",
31198
+ 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.",
31199
+ acceptanceCriteria: [
31200
+ "Visual styling and responsiveness are meaningfully improved.",
31201
+ "Motion and polish remain consistent with the requested UI direction."
31202
+ ],
31203
+ outputs: [
31204
+ "Visual polish update"
31205
+ ]
31206
+ }
31207
+ ]
31208
+ };
31209
+ }
31210
+ if (task.agentRole === "backend-specialist") {
31211
+ return {
31212
+ label: "auto-backend-swarm",
31213
+ strategy: "sequential",
31214
+ members: [
31215
+ {
31216
+ id: "contract-architect",
31217
+ label: "contract-architect",
31218
+ agentRole: "backend-specialist",
31219
+ description: "Define the API/service surface, request-response shapes, and failure behavior.",
31220
+ instructions: "Focus on service and API contracts, input/output shapes, handlers, and edge cases before broad implementation changes.",
31221
+ acceptanceCriteria: [
31222
+ "Contracts and failure cases are explicit.",
31223
+ "The implementation path is narrowed to concrete handlers or services."
31224
+ ],
31225
+ outputs: [
31226
+ "Backend contract design"
31227
+ ]
31228
+ },
31229
+ {
31230
+ id: "service-implementer",
31231
+ label: "service-implementer",
31232
+ agentRole: "backend-specialist",
31233
+ description: "Implement handlers, services, and domain logic against the agreed contract.",
31234
+ instructions: "Implement the core backend behavior against the established contract. Prefer targeted file edits and verification over broad rewrites.",
31235
+ acceptanceCriteria: [
31236
+ "Business logic is implemented against the contract.",
31237
+ "The backend behavior satisfies the task acceptance criteria."
31238
+ ],
31239
+ outputs: [
31240
+ "Backend implementation"
31241
+ ]
31242
+ }
31243
+ ]
31244
+ };
31245
+ }
31246
+ if (task.agentRole === "database-specialist") {
31247
+ return {
31248
+ label: "auto-database-swarm",
31249
+ strategy: "sequential",
31250
+ members: [
31251
+ {
31252
+ id: "schema-designer",
31253
+ label: "schema-designer",
31254
+ agentRole: "database-specialist",
31255
+ description: "Design models, fields, relations, constraints, and persistence boundaries.",
31256
+ instructions: "Focus on schema structure, data modeling, constraints, and identifiers. Keep the migration path safe and explicit.",
31257
+ acceptanceCriteria: [
31258
+ "Schema design reflects the requested domain.",
31259
+ "Constraints and data relationships are explicit."
31260
+ ],
31261
+ outputs: [
31262
+ "Schema design"
31263
+ ]
31264
+ },
31265
+ {
31266
+ id: "migration-planner",
31267
+ label: "migration-planner",
31268
+ agentRole: "database-specialist",
31269
+ description: "Apply or prepare migrations and persistence wiring around the approved schema.",
31270
+ instructions: "Translate the schema design into migrations or persistence updates. Keep destructive changes obvious and verification-friendly.",
31271
+ acceptanceCriteria: [
31272
+ "Persistence updates align with the intended schema.",
31273
+ "Migration risk and verification needs are explicit."
31274
+ ],
31275
+ outputs: [
31276
+ "Migration/persistence update"
31277
+ ]
31278
+ }
31279
+ ]
31280
+ };
31281
+ }
31282
+ if (task.agentRole === "infra-specialist") {
31283
+ return {
31284
+ label: "auto-infra-swarm",
31285
+ strategy: "sequential",
31286
+ members: [
31287
+ {
31288
+ id: "workspace-scaffolder",
31289
+ label: "workspace-scaffolder",
31290
+ agentRole: "infra-specialist",
31291
+ description: "Set up required files, scripts, package wiring, and environment plumbing.",
31292
+ instructions: "Focus on scaffolding, package manifests, scripts, environment wiring, and local runtime setup. Keep the workspace runnable.",
31293
+ acceptanceCriteria: [
31294
+ "Required scaffolding and environment wiring are in place.",
31295
+ "The workspace can proceed into implementation or verification."
31296
+ ],
31297
+ outputs: [
31298
+ "Workspace scaffolding"
31299
+ ]
31300
+ },
31301
+ {
31302
+ id: "runtime-verifier",
31303
+ label: "runtime-verifier",
31304
+ agentRole: "infra-specialist",
31305
+ description: "Verify build/runtime setup and tighten any configuration or tooling gaps.",
31306
+ instructions: "Focus on runtime, toolchain, script, and build verification after the initial setup work has landed.",
31307
+ acceptanceCriteria: [
31308
+ "The environment or app can be verified locally.",
31309
+ "Tooling and configuration gaps are closed."
31310
+ ],
31311
+ outputs: [
31312
+ "Runtime/config verification"
31313
+ ]
31314
+ }
31315
+ ]
31316
+ };
31317
+ }
31318
+ return null;
31319
+ }
31320
+ function materializeDelegatedTasks(plan, task, label, strategy, members) {
31321
+ const existingIds = new Set(flattenPlanTasks(plan).filter((candidate) => candidate.id !== task.id).map((candidate) => candidate.id));
31322
+ const teamMemberIds = members.map((member) => member.id);
31323
+ const generatedTaskIds = members.map((member, index) => createUniqueTaskId2(`${task.id}-${slugify2(member.id) || `worker-${index + 1}`}`, existingIds));
31324
+ return members.map((member, index) => {
31325
+ const taskId = generatedTaskIds[index];
31326
+ const dependsOn = strategy === "parallel" ? [
31327
+ ...task.dependsOn
31328
+ ] : index === 0 ? [
31329
+ ...task.dependsOn
31330
+ ] : [
31331
+ generatedTaskIds[index - 1]
31332
+ ];
31333
+ return {
31334
+ ...task,
31335
+ id: taskId,
31336
+ title: `${task.title} (${member.label})`,
31337
+ description: [
31338
+ task.description,
31339
+ `Delegated worker: ${member.label}.`,
31340
+ member.description
31341
+ ].join("\n\n"),
31342
+ agentRole: member.agentRole,
31343
+ dependsOn,
31344
+ acceptanceCriteria: member.acceptanceCriteria?.length ? member.acceptanceCriteria : index === members.length - 1 ? task.acceptanceCriteria : [
31345
+ `Advance ${task.title.toLowerCase()} from the ${member.label} perspective.`,
31346
+ "Leave concrete implementation evidence for the next worker."
31347
+ ],
31348
+ outputs: member.outputs?.length ? member.outputs : index === members.length - 1 ? task.outputs : [
31349
+ `Delegated handoff from ${member.id}`
31350
+ ],
31351
+ filesLikelyTouched: member.filesLikelyTouched?.length ? member.filesLikelyTouched : task.filesLikelyTouched,
31352
+ originTaskId: task.id,
31353
+ swarmDepth: (task.swarmDepth ?? 0) + 1,
31354
+ teamId: label,
31355
+ teamMemberIds,
31356
+ subagentLabel: member.label,
31357
+ subagentInstructions: member.instructions
31358
+ };
31359
+ });
31360
+ }
31361
+ function appendReviewAndIntegrationTasks(plan, originalTask, expandedTasks, delegationLabel) {
31362
+ const existingIds = new Set(flattenPlanTasks(plan).filter((candidate) => candidate.id !== originalTask.id).map((candidate) => candidate.id));
31363
+ for (const task of expandedTasks) {
31364
+ existingIds.add(task.id);
31365
+ }
31366
+ const terminalIds = terminalExpansionTaskIds(expandedTasks);
31367
+ const reviewerId = createUniqueTaskId2(`${originalTask.id}-review`, existingIds);
31368
+ const integratorId = createUniqueTaskId2(`${originalTask.id}-integrate`, existingIds);
31369
+ const reviewerTask = {
31370
+ ...originalTask,
31371
+ id: reviewerId,
31372
+ title: `Review ${originalTask.title.toLowerCase()}`,
31373
+ description: `Inspect delegated worker output from ${delegationLabel} before integration and call out correctness or verification risk.`,
31374
+ type: "verification",
31375
+ agentRole: "reviewer",
31376
+ dependsOn: terminalIds,
31377
+ acceptanceCriteria: [
31378
+ "Inspect the delegated changes for regressions or missing coverage.",
31379
+ "Confirm whether the worker output is ready for integration."
31380
+ ],
31381
+ outputs: [
31382
+ "Review summary"
31383
+ ],
31384
+ originTaskId: originalTask.id,
31385
+ swarmDepth: (originalTask.swarmDepth ?? 0) + 1,
31386
+ teamId: delegationLabel,
31387
+ teamMemberIds: [
31388
+ ...originalTask.teamMemberIds ?? [],
31389
+ "reviewer"
31390
+ ],
31391
+ subagentLabel: "reviewer",
31392
+ subagentInstructions: "Inspect the delegated changes, diff, and verification evidence. Surface concrete risks before integration."
31393
+ };
31394
+ const integratorTask = {
31395
+ ...originalTask,
31396
+ id: integratorId,
31397
+ title: `Integrate ${originalTask.title.toLowerCase()}`,
31398
+ description: `Finalize and integrate delegated worker output after reviewer sign-off for ${delegationLabel}.`,
31399
+ type: "integration",
31400
+ agentRole: "integrator",
31401
+ dependsOn: [
31402
+ reviewerId
31403
+ ],
31404
+ acceptanceCriteria: originalTask.acceptanceCriteria,
31405
+ outputs: mergeUnique([
31406
+ ...originalTask.outputs,
31407
+ "Integrated change set"
31408
+ ]),
31409
+ originTaskId: originalTask.id,
31410
+ swarmDepth: (originalTask.swarmDepth ?? 0) + 1,
31411
+ teamId: delegationLabel,
31412
+ teamMemberIds: [
31413
+ ...originalTask.teamMemberIds ?? [],
31414
+ "integrator"
31415
+ ],
31416
+ subagentLabel: "integrator",
31417
+ subagentInstructions: "Finalize the accepted worker output, preserve repository consistency, and leave the workspace ready for downstream verification."
31418
+ };
31419
+ return {
31420
+ tasks: [
31421
+ ...expandedTasks,
31422
+ reviewerTask,
31423
+ integratorTask
31424
+ ],
31425
+ noteSuffix: `review tail ${reviewerId} -> integration tail ${integratorId}`
31426
+ };
31427
+ }
31145
31428
  function renderToolResultSection(results) {
31146
31429
  return results.map((result) => {
31147
31430
  const lines = [
@@ -32199,15 +32482,7 @@ var ExecutionOrchestrator = class {
32199
32482
  }
32200
32483
  async maybeExpandReadyTaskGraph(sessionId, request, plan, events, emitProgress) {
32201
32484
  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));
32485
+ const candidate = envelope.readyTasks.find((task) => shouldDelegateTask(task));
32211
32486
  if (!candidate) {
32212
32487
  return {
32213
32488
  plan
@@ -32215,47 +32490,37 @@ var ExecutionOrchestrator = class {
32215
32490
  }
32216
32491
  const matchedTeam = await selectAgentTeam(request.cwd, candidate, request);
32217
32492
  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(", ")}.`;
32493
+ const teamTasks = materializeDelegatedTasks(plan, candidate, matchedTeam.team.id, matchedTeam.team.strategy, matchedTeam.members.map((member) => ({
32494
+ id: member.id,
32495
+ label: member.label,
32496
+ agentRole: member.baseRole,
32497
+ description: [
32498
+ `Assigned team member: ${member.label} (${member.id}).`,
32499
+ member.purpose ? `Purpose: ${member.purpose}` : "",
32500
+ matchedTeam.team.description ? `Team context: ${matchedTeam.team.description}` : ""
32501
+ ].filter((part) => part.length > 0).join("\n\n"),
32502
+ instructions: member.instructions
32503
+ }))).map((task) => ({
32504
+ ...task,
32505
+ customAgentId: task.customAgentId ?? task.subagentLabel ? matchedTeam.members.find((member) => member.label === task.subagentLabel)?.id : void 0,
32506
+ teamId: matchedTeam.team.id,
32507
+ teamMemberIds: matchedTeam.members.map((member) => member.id)
32508
+ }));
32509
+ const augmented = appendReviewAndIntegrationTasks(plan, candidate, teamTasks, matchedTeam.team.label);
32510
+ 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(", ")}.`;
32511
+ return {
32512
+ plan: integratePlanTaskExpansion(plan, candidate.id, augmented.tasks, note),
32513
+ note,
32514
+ expandedTaskId: candidate.id
32515
+ };
32516
+ }
32517
+ const defaultDelegation = createDefaultDelegationPlan(candidate, request);
32518
+ if (defaultDelegation && defaultDelegation.members.length > 1) {
32519
+ const delegatedTasks = materializeDelegatedTasks(plan, candidate, defaultDelegation.label, defaultDelegation.strategy, defaultDelegation.members);
32520
+ const augmented = appendReviewAndIntegrationTasks(plan, candidate, delegatedTasks, defaultDelegation.label);
32521
+ const note = `Execution manager delegated ${candidate.id} into ${delegatedTasks.length} subagents plus reviewer/integrator: ${augmented.tasks.map((task) => task.id).join(", ")}.`;
32257
32522
  return {
32258
- plan: integratePlanTaskExpansion(plan, candidate.id, teamTasks, note),
32523
+ plan: integratePlanTaskExpansion(plan, candidate.id, augmented.tasks, note),
32259
32524
  note,
32260
32525
  expandedTaskId: candidate.id
32261
32526
  };
@@ -32317,12 +32582,14 @@ var ExecutionOrchestrator = class {
32317
32582
  plan
32318
32583
  };
32319
32584
  }
32585
+ const expandedTasks = flattenPlanTasks(result.plan).filter((task) => result.createdTaskIds.includes(task.id));
32586
+ const augmented = appendReviewAndIntegrationTasks(plan, candidate, expandedTasks, "planner-swarm");
32320
32587
  const noteParts = [
32321
- result.note,
32588
+ result.note ? `${result.note} | Added reviewer/integrator pass: ${augmented.noteSuffix}.` : `Added reviewer/integrator pass: ${augmented.noteSuffix}.`,
32322
32589
  result.warning && result.source !== "model" ? `expander note: ${result.warning}` : ""
32323
32590
  ].filter(Boolean);
32324
32591
  return {
32325
- plan: result.plan,
32592
+ plan: integratePlanTaskExpansion(plan, candidate.id, augmented.tasks, noteParts.join(" | ")),
32326
32593
  ...noteParts.length > 0 ? {
32327
32594
  note: noteParts.join(" | ")
32328
32595
  } : {},
@@ -32877,7 +33144,15 @@ async function generateProjectInitFile(cwd, outputFileName = "kimbho_init.md") {
32877
33144
  return {
32878
33145
  outputPath,
32879
33146
  indexArtifactPath: artifactPath,
32880
- summary: `Generated ${outputFileName} with indexed project context for ${import_node_path15.default.basename(cwd)}.`
33147
+ summary: `Generated ${outputFileName} with indexed project context for ${import_node_path15.default.basename(cwd)}.`,
33148
+ purpose,
33149
+ frameworks,
33150
+ entrypoints,
33151
+ verificationCommands,
33152
+ indexedFiles: index.summary.totalFiles,
33153
+ sourceFiles: index.summary.sourceFiles,
33154
+ routes: index.summary.routes,
33155
+ schemas: index.summary.schemas
32881
33156
  };
32882
33157
  }
32883
33158
 
@@ -32934,7 +33209,15 @@ async function refreshMemoryFiles(cwd) {
32934
33209
  initFilePath: init.outputPath,
32935
33210
  projectMemoryPath,
32936
33211
  userMemoryPath,
32937
- summary: `Refreshed project bootstrap and memory files for ${import_node_path16.default.basename(cwd)}.`
33212
+ summary: `Refreshed project bootstrap and memory files for ${import_node_path16.default.basename(cwd)}.`,
33213
+ purpose: init.purpose,
33214
+ frameworks: init.frameworks,
33215
+ entrypoints: init.entrypoints,
33216
+ verificationCommands: init.verificationCommands,
33217
+ indexedFiles: init.indexedFiles,
33218
+ sourceFiles: init.sourceFiles,
33219
+ routes: init.routes,
33220
+ schemas: init.schemas
32938
33221
  };
32939
33222
  }
32940
33223
  async function appendMemoryNote(cwd, scope, text, agentId) {
@@ -33076,6 +33359,22 @@ function createDoctorCommand() {
33076
33359
 
33077
33360
  // src/commands/init.ts
33078
33361
  var import_node_process7 = __toESM(require("node:process"), 1);
33362
+ function printProjectUnderstanding(result) {
33363
+ console.log(result.summary);
33364
+ console.log("Now I have a durable understanding of the current project structure.");
33365
+ console.log(`Purpose: ${result.purpose}`);
33366
+ console.log(`Indexed: ${result.indexedFiles} files (${result.sourceFiles} source files), ${result.routes} routes, ${result.schemas} schemas`);
33367
+ console.log(`Frameworks: ${result.frameworks.length > 0 ? result.frameworks.join(", ") : "unknown"}`);
33368
+ if (result.entrypoints.length > 0) {
33369
+ console.log(`Entrypoints: ${result.entrypoints.slice(0, 5).join(", ")}`);
33370
+ }
33371
+ if (result.verificationCommands.length > 0) {
33372
+ console.log(`Verification: ${result.verificationCommands.join(" -> ")}`);
33373
+ }
33374
+ console.log(`Wrote ${result.initFilePath}`);
33375
+ console.log(`Wrote ${result.projectMemoryPath}`);
33376
+ console.log(`Wrote ${result.userMemoryPath}`);
33377
+ }
33079
33378
  function createInitCommand() {
33080
33379
  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
33380
  const existing = await loadConfig(import_node_process7.default.cwd());
@@ -33141,10 +33440,7 @@ function createInitCommand() {
33141
33440
  }
33142
33441
  if (!options.configOnly) {
33143
33442
  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}`);
33443
+ printProjectUnderstanding(result);
33148
33444
  }
33149
33445
  });
33150
33446
  }
@@ -34889,6 +35185,9 @@ var PLAN_PREFIXES = [
34889
35185
  "outline ",
34890
35186
  "propose "
34891
35187
  ];
35188
+ function looksLikeExecutionRequest(input) {
35189
+ 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);
35190
+ }
34892
35191
  function color(code, value) {
34893
35192
  return `${code}${value}${RESET}`;
34894
35193
  }
@@ -35282,20 +35581,20 @@ function inferPromptIntent(input) {
35282
35581
  if (/^(hi|hello|hey|yo|sup)\b/.test(normalized)) {
35283
35582
  return "chat";
35284
35583
  }
35285
- if (normalized.endsWith("?")) {
35286
- return "chat";
35287
- }
35288
35584
  if (PLAN_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
35289
35585
  return "plan";
35290
35586
  }
35291
35587
  if (EXECUTION_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
35292
35588
  return "run";
35293
35589
  }
35294
- if (CHAT_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
35590
+ if (looksLikeExecutionRequest(normalized)) {
35591
+ return "run";
35592
+ }
35593
+ if (normalized.endsWith("?")) {
35295
35594
  return "chat";
35296
35595
  }
35297
- if (/\b(build|create|make|scaffold|implement|fix|refactor|setup|set up|generate)\b/.test(normalized)) {
35298
- return "run";
35596
+ if (CHAT_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
35597
+ return "chat";
35299
35598
  }
35300
35599
  return normalized.split(/\s+/).length >= 4 ? "plan" : "chat";
35301
35600
  }
@@ -36377,6 +36676,16 @@ async function handleMemoryCommand(cwd, tokens) {
36377
36676
  if (subcommand === "refresh") {
36378
36677
  const result = await refreshMemoryFiles(cwd);
36379
36678
  console.log(result.summary);
36679
+ console.log("Now I have a durable understanding of the current project structure.");
36680
+ console.log(`Purpose: ${result.purpose}`);
36681
+ console.log(`Indexed: ${result.indexedFiles} files (${result.sourceFiles} source files), ${result.routes} routes, ${result.schemas} schemas`);
36682
+ console.log(`Frameworks: ${result.frameworks.length > 0 ? result.frameworks.join(", ") : "unknown"}`);
36683
+ if (result.entrypoints.length > 0) {
36684
+ console.log(`Entrypoints: ${result.entrypoints.slice(0, 5).join(", ")}`);
36685
+ }
36686
+ if (result.verificationCommands.length > 0) {
36687
+ console.log(`Verification: ${result.verificationCommands.join(" -> ")}`);
36688
+ }
36380
36689
  console.log(`Wrote ${result.initFilePath}`);
36381
36690
  console.log(`Wrote ${result.projectMemoryPath}`);
36382
36691
  console.log(`Wrote ${result.userMemoryPath}`);