@akagilnc/pi-workflow-roles 0.1.2135 → 0.1.2146

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/compliance-transport.js +19 -24
  4. package/dist/doctor-contracts.js +10 -2
  5. package/dist/engine-detour-tool.js +5 -15
  6. package/dist/engine-detour.js +3 -11
  7. package/dist/engine-labor-fallback.js +129 -114
  8. package/dist/evidence-child-executor.js +3 -4
  9. package/dist/merger-contracts.js +9 -2
  10. package/dist/navigator-attendance.js +11 -4
  11. package/dist/package-contracts/judge-output.js +8 -1
  12. package/dist/package-contracts/reviewer-output.js +9 -1
  13. package/dist/package-contracts/terminating-tools.js +14 -5
  14. package/dist/public-cli/main.js +123 -125
  15. package/package.json +1 -1
  16. package/resources/engines/codex.md +3 -4
  17. package/resources/engines/grok-4.6.md +5 -6
  18. package/resources/engines/kimi.md +2 -2
  19. package/resources/engines/opus.md +2 -2
  20. package/scripts/build-package.mjs +2 -0
  21. package/src/collector-role.ts +5 -33
  22. package/src/compliance-transport.ts +19 -24
  23. package/src/doctor-contracts.ts +19 -3
  24. package/src/engine-detour-tool.ts +6 -21
  25. package/src/engine-detour.ts +3 -15
  26. package/src/engine-labor-fallback.ts +100 -2
  27. package/src/evidence-child-executor.ts +3 -4
  28. package/src/factory-board.ts +6 -2
  29. package/src/merger-contracts.ts +18 -3
  30. package/src/navigator-attendance.ts +18 -4
  31. package/src/package-contracts/judge-output.ts +25 -2
  32. package/src/package-contracts/reviewer-output.ts +23 -2
  33. package/src/package-contracts/terminating-tools.ts +22 -6
  34. package/src/package-contracts/worker-output.ts +10 -2
  35. package/src/public-cli/settlement.ts +51 -17
  36. package/src/role-runtime.ts +8 -4
  37. package/src/taishi-metric-families/acceptance-success-rework.ts +6 -3
  38. package/dist/package-owned-tool-idle.js +0 -223
  39. package/src/package-owned-tool-idle.ts +0 -257
