agent-tower 0.6.0-beta.11 → 0.6.0-beta.13
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/dist/app.d.ts.map +1 -1
- package/dist/app.js +4 -0
- package/dist/app.js.map +1 -1
- package/dist/cli.js +39 -19
- package/dist/cli.js.map +1 -1
- package/dist/executors/__tests__/base.executor.test.js +133 -1
- package/dist/executors/__tests__/base.executor.test.js.map +1 -1
- package/dist/executors/__tests__/stdin-prompt.executors.test.js +18 -0
- package/dist/executors/__tests__/stdin-prompt.executors.test.js.map +1 -1
- package/dist/executors/base.executor.d.ts +8 -0
- package/dist/executors/base.executor.d.ts.map +1 -1
- package/dist/executors/base.executor.js +336 -56
- package/dist/executors/base.executor.js.map +1 -1
- package/dist/executors/index.d.ts +2 -1
- package/dist/executors/index.d.ts.map +1 -1
- package/dist/executors/index.js +1 -1
- package/dist/executors/index.js.map +1 -1
- package/dist/executors/start-error.d.ts +17 -0
- package/dist/executors/start-error.d.ts.map +1 -1
- package/dist/executors/start-error.js +36 -1
- package/dist/executors/start-error.js.map +1 -1
- package/dist/index.js +39 -29
- package/dist/index.js.map +1 -1
- package/dist/mcp/http-client.test.js +20 -0
- package/dist/mcp/http-client.test.js.map +1 -1
- package/dist/mcp/tools/__tests__/sessions.test.d.ts +2 -0
- package/dist/mcp/tools/__tests__/sessions.test.d.ts.map +1 -0
- package/dist/mcp/tools/__tests__/sessions.test.js +33 -0
- package/dist/mcp/tools/__tests__/sessions.test.js.map +1 -0
- package/dist/routes/__tests__/sessions-runtime.test.js +75 -3
- package/dist/routes/__tests__/sessions-runtime.test.js.map +1 -1
- package/dist/routes/conversations.d.ts.map +1 -1
- package/dist/routes/conversations.js +5 -1
- package/dist/routes/conversations.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +13 -2
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/team-runs.d.ts.map +1 -1
- package/dist/routes/team-runs.js +13 -1
- package/dist/routes/team-runs.js.map +1 -1
- package/dist/runtime/__tests__/acp-driver-lifecycle.test.js +86 -0
- package/dist/runtime/__tests__/acp-driver-lifecycle.test.js.map +1 -1
- package/dist/runtime/__tests__/acp-process-manager.test.js +393 -6
- package/dist/runtime/__tests__/acp-process-manager.test.js.map +1 -1
- package/dist/runtime/__tests__/cli-driver-lifecycle.test.d.ts +2 -0
- package/dist/runtime/__tests__/cli-driver-lifecycle.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/cli-driver-lifecycle.test.js +244 -0
- package/dist/runtime/__tests__/cli-driver-lifecycle.test.js.map +1 -0
- package/dist/runtime/__tests__/launch-cleanup-registry.test.d.ts +2 -0
- package/dist/runtime/__tests__/launch-cleanup-registry.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/launch-cleanup-registry.test.js +154 -0
- package/dist/runtime/__tests__/launch-cleanup-registry.test.js.map +1 -0
- package/dist/runtime/__tests__/runtime-coordinator.test.js +117 -1
- package/dist/runtime/__tests__/runtime-coordinator.test.js.map +1 -1
- package/dist/runtime/__tests__/server-entry-shutdown.test.d.ts +2 -0
- package/dist/runtime/__tests__/server-entry-shutdown.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/server-entry-shutdown.test.js +38 -0
- package/dist/runtime/__tests__/server-entry-shutdown.test.js.map +1 -0
- package/dist/runtime/__tests__/shutdown-coordinator.test.d.ts +2 -0
- package/dist/runtime/__tests__/shutdown-coordinator.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/shutdown-coordinator.test.js +28 -0
- package/dist/runtime/__tests__/shutdown-coordinator.test.js.map +1 -0
- package/dist/runtime/acp/acp-driver.d.ts.map +1 -1
- package/dist/runtime/acp/acp-driver.js +108 -35
- package/dist/runtime/acp/acp-driver.js.map +1 -1
- package/dist/runtime/acp/agents/managed-directory.d.ts.map +1 -1
- package/dist/runtime/acp/agents/managed-directory.js +3 -1
- package/dist/runtime/acp/agents/managed-directory.js.map +1 -1
- package/dist/runtime/acp/agents/managed-directory.test.d.ts +2 -0
- package/dist/runtime/acp/agents/managed-directory.test.d.ts.map +1 -0
- package/dist/runtime/acp/agents/managed-directory.test.js +25 -0
- package/dist/runtime/acp/agents/managed-directory.test.js.map +1 -0
- package/dist/runtime/acp/launch-cleanup-registry.d.ts +32 -0
- package/dist/runtime/acp/launch-cleanup-registry.d.ts.map +1 -0
- package/dist/runtime/acp/launch-cleanup-registry.js +176 -0
- package/dist/runtime/acp/launch-cleanup-registry.js.map +1 -0
- package/dist/runtime/acp/process-manager.d.ts +58 -0
- package/dist/runtime/acp/process-manager.d.ts.map +1 -1
- package/dist/runtime/acp/process-manager.js +489 -33
- package/dist/runtime/acp/process-manager.js.map +1 -1
- package/dist/runtime/cli-driver.d.ts.map +1 -1
- package/dist/runtime/cli-driver.js +230 -46
- package/dist/runtime/cli-driver.js.map +1 -1
- package/dist/runtime/contracts.d.ts +21 -2
- package/dist/runtime/contracts.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/runtime-coordinator.d.ts +8 -1
- package/dist/runtime/runtime-coordinator.d.ts.map +1 -1
- package/dist/runtime/runtime-coordinator.js +118 -18
- package/dist/runtime/runtime-coordinator.js.map +1 -1
- package/dist/runtime/server-entry-shutdown.d.ts +12 -0
- package/dist/runtime/server-entry-shutdown.d.ts.map +1 -0
- package/dist/runtime/server-entry-shutdown.js +23 -0
- package/dist/runtime/server-entry-shutdown.js.map +1 -0
- package/dist/runtime/shutdown-coordinator.d.ts +17 -0
- package/dist/runtime/shutdown-coordinator.d.ts.map +1 -0
- package/dist/runtime/shutdown-coordinator.js +67 -0
- package/dist/runtime/shutdown-coordinator.js.map +1 -0
- package/dist/services/__tests__/conversation.service.test.js +160 -0
- package/dist/services/__tests__/conversation.service.test.js.map +1 -1
- package/dist/services/__tests__/database-maintenance.service.test.js +97 -0
- package/dist/services/__tests__/database-maintenance.service.test.js.map +1 -1
- package/dist/services/__tests__/member-heartbeat-scheduler.test.js +6 -0
- package/dist/services/__tests__/member-heartbeat-scheduler.test.js.map +1 -1
- package/dist/services/__tests__/member-heartbeat.test.js +7 -11
- package/dist/services/__tests__/member-heartbeat.test.js.map +1 -1
- package/dist/services/__tests__/session-manager.lifecycle.test.js +402 -12
- package/dist/services/__tests__/session-manager.lifecycle.test.js.map +1 -1
- package/dist/services/__tests__/session-manager.team-run.test.js +422 -29
- package/dist/services/__tests__/session-manager.team-run.test.js.map +1 -1
- package/dist/services/__tests__/team-queue-recovery.integration.test.js +1 -0
- package/dist/services/__tests__/team-queue-recovery.integration.test.js.map +1 -1
- package/dist/services/__tests__/team-reconciler.service.test.js +1282 -4
- package/dist/services/__tests__/team-reconciler.service.test.js.map +1 -1
- package/dist/services/__tests__/team-run.service.test.js +161 -1
- package/dist/services/__tests__/team-run.service.test.js.map +1 -1
- package/dist/services/__tests__/team-scheduler.service.test.js +334 -6
- package/dist/services/__tests__/team-scheduler.service.test.js.map +1 -1
- package/dist/services/conversation.service.d.ts.map +1 -1
- package/dist/services/conversation.service.js +21 -2
- package/dist/services/conversation.service.js.map +1 -1
- package/dist/services/database-maintenance.service.d.ts.map +1 -1
- package/dist/services/database-maintenance.service.js +68 -17
- package/dist/services/database-maintenance.service.js.map +1 -1
- package/dist/services/member-heartbeat-scheduler.d.ts +6 -5
- package/dist/services/member-heartbeat-scheduler.d.ts.map +1 -1
- package/dist/services/member-heartbeat-scheduler.js +7 -5
- package/dist/services/member-heartbeat-scheduler.js.map +1 -1
- package/dist/services/session-manager.d.ts +124 -14
- package/dist/services/session-manager.d.ts.map +1 -1
- package/dist/services/session-manager.js +1035 -116
- package/dist/services/session-manager.js.map +1 -1
- package/dist/services/session-runtime-cleanup-gate.d.ts +25 -0
- package/dist/services/session-runtime-cleanup-gate.d.ts.map +1 -0
- package/dist/services/session-runtime-cleanup-gate.js +284 -0
- package/dist/services/session-runtime-cleanup-gate.js.map +1 -0
- package/dist/services/task.service.d.ts +2 -2
- package/dist/services/team-member-admission-barrier.d.ts +3 -0
- package/dist/services/team-member-admission-barrier.d.ts.map +1 -0
- package/dist/services/team-member-admission-barrier.js +26 -0
- package/dist/services/team-member-admission-barrier.js.map +1 -0
- package/dist/services/team-reconciler.service.d.ts +30 -7
- package/dist/services/team-reconciler.service.d.ts.map +1 -1
- package/dist/services/team-reconciler.service.js +528 -111
- package/dist/services/team-reconciler.service.js.map +1 -1
- package/dist/services/team-run.service.d.ts.map +1 -1
- package/dist/services/team-run.service.js +37 -13
- package/dist/services/team-run.service.js.map +1 -1
- package/dist/services/team-scheduler.service.d.ts +8 -6
- package/dist/services/team-scheduler.service.d.ts.map +1 -1
- package/dist/services/team-scheduler.service.js +323 -120
- package/dist/services/team-scheduler.service.js.map +1 -1
- package/dist/services/workspace-background-process-manager.d.ts.map +1 -1
- package/dist/services/workspace-background-process-manager.js +2 -5
- package/dist/services/workspace-background-process-manager.js.map +1 -1
- package/dist/services/workspace.service.d.ts +15 -8
- package/dist/services/workspace.service.d.ts.map +1 -1
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +27 -14
- package/dist/socket/index.js.map +1 -1
- package/dist/utils/__tests__/unix-process-identity.test.d.ts +2 -0
- package/dist/utils/__tests__/unix-process-identity.test.d.ts.map +1 -0
- package/dist/utils/__tests__/unix-process-identity.test.js +73 -0
- package/dist/utils/__tests__/unix-process-identity.test.js.map +1 -0
- package/dist/utils/error-log.d.ts +2 -0
- package/dist/utils/error-log.d.ts.map +1 -1
- package/dist/utils/error-log.js +40 -3
- package/dist/utils/error-log.js.map +1 -1
- package/dist/utils/error-log.test.js +14 -2
- package/dist/utils/error-log.test.js.map +1 -1
- package/dist/utils/process-launch.d.ts +2 -2
- package/dist/utils/process-launch.d.ts.map +1 -1
- package/dist/utils/process-launch.js +339 -79
- package/dist/utils/process-launch.js.map +1 -1
- package/dist/utils/process-launch.test.js +168 -10
- package/dist/utils/process-launch.test.js.map +1 -1
- package/dist/utils/spawned-process-identity.d.ts +7 -0
- package/dist/utils/spawned-process-identity.d.ts.map +1 -0
- package/dist/utils/spawned-process-identity.js +36 -0
- package/dist/utils/spawned-process-identity.js.map +1 -0
- package/dist/utils/tree-cleanup-channel.d.ts +18 -0
- package/dist/utils/tree-cleanup-channel.d.ts.map +1 -0
- package/dist/utils/tree-cleanup-channel.js +16 -0
- package/dist/utils/tree-cleanup-channel.js.map +1 -0
- package/dist/utils/tree-cleanup-channel.test.d.ts +2 -0
- package/dist/utils/tree-cleanup-channel.test.d.ts.map +1 -0
- package/dist/utils/tree-cleanup-channel.test.js +15 -0
- package/dist/utils/tree-cleanup-channel.test.js.map +1 -0
- package/dist/utils/unix-process-identity.d.ts +13 -1
- package/dist/utils/unix-process-identity.d.ts.map +1 -1
- package/dist/utils/unix-process-identity.js +146 -25
- package/dist/utils/unix-process-identity.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/types.d.ts +1 -0
- package/node_modules/@agent-tower/shared/dist/types.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260824000000_add_execution_process_ownership/migration.sql +10 -0
- package/prisma/migrations/20260824010000_add_runtime_cleanup_recovery/migration.sql +10 -0
- package/prisma/migrations/20260824020000_add_runtime_launch_admission/migration.sql +72 -0
- package/prisma/migrations/20260826000000_add_conversation_turn_queue/migration.sql +19 -0
- package/prisma/schema.prisma +50 -7
|
@@ -4,23 +4,58 @@ import path from 'node:path';
|
|
|
4
4
|
export function getNodeRuntimeCommand() {
|
|
5
5
|
return process.env.AGENT_TOWER_NODE_RUNTIME || process.execPath;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Electron packaged builds can use the Electron executable itself as a Node
|
|
9
|
+
* fallback when a bundled Node runtime is unavailable. That executable needs
|
|
10
|
+
* ELECTRON_RUN_AS_NODE; a real Node binary does not.
|
|
11
|
+
*/
|
|
12
|
+
function isStandaloneNodeRuntime(runtimeCommand) {
|
|
13
|
+
// `runtimeCommand` may be a Windows path even when this helper is exercised
|
|
14
|
+
// from a POSIX test process, so do not rely on the host platform's separator.
|
|
15
|
+
const executableName = runtimeCommand.replace(/^.*[\\/]/, '').toLowerCase();
|
|
16
|
+
return executableName === 'node' || executableName === 'node.exe';
|
|
17
|
+
}
|
|
7
18
|
export const PTY_WRAPPER_ENV_KEYS = [
|
|
8
19
|
'AGENT_TOWER_NODE_RUNTIME',
|
|
9
20
|
'ELECTRON_RUN_AS_NODE',
|
|
21
|
+
'AGENT_TOWER_TREE_CLEANUP_CHANNEL',
|
|
22
|
+
'AGENT_TOWER_TREE_CLEANUP_SECRET',
|
|
23
|
+
'AGENT_TOWER_PROCESS_IDENTITY',
|
|
24
|
+
'AGENT_TOWER_PTY_IDENTITY_SEED',
|
|
10
25
|
];
|
|
11
|
-
export function buildPtyWrapperEnv(agentEnv, parentEnv = process.env) {
|
|
26
|
+
export function buildPtyWrapperEnv(agentEnv, parentEnv = process.env, ownershipToken, cleanupChannel) {
|
|
12
27
|
const wrapperEnv = { ...agentEnv };
|
|
28
|
+
const runtimeCommand = parentEnv.AGENT_TOWER_NODE_RUNTIME || process.execPath;
|
|
29
|
+
const preserveElectronNodeMode = !isStandaloneNodeRuntime(runtimeCommand);
|
|
30
|
+
if (!preserveElectronNodeMode) {
|
|
31
|
+
delete wrapperEnv.ELECTRON_RUN_AS_NODE;
|
|
32
|
+
}
|
|
13
33
|
for (const key of PTY_WRAPPER_ENV_KEYS) {
|
|
34
|
+
if (key === 'AGENT_TOWER_TREE_CLEANUP_CHANNEL'
|
|
35
|
+
|| key === 'AGENT_TOWER_TREE_CLEANUP_SECRET'
|
|
36
|
+
|| key === 'AGENT_TOWER_PROCESS_IDENTITY'
|
|
37
|
+
|| key === 'AGENT_TOWER_PTY_IDENTITY_SEED'
|
|
38
|
+
// Electron's bootstrap marker is a parent-runtime implementation detail.
|
|
39
|
+
// It is only needed when the wrapper itself runs through Electron.
|
|
40
|
+
|| (key === 'ELECTRON_RUN_AS_NODE' && !preserveElectronNodeMode))
|
|
41
|
+
continue;
|
|
14
42
|
const value = parentEnv[key];
|
|
15
43
|
if (value !== undefined) {
|
|
16
44
|
wrapperEnv[key] = value;
|
|
17
45
|
}
|
|
18
46
|
}
|
|
47
|
+
if (ownershipToken) {
|
|
48
|
+
wrapperEnv.AGENT_TOWER_PROCESS_IDENTITY = ownershipToken;
|
|
49
|
+
wrapperEnv.AGENT_TOWER_PTY_IDENTITY_SEED = ownershipToken;
|
|
50
|
+
}
|
|
51
|
+
// Completion is parent-owned and intentionally has no environment
|
|
52
|
+
// representation. Keep this argument for API compatibility, but never copy
|
|
53
|
+
// endpoint/secret material into a wrapper or Agent environment.
|
|
54
|
+
void cleanupChannel;
|
|
19
55
|
return wrapperEnv;
|
|
20
56
|
}
|
|
21
57
|
const PTY_WRAPPER_SCRIPT = String.raw `
|
|
22
58
|
const { spawn, spawnSync } = require('node:child_process');
|
|
23
|
-
const { randomBytes } = require('node:crypto');
|
|
24
59
|
const { createReadStream, unlinkSync } = require('node:fs');
|
|
25
60
|
|
|
26
61
|
const [mode, programPath, ...rest] = process.argv.slice(1);
|
|
@@ -30,24 +65,28 @@ const internalEnvKeys = ${JSON.stringify(PTY_WRAPPER_ENV_KEYS)};
|
|
|
30
65
|
const processIdentityEnvKey = 'AGENT_TOWER_PROCESS_IDENTITY';
|
|
31
66
|
const processIdentitySeedEnvKey = 'AGENT_TOWER_PTY_IDENTITY_SEED';
|
|
32
67
|
const processIdentityToken = process.env[processIdentitySeedEnvKey]
|
|
33
|
-
||
|
|
68
|
+
|| process.env[processIdentityEnvKey];
|
|
34
69
|
|
|
35
70
|
let child;
|
|
36
71
|
let cleanupTarget = null;
|
|
37
|
-
const sentSignals = new Set();
|
|
38
72
|
let forceKillTimer = null;
|
|
39
73
|
let treeExitPoll = null;
|
|
40
74
|
let finishing = false;
|
|
41
75
|
let groupIdentityTimers = [];
|
|
42
76
|
const trackedGroupMembers = new Map();
|
|
77
|
+
const trackedWindowsMembers = new Map();
|
|
78
|
+
let identityIncomplete = false;
|
|
79
|
+
let childExited = false;
|
|
43
80
|
|
|
44
81
|
function getChildEnv() {
|
|
45
82
|
const env = { ...process.env };
|
|
46
83
|
for (const key of internalEnvKeys) {
|
|
84
|
+
if (key === processIdentityEnvKey) continue;
|
|
47
85
|
delete env[key];
|
|
48
86
|
}
|
|
49
87
|
delete env[processIdentitySeedEnvKey];
|
|
50
|
-
|
|
88
|
+
// Keep the ownership marker in Agent descendants. It is only an ownership
|
|
89
|
+
// label used for process discovery, never a completion capability.
|
|
51
90
|
return env;
|
|
52
91
|
}
|
|
53
92
|
|
|
@@ -60,58 +99,105 @@ function cleanup() {
|
|
|
60
99
|
try { unlinkSync(target); } catch {}
|
|
61
100
|
}
|
|
62
101
|
|
|
63
|
-
function
|
|
64
|
-
if (
|
|
65
|
-
const
|
|
66
|
-
encoding: 'utf8',
|
|
67
|
-
windowsHide: true,
|
|
68
|
-
});
|
|
69
|
-
if (base.status !== 0 || typeof base.stdout !== 'string') return [];
|
|
70
|
-
const groupPids = base.stdout.split('\n').map((line) => {
|
|
71
|
-
const match = /^\s*(\d+)\s+(\d+)\s+(\d+)\s*$/.exec(line);
|
|
72
|
-
return match && Number(match[3]) === child.pid ? Number(match[1]) : null;
|
|
73
|
-
}).filter(Boolean);
|
|
74
|
-
if (groupPids.length === 0) return [];
|
|
75
|
-
const result = spawnSync('ps', [
|
|
76
|
-
'eww',
|
|
77
|
-
'-p',
|
|
78
|
-
groupPids.join(','),
|
|
79
|
-
'-o',
|
|
80
|
-
'pid=,ppid=,pgid=,lstart=,command=',
|
|
81
|
-
], {
|
|
82
|
-
encoding: 'utf8',
|
|
83
|
-
windowsHide: true,
|
|
84
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
85
|
-
});
|
|
86
|
-
if (result.status !== 0 || typeof result.stdout !== 'string') return [];
|
|
87
|
-
return result.stdout.split('\n').map((line) => {
|
|
102
|
+
function parseProcessRows(stdout) {
|
|
103
|
+
if (typeof stdout !== 'string' || !stdout.trim()) return null;
|
|
104
|
+
const rows = stdout.split('\n').filter((line) => line.trim()).map((line) => {
|
|
88
105
|
const match = /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\S+\s+\S+\s+\d+\s+\d\d:\d\d:\d\d\s+\d{4})\s+(.*)$/.exec(line);
|
|
89
|
-
const token = match
|
|
90
|
-
? new RegExp('(?:^|\\s)' + processIdentityEnvKey + '=([^\\s]+)').exec(match[5])?.[1]
|
|
91
|
-
: null;
|
|
92
106
|
return match ? {
|
|
93
107
|
pid: Number(match[1]),
|
|
94
108
|
ppid: Number(match[2]),
|
|
95
109
|
pgid: Number(match[3]),
|
|
96
|
-
birthIdentity: match[4]
|
|
97
|
-
|
|
110
|
+
birthIdentity: match[4],
|
|
111
|
+
command: match[5],
|
|
98
112
|
} : null;
|
|
99
|
-
})
|
|
113
|
+
});
|
|
114
|
+
return rows.length > 0 && !rows.some((row) => !row) ? rows : null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function readProcessTable() {
|
|
118
|
+
if (!child || isWin) return { status: 'IDENTITY_INCOMPLETE', rows: [], complete: false };
|
|
119
|
+
const probeEnv = { ...process.env };
|
|
120
|
+
delete probeEnv[processIdentityEnvKey];
|
|
121
|
+
delete probeEnv[processIdentitySeedEnvKey];
|
|
122
|
+
// 'lstart' is parsed below as a stable process birth identity. Force the
|
|
123
|
+
// portable C layout even when the server inherits a localized user env.
|
|
124
|
+
probeEnv.LC_ALL = 'C';
|
|
125
|
+
probeEnv.LANG = 'C';
|
|
126
|
+
const base = spawnSync('ps', ['eww', '-axo', 'pid=,ppid=,pgid=,lstart=,command='], {
|
|
127
|
+
encoding: 'utf8',
|
|
128
|
+
windowsHide: true,
|
|
129
|
+
maxBuffer: 256 * 1024 * 1024,
|
|
130
|
+
env: probeEnv,
|
|
131
|
+
});
|
|
132
|
+
if (base.error || base.status !== 0 || typeof base.stdout !== 'string' || !base.stdout.trim()) {
|
|
133
|
+
return { status: 'PROBE_UNAVAILABLE', rows: [], complete: false };
|
|
134
|
+
}
|
|
135
|
+
const rows = parseProcessRows(base.stdout);
|
|
136
|
+
if (!rows) {
|
|
137
|
+
return { status: 'IDENTITY_INCOMPLETE', rows: [], complete: false };
|
|
138
|
+
}
|
|
139
|
+
if (rows.length > 16_384) {
|
|
140
|
+
return { status: 'IDENTITY_INCOMPLETE', rows: [], complete: false };
|
|
141
|
+
}
|
|
142
|
+
const owned = rows.filter((row) => (
|
|
143
|
+
row.pid !== process.pid
|
|
144
|
+
&& row.command.includes(processIdentityEnvKey + '=' + processIdentityToken)
|
|
145
|
+
));
|
|
146
|
+
// The complete flag distinguishes a valid system snapshot with no marker-bearing
|
|
147
|
+
// rows from an empty/failed probe. Only the former can prove that an
|
|
148
|
+
// already-observed child has no remaining owned descendants.
|
|
149
|
+
// Keep the complete process table as well as the marker-bearing owner rows.
|
|
150
|
+
// Native agent launchers are allowed to scrub this marker from descendants;
|
|
151
|
+
// ownership is established by a marked root and then expanded through its
|
|
152
|
+
// process group / parent-child edges below.
|
|
153
|
+
return { status: 'ALIVE', rows, owned, complete: true };
|
|
100
154
|
}
|
|
101
155
|
|
|
102
156
|
function captureProcessGroupIdentity() {
|
|
103
157
|
if (!child || isWin) return;
|
|
104
|
-
const
|
|
105
|
-
|
|
158
|
+
const probe = readProcessTable();
|
|
159
|
+
if (probe.status !== 'ALIVE') return;
|
|
106
160
|
const trackedLeader = trackedGroupMembers.get(child.pid);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
161
|
+
const leader = probe.owned.find((row) => row.pid === child.pid);
|
|
162
|
+
// A short-lived launcher can disappear before the first scheduled ps
|
|
163
|
+
// snapshot. The launch token is unique to this wrapper, so visible marker
|
|
164
|
+
// rows are still valid ownership evidence even when the direct leader row
|
|
165
|
+
// has already exited. If the leader was observed before, reject a birth
|
|
166
|
+
// identity change (PID reuse) rather than widening the owner set.
|
|
167
|
+
if (trackedLeader && (!leader || trackedLeader.birthIdentity !== leader.birthIdentity)) return;
|
|
168
|
+
const ownedPids = new Set(probe.owned.map((row) => row.pid));
|
|
169
|
+
const ownedGroups = new Set(probe.owned.map((row) => row.pgid));
|
|
170
|
+
let changed = true;
|
|
171
|
+
while (changed) {
|
|
172
|
+
changed = false;
|
|
173
|
+
for (const row of probe.rows) {
|
|
174
|
+
if (ownedPids.has(row.pid) || !ownedPids.has(row.ppid)) continue;
|
|
175
|
+
ownedPids.add(row.pid);
|
|
176
|
+
changed = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const row of probe.rows) {
|
|
180
|
+
if (!ownedPids.has(row.pid) && !ownedGroups.has(row.pgid)) continue;
|
|
181
|
+
const existing = trackedGroupMembers.get(row.pid);
|
|
182
|
+
if (existing && existing.birthIdentity !== row.birthIdentity) {
|
|
183
|
+
identityIncomplete = true;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
trackedGroupMembers.set(row.pid, { pgid: row.pgid, birthIdentity: row.birthIdentity });
|
|
110
187
|
}
|
|
111
188
|
}
|
|
112
189
|
|
|
113
190
|
function scheduleProcessGroupIdentityCapture() {
|
|
114
|
-
if (!child
|
|
191
|
+
if (!child) return;
|
|
192
|
+
if (isWin) {
|
|
193
|
+
captureWindowsTree();
|
|
194
|
+
for (const delay of [50, 250, 1000, 5000]) {
|
|
195
|
+
const timer = setTimeout(captureWindowsTree, delay);
|
|
196
|
+
if (timer.unref) timer.unref();
|
|
197
|
+
groupIdentityTimers.push(timer);
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
115
201
|
// Capture synchronously while the group leader is still our known child.
|
|
116
202
|
// Fast commands may spawn a background process and exit before a zero-delay
|
|
117
203
|
// timer runs, leaving no trustworthy identity from which to sweep the group.
|
|
@@ -125,23 +211,47 @@ function scheduleProcessGroupIdentityCapture() {
|
|
|
125
211
|
|
|
126
212
|
function captureRemainingProcessGroupIdentity() {
|
|
127
213
|
if (!child || isWin) return;
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
214
|
+
const probe = readProcessTable();
|
|
215
|
+
if (probe.status !== 'ALIVE') return;
|
|
216
|
+
// Seed from any marker-bearing rows that are still visible. This matters
|
|
217
|
+
// when the direct launcher exits before the first capture but a native
|
|
218
|
+
// descendant remains alive and carries the launch token.
|
|
219
|
+
const trackedPids = new Set([
|
|
220
|
+
...trackedGroupMembers.keys(),
|
|
221
|
+
...probe.owned.map((row) => row.pid),
|
|
222
|
+
]);
|
|
223
|
+
const trackedGroups = new Set([
|
|
224
|
+
...[...trackedGroupMembers.values()].map((member) => member.pgid),
|
|
225
|
+
...probe.owned.map((row) => row.pgid),
|
|
226
|
+
]);
|
|
227
|
+
let changed = true;
|
|
228
|
+
while (changed) {
|
|
229
|
+
changed = false;
|
|
230
|
+
for (const row of probe.rows) {
|
|
231
|
+
if (trackedPids.has(row.pid) || !trackedPids.has(row.ppid)) continue;
|
|
232
|
+
trackedPids.add(row.pid);
|
|
233
|
+
trackedGroups.add(row.pgid);
|
|
234
|
+
changed = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
for (const row of probe.rows) {
|
|
238
|
+
if (!trackedPids.has(row.pid) && !trackedGroups.has(row.pgid)) continue;
|
|
239
|
+
const existing = trackedGroupMembers.get(row.pid);
|
|
240
|
+
if (existing && existing.birthIdentity !== row.birthIdentity) {
|
|
241
|
+
identityIncomplete = true;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (!existing) trackedGroupMembers.set(row.pid, { pgid: row.pgid, birthIdentity: row.birthIdentity });
|
|
138
245
|
}
|
|
139
246
|
}
|
|
140
247
|
|
|
141
248
|
function matchingTrackedGroupMembers() {
|
|
142
249
|
if (!child || isWin || trackedGroupMembers.size === 0) return [];
|
|
143
|
-
|
|
144
|
-
|
|
250
|
+
const probe = readProcessTable();
|
|
251
|
+
if (probe.status !== 'ALIVE') return null;
|
|
252
|
+
return probe.rows.filter((row) => (
|
|
253
|
+
trackedGroupMembers.get(row.pid)?.pgid === row.pgid
|
|
254
|
+
&& trackedGroupMembers.get(row.pid)?.birthIdentity === row.birthIdentity
|
|
145
255
|
));
|
|
146
256
|
}
|
|
147
257
|
|
|
@@ -150,30 +260,139 @@ const unixIdentityAdapter = {
|
|
|
150
260
|
captureRemainingGroup: captureRemainingProcessGroupIdentity,
|
|
151
261
|
matchingGroupMembers: matchingTrackedGroupMembers,
|
|
152
262
|
signalGroup(signal) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
263
|
+
const members = matchingTrackedGroupMembers();
|
|
264
|
+
if (!members || members.length === 0) return false;
|
|
265
|
+
let signalled = false;
|
|
266
|
+
for (const pgid of new Set(members.map((row) => row.pgid))) {
|
|
267
|
+
try {
|
|
268
|
+
process.kill(-pgid, signal);
|
|
269
|
+
signalled = true;
|
|
270
|
+
} catch {}
|
|
159
271
|
}
|
|
272
|
+
return signalled;
|
|
160
273
|
},
|
|
161
274
|
isGroupAlive() {
|
|
162
|
-
|
|
275
|
+
const members = matchingTrackedGroupMembers();
|
|
276
|
+
return members !== null && members.length > 0;
|
|
277
|
+
},
|
|
278
|
+
groupState() {
|
|
279
|
+
if (!child || isWin) return 'IDENTITY_INCOMPLETE';
|
|
280
|
+
const probe = readProcessTable();
|
|
281
|
+
if (probe.status !== 'ALIVE') return probe.status;
|
|
282
|
+
if (identityIncomplete) return 'IDENTITY_INCOMPLETE';
|
|
283
|
+
if (trackedGroupMembers.size === 0) {
|
|
284
|
+
// A complete system snapshot after the direct child exit and with no
|
|
285
|
+
// marker-bearing descendants is the only fast-exit exception. Empty or
|
|
286
|
+
// malformed probes fail closed; there is no safe inference from an empty result.
|
|
287
|
+
return childExited && probe.complete ? 'CLEAN_EMPTY' : 'IDENTITY_INCOMPLETE';
|
|
288
|
+
}
|
|
289
|
+
const matches = probe.rows.filter((row) => (
|
|
290
|
+
trackedGroupMembers.get(row.pid)?.pgid === row.pgid
|
|
291
|
+
&& trackedGroupMembers.get(row.pid)?.birthIdentity === row.birthIdentity
|
|
292
|
+
));
|
|
293
|
+
return matches.length > 0 ? 'ALIVE' : 'CLEAN_EMPTY';
|
|
163
294
|
},
|
|
164
295
|
};
|
|
165
296
|
|
|
297
|
+
function terminateWindowsTree() {
|
|
298
|
+
if (!child || !isWin || child.pid == null) return false;
|
|
299
|
+
try {
|
|
300
|
+
const result = spawnSync('taskkill', ['/PID', String(child.pid), '/T', '/F'], {
|
|
301
|
+
stdio: 'ignore',
|
|
302
|
+
windowsHide: true,
|
|
303
|
+
});
|
|
304
|
+
return result.status === 0;
|
|
305
|
+
} catch {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function readWindowsProcessRows() {
|
|
311
|
+
if (!isWin) return { status: 'IDENTITY_INCOMPLETE', rows: [] };
|
|
312
|
+
try {
|
|
313
|
+
const result = spawnSync('powershell.exe', [
|
|
314
|
+
'-NoProfile',
|
|
315
|
+
'-NonInteractive',
|
|
316
|
+
'-Command',
|
|
317
|
+
'Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CreationDate | ConvertTo-Json -Compress',
|
|
318
|
+
], { encoding: 'utf8', windowsHide: true, maxBuffer: 16 * 1024 * 1024 });
|
|
319
|
+
if (result.error || result.status !== 0 || typeof result.stdout !== 'string') {
|
|
320
|
+
return { status: 'PROBE_UNAVAILABLE', rows: [] };
|
|
321
|
+
}
|
|
322
|
+
if (!result.stdout.trim()) return { status: 'IDENTITY_INCOMPLETE', rows: [] };
|
|
323
|
+
const parsed = JSON.parse(result.stdout);
|
|
324
|
+
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
325
|
+
const normalized = rows.map((row) => ({
|
|
326
|
+
pid: Number(row.ProcessId),
|
|
327
|
+
ppid: Number(row.ParentProcessId),
|
|
328
|
+
birthMarker: String(row.CreationDate || ''),
|
|
329
|
+
}));
|
|
330
|
+
if (normalized.some((row) => row.pid <= 0 || row.ppid < 0 || !row.birthMarker)) {
|
|
331
|
+
return { status: 'IDENTITY_INCOMPLETE', rows: [] };
|
|
332
|
+
}
|
|
333
|
+
return { status: 'ALIVE', rows: normalized };
|
|
334
|
+
} catch {
|
|
335
|
+
return { status: 'PROBE_UNAVAILABLE', rows: [] };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function captureWindowsTree() {
|
|
340
|
+
if (!child || !isWin || child.pid == null) return;
|
|
341
|
+
const probe = readWindowsProcessRows();
|
|
342
|
+
if (probe.status !== 'ALIVE') return;
|
|
343
|
+
const rows = probe.rows;
|
|
344
|
+
const descendants = new Set([child.pid]);
|
|
345
|
+
let changed = true;
|
|
346
|
+
while (changed) {
|
|
347
|
+
changed = false;
|
|
348
|
+
for (const row of rows) {
|
|
349
|
+
if (descendants.has(row.pid) || !descendants.has(row.ppid)) continue;
|
|
350
|
+
descendants.add(row.pid);
|
|
351
|
+
changed = true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
for (const row of rows) {
|
|
355
|
+
if (descendants.has(row.pid)) {
|
|
356
|
+
const existing = trackedWindowsMembers.get(row.pid);
|
|
357
|
+
if (!existing || existing === row.birthMarker) trackedWindowsMembers.set(row.pid, row.birthMarker);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function windowsTreeAlive() {
|
|
363
|
+
if (!child || !isWin) return false;
|
|
364
|
+
const probe = readWindowsProcessRows();
|
|
365
|
+
if (probe.status !== 'ALIVE') return true;
|
|
366
|
+
if (trackedWindowsMembers.size === 0) return false;
|
|
367
|
+
const rows = probe.rows;
|
|
368
|
+
return [...trackedWindowsMembers].some(([pid, birthMarker]) => rows.some((row) => (
|
|
369
|
+
row.pid === pid && row.birthMarker === birthMarker
|
|
370
|
+
)));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function windowsTreeState() {
|
|
374
|
+
if (!child || !isWin) return 'IDENTITY_INCOMPLETE';
|
|
375
|
+
const probe = readWindowsProcessRows();
|
|
376
|
+
if (probe.status !== 'ALIVE') return probe.status;
|
|
377
|
+
if (trackedWindowsMembers.size === 0) return 'IDENTITY_INCOMPLETE';
|
|
378
|
+
const alive = [...trackedWindowsMembers].some(([pid, birthMarker]) => probe.rows.some((row) => (
|
|
379
|
+
row.pid === pid && row.birthMarker === birthMarker
|
|
380
|
+
)));
|
|
381
|
+
return alive ? 'ALIVE' : 'CLEAN_EMPTY';
|
|
382
|
+
}
|
|
383
|
+
|
|
166
384
|
// 终止 child 及其整个进程组。
|
|
167
385
|
// Unix 下 child 以 detached 启动(pgid === child.pid),组播信号可覆盖
|
|
168
386
|
// child 派生的整棵子树(pnpm dev、tsc --watch 等),防止孙进程被 init
|
|
169
387
|
// 收养成为孤儿。同一信号只发送一次;每次组播前重新校验组成员的
|
|
170
388
|
// birth identity 与本次 launch token,身份不匹配时拒绝发送。
|
|
171
|
-
// Windows
|
|
389
|
+
// Windows 使用 taskkill /T /F 处理整个 descendant tree。
|
|
172
390
|
function killTree(signal) {
|
|
173
|
-
if (!child
|
|
174
|
-
sentSignals.add(signal);
|
|
391
|
+
if (!child) return;
|
|
175
392
|
if (isWin) {
|
|
176
|
-
|
|
393
|
+
// Keep the wrapper alive until the child handle settles. A root exit by
|
|
394
|
+
// itself is not tree-cleanup evidence; taskkill owns the descendant kill.
|
|
395
|
+
if (!terminateWindowsTree() && !child.killed) {
|
|
177
396
|
try { child.kill(signal); } catch {}
|
|
178
397
|
}
|
|
179
398
|
return;
|
|
@@ -182,6 +401,19 @@ function killTree(signal) {
|
|
|
182
401
|
unixIdentityAdapter.captureGroup();
|
|
183
402
|
}
|
|
184
403
|
unixIdentityAdapter.signalGroup(signal);
|
|
404
|
+
// The direct child handle is still authoritative while Node reports it
|
|
405
|
+
// alive. Detached Unix children have their own PGID equal to child.pid, so
|
|
406
|
+
// this fallback reaches launchers that scrub the ownership marker before
|
|
407
|
+
// the process-table capture observes them (for example Codex's native
|
|
408
|
+
// launcher). It never targets a reused PID after the child has exited.
|
|
409
|
+
if (child.exitCode === null && child.signalCode === null && child.pid != null) {
|
|
410
|
+
try { process.kill(-child.pid, signal); } catch {}
|
|
411
|
+
// Some launchers replace the detached process-group leader or report a
|
|
412
|
+
// stale group while Node still owns the child handle. Signalling the
|
|
413
|
+
// handle is race-safe (it cannot target a reused PID) and makes the
|
|
414
|
+
// wrapper observe the child exit so its cleanup state machine can finish.
|
|
415
|
+
try { child['kill'](signal); } catch {}
|
|
416
|
+
}
|
|
185
417
|
}
|
|
186
418
|
|
|
187
419
|
// 收到终止信号后兜底:5 秒内进程组未退干净则升级为 SIGKILL。
|
|
@@ -198,36 +430,63 @@ function childProcessGroupExists() {
|
|
|
198
430
|
return unixIdentityAdapter.isGroupAlive();
|
|
199
431
|
}
|
|
200
432
|
|
|
201
|
-
function exitWithChildResult(code, signal) {
|
|
433
|
+
async function exitWithChildResult(code, signal) {
|
|
202
434
|
if (finishing) return;
|
|
203
435
|
finishing = true;
|
|
436
|
+
childExited = true;
|
|
204
437
|
// The group leader may already be reaped. Capture the remaining members with
|
|
205
438
|
// birth identities once, then every poll/signal revalidates those identities
|
|
206
439
|
// so a later PGID/PID reuse cannot be mistaken for this process tree.
|
|
207
440
|
unixIdentityAdapter.captureRemainingGroup();
|
|
441
|
+
captureWindowsTree();
|
|
208
442
|
cleanup();
|
|
209
443
|
// child 已退出:清扫其进程组内残留的后台孙进程(dev server、watch 等)。
|
|
210
|
-
// SIGHUP 与 PTY 关闭语义一致。Unix wrapper
|
|
444
|
+
// SIGHUP 与 PTY 关闭语义一致。Unix wrapper 必须等到所有 marker-owned groups 消失后才能退出,
|
|
211
445
|
// 否则 PTY owner 会把 wrapper exit 误判为进程树已清空。
|
|
212
446
|
killTree('SIGHUP');
|
|
213
447
|
const exitCode = typeof code === 'number' ? code : signal ? 1 : 0;
|
|
214
|
-
|
|
448
|
+
const initialState = isWin ? windowsTreeState() : unixIdentityAdapter.groupState();
|
|
449
|
+
if (initialState === 'CLEAN_EMPTY') {
|
|
450
|
+
process.exit(exitCode);
|
|
451
|
+
}
|
|
215
452
|
|
|
216
453
|
scheduleForceKill();
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
454
|
+
const pollTree = async (attempt = 0) => {
|
|
455
|
+
// Descendants may call setsid or fork after the root exit. Refresh the
|
|
456
|
+
// marker-owned identity set before every state decision and signal every
|
|
457
|
+
// known group, rather than freezing the initial PGID snapshot.
|
|
458
|
+
unixIdentityAdapter.captureRemainingGroup();
|
|
459
|
+
captureWindowsTree();
|
|
460
|
+
const state = isWin ? windowsTreeState() : unixIdentityAdapter.groupState();
|
|
461
|
+
if (state === 'CLEAN_EMPTY') {
|
|
462
|
+
if (forceKillTimer) clearTimeout(forceKillTimer);
|
|
463
|
+
forceKillTimer = null;
|
|
464
|
+
process.exit(exitCode);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
killTree(attempt >= 5 ? 'SIGKILL' : 'SIGHUP');
|
|
468
|
+
scheduleTreePoll(attempt + 1);
|
|
469
|
+
};
|
|
470
|
+
const scheduleTreePoll = (attempt) => {
|
|
471
|
+
const delay = [50, 100, 250, 500, 1_000, 2_000, 5_000][Math.min(attempt, 6)];
|
|
472
|
+
treeExitPoll = setTimeout(() => {
|
|
473
|
+
treeExitPoll = null;
|
|
474
|
+
void pollTree(attempt);
|
|
475
|
+
}, delay);
|
|
476
|
+
};
|
|
477
|
+
scheduleTreePoll(0);
|
|
225
478
|
}
|
|
226
479
|
|
|
227
480
|
function exitWithError(error) {
|
|
228
|
-
cleanup();
|
|
229
481
|
const message = error instanceof Error ? error.message : String(error);
|
|
230
482
|
console.error(message);
|
|
483
|
+
if (child) {
|
|
484
|
+
// Every post-spawn error shares the same tree cleanup state machine. A
|
|
485
|
+
// direct process.exit here would strand detached descendants.
|
|
486
|
+
void exitWithChildResult(1);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
cleanup();
|
|
231
490
|
process.exit(1);
|
|
232
491
|
}
|
|
233
492
|
|
|
@@ -314,7 +573,7 @@ if (mode === 'pipe-file') {
|
|
|
314
573
|
|
|
315
574
|
function exitWithPipeError(error) {
|
|
316
575
|
killTree('SIGTERM');
|
|
317
|
-
afterInputClosed(() =>
|
|
576
|
+
afterInputClosed(() => exitWithChildResult(1));
|
|
318
577
|
}
|
|
319
578
|
|
|
320
579
|
child = isCmdBat
|
|
@@ -323,7 +582,8 @@ if (mode === 'pipe-file') {
|
|
|
323
582
|
scheduleProcessGroupIdentityCapture();
|
|
324
583
|
|
|
325
584
|
child.on('error', (error) => {
|
|
326
|
-
|
|
585
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
586
|
+
afterInputClosed(() => exitWithChildResult(1));
|
|
327
587
|
});
|
|
328
588
|
child.on('exit', finishWithChildResult);
|
|
329
589
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-launch.js","sourceRoot":"","sources":["../../src/utils/process-launch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAO7B,MAAM,UAAU,qBAAqB;IACnC,OAAO,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,OAAO,CAAC,QAAQ,CAAC;AAClE,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,0BAA0B;IAC1B,sBAAsB;
|
|
1
|
+
{"version":3,"file":"process-launch.js","sourceRoot":"","sources":["../../src/utils/process-launch.ts"],"names":[],"mappings":"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"}
|