@lark-codem/codem-cli 0.1.266-dev.100103549344.0.g63304f4 → 0.1.266-dev.100103550201.0.g346816f
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/bin/codem.js +13 -0
- package/bin/worker-runtime.js +155 -0
- package/package.json +8 -8
- package/profile/runtime-logs.js +2 -0
- package/profile/worker-runtime-observation.js +10 -0
package/bin/codem.js
CHANGED
|
@@ -145,6 +145,19 @@ function explainWindowsFatalStatus(code) {
|
|
|
145
145
|
].join("\n");
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// Source/development and npm entrypoints select before invoking business code.
|
|
149
|
+
// The compiled entry has the same guard for managed/direct binary installations.
|
|
150
|
+
if (process.env.CODEM_WORKER_RUNTIME !== undefined) {
|
|
151
|
+
const { isWorkerRuntimeStartup } = await import("./worker-runtime.js");
|
|
152
|
+
if (isWorkerRuntimeStartup()) {
|
|
153
|
+
const bootstrap = await import("../dist/src/worker-runtime-bootstrap.js").catch(() => null);
|
|
154
|
+
if (bootstrap) {
|
|
155
|
+
try { process.exitCode = await bootstrap.runWorkerRuntimeBootstrap(); }
|
|
156
|
+
catch (error) { writeStderrSync(`worker runtime startup failed: ${error.message}`); process.exitCode = 1; }
|
|
157
|
+
process.exit(process.exitCode ?? 0);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
148
161
|
const binaryPath = resolvePlatformBinary();
|
|
149
162
|
|
|
150
163
|
if (binaryPath) {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Startup-only routing. Keep this module independent of Bridge business imports:
|
|
2
|
+
// it is also executed by container entrypoints before either Bridge is loaded.
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { pathToFileURL } from 'node:url';
|
|
9
|
+
import { applyHostedWindowsChildOptions } from './platform-child-process.js';
|
|
10
|
+
|
|
11
|
+
export const WORKER_HOST_HOME = path.join(os.homedir(), '.codem');
|
|
12
|
+
export const WORKER_RUNTIME_ROOT = path.join(WORKER_HOST_HOME, 'worker-runtimes');
|
|
13
|
+
export const EXACT_RUNTIME_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
14
|
+
const families = ['stable', 'current'];
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async function readJSON(file) { return JSON.parse(await fs.readFile(file, 'utf8')); }
|
|
18
|
+
async function confinedFile(root, relative) {
|
|
19
|
+
if (typeof relative !== 'string' || !relative || path.isAbsolute(relative)) throw new Error('invalid runtime path');
|
|
20
|
+
const realRoot = await fs.realpath(root);
|
|
21
|
+
const resolved = await fs.realpath(path.resolve(realRoot, relative));
|
|
22
|
+
const inside = path.relative(realRoot, resolved);
|
|
23
|
+
if (!inside || inside === '..' || inside.startsWith(`..${path.sep}`) || path.isAbsolute(inside)) throw new Error('runtime path escapes pair');
|
|
24
|
+
if (!(await fs.stat(resolved)).isFile()) throw new Error('runtime entry is not a file');
|
|
25
|
+
return resolved;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Only installers write these immutable pair manifests. No npm resolution or
|
|
29
|
+
// floating global/current Core lookup happens in the execution process.
|
|
30
|
+
export async function readWorkerRuntime(root, family, { version = null } = {}) {
|
|
31
|
+
if (!families.includes(family)) throw new Error('invalid worker runtime');
|
|
32
|
+
const familyRoot = path.join(root, family);
|
|
33
|
+
let pointerChannel = null;
|
|
34
|
+
let runtimeRoot = version ? path.join(familyRoot, 'versions', version) : familyRoot;
|
|
35
|
+
if (version && !EXACT_RUNTIME_VERSION.test(version)) throw new Error('invalid runtime version');
|
|
36
|
+
if (!version) try {
|
|
37
|
+
const pointer = await readJSON(path.join(familyRoot, 'current.json'));
|
|
38
|
+
if (!EXACT_RUNTIME_VERSION.test(pointer.version)) throw new Error('invalid runtime pointer');
|
|
39
|
+
pointerChannel = pointer.channel;
|
|
40
|
+
runtimeRoot = path.join(familyRoot, 'versions', pointer.version);
|
|
41
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
42
|
+
const manifest = await readJSON(path.join(runtimeRoot, 'runtime-manifest.json'));
|
|
43
|
+
if (manifest.schema !== 1 || manifest.family !== family || !EXACT_RUNTIME_VERSION.test(manifest.cliVersion) || !EXACT_RUNTIME_VERSION.test(manifest.coreVersion)) throw new Error('invalid runtime manifest');
|
|
44
|
+
if (manifest.workflowPrebound !== (family === 'current')) throw new Error('runtime architecture does not match family');
|
|
45
|
+
const cliEntry = await confinedFile(runtimeRoot, manifest.cliEntry);
|
|
46
|
+
const corePath = await confinedFile(runtimeRoot, manifest.coreBinaryPath);
|
|
47
|
+
return { ...manifest, ...(pointerChannel ? { channel: pointerChannel } : {}), root: runtimeRoot, cliEntry, corePath };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function routeIdentity(env) {
|
|
51
|
+
const values = [env.CODEM_SANDBOX_TENANT_KEY, env.CODEM_SANDBOX_PROJECT_KEY, env.CODEM_SANDBOX_SESSION_ID];
|
|
52
|
+
if (values.some(value => typeof value !== 'string' || !value.trim() || value.length > 1024 || /[\0\r\n]/.test(value))) throw new Error('worker runtime requires trusted tenant/project/session');
|
|
53
|
+
const scope = createHash('sha256').update(JSON.stringify(values)).digest('hex');
|
|
54
|
+
const sessions = env.LINCO_SESSIONS_ROOT || path.join(os.homedir(), '.codem', 'sessions');
|
|
55
|
+
if (!path.isAbsolute(sessions)) throw new Error('worker runtime sessions root must be absolute');
|
|
56
|
+
return { scope, markerPath: path.join(path.dirname(sessions), 'worker-runtime-routes', `${scope}.json`) };
|
|
57
|
+
}
|
|
58
|
+
async function readRoute(markerPath, scope) {
|
|
59
|
+
try {
|
|
60
|
+
const marker = await readJSON(markerPath);
|
|
61
|
+
if (marker.schema !== 1 || marker.scope !== scope || !families.includes(marker.family)) throw new Error('identity or schema mismatch');
|
|
62
|
+
return marker.family;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (error.code === 'ENOENT') return null;
|
|
65
|
+
throw new Error('invalid runtime route', { cause: error });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function recordRoute(markerPath, scope, family) {
|
|
69
|
+
await fs.mkdir(path.dirname(markerPath), { recursive: true, mode: 0o700 });
|
|
70
|
+
const temporary = `${markerPath}.${randomUUID()}.tmp`;
|
|
71
|
+
try {
|
|
72
|
+
await fs.writeFile(temporary, `${JSON.stringify({ schema: 1, scope, family })}\n`, { mode: 0o600, flag: 'wx' });
|
|
73
|
+
// No overwrite: concurrent first starts must agree before either starts work.
|
|
74
|
+
try { await fs.link(temporary, markerPath); } catch (error) { if (error.code !== 'EEXIST') throw error; }
|
|
75
|
+
} finally { await fs.rm(temporary, { force: true }); }
|
|
76
|
+
return readRoute(markerPath, scope);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function selectWorkerRuntime({ env = process.env, root = env.CODEM_WORKER_RUNTIME_ROOT || WORKER_RUNTIME_ROOT, loadRuntime = readWorkerRuntime, currentChannel = null } = {}) {
|
|
80
|
+
const requested = env.CODEM_WORKER_RUNTIME;
|
|
81
|
+
if (!families.includes(requested)) throw new Error('invalid worker runtime');
|
|
82
|
+
const { scope, markerPath } = routeIdentity(env);
|
|
83
|
+
let actual = await readRoute(markerPath, scope);
|
|
84
|
+
const restoring = env.CODEM_TASK_MODE === 'resume';
|
|
85
|
+
const upgradeFrom = env.CODEM_WORKER_RUNTIME_UPGRADE_FROM;
|
|
86
|
+
if (upgradeFrom !== undefined && (upgradeFrom !== 'stable' || !restoring || requested !== 'current')) throw new Error('invalid worker runtime upgrade');
|
|
87
|
+
const upgrading = upgradeFrom === 'stable' && actual === 'stable';
|
|
88
|
+
// Historical state without proven family cannot safely be assigned to either
|
|
89
|
+
// architecture. Core remains responsible for validating checkpoint contents.
|
|
90
|
+
if (!actual && restoring) throw new Error('workflow runtime family unknown: recovery evidence required');
|
|
91
|
+
const reasons = [];
|
|
92
|
+
const load = async family => {
|
|
93
|
+
try {
|
|
94
|
+
const runtime = await loadRuntime(root, family);
|
|
95
|
+
// A retained alpha pair can recover its own Session, but cannot serve a new
|
|
96
|
+
// latest-channel Session after a failed channel switch.
|
|
97
|
+
if ((!actual || upgrading) && family === 'current' && currentChannel !== null && runtime.channel !== currentChannel) throw new Error('worker runtime channel unavailable');
|
|
98
|
+
return runtime;
|
|
99
|
+
} catch { reasons.push(`${family}_unavailable`); return null; }
|
|
100
|
+
};
|
|
101
|
+
let runtime = upgrading ? await load('current') : actual ? await load(actual) : await load(requested);
|
|
102
|
+
if (!actual && !runtime && requested === 'current') runtime = await load('stable');
|
|
103
|
+
if (!runtime) throw new Error(`${actual ? 'required ' : ''}runtime unavailable: ${reasons.join(',')}`);
|
|
104
|
+
if (upgrading) {
|
|
105
|
+
// Only an admitted failed recovery may move stable -> current. Publish after
|
|
106
|
+
// validating the pair, before any business process starts. Promotion is one-way;
|
|
107
|
+
// concurrent admitted promotions write identical identity/family bytes.
|
|
108
|
+
const temporary = `${markerPath}.${randomUUID()}.tmp`;
|
|
109
|
+
try {
|
|
110
|
+
await fs.writeFile(temporary, `${JSON.stringify({ schema: 1, scope, family: 'current' })}\n`, { mode: 0o600, flag: 'wx' });
|
|
111
|
+
await fs.rename(temporary, markerPath);
|
|
112
|
+
} finally { await fs.rm(temporary, { force: true }); }
|
|
113
|
+
actual = 'current';
|
|
114
|
+
}
|
|
115
|
+
if (!actual) {
|
|
116
|
+
actual = await recordRoute(markerPath, scope, runtime.family);
|
|
117
|
+
if (actual !== runtime.family) {
|
|
118
|
+
runtime = await load(actual);
|
|
119
|
+
if (!runtime) throw new Error('required runtime unavailable after concurrent selection');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { ...runtime, requested, markerPath, fallbackReason: requested !== runtime.family ? reasons.join(',') || 'session_family' : null };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function launchWorkerRuntime(runtime, { args = process.argv.slice(2), env = process.env, nodePath = process.execPath, invocation = null, log = console.error } = {}) {
|
|
126
|
+
log(JSON.stringify({ event: 'worker_runtime_selected', requested_family: runtime.requested, actual_family: runtime.family, fallback_reason: runtime.fallbackReason,
|
|
127
|
+
bridge_version: runtime.cliVersion, core_version: runtime.coreVersion, pair: `${runtime.cliVersion}/${runtime.coreVersion}`, dispatch_id: env.CODEM_SANDBOX_DISPATCH_ID, session_id: env.CODEM_SANDBOX_SESSION_ID }));
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
const launch = invocation || { command: nodePath, args: [runtime.cliEntry, ...args] };
|
|
130
|
+
const child = spawn(launch.command, launch.args, applyHostedWindowsChildOptions({ ...launch.options, stdio: 'inherit', env: { ...env,
|
|
131
|
+
CODEM_LINCO_PATH: runtime.corePath, CODEM_WORKER_RUNTIME_READY: '1', CODEM_WORKER_RUNTIME_ACTUAL: runtime.family, CODEM_WORKER_CLI_VERSION: runtime.cliVersion, CODEM_WORKER_CORE_VERSION: runtime.coreVersion,
|
|
132
|
+
CODEM_PLUGIN_NODE: env.CODEM_PLUGIN_NODE || nodePath,
|
|
133
|
+
CODEM_SKIP_UPDATE_CHECK: '1', CODEM_DISABLE_DAEMON_AUTO_UPDATE: '1' } }));
|
|
134
|
+
const signals = ['SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
135
|
+
const handlers = signals.map(signal => () => { if (child.exitCode === null && child.signalCode === null) { try { child.kill(signal); } catch {} } });
|
|
136
|
+
signals.forEach((signal, index) => process.on(signal, handlers[index]));
|
|
137
|
+
const cleanup = () => signals.forEach((signal, index) => process.off(signal, handlers[index]));
|
|
138
|
+
child.once('error', error => { cleanup(); reject(error); });
|
|
139
|
+
child.once('exit', (code, signal) => { cleanup(); resolve(code ?? (signal ? 128 + (os.constants.signals[signal] || 1) : 1)); });
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function isWorkerRuntimeStartup(args = process.argv.slice(2), env = process.env) {
|
|
144
|
+
return env.CODEM_WORKER_RUNTIME !== undefined && env.CODEM_WORKER_RUNTIME_READY !== '1' && args[0] === 'daemon' && args.some(arg => arg === '--sandbox' || arg.startsWith('--sandbox='));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Container entrypoints invoke this directly, with a baked immutable root.
|
|
148
|
+
async function runStandalone() {
|
|
149
|
+
try {
|
|
150
|
+
const runtime = await selectWorkerRuntime();
|
|
151
|
+
process.exitCode = await launchWorkerRuntime(runtime, { nodePath: process.execPath });
|
|
152
|
+
} catch (error) { console.error(`worker runtime startup failed: ${error.message}`); process.exitCode = 1; }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (typeof Bun === 'undefined' && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) void runStandalone();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-codem/codem-cli",
|
|
3
|
-
"version": "0.1.266-dev.
|
|
3
|
+
"version": "0.1.266-dev.100103550201.0.g346816f",
|
|
4
4
|
"codemServiceManagementProtocol": 3,
|
|
5
5
|
"codemProfileProtocol": 1,
|
|
6
6
|
"type": "module",
|
|
@@ -29,17 +29,17 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@lark-codem/codem-core": "0.8.80-dev.
|
|
32
|
+
"@lark-codem/codem-core": "0.8.80-dev.100103550201.0.g581a12e",
|
|
33
33
|
"zod": "3.25.76",
|
|
34
34
|
"@lark-codem/lark-cli": "0.1.1"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@lark-codem/codem-cli-darwin-arm64": "0.1.266-dev.
|
|
38
|
-
"@lark-codem/codem-cli-darwin-x64": "0.1.266-dev.
|
|
39
|
-
"@lark-codem/codem-cli-linux-arm64": "0.1.266-dev.
|
|
40
|
-
"@lark-codem/codem-cli-linux-x64": "0.1.266-dev.
|
|
41
|
-
"@lark-codem/codem-cli-win32-arm64": "0.1.266-dev.
|
|
42
|
-
"@lark-codem/codem-cli-win32-x64": "0.1.266-dev.
|
|
37
|
+
"@lark-codem/codem-cli-darwin-arm64": "0.1.266-dev.100103550201.0.g346816f",
|
|
38
|
+
"@lark-codem/codem-cli-darwin-x64": "0.1.266-dev.100103550201.0.g346816f",
|
|
39
|
+
"@lark-codem/codem-cli-linux-arm64": "0.1.266-dev.100103550201.0.g346816f",
|
|
40
|
+
"@lark-codem/codem-cli-linux-x64": "0.1.266-dev.100103550201.0.g346816f",
|
|
41
|
+
"@lark-codem/codem-cli-win32-arm64": "0.1.266-dev.100103550201.0.g346816f",
|
|
42
|
+
"@lark-codem/codem-cli-win32-x64": "0.1.266-dev.100103550201.0.g346816f"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=18"
|
package/profile/runtime-logs.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { workerRuntimeAttributes } from "./worker-runtime-observation.js";
|
|
1
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
3
|
import os from "node:os";
|
|
3
4
|
import fs from "node:fs";
|
|
@@ -234,6 +235,7 @@ export class RuntimeLogReporter {
|
|
|
234
235
|
const severity = ["info", "warn", "error", "fatal"].includes(level) ? level : "info";
|
|
235
236
|
const identity = { ...this.#identity };
|
|
236
237
|
const category = {
|
|
238
|
+
...workerRuntimeAttributes(),
|
|
237
239
|
client_kind: "cli", runtime_role: this.#role, reporter: "codem_js", log_schema: "1",
|
|
238
240
|
component: token(component) ?? "unknown", event: token(event) ?? "unknown", severity,
|
|
239
241
|
identity_source: identity.deviceId ? "codem" : "process",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const exactVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
2
|
+
|
|
3
|
+
// Low-cardinality process context shared by existing logs, metric categories,
|
|
4
|
+
// and tracing. Ordinary personal-Bot processes have no worker attribution.
|
|
5
|
+
export function workerRuntimeAttributes(env = process.env) {
|
|
6
|
+
if (env.CODEM_WORKER_RUNTIME_READY !== '1' || !['stable', 'current'].includes(env.CODEM_WORKER_RUNTIME_ACTUAL)) return {};
|
|
7
|
+
return { worker_runtime_family: env.CODEM_WORKER_RUNTIME_ACTUAL,
|
|
8
|
+
...(exactVersion.test(env.CODEM_WORKER_CLI_VERSION || '') ? { worker_cli_version: env.CODEM_WORKER_CLI_VERSION } : {}),
|
|
9
|
+
...(exactVersion.test(env.CODEM_WORKER_CORE_VERSION || '') ? { worker_core_version: env.CODEM_WORKER_CORE_VERSION } : {}) };
|
|
10
|
+
}
|