@neuralnomads/codenomad-dev 0.18.0-dev-20260715-07e8ce68 → 0.18.0-dev-20260716-40cee071

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 (81) hide show
  1. package/README.md +12 -0
  2. package/THIRD_PARTY_NOTICES.md +26 -0
  3. package/dist/events/bus.js +13 -0
  4. package/dist/events/bus.test.js +37 -0
  5. package/dist/index.js +33 -56
  6. package/dist/index.test.js +32 -0
  7. package/dist/server/__tests__/remote-proxy.test.js +102 -6
  8. package/dist/server/http-server.js +2 -0
  9. package/dist/server/remote-proxy.js +96 -9
  10. package/dist/server/routes/usage.js +18 -0
  11. package/dist/server/routes/usage.test.js +26 -0
  12. package/dist/server/routes/workspaces.js +32 -1
  13. package/dist/server/routes/workspaces.test.js +75 -0
  14. package/dist/settings/binaries.js +4 -1
  15. package/dist/settings/binaries.test.js +24 -0
  16. package/dist/shutdown.js +75 -0
  17. package/dist/shutdown.test.js +111 -0
  18. package/dist/usage/providers/api-key.js +171 -0
  19. package/dist/usage/providers/google.js +171 -0
  20. package/dist/usage/providers/minimax.js +109 -0
  21. package/dist/usage/providers/oauth.js +111 -0
  22. package/dist/usage/providers/special.js +148 -0
  23. package/dist/usage/service.js +83 -0
  24. package/dist/usage/service.test.js +59 -0
  25. package/dist/usage/shared.js +130 -0
  26. package/dist/usage/shared.test.js +33 -0
  27. package/dist/usage/types.js +1 -0
  28. package/dist/workspaces/__tests__/spawn.test.js +64 -7
  29. package/dist/workspaces/__tests__/workspace-identity.test.js +177 -25
  30. package/dist/workspaces/launch-cleanup.js +132 -0
  31. package/dist/workspaces/launch-cleanup.test.js +33 -0
  32. package/dist/workspaces/manager.js +393 -135
  33. package/dist/workspaces/manager.test.js +318 -0
  34. package/dist/workspaces/process-identity.js +408 -0
  35. package/dist/workspaces/process-identity.test.js +165 -0
  36. package/dist/workspaces/runtime.js +567 -122
  37. package/dist/workspaces/runtime.test.js +603 -0
  38. package/dist/workspaces/spawn.js +86 -15
  39. package/package.json +1 -1
  40. package/public/assets/{FilesTab-EPvldvn1.js → FilesTab-BjztpSdj.js} +2 -2
  41. package/public/assets/{GitChangesTab-ofjovmv2.js → GitChangesTab-B9XraSoR.js} +2 -2
  42. package/public/assets/{SplitFilePanel-CyoPkcLd.js → SplitFilePanel-Cu_5-Z-E.js} +1 -1
  43. package/public/assets/StatusTab-D_IE79r-.js +1 -0
  44. package/public/assets/{align-justify-Bcf1-ZOl.js → align-justify-BKS9gyRk.js} +1 -1
  45. package/public/assets/{bundle-full-D5dzvToA.js → bundle-full-CXGXXlzR.js} +1 -1
  46. package/public/assets/{diff-viewer-DViXCI-4.js → diff-viewer-CSNOYoEB.js} +1 -1
  47. package/public/assets/{git-diff-vendor-CSgooKT_.js → git-diff-vendor-CYS3ApzA.js} +1 -1
  48. package/public/assets/index-B3YjNCh4.js +1 -0
  49. package/public/assets/index-B3ZD2_SU.js +1 -0
  50. package/public/assets/index-Bh2ofaQo.js +1 -0
  51. package/public/assets/index-CM0c9xRZ.js +1 -0
  52. package/public/assets/index-CdDxouJl.js +2 -0
  53. package/public/assets/index-D06Y2cFq.js +1 -0
  54. package/public/assets/{index-lf4nUOU1.js → index-DVc4ls8c.js} +1 -1
  55. package/public/assets/index-PmE51vPh.js +1 -0
  56. package/public/assets/{index-BMvFMsuy.css → index-Qj63IiSj.css} +1 -1
  57. package/public/assets/index-VY_zwmsG.js +1 -0
  58. package/public/assets/index-qiiH7egV.js +1 -0
  59. package/public/assets/{index-UbL8tz_V.js → index-sLe9hEfQ.js} +1 -1
  60. package/public/assets/{loading-CZ_tt3h0.js → loading-CDmt9OJU.js} +1 -1
  61. package/public/assets/main-CTN6Wwz1.js +68 -0
  62. package/public/assets/{markdown-G11aN6hz.js → markdown-1ZLSxCFT.js} +55 -44
  63. package/public/assets/monaco-viewer-D6JgH76W.js +26 -0
  64. package/public/assets/{tool-call-BsSXWErm.js → tool-call-CyXb63LH.js} +32 -32
  65. package/public/assets/{unified-picker-BRNI3UvE.js → unified-picker-DCCdSVwI.js} +1 -1
  66. package/public/assets/{wrap-text-B7up-uv7.js → wrap-text-pNMdTIq3.js} +1 -1
  67. package/public/index.html +5 -5
  68. package/public/loading.html +5 -5
  69. package/public/sw.js +1 -1
  70. package/public/assets/StatusTab-Bgu1Fh24.js +0 -1
  71. package/public/assets/index-3KsjbWGP.js +0 -1
  72. package/public/assets/index-B0WK8-cF.js +0 -1
  73. package/public/assets/index-BDv_iVtj.js +0 -1
  74. package/public/assets/index-BjxZvyb9.js +0 -2
  75. package/public/assets/index-BleKf9Nj.js +0 -1
  76. package/public/assets/index-CiIQ43NW.js +0 -1
  77. package/public/assets/index-DBquqL6Q.js +0 -1
  78. package/public/assets/index-yf9zolv4.js +0 -1
  79. package/public/assets/index-ypaL7i_s.js +0 -1
  80. package/public/assets/main-CAkg_fp_.js +0 -68
  81. package/public/assets/monaco-viewer-CZefBfct.js +0 -26
