@marcoscale98/pi-extensible-workflows 5.14.1-fork.1
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 +536 -0
- package/README.md +64 -0
- package/dist/src/agent-execution.d.ts +338 -0
- package/dist/src/agent-execution.js +1633 -0
- package/dist/src/background-widget.d.ts +74 -0
- package/dist/src/background-widget.js +1340 -0
- package/dist/src/budget.d.ts +38 -0
- package/dist/src/budget.js +188 -0
- package/dist/src/changelog.d.ts +6 -0
- package/dist/src/changelog.js +112 -0
- package/dist/src/decoders.d.ts +96 -0
- package/dist/src/decoders.js +629 -0
- package/dist/src/execution.d.ts +19 -0
- package/dist/src/execution.js +749 -0
- package/dist/src/herdr.d.ts +53 -0
- package/dist/src/herdr.js +270 -0
- package/dist/src/host-delivery.d.ts +95 -0
- package/dist/src/host-delivery.js +376 -0
- package/dist/src/host-navigator.d.ts +83 -0
- package/dist/src/host-navigator.js +1087 -0
- package/dist/src/host-phases.d.ts +89 -0
- package/dist/src/host-phases.js +320 -0
- package/dist/src/host-recovery.d.ts +141 -0
- package/dist/src/host-recovery.js +356 -0
- package/dist/src/host-runtime.d.ts +78 -0
- package/dist/src/host-runtime.js +378 -0
- package/dist/src/host-view.d.ts +116 -0
- package/dist/src/host-view.js +868 -0
- package/dist/src/host.d.ts +40 -0
- package/dist/src/host.js +1641 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.js +13725 -0
- package/dist/src/index.js.map +6 -0
- package/dist/src/io.d.ts +14 -0
- package/dist/src/io.js +82 -0
- package/dist/src/package-identity.d.ts +4 -0
- package/dist/src/package-identity.js +6 -0
- package/dist/src/paths.d.ts +14 -0
- package/dist/src/paths.js +51 -0
- package/dist/src/persistence.d.ts +5 -0
- package/dist/src/persistence.js +5 -0
- package/dist/src/pi-runtime-adapter.d.ts +27 -0
- package/dist/src/pi-runtime-adapter.js +243 -0
- package/dist/src/pi-runtime-runner.d.ts +42 -0
- package/dist/src/pi-runtime-runner.js +505 -0
- package/dist/src/registry.d.ts +48 -0
- package/dist/src/registry.js +379 -0
- package/dist/src/retention.d.ts +17 -0
- package/dist/src/retention.js +195 -0
- package/dist/src/runtime/agent-runner.d.ts +143 -0
- package/dist/src/runtime/agent-runner.js +12 -0
- package/dist/src/runtime/index.d.ts +2 -0
- package/dist/src/runtime/index.js +2 -0
- package/dist/src/runtime/namespace.d.ts +14 -0
- package/dist/src/runtime/namespace.js +1 -0
- package/dist/src/runtime/workflow-result.d.ts +2 -0
- package/dist/src/runtime/workflow-result.js +6 -0
- package/dist/src/session-handoff.d.ts +2 -0
- package/dist/src/session-handoff.js +82 -0
- package/dist/src/session-lease.d.ts +12 -0
- package/dist/src/session-lease.js +180 -0
- package/dist/src/store.d.ts +95 -0
- package/dist/src/store.js +951 -0
- package/dist/src/subagent-manager-handle.d.ts +4 -0
- package/dist/src/subagent-manager-handle.js +6 -0
- package/dist/src/tool-timing.d.ts +12 -0
- package/dist/src/tool-timing.js +33 -0
- package/dist/src/trajectory-contracts.d.ts +8 -0
- package/dist/src/trajectory-contracts.js +9 -0
- package/dist/src/trajectory-host-handle.d.ts +12 -0
- package/dist/src/trajectory-host-handle.js +6 -0
- package/dist/src/trajectory.d.ts +128 -0
- package/dist/src/trajectory.js +594 -0
- package/dist/src/types.d.ts +960 -0
- package/dist/src/types.js +60 -0
- package/dist/src/utils.d.ts +57 -0
- package/dist/src/utils.js +225 -0
- package/dist/src/validation.d.ts +29 -0
- package/dist/src/validation.js +1100 -0
- package/dist/src/workflow-artifacts.d.ts +14 -0
- package/dist/src/workflow-artifacts.js +40 -0
- package/dist/starter/index.d.ts +1 -0
- package/dist/starter/index.js +103 -0
- package/dist/starter/index.js.map +6 -0
- package/dist/starter/review-loop.d.ts +72 -0
- package/dist/starter/review-loop.js +43 -0
- package/dist/starter/roles/developer.md +6 -0
- package/dist/starter/roles/oracle.md +18 -0
- package/dist/starter/roles/researcher.md +20 -0
- package/dist/starter/roles/reviewer.md +19 -0
- package/dist/starter/roles/scout.md +18 -0
- package/dist/subagents/index.d.ts +8 -0
- package/dist/subagents/index.js +8021 -0
- package/dist/subagents/index.js.map +6 -0
- package/dist/subagents/src/contracts.d.ts +173 -0
- package/dist/subagents/src/contracts.js +68 -0
- package/dist/subagents/src/decode.d.ts +15 -0
- package/dist/subagents/src/decode.js +182 -0
- package/dist/subagents/src/index.d.ts +12 -0
- package/dist/subagents/src/index.js +180 -0
- package/dist/subagents/src/manager.d.ts +3 -0
- package/dist/subagents/src/manager.js +1636 -0
- package/dist/subagents/src/navigator.d.ts +5 -0
- package/dist/subagents/src/navigator.js +627 -0
- package/dist/subagents/src/view.d.ts +70 -0
- package/dist/subagents/src/view.js +387 -0
- package/dist/subagents/src/worktree.d.ts +34 -0
- package/dist/subagents/src/worktree.js +68 -0
- package/dist/trajectory/assets/favicon.png +0 -0
- package/dist/trajectory/assets/index.html +772 -0
- package/dist/trajectory/assets/marked.min.js +6 -0
- package/dist/trajectory/assets/morphdom.min.js +1 -0
- package/dist/trajectory/index.d.ts +5 -0
- package/dist/trajectory/index.js +3459 -0
- package/dist/trajectory/index.js.map +6 -0
- package/dist/trajectory/src/assets/favicon.png +0 -0
- package/dist/trajectory/src/assets/index.html +772 -0
- package/dist/trajectory/src/assets/marked.min.js +6 -0
- package/dist/trajectory/src/assets/morphdom.min.js +1 -0
- package/dist/trajectory/src/export.d.ts +25 -0
- package/dist/trajectory/src/export.js +80 -0
- package/dist/trajectory/src/index.d.ts +26 -0
- package/dist/trajectory/src/index.js +732 -0
- package/dist/trajectory/src/server.d.ts +7 -0
- package/dist/trajectory/src/server.js +2534 -0
- package/dist/trajectory/src/server.js.map +6 -0
- package/examples/advanced-patterns/auto-model-router.mjs +78 -0
- package/examples/workflow-extension-template/README.md +37 -0
- package/examples/workflow-extension-template/extension.test.mjs +59 -0
- package/examples/workflow-extension-template/index.js +51 -0
- package/examples/workflow-extension-template/roles/reviewer.md +4 -0
- package/package.json +105 -0
- package/skills/pi-extensible-workflows/SKILL.md +160 -0
- package/src/agent-execution.ts +1533 -0
- package/src/background-widget.ts +1496 -0
- package/src/budget.ts +109 -0
- package/src/changelog.ts +114 -0
- package/src/decoders.ts +567 -0
- package/src/execution.ts +652 -0
- package/src/herdr.ts +240 -0
- package/src/host-delivery.ts +346 -0
- package/src/host-navigator.ts +871 -0
- package/src/host-phases.ts +264 -0
- package/src/host-recovery.ts +333 -0
- package/src/host-runtime.ts +373 -0
- package/src/host-view.ts +828 -0
- package/src/host.ts +1502 -0
- package/src/index.ts +29 -0
- package/src/io.ts +73 -0
- package/src/package-identity.ts +7 -0
- package/src/paths.ts +49 -0
- package/src/persistence.ts +11 -0
- package/src/pi-runtime-adapter.ts +247 -0
- package/src/pi-runtime-runner.ts +436 -0
- package/src/registry.ts +321 -0
- package/src/retention.ts +178 -0
- package/src/runtime/agent-runner.ts +158 -0
- package/src/runtime/index.ts +2 -0
- package/src/runtime/namespace.ts +16 -0
- package/src/runtime/workflow-result.ts +8 -0
- package/src/session-handoff.ts +78 -0
- package/src/session-lease.ts +125 -0
- package/src/store.ts +832 -0
- package/src/subagent-manager-handle.ts +8 -0
- package/src/tool-timing.ts +47 -0
- package/src/trajectory-contracts.ts +13 -0
- package/src/trajectory-host-handle.ts +16 -0
- package/src/trajectory.ts +543 -0
- package/src/types.ts +374 -0
- package/src/utils.ts +192 -0
- package/src/validation.ts +910 -0
- package/src/workflow-artifacts.ts +35 -0
- package/starter/index.ts +35 -0
- package/starter/prompts/council.md +16 -0
- package/starter/prompts/deep-research.md +16 -0
- package/starter/prompts/oracle.md +14 -0
- package/starter/prompts/parallel-review.md +22 -0
- package/starter/prompts/parallel-scout.md +16 -0
- package/starter/prompts/review-loop.md +14 -0
- package/starter/prompts/review.md +14 -0
- package/starter/prompts/scout.md +14 -0
- package/starter/review-loop.ts +73 -0
- package/starter/roles/developer.md +6 -0
- package/starter/roles/oracle.md +18 -0
- package/starter/roles/researcher.md +20 -0
- package/starter/roles/reviewer.md +19 -0
- package/starter/roles/scout.md +18 -0
- package/subagents/README.md +145 -0
- package/subagents/index.ts +8 -0
- package/subagents/src/contracts.ts +176 -0
- package/subagents/src/decode.ts +158 -0
- package/subagents/src/index.ts +194 -0
- package/subagents/src/manager.ts +1560 -0
- package/subagents/src/navigator.ts +488 -0
- package/subagents/src/view.ts +376 -0
- package/subagents/src/worktree.ts +99 -0
- package/trajectory/index.ts +5 -0
- package/trajectory/src/assets/favicon.png +0 -0
- package/trajectory/src/assets/index.html +772 -0
- package/trajectory/src/assets/marked.min.js +6 -0
- package/trajectory/src/assets/morphdom.min.js +1 -0
- package/trajectory/src/export.ts +85 -0
- package/trajectory/src/index.ts +604 -0
- package/trajectory/src/server.ts +447 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type HerdrPaneAction = "live";
|
|
2
|
+
export type HerdrAgentState = "idle" | "working" | "blocked" | "unknown";
|
|
3
|
+
export type HerdrAgentStatus = HerdrAgentState | "done";
|
|
4
|
+
export interface HerdrPaneStatus {
|
|
5
|
+
state: HerdrAgentStatus;
|
|
6
|
+
}
|
|
7
|
+
export interface HerdrPaneRequest {
|
|
8
|
+
action: HerdrPaneAction;
|
|
9
|
+
cwd: string;
|
|
10
|
+
command: string;
|
|
11
|
+
paneId?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface HerdrWorkspacePaneRequest {
|
|
14
|
+
cwd: string;
|
|
15
|
+
workspaceLabel?: string;
|
|
16
|
+
workspaceId?: string;
|
|
17
|
+
tabLabel: string;
|
|
18
|
+
command: string;
|
|
19
|
+
}
|
|
20
|
+
export interface HerdrWorkspacePane {
|
|
21
|
+
workspaceId: string;
|
|
22
|
+
tabId: string;
|
|
23
|
+
paneId: string;
|
|
24
|
+
}
|
|
25
|
+
export type HerdrCommandRunner = (args: readonly string[]) => Promise<string>;
|
|
26
|
+
export declare const herdrCommandRunner: HerdrCommandRunner;
|
|
27
|
+
export declare function herdrPaneId(env?: NodeJS.ProcessEnv): string | undefined;
|
|
28
|
+
export declare function herdrAvailable(env?: NodeJS.ProcessEnv): boolean;
|
|
29
|
+
export declare function herdrPaneCommand(request: HerdrPaneRequest): string;
|
|
30
|
+
export declare function openHerdrPane(request: HerdrPaneRequest, runner?: HerdrCommandRunner): Promise<string>;
|
|
31
|
+
export declare function openHerdrWorkspacePane(request: HerdrWorkspacePaneRequest, runner?: HerdrCommandRunner): Promise<HerdrWorkspacePane>;
|
|
32
|
+
export declare function openHerdrLivePane(request: HerdrPaneRequest | HerdrWorkspacePaneRequest, runner?: HerdrCommandRunner): Promise<string | HerdrWorkspacePane>;
|
|
33
|
+
export declare function waitForHerdrPane(paneId: string, runner?: HerdrCommandRunner, options?: {
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
settled?: Promise<void>;
|
|
36
|
+
intervalMs?: number;
|
|
37
|
+
startupTimeoutMs?: number;
|
|
38
|
+
exitGraceMs?: number;
|
|
39
|
+
originatingEntrypoint?: string;
|
|
40
|
+
onStatus?: (state: HerdrAgentStatus) => void | Promise<void>;
|
|
41
|
+
}): Promise<"closed" | "exited" | "idle" | "settled" | "aborted">;
|
|
42
|
+
export interface HerdrAgentReporter {
|
|
43
|
+
reportSession(session: {
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
sessionPath?: string;
|
|
46
|
+
}, sessionStartSource?: string): Promise<void>;
|
|
47
|
+
reportState(state: HerdrAgentState, message?: string, session?: {
|
|
48
|
+
sessionId?: string;
|
|
49
|
+
sessionPath?: string;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
release(): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
export declare function createHerdrAgentReporter(paneId: string, agent: string, runner?: HerdrCommandRunner): HerdrAgentReporter;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { isObject } from "./utils.js";
|
|
3
|
+
export const herdrCommandRunner = (args) => new Promise((resolve, reject) => {
|
|
4
|
+
execFile("herdr", [...args], { encoding: "utf8", maxBuffer: 1024 * 1024 }, (error, stdout) => {
|
|
5
|
+
if (error) {
|
|
6
|
+
reject(new Error(error.message));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
resolve(stdout);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
export function herdrPaneId(env = process.env) {
|
|
13
|
+
if (env.HERDR_ENV !== "1")
|
|
14
|
+
return undefined;
|
|
15
|
+
const paneId = env.HERDR_PANE_ID?.trim();
|
|
16
|
+
return paneId || undefined;
|
|
17
|
+
}
|
|
18
|
+
export function herdrAvailable(env = process.env) { return Boolean(herdrPaneId(env) && env.HERDR_SOCKET_PATH); }
|
|
19
|
+
function shellQuote(value) { return `'${value.replace(/'/g, `'\\''`)}'`; }
|
|
20
|
+
function json(value) { return JSON.parse(value); }
|
|
21
|
+
function record(value) { return isObject(value) ? value : undefined; }
|
|
22
|
+
function paneLayout(value, targetPane) {
|
|
23
|
+
const root = record(value);
|
|
24
|
+
const result = record(root?.result);
|
|
25
|
+
const layout = record(result?.layout);
|
|
26
|
+
const rawPanes = layout?.panes;
|
|
27
|
+
if (!Array.isArray(rawPanes))
|
|
28
|
+
throw new Error("Herdr returned an invalid pane layout.");
|
|
29
|
+
const panes = rawPanes;
|
|
30
|
+
const pane = panes.find((candidate) => record(candidate)?.pane_id === targetPane);
|
|
31
|
+
const rect = record(record(pane)?.rect);
|
|
32
|
+
const width = rect?.width;
|
|
33
|
+
const height = rect?.height;
|
|
34
|
+
if (width === undefined || height === undefined || typeof width !== "number" || typeof height !== "number")
|
|
35
|
+
throw new Error("Herdr returned an invalid target pane geometry.");
|
|
36
|
+
return { width, height };
|
|
37
|
+
}
|
|
38
|
+
function splitPaneId(value) {
|
|
39
|
+
const pane = record(record(record(value)?.result)?.pane);
|
|
40
|
+
const paneId = pane?.pane_id;
|
|
41
|
+
if (typeof paneId !== "string" || !paneId)
|
|
42
|
+
throw new Error("Herdr returned an invalid created pane ID.");
|
|
43
|
+
return paneId;
|
|
44
|
+
}
|
|
45
|
+
function commandFor(request) {
|
|
46
|
+
const environment = ["PI_CODING_AGENT_DIR", "PI_CODING_AGENT_SESSION_DIR"].flatMap((name) => process.env[name] === undefined ? [] : [`${name}=${shellQuote(process.env[name] ?? "")}`]);
|
|
47
|
+
return `cd ${shellQuote(request.cwd)} && ${environment.length ? `${environment.join(" ")} ` : ""}${request.command}`;
|
|
48
|
+
}
|
|
49
|
+
export function herdrPaneCommand(request) { return commandFor(request); }
|
|
50
|
+
export async function openHerdrPane(request, runner = herdrCommandRunner) {
|
|
51
|
+
const targetPane = request.paneId ?? herdrPaneId();
|
|
52
|
+
if (!targetPane)
|
|
53
|
+
throw new Error("Pane actions require a Herdr-managed session with HERDR_PANE_ID.");
|
|
54
|
+
if (!request.cwd)
|
|
55
|
+
throw new Error("Pane actions require a working directory.");
|
|
56
|
+
if (!request.command)
|
|
57
|
+
throw new Error("Pane action is missing its command.");
|
|
58
|
+
const layout = paneLayout(json(await runner(["pane", "layout", "--pane", targetPane])), targetPane);
|
|
59
|
+
const direction = layout.width > layout.height ? "right" : "down";
|
|
60
|
+
const paneId = splitPaneId(json(await runner(["pane", "split", targetPane, "--direction", direction, "--no-focus"])));
|
|
61
|
+
try {
|
|
62
|
+
await runner(["pane", "run", paneId, commandFor(request)]);
|
|
63
|
+
return paneId;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
await runner(["pane", "close", paneId]).catch(() => undefined);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function resourceId(value, resource, field) {
|
|
71
|
+
const result = record(record(value)?.result);
|
|
72
|
+
const item = record(result?.[resource]);
|
|
73
|
+
const id = item?.[field];
|
|
74
|
+
if (typeof id !== "string" || !id)
|
|
75
|
+
throw new Error(`Herdr returned an invalid ${resource} ID.`);
|
|
76
|
+
return id;
|
|
77
|
+
}
|
|
78
|
+
export async function openHerdrWorkspacePane(request, runner = herdrCommandRunner) {
|
|
79
|
+
if (!request.cwd || !request.tabLabel || !request.command || !request.workspaceId && !request.workspaceLabel)
|
|
80
|
+
throw new Error("Herdr workspace pane is missing required data.");
|
|
81
|
+
const created = json(await runner(request.workspaceId
|
|
82
|
+
? ["tab", "create", "--workspace", request.workspaceId, "--cwd", request.cwd, "--label", request.tabLabel, "--no-focus"]
|
|
83
|
+
: ["workspace", "create", "--cwd", request.cwd, "--label", request.workspaceLabel ?? "", "--no-focus"]));
|
|
84
|
+
const workspaceId = request.workspaceId ?? resourceId(created, "workspace", "workspace_id");
|
|
85
|
+
let tabId = resourceId(created, "tab", "tab_id");
|
|
86
|
+
let paneId = resourceId(created, "root_pane", "pane_id");
|
|
87
|
+
try {
|
|
88
|
+
if (!request.workspaceId) {
|
|
89
|
+
await runner(["tab", "rename", tabId, request.workspaceLabel ?? ""]);
|
|
90
|
+
const tab = json(await runner(["tab", "create", "--workspace", workspaceId, "--cwd", request.cwd, "--label", request.tabLabel, "--no-focus"]));
|
|
91
|
+
tabId = resourceId(tab, "tab", "tab_id");
|
|
92
|
+
paneId = resourceId(tab, "root_pane", "pane_id");
|
|
93
|
+
}
|
|
94
|
+
await runner(["pane", "run", paneId, commandFor({ action: "live", cwd: request.cwd, command: request.command })]);
|
|
95
|
+
return { workspaceId, tabId, paneId };
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
await runner(request.workspaceId ? ["tab", "close", tabId] : ["workspace", "close", workspaceId]).catch(() => undefined);
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export async function openHerdrLivePane(request, runner = herdrCommandRunner) {
|
|
103
|
+
if ("workspaceLabel" in request || "workspaceId" in request)
|
|
104
|
+
return openHerdrWorkspacePane(request, runner);
|
|
105
|
+
return openHerdrPane({ ...request, action: "live" }, runner);
|
|
106
|
+
}
|
|
107
|
+
function hasPiProcess(value, originatingEntrypoint) {
|
|
108
|
+
const result = record(record(value)?.result);
|
|
109
|
+
const info = record(result?.process_info);
|
|
110
|
+
const processes = info?.foreground_processes;
|
|
111
|
+
if (!Array.isArray(processes))
|
|
112
|
+
return false;
|
|
113
|
+
return processes.some((candidate) => {
|
|
114
|
+
const process = record(candidate);
|
|
115
|
+
const name = process?.name;
|
|
116
|
+
const argv0 = process?.argv0;
|
|
117
|
+
const argv = process?.argv;
|
|
118
|
+
const commandLine = process?.cmdline;
|
|
119
|
+
if (originatingEntrypoint) {
|
|
120
|
+
if (Array.isArray(argv) && argv.some((value) => value === originatingEntrypoint) || typeof commandLine === "string" && commandLine.includes(originatingEntrypoint))
|
|
121
|
+
return true;
|
|
122
|
+
return name === "pi" || argv0 === "pi" || Array.isArray(argv) && argv[0] === "pi";
|
|
123
|
+
}
|
|
124
|
+
return name === "pi" || argv0 === "pi" || Array.isArray(argv) && argv[0] === "pi" || typeof commandLine === "string" && commandLine.includes("/bin/pi");
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function isHerdrStatus(value) { return value === "idle" || value === "working" || value === "blocked" || value === "unknown" || value === "done"; }
|
|
128
|
+
function herdrAgentStatus(value) {
|
|
129
|
+
const result = record(record(value)?.result);
|
|
130
|
+
const agent = record(result?.agent);
|
|
131
|
+
const rawState = agent?.agent_status;
|
|
132
|
+
if (typeof rawState !== "string")
|
|
133
|
+
return undefined;
|
|
134
|
+
const state = isHerdrStatus(rawState) ? rawState : "unknown";
|
|
135
|
+
return { state };
|
|
136
|
+
}
|
|
137
|
+
export async function waitForHerdrPane(paneId, runner = herdrCommandRunner, options = {}) {
|
|
138
|
+
const intervalMs = options.intervalMs ?? 250;
|
|
139
|
+
const startupTimeoutMs = options.startupTimeoutMs ?? 10000;
|
|
140
|
+
const exitGraceMs = options.exitGraceMs ?? 5000;
|
|
141
|
+
const startedAt = Date.now();
|
|
142
|
+
const monitorController = new AbortController();
|
|
143
|
+
const isAborted = () => monitorController.signal.aborted;
|
|
144
|
+
let markAborted = () => { };
|
|
145
|
+
const aborted = new Promise((resolve) => { markAborted = () => { resolve("aborted"); }; });
|
|
146
|
+
const abortMonitor = () => { monitorController.abort(); markAborted(); };
|
|
147
|
+
if (options.signal?.aborted)
|
|
148
|
+
abortMonitor();
|
|
149
|
+
else
|
|
150
|
+
options.signal?.addEventListener("abort", abortMonitor, { once: true });
|
|
151
|
+
const delay = () => new Promise((resolve) => {
|
|
152
|
+
if (isAborted()) {
|
|
153
|
+
resolve();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const timer = setTimeout(finish, intervalMs);
|
|
157
|
+
function finish() { clearTimeout(timer); monitorController.signal.removeEventListener("abort", finish); resolve(); }
|
|
158
|
+
monitorController.signal.addEventListener("abort", finish, { once: true });
|
|
159
|
+
});
|
|
160
|
+
const poll = async () => {
|
|
161
|
+
let sawPi = false;
|
|
162
|
+
let sawWorking = false;
|
|
163
|
+
let missingSince;
|
|
164
|
+
for (;;) {
|
|
165
|
+
if (isAborted())
|
|
166
|
+
return "aborted";
|
|
167
|
+
let piRunning;
|
|
168
|
+
try {
|
|
169
|
+
const output = await runner(["pane", "process-info", "--pane", paneId]);
|
|
170
|
+
if (isAborted())
|
|
171
|
+
return "aborted";
|
|
172
|
+
piRunning = hasPiProcess(json(output), options.originatingEntrypoint);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
if (isAborted())
|
|
176
|
+
return "aborted";
|
|
177
|
+
return "closed";
|
|
178
|
+
}
|
|
179
|
+
if (!piRunning) {
|
|
180
|
+
if (sawPi) {
|
|
181
|
+
missingSince ??= Date.now();
|
|
182
|
+
if (Date.now() - missingSince >= exitGraceMs)
|
|
183
|
+
return "exited";
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
missingSince = undefined;
|
|
188
|
+
if (!sawPi) {
|
|
189
|
+
sawPi = true;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const output = await runner(["agent", "get", paneId]);
|
|
193
|
+
if (isAborted())
|
|
194
|
+
return "aborted";
|
|
195
|
+
const status = herdrAgentStatus(json(output));
|
|
196
|
+
if (status) {
|
|
197
|
+
if (status.state === "working")
|
|
198
|
+
sawWorking = true;
|
|
199
|
+
const shouldHandBack = options.settled === undefined && sawWorking && (status.state === "idle" || status.state === "done");
|
|
200
|
+
try {
|
|
201
|
+
await options.onStatus?.(status.state);
|
|
202
|
+
}
|
|
203
|
+
catch { /* Status notifications must not suppress pane handback. */ }
|
|
204
|
+
if (isAborted())
|
|
205
|
+
return "aborted";
|
|
206
|
+
if (shouldHandBack)
|
|
207
|
+
return "idle";
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
if (isAborted())
|
|
212
|
+
return "aborted";
|
|
213
|
+
/* The process monitor remains authoritative when no agent report is available. */
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!piRunning && !sawPi && Date.now() - startedAt >= startupTimeoutMs)
|
|
217
|
+
throw new Error("Herdr pane did not start Pi.");
|
|
218
|
+
await delay();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const polling = poll();
|
|
222
|
+
try {
|
|
223
|
+
const result = await Promise.race(options.settled ? [polling, aborted, options.settled.then(() => "settled")] : [polling, aborted]);
|
|
224
|
+
if (result === "settled" || result === "aborted")
|
|
225
|
+
monitorController.abort();
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
monitorController.abort();
|
|
230
|
+
options.signal?.removeEventListener("abort", abortMonitor);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
export function createHerdrAgentReporter(paneId, agent, runner = herdrCommandRunner) {
|
|
234
|
+
const source = "herdr:pi-extensible-workflows";
|
|
235
|
+
let sequence = Date.now() * 1000;
|
|
236
|
+
let released = false;
|
|
237
|
+
let queue = Promise.resolve();
|
|
238
|
+
const next = () => ++sequence;
|
|
239
|
+
const sessionArgs = (session) => session?.sessionPath ? ["--agent-session-path", session.sessionPath] : session?.sessionId ? ["--agent-session-id", session.sessionId] : [];
|
|
240
|
+
const retry = async (operation) => {
|
|
241
|
+
try {
|
|
242
|
+
await operation();
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
try {
|
|
246
|
+
await operation();
|
|
247
|
+
}
|
|
248
|
+
catch { /* Herdr reporting must not stop the Pi session. */ }
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const enqueue = (operation) => {
|
|
252
|
+
const result = queue.then(operation);
|
|
253
|
+
queue = result.then(() => undefined, () => undefined);
|
|
254
|
+
return result;
|
|
255
|
+
};
|
|
256
|
+
return {
|
|
257
|
+
async reportSession(session, sessionStartSource) {
|
|
258
|
+
await enqueue(() => retry(() => runner(["pane", "report-agent-session", paneId, "--source", source, "--agent", agent, "--seq", String(next()), ...(sessionStartSource ? ["--session-start-source", sessionStartSource] : []), ...sessionArgs(session)])));
|
|
259
|
+
},
|
|
260
|
+
async reportState(state, message, session) {
|
|
261
|
+
await enqueue(() => retry(() => runner(["pane", "report-agent", paneId, "--source", source, "--agent", agent, "--state", state, "--seq", String(next()), ...(message ? ["--message", message] : []), ...sessionArgs(session)])));
|
|
262
|
+
},
|
|
263
|
+
async release() {
|
|
264
|
+
if (released)
|
|
265
|
+
return;
|
|
266
|
+
released = true;
|
|
267
|
+
await enqueue(() => retry(() => runner(["pane", "release-agent", paneId, "--source", source, "--agent", agent, "--seq", String(next())])));
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { type PersistedRun, type RunStore } from "./persistence.js";
|
|
2
|
+
import { WorkflowError, type JsonValue, type WorkflowFailureDiagnostics, type WorkflowMetadata } from "./types.js";
|
|
3
|
+
import { SerialLane } from "./utils.js";
|
|
4
|
+
export type ForegroundDetachResult = {
|
|
5
|
+
runId: string;
|
|
6
|
+
state: "running";
|
|
7
|
+
detached: true;
|
|
8
|
+
run: PersistedRun;
|
|
9
|
+
};
|
|
10
|
+
export type ForegroundDelivery = {
|
|
11
|
+
store: RunStore;
|
|
12
|
+
detached: boolean;
|
|
13
|
+
detach: () => Promise<ForegroundDetachResult>;
|
|
14
|
+
};
|
|
15
|
+
export type PendingFailureDiagnostic = {
|
|
16
|
+
diagnostic: WorkflowFailureDiagnostics;
|
|
17
|
+
store: RunStore;
|
|
18
|
+
};
|
|
19
|
+
type ForegroundDeliveryControllerOptions = {
|
|
20
|
+
runs: ReadonlyMap<string, {
|
|
21
|
+
store: RunStore;
|
|
22
|
+
}>;
|
|
23
|
+
deliver?: (content: string) => void;
|
|
24
|
+
};
|
|
25
|
+
export declare class ForegroundDeliveryController {
|
|
26
|
+
private readonly options;
|
|
27
|
+
readonly foregroundDeliveries: Map<string, ForegroundDelivery>;
|
|
28
|
+
readonly pendingFailureDiagnostics: Map<string, PendingFailureDiagnostic>;
|
|
29
|
+
readonly foregroundResumeClaims: WeakSet<RunStore>;
|
|
30
|
+
readonly terminalDeliveryLanes: WeakMap<RunStore, SerialLane>;
|
|
31
|
+
constructor(options: ForegroundDeliveryControllerOptions);
|
|
32
|
+
claimForegroundDelivery: (store: RunStore, toolCallId: string) => Promise<"claimed" | "delivered" | "detached">;
|
|
33
|
+
deliverTerminal: (store: RunStore, content: string | (() => string | Promise<string>), failure?: boolean) => Promise<void>;
|
|
34
|
+
foregroundDeliveryCandidates: (runId: string) => Array<[string, ForegroundDelivery]>;
|
|
35
|
+
moveForegroundToBackground: (runId: string) => Promise<ForegroundDetachResult>;
|
|
36
|
+
isForegroundAttached: (runId: string) => boolean;
|
|
37
|
+
deliverDetachedTerminal: (toolCallId: string, content: string | (() => string | Promise<string>), failure?: boolean) => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export declare function markWorkflowFailureDiagnostics(error: WorkflowError, diagnostic: WorkflowFailureDiagnostics): void;
|
|
40
|
+
export declare function formatWorkflowFailure(error: unknown): string;
|
|
41
|
+
export declare function workflowFailedAt(error: unknown): string | undefined;
|
|
42
|
+
export declare const DELIVERY_LIMIT_BYTES: number;
|
|
43
|
+
export declare const WORKFLOW_LOG_ENTRY = "workflow-log";
|
|
44
|
+
export interface WorkflowLogEntry {
|
|
45
|
+
workflowName: string;
|
|
46
|
+
message: string;
|
|
47
|
+
}
|
|
48
|
+
export interface CompletionContextUsage {
|
|
49
|
+
tokens: number | null;
|
|
50
|
+
contextWindow: number;
|
|
51
|
+
}
|
|
52
|
+
export interface CompletionDeliveryModel {
|
|
53
|
+
contextWindow?: number;
|
|
54
|
+
maxTokens?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface CompletionDeliveryContext {
|
|
57
|
+
getContextUsage?: () => CompletionContextUsage | undefined;
|
|
58
|
+
getModel?: () => CompletionDeliveryModel | undefined;
|
|
59
|
+
model?: CompletionDeliveryModel;
|
|
60
|
+
}
|
|
61
|
+
export interface CompletionDeliveryOptions {
|
|
62
|
+
mode: "foreground" | "background";
|
|
63
|
+
name: string;
|
|
64
|
+
runId: string;
|
|
65
|
+
value: JsonValue;
|
|
66
|
+
resultPath: string;
|
|
67
|
+
resultBytes: number;
|
|
68
|
+
worktrees: readonly {
|
|
69
|
+
branch: string;
|
|
70
|
+
path: string;
|
|
71
|
+
}[];
|
|
72
|
+
context?: CompletionDeliveryContext;
|
|
73
|
+
}
|
|
74
|
+
export interface CompletionDeliveryStoreOptions extends Omit<CompletionDeliveryOptions, "worktrees"> {
|
|
75
|
+
store: Pick<RunStore, "changedWorktrees">;
|
|
76
|
+
}
|
|
77
|
+
export interface CompletionDeliveryResult {
|
|
78
|
+
content: string;
|
|
79
|
+
inlined: boolean;
|
|
80
|
+
}
|
|
81
|
+
export declare function completionDescriptor(options: Pick<CompletionDeliveryOptions, "runId" | "resultBytes"> & {
|
|
82
|
+
resultPath?: string;
|
|
83
|
+
}): string;
|
|
84
|
+
export declare function completionDelivery(options: CompletionDeliveryOptions): CompletionDeliveryResult;
|
|
85
|
+
export declare function completionDeliveryFromStore(options: CompletionDeliveryStoreOptions): Promise<CompletionDeliveryResult>;
|
|
86
|
+
export declare function utf8Prefix(value: string, maxBytes: number): string;
|
|
87
|
+
export declare function failureDiagnosticsFrom(error: unknown): WorkflowFailureDiagnostics | undefined;
|
|
88
|
+
export declare function incompleteRetryPaths(paths: readonly string[], completedPaths: readonly string[]): string[];
|
|
89
|
+
export declare function createWorkflowFailureDiagnostics(store: RunStore, metadata: WorkflowMetadata, error: unknown, run: PersistedRun): Promise<WorkflowFailureDiagnostics>;
|
|
90
|
+
export declare function formatWorkflowFailureDiagnostics(diagnostic: WorkflowFailureDiagnostics): string;
|
|
91
|
+
export declare function formatWorkflowFailureDelivery(diagnostic: WorkflowFailureDiagnostics): string;
|
|
92
|
+
export declare function formatWorkflowFailureDeliveryFallback(workflowName: string, runId: string, runDirectory: string, error: unknown, retryable?: boolean): string;
|
|
93
|
+
export declare function serializeWorkflowFailureDiagnostics(diagnostic: WorkflowFailureDiagnostics): string;
|
|
94
|
+
export declare function isWorkflowFailureDiagnostics(value: unknown): value is WorkflowFailureDiagnostics;
|
|
95
|
+
export {};
|