@tiangong-lca/cli 0.1.0 → 0.1.2

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 (159) hide show
  1. package/README.md +58 -6
  2. package/dist/src/batch.d.ts +6 -0
  3. package/dist/src/batch.js +6 -0
  4. package/dist/src/batch.js.map +1 -0
  5. package/dist/src/cli.d.ts +161 -0
  6. package/dist/src/cli.js +130 -0
  7. package/dist/src/cli.js.map +1 -1
  8. package/dist/src/command-spec.d.ts +90 -0
  9. package/dist/src/command-spec.js +400 -0
  10. package/dist/src/command-spec.js.map +1 -0
  11. package/dist/src/lib/artifacts.d.ts +9 -0
  12. package/dist/src/lib/auth-identity-receipt.d.ts +160 -0
  13. package/dist/src/lib/auth-identity-receipt.js +634 -0
  14. package/dist/src/lib/auth-identity-receipt.js.map +1 -0
  15. package/dist/src/lib/batch/attempt-recovery.d.ts +12 -0
  16. package/dist/src/lib/batch/attempt-recovery.js +183 -0
  17. package/dist/src/lib/batch/attempt-recovery.js.map +1 -0
  18. package/dist/src/lib/batch/canonical-contracts.d.ts +21 -0
  19. package/dist/src/lib/batch/canonical-contracts.js +180 -0
  20. package/dist/src/lib/batch/canonical-contracts.js.map +1 -0
  21. package/dist/src/lib/batch/engine.d.ts +2 -0
  22. package/dist/src/lib/batch/engine.js +294 -0
  23. package/dist/src/lib/batch/engine.js.map +1 -0
  24. package/dist/src/lib/batch/errors.d.ts +51 -0
  25. package/dist/src/lib/batch/errors.js +81 -0
  26. package/dist/src/lib/batch/errors.js.map +1 -0
  27. package/dist/src/lib/batch/item-projection.d.ts +10 -0
  28. package/dist/src/lib/batch/item-projection.js +118 -0
  29. package/dist/src/lib/batch/item-projection.js.map +1 -0
  30. package/dist/src/lib/batch/run-lock.d.ts +4 -0
  31. package/dist/src/lib/batch/run-lock.js +155 -0
  32. package/dist/src/lib/batch/run-lock.js.map +1 -0
  33. package/dist/src/lib/batch/scheduler-runtime.d.ts +29 -0
  34. package/dist/src/lib/batch/scheduler-runtime.js +114 -0
  35. package/dist/src/lib/batch/scheduler-runtime.js.map +1 -0
  36. package/dist/src/lib/batch/types.d.ts +183 -0
  37. package/dist/src/lib/batch/types.js +2 -0
  38. package/dist/src/lib/batch/types.js.map +1 -0
  39. package/dist/src/lib/dataset-author.d.ts +39 -0
  40. package/dist/src/lib/dataset-bilingual.d.ts +165 -0
  41. package/dist/src/lib/dataset-classification.d.ts +279 -0
  42. package/dist/src/lib/dataset-command.d.ts +53 -0
  43. package/dist/src/lib/dataset-contract.d.ts +82 -0
  44. package/dist/src/lib/dataset-curation-queue.d.ts +219 -0
  45. package/dist/src/lib/dataset-evidence-search.d.ts +134 -0
  46. package/dist/src/lib/dataset-import-lca.d.ts +136 -0
  47. package/dist/src/lib/dataset-local.d.ts +23 -0
  48. package/dist/src/lib/dataset-maintenance-alias-request.d.ts +12 -0
  49. package/dist/src/lib/dataset-maintenance-alias-rewrite.d.ts +111 -0
  50. package/dist/src/lib/dataset-maintenance-apply.d.ts +458 -0
  51. package/dist/src/lib/dataset-maintenance-clear-account.d.ts +161 -0
  52. package/dist/src/lib/dataset-maintenance-contract.d.ts +317 -0
  53. package/dist/src/lib/dataset-maintenance-derivatives.d.ts +48 -0
  54. package/dist/src/lib/dataset-maintenance-flow-identity-approval-claim.d.ts +50 -0
  55. package/dist/src/lib/dataset-maintenance-flow-identity-capture.d.ts +110 -0
  56. package/dist/src/lib/dataset-maintenance-flow-identity-command.d.ts +15 -0
  57. package/dist/src/lib/dataset-maintenance-flow-identity-contract.d.ts +387 -0
  58. package/dist/src/lib/dataset-maintenance-flow-identity-execution-contract.d.ts +456 -0
  59. package/dist/src/lib/dataset-maintenance-flow-identity-freeze.d.ts +99 -0
  60. package/dist/src/lib/dataset-maintenance-flow-identity-plan.d.ts +85 -0
  61. package/dist/src/lib/dataset-maintenance-flow-identity-recovery.d.ts +268 -0
  62. package/dist/src/lib/dataset-maintenance-flow-identity-run.d.ts +123 -0
  63. package/dist/src/lib/dataset-maintenance-flow-identity-seal.d.ts +50 -0
  64. package/dist/src/lib/dataset-maintenance-flow-identity-verify.d.ts +85 -0
  65. package/dist/src/lib/dataset-maintenance-flow-identity-wire.d.ts +32 -0
  66. package/dist/src/lib/dataset-maintenance-pagination.d.ts +58 -0
  67. package/dist/src/lib/dataset-maintenance-plan.d.ts +40 -0
  68. package/dist/src/lib/dataset-maintenance-protected-artifacts.d.ts +16 -0
  69. package/dist/src/lib/dataset-maintenance-protected-before.d.ts +71 -0
  70. package/dist/src/lib/dataset-maintenance-protected-contract.d.ts +385 -0
  71. package/dist/src/lib/dataset-maintenance-protected-freeze.d.ts +148 -0
  72. package/dist/src/lib/dataset-maintenance-protected-preparation.d.ts +76 -0
  73. package/dist/src/lib/dataset-maintenance-protected-run.d.ts +252 -0
  74. package/dist/src/lib/dataset-maintenance-protected-seal.d.ts +93 -0
  75. package/dist/src/lib/dataset-maintenance-protected-toolchain.d.ts +31 -0
  76. package/dist/src/lib/dataset-maintenance-protected-verify.d.ts +99 -0
  77. package/dist/src/lib/dataset-maintenance-remote.d.ts +212 -0
  78. package/dist/src/lib/dataset-maintenance-support-validation.d.ts +18 -0
  79. package/dist/src/lib/dataset-maintenance-verify.d.ts +102 -0
  80. package/dist/src/lib/dataset-patch.d.ts +193 -0
  81. package/dist/src/lib/dataset-references-rewrite.d.ts +77 -0
  82. package/dist/src/lib/dataset-remote-refresh.d.ts +64 -0
  83. package/dist/src/lib/dataset-remote-verify.d.ts +168 -0
  84. package/dist/src/lib/dataset-save-draft-run.d.ts +283 -0
  85. package/dist/src/lib/dataset-save-draft-run.js +54 -21
  86. package/dist/src/lib/dataset-save-draft-run.js.map +1 -1
  87. package/dist/src/lib/dataset-source-upload-attachments.d.ts +109 -0
  88. package/dist/src/lib/dataset-validate.d.ts +62 -0
  89. package/dist/src/lib/dotenv.d.ts +6 -0
  90. package/dist/src/lib/env.d.ts +59 -0
  91. package/dist/src/lib/errors.d.ts +18 -0
  92. package/dist/src/lib/flow-build-alias-map.d.ts +80 -0
  93. package/dist/src/lib/flow-fetch-rows.d.ts +70 -0
  94. package/dist/src/lib/flow-get.d.ts +35 -0
  95. package/dist/src/lib/flow-governance.d.ts +22 -0
  96. package/dist/src/lib/flow-list.d.ts +57 -0
  97. package/dist/src/lib/flow-materialize-decisions.d.ts +67 -0
  98. package/dist/src/lib/flow-payload-validation.d.ts +32 -0
  99. package/dist/src/lib/flow-publish-reviewed-data.d.ts +262 -0
  100. package/dist/src/lib/flow-publish-version.d.ts +193 -0
  101. package/dist/src/lib/flow-qa.d.ts +289 -0
  102. package/dist/src/lib/flow-read.d.ts +70 -0
  103. package/dist/src/lib/flow-regen-product.d.ts +431 -0
  104. package/dist/src/lib/flow-remediate.d.ts +133 -0
  105. package/dist/src/lib/http.d.ts +25 -0
  106. package/dist/src/lib/http.js.map +1 -1
  107. package/dist/src/lib/identity-preflight.d.ts +235 -0
  108. package/dist/src/lib/io.d.ts +2 -0
  109. package/dist/src/lib/kb-search.d.ts +23 -0
  110. package/dist/src/lib/lca-release.d.ts +105 -0
  111. package/dist/src/lib/lifecyclemodel-auto-build.d.ts +223 -0
  112. package/dist/src/lib/lifecyclemodel-bundle-save.d.ts +71 -0
  113. package/dist/src/lib/lifecyclemodel-graph.d.ts +91 -0
  114. package/dist/src/lib/lifecyclemodel-orchestrate.d.ts +349 -0
  115. package/dist/src/lib/lifecyclemodel-publish-build.d.ts +77 -0
  116. package/dist/src/lib/lifecyclemodel-publish-resulting-process.d.ts +27 -0
  117. package/dist/src/lib/lifecyclemodel-qa.d.ts +206 -0
  118. package/dist/src/lib/lifecyclemodel-resulting-process.d.ts +204 -0
  119. package/dist/src/lib/lifecyclemodel-save-draft-run.d.ts +96 -0
  120. package/dist/src/lib/lifecyclemodel-validate-build.d.ts +78 -0
  121. package/dist/src/lib/llm.d.ts +51 -0
  122. package/dist/src/lib/package-version.d.ts +3 -0
  123. package/dist/src/lib/process-auto-build.d.ts +168 -0
  124. package/dist/src/lib/process-batch-build.d.ts +97 -0
  125. package/dist/src/lib/process-dedup-review.d.ts +253 -0
  126. package/dist/src/lib/process-flow-build-plan.d.ts +108 -0
  127. package/dist/src/lib/process-get.d.ts +26 -0
  128. package/dist/src/lib/process-list.d.ts +87 -0
  129. package/dist/src/lib/process-payload-validation.d.ts +27 -0
  130. package/dist/src/lib/process-publish-build.d.ts +148 -0
  131. package/dist/src/lib/process-qa.d.ts +243 -0
  132. package/dist/src/lib/process-refresh-references.d.ts +179 -0
  133. package/dist/src/lib/process-required-fields.d.ts +142 -0
  134. package/dist/src/lib/process-resume-build.d.ts +77 -0
  135. package/dist/src/lib/process-save-draft-run.d.ts +72 -0
  136. package/dist/src/lib/process-save-draft.d.ts +53 -0
  137. package/dist/src/lib/process-scope-statistics.d.ts +210 -0
  138. package/dist/src/lib/process-verify-rows.d.ts +71 -0
  139. package/dist/src/lib/publish.d.ts +219 -0
  140. package/dist/src/lib/remote.d.ts +19 -0
  141. package/dist/src/lib/run.d.ts +60 -0
  142. package/dist/src/lib/runtime-rulesets.d.ts +29 -0
  143. package/dist/src/lib/state-lock.d.ts +25 -0
  144. package/dist/src/lib/state-lock.js +23 -1
  145. package/dist/src/lib/state-lock.js.map +1 -1
  146. package/dist/src/lib/supabase-client.d.ts +47 -0
  147. package/dist/src/lib/supabase-data-api-contract.d.ts +304 -0
  148. package/dist/src/lib/supabase-data-api-replay.d.ts +74 -0
  149. package/dist/src/lib/supabase-json-ordered-write.d.ts +65 -0
  150. package/dist/src/lib/supabase-rest.d.ts +26 -0
  151. package/dist/src/lib/supabase-session.d.ts +115 -0
  152. package/dist/src/lib/tidas-languages.d.ts +3 -0
  153. package/dist/src/lib/tidas-sdk-package-validator.d.ts +111 -0
  154. package/dist/src/lib/tidas-sdk-validation.d.ts +42 -0
  155. package/dist/src/lib/unstructured.d.ts +32 -0
  156. package/dist/src/lib/user-api-key.d.ts +16 -0
  157. package/dist/src/lib/validation.d.ts +82 -0
  158. package/dist/src/main.d.ts +4 -0
  159. package/package.json +17 -3