@@ -0,0 +1,132 @@
1
+ export const LAUNCH_CLEANUP_TOKEN_ENV = "CODENOMAD_LAUNCH_CLEANUP_TOKEN";
2
+ const LINUX_TOKEN_PROBE_SCRIPT = String.raw `
3
+ boot=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) || exit 20
4
+ key=$1; expected=$2
5
+ matches_token() {
6
+ test -r "/proc/$1/environ" || return 1
7
+ tr '\0' '\n' < "/proc/$1/environ" 2>/dev/null | grep -Fqx -- "$key=$expected"
8
+ }
9
+ read_stat() {
10
+ line=$(cat "/proc/$1/stat" 2>/dev/null) || return 1
11
+ stat_pid=$(printf '%s\n' "$line" | cut -d' ' -f1); rest=$(printf '%s\n' "$line" | sed 's/^.*) //'); set -- $rest
12
+ stat_ppid=$2; stat_group=$3; stat_start=$20
13
+ }
14
+ for environ in /proc/[0-9]*/environ; do
15
+ pid=$(basename "$(dirname "$environ")")
16
+ if matches_token "$pid" && read_stat "$pid"; then
17
+ printf '%s|%s|%s|%s|%s|%s\n' "$stat_pid" "$stat_ppid" "$stat_group" "$stat_start" "$boot" "$stat_start"
18
+ fi
19
+ done
20
+ `;
21
+ const LINUX_TOKEN_SIGNAL_SCRIPT = String.raw `
22
+ boot=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) || exit 20
23
+ key=$1; expected=$2; requested_signal=$3
24
+ matches_token() {
25
+ test -r "/proc/$1/environ" || return 1
26
+ tr '\0' '\n' < "/proc/$1/environ" 2>/dev/null | grep -Fqx -- "$key=$expected"
27
+ }
28
+ read_stat() {
29
+ line=$(cat "/proc/$1/stat" 2>/dev/null) || return 1
30
+ stat_pid=$(printf '%s\n' "$line" | cut -d' ' -f1); rest=$(printf '%s\n' "$line" | sed 's/^.*) //'); set -- $rest
31
+ stat_ppid=$2; stat_group=$3; stat_start=$20
32
+ }
33
+ signal_sent=0
34
+ # Repeat inside the one bounded adapter so children forked by a signaled parent are selected too.
35
+ for pass in 1 2 3; do
36
+ for environ in /proc/[0-9]*/environ; do
37
+ pid=$(basename "$(dirname "$environ")")
38
+ if matches_token "$pid" && read_stat "$pid"; then
39
+ printf 'CODENOMAD_TARGET|%s|%s|%s|%s|%s|%s\n' "$stat_pid" "$stat_ppid" "$stat_group" "$stat_start" "$boot" "$stat_start"
40
+ if matches_token "$pid" && read_stat "$pid" && kill "-$requested_signal" "$pid" 2>/dev/null; then signal_sent=1; fi
41
+ fi
42
+ done
43
+ done
44
+ printf 'CODENOMAD_RESULT|%s\n' "$signal_sent"
45
+ `;
46
+ function failure(result, token) {
47
+ const message = result.error?.message || `launch cleanup command failed with exit code ${result.status}`;
48
+ return token ? redactToken(message, token) : message;
49
+ }
50
+ function redactToken(value, token) {
51
+ return value.split(token).join("[REDACTED]");
52
+ }
53
+ function parseIdentity(line) {
54
+ const fields = line.split("|");
55
+ if (fields.length !== 6)
56
+ return null;
57
+ const [pidText = "", parentPidText = "", groupIdText = "", startTime = "", bootId = "", startOrder = ""] = fields;
58
+ if (!/^\d+$/.test(pidText) || !/^\d+$/.test(parentPidText) || !/^\d+$/.test(groupIdText) ||
59
+ !startTime || !bootId || !/^\d+$/.test(startOrder))
60
+ return null;
61
+ const pid = Number.parseInt(pidText, 10);
62
+ const parentPid = Number.parseInt(parentPidText, 10);
63
+ const groupId = Number.parseInt(groupIdText, 10);
64
+ if (pid <= 0 || parentPid < 0 || groupId <= 0)
65
+ return null;
66
+ return { pid, parentPid, groupId, startTime, bootId, startOrder };
67
+ }
68
+ function runLinux(spawnCommand, script, args, timeoutMs, distro) {
69
+ return distro
70
+ ? spawnCommand("wsl.exe", ["--distribution", distro, "--exec", "sh", "-c", script, "codenomad-token-cleanup", ...args], {
71
+ encoding: "utf8",
72
+ timeout: timeoutMs,
73
+ })
74
+ : spawnCommand("sh", ["-c", script, "codenomad-token-cleanup", ...args], { encoding: "utf8", timeout: timeoutMs });
75
+ }
76
+ export function probeLaunchCleanupToken(spawnCommand, token, timeoutMs, distro) {
77
+ try {
78
+ const result = runLinux(spawnCommand, LINUX_TOKEN_PROBE_SCRIPT, [LAUNCH_CLEANUP_TOKEN_ENV, token], timeoutMs, distro);
79
+ if (result.status !== 0)
80
+ return { ok: false, error: failure(result, token) };
81
+ const processes = new Map();
82
+ for (const line of String(result.stdout ?? "").split(/\r?\n/)) {
83
+ if (!line)
84
+ continue;
85
+ const identity = parseIdentity(line);
86
+ if (!identity)
87
+ return { ok: false, error: "launch cleanup probe returned a malformed identity record" };
88
+ processes.set(identity.pid, identity);
89
+ }
90
+ return { ok: true, processes };
91
+ }
92
+ catch (error) {
93
+ return { ok: false, error: redactToken(error instanceof Error ? error.message : String(error), token) };
94
+ }
95
+ }
96
+ export function signalLaunchCleanupToken(spawnCommand, token, signal, timeoutMs, distro) {
97
+ try {
98
+ const signalName = signal === "SIGKILL" ? "KILL" : "TERM";
99
+ const result = runLinux(spawnCommand, LINUX_TOKEN_SIGNAL_SCRIPT, [LAUNCH_CLEANUP_TOKEN_ENV, token, signalName], timeoutMs, distro);
100
+ if (result.status !== 0)
101
+ return { ok: false, signalSent: false, targets: [], error: failure(result, token) };
102
+ const targets = new Map();
103
+ let signalSent;
104
+ for (const line of String(result.stdout ?? "").split(/\r?\n/)) {
105
+ if (!line)
106
+ continue;
107
+ if (line.startsWith("CODENOMAD_TARGET|")) {
108
+ const identity = parseIdentity(line.slice("CODENOMAD_TARGET|".length));
109
+ if (!identity)
110
+ return { ok: false, signalSent: false, targets: [], error: "launch cleanup signal returned a malformed target record" };
111
+ targets.set(identity.pid, identity);
112
+ continue;
113
+ }
114
+ if (line === "CODENOMAD_RESULT|0" || line === "CODENOMAD_RESULT|1") {
115
+ signalSent = line.endsWith("1");
116
+ continue;
117
+ }
118
+ return { ok: false, signalSent: false, targets: [], error: "launch cleanup signal returned unexpected output" };
119
+ }
120
+ return signalSent === undefined
121
+ ? { ok: false, signalSent: false, targets: [], error: "launch cleanup signal returned no structured result" }
122
+ : { ok: true, signalSent, targets: Array.from(targets.values()) };
123
+ }
124
+ catch (error) {
125
+ return {
126
+ ok: false,
127
+ signalSent: false,
128
+ targets: [],
129
+ error: redactToken(error instanceof Error ? error.message : String(error), token),
130
+ };
131
+ }
132
+ }
@@ -0,0 +1,33 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { LAUNCH_CLEANUP_TOKEN_ENV, probeLaunchCleanupToken, signalLaunchCleanupToken, } from "./launch-cleanup";
4
+ function result(stdout = "", status = 0, stderr = "") {
5
+ return { pid: 1, output: [null, stdout, stderr], stdout, stderr, status, signal: null };
6
+ }
7
+ describe("launch cleanup token adapter", () => {
8
+ it("passes the exact token to a bounded Linux environ probe", () => {
9
+ const token = "a".repeat(64);
10
+ let invocation;
11
+ const probe = probeLaunchCleanupToken(((command, args, options) => {
12
+ invocation = { command, args, timeout: options.timeout };
13
+ return result("5000|1|4242|150|boot-a|150\n");
14
+ }), token, 25);
15
+ assert.equal(probe.ok && probe.processes.get(5000)?.startOrder, "150");
16
+ assert.equal(invocation?.command, "sh");
17
+ assert.equal(invocation?.timeout, 25);
18
+ assert.ok(invocation?.args.includes(LAUNCH_CLEANUP_TOKEN_ENV));
19
+ assert.ok(invocation?.args.includes(token));
20
+ assert.match(invocation?.args[1] ?? "", /\/proc\/\$1\/environ/);
21
+ });
22
+ it("signals every exact-token target returned by the bounded adapter", () => {
23
+ const cleanup = signalLaunchCleanupToken((() => result("CODENOMAD_TARGET|4242|1|4242|100|boot-a|100\n" +
24
+ "CODENOMAD_TARGET|5000|1|4242|150|boot-a|150\n" +
25
+ "CODENOMAD_RESULT|1\n")), "b".repeat(64), "SIGKILL", 25);
26
+ assert.equal(cleanup.ok, true);
27
+ assert.deepEqual(cleanup.targets.map((target) => target.pid), [4242, 5000]);
28
+ });
29
+ it("rejects malformed cleanup records conservatively", () => {
30
+ const probe = probeLaunchCleanupToken((() => result("5000|1|4242|150|boot-a|150|truncated\n")), "c".repeat(64), 25);
31
+ assert.equal(probe.ok, false);
32
+ });
33
+ });