@@ -1,257 +0,0 @@
1
- /**
2
- * #102 package-owned tool idle backstop.
3
- *
4
- * Fixed 183000ms silence clock on package-owned tool execute only.
5
- * Real producing onUpdate resets; final resolve/reject clears; timeout throws so
6
- * Pi settles the current call as an LLM-visible isError tool result. No retry,
7
- * role failure, process termination, config, or Pi built-in coverage.
8
- *
9
- * #339: do not name-exempt whole terminating tools. Outer idle stays armed for
10
- * pre/post-audit work. Only the real compliance-audit await suspends this single
11
- * layer (ADR 0059 owns that interval); resume re-arms the same outer backstop.
12
- *
13
- * #380: on idle, abort a derived tool signal (not the caller signal) so detour
14
- * spawn cleanup and softFail can run through the existing AbortSignal path.
15
- * Cooperative soft-settle may win; non-listeners still hard-reject after a
16
- * microtask drain (no second timer).
17
- */
18
- import { AsyncLocalStorage } from "node:async_hooks";
19
- import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
20
-
21
- import {
22
- DEFAULT_STREAM_IDLE_TIMEOUT_MS,
23
- createStreamIdleGuard,
24
- type StreamIdleGuard,
25
- } from "./stream-idle-guard.ts";
26
- import { isProducingToolUpdate } from "./tool-execution-observation.ts";
27
-
28
- export const PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_MS = DEFAULT_STREAM_IDLE_TIMEOUT_MS;
29
- export const PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_CODE = "AK_PACKAGE_OWNED_TOOL_IDLE_TIMEOUT" as const;
30
-
31
- const WRAPPED = Symbol.for("ak.packageOwnedToolIdleWrapped");
32
-
33
- type PackageOwnedToolIdleSuspension = {
34
- suspend(): void;
35
- resume(): void;
36
- /** Reset the silence window (byte/activity signal from the active execute). */
37
- poke(): void;
38
- };
39
-
40
- /**
41
- * Active outer package-owned execute idle, if any. Nested tool executes install
42
- * their own store; compliance audit only suspends the store visible at await time.
43
- */
44
- const packageOwnedToolIdleScope = new AsyncLocalStorage<PackageOwnedToolIdleSuspension>();
45
-
46
- export class PackageOwnedToolIdleTimeoutError extends Error {
47
- readonly code = PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_CODE;
48
- readonly idleTimeoutMs = PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_MS;
49
-
50
- constructor() {
51
- super(`package-owned tool idle timeout after ${PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_MS}ms`);
52
- this.name = "PackageOwnedToolIdleTimeoutError";
53
- }
54
- }
55
-
56
- export function isPackageOwnedToolIdleTimeoutError(
57
- value: unknown,
58
- ): value is PackageOwnedToolIdleTimeoutError {
59
- return (
60
- value instanceof PackageOwnedToolIdleTimeoutError ||
61
- (
62
- typeof value === "object" &&
63
- value !== null &&
64
- (value as { name?: unknown }).name === "PackageOwnedToolIdleTimeoutError" &&
65
- (value as { code?: unknown }).code === PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_CODE
66
- )
67
- );
68
- }
69
-
70
- /** Minimal executable tool shape accepted by the shared idle wrapper. */
71
- export type PackageOwnedToolLike = {
72
- readonly name: string;
73
- execute: (...args: never[]) => Promise<unknown>;
74
- };
75
-
76
- /**
77
- * Package-tool activity includes content production and host-only details
78
- * progress. Keep the observation-plane oracle separate: its stderr heartbeat
79
- * contract remains content-driven. Pi's known execute-entry placeholder
80
- * (`content: [], details: undefined`) is not activity.
81
- */
82
- function isPackageOwnedToolActivityUpdate(partialResult: unknown): boolean {
83
- if (isProducingToolUpdate(partialResult)) return true;
84
- if (typeof partialResult !== "object" || partialResult === null) return false;
85
- const details = (partialResult as { details?: unknown }).details;
86
- if (details === undefined || details === null) return false;
87
- if (typeof details === "string") return details.length > 0;
88
- if (Array.isArray(details)) return details.length > 0;
89
- if (typeof details === "object") return Reflect.ownKeys(details).length > 0;
90
- return true;
91
- }
92
-
93
- /**
94
- * #339: suspend the active package-owned execute idle for one real compliance
95
- * audit await. Single-layer only — production has one runComplianceAudit seam.
96
- * No-op outside a wrapped package-owned execute. No second timeout or retry.
97
- */
98
- export async function withPackageOwnedToolIdleSuspended<T>(
99
- run: () => Promise<T>,
100
- ): Promise<T> {
101
- const scope = packageOwnedToolIdleScope.getStore();
102
- if (scope === undefined) return run();
103
- scope.suspend();
104
- try {
105
- return await run();
106
- } finally {
107
- scope.resume();
108
- }
109
- }
110
-
111
- /**
112
- * Touch the active package-owned execute idle clock (reuse stream-idle-guard poke).
113
- * No-op outside a wrapped package-owned execute or while that layer is suspended.
114
- * Used by long-running tools (engine detour) that see real subprocess output bytes.
115
- */
116
- export function pokePackageOwnedToolIdle(): void {
117
- packageOwnedToolIdleScope.getStore()?.poke();
118
- }
119
-
120
- /**
121
- * Single shared execute wrapper for package-owned tool definitions.
122
- * Idempotent: wrapping twice returns the same protected definition.
123
- */
124
- export function wrapPackageOwnedToolDefinition<T extends PackageOwnedToolLike>(tool: T): T {
125
- // Mark the execute function, not the tool object — callers may spread tool fields
126
- // onto a new definition with a different execute (e.g. auditor customTools).
127
- if ((tool.execute as { [WRAPPED]?: boolean })[WRAPPED] === true) return tool;
128
-
129
- const originalExecute = tool.execute.bind(tool) as (
130
- ...args: unknown[]
131
- ) => Promise<unknown>;
132
-
133
- const wrappedExecute = function packageOwnedToolIdleExecute(
134
- ...args: unknown[]
135
- ): Promise<unknown> {
136
- const parentSignal = args[2] as AbortSignal | undefined;
137
- const onUpdate = args[3] as ((partialResult: unknown) => void) | undefined;
138
- return new Promise((resolve, reject) => {
139
- let settled = false;
140
- let suspended = false;
141
- let idle: StreamIdleGuard = createStreamIdleGuard({
142
- idleTimeoutMs: PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_MS,
143
- });
144
-
145
- // Derived tool signal: caller cancel forwards; idle aborts this only (not parent).
146
- const toolController = new AbortController();
147
- const onParentAbort = (): void => {
148
- if (toolController.signal.aborted) return;
149
- toolController.abort(parentSignal?.reason);
150
- };
151
- if (parentSignal !== undefined) {
152
- if (parentSignal.aborted) {
153
- toolController.abort(parentSignal.reason);
154
- } else {
155
- parentSignal.addEventListener("abort", onParentAbort);
156
- }
157
- }
158
-
159
- const cleanup = (): void => {
160
- idle.signal.removeEventListener("abort", onIdle);
161
- idle.dispose();
162
- parentSignal?.removeEventListener("abort", onParentAbort);
163
- };
164
-
165
- const settle = (deliver: () => void): void => {
166
- if (settled) return;
167
- settled = true;
168
- cleanup();
169
- deliver();
170
- };
171
- const onIdle = (): void => {
172
- const idleError = new PackageOwnedToolIdleTimeoutError();
173
- if (!toolController.signal.aborted) {
174
- toolController.abort(idleError);
175
- }
176
- // Cooperative tools (detour) soft-settle via the aborted signal in the
177
- // next microtasks. Non-listeners still hard-reject after a short drain
178
- // of those microtasks — no second wall-clock timer.
179
- void Promise.resolve()
180
- .then(() => {})
181
- .then(() => {})
182
- .then(() => {
183
- settle(() => reject(idleError));
184
- });
185
- };
186
- idle.signal.addEventListener("abort", onIdle, { once: true });
187
-
188
- const suspension: PackageOwnedToolIdleSuspension = {
189
- suspend(): void {
190
- if (settled || suspended) return;
191
- suspended = true;
192
- // ADR 0059 owns the audit interval — drop this layer until audit returns.
193
- idle.signal.removeEventListener("abort", onIdle);
194
- idle.dispose();
195
- },
196
- resume(): void {
197
- if (settled || !suspended) return;
198
- suspended = false;
199
- // Fresh single-layer silence window for post-audit work (e.g. cleanup).
200
- idle = createStreamIdleGuard({
201
- idleTimeoutMs: PACKAGE_OWNED_TOOL_IDLE_TIMEOUT_MS,
202
- });
203
- idle.signal.addEventListener("abort", onIdle, { once: true });
204
- },
205
- poke(): void {
206
- if (settled || suspended) return;
207
- idle.poke();
208
- },
209
- };
210
-
211
- const guardedOnUpdate = onUpdate === undefined
212
- ? undefined
213
- : (partialResult: unknown) => {
214
- if (settled) return;
215
- if (isPackageOwnedToolActivityUpdate(partialResult)) idle.poke();
216
- onUpdate(partialResult);
217
- };
218
-
219
- const callArgs = args.slice();
220
- // Pass derived signal so idle/cancel can clean up subprocesses without
221
- // aborting the caller/parent agent signal identity.
222
- callArgs[2] = toolController.signal;
223
- callArgs[3] = guardedOnUpdate;
224
-
225
- void packageOwnedToolIdleScope.run(suspension, async () => {
226
- try {
227
- const result = await originalExecute(...callArgs);
228
- settle(() => resolve(result));
229
- } catch (error) {
230
- settle(() => reject(error));
231
- }
232
- });
233
- });
234
- };
235
- (wrappedExecute as { [WRAPPED]?: boolean })[WRAPPED] = true;
236
-
237
- return {
238
- ...tool,
239
- execute: wrappedExecute as T["execute"],
240
- };
241
- }
242
-
243
- /**
244
- * Install the shared registration surface on an ExtensionAPI once.
245
- * All subsequent pi.registerTool calls for package-owned tools are wrapped.
246
- */
247
- export function installPackageOwnedToolRegistration(pi: ExtensionAPI): void {
248
- const current = pi.registerTool;
249
- if ((current as { [WRAPPED]?: boolean })[WRAPPED] === true) return;
250
-
251
- const original = current.bind(pi);
252
- const installed = ((tool: ToolDefinition<any, any, any>) => {
253
- original(wrapPackageOwnedToolDefinition(tool) as ToolDefinition<any, any, any>);
254
- }) as typeof pi.registerTool;
255
- (installed as { [WRAPPED]?: boolean })[WRAPPED] = true;
256
- pi.registerTool = installed;
257
- }