@sublang/slc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +192 -0
- package/dist/app.d.ts +85 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +233 -0
- package/dist/app.js.map +1 -0
- package/dist/artifacts.d.ts +61 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +97 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +26 -0
- package/dist/cli.js.map +1 -0
- package/dist/cligent-agent.d.ts +11 -0
- package/dist/cligent-agent.d.ts.map +1 -0
- package/dist/cligent-agent.js +66 -0
- package/dist/cligent-agent.js.map +1 -0
- package/dist/compiled-executor.d.ts +42 -0
- package/dist/compiled-executor.d.ts.map +1 -0
- package/dist/compiled-executor.js +433 -0
- package/dist/compiled-executor.js.map +1 -0
- package/dist/config-file.d.ts +52 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +159 -0
- package/dist/config-file.js.map +1 -0
- package/dist/config.d.ts +82 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +161 -0
- package/dist/config.js.map +1 -0
- package/dist/entry-module.d.ts +22 -0
- package/dist/entry-module.d.ts.map +1 -0
- package/dist/entry-module.js +216 -0
- package/dist/entry-module.js.map +1 -0
- package/dist/execution.d.ts +71 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +207 -0
- package/dist/execution.js.map +1 -0
- package/dist/file-capability.d.ts +46 -0
- package/dist/file-capability.d.ts.map +1 -0
- package/dist/file-capability.js +234 -0
- package/dist/file-capability.js.map +1 -0
- package/dist/file-grants.d.ts +79 -0
- package/dist/file-grants.d.ts.map +1 -0
- package/dist/file-grants.js +133 -0
- package/dist/file-grants.js.map +1 -0
- package/dist/hash.d.ts +14 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +34 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/interpreter.d.ts +48 -0
- package/dist/interpreter.d.ts.map +1 -0
- package/dist/interpreter.js +118 -0
- package/dist/interpreter.js.map +1 -0
- package/dist/invocation.d.ts +64 -0
- package/dist/invocation.d.ts.map +1 -0
- package/dist/invocation.js +148 -0
- package/dist/invocation.js.map +1 -0
- package/dist/link.d.ts +63 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +172 -0
- package/dist/link.js.map +1 -0
- package/dist/markdown.d.ts +12 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +63 -0
- package/dist/markdown.js.map +1 -0
- package/dist/normalize.md +68 -0
- package/dist/phase-runner.d.ts +64 -0
- package/dist/phase-runner.d.ts.map +1 -0
- package/dist/phase-runner.js +322 -0
- package/dist/phase-runner.js.map +1 -0
- package/dist/phase.d.ts +62 -0
- package/dist/phase.d.ts.map +1 -0
- package/dist/phase.js +111 -0
- package/dist/phase.js.map +1 -0
- package/dist/pin-closure.d.ts +19 -0
- package/dist/pin-closure.d.ts.map +1 -0
- package/dist/pin-closure.js +110 -0
- package/dist/pin-closure.js.map +1 -0
- package/dist/pin-currency.d.ts +55 -0
- package/dist/pin-currency.d.ts.map +1 -0
- package/dist/pin-currency.js +435 -0
- package/dist/pin-currency.js.map +1 -0
- package/dist/pin-generate.d.ts +46 -0
- package/dist/pin-generate.d.ts.map +1 -0
- package/dist/pin-generate.js +131 -0
- package/dist/pin-generate.js.map +1 -0
- package/dist/pin-paths.d.ts +11 -0
- package/dist/pin-paths.d.ts.map +1 -0
- package/dist/pin-paths.js +108 -0
- package/dist/pin-paths.js.map +1 -0
- package/dist/pins.d.ts +84 -0
- package/dist/pins.d.ts.map +1 -0
- package/dist/pins.js +265 -0
- package/dist/pins.js.map +1 -0
- package/dist/pipeline.d.ts +61 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +147 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/playbook-contract.d.ts +194 -0
- package/dist/playbook-contract.d.ts.map +1 -0
- package/dist/playbook-contract.js +180 -0
- package/dist/playbook-contract.js.map +1 -0
- package/dist/playbook-ports.d.ts +53 -0
- package/dist/playbook-ports.d.ts.map +1 -0
- package/dist/playbook-ports.js +217 -0
- package/dist/playbook-ports.js.map +1 -0
- package/dist/resolver.d.ts +68 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +133 -0
- package/dist/resolver.js.map +1 -0
- package/dist/runner.d.ts +45 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +506 -0
- package/dist/runner.js.map +1 -0
- package/dist/runtime-package.d.ts +7 -0
- package/dist/runtime-package.d.ts.map +1 -0
- package/dist/runtime-package.js +132 -0
- package/dist/runtime-package.js.map +1 -0
- package/dist/slc.config.template.yaml +5 -0
- package/dist/verify-coverage.d.ts +99 -0
- package/dist/verify-coverage.d.ts.map +1 -0
- package/dist/verify-coverage.js +1949 -0
- package/dist/verify-coverage.js.map +1 -0
- package/dist/verify-support.d.ts +10 -0
- package/dist/verify-support.d.ts.map +1 -0
- package/dist/verify-support.js +52 -0
- package/dist/verify-support.js.map +1 -0
- package/dist/verify.d.ts +393 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +1790 -0
- package/dist/verify.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
/**
|
|
4
|
+
* Compiled phase execution: load a `playbook` artifact and drive it host-side
|
|
5
|
+
* (PHEXEC-23, PHEXEC-24, PHEXEC-25; DR-005).
|
|
6
|
+
*
|
|
7
|
+
* {@link loadPlaybookRuntime} imports a compiled `playbook` module and returns
|
|
8
|
+
* its `createPlaybookRuntime` factory. {@link createCompiledExecutor} adapts it
|
|
9
|
+
* to the DR-003 {@link PhaseExecutor} boundary: per run it builds the
|
|
10
|
+
* Cligent-backed Playbook ports, constructs the runtime, drives one
|
|
11
|
+
* non-interactive turn (`init` -> `handleBossInput` -> `dispose`), and maps a
|
|
12
|
+
* structured result when present or the bounded legacy host-observable outcome
|
|
13
|
+
* otherwise. The pin-selected contract profile chooses the exact legacy,
|
|
14
|
+
* traced-session, or composed-session init shape without a retry heuristic
|
|
15
|
+
* (DR-010, DR-011). The host-only `drainDiagnostics` stays host-side;
|
|
16
|
+
* human status and non-trace operational telemetry become diagnostics. Like
|
|
17
|
+
* interpreted execution, a compiled phase writes through its agents
|
|
18
|
+
* (`callPlayer`) and relies on the DR-003 generic checks, which defend the
|
|
19
|
+
* protected inputs (not the full write scope); `slc` adds no host-side
|
|
20
|
+
* write-scope enforcement.
|
|
21
|
+
*
|
|
22
|
+
* The turn is seeded per the PHEXEC-29 contract ({@link seedPhaseTurn}), and a
|
|
23
|
+
* transformation-performing direct Captain call additionally carries the host
|
|
24
|
+
* workspace contract ({@link composeWorkspaceContract}; PHEXEC-34) so the
|
|
25
|
+
* host-agnostic artifact's Captain learns the request's absolute paths; the
|
|
26
|
+
* result is derived in {@link drivePhase} from the structured runtime boundary
|
|
27
|
+
* or, for a void-result legacy runtime, the host-observable output delta.
|
|
28
|
+
* See specs/dev/phase-execution.md.
|
|
29
|
+
*/
|
|
30
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
31
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
32
|
+
import { basename, resolve } from 'node:path';
|
|
33
|
+
import { pathToFileURL } from 'node:url';
|
|
34
|
+
import { composeWorkspaceContract, mapPhaseResult, seedPhaseTurn, } from './phase-runner.js';
|
|
35
|
+
import { isPlaybookRunResult, } from './playbook-contract.js';
|
|
36
|
+
import { createPlaybookPorts } from './playbook-ports.js';
|
|
37
|
+
/**
|
|
38
|
+
* Imports a compiled `playbook` module and returns its runtime factory
|
|
39
|
+
* (PHEXEC-23).
|
|
40
|
+
*
|
|
41
|
+
* @throws when the module has no callable `createPlaybookRuntime` default export.
|
|
42
|
+
*/
|
|
43
|
+
export async function loadPlaybookRuntime(artifactPath) {
|
|
44
|
+
const module = await import(pathToFileURL(resolve(artifactPath)).href);
|
|
45
|
+
const create = module.default;
|
|
46
|
+
if (typeof create !== 'function') {
|
|
47
|
+
throw new Error(`compiled artifact "${artifactPath}" has no createPlaybookRuntime default export`);
|
|
48
|
+
}
|
|
49
|
+
return create;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Adapts a compiled `playbook` artifact to the {@link PhaseExecutor} boundary
|
|
53
|
+
* (PHEXEC-24, PHEXEC-25): build the Cligent-backed Playbook ports, load and
|
|
54
|
+
* construct the runtime, drive one non-interactive root-session turn, and map
|
|
55
|
+
* the outcome, appending drained status and non-trace operational telemetry.
|
|
56
|
+
*/
|
|
57
|
+
export function createCompiledExecutor(opts) {
|
|
58
|
+
const load = opts.loadFactory ?? loadPlaybookRuntime;
|
|
59
|
+
return {
|
|
60
|
+
async run(request, signal) {
|
|
61
|
+
let lastFsmState;
|
|
62
|
+
const input = phaseInput(request, opts.runRoot);
|
|
63
|
+
const adapter = createPlaybookPorts({
|
|
64
|
+
player: opts.player,
|
|
65
|
+
judge: opts.judge,
|
|
66
|
+
models: opts.models,
|
|
67
|
+
defaultModel: opts.defaultModel,
|
|
68
|
+
cwd: opts.cwd,
|
|
69
|
+
// The host owns the workspace: a transformation-performing Captain's
|
|
70
|
+
// transported prompt carries the request's absolute paths and
|
|
71
|
+
// write-scope rules (PHEXEC-34).
|
|
72
|
+
captainWorkspace: composeWorkspaceContract(input),
|
|
73
|
+
});
|
|
74
|
+
// Hand the runtime only Playbook's ports — never the host-only
|
|
75
|
+
// drainDiagnostics, nor a file capability (DR-005, PHEXEC-23).
|
|
76
|
+
const ports = {
|
|
77
|
+
callPlayer: adapter.callPlayer,
|
|
78
|
+
callCaptain: adapter.callCaptain,
|
|
79
|
+
callJudge: adapter.callJudge,
|
|
80
|
+
callPlaybook: adapter.callPlaybook,
|
|
81
|
+
emitStatus: adapter.emitStatus,
|
|
82
|
+
emitTelemetry: async (event) => {
|
|
83
|
+
const state = fsmTransitionTarget(event);
|
|
84
|
+
if (state !== undefined)
|
|
85
|
+
lastFsmState = state;
|
|
86
|
+
await adapter.emitTelemetry(event);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
const runtimeContract = opts.runtimeContract ?? 'legacy';
|
|
90
|
+
const identity = phaseSessionIdentity({
|
|
91
|
+
sessionId: (opts.createSessionId ?? randomUUID)(),
|
|
92
|
+
playbookId: opts.playbookId ?? playbookIdFromArtifact(opts.artifactPath),
|
|
93
|
+
});
|
|
94
|
+
const driven = await drivePhase(load, opts.artifactPath, ports, input, signal, identity, runtimeContract);
|
|
95
|
+
const result = mapVoidContractFailedState(driven, lastFsmState, runtimeContract !== 'composed-v2');
|
|
96
|
+
const mapped = mapPhaseResult(result);
|
|
97
|
+
return {
|
|
98
|
+
status: mapped.status,
|
|
99
|
+
diagnostics: [...mapped.diagnostics, ...adapter.drainDiagnostics()],
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** Returns the destination carried by Playbook's standard FSM telemetry. */
|
|
105
|
+
function fsmTransitionTarget(event) {
|
|
106
|
+
if (event.topic !== 'playbook.fsm.state' ||
|
|
107
|
+
typeof event.payload !== 'object' ||
|
|
108
|
+
event.payload === null ||
|
|
109
|
+
!('to' in event.payload) ||
|
|
110
|
+
typeof event.payload.to !== 'string') {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
return event.payload.to;
|
|
114
|
+
}
|
|
115
|
+
/** DR-005 maps a quiescent `failed` FSM state to an executor error. */
|
|
116
|
+
function mapVoidContractFailedState(result, lastFsmState, voidContract) {
|
|
117
|
+
if (!voidContract || result.status === 'error' || lastFsmState !== 'failed') {
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
status: 'error',
|
|
122
|
+
diagnostics: ['compiled runtime reached the failed quiescent state'],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Loads, constructs, and drives one non-interactive turn. Structured results
|
|
127
|
+
* are authoritative; a void legacy result retains DR-010's output-delta and
|
|
128
|
+
* host-observed failed-state mapping.
|
|
129
|
+
*/
|
|
130
|
+
async function drivePhase(load, artifactPath, ports, input, signal, identity, runtimeContract) {
|
|
131
|
+
let runtime;
|
|
132
|
+
try {
|
|
133
|
+
const factory = await load(artifactPath);
|
|
134
|
+
runtime = factory({});
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return {
|
|
138
|
+
status: 'error',
|
|
139
|
+
diagnostics: [`compiled artifact failed to load: ${messageOf(error)}`],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// Snapshot the output before the turn so a pre-existing stale artifact is not
|
|
143
|
+
// mistaken for fresh output the turn produced.
|
|
144
|
+
const outputPath = input.kind === 'compile' ? input.target : input.linked;
|
|
145
|
+
const before = await outputState(outputPath);
|
|
146
|
+
const initValue = runtimeInitValue(runtimeContract, identity, ports);
|
|
147
|
+
let runResult;
|
|
148
|
+
try {
|
|
149
|
+
await callRuntimeInit(runtime, initValue);
|
|
150
|
+
runResult = await callRuntimeTurn(runtime, seedPhaseTurn(input), signal);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const disposal = await disposeRuntime(runtime);
|
|
154
|
+
return {
|
|
155
|
+
status: 'error',
|
|
156
|
+
diagnostics: [
|
|
157
|
+
signal.aborted
|
|
158
|
+
? 'compiled run aborted'
|
|
159
|
+
: `compiled run failed: ${messageOf(error)}`,
|
|
160
|
+
...(disposal === undefined
|
|
161
|
+
? []
|
|
162
|
+
: [`compiled runtime disposal also failed: ${messageOf(disposal)}`]),
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const disposal = await disposeRuntime(runtime);
|
|
167
|
+
if (disposal !== undefined) {
|
|
168
|
+
return {
|
|
169
|
+
status: 'error',
|
|
170
|
+
diagnostics: [`compiled runtime disposal failed: ${messageOf(disposal)}`],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (signal.aborted) {
|
|
174
|
+
return {
|
|
175
|
+
status: 'error',
|
|
176
|
+
diagnostics: ['compiled run aborted'],
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const after = await outputState(outputPath);
|
|
180
|
+
const produced = outputWasProduced(before, after);
|
|
181
|
+
return mapRuntimeOutcome(runResult, produced, runtimeContract);
|
|
182
|
+
}
|
|
183
|
+
async function disposeRuntime(runtime) {
|
|
184
|
+
try {
|
|
185
|
+
await runtime.dispose();
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
return error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function rootSession(identity, ports) {
|
|
193
|
+
return {
|
|
194
|
+
sessionId: identity.sessionId,
|
|
195
|
+
playbookId: identity.playbookId,
|
|
196
|
+
rootSessionId: identity.sessionId,
|
|
197
|
+
depth: 0,
|
|
198
|
+
ports: composedPorts(ports),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function legacyPorts(ports) {
|
|
202
|
+
return {
|
|
203
|
+
callPlayer: ports.callPlayer,
|
|
204
|
+
callJudge: ports.callJudge,
|
|
205
|
+
emitStatus: ports.emitStatus,
|
|
206
|
+
emitTelemetry: ports.emitTelemetry,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function sessionV1Ports(ports) {
|
|
210
|
+
return {
|
|
211
|
+
callPlayer: (playerId, prompt, signal, options) => ports.callPlayer(playerId, prompt, signal, requirePlayerCallOptions(options)),
|
|
212
|
+
callJudge: ports.callJudge,
|
|
213
|
+
emitStatus: ports.emitStatus,
|
|
214
|
+
emitTelemetry: ports.emitTelemetry,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function composedPorts(ports) {
|
|
218
|
+
return {
|
|
219
|
+
callPlayer: (playerId, prompt, signal, options) => preserveControlPlaneRejection('callPlayer', signal, () => ports.callPlayer(playerId, prompt, signal, requirePlayerCallOptions(options))),
|
|
220
|
+
callCaptain: (prompt, signal, options) => preserveControlPlaneRejection('callCaptain', signal, () => ports.callCaptain(prompt, signal, options)),
|
|
221
|
+
callJudge: (prompt, signal) => preserveControlPlaneRejection('callJudge', signal, () => ports.callJudge(prompt, signal)),
|
|
222
|
+
callPlaybook: (request, signal) => preserveControlPlaneRejection('callPlaybook', signal, () => ports.callPlaybook(request, signal)),
|
|
223
|
+
emitStatus: (message, data) => preserveControlPlaneRejection('emitStatus', undefined, () => ports.emitStatus(message, data)),
|
|
224
|
+
emitTelemetry: (event) => preserveControlPlaneRejection('emitTelemetry', undefined, () => ports.emitTelemetry(event)),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Keeps nullish host-port rejections visible to immutable composed runtimes.
|
|
229
|
+
* Playbook 2.0.0 latches control-plane failures with nullish coalescing, so a
|
|
230
|
+
* rejection without a value could otherwise be mistaken for an authored FSM
|
|
231
|
+
* failure. Preserve a causally identical abort reason, but give every other
|
|
232
|
+
* nullish rejection a stable Error identity before it crosses the boundary.
|
|
233
|
+
*/
|
|
234
|
+
async function preserveControlPlaneRejection(port, signal, call) {
|
|
235
|
+
try {
|
|
236
|
+
return await call();
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
if (error !== undefined && error !== null) {
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
if (signal?.aborted === true && error === signal.reason) {
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
throw new Error(`compiled composed-v2 ${port} port rejected without an error`, { cause: error });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function requirePlayerCallOptions(value) {
|
|
249
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
250
|
+
throw new TypeError('session runtime callPlayer requires explicit PlayerCallOptions');
|
|
251
|
+
}
|
|
252
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, 'resume');
|
|
253
|
+
if (descriptor === undefined ||
|
|
254
|
+
!Object.prototype.hasOwnProperty.call(descriptor, 'value') ||
|
|
255
|
+
(descriptor.value !== false && typeof descriptor.value !== 'string')) {
|
|
256
|
+
throw new TypeError('session runtime callPlayer options.resume must be false or a string');
|
|
257
|
+
}
|
|
258
|
+
return { resume: descriptor.value };
|
|
259
|
+
}
|
|
260
|
+
function runtimeInitValue(contract, identity, ports) {
|
|
261
|
+
switch (contract) {
|
|
262
|
+
case 'legacy':
|
|
263
|
+
return legacyPorts(ports);
|
|
264
|
+
case 'session-v1':
|
|
265
|
+
return {
|
|
266
|
+
sessionId: identity.sessionId,
|
|
267
|
+
playbookId: identity.playbookId,
|
|
268
|
+
ports: sessionV1Ports(ports),
|
|
269
|
+
};
|
|
270
|
+
case 'composed-v2':
|
|
271
|
+
return rootSession(identity, ports);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async function callRuntimeInit(runtime, value) {
|
|
275
|
+
const init = runtime.init;
|
|
276
|
+
await init.call(runtime, value);
|
|
277
|
+
}
|
|
278
|
+
async function callRuntimeTurn(runtime, text, signal) {
|
|
279
|
+
const handle = runtime.handleBossInput;
|
|
280
|
+
return handle.call(runtime, { text, signal });
|
|
281
|
+
}
|
|
282
|
+
function mapRuntimeOutcome(result, produced, contract) {
|
|
283
|
+
if (contract !== 'composed-v2') {
|
|
284
|
+
return result === undefined
|
|
285
|
+
? legacyOutputResult(produced)
|
|
286
|
+
: {
|
|
287
|
+
status: 'error',
|
|
288
|
+
diagnostics: [
|
|
289
|
+
`compiled ${contract} runtime returned an unexpected structured result`,
|
|
290
|
+
],
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
if (result === undefined) {
|
|
294
|
+
return {
|
|
295
|
+
status: 'error',
|
|
296
|
+
diagnostics: ['compiled composed-v2 runtime returned no run result'],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
if (!isPlaybookRunResult(result)) {
|
|
300
|
+
return {
|
|
301
|
+
status: 'error',
|
|
302
|
+
diagnostics: ['compiled runtime returned an invalid run result'],
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
return structuredOutputResult(result, produced);
|
|
306
|
+
}
|
|
307
|
+
function phaseSessionIdentity(identity) {
|
|
308
|
+
if (identity.sessionId.trim().length === 0) {
|
|
309
|
+
throw new Error('compiled runtime session id must be non-empty');
|
|
310
|
+
}
|
|
311
|
+
if (identity.playbookId.trim().length === 0) {
|
|
312
|
+
throw new Error('compiled runtime playbook id must be non-empty');
|
|
313
|
+
}
|
|
314
|
+
return identity;
|
|
315
|
+
}
|
|
316
|
+
function legacyOutputResult(produced) {
|
|
317
|
+
return produced
|
|
318
|
+
? { status: 'ok', diagnostics: [] }
|
|
319
|
+
: {
|
|
320
|
+
status: 'blocked',
|
|
321
|
+
diagnostics: [
|
|
322
|
+
'compiled phase produced no output (parked for Boss input)',
|
|
323
|
+
],
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function structuredOutputResult(result, produced) {
|
|
327
|
+
switch (result.outcome) {
|
|
328
|
+
case 'quiescent':
|
|
329
|
+
case 'terminal':
|
|
330
|
+
return produced
|
|
331
|
+
? { status: 'ok', diagnostics: [] }
|
|
332
|
+
: {
|
|
333
|
+
status: 'blocked',
|
|
334
|
+
diagnostics: [
|
|
335
|
+
`compiled runtime ${result.outcome} without producing output`,
|
|
336
|
+
],
|
|
337
|
+
};
|
|
338
|
+
case 'no-action':
|
|
339
|
+
return {
|
|
340
|
+
status: 'blocked',
|
|
341
|
+
diagnostics: ['compiled runtime accepted no phase action'],
|
|
342
|
+
};
|
|
343
|
+
case 'failed':
|
|
344
|
+
case 'aborted':
|
|
345
|
+
return {
|
|
346
|
+
status: 'error',
|
|
347
|
+
diagnostics: [
|
|
348
|
+
`compiled runtime ${result.outcome}${result.error ? `: ${result.error.message}` : ''}`,
|
|
349
|
+
],
|
|
350
|
+
};
|
|
351
|
+
case 'suspended':
|
|
352
|
+
return {
|
|
353
|
+
status: 'error',
|
|
354
|
+
diagnostics: [
|
|
355
|
+
`compiled runtime suspended for unsupported nested playbook call ${result.pendingCall.callId}`,
|
|
356
|
+
],
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function playbookIdFromArtifact(artifactPath) {
|
|
361
|
+
const name = basename(artifactPath);
|
|
362
|
+
return name.endsWith('.playbook.ts')
|
|
363
|
+
? name.slice(0, -'.playbook.ts'.length)
|
|
364
|
+
: name.replace(/\.[^.]+$/, '');
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* A point-in-time output view. Content and file identity supplement timestamps,
|
|
368
|
+
* so an atomic replacement or preserved mtime still counts as produced output.
|
|
369
|
+
*/
|
|
370
|
+
async function outputState(path) {
|
|
371
|
+
try {
|
|
372
|
+
const info = await stat(path);
|
|
373
|
+
const identity = {
|
|
374
|
+
dev: info.dev,
|
|
375
|
+
ino: info.ino,
|
|
376
|
+
mode: info.mode,
|
|
377
|
+
size: info.size,
|
|
378
|
+
mtimeMs: info.mtimeMs,
|
|
379
|
+
ctimeMs: info.ctimeMs,
|
|
380
|
+
};
|
|
381
|
+
if (!info.isFile())
|
|
382
|
+
return { kind: 'other', ...identity };
|
|
383
|
+
const digest = createHash('sha256')
|
|
384
|
+
.update(await readFile(path))
|
|
385
|
+
.digest('hex');
|
|
386
|
+
return { kind: 'file', digest, ...identity };
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return { kind: 'missing' };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function outputWasProduced(before, after) {
|
|
393
|
+
if (after.kind !== 'file')
|
|
394
|
+
return false;
|
|
395
|
+
if (before.kind !== 'file')
|
|
396
|
+
return true;
|
|
397
|
+
return (before.digest !== after.digest ||
|
|
398
|
+
before.dev !== after.dev ||
|
|
399
|
+
before.ino !== after.ino ||
|
|
400
|
+
before.mode !== after.mode ||
|
|
401
|
+
before.size !== after.size ||
|
|
402
|
+
before.mtimeMs !== after.mtimeMs ||
|
|
403
|
+
before.ctimeMs !== after.ctimeMs);
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Maps an {@link ExecuteRequest} to the {@link PhaseInput} the seed carries,
|
|
407
|
+
* resolving its workspace paths against the run root to absolute host paths the
|
|
408
|
+
* runtime's agents can act on (DR-005).
|
|
409
|
+
*/
|
|
410
|
+
function phaseInput(request, runRoot) {
|
|
411
|
+
const abs = (path) => resolve(runRoot, path);
|
|
412
|
+
if (request.kind === 'compile') {
|
|
413
|
+
return {
|
|
414
|
+
kind: 'compile',
|
|
415
|
+
source: abs(request.source),
|
|
416
|
+
target: abs(request.target),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
kind: 'link',
|
|
421
|
+
objects: request.objects.map(abs),
|
|
422
|
+
linkTarget: abs(request.linkTarget),
|
|
423
|
+
options: optionsRecord(request.options),
|
|
424
|
+
linked: abs(request.linked),
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function optionsRecord(options) {
|
|
428
|
+
return Object.fromEntries(options.map((option) => [option.name, option.value]));
|
|
429
|
+
}
|
|
430
|
+
function messageOf(error) {
|
|
431
|
+
return error instanceof Error ? error.message : String(error);
|
|
432
|
+
}
|
|
433
|
+
//# sourceMappingURL=compiled-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiled-executor.js","sourceRoot":"","sources":["../src/compiled-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Config-file basename discovered in the working directory (DR-006). */
|
|
2
|
+
export declare const CONFIG_FILE = "slc.config.yaml";
|
|
3
|
+
/** Config-file path under the user config home (DR-006). */
|
|
4
|
+
export declare const HOME_CONFIG: string;
|
|
5
|
+
/** Partial cligent-invocation selection loaded from a config file (DR-006). */
|
|
6
|
+
export interface FileConfig {
|
|
7
|
+
agent?: string;
|
|
8
|
+
model?: string;
|
|
9
|
+
effort?: string;
|
|
10
|
+
pipelinePath?: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A loaded config file: the parsed {@link FileConfig} plus the resolved file
|
|
14
|
+
* path, or `path: undefined` on a discovery miss (no file loaded).
|
|
15
|
+
*/
|
|
16
|
+
export interface LoadedFileConfig {
|
|
17
|
+
path?: string;
|
|
18
|
+
config: FileConfig;
|
|
19
|
+
}
|
|
20
|
+
/** Injectable IO for {@link loadConfigFile}; all fields default to the process. */
|
|
21
|
+
export interface LoadConfigFileOptions {
|
|
22
|
+
cwd?: string;
|
|
23
|
+
/** Explicit `--config <path>`: disables discovery and errors when absent (CLI-20, CLI-21). */
|
|
24
|
+
configPath?: string;
|
|
25
|
+
/** User config home; defaults to `${XDG_CONFIG_HOME:-~/.config}`. Injectable for tests. */
|
|
26
|
+
configHome?: string;
|
|
27
|
+
/** Environment for resolving `XDG_CONFIG_HOME`; defaults to `process.env`. */
|
|
28
|
+
env?: Record<string, string | undefined>;
|
|
29
|
+
/** Called with the created path when a discovery miss seeds the user config (DR-015, CLI-30). */
|
|
30
|
+
onSeed?: (path: string) => void;
|
|
31
|
+
}
|
|
32
|
+
/** Machine-readable reason a config file was rejected (CLI-21). */
|
|
33
|
+
export type ConfigFileErrorCode = 'config-not-found' | 'config-parse' | 'config-invalid';
|
|
34
|
+
/** Raised when an explicit `--config` file is missing, malformed, or invalid (CLI-21). */
|
|
35
|
+
export declare class ConfigFileError extends Error {
|
|
36
|
+
readonly code: ConfigFileErrorCode;
|
|
37
|
+
constructor(code: ConfigFileErrorCode, message: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads the slc config file (DR-006, CLI-20, CLI-21).
|
|
41
|
+
*
|
|
42
|
+
* Resolves the file via an explicit `--config` path or cwd/home discovery,
|
|
43
|
+
* parses and validates it, and returns the partial selection plus the resolved
|
|
44
|
+
* path. A discovery miss returns `{ config: {} }` so the caller falls through to
|
|
45
|
+
* the environment and built-in defaults.
|
|
46
|
+
*
|
|
47
|
+
* @throws {ConfigFileError} when an explicit `--config` path is absent
|
|
48
|
+
* (`config-not-found`), the file is unreadable or malformed YAML
|
|
49
|
+
* (`config-parse`), or it violates the flat schema (`config-invalid`).
|
|
50
|
+
*/
|
|
51
|
+
export declare function loadConfigFile(options?: LoadConfigFileOptions): Promise<LoadedFileConfig>;
|
|
52
|
+
//# sourceMappingURL=config-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-file.d.ts","sourceRoot":"","sources":["../src/config-file.ts"],"names":[],"mappings":"AA2BA,yEAAyE;AACzE,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAC7C,4DAA4D;AAC5D,eAAO,MAAM,WAAW,QAA6B,CAAC;AAOtD,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,mFAAmF;AACnF,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,iGAAiG;IACjG,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAC3B,kBAAkB,GAClB,cAAc,GACd,gBAAgB,CAAC;AAErB,0FAA0F;AAC1F,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBAEvB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAKvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAQ3B"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
/**
|
|
4
|
+
* Config-file loader for the `slc` bin (DR-006, CLI-20, CLI-21).
|
|
5
|
+
*
|
|
6
|
+
* Discovers and parses the optional YAML config file that supplies the
|
|
7
|
+
* cligent-invocation defaults — `agent`, `model`, `effort`, and `pipelinePath` — which the
|
|
8
|
+
* environment then overrides (DR-006). Discovery reads `slc.config.yaml` in the
|
|
9
|
+
* working directory, then `${XDG_CONFIG_HOME:-~/.config}/slc/config.yaml`; an
|
|
10
|
+
* explicit `--config` path disables discovery and is an error when absent, while
|
|
11
|
+
* a discovery miss returns an empty result that falls through to the environment
|
|
12
|
+
* and defaults. The loader validates a flat schema and rejects unknown keys and
|
|
13
|
+
* mistyped values; the supported-agent check stays with `resolveAgentSelection`
|
|
14
|
+
* so the agent set keeps a single source of truth. Relative `pipelinePath`
|
|
15
|
+
* entries are returned verbatim and resolved against the cwd downstream
|
|
16
|
+
* (CLI-6). See specs/dev/cli.md.
|
|
17
|
+
*/
|
|
18
|
+
import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
19
|
+
import { readFile } from 'node:fs/promises';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
21
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { parse } from 'yaml';
|
|
24
|
+
/** Config-file basename discovered in the working directory (DR-006). */
|
|
25
|
+
export const CONFIG_FILE = 'slc.config.yaml';
|
|
26
|
+
/** Config-file path under the user config home (DR-006). */
|
|
27
|
+
export const HOME_CONFIG = join('slc', 'config.yaml');
|
|
28
|
+
/** Bundled starter template seeded into the user config home on a discovery miss (DR-015). */
|
|
29
|
+
const TEMPLATE_PATH = fileURLToPath(new URL('./slc.config.template.yaml', import.meta.url));
|
|
30
|
+
/** Raised when an explicit `--config` file is missing, malformed, or invalid (CLI-21). */
|
|
31
|
+
export class ConfigFileError extends Error {
|
|
32
|
+
code;
|
|
33
|
+
constructor(code, message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = 'ConfigFileError';
|
|
36
|
+
this.code = code;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads the slc config file (DR-006, CLI-20, CLI-21).
|
|
41
|
+
*
|
|
42
|
+
* Resolves the file via an explicit `--config` path or cwd/home discovery,
|
|
43
|
+
* parses and validates it, and returns the partial selection plus the resolved
|
|
44
|
+
* path. A discovery miss returns `{ config: {} }` so the caller falls through to
|
|
45
|
+
* the environment and built-in defaults.
|
|
46
|
+
*
|
|
47
|
+
* @throws {ConfigFileError} when an explicit `--config` path is absent
|
|
48
|
+
* (`config-not-found`), the file is unreadable or malformed YAML
|
|
49
|
+
* (`config-parse`), or it violates the flat schema (`config-invalid`).
|
|
50
|
+
*/
|
|
51
|
+
export async function loadConfigFile(options = {}) {
|
|
52
|
+
const cwd = options.cwd ?? process.cwd();
|
|
53
|
+
const path = resolveConfigPath(options, cwd);
|
|
54
|
+
if (path === undefined) {
|
|
55
|
+
return { config: {} };
|
|
56
|
+
}
|
|
57
|
+
const config = await readConfigFile(path);
|
|
58
|
+
return { path, config };
|
|
59
|
+
}
|
|
60
|
+
function resolveConfigPath(options, cwd) {
|
|
61
|
+
if (options.configPath !== undefined) {
|
|
62
|
+
const explicit = isAbsolute(options.configPath)
|
|
63
|
+
? options.configPath
|
|
64
|
+
: resolve(cwd, options.configPath);
|
|
65
|
+
if (!existsSync(explicit)) {
|
|
66
|
+
throw new ConfigFileError('config-not-found', `--config file not found: ${options.configPath}`);
|
|
67
|
+
}
|
|
68
|
+
return explicit;
|
|
69
|
+
}
|
|
70
|
+
const cwdConfig = resolve(cwd, CONFIG_FILE);
|
|
71
|
+
if (existsSync(cwdConfig)) {
|
|
72
|
+
return cwdConfig;
|
|
73
|
+
}
|
|
74
|
+
const homeConfig = join(configHome(options), HOME_CONFIG);
|
|
75
|
+
if (existsSync(homeConfig)) {
|
|
76
|
+
return homeConfig;
|
|
77
|
+
}
|
|
78
|
+
// First run: neither discovered file exists, so seed the user config from
|
|
79
|
+
// the bundled starter and load it (DR-015, CLI-30).
|
|
80
|
+
mkdirSync(dirname(homeConfig), { recursive: true });
|
|
81
|
+
copyFileSync(TEMPLATE_PATH, homeConfig);
|
|
82
|
+
options.onSeed?.(homeConfig);
|
|
83
|
+
return homeConfig;
|
|
84
|
+
}
|
|
85
|
+
function configHome(options) {
|
|
86
|
+
if (options.configHome !== undefined) {
|
|
87
|
+
return options.configHome;
|
|
88
|
+
}
|
|
89
|
+
const env = options.env ?? process.env;
|
|
90
|
+
const xdg = (env.XDG_CONFIG_HOME ?? '').trim();
|
|
91
|
+
return xdg !== '' ? xdg : join(homedir(), '.config');
|
|
92
|
+
}
|
|
93
|
+
async function readConfigFile(path) {
|
|
94
|
+
let source;
|
|
95
|
+
try {
|
|
96
|
+
source = await readFile(path, 'utf8');
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw new ConfigFileError('config-parse', `Failed to read config file ${path}: ${messageOf(error)}`);
|
|
100
|
+
}
|
|
101
|
+
let raw;
|
|
102
|
+
try {
|
|
103
|
+
raw = parse(source);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
throw new ConfigFileError('config-parse', `Failed to parse config file ${path}: ${messageOf(error)}`);
|
|
107
|
+
}
|
|
108
|
+
return normalizeFileConfig(raw, path);
|
|
109
|
+
}
|
|
110
|
+
const ALLOWED_KEYS = new Set(['agent', 'model', 'effort', 'pipelinePath']);
|
|
111
|
+
function normalizeFileConfig(value, path) {
|
|
112
|
+
if (value === null || value === undefined) {
|
|
113
|
+
return {};
|
|
114
|
+
}
|
|
115
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
116
|
+
throw new ConfigFileError('config-invalid', `Config file ${path} must contain a mapping of keys to values`);
|
|
117
|
+
}
|
|
118
|
+
const input = value;
|
|
119
|
+
for (const key of Object.keys(input)) {
|
|
120
|
+
if (!ALLOWED_KEYS.has(key)) {
|
|
121
|
+
throw new ConfigFileError('config-invalid', `Unknown config key "${key}" in ${path}; allowed keys: agent, model, effort, pipelinePath`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const config = {};
|
|
125
|
+
if (input.agent !== undefined) {
|
|
126
|
+
config.agent = requireString(input.agent, 'agent', path);
|
|
127
|
+
}
|
|
128
|
+
if (input.model !== undefined) {
|
|
129
|
+
config.model = requireString(input.model, 'model', path);
|
|
130
|
+
}
|
|
131
|
+
if (input.effort !== undefined) {
|
|
132
|
+
config.effort = requireString(input.effort, 'effort', path);
|
|
133
|
+
}
|
|
134
|
+
if (input.pipelinePath !== undefined) {
|
|
135
|
+
config.pipelinePath = requireStringArray(input.pipelinePath, 'pipelinePath', path);
|
|
136
|
+
}
|
|
137
|
+
return config;
|
|
138
|
+
}
|
|
139
|
+
function requireString(value, key, path) {
|
|
140
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
141
|
+
throw new ConfigFileError('config-invalid', `Config key "${key}" in ${path} must be a non-empty string`);
|
|
142
|
+
}
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
function requireStringArray(value, key, path) {
|
|
146
|
+
if (!Array.isArray(value)) {
|
|
147
|
+
throw new ConfigFileError('config-invalid', `Config key "${key}" in ${path} must be a sequence of strings`);
|
|
148
|
+
}
|
|
149
|
+
return value.map((entry, index) => {
|
|
150
|
+
if (typeof entry !== 'string' || entry.trim() === '') {
|
|
151
|
+
throw new ConfigFileError('config-invalid', `Config key "${key}[${index}]" in ${path} must be a non-empty string`);
|
|
152
|
+
}
|
|
153
|
+
return entry;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function messageOf(error) {
|
|
157
|
+
return error instanceof Error ? error.message : String(error);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=config-file.js.map
|