@neuralnomads/codenomad-dev 0.18.0-dev-20260716-40cee071 → 0.18.0-dev-20260720-4c50829d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/auth/manager.js +1 -1
  2. package/dist/filesystem/__tests__/search-cache.test.js +5 -5
  3. package/dist/filesystem/search-cache.js +1 -1
  4. package/dist/index.js +42 -0
  5. package/dist/index.test.js +40 -10
  6. package/dist/opencode-update/service.js +150 -0
  7. package/dist/opencode-update/service.test.js +107 -0
  8. package/dist/permissions/auto-accept-manager.js +165 -0
  9. package/dist/permissions/auto-accept-manager.test.js +208 -0
  10. package/dist/permissions/auto-accept-store.js +5 -2
  11. package/dist/permissions/opencode-yolo-metadata.js +81 -0
  12. package/dist/permissions/opencode-yolo-metadata.test.js +54 -0
  13. package/dist/server/__tests__/remote-proxy.test.js +64 -56
  14. package/dist/server/http-server.js +12 -15
  15. package/dist/server/remote-proxy.js +68 -98
  16. package/dist/server/routes/opencode-update.js +37 -0
  17. package/dist/server/routes/opencode-update.test.js +34 -0
  18. package/dist/server/routes/remote-servers.js +1 -1
  19. package/dist/server/routes/workspaces.test.js +38 -0
  20. package/dist/server/routes/worktrees.js +19 -0
  21. package/dist/server/routes/yolo.js +2 -1
  22. package/dist/server/tls.js +2 -2
  23. package/dist/settings/binaries.test.js +2 -7
  24. package/dist/shutdown.js +67 -59
  25. package/dist/shutdown.test.js +115 -78
  26. package/dist/ui/remote-ui.js +2 -2
  27. package/dist/usage/providers/api-key.js +3 -3
  28. package/dist/usage/providers/google.js +1 -1
  29. package/dist/usage/providers/oauth.js +1 -36
  30. package/dist/usage/providers/special.js +3 -3
  31. package/dist/usage/service.js +1 -1
  32. package/dist/usage/service.test.js +5 -3
  33. package/dist/usage/shared.js +4 -4
  34. package/dist/usage/shared.test.js +4 -4
  35. package/dist/workspaces/__tests__/spawn.test.js +2 -2
  36. package/dist/workspaces/__tests__/workspace-identity.test.js +94 -286
  37. package/dist/workspaces/binary-path.test.js +10 -0
  38. package/dist/workspaces/instance-client.js +4 -3
  39. package/dist/workspaces/launch-cleanup.test.js +21 -25
  40. package/dist/workspaces/manager.js +300 -351
  41. package/dist/workspaces/manager.test.js +209 -237
  42. package/dist/workspaces/process-identity.darwin.test.js +88 -0
  43. package/dist/workspaces/process-identity.js +172 -149
  44. package/dist/workspaces/process-identity.test.js +86 -140
  45. package/dist/workspaces/runtime.js +261 -373
  46. package/dist/workspaces/runtime.test.js +222 -547
  47. package/package.json +1 -1
  48. package/public/assets/{FilesTab-BjztpSdj.js → FilesTab-ChfE8-8N.js} +2 -2
  49. package/public/assets/{GitChangesTab-B9XraSoR.js → GitChangesTab-ntRtkxIF.js} +2 -2
  50. package/public/assets/{SplitFilePanel-Cu_5-Z-E.js → SplitFilePanel-Dav7VCqK.js} +1 -1
  51. package/public/assets/StatusTab-D3toOefp.js +1 -0
  52. package/public/assets/{align-justify-BKS9gyRk.js → align-justify-D91sAsLc.js} +1 -1
  53. package/public/assets/{bundle-full-CXGXXlzR.js → bundle-full-CWkY9-v4.js} +1 -1
  54. package/public/assets/{diff-viewer-CSNOYoEB.js → diff-viewer-Cn_41zpc.js} +1 -1
  55. package/public/assets/index-3dx-hhNQ.js +1 -0
  56. package/public/assets/index-BKwfZLzw.js +1 -0
  57. package/public/assets/index-C5IioEFT.js +1 -0
  58. package/public/assets/index-CZYc0VcU.js +2 -0
  59. package/public/assets/index-CdCoXYXP.js +1 -0
  60. package/public/assets/index-CwAVops2.js +1 -0
  61. package/public/assets/index-CzvCOwKc.js +1 -0
  62. package/public/assets/index-D-loOWPv.js +1 -0
  63. package/public/assets/{index-DVc4ls8c.js → index-DM1cpVNo.js} +1 -1
  64. package/public/assets/{index-sLe9hEfQ.js → index-DOprq6Gt.js} +1 -1
  65. package/public/assets/index-L7fX3W8k.css +1 -0
  66. package/public/assets/index-w2KdHEME.js +1 -0
  67. package/public/assets/{loading-CDmt9OJU.js → loading-BfoDcWcg.js} +1 -1
  68. package/public/assets/main-CaTCcck1.js +68 -0
  69. package/public/assets/{markdown-1ZLSxCFT.js → markdown-D33YI2g2.js} +3 -3
  70. package/public/assets/{monaco-viewer-D6JgH76W.js → monaco-viewer-DM35aobI.js} +4 -4
  71. package/public/assets/{tool-call-CyXb63LH.js → tool-call-tV85Jv2i.js} +3 -3
  72. package/public/assets/{unified-picker-DCCdSVwI.js → unified-picker-DSRT9GMh.js} +1 -1
  73. package/public/assets/{wrap-text-pNMdTIq3.js → wrap-text-Dmrn2DKo.js} +1 -1
  74. package/public/index.html +4 -4
  75. package/public/loading.html +4 -4
  76. package/public/sw.js +1 -1
  77. package/dist/workspaces/launch-cleanup.js +0 -132
  78. package/public/assets/StatusTab-D_IE79r-.js +0 -1
  79. package/public/assets/index-B3YjNCh4.js +0 -1
  80. package/public/assets/index-B3ZD2_SU.js +0 -1
  81. package/public/assets/index-Bh2ofaQo.js +0 -1
  82. package/public/assets/index-CM0c9xRZ.js +0 -1
  83. package/public/assets/index-CdDxouJl.js +0 -2
  84. package/public/assets/index-D06Y2cFq.js +0 -1
  85. package/public/assets/index-PmE51vPh.js +0 -1
  86. package/public/assets/index-Qj63IiSj.css +0 -1
  87. package/public/assets/index-VY_zwmsG.js +0 -1
  88. package/public/assets/index-qiiH7egV.js +0 -1
  89. package/public/assets/main-CTN6Wwz1.js +0 -68
