taskflow-core 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/agents.d.ts +2 -2
- package/dist/agents.d.ts.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/detached-control.d.ts +52 -0
- package/dist/detached-control.d.ts.map +1 -0
- package/dist/detached-control.js +251 -0
- package/dist/detached-control.js.map +1 -0
- package/dist/detached-runner.js +183 -30
- package/dist/detached-runner.js.map +1 -1
- package/dist/exec/driver.d.ts.map +1 -1
- package/dist/exec/driver.js +2 -0
- package/dist/exec/driver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runner-core.d.ts.map +1 -1
- package/dist/runner-core.js +10 -0
- package/dist/runner-core.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +21 -34
- package/dist/runtime.js.map +1 -1
- package/dist/store.d.ts +41 -2
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +489 -180
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -131,7 +131,7 @@ Save it as `.pi/taskflows/audit-api.json`, then run:
|
|
|
131
131
|
/tf:audit-api dir=src/api
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
On Codex, Claude Code, OpenCode, and Grok Build, run the same saved definition by name through `taskflow_run`.
|
|
134
|
+
On Codex, Claude Code, OpenCode, and Grok Build, run the same saved definition by name through `taskflow_run`. For long DAGs, use `mode: "background"`, then manage the durable run with `taskflow_runs` (`list` / `status` / `wait` / `cancel`); list output reports active concurrency and can filter `running` or `terminal` runs.
|
|
135
135
|
|
|
136
136
|
[Follow the full quickstart →](https://heggria.github.io/taskflow/en/docs/getting-started)
|
|
137
137
|
|
|
@@ -315,7 +315,7 @@ claude plugin install claude-taskflow@taskflow
|
|
|
315
315
|
|
|
316
316
|
```bash
|
|
317
317
|
opencode mcp add taskflow -- \
|
|
318
|
-
npx -y -p opencode-taskflow@0.2.
|
|
318
|
+
npx -y -p opencode-taskflow@0.2.3 opencode-taskflow-mcp
|
|
319
319
|
```
|
|
320
320
|
|
|
321
321
|
[OpenCode guide →](https://heggria.github.io/taskflow/en/docs/guides/opencode)
|
|
@@ -324,7 +324,7 @@ opencode mcp add taskflow -- \
|
|
|
324
324
|
|
|
325
325
|
```bash
|
|
326
326
|
grok mcp add taskflow -- \
|
|
327
|
-
npx -y -p grok-taskflow@0.2.
|
|
327
|
+
npx -y -p grok-taskflow@0.2.3 grok-taskflow-mcp
|
|
328
328
|
```
|
|
329
329
|
|
|
330
330
|
Grok Build support is new in 0.2. Its CLI stream does not report token/cost usage, so budget-declaring flows are rejected rather than silently running without enforcement.
|
|
@@ -365,6 +365,7 @@ The test suite covers orchestration semantics, persistence and file-lock races,
|
|
|
365
365
|
| [Host Guides](https://heggria.github.io/taskflow/en/docs/guides/) | Pi, Codex, Claude Code, OpenCode, and Grok setup |
|
|
366
366
|
| [Reference](https://heggria.github.io/taskflow/en/docs/reference/) | Commands, shorthand, and exact tool surfaces |
|
|
367
367
|
| [Showcase](https://heggria.github.io/taskflow/en/docs/showcase/) | Real flows and case studies |
|
|
368
|
+
| [0.2.0 Frontier Assessment](https://github.com/heggria/taskflow/blob/main/docs/taskflow-0.2.0-frontier-assessment.zh-CN.md) | Independent, evidence-based technical assessment (Chinese) |
|
|
368
369
|
|
|
369
370
|
Also see [`examples/`](https://github.com/heggria/taskflow/blob/main/examples), the [changelog](https://github.com/heggria/taskflow/blob/main/CHANGELOG.md), and the [release guide](https://github.com/heggria/taskflow/blob/main/RELEASE.md).
|
|
370
371
|
|
package/dist/agents.d.ts
CHANGED
|
@@ -18,9 +18,9 @@ export interface TaskflowSettings {
|
|
|
18
18
|
builtInAgents: boolean;
|
|
19
19
|
/** Whether package-local built-ins are copied into the current project's .pi/agents/. */
|
|
20
20
|
syncBuiltinAgentsToProject: boolean;
|
|
21
|
-
/** Maximum
|
|
21
|
+
/** Maximum inactive runs to keep. Running runs are never pruned. 0 disables cleanup. */
|
|
22
22
|
maxKeptRuns: number;
|
|
23
|
-
/** Maximum age (days) for
|
|
23
|
+
/** Maximum age (days) for inactive runs. Running runs are never pruned. 0 disables age cleanup. */
|
|
24
24
|
maxRunAgeDays: number;
|
|
25
25
|
/** Library (reusable-flow asset layer) settings. RFC: docs/rfc-library-reuse.md */
|
|
26
26
|
library: LibrarySettings;
|
package/dist/agents.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;AAE1E;iFACiF;AACjF,MAAM,WAAW,eAAe;IAC/B,eAAe,EAAE,sBAAsB,CAAC;IACxC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,yBAAyB,EAAE,eAIvC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAChC,+EAA+E;IAC/E,aAAa,EAAE,OAAO,CAAC;IACvB,yFAAyF;IACzF,0BAA0B,EAAE,OAAO,CAAC;IACpC,
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
|
package/dist/build-info.json
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed control plane for detached Taskflow runs.
|
|
3
|
+
*
|
|
4
|
+
* A detached runner cannot rely on an IPC channel surviving its parent MCP
|
|
5
|
+
* process. Cancellation is therefore requested through a small durable marker
|
|
6
|
+
* in a user-private control directory keyed by the canonical invocation root.
|
|
7
|
+
* The child polls that marker and aborts the normal RuntimeDeps signal,
|
|
8
|
+
* preserving the runtime's existing paused semantics and process-tree cleanup.
|
|
9
|
+
*/
|
|
10
|
+
export interface DetachedCancelRequest {
|
|
11
|
+
requestedAt: number;
|
|
12
|
+
reason?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const DETACHED_CONTROL_VERSION = 1;
|
|
15
|
+
export declare const DETACHED_CONTROL_CWD_ENV = "TASKFLOW_DETACHED_CONTROL_CWD";
|
|
16
|
+
export declare const DETACHED_CONTROL_RUN_ID_ENV = "TASKFLOW_DETACHED_CONTROL_RUN_ID";
|
|
17
|
+
export declare const DETACHED_CONTROL_INSTANCE_ENV = "TASKFLOW_DETACHED_CONTROL_INSTANCE";
|
|
18
|
+
export declare const DETACHED_CONTROL_OWNER_PID_ENV = "TASKFLOW_DETACHED_CONTROL_OWNER_PID";
|
|
19
|
+
export declare const DETACHED_CONTROL_SIGNAL_READY_ENV = "TASKFLOW_DETACHED_CONTROL_SIGNAL_READY";
|
|
20
|
+
export interface DetachedProcessRegistry {
|
|
21
|
+
version: number;
|
|
22
|
+
instanceId: string;
|
|
23
|
+
ownerPid: number;
|
|
24
|
+
heartbeatAt: number;
|
|
25
|
+
pids: number[];
|
|
26
|
+
}
|
|
27
|
+
/** Resolve the cancel marker for a run without accepting caller-selected paths. */
|
|
28
|
+
export declare function detachedCancelRequestPath(cwd: string, runId: string): string;
|
|
29
|
+
/** Persist an idempotent cancellation request for a detached runner. */
|
|
30
|
+
export declare function requestDetachedCancel(cwd: string, runId: string, reason?: string): DetachedCancelRequest;
|
|
31
|
+
/** Read a cancellation request. Corrupt markers still mean "cancel" fail-safe. */
|
|
32
|
+
export declare function readDetachedCancelRequest(cwd: string, runId: string): DetachedCancelRequest | null;
|
|
33
|
+
export declare function clearDetachedCancelRequest(cwd: string, runId: string): void;
|
|
34
|
+
export declare function detachedProcessRegistryPath(cwd: string, runId: string): string;
|
|
35
|
+
export declare function readDetachedProcessRegistry(cwd: string, runId: string): DetachedProcessRegistry | null;
|
|
36
|
+
export declare function heartbeatDetachedProcessRegistry(cwd: string, runId: string, instanceId: string, ownerPid?: number): void;
|
|
37
|
+
/** True only after this exact detached owner installed its persistence-aware signal bridge. */
|
|
38
|
+
export declare function isDetachedSignalOwnerReady(): boolean;
|
|
39
|
+
/** Best-effort hook used by runner-core whenever a Host CLI process group starts. */
|
|
40
|
+
export declare function registerDetachedProcessTreeFromEnv(pid: number): void;
|
|
41
|
+
/** Best-effort hook used by runner-core after a Host CLI process group is reaped. */
|
|
42
|
+
export declare function unregisterDetachedProcessTreeFromEnv(pid: number): void;
|
|
43
|
+
/** Reap every Host CLI process group owned by exactly this worker instance. */
|
|
44
|
+
export declare function terminateDetachedProcessTrees(cwd: string, runId: string, instanceId: string): number[];
|
|
45
|
+
export declare function clearDetachedProcessRegistry(cwd: string, runId: string, instanceId?: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Poll a detached cancellation marker and bridge it into an AbortController.
|
|
48
|
+
* Returns a cleanup callback. The timer is unref'd so it never keeps a
|
|
49
|
+
* completed detached runner alive by itself.
|
|
50
|
+
*/
|
|
51
|
+
export declare function watchDetachedCancel(cwd: string, runId: string, controller: AbortController, pollMs?: number, onRequest?: (request: DetachedCancelRequest) => void): () => void;
|
|
52
|
+
//# sourceMappingURL=detached-control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detached-control.d.ts","sourceRoot":"","sources":["../src/detached-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,qBAAqB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,eAAO,MAAM,wBAAwB,IAAkB,CAAC;AACxD,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AACxE,eAAO,MAAM,2BAA2B,qCAAqC,CAAC;AAC9E,eAAO,MAAM,6BAA6B,uCAAuC,CAAC;AAClF,eAAO,MAAM,8BAA8B,wCAAwC,CAAC;AACpF,eAAO,MAAM,iCAAiC,2CAA2C,CAAC;AAE1F,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AAkBD,mFAAmF;AACnF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,qBAAqB,CAUxG;AAED,kFAAkF;AAClF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAiBlG;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAO3E;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAuBtG;AAOD,wBAAgB,gCAAgC,CAC/C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,SAAc,GACpB,IAAI,CAUN;AAcD,+FAA+F;AAC/F,wBAAgB,0BAA0B,IAAI,OAAO,CAGpD;AAED,qFAAqF;AACrF,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAcpE;AAED,qFAAqF;AACrF,wBAAgB,oCAAoC,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAYtE;AAmBD,+EAA+E;AAC/E,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAKtG;AAED,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAOlG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,eAAe,EAC3B,MAAM,SAAkB,EACxB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,IAAI,GAClD,MAAM,IAAI,CAaZ"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed control plane for detached Taskflow runs.
|
|
3
|
+
*
|
|
4
|
+
* A detached runner cannot rely on an IPC channel surviving its parent MCP
|
|
5
|
+
* process. Cancellation is therefore requested through a small durable marker
|
|
6
|
+
* in a user-private control directory keyed by the canonical invocation root.
|
|
7
|
+
* The child polls that marker and aborts the normal RuntimeDeps signal,
|
|
8
|
+
* preserving the runtime's existing paused semantics and process-tree cleanup.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import { spawnSync } from "node:child_process";
|
|
13
|
+
import { detachedControlDir, validateRunId, writeFileAtomic } from "./store.js";
|
|
14
|
+
const DEFAULT_POLL_MS = 250;
|
|
15
|
+
const CONTROL_VERSION = 1;
|
|
16
|
+
export const DETACHED_CONTROL_VERSION = CONTROL_VERSION;
|
|
17
|
+
export const DETACHED_CONTROL_CWD_ENV = "TASKFLOW_DETACHED_CONTROL_CWD";
|
|
18
|
+
export const DETACHED_CONTROL_RUN_ID_ENV = "TASKFLOW_DETACHED_CONTROL_RUN_ID";
|
|
19
|
+
export const DETACHED_CONTROL_INSTANCE_ENV = "TASKFLOW_DETACHED_CONTROL_INSTANCE";
|
|
20
|
+
export const DETACHED_CONTROL_OWNER_PID_ENV = "TASKFLOW_DETACHED_CONTROL_OWNER_PID";
|
|
21
|
+
export const DETACHED_CONTROL_SIGNAL_READY_ENV = "TASKFLOW_DETACHED_CONTROL_SIGNAL_READY";
|
|
22
|
+
function ensureControlDir(cwd) {
|
|
23
|
+
const dir = detachedControlDir(cwd);
|
|
24
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
25
|
+
const stat = fs.lstatSync(dir);
|
|
26
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
27
|
+
throw new Error("Detached control root must be a private physical directory");
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
fs.chmodSync(dir, 0o700);
|
|
31
|
+
}
|
|
32
|
+
catch { /* Windows / restrictive filesystem */ }
|
|
33
|
+
return dir;
|
|
34
|
+
}
|
|
35
|
+
function controlPath(cwd, runId, suffix) {
|
|
36
|
+
if (!validateRunId(runId))
|
|
37
|
+
throw new Error("Invalid runId for detached control");
|
|
38
|
+
return path.join(detachedControlDir(cwd), `${runId}.${suffix}.json`);
|
|
39
|
+
}
|
|
40
|
+
/** Resolve the cancel marker for a run without accepting caller-selected paths. */
|
|
41
|
+
export function detachedCancelRequestPath(cwd, runId) {
|
|
42
|
+
return controlPath(cwd, runId, "cancel");
|
|
43
|
+
}
|
|
44
|
+
/** Persist an idempotent cancellation request for a detached runner. */
|
|
45
|
+
export function requestDetachedCancel(cwd, runId, reason) {
|
|
46
|
+
ensureControlDir(cwd);
|
|
47
|
+
const request = {
|
|
48
|
+
requestedAt: Date.now(),
|
|
49
|
+
...(typeof reason === "string" && reason.trim()
|
|
50
|
+
? { reason: reason.trim().slice(0, 500) }
|
|
51
|
+
: {}),
|
|
52
|
+
};
|
|
53
|
+
writeFileAtomic(detachedCancelRequestPath(cwd, runId), `${JSON.stringify(request)}\n`);
|
|
54
|
+
return request;
|
|
55
|
+
}
|
|
56
|
+
/** Read a cancellation request. Corrupt markers still mean "cancel" fail-safe. */
|
|
57
|
+
export function readDetachedCancelRequest(cwd, runId) {
|
|
58
|
+
const filePath = detachedCancelRequestPath(cwd, runId);
|
|
59
|
+
if (!fs.existsSync(filePath))
|
|
60
|
+
return null;
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
63
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
64
|
+
const record = parsed;
|
|
65
|
+
return {
|
|
66
|
+
requestedAt: typeof record.requestedAt === "number" ? record.requestedAt : Date.now(),
|
|
67
|
+
...(typeof record.reason === "string" ? { reason: record.reason } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// The marker exists, so fail safe and cancel even if its optional metadata
|
|
73
|
+
// was truncated or externally corrupted.
|
|
74
|
+
}
|
|
75
|
+
return { requestedAt: Date.now(), reason: "Cancellation marker was unreadable" };
|
|
76
|
+
}
|
|
77
|
+
export function clearDetachedCancelRequest(cwd, runId) {
|
|
78
|
+
try {
|
|
79
|
+
fs.unlinkSync(detachedCancelRequestPath(cwd, runId));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* missing/already consumed */
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
fs.rmdirSync(detachedControlDir(cwd));
|
|
86
|
+
}
|
|
87
|
+
catch { /* other markers / missing */ }
|
|
88
|
+
}
|
|
89
|
+
export function detachedProcessRegistryPath(cwd, runId) {
|
|
90
|
+
return controlPath(cwd, runId, "processes");
|
|
91
|
+
}
|
|
92
|
+
export function readDetachedProcessRegistry(cwd, runId) {
|
|
93
|
+
const filePath = detachedProcessRegistryPath(cwd, runId);
|
|
94
|
+
try {
|
|
95
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
96
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
97
|
+
return null;
|
|
98
|
+
const value = parsed;
|
|
99
|
+
if (value.version !== CONTROL_VERSION ||
|
|
100
|
+
typeof value.instanceId !== "string" ||
|
|
101
|
+
!Number.isSafeInteger(value.ownerPid) ||
|
|
102
|
+
typeof value.heartbeatAt !== "number" ||
|
|
103
|
+
!Array.isArray(value.pids))
|
|
104
|
+
return null;
|
|
105
|
+
return {
|
|
106
|
+
version: CONTROL_VERSION,
|
|
107
|
+
instanceId: value.instanceId,
|
|
108
|
+
ownerPid: value.ownerPid,
|
|
109
|
+
heartbeatAt: value.heartbeatAt,
|
|
110
|
+
pids: value.pids.filter((pid) => Number.isSafeInteger(pid) && Number(pid) > 0),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function writeDetachedProcessRegistry(cwd, runId, registry) {
|
|
118
|
+
ensureControlDir(cwd);
|
|
119
|
+
writeFileAtomic(detachedProcessRegistryPath(cwd, runId), `${JSON.stringify(registry)}\n`);
|
|
120
|
+
}
|
|
121
|
+
export function heartbeatDetachedProcessRegistry(cwd, runId, instanceId, ownerPid = process.pid) {
|
|
122
|
+
const existing = readDetachedProcessRegistry(cwd, runId);
|
|
123
|
+
const pids = existing?.instanceId === instanceId ? existing.pids : [];
|
|
124
|
+
writeDetachedProcessRegistry(cwd, runId, {
|
|
125
|
+
version: CONTROL_VERSION,
|
|
126
|
+
instanceId,
|
|
127
|
+
ownerPid,
|
|
128
|
+
heartbeatAt: Date.now(),
|
|
129
|
+
pids,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function processRegistryContextFromEnv() {
|
|
133
|
+
const cwd = process.env[DETACHED_CONTROL_CWD_ENV];
|
|
134
|
+
const runId = process.env[DETACHED_CONTROL_RUN_ID_ENV];
|
|
135
|
+
const instanceId = process.env[DETACHED_CONTROL_INSTANCE_ENV];
|
|
136
|
+
// Host CLIs inherit the detached worker's environment. Only the process that
|
|
137
|
+
// owns this exact PID token may mutate the outer worker's registry; nested
|
|
138
|
+
// Taskflow instances must not overwrite its heartbeat/owner identity.
|
|
139
|
+
if (process.env[DETACHED_CONTROL_OWNER_PID_ENV] !== String(process.pid))
|
|
140
|
+
return null;
|
|
141
|
+
if (!cwd || !runId || !instanceId || !validateRunId(runId))
|
|
142
|
+
return null;
|
|
143
|
+
return { cwd, runId, instanceId };
|
|
144
|
+
}
|
|
145
|
+
/** True only after this exact detached owner installed its persistence-aware signal bridge. */
|
|
146
|
+
export function isDetachedSignalOwnerReady() {
|
|
147
|
+
return process.env[DETACHED_CONTROL_OWNER_PID_ENV] === String(process.pid) &&
|
|
148
|
+
process.env[DETACHED_CONTROL_SIGNAL_READY_ENV] === "1";
|
|
149
|
+
}
|
|
150
|
+
/** Best-effort hook used by runner-core whenever a Host CLI process group starts. */
|
|
151
|
+
export function registerDetachedProcessTreeFromEnv(pid) {
|
|
152
|
+
const context = processRegistryContextFromEnv();
|
|
153
|
+
if (!context || !Number.isSafeInteger(pid) || pid <= 0)
|
|
154
|
+
return;
|
|
155
|
+
try {
|
|
156
|
+
const existing = readDetachedProcessRegistry(context.cwd, context.runId);
|
|
157
|
+
const pids = existing?.instanceId === context.instanceId ? existing.pids : [];
|
|
158
|
+
writeDetachedProcessRegistry(context.cwd, context.runId, {
|
|
159
|
+
version: CONTROL_VERSION,
|
|
160
|
+
instanceId: context.instanceId,
|
|
161
|
+
ownerPid: process.pid,
|
|
162
|
+
heartbeatAt: Date.now(),
|
|
163
|
+
pids: [...new Set([...pids, pid])],
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch { /* lifecycle diagnostics must never replace phase execution */ }
|
|
167
|
+
}
|
|
168
|
+
/** Best-effort hook used by runner-core after a Host CLI process group is reaped. */
|
|
169
|
+
export function unregisterDetachedProcessTreeFromEnv(pid) {
|
|
170
|
+
const context = processRegistryContextFromEnv();
|
|
171
|
+
if (!context)
|
|
172
|
+
return;
|
|
173
|
+
try {
|
|
174
|
+
const existing = readDetachedProcessRegistry(context.cwd, context.runId);
|
|
175
|
+
if (!existing || existing.instanceId !== context.instanceId)
|
|
176
|
+
return;
|
|
177
|
+
writeDetachedProcessRegistry(context.cwd, context.runId, {
|
|
178
|
+
...existing,
|
|
179
|
+
heartbeatAt: Date.now(),
|
|
180
|
+
pids: existing.pids.filter((candidate) => candidate !== pid),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch { /* lifecycle diagnostics must never replace phase execution */ }
|
|
184
|
+
}
|
|
185
|
+
function killRegisteredProcessTree(pid) {
|
|
186
|
+
if (!Number.isSafeInteger(pid) || pid <= 0 || pid === process.pid)
|
|
187
|
+
return;
|
|
188
|
+
if (process.platform === "win32") {
|
|
189
|
+
try {
|
|
190
|
+
spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], {
|
|
191
|
+
shell: false,
|
|
192
|
+
stdio: "ignore",
|
|
193
|
+
windowsHide: true,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch { /* already gone / taskkill unavailable */ }
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
process.kill(-pid, "SIGKILL");
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
try {
|
|
204
|
+
process.kill(pid, "SIGKILL");
|
|
205
|
+
}
|
|
206
|
+
catch { /* already gone */ }
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** Reap every Host CLI process group owned by exactly this worker instance. */
|
|
210
|
+
export function terminateDetachedProcessTrees(cwd, runId, instanceId) {
|
|
211
|
+
const registry = readDetachedProcessRegistry(cwd, runId);
|
|
212
|
+
if (!registry || registry.instanceId !== instanceId)
|
|
213
|
+
return [];
|
|
214
|
+
for (const pid of registry.pids)
|
|
215
|
+
killRegisteredProcessTree(pid);
|
|
216
|
+
return registry.pids;
|
|
217
|
+
}
|
|
218
|
+
export function clearDetachedProcessRegistry(cwd, runId, instanceId) {
|
|
219
|
+
try {
|
|
220
|
+
const existing = readDetachedProcessRegistry(cwd, runId);
|
|
221
|
+
if (instanceId && existing && existing.instanceId !== instanceId)
|
|
222
|
+
return;
|
|
223
|
+
fs.unlinkSync(detachedProcessRegistryPath(cwd, runId));
|
|
224
|
+
}
|
|
225
|
+
catch { /* missing/already cleared */ }
|
|
226
|
+
try {
|
|
227
|
+
fs.rmdirSync(detachedControlDir(cwd));
|
|
228
|
+
}
|
|
229
|
+
catch { /* other markers / missing */ }
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Poll a detached cancellation marker and bridge it into an AbortController.
|
|
233
|
+
* Returns a cleanup callback. The timer is unref'd so it never keeps a
|
|
234
|
+
* completed detached runner alive by itself.
|
|
235
|
+
*/
|
|
236
|
+
export function watchDetachedCancel(cwd, runId, controller, pollMs = DEFAULT_POLL_MS, onRequest) {
|
|
237
|
+
const check = () => {
|
|
238
|
+
if (controller.signal.aborted)
|
|
239
|
+
return;
|
|
240
|
+
const request = readDetachedCancelRequest(cwd, runId);
|
|
241
|
+
if (request) {
|
|
242
|
+
onRequest?.(request);
|
|
243
|
+
controller.abort(request);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
check();
|
|
247
|
+
const timer = setInterval(check, Math.max(50, pollMs));
|
|
248
|
+
timer.unref();
|
|
249
|
+
return () => clearInterval(timer);
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=detached-control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detached-control.js","sourceRoot":"","sources":["../src/detached-control.ts"],"names":[],"mappings":"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"}
|