@ferris1225/pi-subagents 4.2.1 → 4.2.4
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 +4 -2
- package/agents/explorer.md +6 -9
- package/package.json +55 -55
- package/src/prompt.ts +3 -2
- package/src/recovery.ts +20 -2
- package/src/rpc-run.ts +993 -993
- package/src/thread-lifecycle.ts +1 -0
- package/src/worktree.ts +66 -30
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ directly when you want exact control.
|
|
|
53
53
|
|
|
54
54
|
| Agent | Access | Best for |
|
|
55
55
|
| ------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
-
| `explorer` | Read-only | Broad search, unfamiliar-area mapping, symbol and dependency tracing. Returns a retrieval index — never proof.
|
|
56
|
+
| `explorer` | Read-only | Broad search, unfamiliar-area mapping, symbol and dependency tracing. Returns a retrieval index — never proof. A single artifact the main agent must fully absorb (one issue, one spec) stays an inline read. |
|
|
57
57
|
| `executor` | Full | The default route for any non-trivial, self-contained task: implementation, fixes, refactors, tests, evidence-first cleanup, docs/comment sync, or merging a fan-out's results into one brief — carried through verification and a result-only handoff. |
|
|
58
58
|
|
|
59
59
|
Custom roles join them with a Markdown file (see [Custom agents](#custom-agents)).
|
|
@@ -127,7 +127,9 @@ main agent inspects the actual changes before calling anything done.
|
|
|
127
127
|
as a lane wait, not as slot queueing, and its process slot is already released.
|
|
128
128
|
- Setup and integration failures keep the useful patch and worktree, and record
|
|
129
129
|
where they are in `~/.pi/agent/pi-subagents-recovery.json`. Every later session
|
|
130
|
-
start repeats that notice until you remove the artifacts.
|
|
130
|
+
start repeats that notice until you remove the artifacts. When the changes had
|
|
131
|
+
already been applied and only the cleanup failed, the next session start
|
|
132
|
+
removes the retained copy itself and clears the notice.
|
|
131
133
|
|
|
132
134
|
## Threads: resume, stop
|
|
133
135
|
|
package/agents/explorer.md
CHANGED
|
@@ -12,7 +12,7 @@ You are an explorer agent: a fast, read-only reconnaissance specialist. You inve
|
|
|
12
12
|
## Hard constraints
|
|
13
13
|
|
|
14
14
|
- You are READ-ONLY. Never create, edit, or delete files; never run mutating commands. Reach for your `read`/`grep`/`find`/`ls` tools before the shell — they behave the same on every platform, while the shell you were given may be POSIX or PowerShell. Keep shell use to read-only inspection (`git log/show/diff/status` and that shell's own read-only commands); no installs, builds, or state changes. Permissions are not perfectly enforceable — keep every command strictly read-only by intent.
|
|
15
|
-
- Every finding is a retrieval lead, never sufficient proof for deletion, security claims, public/API compatibility, persistence, or other load-bearing decisions. The caller must re-read
|
|
15
|
+
- Every finding is a retrieval lead, never sufficient proof for deletion, security claims, public/API compatibility, persistence, or other load-bearing decisions. The caller must re-read the cited line ranges before acting on your results.
|
|
16
16
|
|
|
17
17
|
## Workflow
|
|
18
18
|
|
|
@@ -26,15 +26,12 @@ Thoroughness scales with the task (default medium): quick = targeted lookups in
|
|
|
26
26
|
|
|
27
27
|
## Final response
|
|
28
28
|
|
|
29
|
-
Return only
|
|
29
|
+
Return only retrieval results, one bare bullet per finding — a single line: path, the fact, nothing else:
|
|
30
30
|
|
|
31
31
|
```text
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- `path/to/file.ts` — first symbol/section to verify and why
|
|
36
|
-
## Gaps
|
|
37
|
-
- unresolved uncertainty (omit this section when none)
|
|
32
|
+
- `path/to/file.ts:10-50` — the fact
|
|
33
|
+
Start here: `path/to/file.ts` — entry symbol and why (only when the caller could not guess it)
|
|
34
|
+
Gaps: unresolved uncertainty (only when real)
|
|
38
35
|
```
|
|
39
36
|
|
|
40
|
-
Do not repeat the task brief, inventory every file opened, paste nonessential code, or narrate search
|
|
37
|
+
No preamble or closing summary. Do not repeat the task brief, inventory every file opened, paste nonessential code, or narrate the search; every line must carry a path with a fact or name a gap — delete anything else. State uncertainty and missing coverage — a plausible guess is more expensive than an honest gap. Stay under 15 lines by default; go longer only when the brief genuinely demands a wide survey — the 40-line delivery cap truncates your tail (usually the Gaps) and the caller pays for every line.
|
package/package.json
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@ferris1225/pi-subagents",
|
|
3
|
-
"version": "4.2.
|
|
4
|
-
"description": "A managed sub-agent team for pi: specialized roles, pre-commit documentation sync, retained threads, auto-fix chains, model fallback, and Git worktree isolation.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"publishConfig": {
|
|
8
|
-
"access": "public"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"pi-package",
|
|
12
|
-
"pi-extension",
|
|
13
|
-
"subagent",
|
|
14
|
-
"sub-agent",
|
|
15
|
-
"delegation",
|
|
16
|
-
"code-cleanup",
|
|
17
|
-
"dead-code"
|
|
18
|
-
],
|
|
19
|
-
"files": [
|
|
20
|
-
"src",
|
|
21
|
-
"agents",
|
|
22
|
-
"README.md",
|
|
23
|
-
"LICENSE"
|
|
24
|
-
],
|
|
25
|
-
"pi": {
|
|
26
|
-
"extensions": [
|
|
27
|
-
"./src/index.ts"
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
"scripts": {
|
|
31
|
-
"check": "tsc --noEmit",
|
|
32
|
-
"test": "vitest run tests",
|
|
33
|
-
"prepack": "npm run check && npm test"
|
|
34
|
-
},
|
|
35
|
-
"peerDependencies": {
|
|
36
|
-
"@earendil-works/pi-agent-core": ">=0.84.4",
|
|
37
|
-
"@earendil-works/pi-ai": ">=0.84.4",
|
|
38
|
-
"@earendil-works/pi-coding-agent": ">=0.84.4",
|
|
39
|
-
"@earendil-works/pi-tui": ">=0.84.4",
|
|
40
|
-
"typebox": "*"
|
|
41
|
-
},
|
|
42
|
-
"devDependencies": {
|
|
43
|
-
"@earendil-works/pi-agent-core": "^0.84.4",
|
|
44
|
-
"@earendil-works/pi-ai": "^0.84.4",
|
|
45
|
-
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
46
|
-
"@earendil-works/pi-tui": "^0.84.4",
|
|
47
|
-
"@types/node": "^22.10.0",
|
|
48
|
-
"typebox": "^1.3.9",
|
|
49
|
-
"typescript": "^5.9.0",
|
|
50
|
-
"vitest": "^4.1.0"
|
|
51
|
-
},
|
|
52
|
-
"engines": {
|
|
53
|
-
"node": ">=22.19.0"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@ferris1225/pi-subagents",
|
|
3
|
+
"version": "4.2.4",
|
|
4
|
+
"description": "A managed sub-agent team for pi: specialized roles, pre-commit documentation sync, retained threads, auto-fix chains, model fallback, and Git worktree isolation.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"pi-package",
|
|
12
|
+
"pi-extension",
|
|
13
|
+
"subagent",
|
|
14
|
+
"sub-agent",
|
|
15
|
+
"delegation",
|
|
16
|
+
"code-cleanup",
|
|
17
|
+
"dead-code"
|
|
18
|
+
],
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"agents",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"pi": {
|
|
26
|
+
"extensions": [
|
|
27
|
+
"./src/index.ts"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"check": "tsc --noEmit",
|
|
32
|
+
"test": "vitest run tests",
|
|
33
|
+
"prepack": "npm run check && npm test"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@earendil-works/pi-agent-core": ">=0.84.4",
|
|
37
|
+
"@earendil-works/pi-ai": ">=0.84.4",
|
|
38
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4",
|
|
39
|
+
"@earendil-works/pi-tui": ">=0.84.4",
|
|
40
|
+
"typebox": "*"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@earendil-works/pi-agent-core": "^0.84.4",
|
|
44
|
+
"@earendil-works/pi-ai": "^0.84.4",
|
|
45
|
+
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
46
|
+
"@earendil-works/pi-tui": "^0.84.4",
|
|
47
|
+
"@types/node": "^22.10.0",
|
|
48
|
+
"typebox": "^1.3.9",
|
|
49
|
+
"typescript": "^5.9.0",
|
|
50
|
+
"vitest": "^4.1.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22.19.0"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/prompt.ts
CHANGED
|
@@ -24,9 +24,10 @@ export function buildDelegationDirective(
|
|
|
24
24
|
|
|
25
25
|
const dispatchRules = [
|
|
26
26
|
`Delegate aggressively: child contexts are cheap, yours is scarce. Inline only trivial work — a lookup, a single focused edit, an answer already in context${hasExecutor ? "; default every non-trivial delegated task (implementation, fix, refactor, test, cleanup, docs sync, result merging) to `executor`" : ""}.`,
|
|
27
|
+
"A single artifact you must fully absorb yourself (one issue, one spec) is inline work — delegation saves search, not that read.",
|
|
27
28
|
...(hasExplorer
|
|
28
29
|
? [
|
|
29
|
-
"`explorer`: split a broad question into parallel explorers with disjoint scopes. Its findings are leads, never proof — re-read
|
|
30
|
+
"`explorer`: split a broad question into parallel explorers with disjoint scopes. Its findings are leads, never proof — re-read the cited line ranges before acting on them (a child you brief re-verifies).",
|
|
30
31
|
]
|
|
31
32
|
: []),
|
|
32
33
|
...(hasExecutor
|
|
@@ -45,7 +46,7 @@ export function buildDelegationDirective(
|
|
|
45
46
|
];
|
|
46
47
|
|
|
47
48
|
const verificationRules = [
|
|
48
|
-
"Never report an unrun check as passed; surface unavailable checks and pre-existing failures, and inspect actual
|
|
49
|
+
"Never report an unrun check as passed; surface unavailable checks and pre-existing failures, and inspect the actual diff before reporting completion.",
|
|
49
50
|
"Commit or push only when explicitly requested and applicable checks pass.",
|
|
50
51
|
];
|
|
51
52
|
|
package/src/recovery.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { existsSync } from "node:fs";
|
|
|
5
5
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { stripVTControlCharacters } from "node:util";
|
|
8
|
-
import type
|
|
8
|
+
import { removeWorktreeGroup, worktreeGroupDir, type WorktreeFinalization } from "./worktree.ts";
|
|
9
9
|
|
|
10
10
|
export const RECOVERY_MANIFEST_FILE_NAME = "pi-subagents-recovery.json";
|
|
11
11
|
const RECOVERY_MANIFEST_VERSION = 1;
|
|
@@ -14,6 +14,8 @@ export interface RecoveryRecord {
|
|
|
14
14
|
runId: number;
|
|
15
15
|
createdAt: number;
|
|
16
16
|
integrated: boolean;
|
|
17
|
+
/** Repository a cleanup retry can prune stale worktree metadata against. */
|
|
18
|
+
originalRoot?: string;
|
|
17
19
|
worktreePath?: string;
|
|
18
20
|
patchPath?: string;
|
|
19
21
|
error?: string;
|
|
@@ -37,6 +39,7 @@ function normalizeRecord(value: unknown): RecoveryRecord | undefined {
|
|
|
37
39
|
runId: raw.runId,
|
|
38
40
|
createdAt: raw.createdAt,
|
|
39
41
|
integrated: raw.integrated === true,
|
|
42
|
+
...(typeof raw.originalRoot === "string" && raw.originalRoot ? { originalRoot: raw.originalRoot } : {}),
|
|
40
43
|
...(typeof raw.worktreePath === "string" && raw.worktreePath ? { worktreePath: raw.worktreePath } : {}),
|
|
41
44
|
...(typeof raw.patchPath === "string" && raw.patchPath ? { patchPath: raw.patchPath } : {}),
|
|
42
45
|
...(typeof raw.error === "string" && raw.error ? { error: raw.error } : {}),
|
|
@@ -105,6 +108,7 @@ export function recoveryRecordFromFinalization(
|
|
|
105
108
|
runId,
|
|
106
109
|
createdAt: now,
|
|
107
110
|
integrated: finalization.integrated,
|
|
111
|
+
...(finalization.originalRoot ? { originalRoot: finalization.originalRoot } : {}),
|
|
108
112
|
...(finalization.worktreePath ? { worktreePath: finalization.worktreePath } : {}),
|
|
109
113
|
...(finalization.patchPath ? { patchPath: finalization.patchPath } : {}),
|
|
110
114
|
...(finalization.error ? { error: finalization.error } : {}),
|
|
@@ -112,7 +116,10 @@ export function recoveryRecordFromFinalization(
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
/** Show retained recovery paths on every later session start until the user
|
|
115
|
-
* removes the artifacts.
|
|
119
|
+
* removes the artifacts. Records whose changes already landed only need the
|
|
120
|
+
* worktree group deleted — the step whose failure retained them — so each
|
|
121
|
+
* session start retries that removal first and forgets records it completes.
|
|
122
|
+
* Stale records are pruned automatically. */
|
|
116
123
|
export async function announceRecoveryRecords(
|
|
117
124
|
configPath: string,
|
|
118
125
|
ctx: {
|
|
@@ -123,6 +130,17 @@ export async function announceRecoveryRecords(
|
|
|
123
130
|
if (ctx.hasUI === false) return;
|
|
124
131
|
const records = await readRecoveryRecords(configPath);
|
|
125
132
|
if (records.length === 0) return;
|
|
133
|
+
for (const record of records) {
|
|
134
|
+
if (!record.integrated || !record.worktreePath) continue;
|
|
135
|
+
const groupDir = worktreeGroupDir(record.worktreePath);
|
|
136
|
+
if (!groupDir) continue;
|
|
137
|
+
if (!existsSync(record.worktreePath) && !(record.patchPath ? existsSync(record.patchPath) : false)) continue;
|
|
138
|
+
await removeWorktreeGroup({
|
|
139
|
+
originalRoot: record.originalRoot,
|
|
140
|
+
worktreePath: record.worktreePath,
|
|
141
|
+
tempDir: groupDir,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
126
144
|
const live = records.filter((record) =>
|
|
127
145
|
(record.worktreePath ? existsSync(record.worktreePath) : false) ||
|
|
128
146
|
(record.patchPath ? existsSync(record.patchPath) : false),
|