@@ -1,32 +1,26 @@
1
- const LINUX_SNAPSHOT_SCRIPT = String.raw `
2
- boot=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) || exit 1
3
- test -n "$boot" || exit 1
4
- for stat in /proc/[0-9]*/stat; do
5
- line=$(cat "$stat" 2>/dev/null) || continue
6
- pid=$(printf '%s\n' "$line" | cut -d' ' -f1)
7
- rest=$(printf '%s\n' "$line" | sed 's/^.*) //')
8
- set -- $rest
9
- printf '%s|%s|%s|%s|%s|%s\n' "$pid" "$2" "$3" "$20" "$boot" "$20"
10
- done
11
- `;
12
- const LINUX_GUARDED_SIGNAL_SCRIPT = String.raw `
1
+ export const LAUNCH_CLEANUP_TOKEN_ENV = "CODENOMAD_LAUNCH_CLEANUP_TOKEN";
2
+ const LINUX_IDENTITY_FUNCTIONS = String.raw `
13
3
  boot=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) || exit 20
14
4
  read_stat() {
15
5
  line=$(cat "/proc/$1/stat" 2>/dev/null) || return 1
16
6
  stat_pid=$(printf '%s\n' "$line" | cut -d' ' -f1); rest=$(printf '%s\n' "$line" | sed 's/^.*) //'); set -- $rest
17
7
  stat_ppid=$2; stat_group=$3; stat_start=$20
18
8
  }
19
- emit_target() {
20
- printf 'CODENOMAD_TARGET|%s|%s|%s|%s|%s|%s\n' "$stat_pid" "$stat_ppid" "$stat_group" "$stat_start" "$boot" "$stat_start"
21
- }
9
+ emit_linux() { printf '%s|%s|%s|%s|%s|%s|%s\n' "$1" "$stat_pid" "$stat_ppid" "$stat_group" "$stat_start" "$boot" "$stat_start"; }
10
+ `;
11
+ const LINUX_SNAPSHOT_SCRIPT = String.raw `${LINUX_IDENTITY_FUNCTIONS}
12
+ for stat in /proc/[0-9]*/stat; do
13
+ pid=$(basename "$(dirname "$stat")"); read_stat "$pid" && emit_linux "" | cut -c2-
14
+ done
15
+ exit 0
16
+ `;
17
+ const LINUX_GUARDED_SIGNAL_SCRIPT = String.raw `${LINUX_IDENTITY_FUNCTIONS}
22
18
  leader_pid=$1; leader_start=$2; leader_boot=$3; expected_group=$4; requested_signal=$5
23
- shift 5
24
- matched=0; cutoff=; signal_sent=0
19
+ shift 5; matched=0; cutoff=; signal_sent=0
25
20
  if read_stat "$leader_pid" && test "$boot" = "$leader_boot" && test "$stat_start" = "$leader_start" && test "$stat_group" = "$expected_group"; then
26
21
  matched=1
27
22
  for stat in /proc/[0-9]*/stat; do
