@cad0p/pi-subagents-tintinweb 0.14.2 → 0.22.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 +20 -1
- package/CONTRIBUTING.md +8 -0
- package/README.md +98 -58
- package/docs/fork-differences.md +51 -0
- package/docs/verification-checklist.md +132 -0
- package/examples/agent-tool-description.md +3 -9
- package/package.json +13 -11
- package/pnpm-workspace.yaml +9 -0
- package/src/abortable.ts +43 -0
- package/src/agent-manager.ts +404 -140
- package/src/agent-runner.ts +462 -89
- package/src/agent-types.ts +269 -23
- package/src/checkpoint.ts +49 -0
- package/src/child-context.ts +30 -0
- package/src/cross-extension-rpc.ts +65 -5
- package/src/custom-agents.ts +161 -14
- package/src/default-agents.ts +1 -1
- package/src/index.ts +1014 -980
- package/src/invocation-config.ts +81 -12
- package/src/model-resolver.ts +18 -0
- package/src/model-scope.ts +62 -0
- package/src/nested-tools.ts +406 -0
- package/src/output-file.ts +18 -1
- package/src/prompts.ts +71 -0
- package/src/result-report.ts +170 -0
- package/src/schedule-store.ts +300 -13
- package/src/schedule.ts +222 -77
- package/src/settings.ts +206 -32
- package/src/status-note.ts +18 -1
- package/src/text-safety.ts +69 -0
- package/src/types.ts +101 -58
- package/src/ui/agent-widget.ts +104 -36
- package/src/ui/conversation-viewer.ts +36 -18
- package/src/ui/fleet-list.ts +19 -8
- package/src/ui/schedule-menu.ts +63 -19
- package/src/usage.ts +128 -8
- package/src/worktree.ts +19 -0
- package/src/group-join.ts +0 -141
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# PR Verification Checklist
|
|
2
|
+
|
|
3
|
+
Automated checks are necessary but not sufficient. This checklist is what a PR
|
|
4
|
+
author runs before requesting review. Record the evidence in the PR body so a
|
|
5
|
+
reviewer can see what was verified, on which setup. Skip a section only when it
|
|
6
|
+
does not apply, and say so explicitly.
|
|
7
|
+
|
|
8
|
+
## Workspace
|
|
9
|
+
|
|
10
|
+
Keep the main checkout on `main`. Do the branch work in an isolated git worktree
|
|
11
|
+
in a sibling folder (`git worktree add ../<repo>-<slug> <branch>`), install its
|
|
12
|
+
dependencies there, and run every gate and live check from it. Remove the
|
|
13
|
+
worktree after merge.
|
|
14
|
+
|
|
15
|
+
## Automated gates
|
|
16
|
+
|
|
17
|
+
Run all four from the repository root; all must pass (mirrors `CONTRIBUTING.md`'s
|
|
18
|
+
"Before Submitting a PR"):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run lint # biome
|
|
22
|
+
npm run typecheck # tsc --noEmit
|
|
23
|
+
npm run test # vitest, including the *-e2e.test.ts suites
|
|
24
|
+
npm run build # tsc
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`npm run lint:fix` auto-fixes most style issues. If the change touches the
|
|
28
|
+
end-to-end surface, also run the scripted suite directly:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm run test:e2e
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`PI_E2E_LIVE=1 npm run test:e2e` swaps the scripted faux suite for the live one
|
|
35
|
+
and exercises a real model through your local `pi` login (`PI_PROVIDER` /
|
|
36
|
+
`PI_MODEL` can pin the provider and model). Run it by hand before publishing.
|
|
37
|
+
|
|
38
|
+
## Manual TUI checks
|
|
39
|
+
|
|
40
|
+
Run these in a live pi session with the extension installed from the branch, and
|
|
41
|
+
note the pi version in the PR body. Renderer behavior differs across pi
|
|
42
|
+
versions; when the change targets a newer runtime, verify on that version too.
|
|
43
|
+
|
|
44
|
+
Maintainer reference setup: `claude-bridge/claude-haiku-5-5` at thinking
|
|
45
|
+
`xhigh`; fall back to `opencode-go/deepseek-v4.1-flash` at `max` when the bridge
|
|
46
|
+
is unavailable. Load the branch build instead of the installed package so the two
|
|
47
|
+
don't collide:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pi --no-extensions -e <pi-claude-bridge>/src/index.ts -e <repo>/src/index.ts \
|
|
51
|
+
--provider claude-bridge --model claude-haiku-5-5 --thinking xhigh
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- Exercise the changed surface end to end in a real session — spawn, steer,
|
|
55
|
+
render, resume, or whatever the PR touches.
|
|
56
|
+
- Toggle collapsed/expanded states with ctrl+o and, on pi 0.87.1+, per-row
|
|
57
|
+
click; confirm both paths reach the same state and the marker and hint update.
|
|
58
|
+
- Check theme and color rendering in at least one dark theme; confirm wrapped or
|
|
59
|
+
clipped text stays within the intended box.
|
|
60
|
+
- Feed long and edge inputs (empty, whitespace-only, multi-line, large) and
|
|
61
|
+
confirm the collapsed row stays bounded while the expanded view shows the full
|
|
62
|
+
content.
|
|
63
|
+
- Confirm terminal control characters (ESC/OSC/CSI, newlines, tabs) in untrusted
|
|
64
|
+
text cannot forge rows or leak into the terminal: display copies are
|
|
65
|
+
sanitized, model-facing payloads are not.
|
|
66
|
+
|
|
67
|
+
## Session-level checks
|
|
68
|
+
|
|
69
|
+
Run these when the change touches session data, rendering, or persistence:
|
|
70
|
+
|
|
71
|
+
- Load and replay an existing session containing the affected entry or tool
|
|
72
|
+
call; the old data must render without throwing.
|
|
73
|
+
- Run `/export` and confirm the HTML renders without a crash and the affected
|
|
74
|
+
content appears where expected.
|
|
75
|
+
- If the change touches cross-extension RPC or events, verify the RPC surface
|
|
76
|
+
still answers.
|
|
77
|
+
|
|
78
|
+
## Independent agent review
|
|
79
|
+
|
|
80
|
+
Every PR, docs included, needs a fresh read-only review agent on each pushed
|
|
81
|
+
head before merge (plus any escalation). This section has no skip; the
|
|
82
|
+
author's own checks don't count as review. Record every round in the PR body,
|
|
83
|
+
under Evidence. A verdict counts only for the SHA it reviewed.
|
|
84
|
+
|
|
85
|
+
- Spawn a new `general-purpose` agent with `max_turns: 20`. Don't
|
|
86
|
+
use `resume`, `inherit_context`, `isolation` (a worktree branches from the
|
|
87
|
+
caller's committed `HEAD`, not the PR head), or `steer_subagent`.
|
|
88
|
+
- Brief it with the linked issue (the guarantees), the head SHA and the
|
|
89
|
+
worktree path holding it, the diff range `origin/main...<head-sha>`, and this
|
|
90
|
+
checklist. Leave out your own conclusions, test results, the PR body's
|
|
91
|
+
verification notes, and earlier verdicts. Frame it as a completeness
|
|
92
|
+
question: which inputs, callers, settings, or runtime versions would break
|
|
93
|
+
the guarantees while the gates stay green?
|
|
94
|
+
- The brief forbids edits, commits, pushes, branch switches, and auto-fixers
|
|
95
|
+
(`npm run lint:fix`). It states the turn budget and the way out: reply
|
|
96
|
+
`NO VERDICT` with what was tested if the budget runs out, `HEAD` differs from
|
|
97
|
+
the head SHA, or the diff is empty.
|
|
98
|
+
- The first line of the final message is `CLEAN`, `FINDINGS(n)`, or
|
|
99
|
+
`NO VERDICT`; then what it checked, and each finding tagged must-fix,
|
|
100
|
+
should-fix, or nit. A run that hit its turn limit, was aborted, or ends
|
|
101
|
+
without a first-line verdict counts as `NO VERDICT`.
|
|
102
|
+
- After a `NO VERDICT`, retry `general-purpose` once with a narrower brief,
|
|
103
|
+
or a higher `max_turns` if the task needs it.
|
|
104
|
+
- Escalate to the user-defined `smart` agent only when the review makes claims
|
|
105
|
+
that are easily shown wrong by facts (a misread API, code that doesn't exist,
|
|
106
|
+
behaviour the source contradicts). Don't escalate over opinionated findings
|
|
107
|
+
you disagree with. Confirm the result reports the escalated type: an unknown
|
|
108
|
+
`subagent_type` silently runs `general-purpose`, which is not an escalation.
|
|
109
|
+
- A must-fix finding blocks its head until it is folded into a new head
|
|
110
|
+
(reviewed by a new `general-purpose` agent) or dismissed with the
|
|
111
|
+
maintainer's reason recorded in the PR body, citing the facts for a wrong
|
|
112
|
+
finding. A later verdict on the same head does not clear it by itself.
|
|
113
|
+
Should-fix and nit findings may stay open if recorded.
|
|
114
|
+
- Merge only when the current head has a `CLEAN` or `FINDINGS(n)` verdict with
|
|
115
|
+
no undismissed must-fix findings.
|
|
116
|
+
|
|
117
|
+
## Fork release rules
|
|
118
|
+
|
|
119
|
+
- Do not edit `CHANGELOG.md` on non-release branches; the fork's
|
|
120
|
+
`validate-package-version` CI gate rejects it.
|
|
121
|
+
- Release notes go in the PR body under `## Release notes`, with attribution
|
|
122
|
+
where one applies.
|
|
123
|
+
|
|
124
|
+
## Evidence
|
|
125
|
+
|
|
126
|
+
In the PR body, record:
|
|
127
|
+
|
|
128
|
+
- the pi version and platform used for the live checks;
|
|
129
|
+
- each command you ran and its result;
|
|
130
|
+
- the manual observations (what you saw, not just "works");
|
|
131
|
+
- every review round: the head it reviewed, the agent type, and the verdict;
|
|
132
|
+
- any check that does not apply, and why.
|
|
@@ -14,18 +14,12 @@ If the target is already known, use a direct tool — `read` for a known path, `
|
|
|
14
14
|
## Usage notes
|
|
15
15
|
|
|
16
16
|
- Always include a short (3-5 word) description summarizing what the agent will do (shown in UI).
|
|
17
|
-
- When
|
|
18
|
-
- When the agent is done, it returns a single message back to you. The result is not visible to the user — to show the user, send a text message with a concise summary.
|
|
17
|
+
- When an agent finishes or fails, you will be notified on subagent completion/failure — do NOT poll or sleep waiting for it.
|
|
19
18
|
- Trust but verify: an agent's summary describes what it intended to do, not necessarily what it did. When an agent writes or edits code, check the actual changes before reporting work as done.
|
|
20
|
-
- Use run_in_background for work you don't need immediately. You will be notified when it completes — do NOT poll or sleep waiting for it. Continue with other work or respond to the user instead.
|
|
21
|
-
- Foreground vs background: use foreground (default) when you need the agent's results before you can proceed. Use background when you have genuinely independent work to do in parallel.
|
|
22
19
|
- Use resume with an agent ID to continue a previous agent's work. A new (non-resume) Agent call starts a fresh agent with no memory of prior runs, so the prompt must be self-contained.
|
|
23
|
-
- Use steer_subagent to send mid-run messages to a running
|
|
20
|
+
- Use steer_subagent to send mid-run messages to a running subagent.
|
|
24
21
|
- Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, etc.), since it is not aware of the user's intent.
|
|
25
|
-
-
|
|
26
|
-
- Use thinking to control extended thinking level.
|
|
27
|
-
- Use inherit_context if the agent needs the parent conversation history.
|
|
28
|
-
- Use isolation: "worktree" to run the agent in an isolated git worktree (safe parallel file modifications). The worktree is automatically cleaned up if the agent makes no changes; otherwise the path and branch are returned in the result.{{scheduleGuideline}}
|
|
22
|
+
- Use inherit_context if the agent needs the parent conversation history.{{isolationGuideline}}{{scheduleGuideline}}
|
|
29
23
|
|
|
30
24
|
## Writing the prompt
|
|
31
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cad0p/pi-subagents-tintinweb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "A pi extension extension that brings smart Claude Code-style autonomous sub-agents to pi.",
|
|
5
5
|
"author": "tintinweb",
|
|
6
6
|
"publishConfig": {
|
|
@@ -25,18 +25,17 @@
|
|
|
25
25
|
"autonomous"
|
|
26
26
|
],
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@earendil-works/pi-ai": ">=0.
|
|
29
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
30
|
-
"@earendil-works/pi-tui": ">=0.
|
|
28
|
+
"@earendil-works/pi-ai": ">=1.0.4",
|
|
29
|
+
"@earendil-works/pi-coding-agent": ">=1.0.4",
|
|
30
|
+
"@earendil-works/pi-tui": ">=1.0.4",
|
|
31
|
+
"@sinclair/typebox": "*"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@sinclair/typebox": "^0.34.49",
|
|
34
34
|
"croner": "^10.0.1",
|
|
35
35
|
"nanoid": "^5.0.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsc",
|
|
39
|
-
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build",
|
|
40
39
|
"test": "vitest run",
|
|
41
40
|
"test:watch": "vitest",
|
|
42
41
|
"test:e2e": "vitest run e2e --reporter=verbose",
|
|
@@ -46,16 +45,19 @@
|
|
|
46
45
|
},
|
|
47
46
|
"devDependencies": {
|
|
48
47
|
"@biomejs/biome": "^2.4.14",
|
|
48
|
+
"@earendil-works/pi-ai": "1.0.4",
|
|
49
|
+
"@earendil-works/pi-coding-agent": "1.0.4",
|
|
50
|
+
"@earendil-works/pi-tui": "1.0.4",
|
|
49
51
|
"@types/node": "^25.5.0",
|
|
50
52
|
"typescript": "^6.0.0",
|
|
51
|
-
"vitest": "^4.0.18"
|
|
52
|
-
"@earendil-works/pi-ai": ">=0.80.0"
|
|
53
|
+
"vitest": "^4.0.18"
|
|
53
54
|
},
|
|
54
55
|
"pi": {
|
|
55
56
|
"extensions": [
|
|
56
57
|
"./src/index.ts"
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=22.19.0"
|
|
60
62
|
}
|
|
61
63
|
}
|
package/pnpm-workspace.yaml
CHANGED
|
@@ -10,3 +10,12 @@ allowBuilds:
|
|
|
10
10
|
esbuild: true
|
|
11
11
|
koffi: false
|
|
12
12
|
protobufjs: true
|
|
13
|
+
minimumReleaseAgeExclude:
|
|
14
|
+
- "@earendil-works/chord@1.0.4"
|
|
15
|
+
- "@earendil-works/pi-agent-core@1.0.4"
|
|
16
|
+
- "@earendil-works/pi-ai@1.0.4"
|
|
17
|
+
- "@earendil-works/pi-codemode@1.0.4"
|
|
18
|
+
- "@earendil-works/pi-coding-agent@1.0.4"
|
|
19
|
+
- "@earendil-works/pi-mcp@1.0.4"
|
|
20
|
+
- "@earendil-works/pi-telemetry@1.0.4"
|
|
21
|
+
- "@earendil-works/pi-tui@1.0.4"
|
package/src/abortable.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* abortable.ts — race a promise against an AbortSignal without cancelling the
|
|
3
|
+
* underlying work.
|
|
4
|
+
*
|
|
5
|
+
* Used by the nested `get_subagent_result` wait path: pressing Esc cancels only
|
|
6
|
+
* the caller's wait; the background child keeps running and its result stays
|
|
7
|
+
* unconsumed. The listener is removed on every settle path so the signal
|
|
8
|
+
* accumulates no handlers, and a late settlement of the wrapped promise after
|
|
9
|
+
* an abort is absorbed as a no-op (no unhandled rejection).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** Await a promise until it settles or the caller cancels, without aborting the underlying work. */
|
|
13
|
+
export function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
14
|
+
if (!signal) return promise;
|
|
15
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
16
|
+
|
|
17
|
+
return new Promise<T>((resolve, reject) => {
|
|
18
|
+
let settled = false;
|
|
19
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
20
|
+
const onAbort = () => {
|
|
21
|
+
if (settled) return;
|
|
22
|
+
settled = true;
|
|
23
|
+
cleanup();
|
|
24
|
+
reject(signal.reason);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
28
|
+
promise.then(
|
|
29
|
+
(value) => {
|
|
30
|
+
if (settled) return;
|
|
31
|
+
settled = true;
|
|
32
|
+
cleanup();
|
|
33
|
+
resolve(value);
|
|
34
|
+
},
|
|
35
|
+
(error: unknown) => {
|
|
36
|
+
if (settled) return;
|
|
37
|
+
settled = true;
|
|
38
|
+
cleanup();
|
|
39
|
+
reject(error);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
}
|