@tiangong-lca/cli 0.1.10 → 0.1.12

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 (32) hide show
  1. package/README.md +5 -3
  2. package/assets/runtime/runtime-manifest.schema.json +3 -0
  3. package/dist/src/lib/runtime/exec-command.js +4 -1
  4. package/dist/src/lib/runtime/exec-command.js.map +1 -1
  5. package/dist/src/lib/runtime/execute.d.ts +4 -3
  6. package/dist/src/lib/runtime/execute.js +24 -17
  7. package/dist/src/lib/runtime/execute.js.map +1 -1
  8. package/dist/src/lib/runtime/host-context-protocol.d.ts +20 -0
  9. package/dist/src/lib/runtime/host-context-protocol.js +83 -0
  10. package/dist/src/lib/runtime/host-context-protocol.js.map +1 -0
  11. package/dist/src/lib/runtime/host-context-server.d.ts +6 -0
  12. package/dist/src/lib/runtime/host-context-server.js +81 -0
  13. package/dist/src/lib/runtime/host-context-server.js.map +1 -0
  14. package/dist/src/lib/runtime/host-context.d.ts +23 -0
  15. package/dist/src/lib/runtime/host-context.js +122 -0
  16. package/dist/src/lib/runtime/host-context.js.map +1 -0
  17. package/dist/src/lib/runtime/manifest-types.d.ts +9 -0
  18. package/dist/src/lib/runtime/manifest-types.js +1 -0
  19. package/dist/src/lib/runtime/manifest-types.js.map +1 -1
  20. package/dist/src/lib/runtime/manifest.d.ts +1 -0
  21. package/dist/src/lib/runtime/manifest.js +26 -7
  22. package/dist/src/lib/runtime/manifest.js.map +1 -1
  23. package/dist/src/lib/runtime/process.d.ts +2 -1
  24. package/dist/src/lib/runtime/process.js +16 -2
  25. package/dist/src/lib/runtime/process.js.map +1 -1
  26. package/dist/src/lib/runtime/work-directory.d.ts +2 -0
  27. package/dist/src/lib/runtime/work-directory.js +16 -0
  28. package/dist/src/lib/runtime/work-directory.js.map +1 -0
  29. package/dist/src/runtime.d.ts +5 -4
  30. package/dist/src/runtime.js +3 -2
  31. package/dist/src/runtime.js.map +1 -1
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -31,13 +31,15 @@ checkPaths:
31
31
  - test/auth-identity*.test.ts
32
32
  - test/public-auth-identity-receipt.test.ts
33
33
  - test/lca-release*.test.ts
34
- lastReviewedAt: 2026-09-05
35
- lastReviewedCommit: 20cf32fd45ae1072bb67db27c74d3d81629206f4
36
- lastReviewedNote: 'Reviewed for CLI #275: release-only 0.1.10 publishes merged runtime manager/bootstrap #274; runtime, dependencies, lock bytes and workflows stay at reviewed merge 20cf32f while release proof adds native and public provenance consumers.'
34
+ lastReviewedAt: 2026-09-08
35
+ lastReviewedCommit: f28aea717219b37a5f055acf08cb3d0a14b77c57
36
+ lastReviewedNote: 'Reviewed for CLI #290: version-only 0.1.12 publishes the Windows HTTP bootstrap correction from merged mainf28aea7 after all four native gates. Only package identity, four version fixtures and single-line review metadata advance; dependency/lock/runtime behavior remain as the qualified source. Immutable tag, public provenance/package/script verification and downstream adoption are still required.'
37
37
  ---
38
38
 
39
39
  CLI 0.1.10 is the designated C1 release for `tiangong-lca runtime describe --json` and the explicit `@tiangong-lca/cli/runtime` API for package, asset and Node content inspection. Runtime inspection loads no project `.env`, performs no authentication and downloads nothing. See [the runtime distribution contract](docs/agents/runtime-distribution-contract.md) for exact fields and trust boundaries; verify public availability and provenance before treating the candidate version as released.
40
40
 
41
+ Issue #278 adds a managed Node host interface in source, for the subsequent qualified CLI release. A release manifest opts its launch into `tiangong-lca.runtime-host.v1`; the host calls `receiveRuntimeHostContext()` from `@tiangong-lca/cli/runtime` before application work. The immutable result carries the selected full manifest, work/cache directories, entry and actual host. `copyTrustedRuntimeManifestBytes(context.manifest)` supplies original verified bytes for another package instance's compatibility checks. The channel closes before the receiver returns, and ordinary task arguments or environment values cannot supply this context. See the runtime distribution contract for lifecycle and trust requirements.
42
+
41
43
  # TianGong LCA CLI
42
44
 
43
45
  Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Current package version: `0.1.10` Node: `24.19.0`
@@ -334,6 +334,9 @@
334
334
  "environment": {
335
335
  "enum": ["isolated", "cli-auth"]
336
336
  },