28
- candidate=$(basename "$(dirname "$stat")")
29
- if read_stat "$candidate" && test "$stat_group" = "$expected_group"; then emit_target; fi
23
+ candidate=$(basename "$(dirname "$stat")"); read_stat "$candidate" && test "$stat_group" = "$expected_group" && emit_linux CODENOMAD_TARGET
30
24
  done
31
25
  if kill "-$requested_signal" -- "-$expected_group" 2>/dev/null; then
32
26
  signal_sent=1
@@ -38,83 +32,106 @@ else
38
32
  while test "$#" -ge 3; do
39
33
  expected_pid=$1; expected_start=$2; expected_boot=$3; shift 3
40
34
  if read_stat "$expected_pid" && test "$boot" = "$expected_boot" && test "$stat_start" = "$expected_start"; then
41
- emit_target
35
+ emit_linux CODENOMAD_TARGET
42
36
  if kill "-$requested_signal" "$expected_pid" 2>/dev/null; then signal_sent=1; fi
43
37
  fi
44
38
  done
45
39
  fi
46
40
  printf 'CODENOMAD_RESULT|%s|%s|%s\n' "$matched" "$cutoff" "$signal_sent"
47
41
  `;
48
- const POSIX_GUARDED_SIGNAL_SCRIPT = String.raw `
42
+ const POSIX_IDENTITY_FUNCTIONS = String.raw `
43
+ LC_ALL=C; export LC_ALL; set -f
49
44
  encode() { printf '%s' "$1" | base64 | tr -d '\r\n'; }
50
45
  read_identity() {
51
- current_meta=$(ps -p "$1" -o ppid= -o pgid= -o lstart= 2>/dev/null) || return 1
52
- current_command=$(ps -p "$1" -o command= 2>/dev/null) || return 1
53
- current_verify=$(ps -p "$1" -o ppid= -o pgid= -o lstart= 2>/dev/null) || return 1
46
+ current_meta=$(ps -p "$1" -o ppid= -o pgid= -o lstart= -o comm= 2>/dev/null) || return 1
47
+ current_verify=$(ps -p "$1" -o ppid= -o pgid= -o lstart= -o comm= 2>/dev/null) || return 1
54
48
  test "$current_meta" = "$current_verify" || return 1
55
- set -- $current_meta
56
- test "$#" -ge 7 || return 1
57
- current_ppid=$1; current_group=$2; shift 2
58
- current_start="$1 $2 $3 $4 $5"
49
+ set -- $current_meta; test "$#" -ge 7 || return 1
50
+ current_ppid=$1; current_group=$2; shift 2; current_start="$1 $2 $3 $4 $5"
51
+ shift 5; current_command="$*"; test -n "$current_command" || return 1
59
52
  current_identity=$(printf '%s\t%s' "$current_start" "$current_command")
60
53
  }
61
54
  emit_target() {
62
55
  printf 'CODENOMAD_TARGET_B64|%s|%s|%s|' "$current_pid" "$current_ppid" "$current_group"
63
56
  encode "$current_start"; printf '|'; encode "$current_command"; printf '\n'
64
57
  }
65
- leader_pid=$1; leader_start=$2; expected_group=$3; requested_signal=$4; shift 4
58
+ group_pids() { ps -axo pid=,pgid= 2>/dev/null | awk -v group="$1" '$2 == group { print $1 }'; }
59
+ has_cleanup_token() {
60
+ test -n "$cleanup_token" || return 1
61
+ ps eww -p "$1" -o command= 2>/dev/null | tr ' ' '\n' | grep -Fqx -- "${LAUNCH_CLEANUP_TOKEN_ENV}=$cleanup_token"
62
+ }
63
+ `;
64
+ const LINUX_TOKEN_SCRIPT = String.raw `${LINUX_IDENTITY_FUNCTIONS}
65
+ key=$1; expected=$2; requested_signal=$3
66
+ matches_token() { test -r "/proc/$1/environ" && tr '\0' '\n' < "/proc/$1/environ" 2>/dev/null | grep -Fqx -- "$key=$expected"; }
67
+ signal_sent=0; passes=1; test -n "$requested_signal" && passes=3
68
+ pass=0
69
+ while test "$pass" -lt "$passes"; do
70
+ pass=$((pass + 1))
71
+ for environ in /proc/[0-9]*/environ; do
72
+ pid=$(basename "$(dirname "$environ")")
73
+ if matches_token "$pid" && read_stat "$pid"; then
74
+ test -n "$requested_signal" && prefix=CODENOMAD_TARGET || prefix=CODENOMAD_PROCESS
75
+ emit_linux "$prefix"
76
+ if test -n "$requested_signal" && matches_token "$pid" && read_stat "$pid" && kill "-$requested_signal" "$pid" 2>/dev/null; then signal_sent=1; fi
77
+ fi
78
+ done
79
+ done
80
+ if test -n "$requested_signal"; then printf 'CODENOMAD_RESULT|%s\n' "$signal_sent"; fi
81
+ exit 0
82
+ `;
83
+ const POSIX_GUARDED_SIGNAL_SCRIPT = String.raw `${POSIX_IDENTITY_FUNCTIONS}
84
+ leader_pid=$1; leader_start=$2; expected_group=$3; requested_signal=$4; allow_leaderless=$5; cleanup_token=$6; shift 6
66
85
  matched=0; signal_sent=0
67
86
  if read_identity "$leader_pid" && test "$current_group" = "$expected_group" && test "$current_identity" = "$leader_start"; then
68
87
  matched=1
69
- for current_pid in $(ps -eo pid= 2>/dev/null); do
70
- if read_identity "$current_pid" && test "$current_group" = "$expected_group"; then emit_target; fi
88
+ for current_pid in $(group_pids "$expected_group"); do
89
+ read_identity "$current_pid" && test "$current_group" = "$expected_group" && emit_target
71
90
  done
72
91
  if kill "-$requested_signal" -- "-$expected_group" 2>/dev/null; then signal_sent=1; fi
92
+ elif test "$allow_leaderless" = 1 && ! read_identity "$expected_group"; then
93
+ anchor=0
94
+ while test "$#" -ge 2; do
95
+ expected_pid=$1; expected_start=$2; shift 2; current_pid=$expected_pid
96
+ if read_identity "$expected_pid" && test "$current_group" = "$expected_group" && test "$current_identity" = "$expected_start"; then anchor=1; fi
97
+ done
98
+ if test "$anchor" = 0; then
99
+ for current_pid in $(group_pids "$expected_group"); do
100
+ if has_cleanup_token "$current_pid" && read_identity "$current_pid" && test "$current_group" = "$expected_group"; then anchor=1; break; fi
101
+ done
102
+ fi
103
+ if test "$anchor" = 1; then
104
+ matched=1
105
+ for current_pid in $(group_pids "$expected_group"); do
106
+ read_identity "$current_pid" && test "$current_group" = "$expected_group" && emit_target
107
+ done
108
+ if kill "-$requested_signal" -- "-$expected_group" 2>/dev/null; then signal_sent=1; fi
109
+ fi
73
110
  else
74
111
  while test "$#" -ge 2; do
75
- expected_pid=$1; expected_start=$2; shift 2
76
- current_pid=$expected_pid
77
- if read_identity "$expected_pid" && test "$current_identity" = "$expected_start"; then
78
- emit_target
79
- if kill "-$requested_signal" "$expected_pid" 2>/dev/null; then signal_sent=1; fi
112
+ expected_pid=$1; expected_start=$2; shift 2; current_pid=$expected_pid
113
+ if read_identity "$expected_pid" && test "$current_group" = "$expected_group" && test "$current_identity" = "$expected_start"; then
114
+ emit_target; if kill "-$requested_signal" "$expected_pid" 2>/dev/null; then signal_sent=1; fi
80
115
  fi
81
116
  done
82
117
  fi
83
118
  printf 'CODENOMAD_RESULT|%s||%s\n' "$matched" "$signal_sent"
84
119
  `;
