@oh-my-pi/pi-coding-agent 14.9.9 → 15.0.0
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/CHANGELOG.md +82 -0
- package/package.json +7 -7
- package/scripts/format-prompts.ts +1 -1
- package/src/cli/args.ts +2 -2
- package/src/cli.ts +1 -0
- package/src/commands/acp.ts +24 -0
- package/src/commands/launch.ts +6 -4
- package/src/commit/agentic/prompts/system.md +1 -1
- package/src/config/model-resolver.ts +30 -0
- package/src/config/settings-schema.ts +31 -0
- package/src/edit/index.ts +22 -1
- package/src/edit/modes/patch.ts +10 -0
- package/src/edit/modes/replace.ts +3 -0
- package/src/edit/renderer.ts +10 -0
- package/src/eval/js/context-manager.ts +1 -1
- package/src/eval/js/shared/rewrite-imports.ts +120 -48
- package/src/eval/js/shared/runtime.ts +31 -4
- package/src/eval/js/tool-bridge.ts +43 -21
- package/src/extensibility/extensions/runner.ts +54 -1
- package/src/extensibility/extensions/types.ts +11 -0
- package/src/extensibility/skills.ts +33 -1
- package/src/internal-urls/docs-index.generated.ts +6 -6
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/issue-pr-protocol.ts +577 -0
- package/src/internal-urls/router.ts +6 -3
- package/src/internal-urls/types.ts +22 -1
- package/src/main.ts +13 -9
- package/src/modes/acp/acp-agent.ts +361 -54
- package/src/modes/acp/acp-client-bridge.ts +152 -0
- package/src/modes/acp/acp-event-mapper.ts +180 -15
- package/src/modes/acp/terminal-auth.ts +37 -0
- package/src/modes/components/read-tool-group.ts +29 -1
- package/src/modes/controllers/command-controller.ts +14 -6
- package/src/modes/controllers/event-controller.ts +24 -11
- package/src/modes/controllers/extension-ui-controller.ts +8 -2
- package/src/modes/controllers/input-controller.ts +72 -39
- package/src/modes/interactive-mode.ts +71 -7
- package/src/modes/rpc/rpc-mode.ts +17 -2
- package/src/modes/types.ts +6 -2
- package/src/modes/utils/ui-helpers.ts +15 -3
- package/src/prompts/agents/designer.md +5 -5
- package/src/prompts/agents/explore.md +7 -7
- package/src/prompts/agents/init.md +9 -9
- package/src/prompts/agents/librarian.md +14 -14
- package/src/prompts/agents/plan.md +4 -4
- package/src/prompts/agents/reviewer.md +5 -5
- package/src/prompts/agents/task.md +10 -10
- package/src/prompts/commands/orchestrate.md +2 -2
- package/src/prompts/compaction/branch-summary.md +3 -3
- package/src/prompts/compaction/compaction-short-summary.md +7 -7
- package/src/prompts/compaction/compaction-summary-context.md +1 -1
- package/src/prompts/compaction/compaction-summary.md +5 -5
- package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
- package/src/prompts/compaction/compaction-update-summary.md +11 -11
- package/src/prompts/memories/consolidation.md +2 -2
- package/src/prompts/memories/read-path.md +1 -1
- package/src/prompts/memories/stage_one_input.md +1 -1
- package/src/prompts/memories/stage_one_system.md +5 -5
- package/src/prompts/review-request.md +4 -4
- package/src/prompts/system/agent-creation-architect.md +17 -17
- package/src/prompts/system/agent-creation-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +2 -2
- package/src/prompts/system/custom-system-prompt.md +2 -2
- package/src/prompts/system/eager-todo.md +6 -6
- package/src/prompts/system/handoff-document.md +1 -1
- package/src/prompts/system/plan-mode-active.md +22 -21
- package/src/prompts/system/plan-mode-approved.md +4 -4
- package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
- package/src/prompts/system/plan-mode-reference.md +2 -2
- package/src/prompts/system/plan-mode-subagent.md +8 -8
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +2 -2
- package/src/prompts/system/project-prompt.md +4 -4
- package/src/prompts/system/subagent-system-prompt.md +7 -7
- package/src/prompts/system/subagent-yield-reminder.md +4 -4
- package/src/prompts/system/system-prompt.md +72 -71
- package/src/prompts/system/ttsr-interrupt.md +1 -1
- package/src/prompts/tools/apply-patch.md +1 -1
- package/src/prompts/tools/ast-edit.md +3 -3
- package/src/prompts/tools/ast-grep.md +3 -3
- package/src/prompts/tools/browser.md +3 -3
- package/src/prompts/tools/checkpoint.md +3 -3
- package/src/prompts/tools/exit-plan-mode.md +2 -2
- package/src/prompts/tools/find.md +3 -3
- package/src/prompts/tools/github.md +2 -5
- package/src/prompts/tools/hashline.md +6 -6
- package/src/prompts/tools/image-gen.md +3 -3
- package/src/prompts/tools/irc.md +1 -1
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +6 -6
- package/src/prompts/tools/read.md +7 -7
- package/src/prompts/tools/replace.md +5 -5
- package/src/prompts/tools/retain.md +1 -1
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search.md +2 -2
- package/src/prompts/tools/ssh.md +2 -2
- package/src/prompts/tools/task.md +12 -6
- package/src/prompts/tools/web-search.md +2 -2
- package/src/prompts/tools/write.md +3 -3
- package/src/sdk.ts +69 -12
- package/src/session/agent-session.ts +231 -22
- package/src/session/client-bridge.ts +81 -0
- package/src/session/compaction/errors.ts +31 -0
- package/src/session/compaction/index.ts +1 -0
- package/src/slash-commands/acp-builtins.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +699 -116
- package/src/slash-commands/helpers/context-report.ts +39 -0
- package/src/slash-commands/helpers/format.ts +23 -0
- package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
- package/src/slash-commands/helpers/mcp.ts +532 -0
- package/src/slash-commands/helpers/parse.ts +85 -0
- package/src/slash-commands/helpers/ssh.ts +193 -0
- package/src/slash-commands/helpers/todo.ts +279 -0
- package/src/slash-commands/helpers/usage-report.ts +91 -0
- package/src/slash-commands/types.ts +126 -0
- package/src/task/executor.ts +10 -3
- package/src/task/index.ts +17 -1
- package/src/task/render.ts +6 -3
- package/src/tools/bash.ts +176 -2
- package/src/tools/conflict-detect.ts +6 -6
- package/src/tools/fetch.ts +15 -4
- package/src/tools/find.ts +19 -1
- package/src/tools/gh-renderer.ts +0 -12
- package/src/tools/gh.ts +682 -176
- package/src/tools/github-cache.ts +548 -0
- package/src/tools/index.ts +3 -0
- package/src/tools/read.ts +110 -27
- package/src/tools/write.ts +23 -1
- package/src/tui/code-cell.ts +70 -2
|
@@ -240,45 +240,12 @@ export class InputController {
|
|
|
240
240
|
text = slashResult;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
// Handle skill commands (/skill:name [args])
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (skillPath) {
|
|
250
|
-
this.ctx.editor.addToHistory(text);
|
|
251
|
-
this.ctx.editor.setText("");
|
|
252
|
-
try {
|
|
253
|
-
const content = await Bun.file(skillPath).text();
|
|
254
|
-
const body = content.replace(/^---\n[\s\S]*?\n---\n/, "").trim();
|
|
255
|
-
const metaLines = [`Skill: ${skillPath}`];
|
|
256
|
-
if (args) {
|
|
257
|
-
metaLines.push(`User: ${args}`);
|
|
258
|
-
}
|
|
259
|
-
const message = `${body}\n\n---\n\n${metaLines.join("\n")}`;
|
|
260
|
-
const skillName = commandName.slice("skill:".length);
|
|
261
|
-
const details: SkillPromptDetails = {
|
|
262
|
-
name: skillName || commandName,
|
|
263
|
-
path: skillPath,
|
|
264
|
-
args: args || undefined,
|
|
265
|
-
lineCount: body ? body.split("\n").length : 0,
|
|
266
|
-
};
|
|
267
|
-
await this.ctx.session.promptCustomMessage(
|
|
268
|
-
{
|
|
269
|
-
customType: SKILL_PROMPT_MESSAGE_TYPE,
|
|
270
|
-
content: message,
|
|
271
|
-
display: true,
|
|
272
|
-
details,
|
|
273
|
-
attribution: "user",
|
|
274
|
-
},
|
|
275
|
-
{ streamingBehavior: "followUp" },
|
|
276
|
-
);
|
|
277
|
-
} catch (err) {
|
|
278
|
-
this.ctx.showError(`Failed to load skill: ${err instanceof Error ? err.message : String(err)}`);
|
|
279
|
-
}
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
243
|
+
// Handle skill commands (/skill:name [args]). Enter ⇒ steer (matches the
|
|
244
|
+
// free-text Enter semantics applied a few lines below at the streaming
|
|
245
|
+
// branch). Ctrl+Enter routes through `handleFollowUp` and dispatches the
|
|
246
|
+
// same helper with `"followUp"`.
|
|
247
|
+
if (await this.#invokeSkillCommand(text, "steer")) {
|
|
248
|
+
return;
|
|
282
249
|
}
|
|
283
250
|
|
|
284
251
|
// Handle bash command (! for normal, !! for excluded from context)
|
|
@@ -439,16 +406,82 @@ export class InputController {
|
|
|
439
406
|
}
|
|
440
407
|
}
|
|
441
408
|
|
|
409
|
+
/**
|
|
410
|
+
* Dispatch a `/skill:<name> [args]` invocation through `promptCustomMessage`
|
|
411
|
+
* using the supplied `streamingBehavior`. Returns true if the text was a
|
|
412
|
+
* recognised skill command and was dispatched. A failure to load the skill
|
|
413
|
+
* file is surfaced via `showError` but still returns true — the editor was
|
|
414
|
+
* already cleared on the success path, so falling through to plain-text
|
|
415
|
+
* handling at that point would double-submit. Returns false when the text
|
|
416
|
+
* isn't a `/skill:` prefix or the command name isn't a registered skill,
|
|
417
|
+
* so the caller can fall through to plain-text handling (this branch
|
|
418
|
+
* leaves the editor state untouched). `streamingBehavior` is only consulted
|
|
419
|
+
* while the agent is streaming; the idle path of `promptCustomMessage`
|
|
420
|
+
* ignores it.
|
|
421
|
+
*/
|
|
422
|
+
async #invokeSkillCommand(text: string, streamingBehavior: "steer" | "followUp"): Promise<boolean> {
|
|
423
|
+
if (!text.startsWith("/skill:")) return false;
|
|
424
|
+
const spaceIndex = text.indexOf(" ");
|
|
425
|
+
const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
|
|
426
|
+
const args = spaceIndex === -1 ? "" : text.slice(spaceIndex + 1).trim();
|
|
427
|
+
const skillPath = this.ctx.skillCommands?.get(commandName);
|
|
428
|
+
if (!skillPath) return false;
|
|
429
|
+
this.ctx.editor.addToHistory(text);
|
|
430
|
+
this.ctx.editor.setText("");
|
|
431
|
+
try {
|
|
432
|
+
const content = await Bun.file(skillPath).text();
|
|
433
|
+
const body = content.replace(/^---\n[\s\S]*?\n---\n/, "").trim();
|
|
434
|
+
const metaLines = [`Skill: ${skillPath}`];
|
|
435
|
+
if (args) {
|
|
436
|
+
metaLines.push(`User: ${args}`);
|
|
437
|
+
}
|
|
438
|
+
const message = `${body}\n\n---\n\n${metaLines.join("\n")}`;
|
|
439
|
+
const skillName = commandName.slice("skill:".length);
|
|
440
|
+
const details: SkillPromptDetails = {
|
|
441
|
+
name: skillName || commandName,
|
|
442
|
+
path: skillPath,
|
|
443
|
+
args: args || undefined,
|
|
444
|
+
lineCount: body ? body.split("\n").length : 0,
|
|
445
|
+
};
|
|
446
|
+
await this.ctx.session.promptCustomMessage(
|
|
447
|
+
{
|
|
448
|
+
customType: SKILL_PROMPT_MESSAGE_TYPE,
|
|
449
|
+
content: message,
|
|
450
|
+
display: true,
|
|
451
|
+
details,
|
|
452
|
+
attribution: "user",
|
|
453
|
+
},
|
|
454
|
+
{ streamingBehavior },
|
|
455
|
+
);
|
|
456
|
+
} catch (err) {
|
|
457
|
+
this.ctx.showError(`Failed to load skill: ${err instanceof Error ? err.message : String(err)}`);
|
|
458
|
+
}
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
|
|
442
462
|
/** Send editor text as a follow-up message (queued behind current stream). */
|
|
443
463
|
async handleFollowUp(): Promise<void> {
|
|
444
464
|
const text = this.ctx.editor.getText().trim();
|
|
445
465
|
if (!text) return;
|
|
446
466
|
|
|
467
|
+
// Compaction first: while compacting, free text gets queued via
|
|
468
|
+
// `queueCompactionMessage`, and `/skill:*` rides the same queue so a
|
|
469
|
+
// skill typed during compaction is not lost or short-circuited through
|
|
470
|
+
// `promptCustomMessage`. The skill text is queued verbatim; whether
|
|
471
|
+
// the queued entry is later re-parsed into a skill invocation is a
|
|
472
|
+
// separate concern owned by the compaction-resume path.
|
|
447
473
|
if (this.ctx.session.isCompacting) {
|
|
448
474
|
this.ctx.queueCompactionMessage(text, "followUp");
|
|
449
475
|
return;
|
|
450
476
|
}
|
|
451
477
|
|
|
478
|
+
// Skill commands invoke through the custom-message path regardless of
|
|
479
|
+
// which keybinding submitted them. Enter routes them as `steer`;
|
|
480
|
+
// Ctrl+Enter (this handler) routes them as `followUp`.
|
|
481
|
+
if (await this.#invokeSkillCommand(text, "followUp")) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
452
485
|
if (this.ctx.session.isStreaming) {
|
|
453
486
|
this.ctx.editor.addToHistory(text);
|
|
454
487
|
this.ctx.editor.setText("");
|
|
@@ -41,7 +41,11 @@ import { resolveLocalUrlToPath } from "../internal-urls";
|
|
|
41
41
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "../lsp/startup-events";
|
|
42
42
|
import { renameApprovedPlanFile } from "../plan-mode/approved-plan";
|
|
43
43
|
import planModeApprovedPrompt from "../prompts/system/plan-mode-approved.md" with { type: "text" };
|
|
44
|
+
import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compact-instructions.md" with {
|
|
45
|
+
type: "text",
|
|
46
|
+
};
|
|
44
47
|
import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
|
|
48
|
+
import type { CompactionOutcome } from "../session/compaction";
|
|
45
49
|
import { HistoryStorage } from "../session/history-storage";
|
|
46
50
|
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
47
51
|
import { getRecentSessions } from "../session/session-manager";
|
|
@@ -1109,7 +1113,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1109
1113
|
|
|
1110
1114
|
async #approvePlan(
|
|
1111
1115
|
planContent: string,
|
|
1112
|
-
options: {
|
|
1116
|
+
options: {
|
|
1117
|
+
planFilePath: string;
|
|
1118
|
+
finalPlanFilePath: string;
|
|
1119
|
+
preserveContext?: boolean;
|
|
1120
|
+
compactBeforeExecute?: boolean;
|
|
1121
|
+
},
|
|
1113
1122
|
): Promise<void> {
|
|
1114
1123
|
await renameApprovedPlanFile({
|
|
1115
1124
|
planFilePath: options.planFilePath,
|
|
@@ -1119,6 +1128,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1119
1128
|
});
|
|
1120
1129
|
const previousTools = this.#planModePreviousTools ?? this.session.getActiveToolNames();
|
|
1121
1130
|
await this.#exitPlanMode({ silent: true, paused: false });
|
|
1131
|
+
|
|
1132
|
+
let compactOutcome: CompactionOutcome | undefined;
|
|
1122
1133
|
if (!options.preserveContext) {
|
|
1123
1134
|
await this.handleClearCommand();
|
|
1124
1135
|
// The new session has a fresh local:// root — persist the approved plan there
|
|
@@ -1128,11 +1139,50 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1128
1139
|
getSessionId: () => this.sessionManager.getSessionId(),
|
|
1129
1140
|
});
|
|
1130
1141
|
await Bun.write(newLocalPath, planContent);
|
|
1131
|
-
}
|
|
1142
|
+
} else if (options.compactBeforeExecute) {
|
|
1143
|
+
// Distill the plan-mode transcript before the execution turn is queued so
|
|
1144
|
+
// the plan-approved synthetic prompt lands as a fresh cache anchor.
|
|
1145
|
+
// Outcome is consumed after tool-restoration and plan-reference-path
|
|
1146
|
+
// bookkeeping below; `markPlanReferenceSent` is intentionally deferred
|
|
1147
|
+
// past the cancel guard — see the comment at the cancel branch.
|
|
1148
|
+
// Cancellation skips the synthetic-prompt dispatch (operator's explicit
|
|
1149
|
+
// abort is honored); failure proceeds best-effort — approval intent stands.
|
|
1150
|
+
const compactionPrompt = prompt.render(planModeCompactInstructionsPrompt, {
|
|
1151
|
+
planFilePath: options.finalPlanFilePath,
|
|
1152
|
+
});
|
|
1153
|
+
// Pin the plan reference path BEFORE compaction so any user messages
|
|
1154
|
+
// queued during the compaction await (which `handleCompactCommand`
|
|
1155
|
+
// flushes via `flushCompactionQueue` before returning) see the
|
|
1156
|
+
// approved plan in `#buildPlanReferenceMessage`. Reassignment at
|
|
1157
|
+
// line 1161 below is idempotent and kept for the !compactBeforeExecute
|
|
1158
|
+
// branch.
|
|
1159
|
+
this.session.setPlanReferencePath(options.finalPlanFilePath);
|
|
1160
|
+
compactOutcome = await this.handleCompactCommand(compactionPrompt);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// Tool restoration runs on every path — the plan mode tools must be
|
|
1164
|
+
// retired regardless of whether the synthetic prompt fires.
|
|
1132
1165
|
if (previousTools.length > 0) {
|
|
1133
1166
|
await this.session.setActiveToolsByName(previousTools);
|
|
1134
1167
|
}
|
|
1135
1168
|
this.session.setPlanReferencePath(options.finalPlanFilePath);
|
|
1169
|
+
|
|
1170
|
+
if (compactOutcome === "cancelled") {
|
|
1171
|
+
// Explicit abort: honor it. `executeCompaction` already surfaced
|
|
1172
|
+
// `showError("Compaction cancelled")` to the operator; we add the
|
|
1173
|
+
// deferred-dispatch warning and exit. `markPlanReferenceSent` is
|
|
1174
|
+
// intentionally skipped here: `#planReferenceSent` stays false, so
|
|
1175
|
+
// `AgentSession.#buildPlanReferenceMessage` will inject the plan
|
|
1176
|
+
// reference on the operator's next `prompt()` call. If we marked it
|
|
1177
|
+
// sent here, the executor's first turn would have no plan context.
|
|
1178
|
+
this.showWarning(
|
|
1179
|
+
"Plan approved, but compaction was cancelled — execution not dispatched. Submit a turn to continue.",
|
|
1180
|
+
);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// markPlanReferenceSent fires only on the dispatch path so the synthetic
|
|
1185
|
+
// plan-approved prompt is the source of the reference injection.
|
|
1136
1186
|
this.session.markPlanReferenceSent();
|
|
1137
1187
|
const planModePrompt = prompt.render(planModeApprovedPrompt, {
|
|
1138
1188
|
planContent,
|
|
@@ -1185,14 +1235,24 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1185
1235
|
this.#renderPlanPreview(planContent, { append: true });
|
|
1186
1236
|
const choice = await this.showHookSelector(
|
|
1187
1237
|
"Plan mode - next step",
|
|
1188
|
-
[
|
|
1238
|
+
[
|
|
1239
|
+
"Approve and execute",
|
|
1240
|
+
"Approve and compact context",
|
|
1241
|
+
"Approve and keep context",
|
|
1242
|
+
"Refine plan",
|
|
1243
|
+
"Stay in plan mode",
|
|
1244
|
+
],
|
|
1189
1245
|
{
|
|
1190
1246
|
helpText: this.#getPlanReviewHelpText(),
|
|
1191
1247
|
onExternalEditor: () => void this.#openPlanInExternalEditor(planFilePath),
|
|
1192
1248
|
},
|
|
1193
1249
|
);
|
|
1194
1250
|
|
|
1195
|
-
if (
|
|
1251
|
+
if (
|
|
1252
|
+
choice === "Approve and execute" ||
|
|
1253
|
+
choice === "Approve and compact context" ||
|
|
1254
|
+
choice === "Approve and keep context"
|
|
1255
|
+
) {
|
|
1196
1256
|
const finalPlanFilePath = details.finalPlanFilePath || planFilePath;
|
|
1197
1257
|
try {
|
|
1198
1258
|
const latestPlanContent = await this.#readPlanFile(planFilePath);
|
|
@@ -1203,7 +1263,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1203
1263
|
await this.#approvePlan(latestPlanContent, {
|
|
1204
1264
|
planFilePath,
|
|
1205
1265
|
finalPlanFilePath,
|
|
1206
|
-
preserveContext: choice
|
|
1266
|
+
preserveContext: choice !== "Approve and execute",
|
|
1267
|
+
compactBeforeExecute: choice === "Approve and compact context",
|
|
1207
1268
|
});
|
|
1208
1269
|
} catch (error) {
|
|
1209
1270
|
this.showError(
|
|
@@ -1727,7 +1788,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1727
1788
|
await controller.handle(text);
|
|
1728
1789
|
}
|
|
1729
1790
|
|
|
1730
|
-
handleCompactCommand(customInstructions?: string): Promise<
|
|
1791
|
+
handleCompactCommand(customInstructions?: string): Promise<CompactionOutcome> {
|
|
1731
1792
|
return this.#commandController.handleCompactCommand(customInstructions);
|
|
1732
1793
|
}
|
|
1733
1794
|
|
|
@@ -1735,7 +1796,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1735
1796
|
return this.#commandController.handleHandoffCommand(customInstructions);
|
|
1736
1797
|
}
|
|
1737
1798
|
|
|
1738
|
-
executeCompaction(
|
|
1799
|
+
executeCompaction(
|
|
1800
|
+
customInstructionsOrOptions?: string | CompactOptions,
|
|
1801
|
+
isAuto?: boolean,
|
|
1802
|
+
): Promise<CompactionOutcome> {
|
|
1739
1803
|
return this.#commandController.executeCompaction(customInstructionsOrOptions, isAuto);
|
|
1740
1804
|
}
|
|
1741
1805
|
|
|
@@ -154,8 +154,17 @@ export function requestRpcEditor(
|
|
|
154
154
|
* Run in RPC mode.
|
|
155
155
|
* Listens for JSON commands on stdin, outputs events and responses on stdout.
|
|
156
156
|
*/
|
|
157
|
-
export async function runRpcMode(
|
|
157
|
+
export async function runRpcMode(
|
|
158
|
+
session: AgentSession,
|
|
159
|
+
setToolUIContext?: (uiContext: ExtensionUIContext, hasUI: boolean) => void,
|
|
160
|
+
): Promise<never> {
|
|
158
161
|
// Signal to RPC clients that the server is ready to accept commands
|
|
162
|
+
// Suppress terminal notifications: they write \x07 (BEL) or OSC sequences directly to
|
|
163
|
+
// process.stdout with no newline, which the reader merges with the next JSON line and
|
|
164
|
+
// breaks JSON.parse. In RPC mode stdout is the JSON protocol channel — nothing else
|
|
165
|
+
// may write there.
|
|
166
|
+
process.env.PI_NOTIFICATIONS = "off";
|
|
167
|
+
|
|
159
168
|
process.stdout.write(`${JSON.stringify({ type: "ready" })}\n`);
|
|
160
169
|
const output = (obj: RpcResponse | RpcExtensionUIRequest | object) => {
|
|
161
170
|
process.stdout.write(`${JSON.stringify(obj)}\n`);
|
|
@@ -405,6 +414,12 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
|
|
405
414
|
}
|
|
406
415
|
}
|
|
407
416
|
|
|
417
|
+
// Wire up UI context for tool execution (ask tool, etc.) and extensions.
|
|
418
|
+
// A single shared instance routes all responses received on stdin to the
|
|
419
|
+
// correct waiting promise regardless of which code path created the request.
|
|
420
|
+
const rpcUiContext = new RpcExtensionUIContext(pendingExtensionRequests, output);
|
|
421
|
+
setToolUIContext?.(rpcUiContext, true);
|
|
422
|
+
|
|
408
423
|
// Set up extensions with RPC-based UI context
|
|
409
424
|
const extensionRunner = session.extensionRunner;
|
|
410
425
|
if (extensionRunner) {
|
|
@@ -481,7 +496,7 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
|
|
481
496
|
},
|
|
482
497
|
compact: instructionsOrOptions => runExtensionCompact(session, instructionsOrOptions),
|
|
483
498
|
},
|
|
484
|
-
|
|
499
|
+
rpcUiContext,
|
|
485
500
|
);
|
|
486
501
|
extensionRunner.onError(err => {
|
|
487
502
|
output({ type: "extension_error", extensionPath: err.extensionPath, event: err.event, error: err.error });
|
package/src/modes/types.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
import type { CompactOptions } from "../extensibility/extensions/types";
|
|
13
13
|
import type { MCPManager } from "../mcp";
|
|
14
14
|
import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
|
|
15
|
+
import type { CompactionOutcome } from "../session/compaction";
|
|
15
16
|
import type { HistoryStorage } from "../session/history-storage";
|
|
16
17
|
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
17
18
|
import type { ExitPlanModeDetails, LspStartupServerInfo } from "../tools";
|
|
@@ -207,13 +208,16 @@ export interface InteractiveModeContext {
|
|
|
207
208
|
handlePythonCommand(code: string, excludeFromContext?: boolean): Promise<void>;
|
|
208
209
|
handleMCPCommand(text: string): Promise<void>;
|
|
209
210
|
handleSSHCommand(text: string): Promise<void>;
|
|
210
|
-
handleCompactCommand(customInstructions?: string): Promise<
|
|
211
|
+
handleCompactCommand(customInstructions?: string): Promise<CompactionOutcome>;
|
|
211
212
|
handleHandoffCommand(customInstructions?: string): Promise<void>;
|
|
212
213
|
handleMoveCommand(targetPath: string): Promise<void>;
|
|
213
214
|
handleRenameCommand(title: string): Promise<void>;
|
|
214
215
|
handleMemoryCommand(text: string): Promise<void>;
|
|
215
216
|
handleSTTToggle(): Promise<void>;
|
|
216
|
-
executeCompaction(
|
|
217
|
+
executeCompaction(
|
|
218
|
+
customInstructionsOrOptions?: string | CompactOptions,
|
|
219
|
+
isAuto?: boolean,
|
|
220
|
+
): Promise<CompactionOutcome>;
|
|
217
221
|
openInBrowser(urlOrPath: string): void;
|
|
218
222
|
refreshSlashCommandState(cwd?: string): Promise<void>;
|
|
219
223
|
|
|
@@ -9,7 +9,11 @@ import { CompactionSummaryMessageComponent } from "../../modes/components/compac
|
|
|
9
9
|
import { CustomMessageComponent } from "../../modes/components/custom-message";
|
|
10
10
|
import { DynamicBorder } from "../../modes/components/dynamic-border";
|
|
11
11
|
import { EvalExecutionComponent } from "../../modes/components/eval-execution";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ReadToolGroupComponent,
|
|
14
|
+
readArgsHaveTarget,
|
|
15
|
+
readArgsTargetInternalUrl,
|
|
16
|
+
} from "../../modes/components/read-tool-group";
|
|
13
17
|
import { SkillMessageComponent } from "../../modes/components/skill-message";
|
|
14
18
|
import { ToolExecutionComponent } from "../../modes/components/tool-execution";
|
|
15
19
|
import { UserMessageComponent } from "../../modes/components/user-message";
|
|
@@ -302,7 +306,11 @@ export class UiHelpers {
|
|
|
302
306
|
continue;
|
|
303
307
|
}
|
|
304
308
|
|
|
305
|
-
if (
|
|
309
|
+
if (
|
|
310
|
+
content.name === "read" &&
|
|
311
|
+
readArgsHaveTarget(content.arguments) &&
|
|
312
|
+
!readArgsTargetInternalUrl(content.arguments)
|
|
313
|
+
) {
|
|
306
314
|
if (hasErrorStop && errorMessage) {
|
|
307
315
|
if (!readGroup) {
|
|
308
316
|
readGroup = new ReadToolGroupComponent({
|
|
@@ -364,7 +372,11 @@ export class UiHelpers {
|
|
|
364
372
|
}
|
|
365
373
|
}
|
|
366
374
|
} else if (message.role === "toolResult") {
|
|
367
|
-
|
|
375
|
+
const pendingReadComponent = this.ctx.pendingTools.get(message.toolCallId);
|
|
376
|
+
const isReadGroupResult =
|
|
377
|
+
message.toolName === "read" &&
|
|
378
|
+
(!pendingReadComponent || pendingReadComponent instanceof ReadToolGroupComponent);
|
|
379
|
+
if (isReadGroupResult) {
|
|
368
380
|
const assistantComponent = readToolCallAssistantComponents.get(message.toolCallId);
|
|
369
381
|
const images: ImageContent[] = message.content.filter(
|
|
370
382
|
(content): content is ImageContent => content.type === "image",
|
|
@@ -30,9 +30,9 @@ Implement and review UI designs. Edit files, create components, run commands whe
|
|
|
30
30
|
</procedure>
|
|
31
31
|
|
|
32
32
|
<directives>
|
|
33
|
-
- You
|
|
34
|
-
- Changes
|
|
35
|
-
- You
|
|
33
|
+
- You SHOULD prefer editing existing files over creating new ones
|
|
34
|
+
- Changes MUST be minimal and consistent with existing code style
|
|
35
|
+
- You NEVER create documentation files (*.md) unless explicitly requested
|
|
36
36
|
</directives>
|
|
37
37
|
|
|
38
38
|
<avoid>
|
|
@@ -61,6 +61,6 @@ Implement and review UI designs. Edit files, create components, run commands whe
|
|
|
61
61
|
|
|
62
62
|
<critical>
|
|
63
63
|
Every interface should prompt "how was this made?" not "which AI made this?"
|
|
64
|
-
You
|
|
65
|
-
You
|
|
64
|
+
You MUST commit to clear aesthetic direction and execute with precision.
|
|
65
|
+
You MUST keep going until implementation is complete.
|
|
66
66
|
</critical>
|
|
@@ -32,13 +32,13 @@ output:
|
|
|
32
32
|
Investigate the codebase rapidly. Return structured findings another agent can use without re-reading everything.
|
|
33
33
|
|
|
34
34
|
<directives>
|
|
35
|
-
- You
|
|
36
|
-
- You
|
|
37
|
-
- If a search returns empty results, you
|
|
35
|
+
- You MUST use tools for broad pattern matching / code search as much as possible.
|
|
36
|
+
- You SHOULD invoke tools in parallel—this is a short investigation, and you are supposed to finish in a few seconds.
|
|
37
|
+
- If a search returns empty results, you MUST try at least one alternate strategy (different pattern, broader path, or AST search) before concluding the target doesn't exist.
|
|
38
38
|
</directives>
|
|
39
39
|
|
|
40
40
|
<thoroughness>
|
|
41
|
-
You
|
|
41
|
+
You MUST infer the thoroughness from the task; default to medium:
|
|
42
42
|
- **Quick**: Targeted lookups, key files only
|
|
43
43
|
- **Medium**: Follow imports, read critical sections
|
|
44
44
|
- **Thorough**: Trace all dependencies, check tests/types.
|
|
@@ -46,12 +46,12 @@ You **MUST** infer the thoroughness from the task; default to medium:
|
|
|
46
46
|
|
|
47
47
|
<procedure>
|
|
48
48
|
1. Locate relevant code using tools.
|
|
49
|
-
2. Read key sections (You
|
|
49
|
+
2. Read key sections (You NEVER read full files unless they're tiny)
|
|
50
50
|
3. Identify types/interfaces/key functions.
|
|
51
51
|
4. Note dependencies between files.
|
|
52
52
|
</procedure>
|
|
53
53
|
|
|
54
54
|
<critical>
|
|
55
|
-
You
|
|
56
|
-
You
|
|
55
|
+
You MUST operate as read-only. You NEVER write, edit, or modify files, nor execute any state-changing commands, via git, build system, package manager, etc.
|
|
56
|
+
You MUST keep going until complete.
|
|
57
57
|
</critical>
|
|
@@ -18,16 +18,16 @@ Generate AGENTS.md by launching multiple `explore` agents in parallel (via `task
|
|
|
18
18
|
</structure>
|
|
19
19
|
|
|
20
20
|
<directives>
|
|
21
|
-
- You
|
|
22
|
-
- You
|
|
23
|
-
- You
|
|
24
|
-
- You
|
|
25
|
-
- You
|
|
26
|
-
- You
|
|
27
|
-
- You
|
|
28
|
-
- You
|
|
21
|
+
- You MUST title the document "Repository Guidelines"
|
|
22
|
+
- You MUST use Markdown headings for structure
|
|
23
|
+
- You MUST be concise and practical
|
|
24
|
+
- You MUST focus on what an AI assistant needs to help with the codebase
|
|
25
|
+
- You SHOULD include examples where helpful (commands, paths, naming patterns)
|
|
26
|
+
- You SHOULD include file paths where relevant
|
|
27
|
+
- You MUST call out architecture and code patterns explicitly
|
|
28
|
+
- You SHOULD omit information obvious from code structure
|
|
29
29
|
</directives>
|
|
30
30
|
|
|
31
31
|
<output>
|
|
32
|
-
After analysis, you
|
|
32
|
+
After analysis, you MUST write AGENTS.md to the project root.
|
|
33
33
|
</output>
|
|
@@ -68,8 +68,8 @@ output:
|
|
|
68
68
|
Answer questions about external libraries, frameworks, and APIs by reading source code and official documentation.
|
|
69
69
|
|
|
70
70
|
<critical>
|
|
71
|
-
You
|
|
72
|
-
You
|
|
71
|
+
You MUST ground every claim in source code or official documentation. You NEVER rely on training data for API details — it may be stale or wrong.
|
|
72
|
+
You MUST operate as read-only on the user's project. You NEVER modify any project files.
|
|
73
73
|
</critical>
|
|
74
74
|
|
|
75
75
|
<procedure>
|
|
@@ -93,27 +93,27 @@ You **MUST** operate as read-only on the user's project. You **MUST NOT** modify
|
|
|
93
93
|
## 4. Verify
|
|
94
94
|
- Cross-reference at least two locations (types + implementation, or source + tests).
|
|
95
95
|
- If the answer involves defaults, find where the default is actually set in code — not where the docs say it is.
|
|
96
|
-
- For API signatures: copy verbatim from source. You
|
|
96
|
+
- For API signatures: copy verbatim from source. You NEVER paraphrase or reconstruct from memory.
|
|
97
97
|
|
|
98
98
|
## 5. Report
|
|
99
99
|
- Call `yield` with structured findings.
|
|
100
|
-
- Every `sources` entry
|
|
101
|
-
- The `api` array
|
|
100
|
+
- Every `sources` entry MUST include a verbatim excerpt.
|
|
101
|
+
- The `api` array MUST contain exact signatures copied from source.
|
|
102
102
|
- Clean up cloned repos: `rm -rf /tmp/librarian-*`.
|
|
103
103
|
</procedure>
|
|
104
104
|
|
|
105
105
|
<directives>
|
|
106
|
-
- You
|
|
107
|
-
- You
|
|
108
|
-
- If the library has breaking changes between versions relevant to the question, you
|
|
109
|
-
- If you discover undocumented behavior or gotchas, you
|
|
110
|
-
- When local `node_modules` has the package, you
|
|
111
|
-
- You
|
|
112
|
-
- If a search or lookup returns empty or unexpectedly few results, you
|
|
113
|
-
- If the package is absent from local `node_modules` and cloning fails, you
|
|
106
|
+
- You SHOULD invoke tools in parallel — search multiple paths simultaneously.
|
|
107
|
+
- You MUST include the exact version you investigated in the `version` field.
|
|
108
|
+
- If the library has breaking changes between versions relevant to the question, you MUST populate `breaking_changes`.
|
|
109
|
+
- If you discover undocumented behavior or gotchas, you MUST populate `caveats`.
|
|
110
|
+
- When local `node_modules` has the package, you SHOULD prefer it over cloning — it reflects the version the project actually uses.
|
|
111
|
+
- You SHOULD use `web_search` to find the canonical repo URL and to check for known issues, but the definitive answer MUST come from reading source code.
|
|
112
|
+
- If a search or lookup returns empty or unexpectedly few results, you MUST try at least 2 fallback strategies (broader query, alternate path, different source) before concluding nothing exists.
|
|
113
|
+
- If the package is absent from local `node_modules` and cloning fails, you MUST fall back to `web_search` for official API documentation before reporting failure.
|
|
114
114
|
</directives>
|
|
115
115
|
|
|
116
116
|
<critical>
|
|
117
117
|
Source code is truth. Documentation is aspiration. Training data is history.
|
|
118
|
-
You
|
|
118
|
+
You MUST keep going until you have a definitive, source-verified answer.
|
|
119
119
|
</critical>
|
|
@@ -20,7 +20,7 @@ Analyze the codebase and the user's request. Produce a detailed implementation p
|
|
|
20
20
|
4. Identify types, interfaces, contracts
|
|
21
21
|
5. Note dependencies between components
|
|
22
22
|
|
|
23
|
-
You
|
|
23
|
+
You MUST spawn `explore` agents for independent areas and synthesize findings.
|
|
24
24
|
|
|
25
25
|
## Phase 3: Design
|
|
26
26
|
1. List concrete changes (files, functions, types)
|
|
@@ -31,7 +31,7 @@ You **MUST** spawn `explore` agents for independent areas and synthesize finding
|
|
|
31
31
|
|
|
32
32
|
## Phase 4: Produce Plan
|
|
33
33
|
|
|
34
|
-
You
|
|
34
|
+
You MUST write a plan executable without re-exploration.
|
|
35
35
|
|
|
36
36
|
<structure>
|
|
37
37
|
- **Summary**: What to build and why (one paragraph).
|
|
@@ -43,6 +43,6 @@ You **MUST** write a plan executable without re-exploration.
|
|
|
43
43
|
</structure>
|
|
44
44
|
|
|
45
45
|
<critical>
|
|
46
|
-
You
|
|
47
|
-
You
|
|
46
|
+
You MUST operate as read-only. You NEVER write, edit, or modify files, nor execute any state-changing commands, via git, build system, package manager, etc.
|
|
47
|
+
You MUST keep going until complete.
|
|
48
48
|
</critical>
|
|
@@ -64,7 +64,7 @@ Identify bugs the author would want fixed before merge.
|
|
|
64
64
|
3. Call `report_finding` per issue
|
|
65
65
|
4. Call `yield` with verdict
|
|
66
66
|
|
|
67
|
-
Bash is read-only: `git diff`, `git log`, `git show`, `gh pr diff`. You
|
|
67
|
+
Bash is read-only: `git diff`, `git log`, `git show`, `gh pr diff`. You NEVER make file edits or trigger builds.
|
|
68
68
|
</procedure>
|
|
69
69
|
|
|
70
70
|
<criteria>
|
|
@@ -86,7 +86,7 @@ For every new type, variant, or value introduced by the patch that crosses a fun
|
|
|
86
86
|
3. If the new type falls through to a silent drop, no-op, or discard (e.g. an unmatched `if`/`switch`
|
|
87
87
|
that simply returns without processing), report it as a defect.
|
|
88
88
|
|
|
89
|
-
The dispatch point is frequently **outside the diff**. You
|
|
89
|
+
The dispatch point is frequently **outside the diff**. You MUST read it before concluding
|
|
90
90
|
the producing side is correct. Tracing only the emitting code while skipping the consuming
|
|
91
91
|
routing logic is the single most common source of missed integration bugs in reviews.
|
|
92
92
|
</cross-boundary>
|
|
@@ -128,13 +128,13 @@ Final `yield` call (payload under `result.data`):
|
|
|
128
128
|
- `result.data.overall_correctness`: "correct" (no bugs/blockers) or "incorrect"
|
|
129
129
|
- `result.data.explanation`: Plain text, 1-3 sentences summarizing verdict. Don't repeat findings (captured via `report_finding`).
|
|
130
130
|
- `result.data.confidence`: 0.0-1.0
|
|
131
|
-
- `result.data.findings`: Optional;
|
|
131
|
+
- `result.data.findings`: Optional; MUST omit (auto-populated from `report_finding`)
|
|
132
132
|
|
|
133
|
-
You
|
|
133
|
+
You NEVER output JSON or code blocks.
|
|
134
134
|
|
|
135
135
|
Correctness ignores non-blocking issues (style, docs, nits).
|
|
136
136
|
</output>
|
|
137
137
|
|
|
138
138
|
<critical>
|
|
139
|
-
Every finding
|
|
139
|
+
Every finding MUST be patch-anchored and evidence-backed.
|
|
140
140
|
</critical>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
You are a worker agent for delegated tasks.
|
|
2
2
|
|
|
3
|
-
You have FULL access to all tools (edit, write, bash, search, read, etc.) and you
|
|
3
|
+
You have FULL access to all tools (edit, write, bash, search, read, etc.) and you MUST use them as needed to complete your task.
|
|
4
4
|
|
|
5
|
-
You
|
|
5
|
+
You MUST maintain hyperfocus on the task at hand, do not deviate from what was assigned to you.
|
|
6
6
|
|
|
7
7
|
<directives>
|
|
8
|
-
- You
|
|
9
|
-
- You
|
|
10
|
-
- You
|
|
11
|
-
- You
|
|
12
|
-
-
|
|
13
|
-
- You
|
|
14
|
-
- You
|
|
15
|
-
- You
|
|
8
|
+
- You MUST finish only the assigned work and return the minimum useful result. Do not repeat what you have written to the filesystem.
|
|
9
|
+
- You MAY make file edits, run commands, and create files when your task requires it—and SHOULD do so.
|
|
10
|
+
- You MUST be concise. You NEVER include filler, repetition, or tool transcripts. User cannot even see you. Your result is just the notes you are leaving for yourself.
|
|
11
|
+
- You SHOULD prefer narrow lookups (`search`/`find`) then read only needed ranges. Do not bother yourself with anything beyond your current scope.
|
|
12
|
+
- AVOID full-file reads unless necessary.
|
|
13
|
+
- You SHOULD prefer edits to existing files over creating new ones.
|
|
14
|
+
- You NEVER create documentation files (*.md) unless explicitly requested.
|
|
15
|
+
- You MUST follow the assignment and the instructions given to you. You gave them for a reason.
|
|
16
16
|
</directives>
|
|
@@ -20,13 +20,13 @@ You decompose, dispatch, verify, and iterate. You do **not** edit code. Every fi
|
|
|
20
20
|
<rules>
|
|
21
21
|
1. **Do not yield until everything is closed.** A phase finishing is *not* a yield point — launch the next phase in the same turn. Stop only when every requested item is verifiably done, or you hit a concrete [blocked] state that genuinely requires the user.
|
|
22
22
|
2. **Enumerate the full surface before dispatching.** If the task references audits, plans, checklists, phase lists, or file lists, expand them into a flat set of items in `todo_write`. "Most of them" or "the important ones" is failure. Re-read the source documents — do not work from memory.
|
|
23
|
-
3. **Parallelize maximally.** Every set of edits with disjoint file scope
|
|
23
|
+
3. **Parallelize maximally.** Every set of edits with disjoint file scope MUST ship as one `task` batch. Serialize only when one subagent produces a contract (types, schema, shared module) the next consumes — and state the dependency when you do.
|
|
24
24
|
4. **Each `task` assignment is self-contained.** Subagents have no shared context. Spell out: target files (≤3–5 explicit paths, no globs), the change with APIs and patterns, edge cases, and observable acceptance criteria. Do not assume they read the same plan you did.
|
|
25
25
|
5. **Verify after every phase before launching the next.** Run the appropriate gate: `bun check` for types, package-scoped `bun test` for behavior, `lsp diagnostics` for changed files. If a phase introduced breakage, dispatch fix-up subagents *before* moving on. Never declare a phase done on a red tree.
|
|
26
26
|
6. **Commit policy.** If the task asks for commits or the repo workflow expects them, commit after each green phase with a focused message. Never commit a red tree. Never commit work the user did not ask to commit.
|
|
27
27
|
7. **Respawn, do not absorb.** If a subagent returns incomplete or wrong work, spawn a corrective subagent with the specific gap — do not silently fix it yourself.
|
|
28
28
|
8. **No scope creep, no scope shrink.** Do not add work the user did not ask for. Do not relabel unfinished items as "follow-up", "v1", or "MVP" to imply completion.
|
|
29
|
-
9. **Subagents do not verify, lint, or format.** Every `task` assignment
|
|
29
|
+
9. **Subagents do not verify, lint, or format.** Every `task` assignment MUST instruct the subagent to skip all gates and formatters. Their job is the edit only. You — the orchestrator — run verification and formatting **once** at the end of the phase across the union of changed files. Avoids redundant runs and racing formatter passes.
|
|
30
30
|
</rules>
|
|
31
31
|
|
|
32
32
|
<workflow>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
You
|
|
1
|
+
You MUST create a structured summary of the conversation branch for context when returning.
|
|
2
2
|
|
|
3
|
-
You
|
|
3
|
+
You MUST use EXACT format:
|
|
4
4
|
|
|
5
5
|
## Goal
|
|
6
6
|
|
|
@@ -27,4 +27,4 @@ You **MUST** use EXACT format:
|
|
|
27
27
|
## Next Steps
|
|
28
28
|
1. [What should happen next to continue]
|
|
29
29
|
|
|
30
|
-
Sections
|
|
30
|
+
Sections MUST be kept concise. You MUST preserve exact file paths, function names, error messages.
|