337
+ "context_protocol": {
338
+ "const": "tiangong-lca.runtime-host.v1"
339
+ },
337
340
  "argv": {
338
341
  "type": "array",
339
342
  "items": {
@@ -63,7 +63,10 @@ export async function runRuntimeExecCommand(args, fetchImpl, env = process.env,
63
63
  ? 1
64
64
  : (result.status ?? (result.signal ? 130 : 1)),
65
65
  stdout: result.stdout,
66
- stderr: result.stderr,
66
+ stderr: result.stderr ||
67
+ (result.error && 'code' in result.error && result.error.code === 'RUNTIME_HOST_CONTEXT'
68
+ ? `${result.error.message}\n`
69
+ : ''),
67
70
  };
68
71
  }
69
72
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"exec-command.js","sourceRoot":"","sources":["../../../../src/lib/runtime/exec-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseArgs } from 'node:util';\nimport { CliError } from '../errors.js';\nimport type { FetchLike } from '../http.js';\nimport { loadTrustedRuntimeManifest } from './manifest.js';\nimport { executeRuntimeLaunch } from './execute.js';\nexport async function runRuntimeExecCommand(\n args: string[],\n fetchImpl?: FetchLike,\n env: NodeJS.ProcessEnv = process.env,\n run: typeof executeRuntimeLaunch = executeRuntimeLaunch,\n): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n const separator = args.indexOf('--'),\n options = separator < 0 ? args : args.slice(0, separator),\n argv = separator < 0 ? [] : args.slice(separator + 1);\n let flags;\n try {\n flags = parseArgs({\n args: options,\n strict: true,\n allowPositionals: false,\n options: {\n help: { type: 'boolean', short: 'h' },\n manifest: { type: 'string' },\n 'manifest-sha256': { type: 'string' },\n 'cache-dir': { type: 'string' },\n entry: { type: 'string' },\n cwd: { type: 'string' },\n lease: { type: 'string' },\n 'lease-owner': { type: 'string' },\n },\n }).values;\n } catch {\n throw new CliError('Invalid runtime exec arguments.', {\n code: 'RUNTIME_ARGUMENT_INVALID',\n exitCode: 2,\n });\n }\n if (flags.help)\n return {\n exitCode: 0,\n stdout:\n 'Usage: tiangong-lca runtime exec --manifest <file> --manifest-sha256 <trusted-sha256> --entry <id> --cwd <work-directory> [--cache-dir <dir>] [--lease <id> --lease-owner <owner>] -- <application argv>\\n',\n stderr: '',\n };\n if (\n !flags.manifest ||\n !flags['manifest-sha256'] ||\n !flags.entry ||\n !flags.cwd ||\n Boolean(flags.lease) !== Boolean(flags['lease-owner'])\n )\n throw new CliError(\n 'Runtime exec requires manifest, trust digest, entry and explicit work directory.',\n { code: 'RUNTIME_ARGUMENT_INVALID', exitCode: 2 },\n );\n const value = loadTrustedRuntimeManifest(flags.manifest, flags['manifest-sha256']);\n const abort = new AbortController();\n const stop = () => abort.abort();\n process.once('SIGINT', stop);\n process.once('SIGTERM', stop);\n try {\n const result = await run(value, {\n cacheDir: flags['cache-dir'],\n entry: flags.entry,\n cwd: flags.cwd,\n argv,\n env,\n fetchImpl,\n signal: abort.signal,\n ...(flags.lease ? { lease: { id: flags.lease, owner: flags['lease-owner']! } } : {}),\n });\n return {\n exitCode: abort.signal.aborted\n ? 130\n : result.error\n ? 1\n : (result.status ?? (result.signal ? 130 : 1)),\n stdout: result.stdout,\n stderr: result.stderr,\n };\n } catch (error) {\n if (abort.signal.aborted)\n return {\n exitCode: 130,\n stdout: '',\n stderr:\n 'Runtime execution interrupted; application recovery must preserve existing attempts.\\n',\n };\n throw error;\n } finally {\n process.removeListener('SIGINT', stop);\n process.removeListener('SIGTERM', stop);\n }\n}\n"]}
1
+ {"version":3,"file":"exec-command.js","sourceRoot":"","sources":["../../../../src/lib/runtime/exec-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseArgs } from 'node:util';\nimport { CliError } from '../errors.js';\nimport type { FetchLike } from '../http.js';\nimport { loadTrustedRuntimeManifest } from './manifest.js';\nimport { executeRuntimeLaunch } from './execute.js';\nexport async function runRuntimeExecCommand(\n args: string[],\n fetchImpl?: FetchLike,\n env: NodeJS.ProcessEnv = process.env,\n run: typeof executeRuntimeLaunch = executeRuntimeLaunch,\n): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n const separator = args.indexOf('--'),\n options = separator < 0 ? args : args.slice(0, separator),\n argv = separator < 0 ? [] : args.slice(separator + 1);\n let flags;\n try {\n flags = parseArgs({\n args: options,\n strict: true,\n allowPositionals: false,\n options: {\n help: { type: 'boolean', short: 'h' },\n manifest: { type: 'string' },\n 'manifest-sha256': { type: 'string' },\n 'cache-dir': { type: 'string' },\n entry: { type: 'string' },\n cwd: { type: 'string' },\n lease: { type: 'string' },\n 'lease-owner': { type: 'string' },\n },\n }).values;\n } catch {\n throw new CliError('Invalid runtime exec arguments.', {\n code: 'RUNTIME_ARGUMENT_INVALID',\n exitCode: 2,\n });\n }\n if (flags.help)\n return {\n exitCode: 0,\n stdout:\n 'Usage: tiangong-lca runtime exec --manifest <file> --manifest-sha256 <trusted-sha256> --entry <id> --cwd <work-directory> [--cache-dir <dir>] [--lease <id> --lease-owner <owner>] -- <application argv>\\n',\n stderr: '',\n };\n if (\n !flags.manifest ||\n !flags['manifest-sha256'] ||\n !flags.entry ||\n !flags.cwd ||\n Boolean(flags.lease) !== Boolean(flags['lease-owner'])\n )\n throw new CliError(\n 'Runtime exec requires manifest, trust digest, entry and explicit work directory.',\n { code: 'RUNTIME_ARGUMENT_INVALID', exitCode: 2 },\n );\n const value = loadTrustedRuntimeManifest(flags.manifest, flags['manifest-sha256']);\n const abort = new AbortController();\n const stop = () => abort.abort();\n process.once('SIGINT', stop);\n process.once('SIGTERM', stop);\n try {\n const result = await run(value, {\n cacheDir: flags['cache-dir'],\n entry: flags.entry,\n cwd: flags.cwd,\n argv,\n env,\n fetchImpl,\n signal: abort.signal,\n ...(flags.lease ? { lease: { id: flags.lease, owner: flags['lease-owner']! } } : {}),\n });\n return {\n exitCode: abort.signal.aborted\n ? 130\n : result.error\n ? 1\n : (result.status ?? (result.signal ? 130 : 1)),\n stdout: result.stdout,\n stderr:\n result.stderr ||\n (result.error && 'code' in result.error && result.error.code === 'RUNTIME_HOST_CONTEXT'\n ? `${result.error.message}\\n`\n : ''),\n };\n } catch (error) {\n if (abort.signal.aborted)\n return {\n exitCode: 130,\n stdout: '',\n stderr:\n 'Runtime execution interrupted; application recovery must preserve existing attempts.\\n',\n };\n throw error;\n } finally {\n process.removeListener('SIGINT', stop);\n process.removeListener('SIGTERM', stop);\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { executeFoundryCommandSpec, type FoundryCommandSpecSpawnResult } from '../../command-spec.js';
1
+ import { type FoundryCommandSpecSpawnResult, type FoundryCommandSpecAsyncSpawnOptions } from '../../command-spec.js';
2
2
  import { type RuntimeManagerOptions } from './manager.js';
3
- import type { TrustedRuntimeManifest } from './manifest-types.js';
3
+ import type { TrustedRuntimeManifest, RuntimeHostContext } from './manifest-types.js';
4
4
  export declare function runtimeChildEnvironment(source: NodeJS.ProcessEnv, mode: 'isolated' | 'cli-auth'): NodeJS.ProcessEnv;
5
5
  export type RuntimeExecutionOptions = RuntimeManagerOptions & {
6
6
  entry: string;
@@ -8,4 +8,5 @@ export type RuntimeExecutionOptions = RuntimeManagerOptions & {
8
8
  argv: readonly string[];
9
9
  env?: Record<string, string | undefined>;
10
10
  };
11
- export declare function executeRuntimeLaunch(value: TrustedRuntimeManifest, options: RuntimeExecutionOptions, spawnImpl?: Parameters<typeof executeFoundryCommandSpec>[1]['spawnImpl']): Promise<FoundryCommandSpecSpawnResult>;
11
+ export type RuntimeExecutionSpawn = (executable: string, argv: readonly string[], options: FoundryCommandSpecAsyncSpawnOptions, context?: RuntimeHostContext) => Promise<FoundryCommandSpecSpawnResult>;
12
+ export declare function executeRuntimeLaunch(value: TrustedRuntimeManifest, options: RuntimeExecutionOptions, spawnImpl?: RuntimeExecutionSpawn): Promise<FoundryCommandSpecSpawnResult>;
@@ -1,5 +1,4 @@
1
1
  import fs from 'node:fs';
2
- import path from 'node:path';
3
2
  import { randomUUID } from 'node:crypto';
4
3
  import { createFoundryCommandSpec, executeFoundryCommandSpec, } from '../../command-spec.js';
5
4
  import { ensureRuntimeComponents, inspectRuntimeComponents, } from './manager.js';
@@ -9,6 +8,7 @@ import { cachePath, defaultRuntimeCache, openRuntimeCache } from './storage.js';
9
8
  import { assertTrustedManifest, componentKey } from './manifest.js';
10
9
  import { inspectRuntimeHost } from './host.js';
11
10
  import { runtimeError } from './files.js';
11
+ import { runtimeWorkDirectory, assertRuntimeWorkDirectoryOutsideInstall, } from './work-directory.js';
12
12
  const systemKeys = [
13
13
  'PATH',
14
14
  'Path',
@@ -52,24 +52,25 @@ export function runtimeChildEnvironment(source, mode) {
52
52
  }
53
53
  export async function executeRuntimeLaunch(value, options, spawnImpl) {
54
54
  assertTrustedManifest(value);
55
- const host = options.host ?? inspectRuntimeHost();
55
+ const observedHost = options.host ?? inspectRuntimeHost();
56
+ const host = Object.freeze({
57
+ platform: observedHost.platform,
58
+ osRelease: observedHost.osRelease,
59
+ glibc: observedHost.glibc,
60
+ });
56
61
  const launch = value.manifest.launches.find((item) => item.id === options.entry && item.platform === host.platform);
57
62
  if (!launch)
58
63
  runtimeError('RUNTIME_LAUNCH_UNKNOWN', 'Selected runtime entry is not declared for this host.');
59
- if (options.argv.length > 512 ||
60
- options.argv.some((arg) => typeof arg !== 'string' ||
61
- arg.includes('\0') ||
62
- arg.length > 32768 ||
63
- /^--(?:username|password|api-key|access-token|refresh-token|authorization-code|oauth-code)(?:=|$)/iu.test(arg)))
64
+ if (options.argv.length > 512)
64
65
  runtimeError('RUNTIME_LAUNCH_ARGUMENT', 'Runtime argv must be bounded and contain no credential arguments.');
65
- if (!path.isAbsolute(options.cwd) || !fs.statSync(options.cwd).isDirectory())
66
- runtimeError('RUNTIME_LAUNCH_CWD', 'Runtime launch requires an explicit existing work directory.');
67
- const cwd = fs.realpathSync(options.cwd), cache = openRuntimeCache(options.cacheDir ?? defaultRuntimeCache(), false);
68
- const relative = path.relative(cache, cwd);
69
- if (relative === '' ||
70
- (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative)) ||
71
- /\/(?:\.agents|\.codex)\/skills(?:\/|$)/u.test(cwd.split(path.sep).join('/')))
72
- runtimeError('RUNTIME_LAUNCH_CWD', 'A runtime cache or installed skill cannot be used as the work directory.');
66
+ const applicationArgv = [...options.argv];
67
+ if (applicationArgv.some((arg) => typeof arg !== 'string' ||
68
+ arg.includes('\0') ||
69
+ arg.length > 32768 ||
70
+ /^--(?:username|password|api-key|access-token|refresh-token|authorization-code|oauth-code)(?:=|$)/iu.test(arg)))
71
+ runtimeError('RUNTIME_LAUNCH_ARGUMENT', 'Runtime argv must be bounded and contain no credential arguments.');
72
+ const cwd = runtimeWorkDirectory(options.cwd), cache = openRuntimeCache(options.cacheDir ?? defaultRuntimeCache(), false);
73
+ assertRuntimeWorkDirectoryOutsideInstall(cwd, cache);
73
74
  const lease = { id: `execution-${randomUUID()}`, owner: `runtime-execution:${process.pid}` };
74
75
  let drain;
75
76
  try {
@@ -97,7 +98,7 @@ export async function executeRuntimeLaunch(value, options, spawnImpl) {
97
98
  .map(artifact);
98
99
  const argv = launch.argv
99
100
  .map((arg) => ('literal' in arg ? arg.literal : artifact(arg).path))
100
- .concat([...options.argv]);
101
+ .concat(applicationArgv);
101
102
  const spec = createFoundryCommandSpec({
102
103
  executable: program.path,
103
104
  argv,
@@ -110,7 +111,13 @@ export async function executeRuntimeLaunch(value, options, spawnImpl) {
110
111
  maxBuffer: 16 * 1024 * 1024,
111
112
  resolveArtifactPath: (file) => file,
112
113
  spawnImpl: (executable, argv, childOptions) => {
113
- drain = (spawnImpl ?? spawnRuntimeProcess)(executable, argv, childOptions);
114
+ const context = launch.context_protocol
115
+ ? Object.freeze({ manifest: value, cacheDir: cache, cwd, entry: launch.id, host })
116
+ : undefined;
117
+ const spawn = spawnImpl ?? spawnRuntimeProcess;
118
+ drain = context
119
+ ? spawn(executable, argv, childOptions, context)
120
+ : spawn(executable, argv, childOptions);
114
121
  return drain;
115
122
  },
116
123
  });
@@ -1 +1 @@
1
- {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../../src/lib/runtime/execute.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport {\n createFoundryCommandSpec,\n executeFoundryCommandSpec,\n type FoundryCommandSpecSpawnResult,\n} from '../../command-spec.js';\nimport {\n ensureRuntimeComponents,\n inspectRuntimeComponents,\n type RuntimeManagerOptions,\n} from './manager.js';\nimport { spawnRuntimeProcess } from './process.js';\nimport { acquireRuntimeLease, releaseRuntimeLease } from './leases.js';\nimport { cachePath, defaultRuntimeCache, openRuntimeCache } from './storage.js';\nimport { assertTrustedManifest, componentKey } from './manifest.js';\nimport { inspectRuntimeHost } from './host.js';\nimport { runtimeError } from './files.js';\nimport type { TrustedRuntimeManifest, ComponentPath } from './manifest-types.js';\n\nconst systemKeys = [\n 'PATH',\n 'Path',\n 'PATHEXT',\n 'SystemRoot',\n 'SYSTEMROOT',\n 'WINDIR',\n 'ComSpec',\n 'COMSPEC',\n 'HOME',\n 'USERPROFILE',\n 'APPDATA',\n 'LOCALAPPDATA',\n 'XDG_CONFIG_HOME',\n 'XDG_CACHE_HOME',\n 'TMPDIR',\n 'TEMP',\n 'TMP',\n 'LANG',\n 'LC_ALL',\n 'TZ',\n] as const;\nconst authKeys = [\n 'TIANGONG_LCA_API_BASE_URL',\n 'TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY',\n 'TIANGONG_LCA_OAUTH_CLIENT_ID',\n 'TIANGONG_LCA_OAUTH_REDIRECT_URI',\n 'TIANGONG_LCA_REGION',\n 'TIANGONG_LCA_AUTH_MODE',\n 'TIANGONG_LCA_SESSION_FILE',\n 'TIANGONG_LCA_DISABLE_SESSION_CACHE',\n 'TIANGONG_LCA_FORCE_REAUTH',\n 'TIANGONG_LCA_ACCESS_TOKEN',\n] as const;\nexport function runtimeChildEnvironment(\n source: NodeJS.ProcessEnv,\n mode: 'isolated' | 'cli-auth',\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const key of [...systemKeys, ...(mode === 'cli-auth' ? authKeys : [])])\n if (source[key] !== undefined) env[key] = source[key];\n return env;\n}\nexport type RuntimeExecutionOptions = RuntimeManagerOptions & {\n entry: string;\n cwd: string;\n argv: readonly string[];\n env?: Record<string, string | undefined>;\n};\nexport async function executeRuntimeLaunch(\n value: TrustedRuntimeManifest,\n options: RuntimeExecutionOptions,\n spawnImpl?: Parameters<typeof executeFoundryCommandSpec>[1]['spawnImpl'],\n): Promise<FoundryCommandSpecSpawnResult> {\n assertTrustedManifest(value);\n const host = options.host ?? inspectRuntimeHost();\n const launch = value.manifest.launches.find(\n (item) => item.id === options.entry && item.platform === host.platform,\n );\n if (!launch)\n runtimeError('RUNTIME_LAUNCH_UNKNOWN', 'Selected runtime entry is not declared for this host.');\n if (\n options.argv.length > 512 ||\n options.argv.some(\n (arg) =>\n typeof arg !== 'string' ||\n arg.includes('\\0') ||\n arg.length > 32768 ||\n /^--(?:username|password|api-key|access-token|refresh-token|authorization-code|oauth-code)(?:=|$)/iu.test(\n arg,\n ),\n )\n )\n runtimeError(\n 'RUNTIME_LAUNCH_ARGUMENT',\n 'Runtime argv must be bounded and contain no credential arguments.',\n );\n if (!path.isAbsolute(options.cwd) || !fs.statSync(options.cwd).isDirectory())\n runtimeError(\n 'RUNTIME_LAUNCH_CWD',\n 'Runtime launch requires an explicit existing work directory.',\n );\n const cwd = fs.realpathSync(options.cwd),\n cache = openRuntimeCache(options.cacheDir ?? defaultRuntimeCache(), false);\n const relative = path.relative(cache, cwd);\n if (\n relative === '' ||\n (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative)) ||\n /\\/(?:\\.agents|\\.codex)\\/skills(?:\\/|$)/u.test(cwd.split(path.sep).join('/'))\n )\n runtimeError(\n 'RUNTIME_LAUNCH_CWD',\n 'A runtime cache or installed skill cannot be used as the work directory.',\n );\n const lease = { id: `execution-${randomUUID()}`, owner: `runtime-execution:${process.pid}` };\n let drain: Promise<FoundryCommandSpecSpawnResult> | undefined;\n try {\n await ensureRuntimeComponents(value, { ...options, cacheDir: cache, host, lease });\n if (options.lease)\n await acquireRuntimeLease(\n cache,\n options.lease.id,\n options.lease.owner,\n value.manifest.components\n .filter((item) => item.platform === host.platform)\n .map(componentKey),\n );\n if (inspectRuntimeComponents(value, { ...options, cacheDir: cache, host }).status !== 'ready')\n runtimeError('RUNTIME_LAUNCH_CHANGED', 'Runtime changed before launch.');\n const artifact = (ref: ComponentPath) => {\n const component = value.manifest.components.find(\n (item) => item.id === ref.component && item.platform === host.platform,\n )!;\n const file = component.files.find((item) => item.path === ref.path)!;\n const filePath = cachePath(cache, `components/${componentKey(component)}/root/${ref.path}`);\n return {\n role: `runtime:${ref.component}:${ref.path}`,\n path: filePath,\n bytes: file.bytes,\n sha256: file.sha256,\n };\n };\n const program = artifact(launch.executable);\n const references = launch.argv\n .filter((arg): arg is ComponentPath => 'component' in arg)\n .map(artifact);\n const argv = launch.argv\n .map((arg) => ('literal' in arg ? arg.literal : artifact(arg).path))\n .concat([...options.argv]);\n const spec = createFoundryCommandSpec({\n executable: program.path,\n argv,\n binding: { artifacts: [program, ...references] },\n });\n const result = await executeFoundryCommandSpec(spec, {\n cwd,\n env: runtimeChildEnvironment(options.env ?? process.env, launch.environment),\n signal: options.signal,\n maxBuffer: 16 * 1024 * 1024,\n resolveArtifactPath: (file) => file,\n spawnImpl: (executable, argv, childOptions) => {\n drain = (spawnImpl ?? spawnRuntimeProcess)(executable, argv, childOptions);\n return drain;\n },\n });\n return result;\n } finally {\n await drain?.catch(() => undefined);\n if (fs.existsSync(cachePath(cache, '.runtime-cache.json')))\n await releaseRuntimeLease(cache, lease.id, lease.owner);\n }\n}\n"]}
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../../src/lib/runtime/execute.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport {\n createFoundryCommandSpec,\n executeFoundryCommandSpec,\n type FoundryCommandSpecSpawnResult,\n type FoundryCommandSpecAsyncSpawnOptions,\n} from '../../command-spec.js';\nimport {\n ensureRuntimeComponents,\n inspectRuntimeComponents,\n type RuntimeManagerOptions,\n} from './manager.js';\nimport { spawnRuntimeProcess } from './process.js';\nimport { acquireRuntimeLease, releaseRuntimeLease } from './leases.js';\nimport { cachePath, defaultRuntimeCache, openRuntimeCache } from './storage.js';\nimport { assertTrustedManifest, componentKey } from './manifest.js';\nimport { inspectRuntimeHost } from './host.js';\nimport { runtimeError } from './files.js';\nimport {\n runtimeWorkDirectory,\n assertRuntimeWorkDirectoryOutsideInstall,\n} from './work-directory.js';\nimport type {\n TrustedRuntimeManifest,\n ComponentPath,\n RuntimeHostContext,\n} from './manifest-types.js';\n\nconst systemKeys = [\n 'PATH',\n 'Path',\n 'PATHEXT',\n 'SystemRoot',\n 'SYSTEMROOT',\n 'WINDIR',\n 'ComSpec',\n 'COMSPEC',\n 'HOME',\n 'USERPROFILE',\n 'APPDATA',\n 'LOCALAPPDATA',\n 'XDG_CONFIG_HOME',\n 'XDG_CACHE_HOME',\n 'TMPDIR',\n 'TEMP',\n 'TMP',\n 'LANG',\n 'LC_ALL',\n 'TZ',\n] as const;\nconst authKeys = [\n 'TIANGONG_LCA_API_BASE_URL',\n 'TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY',\n 'TIANGONG_LCA_OAUTH_CLIENT_ID',\n 'TIANGONG_LCA_OAUTH_REDIRECT_URI',\n 'TIANGONG_LCA_REGION',\n 'TIANGONG_LCA_AUTH_MODE',\n 'TIANGONG_LCA_SESSION_FILE',\n 'TIANGONG_LCA_DISABLE_SESSION_CACHE',\n 'TIANGONG_LCA_FORCE_REAUTH',\n 'TIANGONG_LCA_ACCESS_TOKEN',\n] as const;\nexport function runtimeChildEnvironment(\n source: NodeJS.ProcessEnv,\n mode: 'isolated' | 'cli-auth',\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const key of [...systemKeys, ...(mode === 'cli-auth' ? authKeys : [])])\n if (source[key] !== undefined) env[key] = source[key];\n return env;\n}\nexport type RuntimeExecutionOptions = RuntimeManagerOptions & {\n entry: string;\n cwd: string;\n argv: readonly string[];\n env?: Record<string, string | undefined>;\n};\nexport type RuntimeExecutionSpawn = (\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecAsyncSpawnOptions,\n context?: RuntimeHostContext,\n) => Promise<FoundryCommandSpecSpawnResult>;\nexport async function executeRuntimeLaunch(\n value: TrustedRuntimeManifest,\n options: RuntimeExecutionOptions,\n spawnImpl?: RuntimeExecutionSpawn,\n): Promise<FoundryCommandSpecSpawnResult> {\n assertTrustedManifest(value);\n const observedHost = options.host ?? inspectRuntimeHost();\n const host = Object.freeze({\n platform: observedHost.platform,\n osRelease: observedHost.osRelease,\n glibc: observedHost.glibc,\n });\n const launch = value.manifest.launches.find(\n (item) => item.id === options.entry && item.platform === host.platform,\n );\n if (!launch)\n runtimeError('RUNTIME_LAUNCH_UNKNOWN', 'Selected runtime entry is not declared for this host.');\n if (options.argv.length > 512)\n runtimeError(\n 'RUNTIME_LAUNCH_ARGUMENT',\n 'Runtime argv must be bounded and contain no credential arguments.',\n );\n const applicationArgv = [...options.argv];\n if (\n applicationArgv.some(\n (arg) =>\n typeof arg !== 'string' ||\n arg.includes('\\0') ||\n arg.length > 32768 ||\n /^--(?:username|password|api-key|access-token|refresh-token|authorization-code|oauth-code)(?:=|$)/iu.test(\n arg,\n ),\n )\n )\n runtimeError(\n 'RUNTIME_LAUNCH_ARGUMENT',\n 'Runtime argv must be bounded and contain no credential arguments.',\n );\n const cwd = runtimeWorkDirectory(options.cwd),\n cache = openRuntimeCache(options.cacheDir ?? defaultRuntimeCache(), false);\n assertRuntimeWorkDirectoryOutsideInstall(cwd, cache);\n const lease = { id: `execution-${randomUUID()}`, owner: `runtime-execution:${process.pid}` };\n let drain: Promise<FoundryCommandSpecSpawnResult> | undefined;\n try {\n await ensureRuntimeComponents(value, { ...options, cacheDir: cache, host, lease });\n if (options.lease)\n await acquireRuntimeLease(\n cache,\n options.lease.id,\n options.lease.owner,\n value.manifest.components\n .filter((item) => item.platform === host.platform)\n .map(componentKey),\n );\n if (inspectRuntimeComponents(value, { ...options, cacheDir: cache, host }).status !== 'ready')\n runtimeError('RUNTIME_LAUNCH_CHANGED', 'Runtime changed before launch.');\n const artifact = (ref: ComponentPath) => {\n const component = value.manifest.components.find(\n (item) => item.id === ref.component && item.platform === host.platform,\n )!;\n const file = component.files.find((item) => item.path === ref.path)!;\n const filePath = cachePath(cache, `components/${componentKey(component)}/root/${ref.path}`);\n return {\n role: `runtime:${ref.component}:${ref.path}`,\n path: filePath,\n bytes: file.bytes,\n sha256: file.sha256,\n };\n };\n const program = artifact(launch.executable);\n const references = launch.argv\n .filter((arg): arg is ComponentPath => 'component' in arg)\n .map(artifact);\n const argv = launch.argv\n .map((arg) => ('literal' in arg ? arg.literal : artifact(arg).path))\n .concat(applicationArgv);\n const spec = createFoundryCommandSpec({\n executable: program.path,\n argv,\n binding: { artifacts: [program, ...references] },\n });\n const result = await executeFoundryCommandSpec(spec, {\n cwd,\n env: runtimeChildEnvironment(options.env ?? process.env, launch.environment),\n signal: options.signal,\n maxBuffer: 16 * 1024 * 1024,\n resolveArtifactPath: (file) => file,\n spawnImpl: (executable, argv, childOptions) => {\n const context = launch.context_protocol\n ? Object.freeze({ manifest: value, cacheDir: cache, cwd, entry: launch.id, host })\n : undefined;\n const spawn = spawnImpl ?? spawnRuntimeProcess;\n drain = context\n ? spawn(executable, argv, childOptions, context)\n : spawn(executable, argv, childOptions);\n return drain;\n },\n });\n return result;\n } finally {\n await drain?.catch(() => undefined);\n if (fs.existsSync(cachePath(cache, '.runtime-cache.json')))\n await releaseRuntimeLease(cache, lease.id, lease.owner);\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import type { RuntimeHostContext, TrustedRuntimeManifest } from './manifest-types.js';
2
+ export declare const HOST_CONTEXT_TIMEOUT_MS = 30000;
3
+ export type HostContextBinding = Readonly<{
4
+ nonce: string;
5
+ parent_pid: number;
6
+ child_pid: number;
7
+ }>;
8
+ export type HostContextMessage = Readonly<Record<string, string | number>>;
9
+ export type HostContextSendCallback = (error: Error | null) => void;
10
+ export declare function hostContextError(reason: string): Error;
11
+ export declare function hostControlMessage(kind: string, binding: HostContextBinding): HostContextMessage;
12
+ export declare function readHostRequest(value: unknown, parentPid: number, childPid: number): HostContextBinding;
13
+ export declare function assertHostControl(value: unknown, kind: string, binding: HostContextBinding): void;
14
+ export declare function hostContextMessage(context: RuntimeHostContext, binding: HostContextBinding): HostContextMessage;
15
+ export declare function readHostContextMessage(value: unknown, binding: HostContextBinding): {
16
+ manifest: TrustedRuntimeManifest;
17
+ cacheDir: string;
18
+ cwd: string;
19
+ entry: string;
20
+ };
@@ -0,0 +1,83 @@
1
+ import { copyTrustedRuntimeManifestBytes, trustRuntimeManifest } from './manifest.js';
2
+ import { RUNTIME_HOST_CONTEXT_PROTOCOL } from './manifest-types.js';
3
+ export const HOST_CONTEXT_TIMEOUT_MS = 30_000;
4
+ const bindingKeys = ['schema', 'kind', 'nonce', 'parent_pid', 'child_pid'];
5
+ const contextKeys = ['manifest_base64', 'manifest_sha256', 'cache_dir', 'cwd', 'entry'];
6
+ export function hostContextError(reason) {
7
+ return Object.assign(new Error(`Runtime host context ${reason}.`), {
8
+ code: 'RUNTIME_HOST_CONTEXT',
9
+ });
10
+ }
11
+ function messageRecord(value, keys) {
12
+ if (!value || typeof value !== 'object' || Array.isArray(value))
13
+ throw hostContextError('message must be an object');
14
+ const record = value;
15
+ if (Object.keys(record).length !== keys.length || keys.some((key) => !Object.hasOwn(record, key)))
16
+ throw hostContextError('message has unexpected fields');
17
+ return record;
18
+ }
19
+ export function hostControlMessage(kind, binding) {
20
+ return { schema: RUNTIME_HOST_CONTEXT_PROTOCOL, kind, ...binding };
21
+ }
22
+ export function readHostRequest(value, parentPid, childPid) {
23
+ const message = messageRecord(value, bindingKeys);
24
+ if (message.schema !== RUNTIME_HOST_CONTEXT_PROTOCOL ||
25
+ message.kind !== 'request' ||
26
+ typeof message.nonce !== 'string' ||
27
+ !/^[0-9a-f]{64}$/u.test(message.nonce) ||
28
+ message.parent_pid !== parentPid ||
29
+ message.child_pid !== childPid)
30
+ throw hostContextError('request is not bound to this child');
31
+ return Object.freeze({ nonce: message.nonce, parent_pid: parentPid, child_pid: childPid });
32
+ }
33
+ export function assertHostControl(value, kind, binding) {
34
+ assertBinding(messageRecord(value, bindingKeys), kind, binding);
35
+ }
36
+ function assertBinding(message, kind, binding) {
37
+ if (message.schema !== RUNTIME_HOST_CONTEXT_PROTOCOL ||
38
+ message.kind !== kind ||
39
+ message.nonce !== binding.nonce ||
40
+ message.parent_pid !== binding.parent_pid ||
41
+ message.child_pid !== binding.child_pid)
42
+ throw hostContextError('message belongs to another handshake');
43
+ }
44
+ export function hostContextMessage(context, binding) {
45
+ return {
46
+ ...hostControlMessage('context', binding),
47
+ manifest_base64: copyTrustedRuntimeManifestBytes(context.manifest).toString('base64'),
48
+ manifest_sha256: context.manifest.sha256,
49
+ cache_dir: context.cacheDir,
50
+ cwd: context.cwd,
51
+ entry: context.entry,
52
+ };
53
+ }
54
+ export function readHostContextMessage(value, binding) {
55
+ const message = messageRecord(value, [...bindingKeys, ...contextKeys]);
56
+ assertBinding(message, 'context', binding);
57
+ if (typeof message.manifest_base64 !== 'string' ||
58
+ message.manifest_base64.length === 0 ||
59
+ message.manifest_base64.length > 4 * Math.ceil((32 * 1024 * 1024) / 3) ||
60
+ typeof message.manifest_sha256 !== 'string')
61
+ throw hostContextError('manifest exceeds its wire bound');
62
+ const bytes = Buffer.from(message.manifest_base64, 'base64');
63
+ if (bytes.toString('base64') !== message.manifest_base64)
64
+ throw hostContextError('manifest encoding is not canonical');
65
+ const stringField = (key) => {
66
+ const value = message[key];
67
+ if (typeof value !== 'string' ||
68
+ !value ||
69
+ value.length > 32768 ||
70
+ value
71
+ .split('')
72
+ .some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127))
73
+ throw hostContextError('selection fields are invalid');
74
+ return value;
75
+ };
76
+ return {
77
+ manifest: trustRuntimeManifest(bytes, message.manifest_sha256),
78
+ cacheDir: stringField('cache_dir'),
79
+ cwd: stringField('cwd'),
80
+ entry: stringField('entry'),
81
+ };
82
+ }
83
+ //# sourceMappingURL=host-context-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-context-protocol.js","sourceRoot":"","sources":["../../../../src/lib/runtime/host-context-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { copyTrustedRuntimeManifestBytes, trustRuntimeManifest } from './manifest.js';\nimport { RUNTIME_HOST_CONTEXT_PROTOCOL } from './manifest-types.js';\nimport type { RuntimeHostContext, TrustedRuntimeManifest } from './manifest-types.js';\n\nexport const HOST_CONTEXT_TIMEOUT_MS = 30_000;\nexport type HostContextBinding = Readonly<{ nonce: string; parent_pid: number; child_pid: number }>;\nexport type HostContextMessage = Readonly<Record<string, string | number>>;\nexport type HostContextSendCallback = (error: Error | null) => void;\nconst bindingKeys = ['schema', 'kind', 'nonce', 'parent_pid', 'child_pid'];\nconst contextKeys = ['manifest_base64', 'manifest_sha256', 'cache_dir', 'cwd', 'entry'];\n\nexport function hostContextError(reason: string): Error {\n return Object.assign(new Error(`Runtime host context ${reason}.`), {\n code: 'RUNTIME_HOST_CONTEXT',\n });\n}\n\nfunction messageRecord(value: unknown, keys: readonly string[]): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw hostContextError('message must be an object');\n const record = value as Record<string, unknown>;\n if (Object.keys(record).length !== keys.length || keys.some((key) => !Object.hasOwn(record, key)))\n throw hostContextError('message has unexpected fields');\n return record;\n}\n\nexport function hostControlMessage(kind: string, binding: HostContextBinding): HostContextMessage {\n return { schema: RUNTIME_HOST_CONTEXT_PROTOCOL, kind, ...binding };\n}\n\nexport function readHostRequest(\n value: unknown,\n parentPid: number,\n childPid: number,\n): HostContextBinding {\n const message = messageRecord(value, bindingKeys);\n if (\n message.schema !== RUNTIME_HOST_CONTEXT_PROTOCOL ||\n message.kind !== 'request' ||\n typeof message.nonce !== 'string' ||\n !/^[0-9a-f]{64}$/u.test(message.nonce) ||\n message.parent_pid !== parentPid ||\n message.child_pid !== childPid\n )\n throw hostContextError('request is not bound to this child');\n return Object.freeze({ nonce: message.nonce, parent_pid: parentPid, child_pid: childPid });\n}\n\nexport function assertHostControl(value: unknown, kind: string, binding: HostContextBinding): void {\n assertBinding(messageRecord(value, bindingKeys), kind, binding);\n}\n\nfunction assertBinding(\n message: Record<string, unknown>,\n kind: string,\n binding: HostContextBinding,\n): void {\n if (\n message.schema !== RUNTIME_HOST_CONTEXT_PROTOCOL ||\n message.kind !== kind ||\n message.nonce !== binding.nonce ||\n message.parent_pid !== binding.parent_pid ||\n message.child_pid !== binding.child_pid\n )\n throw hostContextError('message belongs to another handshake');\n}\n\nexport function hostContextMessage(\n context: RuntimeHostContext,\n binding: HostContextBinding,\n): HostContextMessage {\n return {\n ...hostControlMessage('context', binding),\n manifest_base64: copyTrustedRuntimeManifestBytes(context.manifest).toString('base64'),\n manifest_sha256: context.manifest.sha256,\n cache_dir: context.cacheDir,\n cwd: context.cwd,\n entry: context.entry,\n };\n}\n\nexport function readHostContextMessage(\n value: unknown,\n binding: HostContextBinding,\n): {\n manifest: TrustedRuntimeManifest;\n cacheDir: string;\n cwd: string;\n entry: string;\n} {\n const message = messageRecord(value, [...bindingKeys, ...contextKeys]);\n assertBinding(message, 'context', binding);\n if (\n typeof message.manifest_base64 !== 'string' ||\n message.manifest_base64.length === 0 ||\n message.manifest_base64.length > 4 * Math.ceil((32 * 1024 * 1024) / 3) ||\n typeof message.manifest_sha256 !== 'string'\n )\n throw hostContextError('manifest exceeds its wire bound');\n const bytes = Buffer.from(message.manifest_base64, 'base64');\n if (bytes.toString('base64') !== message.manifest_base64)\n throw hostContextError('manifest encoding is not canonical');\n const stringField = (key: 'cache_dir' | 'cwd' | 'entry') => {\n const value = message[key];\n if (\n typeof value !== 'string' ||\n !value ||\n value.length > 32768 ||\n value\n .split('')\n .some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)\n )\n throw hostContextError('selection fields are invalid');\n return value;\n };\n return {\n manifest: trustRuntimeManifest(bytes, message.manifest_sha256),\n cacheDir: stringField('cache_dir'),\n cwd: stringField('cwd'),\n entry: stringField('entry'),\n };\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+ import type { RuntimeHostContext } from './manifest-types.js';
3
+ /** One IPC handshake, owned by the same process that holds the execution lease. */
4
+ export declare function serveRuntimeHostContext(child: ChildProcess, context: RuntimeHostContext, onFailure: (error: Error) => void): {
5
+ finish(): Error | undefined;
6
+ };
@@ -0,0 +1,81 @@
1
+ import { HOST_CONTEXT_TIMEOUT_MS, assertHostControl, hostContextError, hostContextMessage, hostControlMessage, readHostRequest, } from './host-context-protocol.js';
2
+ /** One IPC handshake, owned by the same process that holds the execution lease. */
3
+ export function serveRuntimeHostContext(child, context, onFailure) {
4
+ let phase = 'request';
5
+ let binding;
6
+ let readySent = false, clientClosed = false;
7
+ const cleanup = () => {
8
+ clearTimeout(timer);
9
+ child.off('message', message);
10
+ child.off('disconnect', disconnected);
11
+ };
12
+ const fail = (error) => {
13
+ if (phase === 'failed' || phase === 'complete')
14
+ return;
15
+ phase = 'failed';
16
+ cleanup();
17
+ onFailure(error instanceof Error ? error : hostContextError('transport failed'));
18
+ };
19
+ const complete = () => {
20
+ if (readySent && clientClosed) {
21
+ phase = 'complete';
22
+ cleanup();
23
+ }
24
+ };
25
+ const send = (frame, ready = false) => {
26
+ if (!child.connected || !child.send)
27
+ throw hostContextError('channel is unavailable');
28
+ child.send(frame, (error) => {
29
+ if (error) {
30
+ fail(error);
31
+ return;
32
+ }
33
+ if (ready && phase === 'ready') {
34
+ readySent = true;
35
+ complete();
36
+ }
37
+ });
38
+ };
39
+ const message = (value) => {
40
+ try {
41
+ if (phase === 'request') {
42
+ if (!child.pid)
43
+ throw hostContextError('child identity is unavailable');
44
+ binding = readHostRequest(value, process.pid, child.pid);
45
+ phase = 'accept';
46
+ send(hostContextMessage(context, binding));
47
+ }
48
+ else if (phase === 'accept') {
49
+ assertHostControl(value, 'accept', binding);
50
+ phase = 'ready';
51
+ send(hostControlMessage('ready', binding), true);
52
+ }
53
+ else
54
+ throw hostContextError('message is repeated or out of order');
55
+ }
56
+ catch (error) {
57
+ fail(error);
58
+ }
59
+ };
60
+ const disconnected = () => {
61
+ if (phase === 'ready') {
62
+ clientClosed = true;
63
+ complete();
64
+ }
65
+ else
66
+ fail(hostContextError('channel closed before acceptance'));
67
+ };
68
+ const timer = setTimeout(() => fail(hostContextError('handshake timed out')), HOST_CONTEXT_TIMEOUT_MS);
69
+ child.on('message', message);
70
+ child.on('disconnect', disconnected);
71
+ return {
72
+ finish() {
73
+ const error = phase === 'complete' ? undefined : hostContextError('child closed before acceptance');
74
+ if (error)
75
+ phase = 'failed';
76
+ cleanup();
77
+ return error;
78
+ },
79
+ };
80
+ }
81
+ //# sourceMappingURL=host-context-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-context-server.js","sourceRoot":"","sources":["../../../../src/lib/runtime/host-context-server.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,GAGhB,MAAM,4BAA4B,CAAC;AAEpC,mFAAmF;AACnF,MAAM,UAAU,uBAAuB,CACrC,KAAmB,EACnB,OAA2B,EAC3B,SAAiC;IAEjC,IAAI,KAAK,GAA2D,SAAS,CAAC;IAC9E,IAAI,OAAuC,CAAC;IAC5C,IAAI,SAAS,GAAG,KAAK,EACnB,YAAY,GAAG,KAAK,CAAC;IACvB,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC9B,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACxC,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE;QAC9B,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,UAAU;YAAE,OAAO;QACvD,KAAK,GAAG,QAAQ,CAAC;QACjB,OAAO,EAAE,CAAC;QACV,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACnF,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,IAAI,SAAS,IAAI,YAAY,EAAE,CAAC;YAC9B,KAAK,GAAG,UAAU,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,KAAyB,EAAE,KAAK,GAAG,KAAK,EAAE,EAAE;QACxD,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,MAAM,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;QACtF,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBAC/B,SAAS,GAAG,IAAI,CAAC;gBACjB,QAAQ,EAAE,CAAC;YACb,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,GAAG;oBAAE,MAAM,gBAAgB,CAAC,+BAA+B,CAAC,CAAC;gBACxE,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;gBACzD,KAAK,GAAG,QAAQ,CAAC;gBACjB,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7C,CAAC;iBAAM,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAQ,CAAC,CAAC;gBAC7C,KAAK,GAAG,OAAO,CAAC;gBAChB,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,OAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;YACpD,CAAC;;gBAAM,MAAM,gBAAgB,CAAC,qCAAqC,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IACF,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,YAAY,GAAG,IAAI,CAAC;YACpB,QAAQ,EAAE,CAAC;QACb,CAAC;;YAAM,IAAI,CAAC,gBAAgB,CAAC,kCAAkC,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,EACnD,uBAAuB,CACxB,CAAC;IACF,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACrC,OAAO;QACL,MAAM;YACJ,MAAM,KAAK,GACT,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,CAAC;YACxF,IAAI,KAAK;gBAAE,KAAK,GAAG,QAAQ,CAAC;YAC5B,OAAO,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { ChildProcess } from 'node:child_process';\nimport type { RuntimeHostContext } from './manifest-types.js';\nimport {\n HOST_CONTEXT_TIMEOUT_MS,\n assertHostControl,\n hostContextError,\n hostContextMessage,\n hostControlMessage,\n readHostRequest,\n type HostContextBinding,\n type HostContextMessage,\n} from './host-context-protocol.js';\n\n/** One IPC handshake, owned by the same process that holds the execution lease. */\nexport function serveRuntimeHostContext(\n child: ChildProcess,\n context: RuntimeHostContext,\n onFailure: (error: Error) => void,\n): { finish(): Error | undefined } {\n let phase: 'request' | 'accept' | 'ready' | 'complete' | 'failed' = 'request';\n let binding: HostContextBinding | undefined;\n let readySent = false,\n clientClosed = false;\n const cleanup = () => {\n clearTimeout(timer);\n child.off('message', message);\n child.off('disconnect', disconnected);\n };\n const fail = (error: unknown) => {\n if (phase === 'failed' || phase === 'complete') return;\n phase = 'failed';\n cleanup();\n onFailure(error instanceof Error ? error : hostContextError('transport failed'));\n };\n const complete = () => {\n if (readySent && clientClosed) {\n phase = 'complete';\n cleanup();\n }\n };\n const send = (frame: HostContextMessage, ready = false) => {\n if (!child.connected || !child.send) throw hostContextError('channel is unavailable');\n child.send(frame, (error) => {\n if (error) {\n fail(error);\n return;\n }\n if (ready && phase === 'ready') {\n readySent = true;\n complete();\n }\n });\n };\n const message = (value: unknown) => {\n try {\n if (phase === 'request') {\n if (!child.pid) throw hostContextError('child identity is unavailable');\n binding = readHostRequest(value, process.pid, child.pid);\n phase = 'accept';\n send(hostContextMessage(context, binding));\n } else if (phase === 'accept') {\n assertHostControl(value, 'accept', binding!);\n phase = 'ready';\n send(hostControlMessage('ready', binding!), true);\n } else throw hostContextError('message is repeated or out of order');\n } catch (error) {\n fail(error);\n }\n };\n const disconnected = () => {\n if (phase === 'ready') {\n clientClosed = true;\n complete();\n } else fail(hostContextError('channel closed before acceptance'));\n };\n const timer = setTimeout(\n () => fail(hostContextError('handshake timed out')),\n HOST_CONTEXT_TIMEOUT_MS,\n );\n child.on('message', message);\n child.on('disconnect', disconnected);\n return {\n finish() {\n const error =\n phase === 'complete' ? undefined : hostContextError('child closed before acceptance');\n if (error) phase = 'failed';\n cleanup();\n return error;\n },\n };\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { type RuntimeHostContext } from './manifest-types.js';
2
+ import { readHostContextMessage, type HostContextMessage, type HostContextSendCallback } from './host-context-protocol.js';
3
+ type Listener = (value?: unknown) => void;
4
+ export type RuntimeHostProcess = {
5
+ pid: number;
6
+ ppid: number;
7
+ execPath: string;
8
+ cwd(): string;
9
+ connected?: boolean;
10
+ send?: (message: HostContextMessage, callback: HostContextSendCallback) => unknown;
11
+ disconnect?: () => void;
12
+ on(event: 'message' | 'disconnect', listener: Listener): unknown;
13
+ off(event: 'message' | 'disconnect', listener: Listener): unknown;
14
+ };
15
+ declare function validateSelection(input: ReturnType<typeof readHostContextMessage>, child: RuntimeHostProcess): RuntimeHostContext;
16
+ declare function receiveFromProcess(child: RuntimeHostProcess): Promise<RuntimeHostContext>;
17
+ /** Receive only the owning manager's one-use IPC handoff, before loading task input. */
18
+ export declare function receiveRuntimeHostContext(): Promise<RuntimeHostContext>;
19
+ export declare const runtimeHostContextInternals: {
20
+ receiveFromProcess: typeof receiveFromProcess;
21
+ validateSelection: typeof validateSelection;
22
+ };
23
+ export {};
@@ -0,0 +1,122 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { randomBytes } from 'node:crypto';
4
+ import { componentKey } from './manifest.js';
5
+ import { inspectRuntimeHost } from './host.js';
6
+ import { inspectRuntimeComponents } from './manager.js';
7
+ import { openRuntimeCache, cachePath } from './storage.js';
8
+ import { runtimeWorkDirectory, assertRuntimeWorkDirectoryOutsideInstall, } from './work-directory.js';
9
+ import { RUNTIME_HOST_CONTEXT_PROTOCOL } from './manifest-types.js';
10
+ import { HOST_CONTEXT_TIMEOUT_MS, assertHostControl, hostContextError, hostControlMessage, readHostContextMessage, } from './host-context-protocol.js';
11
+ const claimed = new WeakSet();
12
+ function validateSelection(input, child) {
13
+ if (!path.isAbsolute(input.cacheDir) || !path.isAbsolute(input.cwd))
14
+ throw hostContextError('requires absolute cache and work directories');
15
+ const cacheDir = openRuntimeCache(input.cacheDir, false);
16
+ const cwd = runtimeWorkDirectory(input.cwd);
17
+ if (cwd !== fs.realpathSync(child.cwd()))
18
+ throw hostContextError('work directory changed');
19
+ assertRuntimeWorkDirectoryOutsideInstall(cwd, cacheDir);
20
+ const host = inspectRuntimeHost();
21
+ const launch = input.manifest.manifest.launches.find((item) => item.platform === host.platform && item.id === input.entry);
22
+ if (launch?.context_protocol !== RUNTIME_HOST_CONTEXT_PROTOCOL)
23
+ throw hostContextError('launch did not select this protocol');
24
+ if (inspectRuntimeComponents(input.manifest, { cacheDir, host }).status !== 'ready')
25
+ throw hostContextError('selected components changed');
26
+ const component = input.manifest.manifest.components.find((item) => item.platform === host.platform && item.id === launch.executable.component);
27
+ const executable = cachePath(cacheDir, `components/${componentKey(component)}/root/${launch.executable.path}`);
28
+ const expected = fs.statSync(executable, { bigint: true }), actual = fs.statSync(child.execPath, { bigint: true });
29
+ if (expected.dev !== actual.dev || expected.ino !== actual.ino)
30
+ throw hostContextError('executable is not the declared managed Node');
31
+ return Object.freeze({ ...input, cacheDir, cwd, host });
32
+ }
33
+ function receiveFromProcess(child) {
34
+ return new Promise((resolve, reject) => {
35
+ if (!child.connected || !child.send || !child.disconnect) {
36
+ reject(hostContextError('requires an inherited manager IPC channel'));
37
+ return;
38
+ }
39
+ if (claimed.has(child)) {
40
+ reject(hostContextError('handshake was already consumed'));
41
+ return;
42
+ }
43
+ claimed.add(child);
44
+ const binding = Object.freeze({
45
+ nonce: randomBytes(32).toString('hex'),
46
+ parent_pid: child.ppid,
47
+ child_pid: child.pid,
48
+ });
49
+ let context;
50
+ let ready = false, settled = false, closing = false;
51
+ const disconnect = () => {
52
+ if (closing || !child.connected)
53
+ return;
54
+ closing = true;
55
+ child.disconnect();
56
+ };
57
+ const cleanup = () => {
58
+ clearTimeout(timer);
59
+ child.off('message', message);
60
+ child.off('disconnect', disconnected);
61
+ };
62
+ const fail = (error) => {
63
+ if (settled)
64
+ return;
65
+ settled = true;
66
+ cleanup();
67
+ reject(error instanceof Error ? error : hostContextError('transport failed'));
68
+ try {
69
+ disconnect();
70
+ }
71
+ catch {
72
+ /* Preserve the original failure; the owning manager drains the child. */
73
+ }
74
+ };
75
+ const send = (value) => child.send(value, (error) => {
76
+ if (error)
77
+ fail(error);
78
+ });
79
+ const message = (value) => {
80
+ try {
81
+ if (!context) {
82
+ context = validateSelection(readHostContextMessage(value, binding), child);
83
+ send(hostControlMessage('accept', binding));
84
+ }
85
+ else if (!ready) {
86
+ assertHostControl(value, 'ready', binding);
87
+ ready = true;
88
+ disconnect();
89
+ }
90
+ else
91
+ throw hostContextError('message is repeated or out of order');
92
+ }
93
+ catch (error) {
94
+ fail(error);
95
+ }
96
+ };
97
+ const disconnected = () => {
98
+ if (!ready) {
99
+ fail(hostContextError('manager closed before confirming acceptance'));
100
+ return;
101
+ }
102
+ settled = true;
103
+ cleanup();
104
+ resolve(context);
105
+ };
106
+ const timer = setTimeout(() => fail(hostContextError('handshake timed out')), HOST_CONTEXT_TIMEOUT_MS);
107
+ child.on('message', message);
108
+ child.on('disconnect', disconnected);
109
+ try {
110
+ send(hostControlMessage('request', binding));
111
+ }
112
+ catch (error) {
113
+ fail(error);
114
+ }
115
+ });
116
+ }
117
+ /** Receive only the owning manager's one-use IPC handoff, before loading task input. */
118
+ export function receiveRuntimeHostContext() {
119
+ return receiveFromProcess(process);
120
+ }
121
+ export const runtimeHostContextInternals = { receiveFromProcess, validateSelection };
122
+ //# sourceMappingURL=host-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-context.js","sourceRoot":"","sources":["../../../../src/lib/runtime/host-context.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport { componentKey } from './manifest.js';\nimport { inspectRuntimeHost } from './host.js';\nimport { inspectRuntimeComponents } from './manager.js';\nimport { openRuntimeCache, cachePath } from './storage.js';\nimport {\n runtimeWorkDirectory,\n assertRuntimeWorkDirectoryOutsideInstall,\n} from './work-directory.js';\nimport { RUNTIME_HOST_CONTEXT_PROTOCOL, type RuntimeHostContext } from './manifest-types.js';\nimport {\n HOST_CONTEXT_TIMEOUT_MS,\n assertHostControl,\n hostContextError,\n hostControlMessage,\n readHostContextMessage,\n type HostContextMessage,\n type HostContextSendCallback,\n} from './host-context-protocol.js';\n\ntype Listener = (value?: unknown) => void;\nexport type RuntimeHostProcess = {\n pid: number;\n ppid: number;\n execPath: string;\n cwd(): string;\n connected?: boolean;\n send?: (message: HostContextMessage, callback: HostContextSendCallback) => unknown;\n disconnect?: () => void;\n on(event: 'message' | 'disconnect', listener: Listener): unknown;\n off(event: 'message' | 'disconnect', listener: Listener): unknown;\n};\nconst claimed = new WeakSet<RuntimeHostProcess>();\n\nfunction validateSelection(\n input: ReturnType<typeof readHostContextMessage>,\n child: RuntimeHostProcess,\n): RuntimeHostContext {\n if (!path.isAbsolute(input.cacheDir) || !path.isAbsolute(input.cwd))\n throw hostContextError('requires absolute cache and work directories');\n const cacheDir = openRuntimeCache(input.cacheDir, false);\n const cwd = runtimeWorkDirectory(input.cwd);\n if (cwd !== fs.realpathSync(child.cwd())) throw hostContextError('work directory changed');\n assertRuntimeWorkDirectoryOutsideInstall(cwd, cacheDir);\n const host = inspectRuntimeHost();\n const launch = input.manifest.manifest.launches.find(\n (item) => item.platform === host.platform && item.id === input.entry,\n );\n if (launch?.context_protocol !== RUNTIME_HOST_CONTEXT_PROTOCOL)\n throw hostContextError('launch did not select this protocol');\n if (inspectRuntimeComponents(input.manifest, { cacheDir, host }).status !== 'ready')\n throw hostContextError('selected components changed');\n const component = input.manifest.manifest.components.find(\n (item) => item.platform === host.platform && item.id === launch.executable.component,\n )!;\n const executable = cachePath(\n cacheDir,\n `components/${componentKey(component)}/root/${launch.executable.path}`,\n );\n const expected = fs.statSync(executable, { bigint: true }),\n actual = fs.statSync(child.execPath, { bigint: true });\n if (expected.dev !== actual.dev || expected.ino !== actual.ino)\n throw hostContextError('executable is not the declared managed Node');\n return Object.freeze({ ...input, cacheDir, cwd, host });\n}\n\nfunction receiveFromProcess(child: RuntimeHostProcess): Promise<RuntimeHostContext> {\n return new Promise((resolve, reject) => {\n if (!child.connected || !child.send || !child.disconnect) {\n reject(hostContextError('requires an inherited manager IPC channel'));\n return;\n }\n if (claimed.has(child)) {\n reject(hostContextError('handshake was already consumed'));\n return;\n }\n claimed.add(child);\n const binding = Object.freeze({\n nonce: randomBytes(32).toString('hex'),\n parent_pid: child.ppid,\n child_pid: child.pid,\n });\n let context: RuntimeHostContext | undefined;\n let ready = false,\n settled = false,\n closing = false;\n const disconnect = () => {\n if (closing || !child.connected) return;\n closing = true;\n child.disconnect!();\n };\n const cleanup = () => {\n clearTimeout(timer);\n child.off('message', message);\n child.off('disconnect', disconnected);\n };\n const fail = (error: unknown) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(error instanceof Error ? error : hostContextError('transport failed'));\n try {\n disconnect();\n } catch {\n /* Preserve the original failure; the owning manager drains the child. */\n }\n };\n const send = (value: HostContextMessage) =>\n child.send!(value, (error) => {\n if (error) fail(error);\n });\n const message = (value: unknown) => {\n try {\n if (!context) {\n context = validateSelection(readHostContextMessage(value, binding), child);\n send(hostControlMessage('accept', binding));\n } else if (!ready) {\n assertHostControl(value, 'ready', binding);\n ready = true;\n disconnect();\n } else throw hostContextError('message is repeated or out of order');\n } catch (error) {\n fail(error);\n }\n };\n const disconnected = () => {\n if (!ready) {\n fail(hostContextError('manager closed before confirming acceptance'));\n return;\n }\n settled = true;\n cleanup();\n resolve(context!);\n };\n const timer = setTimeout(\n () => fail(hostContextError('handshake timed out')),\n HOST_CONTEXT_TIMEOUT_MS,\n );\n child.on('message', message);\n child.on('disconnect', disconnected);\n try {\n send(hostControlMessage('request', binding));\n } catch (error) {\n fail(error);\n }\n });\n}\n\n/** Receive only the owning manager's one-use IPC handoff, before loading task input. */\nexport function receiveRuntimeHostContext(): Promise<RuntimeHostContext> {\n return receiveFromProcess(process);\n}\nexport const runtimeHostContextInternals = { receiveFromProcess, validateSelection };\n"]}
@@ -2,6 +2,7 @@ import type { RuntimePlatform } from './types.js';
2
2
  export declare const RUNTIME_MANIFEST_SCHEMA: 'tiangong-lca.runtime-manifest.v1';
3
3
  export declare const RUNTIME_BOOTSTRAP_PROTOCOL: 'tiangong-lca.runtime-bootstrap.v1';
4
4
  export declare const RUNTIME_ARCHIVE_FORMAT: 'tar-gzip-ustar-v1';
5
+ export declare const RUNTIME_HOST_CONTEXT_PROTOCOL: 'tiangong-lca.runtime-host.v1';
5
6
  export type ComponentFile = Readonly<{
6
7
  path: string;
7
8
  bytes: number;
@@ -36,6 +37,7 @@ export type RuntimeLaunch = Readonly<{
36
37
  platform: RuntimePlatform;
37
38
  executable: ComponentPath;
38
39
  environment: 'isolated' | 'cli-auth';
40
+ context_protocol?: typeof RUNTIME_HOST_CONTEXT_PROTOCOL;
39
41
  argv: readonly (ComponentPath | Readonly<{
40
42
  literal: string;
41
43
  }>)[];
@@ -71,3 +73,10 @@ export type RuntimeHost = Readonly<{
71
73
  osRelease: string;
72
74
  glibc: string | null;
73
75
  }>;
76
+ export type RuntimeHostContext = Readonly<{
77
+ manifest: TrustedRuntimeManifest;
78
+ cacheDir: string;
79
+ cwd: string;
80
+ entry: string;
81
+ host: RuntimeHost;
82
+ }>;
@@ -1,4 +1,5 @@
1
1
  export const RUNTIME_MANIFEST_SCHEMA = 'tiangong-lca.runtime-manifest.v1';
2
2
  export const RUNTIME_BOOTSTRAP_PROTOCOL = 'tiangong-lca.runtime-bootstrap.v1';
3
3
  export const RUNTIME_ARCHIVE_FORMAT = 'tar-gzip-ustar-v1';
4
+ export const RUNTIME_HOST_CONTEXT_PROTOCOL = 'tiangong-lca.runtime-host.v1';
4
5
  //# sourceMappingURL=manifest-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-types.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest-types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,uBAAuB,GAAG,kCAA2C,CAAC;AACnF,MAAM,CAAC,MAAM,0BAA0B,GAAG,mCAA4C,CAAC;AACvF,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAA4B,CAAC","sourcesContent":["import type { RuntimePlatform } from './types.js';\n\nexport const RUNTIME_MANIFEST_SCHEMA = 'tiangong-lca.runtime-manifest.v1' as const;\nexport const RUNTIME_BOOTSTRAP_PROTOCOL = 'tiangong-lca.runtime-bootstrap.v1' as const;\nexport const RUNTIME_ARCHIVE_FORMAT = 'tar-gzip-ustar-v1' as const;\nexport type ComponentFile = Readonly<{\n path: string;\n bytes: number;\n sha256: string;\n mode: 420 | 493;\n}>;\nexport type RuntimeComponent = Readonly<{\n id: string;\n version: string;\n platform: RuntimePlatform;\n archive: Readonly<{\n format: typeof RUNTIME_ARCHIVE_FORMAT;\n url: string;\n bytes: number;\n sha256: string;\n }>;\n files: readonly ComponentFile[];\n content_sha256: string;\n production_lock: string;\n sbom: string;\n licenses: readonly string[];\n provenance: readonly string[];\n protocols: readonly string[];\n asset_fingerprints: Readonly<Record<string, string>>;\n}>;\nexport type ComponentPath = Readonly<{ component: string; path: string }>;\nexport type RuntimeLaunch = Readonly<{\n id: string;\n platform: RuntimePlatform;\n executable: ComponentPath;\n environment: 'isolated' | 'cli-auth';\n argv: readonly (ComponentPath | Readonly<{ literal: string }>)[];\n}>;\nexport type WorkspaceCompatibility = Readonly<{ schema: string; features: readonly string[] }>;\nexport type RuntimeManifest = Readonly<{\n schema: typeof RUNTIME_MANIFEST_SCHEMA;\n bootstrap_protocol: typeof RUNTIME_BOOTSTRAP_PROTOCOL;\n product: Readonly<{ id: string; version: string }>;\n minimum_hosts: Readonly<\n Partial<Record<RuntimePlatform, Readonly<{ os_release: string; glibc: string | null }>>>\n >;\n workspace: Readonly<{\n read: readonly WorkspaceCompatibility[];\n write: readonly WorkspaceCompatibility[];\n }>;\n components: readonly RuntimeComponent[];\n launches: readonly RuntimeLaunch[];\n}>;\nexport type TrustedRuntimeManifest = Readonly<{ sha256: string; manifest: RuntimeManifest }>;\nexport type RuntimeHost = Readonly<{\n platform: RuntimePlatform;\n osRelease: string;\n glibc: string | null;\n}>;\n"]}
1
+ {"version":3,"file":"manifest-types.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest-types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,uBAAuB,GAAG,kCAA2C,CAAC;AACnF,MAAM,CAAC,MAAM,0BAA0B,GAAG,mCAA4C,CAAC;AACvF,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAA4B,CAAC;AACnE,MAAM,CAAC,MAAM,6BAA6B,GAAG,8BAAuC,CAAC","sourcesContent":["import type { RuntimePlatform } from './types.js';\n\nexport const RUNTIME_MANIFEST_SCHEMA = 'tiangong-lca.runtime-manifest.v1' as const;\nexport const RUNTIME_BOOTSTRAP_PROTOCOL = 'tiangong-lca.runtime-bootstrap.v1' as const;\nexport const RUNTIME_ARCHIVE_FORMAT = 'tar-gzip-ustar-v1' as const;\nexport const RUNTIME_HOST_CONTEXT_PROTOCOL = 'tiangong-lca.runtime-host.v1' as const;\nexport type ComponentFile = Readonly<{\n path: string;\n bytes: number;\n sha256: string;\n mode: 420 | 493;\n}>;\nexport type RuntimeComponent = Readonly<{\n id: string;\n version: string;\n platform: RuntimePlatform;\n archive: Readonly<{\n format: typeof RUNTIME_ARCHIVE_FORMAT;\n url: string;\n bytes: number;\n sha256: string;\n }>;\n files: readonly ComponentFile[];\n content_sha256: string;\n production_lock: string;\n sbom: string;\n licenses: readonly string[];\n provenance: readonly string[];\n protocols: readonly string[];\n asset_fingerprints: Readonly<Record<string, string>>;\n}>;\nexport type ComponentPath = Readonly<{ component: string; path: string }>;\nexport type RuntimeLaunch = Readonly<{\n id: string;\n platform: RuntimePlatform;\n executable: ComponentPath;\n environment: 'isolated' | 'cli-auth';\n context_protocol?: typeof RUNTIME_HOST_CONTEXT_PROTOCOL;\n argv: readonly (ComponentPath | Readonly<{ literal: string }>)[];\n}>;\nexport type WorkspaceCompatibility = Readonly<{ schema: string; features: readonly string[] }>;\nexport type RuntimeManifest = Readonly<{\n schema: typeof RUNTIME_MANIFEST_SCHEMA;\n bootstrap_protocol: typeof RUNTIME_BOOTSTRAP_PROTOCOL;\n product: Readonly<{ id: string; version: string }>;\n minimum_hosts: Readonly<\n Partial<Record<RuntimePlatform, Readonly<{ os_release: string; glibc: string | null }>>>\n >;\n workspace: Readonly<{\n read: readonly WorkspaceCompatibility[];\n write: readonly WorkspaceCompatibility[];\n }>;\n components: readonly RuntimeComponent[];\n launches: readonly RuntimeLaunch[];\n}>;\nexport type TrustedRuntimeManifest = Readonly<{ sha256: string; manifest: RuntimeManifest }>;\nexport type RuntimeHost = Readonly<{\n platform: RuntimePlatform;\n osRelease: string;\n glibc: string | null;\n}>;\nexport type RuntimeHostContext = Readonly<{\n manifest: TrustedRuntimeManifest;\n cacheDir: string;\n cwd: string;\n entry: string;\n host: RuntimeHost;\n}>;\n"]}
@@ -3,5 +3,6 @@ export declare function parseRuntimeManifest(value: unknown): RuntimeManifest;
3
3
  export declare function trustRuntimeManifest(bytes: Uint8Array, expectedSha256: string): TrustedRuntimeManifest;
4
4
  export declare function loadTrustedRuntimeManifest(file: string, expectedSha256: string): TrustedRuntimeManifest;
5
5
  export declare function assertTrustedManifest(value: TrustedRuntimeManifest): void;
6
+ export declare function copyTrustedRuntimeManifestBytes(value: TrustedRuntimeManifest): Buffer;
6
7
  export declare function componentKey(value: RuntimeComponent): string;
7
8
  export declare function assertWorkspaceCompatibility(value: TrustedRuntimeManifest, request: WorkspaceCompatibility, access: 'read' | 'write'): void;
@@ -2,8 +2,8 @@ import fs from 'node:fs';
2
2
  import { createHash } from 'node:crypto';
3
3
  import { contentHash, runtimeError } from './files.js';
4
4
  import { array, deepFreeze, distributionUrl, exact, id, integer, invalid, platform, record, relativeFile, sha, text, unique, version, } from './manifest-values.js';
5
- import { RUNTIME_ARCHIVE_FORMAT, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_MANIFEST_SCHEMA, } from './manifest-types.js';
6
- const trusted = new WeakSet();
5
+ import { RUNTIME_ARCHIVE_FORMAT, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_MANIFEST_SCHEMA, RUNTIME_HOST_CONTEXT_PROTOCOL, } from './manifest-types.js';
6
+ const trusted = new WeakMap();
7
7
  function compatibility(value) {
8
8
  const result = array(value, 32).map((item) => {
9
9
  const entry = record(item, 'workspace compatibility');
@@ -148,7 +148,17 @@ export function parseRuntimeManifest(value) {
148
148
  invalid('host/component platform coverage');
149
149
  const launches = array(item.launches, 64, 1).map((value) => {
150
150
  const launch = record(value, 'launch');
151
- exact(launch, ['id', 'platform', 'executable', 'environment', 'argv'], 'launch');
151
+ const hasContext = Object.hasOwn(launch, 'context_protocol');
152
+ exact(launch, [
153
+ 'id',
154
+ 'platform',
155
+ 'executable',
156
+ 'environment',
157
+ 'argv',
158
+ ...(hasContext ? ['context_protocol'] : []),
159
+ ], 'launch');
160
+ if (hasContext && launch.context_protocol !== RUNTIME_HOST_CONTEXT_PROTOCOL)
161
+ invalid('host context protocol');
152
162
  if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')
153
163
  invalid('launch environment');
154
164
  const target = platform(launch.platform);
@@ -165,6 +175,7 @@ export function parseRuntimeManifest(value) {
165
175
  platform: target,
166
176
  executable: componentPath(launch.executable, components, target, true),
167
177
  environment: launch.environment,
178
+ ...(hasContext ? { context_protocol: RUNTIME_HOST_CONTEXT_PROTOCOL } : {}),
168
179
  argv,
169
180
  };
170
181
  });
@@ -184,18 +195,20 @@ export function parseRuntimeManifest(value) {
184
195
  }
185
196
  export function trustRuntimeManifest(bytes, expectedSha256) {
186
197
  sha(expectedSha256);
187
- if (bytes.byteLength > 32 * 1024 * 1024 ||
188
- createHash('sha256').update(bytes).digest('hex') !== expectedSha256)
198
+ if (bytes.byteLength > 32 * 1024 * 1024)
199
+ runtimeError('RUNTIME_MANIFEST_INTEGRITY', 'Runtime manifest bytes do not match the independent trust anchor.');
200
+ const snapshot = Buffer.from(bytes);
201
+ if (createHash('sha256').update(snapshot).digest('hex') !== expectedSha256)
189
202
  runtimeError('RUNTIME_MANIFEST_INTEGRITY', 'Runtime manifest bytes do not match the independent trust anchor.');
190
203
  let value;
191
204
  try {
192
- value = JSON.parse(Buffer.from(bytes).toString('utf8'));
205
+ value = JSON.parse(snapshot.toString('utf8'));
193
206
  }
194
207
  catch {
195
208
  invalid('JSON');
196
209
  }
197
210
  const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });
198
- trusted.add(result);
211
+ trusted.set(result, snapshot);
199
212
  return result;
200
213
  }
201
214
  export function loadTrustedRuntimeManifest(file, expectedSha256) {
@@ -208,6 +221,12 @@ export function assertTrustedManifest(value) {
208
221
  if (!value || !trusted.has(value))
209
222
  runtimeError('RUNTIME_MANIFEST_UNTRUSTED', 'Supply a manifest verified against an independent trusted digest.');
210
223
  }
224
+ export function copyTrustedRuntimeManifestBytes(value) {
225
+ const bytes = trusted.get(value);
226
+ if (!bytes)
227
+ runtimeError('RUNTIME_MANIFEST_UNTRUSTED', 'Supply a manifest verified against an independent trusted digest.');
228
+ return Buffer.from(bytes);
229
+ }
211
230
  export function componentKey(value) {
212
231
  return contentHash(value);
213
232
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { contentHash, runtimeError } from './files.js';\nimport {\n array,\n deepFreeze,\n distributionUrl,\n exact,\n id,\n integer,\n invalid,\n platform,\n record,\n relativeFile,\n sha,\n text,\n unique,\n version,\n} from './manifest-values.js';\nimport {\n RUNTIME_ARCHIVE_FORMAT,\n RUNTIME_BOOTSTRAP_PROTOCOL,\n RUNTIME_MANIFEST_SCHEMA,\n} from './manifest-types.js';\nimport type {\n ComponentFile,\n ComponentPath,\n RuntimeComponent,\n RuntimeLaunch,\n RuntimeManifest,\n TrustedRuntimeManifest,\n WorkspaceCompatibility,\n} from './manifest-types.js';\nconst trusted = new WeakSet<object>();\n\nfunction compatibility(value: unknown): WorkspaceCompatibility[] {\n const result = array(value, 32).map((item) => {\n const entry = record(item, 'workspace compatibility');\n exact(entry, ['schema', 'features'], 'workspace compatibility');\n const features = array(entry.features, 64).map((value) =>\n text(value, 'workspace feature', 128),\n );\n unique(features, 'workspace feature');\n return { schema: text(entry.schema, 'workspace schema', 128), features };\n });\n unique(\n result.map((entry) => entry.schema),\n 'workspace schema',\n );\n return result;\n}\nfunction component(value: unknown): RuntimeComponent {\n const item = record(value, 'component');\n exact(\n item,\n [\n 'id',\n 'version',\n 'platform',\n 'archive',\n 'files',\n 'content_sha256',\n 'production_lock',\n 'sbom',\n 'licenses',\n 'provenance',\n 'protocols',\n 'asset_fingerprints',\n ],\n 'component',\n );\n const archive = record(item.archive, 'archive');\n exact(archive, ['format', 'url', 'bytes', 'sha256'], 'archive');\n if (archive.format !== RUNTIME_ARCHIVE_FORMAT) invalid('archive format');\n let total = 0;\n const files: ComponentFile[] = array(item.files, 50_000, 1).map((value) => {\n const file = record(value, 'component file');\n exact(file, ['path', 'bytes', 'sha256', 'mode'], 'component file');\n if (file.mode !== 420 && file.mode !== 493) invalid('file mode');\n const bytes = integer(file.bytes, 512 * 1024 * 1024);\n total += bytes;\n return { path: relativeFile(file.path), bytes, sha256: sha(file.sha256), mode: file.mode };\n });\n if (total > 2 * 1024 * 1024 * 1024) invalid('unpacked size');\n const paths = files.map((file) => file.path);\n unique(\n paths.map((path) => path.toLowerCase()),\n 'case-folded file path',\n );\n if (JSON.stringify(paths) !== JSON.stringify([...paths].sort())) invalid('file order');\n const pathSet = new Set(paths.map((path) => path.toLowerCase()));\n for (const file of paths) {\n const parts = file.split('/');\n for (let i = 1; i < parts.length; i++)\n if (pathSet.has(parts.slice(0, i).join('/').toLowerCase()))\n invalid('file/directory collision');\n }\n const content = sha(item.content_sha256);\n if (content !== contentHash(files)) invalid('component content SHA-256');\n const requiredFile = (value: unknown) => {\n const file = relativeFile(value);\n if (!paths.includes(file)) invalid('metadata file reference');\n return file;\n };\n const licenses = array(item.licenses, 64, 1).map(requiredFile),\n provenance = array(item.provenance, 64, 1).map(requiredFile);\n unique(licenses, 'license');\n unique(provenance, 'provenance');\n const protocols = array(item.protocols, 32, 1).map((value) =>\n text(value, 'component protocol', 128),\n );\n unique(protocols, 'protocol');\n const fingerprints = record(item.asset_fingerprints, 'asset fingerprints');\n if (Object.keys(fingerprints).length > 64) invalid('fingerprint count');\n const asset_fingerprints = Object.fromEntries(\n Object.entries(fingerprints).map(([key, value]) => [id(key), sha(value)]),\n );\n return {\n id: id(item.id),\n version: version(item.version),\n platform: platform(item.platform),\n archive: {\n format: RUNTIME_ARCHIVE_FORMAT,\n url: distributionUrl(archive.url),\n bytes: integer(archive.bytes, 512 * 1024 * 1024, 1),\n sha256: sha(archive.sha256),\n },\n files,\n content_sha256: content,\n production_lock: requiredFile(item.production_lock),\n sbom: requiredFile(item.sbom),\n licenses,\n provenance,\n protocols,\n asset_fingerprints,\n };\n}\nfunction componentPath(\n value: unknown,\n components: readonly RuntimeComponent[],\n target: string,\n executable = false,\n): ComponentPath {\n const entry = record(value, 'component path');\n exact(entry, ['component', 'path'], 'component path');\n const componentId = id(entry.component),\n file = relativeFile(entry.path);\n const owner = components.find((item) => item.platform === target && item.id === componentId);\n const fact = owner?.files.find((item) => item.path === file);\n if (!fact || (executable && fact.mode !== 493)) invalid('launch file reference');\n return { component: componentId, path: file };\n}\nexport function parseRuntimeManifest(value: unknown): RuntimeManifest {\n const item = record(value, 'manifest');\n exact(\n item,\n [\n 'schema',\n 'bootstrap_protocol',\n 'product',\n 'minimum_hosts',\n 'workspace',\n 'components',\n 'launches',\n ],\n 'manifest',\n );\n if (\n item.schema !== RUNTIME_MANIFEST_SCHEMA ||\n item.bootstrap_protocol !== RUNTIME_BOOTSTRAP_PROTOCOL\n )\n invalid('manifest protocol version');\n const product = record(item.product, 'product');\n exact(product, ['id', 'version'], 'product');\n const workspace = record(item.workspace, 'workspace');\n exact(workspace, ['read', 'write'], 'workspace');\n const read = compatibility(workspace.read),\n write = compatibility(workspace.write);\n for (const entry of write)\n if (\n !read.some(\n (candidate) =>\n candidate.schema === entry.schema &&\n entry.features.every((feature) => candidate.features.includes(feature)),\n )\n )\n invalid('write compatibility outside read support');\n const components = array(item.components, 128, 1).map(component);\n unique(\n components.map((item) => `${item.platform}:${item.id}`),\n 'platform component',\n );\n const minimum = record(item.minimum_hosts, 'minimum hosts');\n const minimum_hosts = Object.fromEntries(\n Object.entries(minimum).map(([key, value]) => {\n const target = platform(key),\n host = record(value, 'minimum host');\n exact(host, ['os_release', 'glibc'], 'minimum host');\n if (\n (target.startsWith('linux-') && typeof host.glibc !== 'string') ||\n (!target.startsWith('linux-') && host.glibc !== null)\n )\n invalid('host ABI');\n const glibc = host.glibc === null ? null : text(host.glibc, 'glibc version', 40);\n if (glibc !== null && !/^[0-9]+\\.[0-9]+$/u.test(glibc)) invalid('glibc version');\n return [target, { os_release: version(host.os_release), glibc }];\n }),\n );\n const supported = [...new Set(components.map((item) => item.platform))].sort();\n if (JSON.stringify(Object.keys(minimum_hosts).sort()) !== JSON.stringify(supported))\n invalid('host/component platform coverage');\n const launches: RuntimeLaunch[] = array(item.launches, 64, 1).map((value) => {\n const launch = record(value, 'launch');\n exact(launch, ['id', 'platform', 'executable', 'environment', 'argv'], 'launch');\n if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')\n invalid('launch environment');\n const target = platform(launch.platform);\n const argv = array(launch.argv, 32).map((value) => {\n const arg = record(value, 'launch argument');\n if (Object.hasOwn(arg, 'literal')) {\n exact(arg, ['literal'], 'literal argument');\n return { literal: text(arg.literal, 'literal argument', 4096) };\n }\n return componentPath(arg, components, target);\n });\n return {\n id: id(launch.id),\n platform: target,\n executable: componentPath(launch.executable, components, target, true),\n environment: launch.environment,\n argv,\n };\n });\n unique(\n launches.map((item) => `${item.platform}:${item.id}`),\n 'platform launch',\n );\n for (const target of supported)\n if (!launches.some((launch) => launch.platform === target)) invalid('platform launch coverage');\n return deepFreeze({\n schema: RUNTIME_MANIFEST_SCHEMA,\n bootstrap_protocol: RUNTIME_BOOTSTRAP_PROTOCOL,\n product: { id: id(product.id), version: version(product.version) },\n minimum_hosts,\n workspace: { read, write },\n components,\n launches,\n });\n}\nexport function trustRuntimeManifest(\n bytes: Uint8Array,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n sha(expectedSha256);\n if (\n bytes.byteLength > 32 * 1024 * 1024 ||\n createHash('sha256').update(bytes).digest('hex') !== expectedSha256\n )\n runtimeError(\n 'RUNTIME_MANIFEST_INTEGRITY',\n 'Runtime manifest bytes do not match the independent trust anchor.',\n );\n let value: unknown;\n try {\n value = JSON.parse(Buffer.from(bytes).toString('utf8'));\n } catch {\n invalid('JSON');\n }\n const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });\n trusted.add(result);\n return result;\n}\nexport function loadTrustedRuntimeManifest(\n file: string,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n const stat = fs.lstatSync(file);\n if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32 * 1024 * 1024)\n runtimeError('RUNTIME_MANIFEST_FILE', 'Runtime manifest must be a bounded regular file.');\n return trustRuntimeManifest(fs.readFileSync(file), expectedSha256);\n}\nexport function assertTrustedManifest(value: TrustedRuntimeManifest): void {\n if (!value || !trusted.has(value))\n runtimeError(\n 'RUNTIME_MANIFEST_UNTRUSTED',\n 'Supply a manifest verified against an independent trusted digest.',\n );\n}\nexport function componentKey(value: RuntimeComponent): string {\n return contentHash(value);\n}\nexport function assertWorkspaceCompatibility(\n value: TrustedRuntimeManifest,\n request: WorkspaceCompatibility,\n access: 'read' | 'write',\n): void {\n assertTrustedManifest(value);\n const support = value.manifest.workspace[access]?.find(\n (entry) => entry.schema === request.schema,\n );\n if (!support || !request.features.every((feature) => support.features.includes(feature)))\n runtimeError(\n 'RUNTIME_WORKSPACE_INCOMPATIBLE',\n 'The selected runtime does not support the requested workspace access/schema/features.',\n );\n}\n"]}
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { contentHash, runtimeError } from './files.js';\nimport {\n array,\n deepFreeze,\n distributionUrl,\n exact,\n id,\n integer,\n invalid,\n platform,\n record,\n relativeFile,\n sha,\n text,\n unique,\n version,\n} from './manifest-values.js';\nimport {\n RUNTIME_ARCHIVE_FORMAT,\n RUNTIME_BOOTSTRAP_PROTOCOL,\n RUNTIME_MANIFEST_SCHEMA,\n RUNTIME_HOST_CONTEXT_PROTOCOL,\n} from './manifest-types.js';\nimport type {\n ComponentFile,\n ComponentPath,\n RuntimeComponent,\n RuntimeLaunch,\n RuntimeManifest,\n TrustedRuntimeManifest,\n WorkspaceCompatibility,\n} from './manifest-types.js';\nconst trusted = new WeakMap<object, Buffer>();\n\nfunction compatibility(value: unknown): WorkspaceCompatibility[] {\n const result = array(value, 32).map((item) => {\n const entry = record(item, 'workspace compatibility');\n exact(entry, ['schema', 'features'], 'workspace compatibility');\n const features = array(entry.features, 64).map((value) =>\n text(value, 'workspace feature', 128),\n );\n unique(features, 'workspace feature');\n return { schema: text(entry.schema, 'workspace schema', 128), features };\n });\n unique(\n result.map((entry) => entry.schema),\n 'workspace schema',\n );\n return result;\n}\nfunction component(value: unknown): RuntimeComponent {\n const item = record(value, 'component');\n exact(\n item,\n [\n 'id',\n 'version',\n 'platform',\n 'archive',\n 'files',\n 'content_sha256',\n 'production_lock',\n 'sbom',\n 'licenses',\n 'provenance',\n 'protocols',\n 'asset_fingerprints',\n ],\n 'component',\n );\n const archive = record(item.archive, 'archive');\n exact(archive, ['format', 'url', 'bytes', 'sha256'], 'archive');\n if (archive.format !== RUNTIME_ARCHIVE_FORMAT) invalid('archive format');\n let total = 0;\n const files: ComponentFile[] = array(item.files, 50_000, 1).map((value) => {\n const file = record(value, 'component file');\n exact(file, ['path', 'bytes', 'sha256', 'mode'], 'component file');\n if (file.mode !== 420 && file.mode !== 493) invalid('file mode');\n const bytes = integer(file.bytes, 512 * 1024 * 1024);\n total += bytes;\n return { path: relativeFile(file.path), bytes, sha256: sha(file.sha256), mode: file.mode };\n });\n if (total > 2 * 1024 * 1024 * 1024) invalid('unpacked size');\n const paths = files.map((file) => file.path);\n unique(\n paths.map((path) => path.toLowerCase()),\n 'case-folded file path',\n );\n if (JSON.stringify(paths) !== JSON.stringify([...paths].sort())) invalid('file order');\n const pathSet = new Set(paths.map((path) => path.toLowerCase()));\n for (const file of paths) {\n const parts = file.split('/');\n for (let i = 1; i < parts.length; i++)\n if (pathSet.has(parts.slice(0, i).join('/').toLowerCase()))\n invalid('file/directory collision');\n }\n const content = sha(item.content_sha256);\n if (content !== contentHash(files)) invalid('component content SHA-256');\n const requiredFile = (value: unknown) => {\n const file = relativeFile(value);\n if (!paths.includes(file)) invalid('metadata file reference');\n return file;\n };\n const licenses = array(item.licenses, 64, 1).map(requiredFile),\n provenance = array(item.provenance, 64, 1).map(requiredFile);\n unique(licenses, 'license');\n unique(provenance, 'provenance');\n const protocols = array(item.protocols, 32, 1).map((value) =>\n text(value, 'component protocol', 128),\n );\n unique(protocols, 'protocol');\n const fingerprints = record(item.asset_fingerprints, 'asset fingerprints');\n if (Object.keys(fingerprints).length > 64) invalid('fingerprint count');\n const asset_fingerprints = Object.fromEntries(\n Object.entries(fingerprints).map(([key, value]) => [id(key), sha(value)]),\n );\n return {\n id: id(item.id),\n version: version(item.version),\n platform: platform(item.platform),\n archive: {\n format: RUNTIME_ARCHIVE_FORMAT,\n url: distributionUrl(archive.url),\n bytes: integer(archive.bytes, 512 * 1024 * 1024, 1),\n sha256: sha(archive.sha256),\n },\n files,\n content_sha256: content,\n production_lock: requiredFile(item.production_lock),\n sbom: requiredFile(item.sbom),\n licenses,\n provenance,\n protocols,\n asset_fingerprints,\n };\n}\nfunction componentPath(\n value: unknown,\n components: readonly RuntimeComponent[],\n target: string,\n executable = false,\n): ComponentPath {\n const entry = record(value, 'component path');\n exact(entry, ['component', 'path'], 'component path');\n const componentId = id(entry.component),\n file = relativeFile(entry.path);\n const owner = components.find((item) => item.platform === target && item.id === componentId);\n const fact = owner?.files.find((item) => item.path === file);\n if (!fact || (executable && fact.mode !== 493)) invalid('launch file reference');\n return { component: componentId, path: file };\n}\nexport function parseRuntimeManifest(value: unknown): RuntimeManifest {\n const item = record(value, 'manifest');\n exact(\n item,\n [\n 'schema',\n 'bootstrap_protocol',\n 'product',\n 'minimum_hosts',\n 'workspace',\n 'components',\n 'launches',\n ],\n 'manifest',\n );\n if (\n item.schema !== RUNTIME_MANIFEST_SCHEMA ||\n item.bootstrap_protocol !== RUNTIME_BOOTSTRAP_PROTOCOL\n )\n invalid('manifest protocol version');\n const product = record(item.product, 'product');\n exact(product, ['id', 'version'], 'product');\n const workspace = record(item.workspace, 'workspace');\n exact(workspace, ['read', 'write'], 'workspace');\n const read = compatibility(workspace.read),\n write = compatibility(workspace.write);\n for (const entry of write)\n if (\n !read.some(\n (candidate) =>\n candidate.schema === entry.schema &&\n entry.features.every((feature) => candidate.features.includes(feature)),\n )\n )\n invalid('write compatibility outside read support');\n const components = array(item.components, 128, 1).map(component);\n unique(\n components.map((item) => `${item.platform}:${item.id}`),\n 'platform component',\n );\n const minimum = record(item.minimum_hosts, 'minimum hosts');\n const minimum_hosts = Object.fromEntries(\n Object.entries(minimum).map(([key, value]) => {\n const target = platform(key),\n host = record(value, 'minimum host');\n exact(host, ['os_release', 'glibc'], 'minimum host');\n if (\n (target.startsWith('linux-') && typeof host.glibc !== 'string') ||\n (!target.startsWith('linux-') && host.glibc !== null)\n )\n invalid('host ABI');\n const glibc = host.glibc === null ? null : text(host.glibc, 'glibc version', 40);\n if (glibc !== null && !/^[0-9]+\\.[0-9]+$/u.test(glibc)) invalid('glibc version');\n return [target, { os_release: version(host.os_release), glibc }];\n }),\n );\n const supported = [...new Set(components.map((item) => item.platform))].sort();\n if (JSON.stringify(Object.keys(minimum_hosts).sort()) !== JSON.stringify(supported))\n invalid('host/component platform coverage');\n const launches: RuntimeLaunch[] = array(item.launches, 64, 1).map((value) => {\n const launch = record(value, 'launch');\n const hasContext = Object.hasOwn(launch, 'context_protocol');\n exact(\n launch,\n [\n 'id',\n 'platform',\n 'executable',\n 'environment',\n 'argv',\n ...(hasContext ? ['context_protocol'] : []),\n ],\n 'launch',\n );\n if (hasContext && launch.context_protocol !== RUNTIME_HOST_CONTEXT_PROTOCOL)\n invalid('host context protocol');\n if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')\n invalid('launch environment');\n const target = platform(launch.platform);\n const argv = array(launch.argv, 32).map((value) => {\n const arg = record(value, 'launch argument');\n if (Object.hasOwn(arg, 'literal')) {\n exact(arg, ['literal'], 'literal argument');\n return { literal: text(arg.literal, 'literal argument', 4096) };\n }\n return componentPath(arg, components, target);\n });\n return {\n id: id(launch.id),\n platform: target,\n executable: componentPath(launch.executable, components, target, true),\n environment: launch.environment,\n ...(hasContext ? { context_protocol: RUNTIME_HOST_CONTEXT_PROTOCOL } : {}),\n argv,\n };\n });\n unique(\n launches.map((item) => `${item.platform}:${item.id}`),\n 'platform launch',\n );\n for (const target of supported)\n if (!launches.some((launch) => launch.platform === target)) invalid('platform launch coverage');\n return deepFreeze({\n schema: RUNTIME_MANIFEST_SCHEMA,\n bootstrap_protocol: RUNTIME_BOOTSTRAP_PROTOCOL,\n product: { id: id(product.id), version: version(product.version) },\n minimum_hosts,\n workspace: { read, write },\n components,\n launches,\n });\n}\nexport function trustRuntimeManifest(\n bytes: Uint8Array,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n sha(expectedSha256);\n if (bytes.byteLength > 32 * 1024 * 1024)\n runtimeError(\n 'RUNTIME_MANIFEST_INTEGRITY',\n 'Runtime manifest bytes do not match the independent trust anchor.',\n );\n const snapshot = Buffer.from(bytes);\n if (createHash('sha256').update(snapshot).digest('hex') !== expectedSha256)\n runtimeError(\n 'RUNTIME_MANIFEST_INTEGRITY',\n 'Runtime manifest bytes do not match the independent trust anchor.',\n );\n let value: unknown;\n try {\n value = JSON.parse(snapshot.toString('utf8'));\n } catch {\n invalid('JSON');\n }\n const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });\n trusted.set(result, snapshot);\n return result;\n}\nexport function loadTrustedRuntimeManifest(\n file: string,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n const stat = fs.lstatSync(file);\n if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32 * 1024 * 1024)\n runtimeError('RUNTIME_MANIFEST_FILE', 'Runtime manifest must be a bounded regular file.');\n return trustRuntimeManifest(fs.readFileSync(file), expectedSha256);\n}\nexport function assertTrustedManifest(value: TrustedRuntimeManifest): void {\n if (!value || !trusted.has(value))\n runtimeError(\n 'RUNTIME_MANIFEST_UNTRUSTED',\n 'Supply a manifest verified against an independent trusted digest.',\n );\n}\nexport function copyTrustedRuntimeManifestBytes(value: TrustedRuntimeManifest): Buffer {\n const bytes = trusted.get(value);\n if (!bytes)\n runtimeError(\n 'RUNTIME_MANIFEST_UNTRUSTED',\n 'Supply a manifest verified against an independent trusted digest.',\n );\n return Buffer.from(bytes);\n}\nexport function componentKey(value: RuntimeComponent): string {\n return contentHash(value);\n}\nexport function assertWorkspaceCompatibility(\n value: TrustedRuntimeManifest,\n request: WorkspaceCompatibility,\n access: 'read' | 'write',\n): void {\n assertTrustedManifest(value);\n const support = value.manifest.workspace[access]?.find(\n (entry) => entry.schema === request.schema,\n );\n if (!support || !request.features.every((feature) => support.features.includes(feature)))\n runtimeError(\n 'RUNTIME_WORKSPACE_INCOMPATIBLE',\n 'The selected runtime does not support the requested workspace access/schema/features.',\n );\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  import type { FoundryCommandSpecAsyncSpawnOptions, FoundryCommandSpecSpawnResult } from '../../command-spec.js';
2
+ import type { RuntimeHostContext } from './manifest-types.js';
2
3
  /** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */
3
- export declare function spawnRuntimeProcess(executable: string, argv: readonly string[], options: FoundryCommandSpecAsyncSpawnOptions): Promise<FoundryCommandSpecSpawnResult>;
4
+ export declare function spawnRuntimeProcess(executable: string, argv: readonly string[], options: FoundryCommandSpecAsyncSpawnOptions, context?: RuntimeHostContext): Promise<FoundryCommandSpecSpawnResult>;
@@ -1,19 +1,22 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import { serveRuntimeHostContext } from './host-context-server.js';
2
3
  /** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */
3
- export function spawnRuntimeProcess(executable, argv, options) {
4
+ export function spawnRuntimeProcess(executable, argv, options, context) {
4
5
  return new Promise((resolve) => {
5
6
  const child = spawn(executable, [...argv], {
6
7
  cwd: options.cwd,
7
8
  env: options.env,
8
9
  shell: false,
9
10
  windowsHide: true,
10
- stdio: ['ignore', 'pipe', 'pipe'],
11
+ stdio: ['ignore', 'pipe', 'pipe', ...(context ? ['ipc'] : [])],
11
12
  });
12
13
  const stdout = [], stderr = [];
13
14
  let bytes = 0;
14
15
  let error;
15
16
  let force;
17
+ let hostSession;
16
18
  const stop = () => {
19
+ hostSession?.finish();
17
20
  child.kill('SIGTERM');
18
21
  force ??= setTimeout(() => child.kill('SIGKILL'), 3000);
19
22
  };
@@ -21,6 +24,15 @@ export function spawnRuntimeProcess(executable, argv, options) {
21
24
  error = new Error('Runtime execution was interrupted.');
22
25
  stop();
23
26
  };
27
+ if (context)
28
+ child.once('spawn', () => {
29
+ if (error)
30
+ return;
31
+ hostSession = serveRuntimeHostContext(child, context, (failure) => {
32
+ error ??= failure;
33
+ stop();
34
+ });
35
+ });
24
36
  options.signal.addEventListener('abort', abort, { once: true });
25
37
  if (options.signal.aborted)
26
38
  abort();
@@ -39,6 +51,8 @@ export function spawnRuntimeProcess(executable, argv, options) {
39
51
  error = value;
40
52
  });
41
53
  child.once('close', (status, signal) => {
54
+ const contextError = hostSession?.finish();
55
+ error ??= contextError;
42
56
  if (force)
43
57
  clearTimeout(force);
44
58
  options.signal.removeEventListener('abort', abort);
@@ -1 +1 @@
1
- {"version":3,"file":"process.js","sourceRoot":"","sources":["../../../../src/lib/runtime/process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAM3C,gHAAgH;AAChH,MAAM,UAAU,mBAAmB,CACjC,UAAkB,EAClB,IAAuB,EACvB,OAA4C;IAE5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE;YACzC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,KAAK;YACZ,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QACH,MAAM,MAAM,GAAa,EAAE,EACzB,MAAM,GAAa,EAAE,CAAC;QACxB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAwB,CAAC;QAC7B,IAAI,KAAiC,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,KAAK,KAAK,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,KAAK,GAAG,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,IAAI,EAAE,CAAC;QACT,CAAC,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;YAAE,KAAK,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,CAAC,MAAgB,EAAE,KAAa,EAAE,EAAE;YAClD,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;YACtB,IAAI,KAAK,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACpD,KAAK,GAAG,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;gBACxD,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC;QACF,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QACnE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QACnE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC5B,KAAK,GAAG,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACnD,OAAO,CAAC;gBACN,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC9C,MAAM;gBACN,MAAM;gBACN,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { spawn } from 'node:child_process';\nimport type {\n FoundryCommandSpecAsyncSpawnOptions,\n FoundryCommandSpecSpawnResult,\n} from '../../command-spec.js';\n\n/** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */\nexport function spawnRuntimeProcess(\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecAsyncSpawnOptions,\n): Promise<FoundryCommandSpecSpawnResult> {\n return new Promise((resolve) => {\n const child = spawn(executable, [...argv], {\n cwd: options.cwd,\n env: options.env,\n shell: false,\n windowsHide: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n const stdout: Buffer[] = [],\n stderr: Buffer[] = [];\n let bytes = 0;\n let error: Error | undefined;\n let force: NodeJS.Timeout | undefined;\n const stop = () => {\n child.kill('SIGTERM');\n force ??= setTimeout(() => child.kill('SIGKILL'), 3000);\n };\n const abort = () => {\n error = new Error('Runtime execution was interrupted.');\n stop();\n };\n options.signal.addEventListener('abort', abort, { once: true });\n if (options.signal.aborted) abort();\n const capture = (target: Buffer[], chunk: Buffer) => {\n bytes += chunk.length;\n if (bytes > (options.maxBuffer ?? 16 * 1024 * 1024)) {\n error = new Error('Runtime output exceeded its bound.');\n stop();\n return;\n }\n target.push(chunk);\n };\n child.stdout.on('data', (chunk: Buffer) => capture(stdout, chunk));\n child.stderr.on('data', (chunk: Buffer) => capture(stderr, chunk));\n child.once('error', (value) => {\n error = value;\n });\n child.once('close', (status, signal) => {\n if (force) clearTimeout(force);\n options.signal.removeEventListener('abort', abort);\n resolve({\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n status,\n signal,\n ...(error ? { error } : {}),\n });\n });\n });\n}\n"]}
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../../../src/lib/runtime/process.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport type {\n FoundryCommandSpecAsyncSpawnOptions,\n FoundryCommandSpecSpawnResult,\n} from '../../command-spec.js';\nimport type { RuntimeHostContext } from './manifest-types.js';\nimport { serveRuntimeHostContext } from './host-context-server.js';\n\n/** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */\nexport function spawnRuntimeProcess(\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecAsyncSpawnOptions,\n context?: RuntimeHostContext,\n): Promise<FoundryCommandSpecSpawnResult> {\n return new Promise((resolve) => {\n const child = spawn(executable, [...argv], {\n cwd: options.cwd,\n env: options.env,\n shell: false,\n windowsHide: true,\n stdio: ['ignore', 'pipe', 'pipe', ...(context ? ['ipc' as const] : [])],\n });\n const stdout: Buffer[] = [],\n stderr: Buffer[] = [];\n let bytes = 0;\n let error: Error | undefined;\n let force: NodeJS.Timeout | undefined;\n let hostSession: ReturnType<typeof serveRuntimeHostContext> | undefined;\n const stop = () => {\n hostSession?.finish();\n child.kill('SIGTERM');\n force ??= setTimeout(() => child.kill('SIGKILL'), 3000);\n };\n const abort = () => {\n error = new Error('Runtime execution was interrupted.');\n stop();\n };\n if (context)\n child.once('spawn', () => {\n if (error) return;\n hostSession = serveRuntimeHostContext(child, context, (failure) => {\n error ??= failure;\n stop();\n });\n });\n options.signal.addEventListener('abort', abort, { once: true });\n if (options.signal.aborted) abort();\n const capture = (target: Buffer[], chunk: Buffer) => {\n bytes += chunk.length;\n if (bytes > (options.maxBuffer ?? 16 * 1024 * 1024)) {\n error = new Error('Runtime output exceeded its bound.');\n stop();\n return;\n }\n target.push(chunk);\n };\n child.stdout!.on('data', (chunk: Buffer) => capture(stdout, chunk));\n child.stderr!.on('data', (chunk: Buffer) => capture(stderr, chunk));\n child.once('error', (value) => {\n error = value;\n });\n child.once('close', (status, signal) => {\n const contextError = hostSession?.finish();\n error ??= contextError;\n if (force) clearTimeout(force);\n options.signal.removeEventListener('abort', abort);\n resolve({\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n status,\n signal,\n ...(error ? { error } : {}),\n });\n });\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function runtimeWorkDirectory(value: string): string;
2
+ export declare function assertRuntimeWorkDirectoryOutsideInstall(cwd: string, cache: string): void;
@@ -0,0 +1,16 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { runtimeError } from './files.js';
4
+ export function runtimeWorkDirectory(value) {
5
+ if (!path.isAbsolute(value) || !fs.statSync(value).isDirectory())
6
+ runtimeError('RUNTIME_LAUNCH_CWD', 'Runtime launch requires an explicit existing work directory.');
7
+ return fs.realpathSync(value);
8
+ }
9
+ export function assertRuntimeWorkDirectoryOutsideInstall(cwd, cache) {
10
+ const relative = path.relative(cache, cwd);
11
+ if (relative === '' ||
12
+ (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative)) ||
13
+ /\/(?:\.agents|\.codex)\/skills(?:\/|$)/u.test(cwd.split(path.sep).join('/')))
14
+ runtimeError('RUNTIME_LAUNCH_CWD', 'A runtime cache or installed skill cannot be used as the work directory.');
15
+ }
16
+ //# sourceMappingURL=work-directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-directory.js","sourceRoot":"","sources":["../../../../src/lib/runtime/work-directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;QAC9D,YAAY,CACV,oBAAoB,EACpB,8DAA8D,CAC/D,CAAC;IACJ,OAAO,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,wCAAwC,CAAC,GAAW,EAAE,KAAa;IACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3C,IACE,QAAQ,KAAK,EAAE;QACf,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1F,yCAAyC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE7E,YAAY,CACV,oBAAoB,EACpB,0EAA0E,CAC3E,CAAC;AACN,CAAC","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { runtimeError } from './files.js';\n\nexport function runtimeWorkDirectory(value: string): string {\n if (!path.isAbsolute(value) || !fs.statSync(value).isDirectory())\n runtimeError(\n 'RUNTIME_LAUNCH_CWD',\n 'Runtime launch requires an explicit existing work directory.',\n );\n return fs.realpathSync(value);\n}\n\nexport function assertRuntimeWorkDirectoryOutsideInstall(cwd: string, cache: string): void {\n const relative = path.relative(cache, cwd);\n if (\n relative === '' ||\n (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative)) ||\n /\\/(?:\\.agents|\\.codex)\\/skills(?:\\/|$)/u.test(cwd.split(path.sep).join('/'))\n )\n runtimeError(\n 'RUNTIME_LAUNCH_CWD',\n 'A runtime cache or installed skill cannot be used as the work directory.',\n );\n}\n"]}
@@ -5,11 +5,12 @@ export type { CliRuntimeDescriptor, CliRuntimeExpectation, RuntimeFileFact, Runt
5
5
  export declare function describeCliRuntime(): CliRuntimeDescriptor;
6
6
  /** The caller supplies independently trusted expected release facts. This grants no account permission. */
7
7
  export declare function assertCliRuntimeMatches(expected: unknown): CliRuntimeDescriptor;
8
- export { parseRuntimeManifest, trustRuntimeManifest, loadTrustedRuntimeManifest, assertWorkspaceCompatibility, } from './lib/runtime/manifest.js';
9
- export { RUNTIME_MANIFEST_SCHEMA, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_ARCHIVE_FORMAT, } from './lib/runtime/manifest-types.js';
10
- export type { RuntimeManifest, RuntimeComponent, RuntimeLaunch, ComponentFile, TrustedRuntimeManifest, RuntimeHost, WorkspaceCompatibility, } from './lib/runtime/manifest-types.js';
8
+ export { parseRuntimeManifest, trustRuntimeManifest, loadTrustedRuntimeManifest, assertWorkspaceCompatibility, copyTrustedRuntimeManifestBytes, } from './lib/runtime/manifest.js';
9
+ export { RUNTIME_MANIFEST_SCHEMA, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_ARCHIVE_FORMAT, RUNTIME_HOST_CONTEXT_PROTOCOL, } from './lib/runtime/manifest-types.js';
10
+ export type { RuntimeManifest, RuntimeComponent, RuntimeLaunch, ComponentFile, TrustedRuntimeManifest, RuntimeHost, RuntimeHostContext, WorkspaceCompatibility, } from './lib/runtime/manifest-types.js';
11
11
  export { ensureRuntimeComponents, inspectRuntimeComponents, pruneRuntimeComponents, } from './lib/runtime/manager.js';
12
12
  export type { RuntimeManagerOptions, RuntimeManagerReport, RuntimeComponentStatus, } from './lib/runtime/manager.js';
13
13
  export { executeRuntimeLaunch } from './lib/runtime/execute.js';
14
- export type { RuntimeExecutionOptions } from './lib/runtime/execute.js';
14
+ export type { RuntimeExecutionOptions, RuntimeExecutionSpawn } from './lib/runtime/execute.js';
15
+ export { receiveRuntimeHostContext } from './lib/runtime/host-context.js';
15
16
  export { writeRuntimeComponentArchive } from './lib/runtime/archive-writer.js';
@@ -14,9 +14,10 @@ export function assertCliRuntimeMatches(expected) {
14
14
  validateRuntimeExpectation(expected);
15
15
  return assertRuntimeObservationMatches(describeCliRuntime(), expected);
16
16
  }
17
- export { parseRuntimeManifest, trustRuntimeManifest, loadTrustedRuntimeManifest, assertWorkspaceCompatibility, } from './lib/runtime/manifest.js';
18
- export { RUNTIME_MANIFEST_SCHEMA, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_ARCHIVE_FORMAT, } from './lib/runtime/manifest-types.js';
17
+ export { parseRuntimeManifest, trustRuntimeManifest, loadTrustedRuntimeManifest, assertWorkspaceCompatibility, copyTrustedRuntimeManifestBytes, } from './lib/runtime/manifest.js';
18
+ export { RUNTIME_MANIFEST_SCHEMA, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_ARCHIVE_FORMAT, RUNTIME_HOST_CONTEXT_PROTOCOL, } from './lib/runtime/manifest-types.js';
19
19
  export { ensureRuntimeComponents, inspectRuntimeComponents, pruneRuntimeComponents, } from './lib/runtime/manager.js';
20
20
  export { executeRuntimeLaunch } from './lib/runtime/execute.js';
21
+ export { receiveRuntimeHostContext } from './lib/runtime/host-context.js';
21
22
  export { writeRuntimeComponentArchive } from './lib/runtime/archive-writer.js';
22
23
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC9B,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAQhC,kGAAkG;AAClG,MAAM,UAAU,kBAAkB;IAChC,OAAO,iBAAiB,CAAC,kBAAkB,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE;QAC5D,UAAU,EAAE,OAAO,CAAC,QAAQ;QAC5B,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAC,CAAC;AACL,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,uBAAuB,CAAC,QAAiB;IACvD,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,OAAO,+BAA+B,CAAC,kBAAkB,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AAUzC,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC","sourcesContent":["import {\n inspectCliRuntime,\n runtimePackageRoot,\n assertRuntimeObservationMatches,\n validateRuntimeExpectation,\n} from './lib/runtime/descriptor.js';\nimport type { CliRuntimeDescriptor } from './lib/runtime/types.js';\nexport {\n CLI_RUNTIME_DESCRIPTOR_SCHEMA,\n CLI_RUNTIME_EXPECTATION_SCHEMA,\n RUNTIME_PLATFORMS,\n} from './lib/runtime/types.js';\nexport type {\n CliRuntimeDescriptor,\n CliRuntimeExpectation,\n RuntimeFileFact,\n RuntimePlatform,\n} from './lib/runtime/types.js';\n\n/** Observe this installed package without reading user configuration or accessing the network. */\nexport function describeCliRuntime(): CliRuntimeDescriptor {\n return inspectCliRuntime(runtimePackageRoot(import.meta.url), {\n executable: process.execPath,\n version: process.versions.node,\n platform: process.platform,\n arch: process.arch,\n });\n}\n\n/** The caller supplies independently trusted expected release facts. This grants no account permission. */\nexport function assertCliRuntimeMatches(expected: unknown): CliRuntimeDescriptor {\n validateRuntimeExpectation(expected);\n return assertRuntimeObservationMatches(describeCliRuntime(), expected);\n}\n\nexport {\n parseRuntimeManifest,\n trustRuntimeManifest,\n loadTrustedRuntimeManifest,\n assertWorkspaceCompatibility,\n} from './lib/runtime/manifest.js';\nexport {\n RUNTIME_MANIFEST_SCHEMA,\n RUNTIME_BOOTSTRAP_PROTOCOL,\n RUNTIME_ARCHIVE_FORMAT,\n} from './lib/runtime/manifest-types.js';\nexport type {\n RuntimeManifest,\n RuntimeComponent,\n RuntimeLaunch,\n ComponentFile,\n TrustedRuntimeManifest,\n RuntimeHost,\n WorkspaceCompatibility,\n} from './lib/runtime/manifest-types.js';\nexport {\n ensureRuntimeComponents,\n inspectRuntimeComponents,\n pruneRuntimeComponents,\n} from './lib/runtime/manager.js';\nexport type {\n RuntimeManagerOptions,\n RuntimeManagerReport,\n RuntimeComponentStatus,\n} from './lib/runtime/manager.js';\n\nexport { executeRuntimeLaunch } from './lib/runtime/execute.js';\nexport type { RuntimeExecutionOptions } from './lib/runtime/execute.js';\nexport { writeRuntimeComponentArchive } from './lib/runtime/archive-writer.js';\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC9B,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAQhC,kGAAkG;AAClG,MAAM,UAAU,kBAAkB;IAChC,OAAO,iBAAiB,CAAC,kBAAkB,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE;QAC5D,UAAU,EAAE,OAAO,CAAC,QAAQ;QAC5B,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAC,CAAC;AACL,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,uBAAuB,CAAC,QAAiB;IACvD,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,OAAO,+BAA+B,CAAC,kBAAkB,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,6BAA6B,GAC9B,MAAM,iCAAiC,CAAC;AAWzC,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC","sourcesContent":["import {\n inspectCliRuntime,\n runtimePackageRoot,\n assertRuntimeObservationMatches,\n validateRuntimeExpectation,\n} from './lib/runtime/descriptor.js';\nimport type { CliRuntimeDescriptor } from './lib/runtime/types.js';\nexport {\n CLI_RUNTIME_DESCRIPTOR_SCHEMA,\n CLI_RUNTIME_EXPECTATION_SCHEMA,\n RUNTIME_PLATFORMS,\n} from './lib/runtime/types.js';\nexport type {\n CliRuntimeDescriptor,\n CliRuntimeExpectation,\n RuntimeFileFact,\n RuntimePlatform,\n} from './lib/runtime/types.js';\n\n/** Observe this installed package without reading user configuration or accessing the network. */\nexport function describeCliRuntime(): CliRuntimeDescriptor {\n return inspectCliRuntime(runtimePackageRoot(import.meta.url), {\n executable: process.execPath,\n version: process.versions.node,\n platform: process.platform,\n arch: process.arch,\n });\n}\n\n/** The caller supplies independently trusted expected release facts. This grants no account permission. */\nexport function assertCliRuntimeMatches(expected: unknown): CliRuntimeDescriptor {\n validateRuntimeExpectation(expected);\n return assertRuntimeObservationMatches(describeCliRuntime(), expected);\n}\n\nexport {\n parseRuntimeManifest,\n trustRuntimeManifest,\n loadTrustedRuntimeManifest,\n assertWorkspaceCompatibility,\n copyTrustedRuntimeManifestBytes,\n} from './lib/runtime/manifest.js';\nexport {\n RUNTIME_MANIFEST_SCHEMA,\n RUNTIME_BOOTSTRAP_PROTOCOL,\n RUNTIME_ARCHIVE_FORMAT,\n RUNTIME_HOST_CONTEXT_PROTOCOL,\n} from './lib/runtime/manifest-types.js';\nexport type {\n RuntimeManifest,\n RuntimeComponent,\n RuntimeLaunch,\n ComponentFile,\n TrustedRuntimeManifest,\n RuntimeHost,\n RuntimeHostContext,\n WorkspaceCompatibility,\n} from './lib/runtime/manifest-types.js';\nexport {\n ensureRuntimeComponents,\n inspectRuntimeComponents,\n pruneRuntimeComponents,\n} from './lib/runtime/manager.js';\nexport type {\n RuntimeManagerOptions,\n RuntimeManagerReport,\n RuntimeComponentStatus,\n} from './lib/runtime/manager.js';\n\nexport { executeRuntimeLaunch } from './lib/runtime/execute.js';\nexport type { RuntimeExecutionOptions, RuntimeExecutionSpawn } from './lib/runtime/execute.js';\nexport { receiveRuntimeHostContext } from './lib/runtime/host-context.js';\nexport { writeRuntimeComponentArchive } from './lib/runtime/archive-writer.js';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiangong-lca/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Unified TianGong LCA CLI with direct REST adapters and low-entropy command surface.",
5
5
  "repository": {
6
6
  "type": "git",