85
- const POSIX_OWNED_GROUP_SIGNAL_SCRIPT = String.raw `
86
- encode() { printf '%s' "$1" | base64 | tr -d '\r\n'; }
87
- read_identity() {
88
- current_meta=$(ps -p "$1" -o ppid= -o pgid= -o lstart= 2>/dev/null) || return 1
89
- current_command=$(ps -p "$1" -o command= 2>/dev/null) || return 1
90
- current_verify=$(ps -p "$1" -o ppid= -o pgid= -o lstart= 2>/dev/null) || return 1
91
- test "$current_meta" = "$current_verify" || return 1
92
- set -- $current_meta
93
- test "$#" -ge 7 || return 1
94
- current_ppid=$1; current_group=$2; shift 2
95
- current_start="$1 $2 $3 $4 $5"
96
- current_identity=$(printf '%s\t%s' "$current_start" "$current_command")
97
- }
98
- emit_target() {
99
- printf 'CODENOMAD_TARGET_B64|%s|%s|%s|' "$current_pid" "$current_ppid" "$current_group"
100
- encode "$current_start"; printf '|'; encode "$current_command"; printf '\n'
101
- }
120
+ const POSIX_OWNED_GROUP_SIGNAL_SCRIPT = String.raw `${POSIX_IDENTITY_FUNCTIONS}
102
121
  root_pid=$1; requested_signal=$2; matched=0; signal_sent=0
103
122
  if read_identity "$root_pid" && test "$current_group" = "$root_pid"; then
104
123
  matched=1
105
- for current_pid in $(ps -eo pid= 2>/dev/null); do
106
- if read_identity "$current_pid" && test "$current_group" = "$root_pid"; then emit_target; fi
124
+ for current_pid in $(group_pids "$root_pid"); do
125
+ read_identity "$current_pid" && test "$current_group" = "$root_pid" && emit_target
107
126
  done
