@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 +912 -119
- package/dist/index.cjs.map +3 -3
- package/package.json +1 -1
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.
|
|
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) ||
|
|
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" &&
|
|
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
|
|
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(
|
|
27960
|
+
toolId: toMcpToolId(resolvedServerName, toolName),
|
|
27790
27961
|
success: false,
|
|
27791
|
-
summary: `MCP server ${
|
|
27962
|
+
summary: `MCP server ${resolvedServerName} is not configured or is disabled.`,
|
|
27792
27963
|
artifacts: []
|
|
27793
27964
|
};
|
|
27794
27965
|
}
|
|
27795
|
-
const result = await withMcpClient(cwd,
|
|
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(
|
|
27971
|
+
toolId: toMcpToolId(resolvedServerName, toolName),
|
|
27801
27972
|
success: !result.isError,
|
|
27802
|
-
summary: result.isError ? `MCP tool ${
|
|
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[
|
|
27997
|
+
const server = config2.mcpServers[resolvedServerName];
|
|
27826
27998
|
if (!server || server.enabled === false) {
|
|
27827
|
-
throw new Error(`MCP server ${
|
|
27999
|
+
throw new Error(`MCP server ${resolvedServerName} is not configured or is disabled.`);
|
|
27828
28000
|
}
|
|
27829
|
-
const result = await withMcpClient(cwd,
|
|
27830
|
-
name:
|
|
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[
|
|
28017
|
+
const server = config2.mcpServers[resolvedServerName];
|
|
27845
28018
|
if (!server || server.enabled === false) {
|
|
27846
|
-
throw new Error(`MCP server ${
|
|
28019
|
+
throw new Error(`MCP server ${resolvedServerName} is not configured or is disabled.`);
|
|
27847
28020
|
}
|
|
27848
|
-
const result = await withMcpClient(cwd,
|
|
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
|
|
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
|
|
32219
|
-
|
|
32220
|
-
|
|
32221
|
-
|
|
32222
|
-
|
|
32223
|
-
|
|
32224
|
-
|
|
32225
|
-
|
|
32226
|
-
|
|
32227
|
-
|
|
32228
|
-
|
|
32229
|
-
|
|
32230
|
-
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
|
|
32234
|
-
|
|
32235
|
-
|
|
32236
|
-
|
|
32237
|
-
|
|
32238
|
-
|
|
32239
|
-
|
|
32240
|
-
|
|
32241
|
-
|
|
32242
|
-
|
|
32243
|
-
|
|
32244
|
-
|
|
32245
|
-
|
|
32246
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
35195
|
-
"/
|
|
35196
|
-
"/
|
|
35197
|
-
"/
|
|
35198
|
-
"/
|
|
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
|
|
35204
|
-
"/model focus <role> Change
|
|
35205
|
-
"
|
|
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
|
-
"/
|
|
35211
|
-
"/
|
|
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>
|
|
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
|
-
"/
|
|
35219
|
-
"/
|
|
35220
|
-
"
|
|
35221
|
-
|
|
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
|
-
"/
|
|
35228
|
-
"/
|
|
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 (
|
|
36010
|
+
if (looksLikeExecutionRequest(normalized)) {
|
|
36011
|
+
return "run";
|
|
36012
|
+
}
|
|
36013
|
+
if (normalized.endsWith("?")) {
|
|
35295
36014
|
return "chat";
|
|
35296
36015
|
}
|
|
35297
|
-
if (
|
|
35298
|
-
return "
|
|
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
|
|
36500
|
-
const
|
|
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|
|
|
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
|
-
|
|
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();
|