@ferris1225/pi-subagents 2.0.2 → 2.1.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/README.md +11 -6
- package/package.json +1 -1
- package/src/announcements.ts +70 -70
- package/src/dispatch.ts +24 -996
- package/src/format.ts +177 -177
- package/src/index.ts +3 -2
- package/src/rpc-run.ts +1125 -1059
- package/src/spawn.ts +13 -1
- package/src/thread-lifecycle.ts +1061 -0
- package/src/widget.ts +144 -144
- package/src/worktree.ts +687 -687
package/README.md
CHANGED
|
@@ -338,9 +338,13 @@ parent does not `abort_retry` them — and only a settled model-level failure
|
|
|
338
338
|
hands off to current main. This uses supported extension/RPC surfaces in Node
|
|
339
339
|
and standalone/Bun builds, never rewrites global or project settings, and does
|
|
340
340
|
not alter descendant tool environments. Tool/test failures stay on the same
|
|
341
|
-
model because they are task failures, not model availability failures.
|
|
342
|
-
|
|
343
|
-
|
|
341
|
+
model because they are task failures, not model availability failures. A child is
|
|
342
|
+
probed with RPC `get_state` before the first prompt so the 30s command ACK clock
|
|
343
|
+
does not include process boot. Only a zero-activity startup miss can retry — a
|
|
344
|
+
silent fast exit, a `get_state` handshake timeout, or an initial prompt ACK
|
|
345
|
+
timeout before any agent/turn/stream/tool activity. Those transport misses are
|
|
346
|
+
not model-level failures and do not hand the task to the main window. An accepted
|
|
347
|
+
prompt or any activity forbids replay.
|
|
344
348
|
|
|
345
349
|
Auto thinking starts from the Agent's declared preference (`low` for `explore`,
|
|
346
350
|
`high` for the other built-ins) and uses Pi's capability map to clamp it to the
|
|
@@ -425,12 +429,13 @@ npm run check
|
|
|
425
429
|
npm test
|
|
426
430
|
```
|
|
427
431
|
|
|
428
|
-
The source is modular: `dispatch.ts` (dispatch
|
|
432
|
+
The source is modular: `dispatch.ts` (public dispatch contract + auto-fix),
|
|
433
|
+
`thread-lifecycle.ts` (queued generations, resume/fork, and isolation settlement),
|
|
429
434
|
`rpc-run.ts` / `spawn.ts` (persistent child transport + selected→main handoff),
|
|
430
435
|
`worktree.ts` / `session-fork.ts` (filesystem/session branching), `tools.ts`
|
|
431
436
|
(wait/status/control/stop), `widget.ts` (active-only TUI status), `announcements.ts`
|
|
432
|
-
(recovery and feature notices), and `runtime.ts` (session-scoped ownership). No runtime
|
|
433
|
-
dependencies.
|
|
437
|
+
(recovery and feature notices), and `runtime.ts` (session-scoped ownership). No runtime
|
|
438
|
+
dependencies beyond pi peer dependencies.
|
|
434
439
|
|
|
435
440
|
## License
|
|
436
441
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ferris1225/pi-subagents",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Controllable background sub-agent threads for pi: specialized roles, capability-aware thinking, direct main-model fallback, auto-fix chains, and Git worktree isolation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/announcements.ts
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
/** Session-start recovery and one-time feature announcements. */
|
|
2
|
-
|
|
3
|
-
import { stat } from "node:fs/promises";
|
|
4
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { loadConfig, saveConfig } from "./config.ts";
|
|
6
|
-
import { announceRecoveryRecords } from "./recovery.ts";
|
|
7
|
-
import type { SubagentRuntime } from "./runtime.ts";
|
|
8
|
-
import { pruneResultArtifacts } from "./spawn.ts";
|
|
9
|
-
import { installActiveRunsWidget } from "./widget.ts";
|
|
10
|
-
|
|
11
|
-
const ANNOUNCEMENTS: Array<{
|
|
12
|
-
key: string;
|
|
13
|
-
condition: (config: Awaited<ReturnType<typeof loadConfig>>) => boolean;
|
|
14
|
-
message: string;
|
|
15
|
-
}> = [
|
|
16
|
-
{
|
|
17
|
-
key: "visionModel",
|
|
18
|
-
condition: (config) => config.visionModel === undefined,
|
|
19
|
-
message:
|
|
20
|
-
"pi-subagents: new — a vision-capable model can now handle image tasks (screenshots, mockups, designs). Run /subagents-setup to configure it; until set, vision tasks use the main session's current model.",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
key: "cleanerAgent",
|
|
24
|
-
condition: (config) => !config.enabledAgents.includes("cleaner"),
|
|
25
|
-
message:
|
|
26
|
-
"pi-subagents: new built-in cleaner agent is available for evidence-first code cleanup. Run /subagents-setup to enable it; your existing enabledAgents selection was left unchanged.",
|
|
27
|
-
},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
async function announceNewFeatures(
|
|
31
|
-
ctx: { ui: { notify: (message: string, kind: "info" | "warning" | "error") => void } },
|
|
32
|
-
runtime: SubagentRuntime,
|
|
33
|
-
): Promise<void> {
|
|
34
|
-
try {
|
|
35
|
-
let configExists = true;
|
|
36
|
-
try {
|
|
37
|
-
await stat(runtime.configPath);
|
|
38
|
-
} catch {
|
|
39
|
-
configExists = false;
|
|
40
|
-
}
|
|
41
|
-
if (!configExists) return;
|
|
42
|
-
|
|
43
|
-
const config = await loadConfig(runtime.configPath);
|
|
44
|
-
const pending = ANNOUNCEMENTS.filter(
|
|
45
|
-
(announcement) =>
|
|
46
|
-
announcement.condition(config) && !config.announcedFeatures.includes(announcement.key),
|
|
47
|
-
);
|
|
48
|
-
if (pending.length === 0) return;
|
|
49
|
-
await saveConfig(
|
|
50
|
-
{
|
|
51
|
-
...config,
|
|
52
|
-
announcedFeatures: [...config.announcedFeatures, ...pending.map((announcement) => announcement.key)],
|
|
53
|
-
},
|
|
54
|
-
runtime.configPath,
|
|
55
|
-
);
|
|
56
|
-
for (const announcement of pending) ctx.ui.notify(announcement.message, "info");
|
|
57
|
-
} catch {
|
|
58
|
-
/* announcement failures are non-fatal */
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function registerAnnouncements(pi: ExtensionAPI, runtime: SubagentRuntime): void {
|
|
63
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
64
|
-
pruneResultArtifacts();
|
|
65
|
-
await announceRecoveryRecords(runtime.configPath, ctx);
|
|
66
|
-
if (ctx.mode !== "tui") return;
|
|
67
|
-
installActiveRunsWidget(ctx);
|
|
68
|
-
await announceNewFeatures(ctx, runtime);
|
|
69
|
-
});
|
|
70
|
-
}
|
|
1
|
+
/** Session-start recovery and one-time feature announcements. */
|
|
2
|
+
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { loadConfig, saveConfig } from "./config.ts";
|
|
6
|
+
import { announceRecoveryRecords } from "./recovery.ts";
|
|
7
|
+
import type { SubagentRuntime } from "./runtime.ts";
|
|
8
|
+
import { pruneResultArtifacts } from "./spawn.ts";
|
|
9
|
+
import { installActiveRunsWidget } from "./widget.ts";
|
|
10
|
+
|
|
11
|
+
const ANNOUNCEMENTS: Array<{
|
|
12
|
+
key: string;
|
|
13
|
+
condition: (config: Awaited<ReturnType<typeof loadConfig>>) => boolean;
|
|
14
|
+
message: string;
|
|
15
|
+
}> = [
|
|
16
|
+
{
|
|
17
|
+
key: "visionModel",
|
|
18
|
+
condition: (config) => config.visionModel === undefined,
|
|
19
|
+
message:
|
|
20
|
+
"pi-subagents: new — a vision-capable model can now handle image tasks (screenshots, mockups, designs). Run /subagents-setup to configure it; until set, vision tasks use the main session's current model.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
key: "cleanerAgent",
|
|
24
|
+
condition: (config) => !config.enabledAgents.includes("cleaner"),
|
|
25
|
+
message:
|
|
26
|
+
"pi-subagents: new built-in cleaner agent is available for evidence-first code cleanup. Run /subagents-setup to enable it; your existing enabledAgents selection was left unchanged.",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
async function announceNewFeatures(
|
|
31
|
+
ctx: { ui: { notify: (message: string, kind: "info" | "warning" | "error") => void } },
|
|
32
|
+
runtime: SubagentRuntime,
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
try {
|
|
35
|
+
let configExists = true;
|
|
36
|
+
try {
|
|
37
|
+
await stat(runtime.configPath);
|
|
38
|
+
} catch {
|
|
39
|
+
configExists = false;
|
|
40
|
+
}
|
|
41
|
+
if (!configExists) return;
|
|
42
|
+
|
|
43
|
+
const config = await loadConfig(runtime.configPath);
|
|
44
|
+
const pending = ANNOUNCEMENTS.filter(
|
|
45
|
+
(announcement) =>
|
|
46
|
+
announcement.condition(config) && !config.announcedFeatures.includes(announcement.key),
|
|
47
|
+
);
|
|
48
|
+
if (pending.length === 0) return;
|
|
49
|
+
await saveConfig(
|
|
50
|
+
{
|
|
51
|
+
...config,
|
|
52
|
+
announcedFeatures: [...config.announcedFeatures, ...pending.map((announcement) => announcement.key)],
|
|
53
|
+
},
|
|
54
|
+
runtime.configPath,
|
|
55
|
+
);
|
|
56
|
+
for (const announcement of pending) ctx.ui.notify(announcement.message, "info");
|
|
57
|
+
} catch {
|
|
58
|
+
/* announcement failures are non-fatal */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function registerAnnouncements(pi: ExtensionAPI, runtime: SubagentRuntime): void {
|
|
63
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
64
|
+
pruneResultArtifacts();
|
|
65
|
+
await announceRecoveryRecords(runtime.configPath, ctx);
|
|
66
|
+
if (ctx.mode !== "tui") return;
|
|
67
|
+
installActiveRunsWidget(ctx);
|
|
68
|
+
await announceNewFeatures(ctx, runtime);
|
|
69
|
+
});
|
|
70
|
+
}
|