108
127
  if kill "-$requested_signal" -- "-$root_pid" 2>/dev/null; then signal_sent=1; fi
109
- for current_pid in $(ps -eo pid= 2>/dev/null); do
110
- if read_identity "$current_pid" && test "$current_group" = "$root_pid"; then emit_target; fi
128
+ for current_pid in $(group_pids "$root_pid"); do
129
+ read_identity "$current_pid" && test "$current_group" = "$root_pid" && emit_target
111
130
  done
112
131
  fi
113
132
  printf 'CODENOMAD_RESULT|%s||%s\n' "$matched" "$signal_sent"
114
133
  `;
115
- function commandError(result) {
116
- return result.error?.message || String(result.stderr ?? result.stdout ?? "").trim() || `exit code ${result.status}`;
117
- }
134
+ const commandError = (result) => result.error?.message || String(result.stderr ?? result.stdout ?? "").trim() || `exit code ${result.status}`;
118
135
  function parseDelimitedSnapshot(output, requireBootId = false) {
119
136
  const processes = new Map();
120
137
  for (const line of output.split(/\r?\n/)) {
@@ -130,14 +147,8 @@ function parseDelimitedSnapshot(output, requireBootId = false) {
130
147
  if (!/^\d+$/.test(pidText ?? "") || !/^\d+$/.test(parentPidText ?? "") || !/^\d+$/.test(groupIdText ?? "") ||
131
148
  !Number.isInteger(pid) || pid <= 0 || !Number.isInteger(parentPid) || !startTime || (requireBootId && !bootId))
132
149
  return null;
133
- processes.set(pid, {
134
- pid,
135
- parentPid,
136
- groupId: Number.isInteger(groupId) && groupId > 0 ? groupId : pid,
137
- startTime,
138
- ...(bootId ? { bootId } : {}),
139
- ...(startOrder ? { startOrder } : {}),
140
- });
150
+ processes.set(pid, { pid, parentPid, groupId: Number.isInteger(groupId) && groupId > 0 ? groupId : pid, startTime,
151
+ ...(bootId ? { bootId } : {}), ...(startOrder ? { startOrder } : {}) });
141
152
  }
142
153
  return processes;
143
154
  }
@@ -179,50 +190,69 @@ function parseBase64Snapshot(output, prefix = "CODENOMAD_B64|") {
179
190
  }
180
191
  return processes;
181
192
  }
182
- function parsePortablePosixSnapshot(output) {
193
+ function parsePortablePosixSnapshot(output, filter) {
183
194
  const processes = new Map();
195
+ const requestedPids = filter?.pids ? new Set(filter.pids) : undefined;
184
196
  for (const line of output.split(/\r?\n/)) {
185
197
  if (!line.trim())
186
198
  continue;
187
199
  const match = line.match(/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\S+\s+\S+\s+\d+\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s+(.+)$/);
188
- if (!match)
189
- return null;
200
+ if (!match) {
201
+ const numeric = line.match(/^\s*(\d+)\s+(\d+)\s+(\d+)\s+/);
202
+ if (!filter || !numeric || requestedPids?.has(Number(numeric[1])) || Number(numeric[3]) === filter.groupId)
203
+ return null;
204
+ continue;
205
+ }
190
206
  const [, pidText = "", parentPidText = "", groupIdText = "", start = "", command = ""] = match;
191
207
  const pid = Number.parseInt(pidText, 10);
192
208
  const parentPid = Number.parseInt(parentPidText, 10);
193
209
  const groupId = Number.parseInt(groupIdText, 10);
194
210
  if (pid <= 0 || parentPid < 0 || groupId <= 0)
195
211
  return null;
212
+ if (filter && !requestedPids?.has(pid) && groupId !== filter.groupId)
213
+ continue;
196
214
  processes.set(pid, { pid, parentPid, groupId, startTime: `${start}\t${command}` });
197
215
  }
198
216
  return processes;
199
217
  }
200
- function snapshotOrFailure(processes) {
201
- return processes && processes.size > 0
202
- ? { ok: true, processes }
203
- : { ok: false, error: "process identity query returned no parseable processes" };
218
+ function querySnapshot(run, parse, options = {}) {
219
+ const sanitize = options.redact ?? ((error) => error);
220
+ try {
221
+ const result = run();
222
+ if (result.status !== 0)
223
+ return { ok: false, error: sanitize(commandError(result)) };
224
+ const processes = parse(String(result.stdout ?? ""));
225
+ if (processes && (options.allowEmpty || processes.size > 0))
226
+ return { ok: true, processes };
227
+ return { ok: false, error: options.malformedError ?? "process identity query returned no parseable processes" };
228
+ }
229
+ catch (error) {
230
+ return { ok: false, error: sanitize(error instanceof Error ? error.message : String(error)) };
231
+ }
232
+ }
233
+ function parsePrefixedSnapshot(output, prefix) {
234
+ const records = [];
235
+ for (const line of output.split(/\r?\n/)) {
236
+ if (!line)
237
+ continue;
238
+ if (!line.startsWith(prefix))
239
+ return null;
240
+ records.push(line.slice(prefix.length));
241
+ }
242
+ return parseDelimitedSnapshot(records.join("\n"), true);
204
243
  }
205
244
  function parseGuardedResult(result) {
206
245
  const signaled = new Map();
207
- const failure = (error) => ({
208
- ok: false,
209
- error,
210
- ...(signaled.size > 0 ? { observed: Array.from(signaled.values()) } : {}),
211
- });
246
+ const failure = (error) => ({ ok: false, error,
247
+ ...(signaled.size > 0 ? { observed: Array.from(signaled.values()) } : {}) });
212
248
  let matched;
213
249
  let signalSent = false;
214
250
  let cutoff;
215
251
  for (const line of String(result.stdout ?? "").split(/\r?\n/)) {
216
- if (line.startsWith("CODENOMAD_TARGET|")) {
217
- const parsed = parseDelimitedSnapshot(line.slice("CODENOMAD_TARGET|".length));
218
- if (!parsed)
219
- return failure("guarded signal command returned a malformed target record");
220
- for (const identity of parsed.values())
221
- signaled.set(identity.pid, identity);
222
- continue;
223
- }
224
- if (line.startsWith("CODENOMAD_TARGET_B64|")) {
225
- const parsed = parseBase64Snapshot(line, "CODENOMAD_TARGET_B64|");
252
+ if (line.startsWith("CODENOMAD_TARGET|") || line.startsWith("CODENOMAD_TARGET_B64|")) {
253
+ const parsed = line.startsWith("CODENOMAD_TARGET_B64|")
254
+ ? parseBase64Snapshot(line, "CODENOMAD_TARGET_B64|")
255
+ : parseDelimitedSnapshot(line.slice("CODENOMAD_TARGET|".length));
226
256
  if (!parsed)
227
257
  return failure("guarded signal command returned a malformed target record");
228
258
  for (const identity of parsed.values())
@@ -249,22 +279,27 @@ function parseGuardedResult(result) {
249
279
  ? failure("guarded signal command returned no structured result")
250
280
  : { ok: true, matched, signalSent, signaled: Array.from(signaled.values()), ...(cutoff ? { cutoff } : {}) };
251
281
  }
252
- function runGuardedCommand(spawnCommand, command, args, timeoutMs) {
282
+ function runGuardedCommand(run) {
253
283
  try {
254
- return parseGuardedResult(spawnCommand(command, args, { encoding: "utf8", timeout: timeoutMs }));
284
+ return parseGuardedResult(run());
255
285
  }
256
286
  catch (error) {
257
287
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
258
288
  }
259
289
  }
260
- function signalName(signal) {
261
- return signal === "SIGKILL" ? "KILL" : "TERM";
290
+ const signalName = (signal) => signal === "SIGKILL" ? "KILL" : "TERM";
291
+ function runLinuxScript(spawnCommand, script, args, timeoutMs, label, distro) {
292
+ return distro
293
+ ? spawnCommand("wsl.exe", ["--distribution", distro, "--exec", "sh", "-c", script, label, ...args], { encoding: "utf8", timeout: timeoutMs })
294
+ : spawnCommand("sh", ["-c", script, label, ...args], { encoding: "utf8", timeout: timeoutMs });
262
295
  }
296
+ const redactToken = (value, token) => value.split(token).join("[REDACTED]");
263
297
  function shellGuardArgs(request, linux) {
264
298
  const leader = request.leader;
265
299
  const args = linux
266
300
  ? [String(leader?.pid ?? 0), leader?.startTime ?? "", leader?.bootId ?? "", String(request.groupId ?? 0), signalName(request.signal)]
267
- : [String(leader?.pid ?? 0), leader?.startTime ?? "", String(request.groupId ?? 0), signalName(request.signal)];
301
+ : [String(leader?.pid ?? 0), leader?.startTime ?? "", String(request.groupId ?? 0), signalName(request.signal),
302
+ request.allowLeaderlessGroup ? "1" : "0", request.cleanupToken ?? ""];
268
303
  for (const member of request.members) {
269
304
  args.push(String(member.pid), member.startTime);
270
305
  if (linux)
@@ -272,15 +307,11 @@ function shellGuardArgs(request, linux) {
272
307
  }
273
308
  return args;
274
309
  }
275
- function quotePowerShell(value) {
276
- return `'${value.replace(/'/g, "''")}'`;
277
- }
310
+ const quotePowerShell = (value) => `'${value.replace(/'/g, "''")}'`;
278
311
  function buildWindowsGuardedScript(request) {
279
312
  const leaderPid = request.leader?.pid ?? 0;
280
313
  const leaderStart = quotePowerShell(request.leader?.startTime ?? "");
281
- const expected = request.members
282
- .map((identity) => `@{ Pid = ${identity.pid}; Start = ${quotePowerShell(identity.startTime)} }`)
283
- .join(", ");
314
+ const expected = request.members.map((identity) => `@{ Pid = ${identity.pid}; Start = ${quotePowerShell(identity.startTime)} }`).join(", ");
284
315
  return [
285
316
  "$ErrorActionPreference = 'Stop'",
286
317
  `$leaderPid = ${leaderPid}`,
@@ -340,69 +371,61 @@ export function descendantsOf(processes, rootPid) {
340
371
  }
341
372
  return descendants;
342
373
  }
343
- export function probePosixProcesses(spawnCommand, timeoutMs, platform = process.platform) {
344
- try {
345
- if (platform === "linux") {
346
- const result = spawnCommand("sh", ["-c", LINUX_SNAPSHOT_SCRIPT, "codenomad-posix-identity"], {
347
- encoding: "utf8",
348
- timeout: timeoutMs,
349
- });
350
- if (result.status !== 0)
351
- return { ok: false, error: commandError(result) };
352
- return snapshotOrFailure(parseDelimitedSnapshot(String(result.stdout ?? ""), true));
353
- }
354
- // POSIX has no portable pidfd/start ticks; collect one coherent table instead of probing every PID.
355
- const result = spawnCommand("ps", ["-axo", "pid=,ppid=,pgid=,lstart=,command="], {
356
- encoding: "utf8",
357
- timeout: timeoutMs,
358
- });
359
- if (result.status !== 0)
360
- return { ok: false, error: commandError(result) };
361
- return snapshotOrFailure(parsePortablePosixSnapshot(String(result.stdout ?? "")));
362
- }
363
- catch (error) {
364
- return { ok: false, error: error instanceof Error ? error.message : String(error) };
365
- }
374
+ export function probePosixProcesses(spawnCommand, timeoutMs, platform = process.platform, filter) {
375
+ if (platform === "linux")
376
+ return querySnapshot(() => runLinuxScript(spawnCommand, LINUX_SNAPSHOT_SCRIPT, [], timeoutMs, "codenomad-posix-identity"), (output) => parseDelimitedSnapshot(output, true));
377
+ // POSIX has no portable pidfd/start ticks; collect one coherent table instead of probing every PID.
378
+ return querySnapshot(() => spawnCommand("ps", ["-axo", "pid=,ppid=,pgid=,lstart=,comm="], {
379
+ encoding: "utf8", timeout: timeoutMs, env: { ...process.env, LC_ALL: "C", LANG: "C" },
380
+ }), (output) => parsePortablePosixSnapshot(output, filter), { allowEmpty: Boolean(filter) });
366
381
  }
367
382
  export function probeWindowsProcesses(spawnCommand, timeoutMs) {
368
383
  const script = [
369
384
  "$all = @(Get-CimInstance Win32_Process -ErrorAction Stop)",
370
385
  "$all | Where-Object { [int]$_.ProcessId -gt 0 } | ForEach-Object { $start = ([datetime]$_.CreationDate).ToUniversalTime().Ticks.ToString(); '{0}|{1}|0|{2}||{2}' -f [int]$_.ProcessId, [int]$_.ParentProcessId, $start }",
371
386
  ].join("; ");
372
- try {
373
- const result = spawnCommand("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
374
- encoding: "utf8",
375
- timeout: timeoutMs,
376
- });
377
- if (result.status !== 0)
378
- return { ok: false, error: commandError(result) };
379
- return snapshotOrFailure(parseDelimitedSnapshot(String(result.stdout ?? "")));
380
- }
381
- catch (error) {
382
- return { ok: false, error: error instanceof Error ? error.message : String(error) };
383
- }
387
+ return querySnapshot(() => spawnCommand("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { encoding: "utf8", timeout: timeoutMs }), parseDelimitedSnapshot);
384
388
  }
385
389
  export function probeWslProcesses(spawnCommand, distro, timeoutMs) {
386
- try {
387
- const result = spawnCommand("wsl.exe", ["--distribution", distro, "--exec", "sh", "-c", LINUX_SNAPSHOT_SCRIPT, "codenomad-wsl-identity"], { encoding: "utf8", timeout: timeoutMs });
388
- if (result.status !== 0)
389
- return { ok: false, error: commandError(result) };
390
- return snapshotOrFailure(parseDelimitedSnapshot(String(result.stdout ?? ""), true));
391
- }
392
- catch (error) {
393
- return { ok: false, error: error instanceof Error ? error.message : String(error) };
394
- }
390
+ return querySnapshot(() => runLinuxScript(spawnCommand, LINUX_SNAPSHOT_SCRIPT, [], timeoutMs, "codenomad-wsl-identity", distro), (output) => parseDelimitedSnapshot(output, true));
395
391
  }
396
392
  export function signalPosixProcesses(spawnCommand, request, timeoutMs, platform) {
397
393
  const linux = platform === "linux";
398
- return runGuardedCommand(spawnCommand, "sh", ["-c", linux ? LINUX_GUARDED_SIGNAL_SCRIPT : POSIX_GUARDED_SIGNAL_SCRIPT, "codenomad-guarded-signal", ...shellGuardArgs(request, linux)], timeoutMs);
394
+ return runGuardedCommand(() => spawnCommand("sh", ["-c", linux ? LINUX_GUARDED_SIGNAL_SCRIPT : POSIX_GUARDED_SIGNAL_SCRIPT, "codenomad-guarded-signal", ...shellGuardArgs(request, linux)], { encoding: "utf8", timeout: timeoutMs }));
399
395
  }
400
396
  export function signalOwnedPosixProcessGroup(spawnCommand, rootPid, signal, timeoutMs) {
401
- return runGuardedCommand(spawnCommand, "sh", ["-c", POSIX_OWNED_GROUP_SIGNAL_SCRIPT, "codenomad-owned-group-cleanup", String(rootPid), signalName(signal)], timeoutMs);
397
+ return runGuardedCommand(() => spawnCommand("sh", ["-c", POSIX_OWNED_GROUP_SIGNAL_SCRIPT, "codenomad-owned-group-cleanup", String(rootPid), signalName(signal)], { encoding: "utf8", timeout: timeoutMs }));
402
398
  }
403
399
  export function signalWslProcesses(spawnCommand, distro, request, timeoutMs) {
404
- return runGuardedCommand(spawnCommand, "wsl.exe", ["--distribution", distro, "--exec", "sh", "-c", LINUX_GUARDED_SIGNAL_SCRIPT, "codenomad-wsl-guarded-signal", ...shellGuardArgs(request, true)], timeoutMs);
400
+ return runGuardedCommand(() => runLinuxScript(spawnCommand, LINUX_GUARDED_SIGNAL_SCRIPT, shellGuardArgs(request, true), timeoutMs, "codenomad-wsl-guarded-signal", distro));
405
401
  }
406
402
  export function signalWindowsProcesses(spawnCommand, request, timeoutMs) {
407
- return runGuardedCommand(spawnCommand, "powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", buildWindowsGuardedScript(request)], timeoutMs);
403
+ return runGuardedCommand(() => spawnCommand("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", buildWindowsGuardedScript(request)], { encoding: "utf8", timeout: timeoutMs }));
404
+ }
405
+ export function probeLaunchCleanupToken(spawnCommand, token, timeoutMs, distro) {
406
+ return querySnapshot(() => runLinuxScript(spawnCommand, LINUX_TOKEN_SCRIPT, [LAUNCH_CLEANUP_TOKEN_ENV, token, ""], timeoutMs, "codenomad-token-cleanup", distro), (output) => parsePrefixedSnapshot(output, "CODENOMAD_PROCESS|"), {
407
+ allowEmpty: true,
408
+ malformedError: "launch cleanup probe returned malformed or unexpected output",
409
+ redact: (error) => redactToken(error, token),
410
+ });
411
+ }
412
+ export function signalLaunchCleanupToken(spawnCommand, token, signal, timeoutMs, distro) {
413
+ const failed = (error) => ({ ok: false, signalSent: false, targets: [], error });
414
+ try {
415
+ const result = runLinuxScript(spawnCommand, LINUX_TOKEN_SCRIPT, [LAUNCH_CLEANUP_TOKEN_ENV, token, signalName(signal)], timeoutMs, "codenomad-token-cleanup", distro);
416
+ if (result.status !== 0)
417
+ return failed(redactToken(commandError(result), token));
418
+ const lines = String(result.stdout ?? "").split(/\r?\n/).filter(Boolean);
419
+ const resultLines = lines.filter((line) => line.startsWith("CODENOMAD_RESULT|"));
420
+ if (resultLines.length !== 1 || !/^CODENOMAD_RESULT\|[01]$/.test(resultLines[0] ?? "")) {
421
+ return failed("launch cleanup signal returned no valid structured result");
422
+ }
423
+ const targets = parsePrefixedSnapshot(lines.filter((line) => !line.startsWith("CODENOMAD_RESULT|")).join("\n"), "CODENOMAD_TARGET|");
424
+ return targets
425
+ ? { ok: true, signalSent: resultLines[0].endsWith("1"), targets: Array.from(targets.values()) }
426
+ : failed("launch cleanup signal returned malformed or unexpected output");
427
+ }
428
+ catch (error) {
429
+ return failed(redactToken(error instanceof Error ? error.message : String(error), token));
430
+ }
408
431
  }