@oh-my-pi/pi-coding-agent 14.9.3 → 14.9.5
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 +44 -0
- package/package.json +7 -7
- package/src/async/job-manager.ts +66 -9
- package/src/capability/rule.ts +20 -0
- package/src/config/model-registry.ts +13 -0
- package/src/config/model-resolver.ts +8 -2
- package/src/config/settings-schema.ts +1 -1
- package/src/edit/index.ts +8 -0
- package/src/edit/renderer.ts +6 -1
- package/src/edit/streaming.ts +53 -2
- package/src/eval/js/context-manager.ts +1 -38
- package/src/eval/js/prelude.txt +0 -2
- package/src/eval/py/executor.ts +24 -8
- package/src/eval/py/index.ts +1 -0
- package/src/eval/py/prelude.py +11 -80
- package/src/export/html/template.css +12 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +20 -2
- package/src/extensibility/plugins/loader.ts +31 -6
- package/src/extensibility/skills.ts +20 -0
- package/src/internal-urls/agent-protocol.ts +63 -52
- package/src/internal-urls/artifact-protocol.ts +51 -51
- package/src/internal-urls/docs-index.generated.ts +33 -1
- package/src/internal-urls/index.ts +6 -19
- package/src/internal-urls/local-protocol.ts +49 -7
- package/src/internal-urls/mcp-protocol.ts +2 -8
- package/src/internal-urls/memory-protocol.ts +89 -59
- package/src/internal-urls/router.ts +38 -22
- package/src/internal-urls/rule-protocol.ts +2 -20
- package/src/internal-urls/skill-protocol.ts +4 -27
- package/src/main.ts +1 -1
- package/src/mcp/manager.ts +17 -0
- package/src/modes/components/session-observer-overlay.ts +2 -2
- package/src/modes/components/tool-execution.ts +6 -0
- package/src/modes/components/tree-selector.ts +4 -0
- package/src/modes/controllers/event-controller.ts +23 -2
- package/src/modes/controllers/mcp-command-controller.ts +7 -10
- package/src/modes/interactive-mode.ts +2 -2
- package/src/modes/theme/theme.ts +27 -27
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +14 -9
- package/src/prompts/commands/orchestrate.md +1 -0
- package/src/prompts/system/project-prompt.md +10 -2
- package/src/prompts/system/subagent-system-prompt.md +8 -8
- package/src/prompts/system/system-prompt.md +13 -7
- package/src/prompts/tools/ask.md +0 -1
- package/src/prompts/tools/bash.md +0 -10
- package/src/prompts/tools/eval.md +1 -3
- package/src/prompts/tools/github.md +6 -5
- package/src/prompts/tools/hashline.md +1 -0
- package/src/prompts/tools/job.md +14 -6
- package/src/prompts/tools/task.md +20 -3
- package/src/registry/agent-registry.ts +2 -1
- package/src/sdk.ts +87 -89
- package/src/session/agent-session.ts +58 -20
- package/src/session/artifacts.ts +7 -4
- package/src/session/session-manager.ts +30 -1
- package/src/ssh/connection-manager.ts +32 -16
- package/src/ssh/sshfs-mount.ts +10 -7
- package/src/system-prompt.ts +0 -5
- package/src/task/executor.ts +14 -2
- package/src/task/index.ts +19 -5
- package/src/tool-discovery/tool-index.ts +21 -8
- package/src/tools/ast-edit.ts +3 -2
- package/src/tools/ast-grep.ts +3 -2
- package/src/tools/bash.ts +15 -9
- package/src/tools/browser/tab-supervisor.ts +12 -2
- package/src/tools/eval.ts +48 -10
- package/src/tools/fetch.ts +1 -1
- package/src/tools/gh.ts +140 -4
- package/src/tools/index.ts +12 -11
- package/src/tools/job.ts +48 -12
- package/src/tools/read.ts +5 -4
- package/src/tools/search.ts +3 -2
- package/src/tools/todo-write.ts +1 -1
- package/src/web/scrapers/mastodon.ts +1 -1
- package/src/web/scrapers/repology.ts +7 -7
- package/src/internal-urls/jobs-protocol.ts +0 -120
- package/src/prompts/system/now-prompt.md +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INTENT_FIELD } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import { Loader, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { type Component, Loader, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { settings } from "../../config/settings";
|
|
5
5
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
6
6
|
import { ReadToolGroupComponent } from "../../modes/components/read-tool-group";
|
|
@@ -15,6 +15,8 @@ import type { ExitPlanModeDetails } from "../../tools";
|
|
|
15
15
|
|
|
16
16
|
type AgentSessionEventKind = AgentSessionEvent["type"];
|
|
17
17
|
|
|
18
|
+
const IRC_MESSAGE_VISIBLE_TTL_MS = 10_000;
|
|
19
|
+
|
|
18
20
|
type AgentSessionEventHandlers = {
|
|
19
21
|
[E in AgentSessionEventKind]: (event: Extract<AgentSessionEvent, { type: E }>) => Promise<void>;
|
|
20
22
|
};
|
|
@@ -29,6 +31,7 @@ export class EventController {
|
|
|
29
31
|
#readToolCallAssistantComponents = new Map<string, AssistantMessageComponent>();
|
|
30
32
|
#lastAssistantComponent: AssistantMessageComponent | undefined = undefined;
|
|
31
33
|
#idleCompactionTimer?: NodeJS.Timeout;
|
|
34
|
+
#ircExpiryTimers = new Map<string, NodeJS.Timeout>();
|
|
32
35
|
#handlers: AgentSessionEventHandlers;
|
|
33
36
|
|
|
34
37
|
constructor(private ctx: InteractiveModeContext) {
|
|
@@ -59,6 +62,10 @@ export class EventController {
|
|
|
59
62
|
|
|
60
63
|
dispose(): void {
|
|
61
64
|
this.#cancelIdleCompaction();
|
|
65
|
+
for (const timer of this.#ircExpiryTimers.values()) {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
}
|
|
68
|
+
this.#ircExpiryTimers.clear();
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
#resetReadGroup(): void {
|
|
@@ -222,10 +229,24 @@ export class EventController {
|
|
|
222
229
|
}
|
|
223
230
|
this.#renderedCustomMessages.add(signature);
|
|
224
231
|
this.#resetReadGroup();
|
|
225
|
-
this.ctx.addMessageToChat(event.message);
|
|
232
|
+
const components = this.ctx.addMessageToChat(event.message);
|
|
233
|
+
this.#scheduleIrcExpiry(signature, components);
|
|
226
234
|
this.ctx.ui.requestRender();
|
|
227
235
|
}
|
|
228
236
|
|
|
237
|
+
#scheduleIrcExpiry(signature: string, components: Component[]): void {
|
|
238
|
+
if (components.length === 0 || this.#ircExpiryTimers.has(signature)) return;
|
|
239
|
+
const timer = setTimeout(() => {
|
|
240
|
+
this.#ircExpiryTimers.delete(signature);
|
|
241
|
+
for (const component of components) {
|
|
242
|
+
this.ctx.chatContainer.removeChild(component);
|
|
243
|
+
}
|
|
244
|
+
this.ctx.ui.requestRender();
|
|
245
|
+
}, IRC_MESSAGE_VISIBLE_TTL_MS);
|
|
246
|
+
timer.unref?.();
|
|
247
|
+
this.#ircExpiryTimers.set(signature, timer);
|
|
248
|
+
}
|
|
249
|
+
|
|
229
250
|
async #handleNotice(event: Extract<AgentSessionEvent, { type: "notice" }>): Promise<void> {
|
|
230
251
|
const message = event.source ? `${event.source}: ${event.message}` : event.message;
|
|
231
252
|
if (event.level === "error") {
|
|
@@ -1238,12 +1238,12 @@ export class MCPCommandController {
|
|
|
1238
1238
|
? theme.fg("muted", "Connecting")
|
|
1239
1239
|
: theme.fg("warning", "Not connected yet");
|
|
1240
1240
|
this.#showMessage(
|
|
1241
|
-
["", theme.fg("success",
|
|
1241
|
+
["", theme.fg("success", `✓ Enabled "${name}"`), "", ` Status: ${status}`, ""].join("\n"),
|
|
1242
1242
|
);
|
|
1243
1243
|
} else {
|
|
1244
1244
|
await this.ctx.mcpManager?.disconnectServer(name);
|
|
1245
1245
|
await this.ctx.session.refreshMCPTools(this.ctx.mcpManager?.getTools() ?? []);
|
|
1246
|
-
this.#showMessage(["", theme.fg("success",
|
|
1246
|
+
this.#showMessage(["", theme.fg("success", `✓ Disabled "${name}"`), ""].join("\n"));
|
|
1247
1247
|
}
|
|
1248
1248
|
return;
|
|
1249
1249
|
}
|
|
@@ -1429,12 +1429,9 @@ export class MCPCommandController {
|
|
|
1429
1429
|
await this.ctx.session.refreshMCPTools(this.ctx.mcpManager.getTools());
|
|
1430
1430
|
const serverTools = this.ctx.mcpManager.getTools().filter(t => t.mcpServerName === name);
|
|
1431
1431
|
this.#showMessage(
|
|
1432
|
-
[
|
|
1433
|
-
"\n",
|
|
1434
|
-
theme.fg("success", `\u2713 Reconnected to "${name}"`),
|
|
1435
|
-
` Tools: ${serverTools.length}`,
|
|
1432
|
+
["\n", theme.fg("success", `✓ Reconnected to "${name}"`), ` Tools: ${serverTools.length}`, "\n"].join(
|
|
1436
1433
|
"\n",
|
|
1437
|
-
|
|
1434
|
+
),
|
|
1438
1435
|
);
|
|
1439
1436
|
} else {
|
|
1440
1437
|
this.ctx.showError(`Failed to reconnect to "${name}". Check server status and logs.`);
|
|
@@ -1589,8 +1586,8 @@ export class MCPCommandController {
|
|
|
1589
1586
|
hasAny = true;
|
|
1590
1587
|
|
|
1591
1588
|
lines.push(`${theme.fg("accent", name)}:`);
|
|
1592
|
-
const check = theme.fg("success", "
|
|
1593
|
-
const cross = theme.fg("dim", "
|
|
1589
|
+
const check = theme.fg("success", "✓");
|
|
1590
|
+
const cross = theme.fg("dim", "✗");
|
|
1594
1591
|
if (supportsToolsChanged) lines.push(` ${check} tools/list_changed`);
|
|
1595
1592
|
if (supportsResourcesChanged) lines.push(` ${check} resources/list_changed`);
|
|
1596
1593
|
if (supportsPromptsChanged) lines.push(` ${check} prompts/list_changed`);
|
|
@@ -1607,7 +1604,7 @@ export class MCPCommandController {
|
|
|
1607
1604
|
lines.push(` ${check} resources/subscribe ${subStatus}`);
|
|
1608
1605
|
if (enabled && subscribedUris && subscribedUris.size > 0) {
|
|
1609
1606
|
for (const uri of subscribedUris) {
|
|
1610
|
-
lines.push(` ${theme.fg("success", "
|
|
1607
|
+
lines.push(` ${theme.fg("success", "✓")} ${theme.fg("dim", uri)}`);
|
|
1611
1608
|
}
|
|
1612
1609
|
}
|
|
1613
1610
|
} else if (supportsResources) {
|
|
@@ -1502,8 +1502,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1502
1502
|
return this.#uiHelpers.isKnownSlashCommand(text);
|
|
1503
1503
|
}
|
|
1504
1504
|
|
|
1505
|
-
addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }):
|
|
1506
|
-
this.#uiHelpers.addMessageToChat(message, options);
|
|
1505
|
+
addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): Component[] {
|
|
1506
|
+
return this.#uiHelpers.addMessageToChat(message, options);
|
|
1507
1507
|
}
|
|
1508
1508
|
|
|
1509
1509
|
renderSessionContext(
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -387,51 +387,51 @@ const NERD_SYMBOLS: SymbolMap = {
|
|
|
387
387
|
"nav.back": "\uf060",
|
|
388
388
|
// Tree Connectors (same as unicode)
|
|
389
389
|
// pick: ├─ | alt: ├╴ ├╌ ╠═ ┣━
|
|
390
|
-
"tree.branch": "
|
|
390
|
+
"tree.branch": "├─",
|
|
391
391
|
// pick: └─ | alt: └╴ └╌ ╚═ ┗━
|
|
392
|
-
"tree.last": "
|
|
392
|
+
"tree.last": "└─",
|
|
393
393
|
// pick: │ | alt: ┃ ║ ▏ ▕
|
|
394
|
-
"tree.vertical": "
|
|
394
|
+
"tree.vertical": "│",
|
|
395
395
|
// pick: ─ | alt: ━ ═ ╌ ┄
|
|
396
|
-
"tree.horizontal": "
|
|
396
|
+
"tree.horizontal": "─",
|
|
397
397
|
// pick: └ | alt: ╰ ⎿ ↳
|
|
398
|
-
"tree.hook": "
|
|
398
|
+
"tree.hook": "└",
|
|
399
399
|
// Box Drawing - Rounded (same as unicode)
|
|
400
400
|
// pick: ╭ | alt: ┌ ┏ ╔
|
|
401
|
-
"boxRound.topLeft": "
|
|
401
|
+
"boxRound.topLeft": "╭",
|
|
402
402
|
// pick: ╮ | alt: ┐ ┓ ╗
|
|
403
|
-
"boxRound.topRight": "
|
|
403
|
+
"boxRound.topRight": "╮",
|
|
404
404
|
// pick: ╰ | alt: └ ┗ ╚
|
|
405
|
-
"boxRound.bottomLeft": "
|
|
405
|
+
"boxRound.bottomLeft": "╰",
|
|
406
406
|
// pick: ╯ | alt: ┘ ┛ ╝
|
|
407
|
-
"boxRound.bottomRight": "
|
|
407
|
+
"boxRound.bottomRight": "╯",
|
|
408
408
|
// pick: ─ | alt: ━ ═ ╌
|
|
409
|
-
"boxRound.horizontal": "
|
|
409
|
+
"boxRound.horizontal": "─",
|
|
410
410
|
// pick: │ | alt: ┃ ║ ▏
|
|
411
|
-
"boxRound.vertical": "
|
|
411
|
+
"boxRound.vertical": "│",
|
|
412
412
|
// Box Drawing - Sharp (same as unicode)
|
|
413
413
|
// pick: ┌ | alt: ┏ ╭ ╔
|
|
414
|
-
"boxSharp.topLeft": "
|
|
414
|
+
"boxSharp.topLeft": "┌",
|
|
415
415
|
// pick: ┐ | alt: ┓ ╮ ╗
|
|
416
|
-
"boxSharp.topRight": "
|
|
416
|
+
"boxSharp.topRight": "┐",
|
|
417
417
|
// pick: └ | alt: ┗ ╰ ╚
|
|
418
|
-
"boxSharp.bottomLeft": "
|
|
418
|
+
"boxSharp.bottomLeft": "└",
|
|
419
419
|
// pick: ┘ | alt: ┛ ╯ ╝
|
|
420
|
-
"boxSharp.bottomRight": "
|
|
420
|
+
"boxSharp.bottomRight": "┘",
|
|
421
421
|
// pick: ─ | alt: ━ ═ ╌
|
|
422
|
-
"boxSharp.horizontal": "
|
|
422
|
+
"boxSharp.horizontal": "─",
|
|
423
423
|
// pick: │ | alt: ┃ ║ ▏
|
|
424
|
-
"boxSharp.vertical": "
|
|
424
|
+
"boxSharp.vertical": "│",
|
|
425
425
|
// pick: ┼ | alt: ╋ ╬ ┿
|
|
426
|
-
"boxSharp.cross": "
|
|
426
|
+
"boxSharp.cross": "┼",
|
|
427
427
|
// pick: ┬ | alt: ╦ ┯ ┳
|
|
428
|
-
"boxSharp.teeDown": "
|
|
428
|
+
"boxSharp.teeDown": "┬",
|
|
429
429
|
// pick: ┴ | alt: ╩ ┷ ┻
|
|
430
|
-
"boxSharp.teeUp": "
|
|
430
|
+
"boxSharp.teeUp": "┴",
|
|
431
431
|
// pick: ├ | alt: ╠ ┝ ┣
|
|
432
|
-
"boxSharp.teeRight": "
|
|
432
|
+
"boxSharp.teeRight": "├",
|
|
433
433
|
// pick: ┤ | alt: ╣ ┥ ┫
|
|
434
|
-
"boxSharp.teeLeft": "
|
|
434
|
+
"boxSharp.teeLeft": "┤",
|
|
435
435
|
// Separators - Nerd Font specific
|
|
436
436
|
// pick: | alt:
|
|
437
437
|
"sep.powerline": "\ue0b0",
|
|
@@ -446,7 +446,7 @@ const NERD_SYMBOLS: SymbolMap = {
|
|
|
446
446
|
// pick: | alt:
|
|
447
447
|
"sep.powerlineThinRight": "\ue0b3",
|
|
448
448
|
// pick: █ | alt: ▓ ▒ ░ ▉ ▌
|
|
449
|
-
"sep.block": "
|
|
449
|
+
"sep.block": "█",
|
|
450
450
|
// pick: space | alt: ␠ ·
|
|
451
451
|
"sep.space": " ",
|
|
452
452
|
// pick: > | alt: › » ▸
|
|
@@ -454,7 +454,7 @@ const NERD_SYMBOLS: SymbolMap = {
|
|
|
454
454
|
// pick: < | alt: ‹ « ◂
|
|
455
455
|
"sep.asciiRight": "<",
|
|
456
456
|
// pick: · | alt: • ⋅
|
|
457
|
-
"sep.dot": "
|
|
457
|
+
"sep.dot": " · ",
|
|
458
458
|
// pick: | alt: / ∕ ⁄
|
|
459
459
|
"sep.slash": "\ue0bb",
|
|
460
460
|
// pick: | alt: │ ┃ |
|
|
@@ -545,16 +545,16 @@ const NERD_SYMBOLS: SymbolMap = {
|
|
|
545
545
|
// pick: | alt: •
|
|
546
546
|
"format.bullet": "\uf111",
|
|
547
547
|
// pick: – | alt: — ― -
|
|
548
|
-
"format.dash": "
|
|
548
|
+
"format.dash": "–",
|
|
549
549
|
// pick: ⟨ | alt: [ ⟦
|
|
550
550
|
"format.bracketLeft": "⟨",
|
|
551
551
|
// pick: ⟩ | alt: ] ⟧
|
|
552
552
|
"format.bracketRight": "⟩",
|
|
553
553
|
// Markdown-specific
|
|
554
554
|
// pick: │ | alt: ┃ ║
|
|
555
|
-
"md.quoteBorder": "
|
|
555
|
+
"md.quoteBorder": "│",
|
|
556
556
|
// pick: ─ | alt: ━ ═
|
|
557
|
-
"md.hrChar": "
|
|
557
|
+
"md.hrChar": "─",
|
|
558
558
|
// pick: | alt: •
|
|
559
559
|
"md.bullet": "\uf111",
|
|
560
560
|
// Language icons (nerd font devicons)
|
package/src/modes/types.ts
CHANGED
|
@@ -170,7 +170,7 @@ export interface InteractiveModeContext {
|
|
|
170
170
|
*/
|
|
171
171
|
withLocalSubmission<T>(text: string, fn: () => Promise<T>, options?: { imageCount?: number }): Promise<T>;
|
|
172
172
|
isKnownSlashCommand(text: string): boolean;
|
|
173
|
-
addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }):
|
|
173
|
+
addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): Component[];
|
|
174
174
|
renderSessionContext(
|
|
175
175
|
sessionContext: SessionContext,
|
|
176
176
|
options?: { updateFooter?: boolean; populateHistory?: boolean },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { AssistantMessage, ImageContent, Message } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import { Spacer, Text, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { type Component, Spacer, Text, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { settings } from "../../config/settings";
|
|
5
5
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
6
6
|
import { BashExecutionComponent } from "../../modes/components/bash-execution";
|
|
@@ -70,7 +70,7 @@ export class UiHelpers {
|
|
|
70
70
|
this.ctx.ui.requestRender();
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }):
|
|
73
|
+
addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): Component[] {
|
|
74
74
|
switch (message.role) {
|
|
75
75
|
case "bashExecution": {
|
|
76
76
|
const component = new BashExecutionComponent(message.command, this.ctx.ui, message.excludeFromContext);
|
|
@@ -147,26 +147,30 @@ export class UiHelpers {
|
|
|
147
147
|
if (message.customType === "irc:incoming") {
|
|
148
148
|
const peer = details?.from ?? "?";
|
|
149
149
|
body = details?.message ?? "";
|
|
150
|
-
arrow =
|
|
150
|
+
arrow = `⇦ ${peer}`;
|
|
151
151
|
} else if (message.customType === "irc:autoreply") {
|
|
152
152
|
const peer = details?.to ?? "?";
|
|
153
153
|
body = details?.reply ?? "";
|
|
154
|
-
arrow =
|
|
154
|
+
arrow = `⇨ ${peer}`;
|
|
155
155
|
} else {
|
|
156
156
|
const from = details?.from ?? "?";
|
|
157
157
|
const to = details?.to ?? "?";
|
|
158
158
|
body = details?.body ?? "";
|
|
159
|
-
|
|
160
|
-
arrow = `${from} \u21e8 ${to}${suffix}`;
|
|
159
|
+
arrow = `${from} ⇨ ${to}`;
|
|
161
160
|
}
|
|
161
|
+
const components: Component[] = [];
|
|
162
162
|
const header = `${theme.fg("accent", `[IRC] ${arrow}`)}`;
|
|
163
|
-
|
|
163
|
+
const headerComponent = new Text(header, 1, 0);
|
|
164
|
+
this.ctx.chatContainer.addChild(headerComponent);
|
|
165
|
+
components.push(headerComponent);
|
|
164
166
|
if (body) {
|
|
165
167
|
for (const line of body.split("\n")) {
|
|
166
|
-
|
|
168
|
+
const lineComponent = new Text(theme.fg("muted", ` ${line}`), 0, 0);
|
|
169
|
+
this.ctx.chatContainer.addChild(lineComponent);
|
|
170
|
+
components.push(lineComponent);
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
|
-
|
|
173
|
+
return components;
|
|
170
174
|
}
|
|
171
175
|
const renderer = this.ctx.session.extensionRunner?.getMessageRenderer(message.customType);
|
|
172
176
|
// Both HookMessage and CustomMessage have the same structure, cast for compatibility
|
|
@@ -240,6 +244,7 @@ export class UiHelpers {
|
|
|
240
244
|
const _exhaustive: never = message;
|
|
241
245
|
}
|
|
242
246
|
}
|
|
247
|
+
return [];
|
|
243
248
|
}
|
|
244
249
|
|
|
245
250
|
/**
|
|
@@ -26,6 +26,7 @@ You decompose, dispatch, verify, and iterate. You do **not** edit code. Every fi
|
|
|
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 **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.
|
|
29
30
|
</rules>
|
|
30
31
|
|
|
31
32
|
<workflow>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
[PROJECT]
|
|
2
2
|
<workstation>
|
|
3
3
|
{{#list environment prefix="- " join="\n"}}{{label}}: {{value}}{{/list}}
|
|
4
4
|
</workstation>
|
|
@@ -32,7 +32,15 @@ Working directory layout (sorted by mtime, recent first; depth ≤ 3):
|
|
|
32
32
|
</workspace-tree>
|
|
33
33
|
{{/if}}
|
|
34
34
|
|
|
35
|
+
Today is {{date}}, and the current working directory is '{{cwd}}'.
|
|
36
|
+
|
|
37
|
+
<critical>
|
|
38
|
+
- Each response **MUST** advance the task. There is no stopping condition other than completion.
|
|
39
|
+
- You **MUST** default to informed action; do not ask for confirmation when tools or repo context can answer.
|
|
40
|
+
- You **MUST** verify the effect of significant behavioral changes before yielding: run the specific test, command, or scenario that covers your change.
|
|
41
|
+
</critical>
|
|
42
|
+
|
|
35
43
|
{{#if appendPrompt}}
|
|
36
44
|
{{appendPrompt}}
|
|
37
45
|
{{/if}}
|
|
38
|
-
|
|
46
|
+
[/PROJECT]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
[ROLE]
|
|
2
2
|
{{agent}}
|
|
3
|
-
|
|
3
|
+
[/ROLE]
|
|
4
4
|
|
|
5
5
|
{{#if context}}
|
|
6
|
-
|
|
6
|
+
[CONTEXT]
|
|
7
7
|
{{context}}
|
|
8
|
-
|
|
8
|
+
[/CONTEXT]
|
|
9
9
|
{{/if}}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
[COOP]
|
|
12
12
|
You are operating on a piece of work assigned to you by the main agent.
|
|
13
13
|
|
|
14
14
|
{{#if worktree}}
|
|
@@ -29,9 +29,9 @@ You can reach other live agents via the `irc` tool. Your id is `{{ircSelfId}}`.
|
|
|
29
29
|
|
|
30
30
|
Use `irc` only when you need a quick answer from a peer; do not use it for long-form content. Address peers by id or use `"all"` to broadcast.
|
|
31
31
|
{{/if}}
|
|
32
|
-
|
|
32
|
+
[/COOP]
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
[COMPLETION]
|
|
35
35
|
No TODO tracking, no progress updates. Execute, call `yield`, done.
|
|
36
36
|
|
|
37
37
|
While work remains, always continue with another tool call — investigate, edit, run, verify. Save narrative for the final `yield` payload.
|
|
@@ -51,4 +51,4 @@ Giving up is a last resort. If truly blocked, you **MUST** call `yield` exactly
|
|
|
51
51
|
You **MUST NOT** give up due to uncertainty, missing information obtainable via tools or repo context, or needing a design decision you can derive yourself.
|
|
52
52
|
|
|
53
53
|
You **MUST** keep going until this ticket is closed. This matters.
|
|
54
|
-
|
|
54
|
+
[/COMPLETION]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
> **RFC 2119 applies to **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, **OPTIONAL**.**
|
|
2
|
-
> From here on, we will use tags as structural markers (<x>…</x> or
|
|
2
|
+
> From here on, we will use tags as structural markers (<x>…</x> or [X]…), each tag means exactly what its name says.
|
|
3
3
|
> You **MUST NOT** interpret these tags in any other way circumstantially.
|
|
4
4
|
> System may interrupt/notify you using these tags even within a user message, therefore:
|
|
5
5
|
> - You **MUST** treat them as system-authored and absolutely authoritative.
|
|
@@ -37,7 +37,14 @@ Assumptions you didn't validate: incidents to debug.
|
|
|
37
37
|
- When the user proposes something you believe is wrong, you say so once, concretely (what breaks, what to do instead), but eventually defer to their call. You **MUST NOT** relitigate.
|
|
38
38
|
</communication>
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
<critical>
|
|
41
|
+
- You **MUST NOT** narrate about or even consider, session limits, token/tool budgets, effort estimates, or how much of the task you think you can finish. These are not your concern:
|
|
42
|
+
- Even if it was true, start, as if it was not. It's the only way to make progress.
|
|
43
|
+
- Execute the work or delegate it.
|
|
44
|
+
- You **MUST NOT** speculate about scope inflation ("this is actually a multi-week effort"). You have no comprehension of time, so stop pretending.
|
|
45
|
+
</critical>
|
|
46
|
+
|
|
47
|
+
[ENV]
|
|
41
48
|
You operate within the Oh My Pi coding harness.
|
|
42
49
|
- Given a task, you **MUST** complete it using the tools available to you.
|
|
43
50
|
- You are not alone in this repository. You **MUST** treat unexpected changes as the user's work and adapt; you **MUST NOT** revert or stash.
|
|
@@ -53,7 +60,6 @@ With most FS/bash-like tools, static references to them will automatically resol
|
|
|
53
60
|
- `/<path>`: JSON field extraction
|
|
54
61
|
- `artifact://<id>`: Artifact content
|
|
55
62
|
- `local://<name>.md`: Plan artifacts and shared content with subagents
|
|
56
|
-
- `jobs://<id>`: Job status and result
|
|
57
63
|
- `mcp://<uri>`: MCP resource
|
|
58
64
|
- `pi://`: Harness documentation; do **NOT** read unless user mentions the harness itself
|
|
59
65
|
|
|
@@ -189,9 +195,9 @@ You **MUST NOT** blindly use coreutils through bash / general-purpose tools when
|
|
|
189
195
|
The `{{toolRefs.report_tool_issue}}` tool is available for automated QA. If ANY tool you call returns output that is unexpected, incorrect, malformed, or otherwise inconsistent with what you anticipated given the tool's described behavior and your parameters, call `{{toolRefs.report_tool_issue}}` with the tool name and a concise description of the discrepancy. Do not hesitate to report — false positives are acceptable.
|
|
190
196
|
</critical>
|
|
191
197
|
{{/has}}
|
|
192
|
-
|
|
198
|
+
[/ENV]
|
|
193
199
|
|
|
194
|
-
|
|
200
|
+
[CONTRACT]
|
|
195
201
|
These are inviolable.
|
|
196
202
|
- You **MUST NOT** yield unless the deliverable is complete. A phase boundary, todo flip, or completed sub-step is **NOT** a yield point — continue directly to the next step in the same turn.
|
|
197
203
|
- You **MUST NOT** suppress tests to make code pass.
|
|
@@ -218,7 +224,7 @@ Before yielding, you **MUST** verify:
|
|
|
218
224
|
- All explicitly requested deliverables are complete; no partial implementation is presented as complete
|
|
219
225
|
- All directly affected artifacts (callsites, tests, docs) are updated or intentionally left unchanged
|
|
220
226
|
- The output format matches the ask
|
|
221
|
-
- No unobserved claim is presented as fact. Mark explicitly as
|
|
227
|
+
- No unobserved claim is presented as fact. Mark explicitly as `[INFERENCE]` if so
|
|
222
228
|
- No required tool-based lookup was skipped when it would materially reduce uncertainty
|
|
223
229
|
|
|
224
230
|
Before declaring blocked:
|
|
@@ -252,4 +258,4 @@ Before declaring blocked:
|
|
|
252
258
|
- Do not test defaults: changing the default configuration, or a string, should not break the test. Assert logical behavior, not the current state.
|
|
253
259
|
- Aim at: conditional branches and edge values, invariants across fields, error handling on bad input vs silent broken results.
|
|
254
260
|
</workflow>
|
|
255
|
-
|
|
261
|
+
[/CONTRACT]
|
package/src/prompts/tools/ask.md
CHANGED
|
@@ -8,7 +8,6 @@ Asks user when you need clarification or input during task execution.
|
|
|
8
8
|
- Use `recommended: <index>` to mark default (0-indexed); " (Recommended)" added automatically
|
|
9
9
|
- Use `questions` for multiple related questions instead of asking one at a time
|
|
10
10
|
- Set `multi: true` on question to allow multiple selections
|
|
11
|
-
- `ask.timeout` only applies while choosing options; once the user selects "Other (type your own)", there is no timeout
|
|
12
11
|
</instruction>
|
|
13
12
|
|
|
14
13
|
<caution>
|
|
@@ -10,16 +10,6 @@ Executes bash command in shell session for terminal operations like git, bun, ca
|
|
|
10
10
|
{{#if asyncEnabled}}
|
|
11
11
|
- Use `async: true` for long-running commands when you don't need immediate output; the call returns a background job ID and the result is delivered automatically as a follow-up.
|
|
12
12
|
{{/if}}
|
|
13
|
-
{{#if autoBackgroundEnabled}}
|
|
14
|
-
- Long-running non-PTY commands may auto-background after ~{{autoBackgroundThresholdSeconds}}s and continue as background jobs.
|
|
15
|
-
{{/if}}
|
|
16
|
-
{{#if asyncEnabled}}
|
|
17
|
-
- Inspect background jobs with `read jobs://` (`read jobs://<job-id>` for detail). To wait for results, call `job` (with `poll`) — do NOT poll `read jobs://` in a loop or yield and hope for delivery.
|
|
18
|
-
{{else}}
|
|
19
|
-
{{#if autoBackgroundEnabled}}
|
|
20
|
-
- For auto-backgrounded jobs, inspect with `read jobs://` and call `job` (with `poll`) to wait — do NOT poll in a loop.
|
|
21
|
-
{{/if}}
|
|
22
|
-
{{/if}}
|
|
23
13
|
</instruction>
|
|
24
14
|
|
|
25
15
|
<output>
|
|
@@ -46,8 +46,6 @@ tree(path?=".", max_depth?=3, show_hidden?=False) → str
|
|
|
46
46
|
Render a directory tree.
|
|
47
47
|
diff(a, b) → str
|
|
48
48
|
Unified diff between two files.
|
|
49
|
-
run(cmd, cwd?=None, timeout?=None) → {stdout, stderr, exit_code}
|
|
50
|
-
Run a shell command.
|
|
51
49
|
env(key?=None, value?=None) → str | None | dict
|
|
52
50
|
No args → full environment as dict. One arg → value of `key`. Two args → set `key=value` and return value.
|
|
53
51
|
output(*ids, format?="raw", query?=None, offset?=None, limit?=None) → str | dict | list[dict]
|
|
@@ -63,7 +61,7 @@ Cells render like a Jupyter notebook. `display(value)` renders non-presentable d
|
|
|
63
61
|
|
|
64
62
|
<caution>
|
|
65
63
|
- In session mode, use `*** Reset` on a cell to wipe its language's kernel before running.{{#ifAll py js}} Reset is per-language: a python cell's `*** Reset` does not touch the JavaScript kernel and vice versa.{{/ifAll}}
|
|
66
|
-
{{#if js}}- **js**: the VM exposes a selective `process` subset, Web APIs, `Buffer`, `fs/promises
|
|
64
|
+
{{#if js}}- **js**: the VM exposes a selective `process` subset, Web APIs, `Buffer`, `fs/promises`, and the `Bun` global.
|
|
67
65
|
{{/if}}</caution>
|
|
68
66
|
|
|
69
67
|
<example>
|
|
@@ -9,11 +9,12 @@ Pick the operation via `op`. Each op uses a subset of the parameters:
|
|
|
9
9
|
- `pr_diff` — Read one or more pull request diffs. Optional `pr` (single identifier or array for batch). Optional `repo`. Set `nameOnly: true` for changed file names. Use `exclude` to drop generated paths from the diff.
|
|
10
10
|
- `pr_checkout` — Check one or more pull requests out into dedicated git worktrees. Optional `pr` (number, URL, branch, or array of any of those — pass an array to batch-check-out multiple PRs in one call), `repo`, `force` (reset existing local branch).
|
|
11
11
|
- `pr_push` — Push a checked-out PR branch back to its source branch. Requires the branch to have been checked out via `op: pr_checkout` (carries push metadata). Optional `branch`; defaults to the current checked-out git branch. Optional `forceWithLease`.
|
|
12
|
-
- `search_issues` — Search issues using normal GitHub issue search syntax.
|
|
13
|
-
- `search_prs` — Search pull requests using normal GitHub PR search syntax.
|
|
14
|
-
- `search_code` — Search code with GitHub code search syntax. Required `query`. Optional `repo`, `limit`. Returns matching paths with surrounding fragments.
|
|
15
|
-
- `search_commits` — Search commits across GitHub.
|
|
16
|
-
- `search_repos` — Search repositories across GitHub.
|
|
12
|
+
- `search_issues` — Search issues using normal GitHub issue search syntax. Optional `query` (required unless `since`/`until` is set), `repo`, `limit`, `since`, `until`, `dateField`.
|
|
13
|
+
- `search_prs` — Search pull requests using normal GitHub PR search syntax. Optional `query` (required unless `since`/`until` is set), `repo`, `limit`, `since`, `until`, `dateField`.
|
|
14
|
+
- `search_code` — Search code with GitHub code search syntax. Required `query`. Optional `repo`, `limit`. Returns matching paths with surrounding fragments. Date filtering (`since`/`until`) is **not** supported by GitHub code search.
|
|
15
|
+
- `search_commits` — Search commits across GitHub. Optional `query` (required unless `since`/`until` is set), `repo`, `limit`, `since`, `until`. `dateField` is ignored — always uses `committer-date`.
|
|
16
|
+
- `search_repos` — Search repositories across GitHub. Optional `query` (required unless `since`/`until` is set), `limit`, `since`, `until`, `dateField` (use query qualifiers like `org:`, `language:` instead of `repo`).
|
|
17
|
+
- Date filter format for `since` / `until`: relative duration `<n><unit>` (`m`/`h`/`d`/`w`/`mo`/`y`, e.g. `3d`, `12h`, `2w`), an ISO date `YYYY-MM-DD`, or an ISO datetime. Translated to a single GitHub-search qualifier (`created:≥…`, `created:≤…`, or `created:since..until`). `dateField: "updated"` maps to `updated:` for issues/prs and `pushed:` for repos. When you only want a date filter and no keywords, omit `query` entirely.
|
|
17
18
|
- `run_watch` — Watch a GitHub Actions workflow run. Optional `run` (id or URL). Omitting `run` watches all workflow runs for the current HEAD commit; `branch` falls back to the current branch. Optional `tail` (log lines per failed job). Streams snapshots, fast-fails on the first detected job failure (with a brief grace period to capture concurrent failures), then fetches tailed logs for the failed jobs. The full failed-job logs are saved as a session artifact for on-demand reads.
|
|
18
19
|
</instruction>
|
|
19
20
|
|
|
@@ -17,6 +17,7 @@ Purely textual format. The tool has NO awareness of language, indentation, brack
|
|
|
17
17
|
<rules>
|
|
18
18
|
- Every line of inserted/replacement content **MUST** be emitted as a payload line starting with `{{hsep}}`.
|
|
19
19
|
- `{{hsep}}` is syntax, not content. The inserted text begins after the first `{{hsep}}`; use a bare `{{hsep}}` to insert a blank line.
|
|
20
|
+
- Payload is verbatim — don't escape unicode (write `—`, not `\u2014`).
|
|
20
21
|
- `< A` inserts before line A; `+ A` inserts after line A. `< BOF` / `+ BOF` both prepend; `< EOF` / `+ EOF` both append.
|
|
21
22
|
- `= A..B` replaces the inclusive range with the following payload lines. `= A..B` with no payload blanks the range to a single empty line.
|
|
22
23
|
- `- A..B` deletes the inclusive range; `A..A` for one line.
|
package/src/prompts/tools/job.md
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
Inspects, waits, or cancels async jobs.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Background job results are delivered automatically when complete. Reach for this tool only when you need to intervene.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# Operations
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## `list: true`
|
|
8
|
+
Use to inspect what's running.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
## `poll: [id, …]`
|
|
11
|
+
Block until the specified jobs finish or the wait window elapses.
|
|
12
|
+
- Use when you are genuinely blocked on a result and have no other work to do.
|
|
13
|
+
- Returns the current snapshot when the timer elapses; running jobs remain running.
|
|
14
|
+
- Completed jobs include their final output in the returned snapshot.
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
## `cancel: [id, …]`
|
|
17
|
+
Stop running jobs.
|
|
18
|
+
- Use when a job is stalled, hung, or no longer needed.
|
|
19
|
+
- Returns immediately after cancelling.
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
Launches subagents to parallelize workflows.
|
|
2
2
|
|
|
3
3
|
{{#if asyncEnabled}}
|
|
4
|
-
-
|
|
5
|
-
-
|
|
4
|
+
- Results are delivered automatically when complete.
|
|
5
|
+
- If genuinely blocked on task completion, wait with `job` using `poll`; otherwise continue with another task when possible.
|
|
6
|
+
- Call `job` with `list: true` to snapshot manager state; pass `poll: [id]` to wait or `cancel: [id]` to stop \u2014 only when inspection or intervention is useful.
|
|
6
7
|
{{/if}}
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
{{#if ircEnabled}}
|
|
10
|
+
Subagents have no conversation history, but they can reach you and their siblings live via the `irc` tool. Front-load every fact, file path, and direction they need in {{#if contextEnabled}}`context` or `assignment`{{else}}each `assignment`{{/if}}.
|
|
11
|
+
{{else}}
|
|
12
|
+
Subagents have no conversation history. Every fact, file path, and direction they need **MUST** be explicit in {{#if contextEnabled}}`context` or `assignment`{{else}}each `assignment`{{/if}}.
|
|
13
|
+
{{/if}}
|
|
9
14
|
|
|
10
15
|
<parameters>
|
|
11
16
|
- `agent`: agent type for all tasks
|
|
@@ -20,16 +25,28 @@ Subagents have no conversation history. Every fact, file path, and decision they
|
|
|
20
25
|
|
|
21
26
|
<rules>
|
|
22
27
|
- **MUST NOT** assign tasks to run project-wide build/test/lint. Caller verifies after the batch.
|
|
28
|
+
- **Subagents do not verify, lint, or format.** Every assignment **MUST** instruct the subagent to skip all gates and formatters. You run them once at the end across the union of changed files — avoids redundant runs and racing formatter passes.
|
|
29
|
+
{{#if ircEnabled}}
|
|
30
|
+
- Each task: ≤3–5 explicit files. Overlapping file sets are tolerable when peers can coordinate via `irc`, but still fan out to a cluster when the scopes are cleanly separable.
|
|
31
|
+
- No globs, no "update all", no package-wide scope.
|
|
32
|
+
{{else}}
|
|
23
33
|
- Each task: ≤3–5 explicit files. No globs, no "update all", no package-wide scope. Fan out to a cluster instead.
|
|
34
|
+
{{/if}}
|
|
24
35
|
- Pass large payloads via `local://<path>` URIs, not inline.
|
|
25
36
|
{{#if contextEnabled}}- Put shared constraints in `context` once; do not duplicate across assignments.{{/if}}
|
|
26
37
|
- Prefer agents that investigate **and** edit in one pass; only spin a read-only discovery step when affected files are genuinely unknown.
|
|
27
38
|
</rules>
|
|
28
39
|
|
|
29
40
|
<parallelization>
|
|
41
|
+
{{#if ircEnabled}}
|
|
42
|
+
Test: can task B run correctly without seeing A's output? If no, sequence A → B — **unless** B can reasonably ask A for the missing piece over `irc`. Live coordination beats a serial waterfall when the contract is small and easy to describe in a DM.
|
|
43
|
+
Still sequence when one task produces a large, evolving contract (generated types, schema migration, core module API) the other consumes wholesale — IRC round-trips do not replace a finished artifact.
|
|
44
|
+
Parallel when tasks touch disjoint files, are independent refactors/tests, or only need occasional clarification that can be resolved peer-to-peer.
|
|
45
|
+
{{else}}
|
|
30
46
|
Test: can task B run correctly without seeing A's output? If no, sequence A → B.
|
|
31
47
|
Sequential when one task produces a contract (types, API, schema, core module) the other consumes.
|
|
32
48
|
Parallel when tasks touch disjoint files or are independent refactors/tests.
|
|
49
|
+
{{/if}}
|
|
33
50
|
</parallelization>
|
|
34
51
|
|
|
35
52
|
{{#if contextEnabled}}
|
|
@@ -86,10 +86,11 @@ export class AgentRegistry {
|
|
|
86
86
|
this.#emit({ type: "status_changed", ref });
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
attachSession(id: string, session: AgentSession): void {
|
|
89
|
+
attachSession(id: string, session: AgentSession, sessionFile?: string | null): void {
|
|
90
90
|
const ref = this.#refs.get(id);
|
|
91
91
|
if (!ref) return;
|
|
92
92
|
ref.session = session;
|
|
93
|
+
if (sessionFile !== undefined) ref.sessionFile = sessionFile;
|
|
93
94
|
ref.lastActivity = Date.now();
|
|
94
95
|
}
|
|
95
96
|
|