@diffexai/diffex 0.3.0 → 0.3.2
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 +45 -0
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.js +39 -0
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session.d.ts +4 -5
- package/dist/core/agent-session.js +11 -62
- package/dist/core/compaction/branch-summarization.js +3 -2
- package/dist/core/compaction/compaction.js +9 -7
- package/dist/core/compaction/utils.d.ts +3 -0
- package/dist/core/compaction/utils.js +21 -0
- package/dist/core/current-plan-state.d.ts +3 -2
- package/dist/core/current-plan-state.js +23 -6
- package/dist/core/plan-snapshot.d.ts +3 -0
- package/dist/core/plan-snapshot.js +23 -0
- package/dist/core/sdk.d.ts +3 -0
- package/dist/core/sdk.js +1 -0
- package/dist/core/session-manager.js +21 -1
- package/dist/core/subagents/services.d.ts +2 -0
- package/dist/core/subagents/services.js +2 -0
- package/dist/core/tools/bash.js +47 -12
- package/dist/core/tools/update-plan.d.ts +27 -6
- package/dist/core/tools/update-plan.js +122 -18
- package/dist/index.d.ts +1 -0
- package/dist/main.js +4 -0
- package/dist/modes/interactive/components/footer.js +16 -5
- package/dist/modes/interactive/components/tool-group.d.ts +1 -0
- package/dist/modes/interactive/components/tool-group.js +26 -7
- package/dist/modes/print-mode.js +16 -13
- package/dist/node_modules/@diffexai/diffex-agent-core/dist/agent-loop.js +21 -3
- package/dist/node_modules/@diffexai/diffex-agent-core/dist/types.d.ts +17 -10
- package/dist/node_modules/@diffexai/diffex-agent-core/distribution-components.json +4 -4
- package/dist/node_modules/@diffexai/diffex-agent-core/distribution-files.json +3 -3
- package/dist/node_modules/@diffexai/diffex-agent-core/package.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/.manifest.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/anthropic.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/azure-openai-responses.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cerebras.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/fireworks.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/github-copilot.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/google-vertex.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/google.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/huggingface.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/minimax-cn.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/minimax.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/mistral.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/moonshotai-cn.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/moonshotai.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/nvidia.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openai.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode-go.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openrouter.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/together.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xai.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi.json +1 -1
- package/dist/node_modules/@diffexai/diffex-ai/distribution-components.json +3 -3
- package/dist/node_modules/@diffexai/diffex-ai/distribution-files.json +30 -30
- package/dist/node_modules/@diffexai/diffex-ai/package.json +1 -1
- package/dist/node_modules/@diffexai/diffex-client/distribution-components.json +3 -3
- package/dist/node_modules/@diffexai/diffex-client/distribution-files.json +1 -1
- package/dist/node_modules/@diffexai/diffex-client/package.json +1 -1
- package/dist/node_modules/@diffexai/diffex-harness-state/distribution-components.json +2 -2
- package/dist/node_modules/@diffexai/diffex-harness-state/distribution-files.json +1 -1
- package/dist/node_modules/@diffexai/diffex-harness-state/package.json +1 -1
- package/dist/node_modules/@diffexai/diffex-protocol/distribution-components.json +2 -2
- package/dist/node_modules/@diffexai/diffex-protocol/distribution-files.json +1 -1
- package/dist/node_modules/@diffexai/diffex-protocol/package.json +1 -1
- package/dist/node_modules/@diffexai/diffex-telemetry/distribution-components.json +2 -2
- package/dist/node_modules/@diffexai/diffex-telemetry/distribution-files.json +1 -1
- package/dist/node_modules/@diffexai/diffex-telemetry/package.json +1 -1
- package/dist/node_modules/@diffexai/diffex-tui/distribution-components.json +2 -2
- package/dist/node_modules/@diffexai/diffex-tui/distribution-files.json +1 -1
- package/dist/node_modules/@diffexai/diffex-tui/package.json +1 -1
- package/dist/utils/child-process.d.ts +5 -1
- package/dist/utils/child-process.js +9 -1
- package/dist/utils/owned-shell-processes.d.ts +23 -2
- package/dist/utils/owned-shell-processes.js +149 -39
- package/dist/utils/shell-process-identity.d.ts +11 -0
- package/dist/utils/shell-process-identity.js +61 -0
- package/dist/utils/shell.d.ts +1 -1
- package/dist/utils/shell.js +5 -5
- package/distribution-components.json +11 -11
- package/distribution-files.json +101 -85
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/release/distribution-manifest.json +4 -4
- package/release/install-package-lock.json +5 -5
- package/release/install-package.json +2 -2
|
@@ -1,61 +1,171 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { closeSync, fsyncSync, mkdirSync, openSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { isAbsolute, join } from "node:path";
|
|
2
4
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3
5
|
import { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from "./shell.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
process.kill(process.platform === "win32" ? pid : -pid, 0);
|
|
7
|
-
return true;
|
|
8
|
-
}
|
|
9
|
-
catch (error) {
|
|
10
|
-
if (error.code === "ESRCH")
|
|
11
|
-
return false;
|
|
12
|
-
if (error.code === "EPERM")
|
|
13
|
-
return true;
|
|
14
|
-
throw error;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/** A session owns the process groups it launches, including background jobs. */
|
|
6
|
+
import { hasShellExecutionToken, readShellProcessGroup } from "./shell-process-identity.js";
|
|
7
|
+
/** Session ownership ends only after a successful, durably published handoff. */
|
|
18
8
|
export class OwnedShellProcesses {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
policy;
|
|
10
|
+
#executions = new Map();
|
|
11
|
+
constructor(policy = { lifetime: "session" }) {
|
|
12
|
+
if (policy.lifetime !== "session" && policy.lifetime !== "environment") {
|
|
13
|
+
throw new Error("Invalid background process lifetime");
|
|
14
|
+
}
|
|
15
|
+
if (policy.lifetime === "environment") {
|
|
16
|
+
if (process.platform !== "linux" && process.platform !== "darwin") {
|
|
17
|
+
throw new Error("Environment background process ownership requires Linux or macOS");
|
|
18
|
+
}
|
|
19
|
+
if (!policy.ownershipDirectory || !isAbsolute(policy.ownershipDirectory)) {
|
|
20
|
+
throw new Error("Environment background process ownership requires an absolute ownershipDirectory");
|
|
21
|
+
}
|
|
22
|
+
mkdirSync(policy.ownershipDirectory, { recursive: true, mode: 0o700 });
|
|
23
|
+
}
|
|
24
|
+
this.policy = Object.freeze({ ...policy });
|
|
25
|
+
}
|
|
26
|
+
track(pid, executionId) {
|
|
27
|
+
const execution = { id: executionId, state: "active", members: [] };
|
|
28
|
+
this.#executions.set(pid, execution);
|
|
29
|
+
trackDetachedChildPid(pid, () => this.terminate(pid));
|
|
30
|
+
try {
|
|
31
|
+
execution.members = process.platform === "win32" ? [] : readShellProcessGroup(pid);
|
|
32
|
+
this.#publish(pid, execution, "session", "active");
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
this.terminate(pid);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Called synchronously on shell exit, before output draining or another event can cancel it. */
|
|
40
|
+
complete(pid, successful) {
|
|
41
|
+
const execution = this.#executions.get(pid);
|
|
42
|
+
if (!execution || execution.state !== "active")
|
|
43
|
+
return;
|
|
44
|
+
// This callback belongs to the ChildProcess just reaped by Node. Capture the
|
|
45
|
+
// surviving group now; later cleanup must validate these process identities.
|
|
46
|
+
execution.members = process.platform === "win32" ? [] : readShellProcessGroup(pid);
|
|
47
|
+
execution.state = "background";
|
|
48
|
+
if (!successful || this.policy.lifetime === "session")
|
|
49
|
+
return;
|
|
50
|
+
const members = this.#members(pid, execution);
|
|
51
|
+
if (members.length === 0) {
|
|
52
|
+
this.releaseIfExited(pid);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
execution.members = members;
|
|
56
|
+
// No await between publication and removing both cleanup registrations.
|
|
57
|
+
// Atomic rename is the ownership commit point, including after a forced CLI death.
|
|
58
|
+
this.#publish(pid, execution, "environment", "background");
|
|
59
|
+
this.#executions.delete(pid);
|
|
60
|
+
untrackDetachedChildPid(pid);
|
|
61
|
+
}
|
|
62
|
+
#publish(pid, execution, owner, state) {
|
|
63
|
+
if (this.policy.lifetime !== "environment")
|
|
64
|
+
return;
|
|
65
|
+
const record = {
|
|
66
|
+
version: 1,
|
|
67
|
+
executionId: execution.id,
|
|
68
|
+
owner,
|
|
69
|
+
state,
|
|
70
|
+
processGroupId: pid,
|
|
71
|
+
supervisorPid: process.pid,
|
|
72
|
+
members: execution.members,
|
|
73
|
+
};
|
|
74
|
+
const path = join(this.policy.ownershipDirectory, `${execution.id}.json`);
|
|
75
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
76
|
+
const fd = openSync(temporary, "wx", 0o600);
|
|
77
|
+
try {
|
|
78
|
+
try {
|
|
79
|
+
writeFileSync(fd, `${JSON.stringify(record)}\n`);
|
|
80
|
+
fsyncSync(fd);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
renameSync(temporary, path);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
try {
|
|
89
|
+
unlinkSync(temporary);
|
|
90
|
+
}
|
|
91
|
+
catch { }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
#members(pid, execution) {
|
|
95
|
+
const members = readShellProcessGroup(pid);
|
|
96
|
+
if (members.length === 0)
|
|
97
|
+
return [];
|
|
98
|
+
const known = members.some((member) => execution.members.some((previous) => previous.pid === member.pid && previous.startTime === member.startTime));
|
|
99
|
+
if (!known && !members.some((member) => hasShellExecutionToken(member.pid, execution.id))) {
|
|
100
|
+
throw new Error(`Cannot verify ownership of shell process group ${pid}`);
|
|
101
|
+
}
|
|
102
|
+
return members;
|
|
103
|
+
}
|
|
104
|
+
terminate(pid) {
|
|
105
|
+
const execution = this.#executions.get(pid);
|
|
106
|
+
if (!execution)
|
|
107
|
+
return;
|
|
108
|
+
if (execution.state === "active" && process.platform !== "win32") {
|
|
109
|
+
// The launching ChildProcess has not delivered its exit event yet.
|
|
110
|
+
execution.members = readShellProcessGroup(pid);
|
|
111
|
+
}
|
|
112
|
+
execution.state = "terminating";
|
|
113
|
+
if (process.platform === "win32") {
|
|
114
|
+
killProcessTree(pid);
|
|
115
|
+
}
|
|
116
|
+
else if (this.#members(pid, execution).length > 0) {
|
|
117
|
+
// Never fall back to a recycled leader PID when its group has disappeared.
|
|
118
|
+
try {
|
|
119
|
+
process.kill(-pid, "SIGKILL");
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (error.code !== "ESRCH")
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
23
126
|
}
|
|
24
127
|
releaseIfExited(pid) {
|
|
25
|
-
|
|
26
|
-
|
|
128
|
+
const execution = this.#executions.get(pid);
|
|
129
|
+
if (!execution)
|
|
130
|
+
return;
|
|
131
|
+
let alive;
|
|
132
|
+
if (process.platform === "win32") {
|
|
133
|
+
try {
|
|
134
|
+
process.kill(pid, 0);
|
|
135
|
+
alive = true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
alive = false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
alive = this.#members(pid, execution).length > 0;
|
|
143
|
+
}
|
|
144
|
+
if (!alive) {
|
|
145
|
+
this.#publish(pid, execution, "session", "terminated");
|
|
146
|
+
this.#executions.delete(pid);
|
|
27
147
|
untrackDetachedChildPid(pid);
|
|
28
148
|
}
|
|
29
149
|
}
|
|
30
150
|
get count() {
|
|
31
|
-
for (const pid of this.#
|
|
151
|
+
for (const pid of this.#executions.keys())
|
|
32
152
|
this.releaseIfExited(pid);
|
|
33
|
-
return this.#
|
|
153
|
+
return this.#executions.size;
|
|
34
154
|
}
|
|
35
155
|
async terminateAll() {
|
|
36
|
-
const pids = [...this.#
|
|
156
|
+
const pids = [...this.#executions.keys()];
|
|
37
157
|
for (const pid of pids)
|
|
38
|
-
|
|
158
|
+
this.terminate(pid);
|
|
39
159
|
const deadline = performance.now() + 5_000;
|
|
40
160
|
for (const pid of pids) {
|
|
41
|
-
while (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const result = spawnSync("ps", ["-eo", "pgid=,stat="], { encoding: "utf8", timeout: 1_000 });
|
|
46
|
-
if (result.status === 0 &&
|
|
47
|
-
!result.stdout.split("\n").some((line) => {
|
|
48
|
-
const [group, state] = line.trim().split(/\s+/);
|
|
49
|
-
return Number(group) === pid && state && !state.startsWith("Z");
|
|
50
|
-
}))
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
161
|
+
while (this.#executions.has(pid)) {
|
|
162
|
+
this.releaseIfExited(pid);
|
|
163
|
+
if (!this.#executions.has(pid))
|
|
164
|
+
break;
|
|
53
165
|
if (performance.now() >= deadline)
|
|
54
166
|
throw new Error(`Shell process group ${pid} did not terminate`);
|
|
55
167
|
await delay(25);
|
|
56
168
|
}
|
|
57
|
-
this.#pids.delete(pid);
|
|
58
|
-
untrackDetachedChildPid(pid);
|
|
59
169
|
}
|
|
60
170
|
}
|
|
61
171
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const SHELL_EXECUTION_ID_ENV = "DIFFEX_SHELL_EXECUTION_ID";
|
|
2
|
+
export interface ShellProcessIdentity {
|
|
3
|
+
readonly pid: number;
|
|
4
|
+
readonly processGroupId: number;
|
|
5
|
+
/** Linux boot ID and start ticks, or macOS ps lstart in UTC and the C locale. */
|
|
6
|
+
readonly startTime: string;
|
|
7
|
+
}
|
|
8
|
+
/** Read live group members without treating orphaned zombies as running work. */
|
|
9
|
+
export declare function readShellProcessGroup(processGroupId: number): ShellProcessIdentity[];
|
|
10
|
+
/** The launch token prevents a recycled group ID from authorizing a signal. */
|
|
11
|
+
export declare function hasShellExecutionToken(pid: number, executionId: string): boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
export const SHELL_EXECUTION_ID_ENV = "DIFFEX_SHELL_EXECUTION_ID";
|
|
4
|
+
/** Read live group members without treating orphaned zombies as running work. */
|
|
5
|
+
export function readShellProcessGroup(processGroupId) {
|
|
6
|
+
if (process.platform === "linux") {
|
|
7
|
+
const bootId = readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
|
|
8
|
+
const members = [];
|
|
9
|
+
for (const name of readdirSync("/proc")) {
|
|
10
|
+
if (!/^\d+$/.test(name))
|
|
11
|
+
continue;
|
|
12
|
+
try {
|
|
13
|
+
const stat = readFileSync(`/proc/${name}/stat`, "utf8");
|
|
14
|
+
const fields = stat
|
|
15
|
+
.slice(stat.lastIndexOf(")") + 2)
|
|
16
|
+
.trim()
|
|
17
|
+
.split(/\s+/);
|
|
18
|
+
if (Number(fields[2]) !== processGroupId || fields[0] === "Z")
|
|
19
|
+
continue;
|
|
20
|
+
members.push({ pid: Number(name), processGroupId, startTime: `${bootId}:${fields[19]}` });
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (["ENOENT", "ESRCH"].includes(error.code ?? ""))
|
|
24
|
+
continue;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return members;
|
|
29
|
+
}
|
|
30
|
+
const result = spawnSync("ps", ["-axo", "pid=,pgid=,stat=,lstart="], {
|
|
31
|
+
encoding: "utf8",
|
|
32
|
+
timeout: 1_000,
|
|
33
|
+
env: { ...process.env, LC_ALL: "C", TZ: "UTC" },
|
|
34
|
+
});
|
|
35
|
+
if (result.status !== 0)
|
|
36
|
+
throw new Error("Cannot inspect shell process groups", { cause: result.error });
|
|
37
|
+
return result.stdout.split("\n").flatMap((line) => {
|
|
38
|
+
const [pid, group, state, ...started] = line.trim().split(/\s+/);
|
|
39
|
+
return Number(group) === processGroupId && state && !state.startsWith("Z")
|
|
40
|
+
? [{ pid: Number(pid), processGroupId, startTime: started.join(" ") }]
|
|
41
|
+
: [];
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** The launch token prevents a recycled group ID from authorizing a signal. */
|
|
45
|
+
export function hasShellExecutionToken(pid, executionId) {
|
|
46
|
+
try {
|
|
47
|
+
const token = `${SHELL_EXECUTION_ID_ENV}=${executionId}`;
|
|
48
|
+
if (process.platform === "linux") {
|
|
49
|
+
return readFileSync(`/proc/${pid}/environ`, "utf8").split("\0").includes(token);
|
|
50
|
+
}
|
|
51
|
+
const result = spawnSync("ps", ["-Eww", "-p", String(pid), "-o", "command="], {
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
timeout: 1_000,
|
|
54
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
55
|
+
});
|
|
56
|
+
return result.status === 0 && result.stdout.split(/\s+/).includes(token);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
package/dist/utils/shell.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare function getShellEnv(): NodeJS.ProcessEnv;
|
|
|
21
21
|
* - Characters with undefined code points
|
|
22
22
|
*/
|
|
23
23
|
export declare function sanitizeBinaryOutput(str: string): string;
|
|
24
|
-
export declare function trackDetachedChildPid(pid: number): void;
|
|
24
|
+
export declare function trackDetachedChildPid(pid: number, terminate?: () => void): void;
|
|
25
25
|
export declare function untrackDetachedChildPid(pid: number): void;
|
|
26
26
|
export declare function killTrackedDetachedChildren(): void;
|
|
27
27
|
/**
|
package/dist/utils/shell.js
CHANGED
|
@@ -153,16 +153,16 @@ export function sanitizeBinaryOutput(str) {
|
|
|
153
153
|
* Detached child processes must be tracked so they can be killed on parent
|
|
154
154
|
* shutdown signals (SIGHUP/SIGTERM).
|
|
155
155
|
*/
|
|
156
|
-
const trackedDetachedChildPids = new
|
|
157
|
-
export function trackDetachedChildPid(pid) {
|
|
158
|
-
trackedDetachedChildPids.
|
|
156
|
+
const trackedDetachedChildPids = new Map();
|
|
157
|
+
export function trackDetachedChildPid(pid, terminate = () => killProcessTree(pid)) {
|
|
158
|
+
trackedDetachedChildPids.set(pid, terminate);
|
|
159
159
|
}
|
|
160
160
|
export function untrackDetachedChildPid(pid) {
|
|
161
161
|
trackedDetachedChildPids.delete(pid);
|
|
162
162
|
}
|
|
163
163
|
export function killTrackedDetachedChildren() {
|
|
164
|
-
for (const
|
|
165
|
-
|
|
164
|
+
for (const terminate of trackedDetachedChildPids.values()) {
|
|
165
|
+
terminate();
|
|
166
166
|
}
|
|
167
167
|
trackedDetachedChildPids.clear();
|
|
168
168
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"name": "@diffexai/diffex",
|
|
4
|
-
"version": "0.3.
|
|
5
|
-
"sourceCommit": "
|
|
4
|
+
"version": "0.3.2",
|
|
5
|
+
"sourceCommit": "57dbba8a810d2e4cc81e48a30a4f5736e0e2d5bf",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"portions": "Diffex contributions; Pi-derived portions retain MIT terms in LICENSE",
|
|
8
8
|
"notice": "LICENSE",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"name": "@diffexai/diffex-evolution",
|
|
13
|
-
"version": "0.3.
|
|
13
|
+
"version": "0.3.2",
|
|
14
14
|
"license": "Apache-2.0",
|
|
15
15
|
"portions": "dist/vendor/evolution: runtime JavaScript and declarations",
|
|
16
16
|
"notice": "LICENSE",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"name": "@diffexai/diffex-harness-trace",
|
|
21
|
-
"version": "0.3.
|
|
21
|
+
"version": "0.3.2",
|
|
22
22
|
"license": "Apache-2.0",
|
|
23
23
|
"portions": "dist/vendor/harness-trace: runtime JavaScript and declarations",
|
|
24
24
|
"notice": "LICENSE",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
},
|
|
135
135
|
{
|
|
136
136
|
"name": "@diffexai/diffex-agent-core",
|
|
137
|
-
"version": "0.3.
|
|
137
|
+
"version": "0.3.2",
|
|
138
138
|
"license": "Apache-2.0",
|
|
139
139
|
"portions": "dist/node_modules/@diffexai/diffex-agent-core: bundled runtime, declarations, approved assets and native prebuilds",
|
|
140
140
|
"notice": "dist/node_modules/@diffexai/diffex-agent-core/LICENSE",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
},
|
|
143
143
|
{
|
|
144
144
|
"name": "@diffexai/diffex-ai",
|
|
145
|
-
"version": "0.3.
|
|
145
|
+
"version": "0.3.2",
|
|
146
146
|
"license": "Apache-2.0",
|
|
147
147
|
"portions": "dist/node_modules/@diffexai/diffex-ai: bundled runtime, declarations, approved assets and native prebuilds",
|
|
148
148
|
"notice": "dist/node_modules/@diffexai/diffex-ai/LICENSE",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
"name": "@diffexai/diffex-client",
|
|
153
|
-
"version": "0.3.
|
|
153
|
+
"version": "0.3.2",
|
|
154
154
|
"license": "Apache-2.0",
|
|
155
155
|
"portions": "dist/node_modules/@diffexai/diffex-client: bundled runtime, declarations, approved assets and native prebuilds",
|
|
156
156
|
"notice": "dist/node_modules/@diffexai/diffex-client/LICENSE",
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
160
|
"name": "@diffexai/diffex-harness-state",
|
|
161
|
-
"version": "0.3.
|
|
161
|
+
"version": "0.3.2",
|
|
162
162
|
"license": "Apache-2.0",
|
|
163
163
|
"portions": "dist/node_modules/@diffexai/diffex-harness-state: bundled runtime, declarations, approved assets and native prebuilds",
|
|
164
164
|
"notice": "dist/node_modules/@diffexai/diffex-harness-state/LICENSE",
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
},
|
|
167
167
|
{
|
|
168
168
|
"name": "@diffexai/diffex-protocol",
|
|
169
|
-
"version": "0.3.
|
|
169
|
+
"version": "0.3.2",
|
|
170
170
|
"license": "Apache-2.0",
|
|
171
171
|
"portions": "dist/node_modules/@diffexai/diffex-protocol: bundled runtime, declarations, approved assets and native prebuilds",
|
|
172
172
|
"notice": "dist/node_modules/@diffexai/diffex-protocol/LICENSE",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"name": "@diffexai/diffex-telemetry",
|
|
177
|
-
"version": "0.3.
|
|
177
|
+
"version": "0.3.2",
|
|
178
178
|
"license": "Apache-2.0",
|
|
179
179
|
"portions": "dist/node_modules/@diffexai/diffex-telemetry: bundled runtime, declarations, approved assets and native prebuilds",
|
|
180
180
|
"notice": "dist/node_modules/@diffexai/diffex-telemetry/LICENSE",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
},
|
|
183
183
|
{
|
|
184
184
|
"name": "@diffexai/diffex-tui",
|
|
185
|
-
"version": "0.3.
|
|
185
|
+
"version": "0.3.2",
|
|
186
186
|
"license": "Apache-2.0",
|
|
187
187
|
"portions": "dist/node_modules/@diffexai/diffex-tui: bundled runtime, declarations, approved assets and native prebuilds",
|
|
188
188
|
"notice": "dist/node_modules/@diffexai/diffex-tui/LICENSE",
|