@mgiles/perk 2.3.0 → 3.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 +1 -1
- package/extension/adapters/planAdapterPlannotator.ts +135 -91
- package/extension/adapters/planAdapterTombell.ts +5 -3
- package/extension/doors/address.ts +235 -37
- package/extension/doors/annotationPush.ts +924 -0
- package/extension/doors/auditWaveTools.ts +352 -0
- package/extension/doors/ciExecutor.ts +220 -55
- package/extension/doors/commitCompact.ts +98 -10
- package/extension/doors/draftReviewWaveTools.ts +412 -0
- package/extension/doors/dreamWaveTools.ts +475 -0
- package/extension/doors/harvestWaveTools.ts +279 -0
- package/extension/doors/land.ts +1 -0
- package/extension/doors/learn.ts +24 -6
- package/extension/doors/learnFactory.ts +33 -7
- package/extension/doors/lifecycleGates.ts +1 -1
- package/extension/doors/objectiveReviewBrowser.ts +537 -0
- package/extension/doors/objectiveStack.ts +1143 -0
- package/extension/doors/planReviewBrowser.ts +475 -0
- package/extension/doors/plannotatorHandoff.ts +120 -49
- package/extension/doors/prReview.ts +180 -63
- package/extension/doors/prReviewBrowser.ts +31 -23
- package/extension/doors/prReviewDynamic.ts +57 -30
- package/extension/doors/prReviewTerminal.ts +6 -11
- package/extension/doors/reviewWaveTools.ts +397 -0
- package/extension/doors/selfcheck.ts +1 -1
- package/extension/doors/submit.ts +82 -7
- package/extension/factories/gistAuthor.ts +4 -4
- package/extension/factories/gistDraft.ts +1 -1
- package/extension/factories/gistSave.ts +2 -2
- package/extension/factories/objective.ts +7 -7
- package/extension/factories/objectiveAuthor.ts +5 -4
- package/extension/factories/objectiveDraft.ts +153 -30
- package/extension/factories/objectiveDreamReport.ts +347 -0
- package/extension/factories/objectivePlan.ts +163 -9
- package/extension/factories/objectiveSave.ts +90 -2
- package/extension/factories/planMode.ts +5 -3
- package/extension/factories/planReview.ts +304 -46
- package/extension/factories/planTitle.ts +27 -9
- package/extension/hunkFeedback/inbox.ts +389 -0
- package/extension/hunkFeedback/perkFeedback.ts +364 -0
- package/extension/hunkFeedback/receiver.ts +296 -0
- package/extension/hunkFeedback/store.ts +533 -0
- package/extension/index.ts +169 -57
- package/extension/substrate/agentScratch.ts +171 -0
- package/extension/substrate/bindingDelivery.ts +9 -11
- package/extension/substrate/cache.ts +166 -23
- package/extension/substrate/coldDoor.ts +2 -3
- package/extension/substrate/command.ts +9 -6
- package/extension/substrate/config.ts +41 -12
- package/extension/substrate/git.ts +95 -2
- package/extension/substrate/providers.ts +4 -33
- package/extension/substrate/resources.ts +11 -0
- package/extension/substrate/result.ts +16 -7
- package/extension/substrate/sessionData.ts +8 -6
- package/extension/substrate/sessionPointers.ts +4 -5
- package/extension/substrate/structuredOutput.ts +78 -19
- package/extension/substrate/toolGating.ts +179 -23
- package/extension/substrate/workflowState.ts +50 -2
- package/extension/surfaces/footerProvider.ts +6 -6
- package/extension/surfaces/report.ts +38 -12
- package/extension/surfaces/surfaces.ts +213 -275
- package/extension/vendor/btw/btw.ts +94 -17
- package/extension/waves/adversarialReviewWave.ts +181 -0
- package/extension/waves/auditWave.ts +312 -0
- package/extension/waves/draftReviewWave.ts +205 -0
- package/extension/waves/dreamReducerWave.ts +700 -0
- package/extension/waves/dreamReport.ts +1494 -0
- package/extension/waves/dreamWave.ts +927 -0
- package/extension/waves/harvestWave.ts +399 -0
- package/extension/waves/memoryAdapter.ts +14 -1
- package/extension/waves/objectiveExplorerWave.ts +120 -0
- package/extension/waves/ponytail.ts +104 -0
- package/extension/waves/prReviewDynamicWave.ts +383 -72
- package/extension/waves/prReviewWave.ts +175 -25
- package/extension/waves/reportWave.ts +503 -107
- package/extension/waves/reviewClassifierWave.ts +109 -0
- package/extension/waves/rpcAdapter.ts +65 -2
- package/extension/worker/readOnlySession.ts +4 -5
- package/extension/worker/worker.ts +71 -93
- package/extension/workerMain.ts +4 -6
- package/package.json +18 -5
- package/prompts/README.md +19 -0
- package/prompts/_fixtures/live.yaml +115 -65
- package/prompts/commit-and-compact-continuation.md +13 -0
- package/prompts/common/resume-advisory.md +1 -0
- package/prompts/contexts/adapters/plannotator-gist.md +13 -0
- package/prompts/contexts/adapters/plannotator-objective.md +8 -3
- package/prompts/contexts/adapters/plannotator-plan.md +8 -3
- package/prompts/contexts/gist-authoring.md +6 -20
- package/prompts/contexts/objective-authoring.md +6 -18
- package/prompts/stages/address/action.md +3 -14
- package/prompts/stages/address/preview.md +2 -13
- package/prompts/stages/audit.md +18 -0
- package/prompts/stages/conflict-resolution.md +1 -1
- package/prompts/stages/gist-author/seed.md +4 -4
- package/prompts/stages/gist-save.md +1 -1
- package/prompts/stages/implement.md +3 -1
- package/prompts/stages/learn-code.md +1 -1
- package/prompts/stages/learn-docs.md +2 -2
- package/prompts/stages/learn-dream.md +10 -0
- package/prompts/stages/learn-harvest.md +15 -0
- package/prompts/stages/learn-orchestrate.md +1 -1
- package/prompts/stages/objective-author/adopt.md +5 -3
- package/prompts/stages/objective-author/file.md +5 -4
- package/prompts/stages/objective-author/seed.md +5 -4
- package/prompts/stages/objective-land.md +7 -0
- package/prompts/stages/objective-plan/guidance.md +2 -13
- package/prompts/stages/objective-plan/seed.md +5 -12
- package/prompts/stages/objective-recover.md +8 -0
- package/prompts/stages/objective-replan.md +4 -2
- package/prompts/stages/objective-review-browser.md +9 -0
- package/prompts/stages/objective-sync.md +6 -0
- package/prompts/stages/plan-from/adopt.md +2 -2
- package/prompts/stages/plan-from/file.md +2 -2
- package/prompts/stages/plan-review-browser.md +9 -0
- package/prompts/stages/pr-review-browser/active.md +6 -14
- package/prompts/stages/pr-review-browser/foreign.md +6 -14
- package/prompts/stages/pr-review-dynamic.md +6 -6
- package/prompts/stages/pr-review-terminal/active.md +7 -15
- package/prompts/stages/pr-review-terminal/foreign.md +7 -15
- package/prompts/stages/pr-review-terminal/local.md +1 -1
- package/prompts/stages/pr-review.md +5 -5
- package/prompts/stages/replan.md +3 -3
- package/shared/README.md +2 -2
- package/shared/bindings.yaml +15 -0
- package/shared/contracts-history.md +11 -0
- package/shared/contracts.md +5373 -281
- package/shared/providers.yaml +27 -60
- package/shared/registry.yaml +42 -18
- package/shared/schemas/inputs/review-post-batch.schema.json +14 -1
- package/shared/schemas/outputs/objective-doctor.schema.json +487 -0
- package/shared/schemas/outputs/objective-stack-land.schema.json +732 -0
- package/shared/schemas/outputs/objective-stack-recover.schema.json +397 -0
- package/shared/schemas/outputs/objective-stack-status.schema.json +577 -0
- package/shared/schemas/outputs/objective-stack-sync.schema.json +184 -0
- package/shared/schemas/outputs/plan-save.schema.json +12 -0
- package/shared/schemas/outputs/pr-land.schema.json +3 -3
- package/shared/schemas/outputs/pr-submit.schema.json +177 -1
- package/extension/adapters/todoAdapterJuicesharp.ts +0 -102
- package/extension/checkpoints/checkpoints.ts +0 -550
- package/extension/checkpoints/planSteps.ts +0 -108
- package/extension/doors/askUser.ts +0 -198
- package/prompts/common/output-schemas/objective-explorer.md +0 -36
- package/prompts/common/output-schemas/review-classifier.md +0 -47
- package/prompts/contexts/adapters/juicesharp-todo.md +0 -7
|
@@ -53,20 +53,29 @@ export function ok<D extends object>(
|
|
|
53
53
|
/**
|
|
54
54
|
* Bind the module's fail constructor once: `const fail = failFor(ctx, scope)` (or
|
|
55
55
|
* `failFor(ctx, scope, label)` when the content label differs from the report scope). Each call
|
|
56
|
-
* reports
|
|
57
|
-
* canonical soft failure: content
|
|
58
|
-
* `
|
|
56
|
+
* reports through the terminal-safe report seam (`alsoLog` mirrors complete diagnostics only in
|
|
57
|
+
* headless/RPC contexts) and returns the canonical soft failure: content
|
|
58
|
+
* `"<label> failed: <message>"`, details
|
|
59
|
+
* `{ ok: false, error: message, error_type: errorType }`, no `terminate`. `X` is the
|
|
60
|
+
* `FailDetails` extras hook: `failFor<X>(…)` lets a call attach module-specific fail details
|
|
61
|
+
* (spread AFTER `error`/`error_type`) — e.g. the learn wave's attempt receipts. Extras stay
|
|
62
|
+
* optional, so existing extras-free call sites are unchanged.
|
|
59
63
|
*/
|
|
60
|
-
export function failFor(
|
|
64
|
+
export function failFor<X extends object = Record<never, never>>(
|
|
61
65
|
target: ReportTarget,
|
|
62
66
|
scope: string,
|
|
63
67
|
label: string = scope,
|
|
64
|
-
): (message: string, errorType: string) => FailResult {
|
|
65
|
-
return (message, errorType) => {
|
|
68
|
+
): (message: string, errorType: string, extras?: X) => FailResult<X> {
|
|
69
|
+
return (message, errorType, extras) => {
|
|
66
70
|
report(target, scope, "error", message, { alsoLog: true });
|
|
67
71
|
return {
|
|
68
72
|
content: [{ type: "text", text: `${label} failed: ${message}` }],
|
|
69
|
-
details: {
|
|
73
|
+
details: {
|
|
74
|
+
ok: false,
|
|
75
|
+
error: message,
|
|
76
|
+
error_type: errorType,
|
|
77
|
+
...(extras ?? {}),
|
|
78
|
+
} as FailDetails<X>,
|
|
70
79
|
};
|
|
71
80
|
};
|
|
72
81
|
}
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
// loadable under `node --test`; accepts a minimal structural ctx (`BranchSource & { cwd }`).
|
|
34
34
|
|
|
35
35
|
import { createHash } from "node:crypto";
|
|
36
|
-
import { existsSync, mkdirSync, readFileSync
|
|
36
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
37
37
|
import { join, relative } from "node:path";
|
|
38
38
|
import type { ReportTarget } from "../surfaces/report.ts";
|
|
39
|
-
import { sessionDataDir } from "./cache.ts";
|
|
39
|
+
import { atomicWriteFileSync, ensureRunScratch, sessionDataDir } from "./cache.ts";
|
|
40
40
|
import {
|
|
41
41
|
appendWorkflowState,
|
|
42
42
|
type BranchSource,
|
|
@@ -72,11 +72,13 @@ export function activeSessionDataDir(ctx: SessionDataCtx): string | null {
|
|
|
72
72
|
return sessionDataDir(ctx.cwd, runId);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
/** Ensure
|
|
75
|
+
/** Ensure the validated run root, then its data dir; `null` + a warning on failure. */
|
|
76
76
|
export function ensureSessionDataDir(ctx: SessionDataCtx): string | null {
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
77
|
+
const runId = activeSessionRunId(ctx);
|
|
78
|
+
if (runId === null) return null;
|
|
79
|
+
const dir = sessionDataDir(ctx.cwd, runId);
|
|
79
80
|
try {
|
|
81
|
+
ensureRunScratch(ctx.cwd, runId);
|
|
80
82
|
mkdirSync(dir, { recursive: true });
|
|
81
83
|
} catch (error) {
|
|
82
84
|
console.error(`perk: warning: could not create session data dir ${dir}: ${error}`);
|
|
@@ -115,7 +117,7 @@ export function writeSessionData(
|
|
|
115
117
|
if (dir === null) return null;
|
|
116
118
|
const path = join(dir, name);
|
|
117
119
|
try {
|
|
118
|
-
|
|
120
|
+
atomicWriteFileSync(path, content);
|
|
119
121
|
} catch (error) {
|
|
120
122
|
console.error(`perk: warning: could not write session data ${path}: ${error}`);
|
|
121
123
|
return null;
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
// wedge the save/launch/drive it rides on. Node builtins + cache.ts + git.ts only (loads under
|
|
14
14
|
// `node --test`).
|
|
15
15
|
|
|
16
|
-
import { existsSync,
|
|
16
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
17
17
|
import { basename, join } from "node:path";
|
|
18
|
-
import { runScratchDir } from "./cache.ts";
|
|
18
|
+
import { atomicWriteFileSync, ensureRunScratch, runScratchDir } from "./cache.ts";
|
|
19
19
|
import { mainCheckoutRoot } from "./git.ts";
|
|
20
20
|
|
|
21
21
|
export const SESSION_POINTERS_FILE = "session-pointers.json";
|
|
@@ -119,9 +119,8 @@ export function recordSessionPointer(
|
|
|
119
119
|
// The run id is authoritative — a record read from disk keeps its own; a fresh one is minted
|
|
120
120
|
// with `runId`. (A mismatched on-disk run_id is left as-is; self-keying guarantees a match.)
|
|
121
121
|
record[klass][site] = pointer;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
writeFileSync(sessionPointersPath(root, runId), serialize(record), "utf8");
|
|
122
|
+
ensureRunScratch(root, runId);
|
|
123
|
+
atomicWriteFileSync(sessionPointersPath(root, runId), serialize(record));
|
|
125
124
|
return true;
|
|
126
125
|
} catch (error) {
|
|
127
126
|
console.error(`perk: warning: could not record session pointer (${klass}.${site}): ${error}`);
|
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
//
|
|
3
3
|
// pi-ai has no dedicated JSON-mode; structured output is done via tool calling. This module wraps
|
|
4
4
|
// that idiom into two pure, dependency-light, NEVER-throwing helpers:
|
|
5
|
-
// - `resolveModelAuth(ctx)` reuses the session's configured + authenticated model (the
|
|
6
|
-
// `ModelRegistry.getApiKeyAndHeaders` path
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// - `resolveModelAuth(ctx)` reuses the session's configured + authenticated model (the compat
|
|
6
|
+
// `ModelRegistry.getApiKeyAndHeaders` path — the fallback for hosts without registry
|
|
7
|
+
// dispatch), and
|
|
8
|
+
// - `completeStructured(opts)` builds a single-tool `Context`, completes it (via the injected
|
|
9
|
+
// registry `dispatch` when the host provides one, else the compat `complete`), and validates
|
|
10
|
+
// the returned tool-call arguments against a TypeBox schema.
|
|
9
11
|
// Both report failure via a soft `{ ok:false, error }` outcome — no throws ever reach the caller, so
|
|
10
12
|
// every consumer can stay fail-safe with a deterministic fallback. The first consumer is
|
|
11
13
|
// `extension/factories/planTitle.ts` (LLM-generated plan-issue titles).
|
|
12
14
|
|
|
13
15
|
import {
|
|
14
16
|
type Api,
|
|
17
|
+
type AssistantMessage,
|
|
15
18
|
type Context,
|
|
16
19
|
type Model,
|
|
17
20
|
type Static,
|
|
@@ -24,21 +27,54 @@ import {
|
|
|
24
27
|
// keeps the types. Pi's extension loader aliases both the root and /compat to the compat entry.
|
|
25
28
|
import { complete } from "@earendil-works/pi-ai/compat";
|
|
26
29
|
|
|
27
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Registry dispatch (mirrors pi ≥ 0.84's `ModelRegistry.complete`): pi owns final request
|
|
32
|
+
* assembly — resolved auth, nullable headers, credential-resolved `baseUrl`, provider `env` —
|
|
33
|
+
* end to end. Feature-detect it (`typeof … === "function"`); absent on older hosts.
|
|
34
|
+
*/
|
|
35
|
+
export type ModelDispatch = (
|
|
36
|
+
model: Model<Api>,
|
|
37
|
+
context: Context,
|
|
38
|
+
options: { signal?: AbortSignal; timeoutMs?: number },
|
|
39
|
+
) => Promise<AssistantMessage>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Structurally-minimal slice of `ExtensionContext` needed to reuse the session's model + auth.
|
|
43
|
+
* Header values mirror pi-ai's `ProviderHeaders` (`string | null` — null is a header-deletion
|
|
44
|
+
* marker); `baseUrl`/`env` mirror pi 0.84's `ResolvedRequestAuth`.
|
|
45
|
+
*/
|
|
28
46
|
export interface ModelAuthContext {
|
|
29
47
|
model: Model<Api> | undefined;
|
|
30
48
|
modelRegistry: {
|
|
31
|
-
getApiKeyAndHeaders(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
getApiKeyAndHeaders(model: Model<Api>): Promise<
|
|
50
|
+
| {
|
|
51
|
+
ok: true;
|
|
52
|
+
apiKey?: string;
|
|
53
|
+
headers?: Record<string, string | null>;
|
|
54
|
+
baseUrl?: string;
|
|
55
|
+
env?: Record<string, string>;
|
|
56
|
+
}
|
|
57
|
+
| { ok: false; error: string }
|
|
35
58
|
>;
|
|
59
|
+
/** pi ≥ 0.84 registry dispatch; absent on older hosts (feature-detected, never assumed). */
|
|
60
|
+
complete?(
|
|
61
|
+
model: Model<Api>,
|
|
62
|
+
context: Context,
|
|
63
|
+
options?: { signal?: AbortSignal; timeoutMs?: number },
|
|
64
|
+
): Promise<AssistantMessage>;
|
|
36
65
|
};
|
|
37
66
|
}
|
|
38
67
|
|
|
39
68
|
/** Resolved model + auth, or a soft failure (no model / unresolved auth). */
|
|
40
69
|
export type ResolvedModelAuth =
|
|
41
|
-
| {
|
|
70
|
+
| {
|
|
71
|
+
ok: true;
|
|
72
|
+
model: Model<Api>;
|
|
73
|
+
apiKey?: string;
|
|
74
|
+
headers?: Record<string, string | null>;
|
|
75
|
+
baseUrl?: string;
|
|
76
|
+
env?: Record<string, string>;
|
|
77
|
+
}
|
|
42
78
|
| { ok: false; error: string };
|
|
43
79
|
|
|
44
80
|
/** The generic structured-output outcome — soft success/failure, never a throw. */
|
|
@@ -60,7 +96,14 @@ export async function resolveModelAuth(ctx: ModelAuthContext): Promise<ResolvedM
|
|
|
60
96
|
try {
|
|
61
97
|
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
62
98
|
if (!auth.ok) return { ok: false, error: auth.error };
|
|
63
|
-
return {
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
model,
|
|
102
|
+
apiKey: auth.apiKey,
|
|
103
|
+
headers: auth.headers,
|
|
104
|
+
baseUrl: auth.baseUrl,
|
|
105
|
+
env: auth.env,
|
|
106
|
+
};
|
|
64
107
|
} catch (err) {
|
|
65
108
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
66
109
|
}
|
|
@@ -79,8 +122,17 @@ export interface CompleteStructuredOptions<S extends TSchema> {
|
|
|
79
122
|
instruction: string;
|
|
80
123
|
/** The payload (e.g. the document to summarize/classify). */
|
|
81
124
|
input: string;
|
|
125
|
+
/**
|
|
126
|
+
* Registry dispatch (pi ≥ 0.84). When present it REPLACES the compat `complete` +
|
|
127
|
+
* apiKey/headers assembly below — pi owns auth end to end, including the credential-resolved
|
|
128
|
+
* `baseUrl` the fallback path cannot carry.
|
|
129
|
+
*/
|
|
130
|
+
dispatch?: ModelDispatch;
|
|
82
131
|
apiKey?: string;
|
|
83
|
-
|
|
132
|
+
/** `string | null` mirrors pi-ai's `ProviderHeaders` — a null value deletes a default header. */
|
|
133
|
+
headers?: Record<string, string | null>;
|
|
134
|
+
/** Provider-scoped environment values (pi 0.84 `ResolvedRequestAuth.env`), fallback path only. */
|
|
135
|
+
env?: Record<string, string>;
|
|
84
136
|
signal?: AbortSignal;
|
|
85
137
|
timeoutMs?: number;
|
|
86
138
|
}
|
|
@@ -114,14 +166,21 @@ export async function completeStructured<S extends TSchema>(
|
|
|
114
166
|
tools: [tool],
|
|
115
167
|
};
|
|
116
168
|
|
|
117
|
-
|
|
169
|
+
// Primary: registry dispatch (pi ≥ 0.84 owns auth/headers/baseUrl/env). Fallback: the compat
|
|
170
|
+
// `complete` with caller-resolved auth — it forwards apiKey/headers/env but has NO `baseUrl`
|
|
171
|
+
// option, so a credential-resolved endpoint is silently dropped on old hosts (the fallback's
|
|
172
|
+
// named, pre-existing limitation; the dispatch path is the fix).
|
|
173
|
+
let msg: AssistantMessage;
|
|
118
174
|
try {
|
|
119
|
-
msg =
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
175
|
+
msg = opts.dispatch
|
|
176
|
+
? await opts.dispatch(opts.model, context, { signal: opts.signal, timeoutMs: opts.timeoutMs })
|
|
177
|
+
: await complete(opts.model, context, {
|
|
178
|
+
apiKey: opts.apiKey,
|
|
179
|
+
headers: opts.headers,
|
|
180
|
+
env: opts.env,
|
|
181
|
+
signal: opts.signal,
|
|
182
|
+
timeoutMs: opts.timeoutMs,
|
|
183
|
+
});
|
|
125
184
|
} catch (err) {
|
|
126
185
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
127
186
|
}
|
|
@@ -89,8 +89,9 @@ export const LINEAR_MUTATING_TOOLS: readonly string[] = [
|
|
|
89
89
|
* (≈830 schema chars — accepted, documented, test-pinned). A later `session_tree` re-apply
|
|
90
90
|
* filters over the original snapshot (which lacks the late names), so a tree navigation drops
|
|
91
91
|
* them — the pre-existing snapshot behavior, unchanged. Child-side tools (`contact_supervisor`,
|
|
92
|
-
* `structured_output`) are out of scope
|
|
93
|
-
* adopt-never-impersonates)
|
|
92
|
+
* `structured_output`) are out of scope for the STAGE census — spawned children stay
|
|
93
|
+
* stage-unscoped by design (§8.40 adopt-never-impersonates) — but they DO ride READ_ONLY_TOOLS,
|
|
94
|
+
* because the read-only gate IS inherited by adopted children (see SUBAGENT_CHILD_TOOLS).
|
|
94
95
|
*/
|
|
95
96
|
export const SUBAGENT_TOOLS: readonly string[] = [
|
|
96
97
|
"subagent",
|
|
@@ -99,6 +100,31 @@ export const SUBAGENT_TOOLS: readonly string[] = [
|
|
|
99
100
|
"intercom",
|
|
100
101
|
];
|
|
101
102
|
|
|
103
|
+
/**
|
|
104
|
+
* pi-subagents' CHILD-side engine tools. `structured_output` and `contact_supervisor` register
|
|
105
|
+
* only inside spawned child sessions (the env-keyed prompt-runtime registration — never in
|
|
106
|
+
* parents, so those names are inert in every gated parent session; `setActiveTools` ignores
|
|
107
|
+
* unknown names). `subagent_wait` is ALSO registered by the top-level parent extension
|
|
108
|
+
* (pi-subagents 0.45.1's `registerWaitTool`) — the accepted widening: a wait-only,
|
|
109
|
+
* non-repo-mutating tool active in gated parents. A gated ADOPTED child (mode inherited via the
|
|
110
|
+
* `adopt` arm, contracts.md §8.3) must keep them active:
|
|
111
|
+
* - `structured_output` is the engine-REQUIRED completion call when the launch carries an
|
|
112
|
+
* `outputSchema` — stripping it makes the child physically unable to finish and fails the
|
|
113
|
+
* run with `structuredOutputFailed`;
|
|
114
|
+
* - `contact_supervisor` is the child→parent intercom door;
|
|
115
|
+
* - `subagent_wait` is the fanout-child wait door.
|
|
116
|
+
* None mutates the repo (`structured_output` writes only the engine's capture file under
|
|
117
|
+
* `.pi-subagents/` scratch). Census decision, recorded: these names deliberately join NEITHER
|
|
118
|
+
* PERK_TOOLS nor BORROWED_TOOLS — the stage-filter universe never sees them because children
|
|
119
|
+
* are stage-unscoped by design (adopt never impersonates a stage), so gate membership is their
|
|
120
|
+
* only governance surface.
|
|
121
|
+
*/
|
|
122
|
+
export const SUBAGENT_CHILD_TOOLS: readonly string[] = [
|
|
123
|
+
"structured_output",
|
|
124
|
+
"contact_supervisor",
|
|
125
|
+
"subagent_wait",
|
|
126
|
+
];
|
|
127
|
+
|
|
102
128
|
/**
|
|
103
129
|
* @ff-labs/pi-fff's search tools. BOTH mode name-sets are enumerated (static names, inert
|
|
104
130
|
* when absent — the code_search version-tolerance precedent): warm sessions run pi-fff's
|
|
@@ -131,9 +157,12 @@ export const FFF_SEARCH_TOOLS: readonly string[] = [
|
|
|
131
157
|
* stage set over a foreign restriction. Pre-existing interplay, recorded, not re-engineered.
|
|
132
158
|
* - Zero-tool packages: @tombell/pi-diff (commands only), the footer providers, and the hunk
|
|
133
159
|
* review CLI (not a Pi package) register nothing — nothing to enumerate.
|
|
134
|
-
* - Single-governance rule:
|
|
135
|
-
*
|
|
136
|
-
* name
|
|
160
|
+
* - Single-governance rule: a name is governed ONCE — it lives in exactly one census. perk
|
|
161
|
+
* registers no same-named `ask_user_question` anymore (the first-party tool is deleted), so
|
|
162
|
+
* the name lives HERE, in the borrowed census, not in PERK_TOOLS (hygiene-tested).
|
|
163
|
+
* Registration timing nuance: @juicesharp/rpiv-ask-user-question registers the tool at load
|
|
164
|
+
* time, then a `hasUI`-keyed reconcile strips/restores it — headless sessions carry no
|
|
165
|
+
* `ask_user_question` schema at all.
|
|
137
166
|
* - @ff-labs/pi-fff (FFF_SEARCH_TOOLS): registration timing load-time (both modes); no
|
|
138
167
|
* `setFooter` (only a keyed optional-chained `setStatus`); zero bundled skills.
|
|
139
168
|
*/
|
|
@@ -143,7 +172,12 @@ export const BORROWED_TOOLS: readonly string[] = [
|
|
|
143
172
|
...LINEAR_MUTATING_TOOLS,
|
|
144
173
|
...SUBAGENT_TOOLS,
|
|
145
174
|
...FFF_SEARCH_TOOLS,
|
|
146
|
-
|
|
175
|
+
// @juicesharp/rpiv-todo (required borrow) — registers at load; its checklist overlay is
|
|
176
|
+
// `hasUI`-gated (headless-safe).
|
|
177
|
+
"todo",
|
|
178
|
+
// @juicesharp/rpiv-ask-user-question (required borrow) — registers at load; strips itself
|
|
179
|
+
// headlessly (!hasUI reconcile).
|
|
180
|
+
"ask_user_question",
|
|
147
181
|
// @plannotator/pi-extension: perk never drives its plan phases (the adapter bridges
|
|
148
182
|
// `plan_review` to its event API), so the submit tool is dead weight in stage sessions.
|
|
149
183
|
"plannotator_submit_plan",
|
|
@@ -189,23 +223,60 @@ export const READ_ONLY_TOOLS = [
|
|
|
189
223
|
// FFF local search belongs in read-only exploration (the override names find/grep are
|
|
190
224
|
// already present above; these are the additive tools-and-ui names + multi_grep).
|
|
191
225
|
...FFF_SEARCH_TOOLS,
|
|
192
|
-
// The delegation carve-in: the
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
// children are unscoped by design (§8.40
|
|
198
|
-
//
|
|
199
|
-
// agents/objective-explorer.md), but the `subagent` tool itself can spawn ad-hoc read-write
|
|
226
|
+
// The delegation carve-in: `subagent`/`wait` (+ the parent supervisor pair, which already
|
|
227
|
+
// leaks active into cold-door gated sessions via late registration — keeping warm-entered
|
|
228
|
+
// gates consistent, and letting the parent answer child `contact_supervisor` asks) stay
|
|
229
|
+
// reachable while gated for the other delegation flows (the gated objective-plan guidance now
|
|
230
|
+
// names the `explore_objective_node` tool below, not a direct spawn). ACCEPTED LENIENCY,
|
|
231
|
+
// deliberately documented: spawned children are unscoped by design (§8.40
|
|
232
|
+
// adopt-never-impersonates), and the `subagent` tool itself can spawn ad-hoc read-write
|
|
200
233
|
// children — a posture choice with NO agent-allowlist backstop, consistent with the arg-blind
|
|
201
234
|
// `curl`/`agent-browser` precedents (contracts.md §8.3).
|
|
202
235
|
...SUBAGENT_TOOLS,
|
|
236
|
+
// The explorer-wave carve-in: the gated objective-plan session's OPTIONAL explore step is the
|
|
237
|
+
// `explore_objective_node` tool — it spawns the read-only `perk.objective-explorer` child over
|
|
238
|
+
// the already-carved-in SUBAGENT tools (the draft-review-wave precedent) and writes nothing to
|
|
239
|
+
// the worktree.
|
|
240
|
+
"explore_objective_node",
|
|
241
|
+
// The child-side carve-in: gated adopt-children must keep the engine's injected tools — see
|
|
242
|
+
// SUBAGENT_CHILD_TOOLS.
|
|
243
|
+
...SUBAGENT_CHILD_TOOLS,
|
|
244
|
+
// The draft-review-door carve-in: plan-authoring sessions run GATED, so the
|
|
245
|
+
// /plan-review-browser companions must be reachable while read-only. `push_annotations` only
|
|
246
|
+
// POSTs findings to the door-primed local plannotator server (no worktree writes — the
|
|
247
|
+
// fetch_content cache-write precedent class); the wave pair spawns the read-only
|
|
248
|
+
// `perk.draft-reviewer` over the already-carved-in SUBAGENT_TOOLS/SUBAGENT_CHILD_TOOLS.
|
|
249
|
+
"push_annotations",
|
|
250
|
+
"start_draft_review_wave",
|
|
251
|
+
"collect_draft_review_wave",
|
|
252
|
+
// The audit-wave carve-in: the seeded `perk-dev audit judge` session runs GATED (the `audit`
|
|
253
|
+
// stage is read-only), so `run_audit_wave` must be reachable while read-only. Its one write
|
|
254
|
+
// (`<bundle>/verdicts.json`) is structurally bound to the cold door's workflow-state
|
|
255
|
+
// `audit_bundle_dir` — the tool takes NO parameters, so no caller-supplied path exists and a
|
|
256
|
+
// gated session cannot aim the writer anywhere (contracts.md §8.50).
|
|
257
|
+
"run_audit_wave",
|
|
258
|
+
// The harvest-wave carve-in: the seeded learn-harvest session runs GATED (the read-only
|
|
259
|
+
// objective-author borrow), so `run_harvest_wave` must be reachable while read-only. Its
|
|
260
|
+
// manifest read is structurally bound to the session's claimed run-scoped scratch path (the
|
|
261
|
+
// `manifest_path` param is verified against it and any other path refused — the
|
|
262
|
+
// `run_audit_wave` no-aimable-writer posture, read-side), it spawns the read-only
|
|
263
|
+
// `perk.harvest-analyst` over the already-carved-in SUBAGENT_TOOLS/SUBAGENT_CHILD_TOOLS, and
|
|
264
|
+
// it writes nothing to the worktree (contracts.md §8.48).
|
|
265
|
+
"run_harvest_wave",
|
|
266
|
+
// The dream-wave carve-in: the seeded `perk learn dream` session runs GATED (the read-only
|
|
267
|
+
// objective-author borrow), so `run_dream_wave` must be reachable while read-only. The tool
|
|
268
|
+
// takes NO parameters: its manifest read AND its one write (the fixed-name run-scratch
|
|
269
|
+
// bundle beside that manifest) are both derived from the claimed run's manifest path — no
|
|
270
|
+
// caller-supplied path exists (the `run_audit_wave` no-aimable-writer posture, BOTH sides),
|
|
271
|
+
// and it spawns only the read-only `perk.dream-analyst`/`perk.dream-reducer` over the
|
|
272
|
+
// already-carved-in delegation family (contracts.md §8.61).
|
|
273
|
+
"run_dream_wave",
|
|
203
274
|
];
|
|
204
275
|
|
|
205
276
|
/**
|
|
206
277
|
* Every tool perk itself registers (contracts.md §8.40). Name-keyed: `setActiveTools` ignores
|
|
207
|
-
* unknown names, so
|
|
208
|
-
*
|
|
278
|
+
* unknown names, so an absent tool is inert (e.g. a borrowed census name whose package stripped
|
|
279
|
+
* or never registered it — `ask_user_question` in a headless session — has nothing to enable).
|
|
209
280
|
* Stage scoping filters the scoped universe `PERK_TOOLS ∪ BORROWED_TOOLS` — builtins and
|
|
210
281
|
* un-enumerated foreign names pass through untouched (fail-open).
|
|
211
282
|
*/
|
|
@@ -222,16 +293,34 @@ export const PERK_TOOLS: readonly string[] = [
|
|
|
222
293
|
"gist_save",
|
|
223
294
|
"learn",
|
|
224
295
|
"run_learn_wave",
|
|
225
|
-
"
|
|
296
|
+
"run_audit_wave",
|
|
297
|
+
"run_harvest_wave",
|
|
298
|
+
"run_dream_wave",
|
|
226
299
|
"land",
|
|
227
300
|
"post_pr_review",
|
|
228
301
|
"ready",
|
|
229
|
-
"
|
|
302
|
+
"classify_review_feedback",
|
|
303
|
+
"finalize_address",
|
|
304
|
+
"explore_objective_node",
|
|
230
305
|
"run_pr_review_wave",
|
|
231
306
|
"run_pr_review_dynamic_wave",
|
|
232
307
|
"submit_pr_review",
|
|
308
|
+
"start_review_wave",
|
|
309
|
+
"collect_review_wave",
|
|
310
|
+
"push_annotations",
|
|
311
|
+
"start_draft_review_wave",
|
|
312
|
+
"collect_draft_review_wave",
|
|
233
313
|
"run_ci",
|
|
234
314
|
"submit",
|
|
315
|
+
// The stacked-delivery warm surface (contracts.md §8.51/§8.56): read + control tools over
|
|
316
|
+
// the cold `objective stack` workers. Never in READ_ONLY_TOOLS — sync/adopt/recover/land
|
|
317
|
+
// mutate published branches and PRs; the gated posture is the driving commands' soft
|
|
318
|
+
// refusal.
|
|
319
|
+
"objective_stack_status",
|
|
320
|
+
"objective_stack_sync",
|
|
321
|
+
"objective_stack_adopt",
|
|
322
|
+
"objective_stack_recover",
|
|
323
|
+
"objective_stack_land",
|
|
235
324
|
];
|
|
236
325
|
|
|
237
326
|
/**
|
|
@@ -253,7 +342,7 @@ const RESEARCH_TOOLS: readonly string[] = [
|
|
|
253
342
|
* the post-land reconcile drive — `/land` auto-drives `/objective-reconcile` in-session, whose
|
|
254
343
|
* guidance names the reconcile trio, so the trio must be active in every worktree stage). The
|
|
255
344
|
* headless worker also REQUIRES the model-invoked `submit` (implement) /
|
|
256
|
-
* `
|
|
345
|
+
* `finalize_address` (address) to reach its completion bar. Borrowed additions: delegation
|
|
257
346
|
* (SUBAGENT_TOOLS — the `/pr-review`/`/address`/`/submit`-conflict/`/learn` orchestration flows)
|
|
258
347
|
* and `todo` (the foreign checklist overlay the implement-progress discipline rides) are
|
|
259
348
|
* worktree-family only.
|
|
@@ -266,17 +355,34 @@ const WORKTREE_STAGE_TOOLS: readonly string[] = [
|
|
|
266
355
|
"land",
|
|
267
356
|
"learn",
|
|
268
357
|
"run_learn_wave",
|
|
269
|
-
"
|
|
358
|
+
"classify_review_feedback",
|
|
359
|
+
"finalize_address",
|
|
270
360
|
"post_pr_review",
|
|
271
361
|
"run_pr_review_wave",
|
|
272
362
|
"run_pr_review_dynamic_wave",
|
|
273
363
|
"submit_pr_review",
|
|
364
|
+
// The human review doors' companion tools (/pr-review-terminal, /pr-review-browser): the
|
|
365
|
+
// review-wave pair + the door-primed annotation push. The plan-stage widening landed via the
|
|
366
|
+
// draft-review door (/plan-review-browser): the plan-family stage lists carry the draft-wave
|
|
367
|
+
// pair + push_annotations.
|
|
368
|
+
"start_review_wave",
|
|
369
|
+
"collect_review_wave",
|
|
370
|
+
"push_annotations",
|
|
274
371
|
// The reconcile trio: `/land` auto-drives the objective-reconcile pass inside the CURRENT
|
|
275
372
|
// worktree session (driveReconcileAfterLand), and the manual `/objective-reconcile` gesture is
|
|
276
373
|
// registered globally — both inject guidance naming these three tools.
|
|
277
374
|
"reconcile_objective",
|
|
278
375
|
"add_objective_node",
|
|
279
376
|
"objective_node",
|
|
377
|
+
// The stacked-delivery quintet: `/objective-sync`/`/objective-recover`/`/objective-land`
|
|
378
|
+
// drive worktree sessions (post-amend sync from implement/address; recovery and the atomic
|
|
379
|
+
// landing from anywhere in the PR loop), so their guidance-named tools must be active
|
|
380
|
+
// across the whole family.
|
|
381
|
+
"objective_stack_status",
|
|
382
|
+
"objective_stack_sync",
|
|
383
|
+
"objective_stack_adopt",
|
|
384
|
+
"objective_stack_recover",
|
|
385
|
+
"objective_stack_land",
|
|
280
386
|
...RESEARCH_TOOLS,
|
|
281
387
|
...SUBAGENT_TOOLS,
|
|
282
388
|
"todo",
|
|
@@ -286,7 +392,8 @@ const WORKTREE_STAGE_TOOLS: readonly string[] = [
|
|
|
286
392
|
* Per-stage active perk tools for gate-OFF sessions (contracts.md §8.40). Keys = the registry
|
|
287
393
|
* stage ids; an unknown/absent stage id is fail-open (no filtering — version-skew safety).
|
|
288
394
|
* Rationale pins:
|
|
289
|
-
* - `ask_user_question` is universal (every stage list carries it)
|
|
395
|
+
* - `ask_user_question` is universal (every stage list carries it); the name is BORROWED now
|
|
396
|
+
* (the @juicesharp questionnaire, via BORROWED_TOOLS — headless sessions carry no schema).
|
|
290
397
|
* - `plan`/`save` cover the plan-family stage borrowers (`plan from`/`plan replan`/
|
|
291
398
|
* `learn docs`/`learn code` borrow `plan`; `skills create/refine` borrow `save`).
|
|
292
399
|
* - `objective-author`/`objective-save` cover `objective replan` + `objective author --from`.
|
|
@@ -296,6 +403,12 @@ const WORKTREE_STAGE_TOOLS: readonly string[] = [
|
|
|
296
403
|
* three objective stages (the post-save `/objective-reconcile` gesture) AND the worktree
|
|
297
404
|
* family (the post-land `driveReconcileAfterLand` drive + the manual `/objective-reconcile`
|
|
298
405
|
* gesture — its guidance names all three).
|
|
406
|
+
* - the draft-review companions (`start_draft_review_wave`/`collect_draft_review_wave`/
|
|
407
|
+
* `push_annotations`) also ride the two objective stages (§8.23's
|
|
408
|
+
* `/objective-review-browser` — gate-OFF coverage: after `objectiveApprovalSave` exits the
|
|
409
|
+
* gate mid-flow, late collects/pushes must not dead-end), and `plan_review` rides them
|
|
410
|
+
* because the door guidance names it (in both objective stages it routes to the objective
|
|
411
|
+
* review arm; the drive-coverage guard forces both the moment the guidance names them).
|
|
299
412
|
*/
|
|
300
413
|
export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
|
|
301
414
|
"gist-author": ["ask_user_question", "gist_draft", "gist_save", ...RESEARCH_TOOLS],
|
|
@@ -307,6 +420,13 @@ export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
|
|
|
307
420
|
"reconcile_objective",
|
|
308
421
|
"add_objective_node",
|
|
309
422
|
"objective_node",
|
|
423
|
+
// The /objective-review-browser companions (gate-OFF coverage: after objectiveApprovalSave
|
|
424
|
+
// exits the gate mid-flow, late collects/pushes must not dead-end) + plan_review (the door
|
|
425
|
+
// guidance names it; it routes to the objective review arm here).
|
|
426
|
+
"start_draft_review_wave",
|
|
427
|
+
"collect_draft_review_wave",
|
|
428
|
+
"push_annotations",
|
|
429
|
+
"plan_review",
|
|
310
430
|
...RESEARCH_TOOLS,
|
|
311
431
|
],
|
|
312
432
|
"objective-save": [
|
|
@@ -316,6 +436,11 @@ export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
|
|
|
316
436
|
"reconcile_objective",
|
|
317
437
|
"add_objective_node",
|
|
318
438
|
"objective_node",
|
|
439
|
+
// The /objective-review-browser companions + plan_review (see the objective-author note).
|
|
440
|
+
"start_draft_review_wave",
|
|
441
|
+
"collect_draft_review_wave",
|
|
442
|
+
"push_annotations",
|
|
443
|
+
"plan_review",
|
|
319
444
|
...RESEARCH_TOOLS,
|
|
320
445
|
],
|
|
321
446
|
"objective-plan": [
|
|
@@ -324,17 +449,48 @@ export const STAGE_TOOLS: Readonly<Record<string, readonly string[]>> = {
|
|
|
324
449
|
"plan_review",
|
|
325
450
|
"plan_save",
|
|
326
451
|
"objective_node",
|
|
452
|
+
"explore_objective_node",
|
|
327
453
|
"reconcile_objective",
|
|
328
454
|
"add_objective_node",
|
|
455
|
+
// The /plan-review-browser companions (gate-OFF coverage: after approvalSave exits the gate
|
|
456
|
+
// mid-flow, late collects/pushes must not dead-end — the drive-coverage guard forces this
|
|
457
|
+
// the moment the guidance names them).
|
|
458
|
+
"start_draft_review_wave",
|
|
459
|
+
"collect_draft_review_wave",
|
|
460
|
+
"push_annotations",
|
|
461
|
+
...RESEARCH_TOOLS,
|
|
462
|
+
],
|
|
463
|
+
plan: [
|
|
464
|
+
"ask_user_question",
|
|
465
|
+
"plan_draft",
|
|
466
|
+
"plan_review",
|
|
467
|
+
"plan_save",
|
|
468
|
+
// The /plan-review-browser companions (see the objective-plan note).
|
|
469
|
+
"start_draft_review_wave",
|
|
470
|
+
"collect_draft_review_wave",
|
|
471
|
+
"push_annotations",
|
|
472
|
+
...RESEARCH_TOOLS,
|
|
473
|
+
],
|
|
474
|
+
save: [
|
|
475
|
+
"ask_user_question",
|
|
476
|
+
"plan_draft",
|
|
477
|
+
"plan_review",
|
|
478
|
+
"plan_save",
|
|
479
|
+
// The /plan-review-browser companions (see the objective-plan note).
|
|
480
|
+
"start_draft_review_wave",
|
|
481
|
+
"collect_draft_review_wave",
|
|
482
|
+
"push_annotations",
|
|
329
483
|
...RESEARCH_TOOLS,
|
|
330
484
|
],
|
|
331
|
-
plan: ["ask_user_question", "plan_draft", "plan_review", "plan_save", ...RESEARCH_TOOLS],
|
|
332
|
-
save: ["ask_user_question", "plan_draft", "plan_review", "plan_save", ...RESEARCH_TOOLS],
|
|
333
485
|
implement: WORKTREE_STAGE_TOOLS,
|
|
334
486
|
submit: WORKTREE_STAGE_TOOLS,
|
|
335
487
|
address: WORKTREE_STAGE_TOOLS,
|
|
336
488
|
land: WORKTREE_STAGE_TOOLS,
|
|
337
489
|
learn: WORKTREE_STAGE_TOOLS,
|
|
490
|
+
// The dev-only session-audit orchestrator (`perk-dev audit judge`). The session runs GATED
|
|
491
|
+
// (read-only mode), where this list is inert; it exists for the keys≡registry pin and the
|
|
492
|
+
// defensive gate-off arm.
|
|
493
|
+
audit: ["ask_user_question", "run_audit_wave", ...RESEARCH_TOOLS],
|
|
338
494
|
};
|
|
339
495
|
|
|
340
496
|
/** The read-only marker / custom-message type injected into context while active. */
|