@@ -0,0 +1,90 @@
1
+ export declare const FOUNDRY_COMMAND_SPEC_SCHEMA: 'tiangong-foundry.command-spec.v1';
2
+ export type FoundryArtifactFact = {
3
+ role: string;
4
+ path: string;
5
+ bytes: number;
6
+ sha256: string;
7
+ };
8
+ export type FoundryCommandSpecBinding = {
9
+ artifacts: FoundryArtifactFact[];
10
+ };
11
+ export type FoundryCommandSpec = {
12
+ schema: typeof FOUNDRY_COMMAND_SPEC_SCHEMA;
13
+ executable: string;
14
+ argv: string[];
15
+ display: string;
16
+ binding: FoundryCommandSpecBinding;
17
+ sha256: string;
18
+ };
19
+ export type CreateFoundryCommandSpecOptions = {
20
+ executable: string;
21
+ argv: readonly string[];
22
+ binding?: FoundryCommandSpecBinding;
23
+ };
24
+ export type CreateFileArtifactFactOptions = {
25
+ role: string;
26
+ path: string;
27
+ filePath: string;
28
+ };
29
+ export type FoundryCommandSpecEnvironment = Record<string, string | undefined>;
30
+ export type FoundryCommandSpecSpawnOptions = {
31
+ cwd?: string;
32
+ env?: FoundryCommandSpecEnvironment;
33
+ encoding: 'utf8';
34
+ maxBuffer?: number;
35
+ shell: false;
36
+ windowsHide: true;
37
+ };
38
+ export type FoundryCommandSpecAsyncSpawnOptions = FoundryCommandSpecSpawnOptions & {
39
+ signal: AbortSignal;
40
+ };
41
+ export type FoundryCommandSpecSpawnResult = {
42
+ pid?: number;
43
+ output?: unknown[];
44
+ stdout: string;
45
+ stderr: string;
46
+ status: number | null;
47
+ signal: string | null;
48
+ error?: Error;
49
+ };
50
+ export type ExecuteFoundryCommandSpecSyncOptions = {
51
+ resolveArtifactPath: (artifactPath: string) => string | null;
52
+ cwd?: string;
53
+ env?: FoundryCommandSpecEnvironment;
54
+ maxBuffer?: number;
55
+ spawnImpl?: (executable: string, argv: readonly string[], options: FoundryCommandSpecSpawnOptions) => FoundryCommandSpecSpawnResult;
56
+ };
57
+ export type FoundryCommandSpecClock = {
58
+ now: () => number;
59
+ };
60
+ export type FoundryCommandSpecSleep = (milliseconds: number, signal: AbortSignal) => Promise<void>;
61
+ export type ExecuteFoundryCommandSpecOptions = {
62
+ resolveArtifactPath: (artifactPath: string) => string | null;
63
+ cwd?: string;
64
+ env?: FoundryCommandSpecEnvironment;
65
+ maxBuffer?: number;
66
+ timeoutMs?: number;
67
+ signal?: AbortSignal;
68
+ clock?: FoundryCommandSpecClock;
69
+ sleep?: FoundryCommandSpecSleep;
70
+ spawnImpl?: (executable: string, argv: readonly string[], options: FoundryCommandSpecAsyncSpawnOptions) => Promise<FoundryCommandSpecSpawnResult>;
71
+ };
72
+ export declare class FoundryCommandSpecTimeoutError extends Error {
73
+ readonly timeoutMs: number;
74
+ readonly startedAtMs: number;
75
+ readonly deadlineMs: number;
76
+ constructor(timeoutMs: number, startedAtMs: number);
77
+ }
78
+ export declare class FoundryCommandSpecAbortError extends Error {
79
+ readonly reason: unknown;
80
+ constructor(reason: unknown);
81
+ }
82
+ export declare function renderFoundryCommandDisplay(executable: string, argv: readonly string[]): string;
83
+ export declare function parseFoundryCommandSpec(value: unknown): FoundryCommandSpec;
84
+ export declare function createFoundryCommandSpec(options: CreateFoundryCommandSpecOptions): FoundryCommandSpec;
85
+ export declare function createFileArtifactFact(options: CreateFileArtifactFactOptions): FoundryArtifactFact;
86
+ export declare function commandSpecOptionValue(value: unknown, optionName: string): string | null;
87
+ export declare function assertFoundryCommandSpecArtifactsCurrent(value: unknown, resolveArtifactPath: (artifactPath: string) => string | null): FoundryCommandSpec;
88
+ export declare function assertFoundryCommandSpecBindsArtifact(value: unknown, requiredArtifact: FoundryArtifactFact): FoundryCommandSpec;
89
+ export declare function executeFoundryCommandSpecSync(value: unknown, options: ExecuteFoundryCommandSpecSyncOptions): FoundryCommandSpecSpawnResult;
90
+ export declare function executeFoundryCommandSpec(value: unknown, options: ExecuteFoundryCommandSpecOptions): Promise<FoundryCommandSpecSpawnResult>;
@@ -0,0 +1,400 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import fs from 'node:fs';
4
+ export const FOUNDRY_COMMAND_SPEC_SCHEMA = 'tiangong-foundry.command-spec.v1';
5
+ const SHA256_PATTERN = /^[a-f0-9]{64}$/u;
6
+ const VALUE_FLAGS = new Set([
7
+ '--input',
8
+ '--input-file',
9
+ '--out-dir',
10
+ '--root-policy',
11
+ '--state-code',
12
+ '--target-user-id',
13
+ '--type',
14
+ ]);
15
+ const BOOLEAN_FLAGS = new Set(['--commit', '--compare-root-payload', '--json']);
16
+ const UNIQUE_FLAGS = new Set([...VALUE_FLAGS, ...BOOLEAN_FLAGS]);
17
+ const INPUT_FLAG_ALIASES = new Set(['--input', '--input-file']);
18
+ const DEFAULT_MAX_BUFFER = 1024 * 1024;
19
+ const MAX_NODE_TIMER_DELAY_MS = 2_147_483_647;
20
+ const EXECUTION_COMPLETED = Symbol('command-spec-execution-completed');
21
+ export class FoundryCommandSpecTimeoutError extends Error {
22
+ timeoutMs;
23
+ startedAtMs;
24
+ deadlineMs;
25
+ constructor(timeoutMs, startedAtMs) {
26
+ super(`CommandSpec execution exceeded its ${timeoutMs} ms timeout.`);
27
+ this.name = 'FoundryCommandSpecTimeoutError';
28
+ this.timeoutMs = timeoutMs;
29
+ this.startedAtMs = startedAtMs;
30
+ this.deadlineMs = startedAtMs + timeoutMs;
31
+ }
32
+ }
33
+ export class FoundryCommandSpecAbortError extends Error {
34
+ reason;
35
+ constructor(reason) {
36
+ super('CommandSpec execution was aborted.', { cause: reason });
37
+ this.name = 'FoundryCommandSpecAbortError';
38
+ this.reason = reason;
39
+ }
40
+ }
41
+ function isRecord(value) {
42
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
43
+ }
44
+ function hasExactKeys(value, expectedKeys) {
45
+ const actual = Object.keys(value).sort();
46
+ const expected = [...expectedKeys].sort();
47
+ return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
48
+ }
49
+ function canonicalJsonValue(value) {
50
+ if (Array.isArray(value))
51
+ return value.map(canonicalJsonValue);
52
+ if (!isRecord(value))
53
+ return value;
54
+ return Object.fromEntries(Object.keys(value)
55
+ .sort()
56
+ .map((key) => [key, canonicalJsonValue(value[key])]));
57
+ }
58
+ function sha256Buffer(value) {
59
+ return createHash('sha256').update(value).digest('hex');
60
+ }
61
+ function commandSpecAuthority(value) {
62
+ return {
63
+ schema: value.schema,
64
+ executable: value.executable,
65
+ argv: value.argv,
66
+ binding: value.binding,
67
+ };
68
+ }
69
+ function commandSpecSha256(value) {
70
+ return sha256Buffer(JSON.stringify(canonicalJsonValue(commandSpecAuthority(value))));
71
+ }
72
+ function commandToken(value, label) {
73
+ if (typeof value !== 'string' || value.length === 0 || /[\0\r\n]/u.test(value)) {
74
+ throw new Error(`${label} must be a non-empty single-line string without NUL bytes.`);
75
+ }
76
+ return value;
77
+ }
78
+ function renderDisplayToken(value) {
79
+ if (/^[A-Za-z0-9_./:@%+=,-]+$/u.test(value))
80
+ return value;
81
+ return `'${value.replace(/'/gu, `'\\''`)}'`;
82
+ }
83
+ export function renderFoundryCommandDisplay(executable, argv) {
84
+ return [executable, ...argv].map(renderDisplayToken).join(' ');
85
+ }
86
+ function parseArtifactFact(value, index) {
87
+ if (!isRecord(value) ||
88
+ !hasExactKeys(value, ['bytes', 'path', 'role', 'sha256']) ||
89
+ !Number.isSafeInteger(value.bytes) ||
90
+ Number(value.bytes) < 0 ||
91
+ typeof value.sha256 !== 'string' ||
92
+ !SHA256_PATTERN.test(value.sha256)) {
93
+ throw new Error(`CommandSpec artifact ${index} failed exact bytes/SHA-256 validation.`);
94
+ }
95
+ return {
96
+ role: commandToken(value.role, `CommandSpec artifact ${index} role`),
97
+ path: commandToken(value.path, `CommandSpec artifact ${index} path`),
98
+ bytes: Number(value.bytes),
99
+ sha256: value.sha256,
100
+ };
101
+ }
102
+ function parseBinding(value) {
103
+ if (!isRecord(value) || !hasExactKeys(value, ['artifacts']) || !Array.isArray(value.artifacts)) {
104
+ throw new Error('CommandSpec binding must contain the exact artifacts key.');
105
+ }
106
+ const artifacts = value.artifacts.map(parseArtifactFact);
107
+ const roles = artifacts.map((artifact) => artifact.role);
108
+ if (new Set(roles).size !== roles.length) {
109
+ throw new Error('CommandSpec artifact roles must be unique.');
110
+ }
111
+ return { artifacts };
112
+ }
113
+ function criticalFlagName(token) {
114
+ if (UNIQUE_FLAGS.has(token))
115
+ return token;
116
+ const equals = token.indexOf('=');
117
+ if (equals <= 0)
118
+ return null;
119
+ const name = token.slice(0, equals);
120
+ return UNIQUE_FLAGS.has(name) ? name : null;
121
+ }
122
+ function validateCriticalFlags(argv) {
123
+ const counts = new Map();
124
+ for (let index = 0; index < argv.length; index += 1) {
125
+ const token = argv[index];
126
+ const name = criticalFlagName(token);
127
+ if (!name)
128
+ continue;
129
+ counts.set(name, (counts.get(name) ?? 0) + 1);
130
+ if (token.startsWith(`${name}=`)) {
131
+ const inlineValue = token.slice(name.length + 1);
132
+ if (VALUE_FLAGS.has(name) && inlineValue.length === 0) {
133
+ throw new Error(`CommandSpec critical flag ${name} requires one value.`);
134
+ }
135
+ if (BOOLEAN_FLAGS.has(name)) {
136
+ throw new Error(`CommandSpec boolean flag ${name} must not use an inline value.`);
137
+ }
138
+ }
139
+ if (VALUE_FLAGS.has(name) && token === name) {
140
+ const value = argv[index + 1];
141
+ if (!value || value.startsWith('--')) {
142
+ throw new Error(`CommandSpec critical flag ${name} requires one value.`);
143
+ }
144
+ }
145
+ }
146
+ for (const [name, count] of counts) {
147
+ if (count > 1)
148
+ throw new Error(`CommandSpec critical flag ${name} may appear only once.`);
149
+ }
150
+ const inputAliasCount = [...INPUT_FLAG_ALIASES].reduce((count, name) => count + (counts.get(name) ?? 0), 0);
151
+ if (inputAliasCount > 1) {
152
+ throw new Error('CommandSpec input aliases --input and --input-file are mutually exclusive.');
153
+ }
154
+ }
155
+ export function parseFoundryCommandSpec(value) {
156
+ if (!isRecord(value) ||
157
+ !hasExactKeys(value, ['argv', 'binding', 'display', 'executable', 'schema', 'sha256'])) {
158
+ throw new Error('CommandSpec must contain exact keys with no unexpected fields.');
159
+ }
160
+ if (value.schema !== FOUNDRY_COMMAND_SPEC_SCHEMA) {
161
+ throw new Error(`CommandSpec schema must be ${FOUNDRY_COMMAND_SPEC_SCHEMA}.`);
162
+ }
163
+ const executable = commandToken(value.executable, 'CommandSpec executable');
164
+ if (!Array.isArray(value.argv))
165
+ throw new Error('CommandSpec argv must be an array.');
166
+ const argv = value.argv.map((entry, index) => commandToken(entry, `CommandSpec argv[${index}]`));
167
+ const display = commandToken(value.display, 'CommandSpec display');
168
+ const binding = parseBinding(value.binding);
169
+ validateCriticalFlags(argv);
170
+ if (typeof value.sha256 !== 'string' || !SHA256_PATTERN.test(value.sha256)) {
171
+ throw new Error('CommandSpec SHA-256 is missing or malformed.');
172
+ }
173
+ const expectedSha256 = commandSpecSha256({
174
+ schema: value.schema,
175
+ executable,
176
+ argv,
177
+ binding,
178
+ });
179
+ if (value.sha256 !== expectedSha256) {
180
+ throw new Error('CommandSpec SHA-256 does not match executable, argv, and binding.');
181
+ }
182
+ return {
183
+ schema: FOUNDRY_COMMAND_SPEC_SCHEMA,
184
+ executable,
185
+ argv,
186
+ display,
187
+ binding,
188
+ sha256: value.sha256,
189
+ };
190
+ }
191
+ export function createFoundryCommandSpec(options) {
192
+ const executable = commandToken(options.executable, 'CommandSpec executable');
193
+ const argv = options.argv.map((entry, index) => commandToken(entry, `CommandSpec argv[${index}]`));
194
+ const binding = parseBinding(options.binding ?? { artifacts: [] });
195
+ validateCriticalFlags(argv);
196
+ const authority = {
197
+ schema: FOUNDRY_COMMAND_SPEC_SCHEMA,
198
+ executable,
199
+ argv,
200
+ binding,
201
+ };
202
+ return parseFoundryCommandSpec({
203
+ ...authority,
204
+ display: renderFoundryCommandDisplay(executable, argv),
205
+ sha256: commandSpecSha256(authority),
206
+ });
207
+ }
208
+ export function createFileArtifactFact(options) {
209
+ const role = commandToken(options.role, 'Artifact role');
210
+ const artifactPath = commandToken(options.path, 'Artifact path');
211
+ const filePath = commandToken(options.filePath, 'Artifact file path');
212
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
213
+ throw new Error(`CommandSpec artifact is not a readable file: ${artifactPath}`);
214
+ }
215
+ const bytes = fs.readFileSync(filePath);
216
+ return {
217
+ role,
218
+ path: artifactPath,
219
+ bytes: bytes.byteLength,
220
+ sha256: sha256Buffer(bytes),
221
+ };
222
+ }
223
+ export function commandSpecOptionValue(value, optionName) {
224
+ const spec = parseFoundryCommandSpec(value);
225
+ for (let index = 0; index < spec.argv.length; index += 1) {
226
+ const token = spec.argv[index];
227
+ if (token === optionName)
228
+ return spec.argv[index + 1] ?? null;
229
+ if (token.startsWith(`${optionName}=`))
230
+ return token.slice(optionName.length + 1) || null;
231
+ }
232
+ return null;
233
+ }
234
+ export function assertFoundryCommandSpecArtifactsCurrent(value, resolveArtifactPath) {
235
+ const spec = parseFoundryCommandSpec(value);
236
+ for (const artifact of spec.binding.artifacts) {
237
+ const filePath = resolveArtifactPath(artifact.path);
238
+ if (!filePath || !fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
239
+ throw new Error(`CommandSpec artifact drift: ${artifact.role} is missing.`);
240
+ }
241
+ const bytes = fs.readFileSync(filePath);
242
+ const sha256 = sha256Buffer(bytes);
243
+ if (bytes.byteLength !== artifact.bytes || sha256 !== artifact.sha256) {
244
+ throw new Error(`CommandSpec artifact drift: ${artifact.role} bytes/SHA-256 changed.`);
245
+ }
246
+ }
247
+ return spec;
248
+ }
249
+ export function assertFoundryCommandSpecBindsArtifact(value, requiredArtifact) {
250
+ const spec = parseFoundryCommandSpec(value);
251
+ const required = parseArtifactFact(requiredArtifact, 0);
252
+ const matched = spec.binding.artifacts.some((artifact) => artifact.role === required.role &&
253
+ artifact.path === required.path &&
254
+ artifact.bytes === required.bytes &&
255
+ artifact.sha256 === required.sha256);
256
+ if (!matched) {
257
+ throw new Error(`CommandSpec required artifact binding does not match: ${required.role}.`);
258
+ }
259
+ return spec;
260
+ }
261
+ export function executeFoundryCommandSpecSync(value, options) {
262
+ const spec = assertFoundryCommandSpecArtifactsCurrent(value, options.resolveArtifactPath);
263
+ const spawnOptions = {
264
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
265
+ ...(options.env === undefined ? {} : { env: options.env }),
266
+ ...(options.maxBuffer === undefined ? {} : { maxBuffer: options.maxBuffer }),
267
+ encoding: 'utf8',
268
+ shell: false,
269
+ windowsHide: true,
270
+ };
271
+ const spawnImpl = options.spawnImpl ??
272
+ ((executable, argv, childOptions) => spawnSync(executable, [...argv], childOptions));
273
+ return spawnImpl(spec.executable, spec.argv, spawnOptions);
274
+ }
275
+ export async function executeFoundryCommandSpec(value, options) {
276
+ const spec = assertFoundryCommandSpecArtifactsCurrent(value, options.resolveArtifactPath);
277
+ validateAsyncExecutionOptions(options);
278
+ const clock = options.clock ?? { now: Date.now };
279
+ const sleep = options.sleep ?? defaultSleep;
280
+ if (options.signal?.aborted) {
281
+ throw new FoundryCommandSpecAbortError(options.signal.reason);
282
+ }
283
+ const controller = new AbortController();
284
+ const startedAtMs = clock.now();
285
+ if (!Number.isFinite(startedAtMs)) {
286
+ throw new Error('CommandSpec clock must return a finite millisecond value.');
287
+ }
288
+ let settled = false;
289
+ const forwardAbort = () => controller.abort(options.signal?.reason);
290
+ options.signal?.addEventListener('abort', forwardAbort, { once: true });
291
+ try {
292
+ const spawnOptions = {
293
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
294
+ ...(options.env === undefined ? {} : { env: options.env }),
295
+ ...(options.maxBuffer === undefined ? {} : { maxBuffer: options.maxBuffer }),
296
+ encoding: 'utf8',
297
+ shell: false,
298
+ windowsHide: true,
299
+ signal: controller.signal,
300
+ };
301
+ const spawnImpl = options.spawnImpl ?? spawnCommandAsync;
302
+ const spawnPromise = spawnImpl(spec.executable, spec.argv, spawnOptions);
303
+ const abortPromise = new Promise((_resolve, reject) => {
304
+ const rejectAbort = () => {
305
+ if (settled || controller.signal.reason === EXECUTION_COMPLETED)
306
+ return;
307
+ const reason = controller.signal.reason;
308
+ reject(reason instanceof FoundryCommandSpecTimeoutError
309
+ ? reason
310
+ : new FoundryCommandSpecAbortError(reason));
311
+ };
312
+ controller.signal.addEventListener('abort', rejectAbort, { once: true });
313
+ });
314
+ const timeoutPromise = options.timeoutMs === undefined
315
+ ? new Promise(() => undefined)
316
+ : sleep(options.timeoutMs, controller.signal).then(() => {
317
+ const error = new FoundryCommandSpecTimeoutError(options.timeoutMs, startedAtMs);
318
+ controller.abort(error);
319
+ throw error;
320
+ });
321
+ const result = await Promise.race([spawnPromise, abortPromise, timeoutPromise]);
322
+ settled = true;
323
+ controller.abort(EXECUTION_COMPLETED);
324
+ return result;
325
+ }
326
+ finally {
327
+ settled = true;
328
+ options.signal?.removeEventListener('abort', forwardAbort);
329
+ }
330
+ }
331
+ function validateAsyncExecutionOptions(options) {
332
+ if (options.timeoutMs !== undefined &&
333
+ (!Number.isSafeInteger(options.timeoutMs) ||
334
+ options.timeoutMs <= 0 ||
335
+ options.timeoutMs > MAX_NODE_TIMER_DELAY_MS)) {
336
+ throw new Error(`CommandSpec timeoutMs must be a positive safe integer no greater than the maximum supported timer delay (${MAX_NODE_TIMER_DELAY_MS} ms).`);
337
+ }
338
+ if (options.maxBuffer !== undefined &&
339
+ (!Number.isSafeInteger(options.maxBuffer) || options.maxBuffer <= 0)) {
340
+ throw new Error('CommandSpec maxBuffer must be a positive safe integer.');
341
+ }
342
+ }
343
+ function defaultSleep(milliseconds, signal) {
344
+ return new Promise((resolve, reject) => {
345
+ const timer = setTimeout(resolve, milliseconds);
346
+ timer.unref();
347
+ signal.addEventListener('abort', () => {
348
+ clearTimeout(timer);
349
+ reject(signal.reason);
350
+ }, { once: true });
351
+ });
352
+ }
353
+ function spawnCommandAsync(executable, argv, options) {
354
+ return new Promise((resolve) => {
355
+ const child = spawn(executable, [...argv], {
356
+ cwd: options.cwd,
357
+ env: options.env,
358
+ shell: false,
359
+ windowsHide: true,
360
+ signal: options.signal,
361
+ stdio: ['ignore', 'pipe', 'pipe'],
362
+ });
363
+ const stdout = [];
364
+ const stderr = [];
365
+ const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;
366
+ let capturedBytes = 0;
367
+ let captureError;
368
+ let spawnError;
369
+ const capture = (target, bytes) => {
370
+ capturedBytes += bytes.byteLength;
371
+ if (capturedBytes > maxBuffer) {
372
+ captureError = new RangeError(`CommandSpec output exceeded maxBuffer (${maxBuffer} bytes).`);
373
+ child.kill();
374
+ return;
375
+ }
376
+ target.push(bytes);
377
+ };
378
+ child.stdout.on('data', (chunk) => capture(stdout, chunk));
379
+ child.stderr.on('data', (chunk) => capture(stderr, chunk));
380
+ child.once('error', (error) => {
381
+ spawnError = error;
382
+ });
383
+ child.once('close', (status, signal) => {
384
+ const stdoutText = Buffer.concat(stdout).toString('utf8');
385
+ const stderrText = Buffer.concat(stderr).toString('utf8');
386
+ resolve({
387
+ ...(child.pid === undefined ? {} : { pid: child.pid }),
388
+ output: [null, stdoutText, stderrText],
389
+ stdout: stdoutText,
390
+ stderr: stderrText,
391
+ status,
392
+ signal,
393
+ ...((captureError ?? spawnError) === undefined
394
+ ? {}
395
+ : { error: (captureError ?? spawnError) }),
396
+ });
397
+ });
398
+ });
399
+ }
400
+ //# sourceMappingURL=command-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-spec.js","sourceRoot":"","sources":["../../src/command-spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, spawnSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\n\nexport const FOUNDRY_COMMAND_SPEC_SCHEMA = 'tiangong-foundry.command-spec.v1' as const;\n\nconst SHA256_PATTERN = /^[a-f0-9]{64}$/u;\nconst VALUE_FLAGS = new Set([\n '--input',\n '--input-file',\n '--out-dir',\n '--root-policy',\n '--state-code',\n '--target-user-id',\n '--type',\n]);\nconst BOOLEAN_FLAGS = new Set(['--commit', '--compare-root-payload', '--json']);\nconst UNIQUE_FLAGS = new Set([...VALUE_FLAGS, ...BOOLEAN_FLAGS]);\nconst INPUT_FLAG_ALIASES = new Set(['--input', '--input-file']);\nconst DEFAULT_MAX_BUFFER = 1024 * 1024;\nconst MAX_NODE_TIMER_DELAY_MS = 2_147_483_647;\nconst EXECUTION_COMPLETED = Symbol('command-spec-execution-completed');\n\ntype JsonRecord = Record<string, unknown>;\n\nexport type FoundryArtifactFact = {\n role: string;\n path: string;\n bytes: number;\n sha256: string;\n};\n\nexport type FoundryCommandSpecBinding = {\n artifacts: FoundryArtifactFact[];\n};\n\nexport type FoundryCommandSpec = {\n schema: typeof FOUNDRY_COMMAND_SPEC_SCHEMA;\n executable: string;\n argv: string[];\n display: string;\n binding: FoundryCommandSpecBinding;\n sha256: string;\n};\n\nexport type CreateFoundryCommandSpecOptions = {\n executable: string;\n argv: readonly string[];\n binding?: FoundryCommandSpecBinding;\n};\n\nexport type CreateFileArtifactFactOptions = {\n role: string;\n path: string;\n filePath: string;\n};\n\nexport type FoundryCommandSpecEnvironment = Record<string, string | undefined>;\n\nexport type FoundryCommandSpecSpawnOptions = {\n cwd?: string;\n env?: FoundryCommandSpecEnvironment;\n encoding: 'utf8';\n maxBuffer?: number;\n shell: false;\n windowsHide: true;\n};\n\nexport type FoundryCommandSpecAsyncSpawnOptions = FoundryCommandSpecSpawnOptions & {\n signal: AbortSignal;\n};\n\nexport type FoundryCommandSpecSpawnResult = {\n pid?: number;\n output?: unknown[];\n stdout: string;\n stderr: string;\n status: number | null;\n signal: string | null;\n error?: Error;\n};\n\nexport type ExecuteFoundryCommandSpecSyncOptions = {\n resolveArtifactPath: (artifactPath: string) => string | null;\n cwd?: string;\n env?: FoundryCommandSpecEnvironment;\n maxBuffer?: number;\n spawnImpl?: (\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecSpawnOptions,\n ) => FoundryCommandSpecSpawnResult;\n};\n\nexport type FoundryCommandSpecClock = {\n now: () => number;\n};\n\nexport type FoundryCommandSpecSleep = (milliseconds: number, signal: AbortSignal) => Promise<void>;\n\nexport type ExecuteFoundryCommandSpecOptions = {\n resolveArtifactPath: (artifactPath: string) => string | null;\n cwd?: string;\n env?: FoundryCommandSpecEnvironment;\n maxBuffer?: number;\n timeoutMs?: number;\n signal?: AbortSignal;\n clock?: FoundryCommandSpecClock;\n sleep?: FoundryCommandSpecSleep;\n spawnImpl?: (\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecAsyncSpawnOptions,\n ) => Promise<FoundryCommandSpecSpawnResult>;\n};\n\nexport class FoundryCommandSpecTimeoutError extends Error {\n readonly timeoutMs: number;\n readonly startedAtMs: number;\n readonly deadlineMs: number;\n\n constructor(timeoutMs: number, startedAtMs: number) {\n super(`CommandSpec execution exceeded its ${timeoutMs} ms timeout.`);\n this.name = 'FoundryCommandSpecTimeoutError';\n this.timeoutMs = timeoutMs;\n this.startedAtMs = startedAtMs;\n this.deadlineMs = startedAtMs + timeoutMs;\n }\n}\n\nexport class FoundryCommandSpecAbortError extends Error {\n readonly reason: unknown;\n\n constructor(reason: unknown) {\n super('CommandSpec execution was aborted.', { cause: reason });\n this.name = 'FoundryCommandSpecAbortError';\n this.reason = reason;\n }\n}\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeys(value: JsonRecord, expectedKeys: readonly string[]): boolean {\n const actual = Object.keys(value).sort();\n const expected = [...expectedKeys].sort();\n return actual.length === expected.length && actual.every((key, index) => key === expected[index]);\n}\n\nfunction canonicalJsonValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalJsonValue);\n if (!isRecord(value)) return value;\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, canonicalJsonValue(value[key])]),\n );\n}\n\nfunction sha256Buffer(value: string | Buffer): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction commandSpecAuthority(value: {\n schema: unknown;\n executable: unknown;\n argv: unknown;\n binding: unknown;\n}): JsonRecord {\n return {\n schema: value.schema,\n executable: value.executable,\n argv: value.argv,\n binding: value.binding,\n };\n}\n\nfunction commandSpecSha256(value: {\n schema: unknown;\n executable: unknown;\n argv: unknown;\n binding: unknown;\n}): string {\n return sha256Buffer(JSON.stringify(canonicalJsonValue(commandSpecAuthority(value))));\n}\n\nfunction commandToken(value: unknown, label: string): string {\n if (typeof value !== 'string' || value.length === 0 || /[\\0\\r\\n]/u.test(value)) {\n throw new Error(`${label} must be a non-empty single-line string without NUL bytes.`);\n }\n return value;\n}\n\nfunction renderDisplayToken(value: string): string {\n if (/^[A-Za-z0-9_./:@%+=,-]+$/u.test(value)) return value;\n return `'${value.replace(/'/gu, `'\\\\''`)}'`;\n}\n\nexport function renderFoundryCommandDisplay(executable: string, argv: readonly string[]): string {\n return [executable, ...argv].map(renderDisplayToken).join(' ');\n}\n\nfunction parseArtifactFact(value: unknown, index: number): FoundryArtifactFact {\n if (\n !isRecord(value) ||\n !hasExactKeys(value, ['bytes', 'path', 'role', 'sha256']) ||\n !Number.isSafeInteger(value.bytes) ||\n Number(value.bytes) < 0 ||\n typeof value.sha256 !== 'string' ||\n !SHA256_PATTERN.test(value.sha256)\n ) {\n throw new Error(`CommandSpec artifact ${index} failed exact bytes/SHA-256 validation.`);\n }\n return {\n role: commandToken(value.role, `CommandSpec artifact ${index} role`),\n path: commandToken(value.path, `CommandSpec artifact ${index} path`),\n bytes: Number(value.bytes),\n sha256: value.sha256,\n };\n}\n\nfunction parseBinding(value: unknown): FoundryCommandSpecBinding {\n if (!isRecord(value) || !hasExactKeys(value, ['artifacts']) || !Array.isArray(value.artifacts)) {\n throw new Error('CommandSpec binding must contain the exact artifacts key.');\n }\n const artifacts = value.artifacts.map(parseArtifactFact);\n const roles = artifacts.map((artifact) => artifact.role);\n if (new Set(roles).size !== roles.length) {\n throw new Error('CommandSpec artifact roles must be unique.');\n }\n return { artifacts };\n}\n\nfunction criticalFlagName(token: string): string | null {\n if (UNIQUE_FLAGS.has(token)) return token;\n const equals = token.indexOf('=');\n if (equals <= 0) return null;\n const name = token.slice(0, equals);\n return UNIQUE_FLAGS.has(name) ? name : null;\n}\n\nfunction validateCriticalFlags(argv: readonly string[]): void {\n const counts = new Map<string, number>();\n for (let index = 0; index < argv.length; index += 1) {\n const token = argv[index];\n const name = criticalFlagName(token);\n if (!name) continue;\n counts.set(name, (counts.get(name) ?? 0) + 1);\n if (token.startsWith(`${name}=`)) {\n const inlineValue = token.slice(name.length + 1);\n if (VALUE_FLAGS.has(name) && inlineValue.length === 0) {\n throw new Error(`CommandSpec critical flag ${name} requires one value.`);\n }\n if (BOOLEAN_FLAGS.has(name)) {\n throw new Error(`CommandSpec boolean flag ${name} must not use an inline value.`);\n }\n }\n if (VALUE_FLAGS.has(name) && token === name) {\n const value = argv[index + 1];\n if (!value || value.startsWith('--')) {\n throw new Error(`CommandSpec critical flag ${name} requires one value.`);\n }\n }\n }\n for (const [name, count] of counts) {\n if (count > 1) throw new Error(`CommandSpec critical flag ${name} may appear only once.`);\n }\n const inputAliasCount = [...INPUT_FLAG_ALIASES].reduce(\n (count, name) => count + (counts.get(name) ?? 0),\n 0,\n );\n if (inputAliasCount > 1) {\n throw new Error('CommandSpec input aliases --input and --input-file are mutually exclusive.');\n }\n}\n\nexport function parseFoundryCommandSpec(value: unknown): FoundryCommandSpec {\n if (\n !isRecord(value) ||\n !hasExactKeys(value, ['argv', 'binding', 'display', 'executable', 'schema', 'sha256'])\n ) {\n throw new Error('CommandSpec must contain exact keys with no unexpected fields.');\n }\n if (value.schema !== FOUNDRY_COMMAND_SPEC_SCHEMA) {\n throw new Error(`CommandSpec schema must be ${FOUNDRY_COMMAND_SPEC_SCHEMA}.`);\n }\n const executable = commandToken(value.executable, 'CommandSpec executable');\n if (!Array.isArray(value.argv)) throw new Error('CommandSpec argv must be an array.');\n const argv = value.argv.map((entry, index) => commandToken(entry, `CommandSpec argv[${index}]`));\n const display = commandToken(value.display, 'CommandSpec display');\n const binding = parseBinding(value.binding);\n validateCriticalFlags(argv);\n if (typeof value.sha256 !== 'string' || !SHA256_PATTERN.test(value.sha256)) {\n throw new Error('CommandSpec SHA-256 is missing or malformed.');\n }\n const expectedSha256 = commandSpecSha256({\n schema: value.schema,\n executable,\n argv,\n binding,\n });\n if (value.sha256 !== expectedSha256) {\n throw new Error('CommandSpec SHA-256 does not match executable, argv, and binding.');\n }\n return {\n schema: FOUNDRY_COMMAND_SPEC_SCHEMA,\n executable,\n argv,\n display,\n binding,\n sha256: value.sha256,\n };\n}\n\nexport function createFoundryCommandSpec(\n options: CreateFoundryCommandSpecOptions,\n): FoundryCommandSpec {\n const executable = commandToken(options.executable, 'CommandSpec executable');\n const argv = options.argv.map((entry, index) =>\n commandToken(entry, `CommandSpec argv[${index}]`),\n );\n const binding = parseBinding(options.binding ?? { artifacts: [] });\n validateCriticalFlags(argv);\n const authority = {\n schema: FOUNDRY_COMMAND_SPEC_SCHEMA,\n executable,\n argv,\n binding,\n };\n return parseFoundryCommandSpec({\n ...authority,\n display: renderFoundryCommandDisplay(executable, argv),\n sha256: commandSpecSha256(authority),\n });\n}\n\nexport function createFileArtifactFact(\n options: CreateFileArtifactFactOptions,\n): FoundryArtifactFact {\n const role = commandToken(options.role, 'Artifact role');\n const artifactPath = commandToken(options.path, 'Artifact path');\n const filePath = commandToken(options.filePath, 'Artifact file path');\n if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {\n throw new Error(`CommandSpec artifact is not a readable file: ${artifactPath}`);\n }\n const bytes = fs.readFileSync(filePath);\n return {\n role,\n path: artifactPath,\n bytes: bytes.byteLength,\n sha256: sha256Buffer(bytes),\n };\n}\n\nexport function commandSpecOptionValue(value: unknown, optionName: string): string | null {\n const spec = parseFoundryCommandSpec(value);\n for (let index = 0; index < spec.argv.length; index += 1) {\n const token = spec.argv[index];\n if (token === optionName) return spec.argv[index + 1] ?? null;\n if (token.startsWith(`${optionName}=`)) return token.slice(optionName.length + 1) || null;\n }\n return null;\n}\n\nexport function assertFoundryCommandSpecArtifactsCurrent(\n value: unknown,\n resolveArtifactPath: (artifactPath: string) => string | null,\n): FoundryCommandSpec {\n const spec = parseFoundryCommandSpec(value);\n for (const artifact of spec.binding.artifacts) {\n const filePath = resolveArtifactPath(artifact.path);\n if (!filePath || !fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {\n throw new Error(`CommandSpec artifact drift: ${artifact.role} is missing.`);\n }\n const bytes = fs.readFileSync(filePath);\n const sha256 = sha256Buffer(bytes);\n if (bytes.byteLength !== artifact.bytes || sha256 !== artifact.sha256) {\n throw new Error(`CommandSpec artifact drift: ${artifact.role} bytes/SHA-256 changed.`);\n }\n }\n return spec;\n}\n\nexport function assertFoundryCommandSpecBindsArtifact(\n value: unknown,\n requiredArtifact: FoundryArtifactFact,\n): FoundryCommandSpec {\n const spec = parseFoundryCommandSpec(value);\n const required = parseArtifactFact(requiredArtifact, 0);\n const matched = spec.binding.artifacts.some(\n (artifact) =>\n artifact.role === required.role &&\n artifact.path === required.path &&\n artifact.bytes === required.bytes &&\n artifact.sha256 === required.sha256,\n );\n if (!matched) {\n throw new Error(`CommandSpec required artifact binding does not match: ${required.role}.`);\n }\n return spec;\n}\n\nexport function executeFoundryCommandSpecSync(\n value: unknown,\n options: ExecuteFoundryCommandSpecSyncOptions,\n): FoundryCommandSpecSpawnResult {\n const spec = assertFoundryCommandSpecArtifactsCurrent(value, options.resolveArtifactPath);\n const spawnOptions: FoundryCommandSpecSpawnOptions = {\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.maxBuffer === undefined ? {} : { maxBuffer: options.maxBuffer }),\n encoding: 'utf8',\n shell: false,\n windowsHide: true,\n };\n const spawnImpl =\n options.spawnImpl ??\n ((executable: string, argv: readonly string[], childOptions: FoundryCommandSpecSpawnOptions) =>\n spawnSync(executable, [...argv], childOptions) as FoundryCommandSpecSpawnResult);\n return spawnImpl(spec.executable, spec.argv, spawnOptions);\n}\n\nexport async function executeFoundryCommandSpec(\n value: unknown,\n options: ExecuteFoundryCommandSpecOptions,\n): Promise<FoundryCommandSpecSpawnResult> {\n const spec = assertFoundryCommandSpecArtifactsCurrent(value, options.resolveArtifactPath);\n validateAsyncExecutionOptions(options);\n const clock = options.clock ?? { now: Date.now };\n const sleep = options.sleep ?? defaultSleep;\n if (options.signal?.aborted) {\n throw new FoundryCommandSpecAbortError(options.signal.reason);\n }\n const controller = new AbortController();\n const startedAtMs = clock.now();\n if (!Number.isFinite(startedAtMs)) {\n throw new Error('CommandSpec clock must return a finite millisecond value.');\n }\n let settled = false;\n\n const forwardAbort = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', forwardAbort, { once: true });\n\n try {\n const spawnOptions: FoundryCommandSpecAsyncSpawnOptions = {\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.env === undefined ? {} : { env: options.env }),\n ...(options.maxBuffer === undefined ? {} : { maxBuffer: options.maxBuffer }),\n encoding: 'utf8',\n shell: false,\n windowsHide: true,\n signal: controller.signal,\n };\n const spawnImpl = options.spawnImpl ?? spawnCommandAsync;\n const spawnPromise = spawnImpl(spec.executable, spec.argv, spawnOptions);\n const abortPromise = new Promise<never>((_resolve, reject) => {\n const rejectAbort = () => {\n if (settled || controller.signal.reason === EXECUTION_COMPLETED) return;\n const reason = controller.signal.reason;\n reject(\n reason instanceof FoundryCommandSpecTimeoutError\n ? reason\n : new FoundryCommandSpecAbortError(reason),\n );\n };\n controller.signal.addEventListener('abort', rejectAbort, { once: true });\n });\n const timeoutPromise =\n options.timeoutMs === undefined\n ? new Promise<never>(() => undefined)\n : sleep(options.timeoutMs, controller.signal).then(() => {\n const error = new FoundryCommandSpecTimeoutError(options.timeoutMs!, startedAtMs);\n controller.abort(error);\n throw error;\n });\n const result = await Promise.race([spawnPromise, abortPromise, timeoutPromise]);\n settled = true;\n controller.abort(EXECUTION_COMPLETED);\n return result;\n } finally {\n settled = true;\n options.signal?.removeEventListener('abort', forwardAbort);\n }\n}\n\nfunction validateAsyncExecutionOptions(options: ExecuteFoundryCommandSpecOptions): void {\n if (\n options.timeoutMs !== undefined &&\n (!Number.isSafeInteger(options.timeoutMs) ||\n options.timeoutMs <= 0 ||\n options.timeoutMs > MAX_NODE_TIMER_DELAY_MS)\n ) {\n throw new Error(\n `CommandSpec timeoutMs must be a positive safe integer no greater than the maximum supported timer delay (${MAX_NODE_TIMER_DELAY_MS} ms).`,\n );\n }\n if (\n options.maxBuffer !== undefined &&\n (!Number.isSafeInteger(options.maxBuffer) || options.maxBuffer <= 0)\n ) {\n throw new Error('CommandSpec maxBuffer must be a positive safe integer.');\n }\n}\n\nfunction defaultSleep(milliseconds: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(resolve, milliseconds);\n timer.unref();\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n reject(signal.reason);\n },\n { once: true },\n );\n });\n}\n\nfunction spawnCommandAsync(\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 signal: options.signal,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;\n let capturedBytes = 0;\n let captureError: Error | undefined;\n let spawnError: Error | undefined;\n\n const capture = (target: Buffer[], bytes: Buffer) => {\n capturedBytes += bytes.byteLength;\n if (capturedBytes > maxBuffer) {\n captureError = new RangeError(\n `CommandSpec output exceeded maxBuffer (${maxBuffer} bytes).`,\n );\n child.kill();\n return;\n }\n target.push(bytes);\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', (error) => {\n spawnError = error;\n });\n child.once('close', (status, signal) => {\n const stdoutText = Buffer.concat(stdout).toString('utf8');\n const stderrText = Buffer.concat(stderr).toString('utf8');\n resolve({\n ...(child.pid === undefined ? {} : { pid: child.pid }),\n output: [null, stdoutText, stderrText],\n stdout: stdoutText,\n stderr: stderrText,\n status,\n signal,\n ...((captureError ?? spawnError) === undefined\n ? {}\n : { error: (captureError ?? spawnError)! }),\n });\n });\n });\n}\n"]}
@@ -0,0 +1,9 @@
1
+ type WriteJsonLinesOptions = {
2
+ append?: boolean;
3
+ };
4
+ export declare function writeTextArtifact(filePath: string, text: string): string;
5
+ export declare function writeJsonArtifact(filePath: string, value: unknown, compact?: boolean): string;
6
+ export declare function writeJsonLinesArtifact(filePath: string, rows: unknown | unknown[], options?: WriteJsonLinesOptions): string;
7
+ export declare function readJsonArtifact(filePath: string): unknown;
8
+ export declare function readJsonLinesArtifact(filePath: string): unknown[];
9
+ export {};