smol-symphony 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.
@@ -0,0 +1,385 @@
1
+ // WORKFLOW.md loader, watcher, and typed config view (SPEC §5, §6).
2
+ import { readFile } from 'node:fs/promises';
3
+ import { existsSync, statSync } from 'node:fs';
4
+ import path from 'node:path';
5
+ import os from 'node:os';
6
+ import chokidar from 'chokidar';
7
+ import { parse as parseYaml } from 'yaml';
8
+ import { log } from './logging.js';
9
+ import { isKnownAdapter } from './agent/adapters.js';
10
+ export class WorkflowError extends Error {
11
+ code;
12
+ constructor(code, message) {
13
+ super(message);
14
+ this.code = code;
15
+ this.name = 'WorkflowError';
16
+ }
17
+ }
18
+ // §5.2: split YAML front matter from prompt body.
19
+ export function splitFrontMatter(text) {
20
+ if (!text.startsWith('---')) {
21
+ return { config: {}, body: text.trim() };
22
+ }
23
+ const lines = text.split(/\r?\n/);
24
+ // First and closing fences must be exactly `---` (with optional trailing whitespace),
25
+ // unindented. Otherwise an indented `---` inside a multiline YAML hook script would be
26
+ // mistaken for the closing fence.
27
+ const isFence = (line) => /^---\s*$/.test(line ?? '');
28
+ if (!isFence(lines[0])) {
29
+ return { config: {}, body: text.trim() };
30
+ }
31
+ let endIdx = -1;
32
+ for (let i = 1; i < lines.length; i++) {
33
+ if (isFence(lines[i])) {
34
+ endIdx = i;
35
+ break;
36
+ }
37
+ }
38
+ if (endIdx < 0) {
39
+ throw new WorkflowError('workflow_parse_error', 'unterminated YAML front matter');
40
+ }
41
+ const fmText = lines.slice(1, endIdx).join('\n');
42
+ const body = lines.slice(endIdx + 1).join('\n').trim();
43
+ let parsed;
44
+ try {
45
+ parsed = fmText.trim().length === 0 ? {} : parseYaml(fmText);
46
+ }
47
+ catch (err) {
48
+ throw new WorkflowError('workflow_parse_error', `invalid YAML front matter: ${err.message}`);
49
+ }
50
+ if (parsed === null || parsed === undefined)
51
+ parsed = {};
52
+ if (typeof parsed !== 'object' || Array.isArray(parsed)) {
53
+ throw new WorkflowError('workflow_front_matter_not_a_map', 'YAML front matter must decode to a map');
54
+ }
55
+ return { config: parsed, body };
56
+ }
57
+ export async function loadWorkflow(workflowPath) {
58
+ let text;
59
+ try {
60
+ text = await readFile(workflowPath, 'utf8');
61
+ }
62
+ catch (err) {
63
+ throw new WorkflowError('missing_workflow_file', `cannot read ${workflowPath}: ${err.message}`);
64
+ }
65
+ const { config, body } = splitFrontMatter(text);
66
+ return { config, prompt_template: body };
67
+ }
68
+ // $VAR / ~ expansion for path/command fields (§6.1).
69
+ export function expandVar(value) {
70
+ if (typeof value !== 'string')
71
+ return value;
72
+ let s = value;
73
+ if (s.startsWith('~/') || s === '~') {
74
+ s = s === '~' ? os.homedir() : path.join(os.homedir(), s.slice(2));
75
+ }
76
+ const m = s.match(/^\$([A-Z_][A-Z0-9_]*)$/);
77
+ if (m) {
78
+ const envVal = process.env[m[1]];
79
+ return envVal ?? '';
80
+ }
81
+ return s;
82
+ }
83
+ function asString(v) {
84
+ if (typeof v === 'string')
85
+ return v;
86
+ return null;
87
+ }
88
+ function asInt(v, fallback) {
89
+ if (typeof v === 'number' && Number.isFinite(v))
90
+ return Math.trunc(v);
91
+ if (typeof v === 'string' && /^-?\d+$/.test(v))
92
+ return parseInt(v, 10);
93
+ return fallback;
94
+ }
95
+ function asStringList(v, fallback) {
96
+ if (Array.isArray(v))
97
+ return v.filter((x) => typeof x === 'string');
98
+ return fallback;
99
+ }
100
+ function asMapStrPosInt(v) {
101
+ const out = {};
102
+ if (v && typeof v === 'object' && !Array.isArray(v)) {
103
+ for (const [k, raw] of Object.entries(v)) {
104
+ const n = asInt(raw, 0);
105
+ if (n > 0)
106
+ out[k.toLowerCase()] = n;
107
+ }
108
+ }
109
+ return out;
110
+ }
111
+ function getObject(parent, key) {
112
+ const v = parent[key];
113
+ if (v && typeof v === 'object' && !Array.isArray(v))
114
+ return v;
115
+ return {};
116
+ }
117
+ // Build a fully typed ServiceConfig from a parsed front matter map (§6.1).
118
+ export function buildServiceConfig(raw, workflowPath) {
119
+ const workflowAbs = path.resolve(workflowPath);
120
+ const workflowDir = path.dirname(workflowAbs);
121
+ // tracker (§5.3.1)
122
+ const trackerRaw = getObject(raw, 'tracker');
123
+ const trackerKind = (asString(trackerRaw['kind']) ?? '').trim();
124
+ const apiKeyRaw = asString(trackerRaw['api_key']);
125
+ const apiKeyResolved = apiKeyRaw ? expandVar(apiKeyRaw) : null;
126
+ const trackerEndpointDefault = trackerKind === 'linear' ? 'https://api.linear.app/graphql' : null;
127
+ // local-tracker extension: optional `tracker.root` path.
128
+ const trackerRootRaw = asString(trackerRaw['root']);
129
+ let trackerRoot = null;
130
+ if (trackerRootRaw) {
131
+ const expanded = expandVar(trackerRootRaw);
132
+ if (expanded === '') {
133
+ throw new WorkflowError('workflow_parse_error', `tracker.root references an unset variable: ${trackerRootRaw}`);
134
+ }
135
+ trackerRoot = path.isAbsolute(expanded) ? expanded : path.resolve(workflowDir, expanded);
136
+ }
137
+ else if (trackerKind === 'local') {
138
+ // Default local tracker root: <workflow-dir>/issues
139
+ trackerRoot = path.resolve(workflowDir, 'issues');
140
+ }
141
+ const tracker = {
142
+ kind: trackerKind,
143
+ endpoint: asString(trackerRaw['endpoint']) ?? trackerEndpointDefault,
144
+ api_key: apiKeyResolved && apiKeyResolved.length > 0 ? apiKeyResolved : null,
145
+ project_slug: asString(trackerRaw['project_slug']),
146
+ active_states: asStringList(trackerRaw['active_states'], ['Todo', 'In Progress']),
147
+ terminal_states: asStringList(trackerRaw['terminal_states'], [
148
+ 'Closed',
149
+ 'Cancelled',
150
+ 'Canceled',
151
+ 'Duplicate',
152
+ 'Done',
153
+ ]),
154
+ root: trackerRoot,
155
+ };
156
+ // polling (§5.3.2)
157
+ const pollingRaw = getObject(raw, 'polling');
158
+ const polling = {
159
+ interval_ms: asInt(pollingRaw['interval_ms'], 30_000),
160
+ };
161
+ // workspace (§5.3.3)
162
+ const workspaceRaw = getObject(raw, 'workspace');
163
+ const wsRootInput = asString(workspaceRaw['root']);
164
+ let workspaceRoot;
165
+ if (wsRootInput) {
166
+ const expanded = expandVar(wsRootInput);
167
+ if (expanded === '') {
168
+ throw new WorkflowError('workflow_parse_error', `workspace.root references an unset variable: ${wsRootInput}`);
169
+ }
170
+ workspaceRoot = path.isAbsolute(expanded) ? expanded : path.resolve(workflowDir, expanded);
171
+ }
172
+ else {
173
+ workspaceRoot = path.join(os.tmpdir(), 'symphony_workspaces');
174
+ }
175
+ const workspace = { root: path.resolve(workspaceRoot) };
176
+ // hooks (§5.3.4)
177
+ const hooksRaw = getObject(raw, 'hooks');
178
+ const hooks = {
179
+ after_create: asString(hooksRaw['after_create']),
180
+ before_run: asString(hooksRaw['before_run']),
181
+ after_run: asString(hooksRaw['after_run']),
182
+ before_remove: asString(hooksRaw['before_remove']),
183
+ timeout_ms: asInt(hooksRaw['timeout_ms'], 60_000),
184
+ };
185
+ if (hooks.timeout_ms <= 0) {
186
+ throw new WorkflowError('workflow_parse_error', 'hooks.timeout_ms must be positive');
187
+ }
188
+ // agent (§5.3.5)
189
+ const agentRaw = getObject(raw, 'agent');
190
+ const maxTurns = asInt(agentRaw['max_turns'], 20);
191
+ if (maxTurns <= 0) {
192
+ throw new WorkflowError('workflow_parse_error', 'agent.max_turns must be positive');
193
+ }
194
+ const agent = {
195
+ max_concurrent_agents: asInt(agentRaw['max_concurrent_agents'], 10),
196
+ max_turns: maxTurns,
197
+ max_retry_backoff_ms: asInt(agentRaw['max_retry_backoff_ms'], 300_000),
198
+ max_concurrent_agents_by_state: asMapStrPosInt(agentRaw['max_concurrent_agents_by_state']),
199
+ };
200
+ // acp (Symphony extension; supersedes the §5.3.6 `codex` block). `adapter` selects
201
+ // one of symphony's known profiles (claude, codex). `command` is optional: when
202
+ // null/unset, symphony auto-derives the launch command from the adapter profile and
203
+ // stages the host credential file into the workspace. Override `command` only if
204
+ // you need a custom launch (testing a forked adapter, a non-default binary path,
205
+ // etc.) — overriding also opts out of credential staging.
206
+ const acpRaw = getObject(raw, 'acp');
207
+ const acp = {
208
+ adapter: asString(acpRaw['adapter']) ?? 'claude',
209
+ command: asString(acpRaw['command']),
210
+ shell: asString(acpRaw['shell']) ?? 'bash',
211
+ prompt_timeout_ms: asInt(acpRaw['prompt_timeout_ms'], 3_600_000),
212
+ read_timeout_ms: asInt(acpRaw['read_timeout_ms'], 30_000),
213
+ stall_timeout_ms: asInt(acpRaw['stall_timeout_ms'], 300_000),
214
+ };
215
+ // smolvm extension
216
+ const smolvmRaw = getObject(raw, 'smolvm');
217
+ const fromRaw = asString(smolvmRaw['from']);
218
+ let from = null;
219
+ if (fromRaw) {
220
+ const expanded = expandVar(fromRaw);
221
+ if (expanded === '') {
222
+ throw new WorkflowError('workflow_parse_error', `smolvm.from references an unset variable: ${fromRaw}`);
223
+ }
224
+ from = path.isAbsolute(expanded) ? expanded : path.resolve(workflowDir, expanded);
225
+ }
226
+ const volumesRaw = smolvmRaw['volumes'];
227
+ const volumes = Array.isArray(volumesRaw)
228
+ ? volumesRaw.flatMap((v) => {
229
+ if (!v || typeof v !== 'object' || Array.isArray(v))
230
+ return [];
231
+ const m = v;
232
+ const hostRaw = asString(m['host']);
233
+ const guest = asString(m['guest']);
234
+ if (!hostRaw || !guest)
235
+ return [];
236
+ const expandedHost = expandVar(hostRaw);
237
+ if (expandedHost === '')
238
+ return [];
239
+ const host = path.isAbsolute(expandedHost)
240
+ ? expandedHost
241
+ : path.resolve(workflowDir, expandedHost);
242
+ const readonly = m['readonly'] === true;
243
+ return [{ host, guest, readonly }];
244
+ })
245
+ : [];
246
+ const smolvm = {
247
+ image: asString(smolvmRaw['image']),
248
+ from,
249
+ cpus: asInt(smolvmRaw['cpus'], 2),
250
+ mem_mib: asInt(smolvmRaw['mem_mib'], 2048),
251
+ net: smolvmRaw['net'] !== false,
252
+ bin_path: asString(smolvmRaw['bin_path']),
253
+ volumes,
254
+ // Default forwarded credentials cover all three shipped ACP adapters so workflows that
255
+ // do not override `smolvm.forward_env` still authenticate after the default-adapter
256
+ // switch to claude-agent-acp.
257
+ forward_env: asStringList(smolvmRaw['forward_env'], [
258
+ 'OPENAI_API_KEY',
259
+ 'ANTHROPIC_API_KEY',
260
+ ]),
261
+ endpoint: asString(smolvmRaw['endpoint']) ??
262
+ `unix://${process.env.XDG_RUNTIME_DIR ?? '/run/user/1000'}/smolvm.sock`,
263
+ };
264
+ // server extension (§13.7)
265
+ const serverRaw = getObject(raw, 'server');
266
+ const server = {
267
+ port: typeof serverRaw['port'] === 'number' ? serverRaw['port'] : null,
268
+ host: asString(serverRaw['host']) ?? '127.0.0.1',
269
+ };
270
+ // mcp extension: per-issue MCP server (mark_done + request_human_steering tools) injected
271
+ // into each ACP session. `host` defaults to the QEMU slirp gateway; the port is the
272
+ // actually-bound HTTP server's port (resolved at runtime, not config-parse time, so
273
+ // `--port` and an unset server.port can never desync). `host_url` is an explicit full-URL
274
+ // override for cases where the VM can't reach the orchestrator via the host gateway.
275
+ const mcpRaw = getObject(raw, 'mcp');
276
+ const mcpEnabledRaw = mcpRaw['enabled'];
277
+ const mcpEnabled = mcpEnabledRaw === undefined ? true : mcpEnabledRaw !== false;
278
+ const mcp = {
279
+ enabled: mcpEnabled,
280
+ // 127.0.0.1 works for smolvm because its VM network intercepts loopback
281
+ // traffic and forwards it to the host's loopback. (Empirically verified;
282
+ // 10.0.2.2 — the QEMU slirp gateway — is NOT reachable here.) Other VMMs
283
+ // can override via the `host` field in the WORKFLOW.md mcp block.
284
+ host: asString(mcpRaw['host']) ?? '127.0.0.1',
285
+ explicit_host_url: asString(mcpRaw['host_url']),
286
+ };
287
+ return {
288
+ workflow_path: workflowAbs,
289
+ workflow_dir: workflowDir,
290
+ tracker,
291
+ polling,
292
+ workspace,
293
+ hooks,
294
+ agent,
295
+ acp,
296
+ smolvm,
297
+ server,
298
+ mcp,
299
+ };
300
+ }
301
+ // §6.3 dispatch preflight validation.
302
+ export function validateDispatch(cfg) {
303
+ if (!cfg.tracker.kind)
304
+ return 'tracker.kind is required';
305
+ if (cfg.tracker.kind !== 'linear' && cfg.tracker.kind !== 'local') {
306
+ return `unsupported_tracker_kind: ${cfg.tracker.kind}`;
307
+ }
308
+ if (cfg.tracker.kind === 'linear') {
309
+ if (!cfg.tracker.api_key)
310
+ return 'missing_tracker_api_key';
311
+ if (!cfg.tracker.project_slug)
312
+ return 'missing_tracker_project_slug';
313
+ }
314
+ if (cfg.tracker.kind === 'local') {
315
+ if (!cfg.tracker.root)
316
+ return 'tracker.root must be set for local tracker';
317
+ if (!existsSync(cfg.tracker.root) || !statSync(cfg.tracker.root).isDirectory()) {
318
+ return `tracker.root not found or not a directory: ${cfg.tracker.root}`;
319
+ }
320
+ }
321
+ // When acp.command is explicitly set, the operator owns the launch (and credential
322
+ // staging). Otherwise the adapter id must be one symphony has a profile for, so
323
+ // the runner can auto-derive the command and ship credentials.
324
+ if (cfg.acp.command !== null) {
325
+ if (!cfg.acp.command.trim())
326
+ return 'acp.command must be non-empty when set';
327
+ }
328
+ else if (!isKnownAdapter(cfg.acp.adapter)) {
329
+ return `acp.adapter "${cfg.acp.adapter}" is not a known profile; set acp.command to override or use one of: claude, codex`;
330
+ }
331
+ return null;
332
+ }
333
+ // Build + watch a workflow source. Throws on initial load failure.
334
+ export async function watchWorkflow(workflowPath) {
335
+ const workflowAbs = path.resolve(workflowPath);
336
+ const initialDef = await loadWorkflow(workflowAbs);
337
+ const initialCfg = buildServiceConfig(initialDef.config, workflowAbs);
338
+ let current = { definition: initialDef, config: initialCfg };
339
+ const listeners = new Set();
340
+ const watcher = chokidar.watch(workflowAbs, {
341
+ ignoreInitial: true,
342
+ persistent: true,
343
+ });
344
+ let reloadInFlight = null;
345
+ const reload = async () => {
346
+ if (reloadInFlight)
347
+ return reloadInFlight;
348
+ reloadInFlight = (async () => {
349
+ try {
350
+ const def = await loadWorkflow(workflowAbs);
351
+ const cfg = buildServiceConfig(def.config, workflowAbs);
352
+ current = { definition: def, config: cfg };
353
+ log.info('workflow reloaded', { path: workflowAbs });
354
+ for (const cb of listeners)
355
+ cb({ definition: def, config: cfg });
356
+ }
357
+ catch (err) {
358
+ const e = err instanceof WorkflowError
359
+ ? err
360
+ : new WorkflowError('workflow_parse_error', err.message);
361
+ log.warn('workflow reload failed; keeping last good config', { error: e.message, code: e.code });
362
+ for (const cb of listeners)
363
+ cb({ error: e });
364
+ }
365
+ finally {
366
+ reloadInFlight = null;
367
+ }
368
+ })();
369
+ return reloadInFlight;
370
+ };
371
+ watcher.on('change', () => void reload());
372
+ watcher.on('add', () => void reload());
373
+ // §5.5: workflow read errors must block dispatch. If the file is deleted or temporarily
374
+ // renamed, surface a missing_workflow_file error so the orchestrator knows.
375
+ watcher.on('unlink', () => void reload());
376
+ return {
377
+ current: () => current,
378
+ onChange: (cb) => {
379
+ listeners.add(cb);
380
+ return () => listeners.delete(cb);
381
+ },
382
+ stop: () => watcher.close(),
383
+ };
384
+ }
385
+ //# sourceMappingURL=workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,196 @@
1
+ // Workspace manager (SPEC §9). Per-issue workspace dirs under workspace.root.
2
+ //
3
+ // Safety invariants enforced:
4
+ // 1. Workspace path is rooted at workspace.root (containment check).
5
+ // 2. Workspace key is sanitized — only [A-Za-z0-9._-] allowed.
6
+ // 3. Agent cwd MUST equal the workspace path (enforced by callers via runWithCwd).
7
+ import { mkdir, rm, lstat } from 'node:fs/promises';
8
+ import path from 'node:path';
9
+ import { spawn } from 'node:child_process';
10
+ export class WorkspaceError extends Error {
11
+ code;
12
+ constructor(code, message) {
13
+ super(message);
14
+ this.code = code;
15
+ this.name = 'WorkspaceError';
16
+ }
17
+ }
18
+ // §9.5 Invariant 3.
19
+ export function sanitizeWorkspaceKey(identifier) {
20
+ return identifier.replace(/[^A-Za-z0-9._-]/g, '_');
21
+ }
22
+ // §9.5 Invariant 2: workspace path MUST be contained within workspace root.
23
+ //
24
+ // We deliberately check for a `..` path component rather than a `..` prefix on the
25
+ // relative path: an identifier like `..fix` sanitizes to a perfectly contained child
26
+ // directory whose relative path begins with the two-character substring `..` but does
27
+ // not actually escape the root.
28
+ export function assertContained(workspaceRoot, candidate) {
29
+ const rootAbs = path.resolve(workspaceRoot);
30
+ const candAbs = path.resolve(candidate);
31
+ if (candAbs === rootAbs) {
32
+ throw new WorkspaceError('invalid_workspace_path', `workspace path must not equal workspace root (${rootAbs})`);
33
+ }
34
+ const rel = path.relative(rootAbs, candAbs);
35
+ if (rel === '' || path.isAbsolute(rel)) {
36
+ throw new WorkspaceError('invalid_workspace_path', `workspace path ${candAbs} is not contained within ${rootAbs}`);
37
+ }
38
+ const parts = rel.split(path.sep);
39
+ if (parts.some((p) => p === '..')) {
40
+ throw new WorkspaceError('invalid_workspace_path', `workspace path ${candAbs} is not contained within ${rootAbs}`);
41
+ }
42
+ }
43
+ // A hook failed when it timed out, exited with a non-zero status, or was terminated by a
44
+ // signal. The signal-termination case is important — otherwise a fatal `before_run` script
45
+ // that calls `kill -TERM $$` would look successful (exit_code=null, timed_out=false).
46
+ function hookFailed(res) {
47
+ return res.timed_out || res.signal !== null || res.exit_code !== 0;
48
+ }
49
+ function hookFailureReason(res) {
50
+ if (res.timed_out)
51
+ return 'timed out';
52
+ if (res.signal !== null)
53
+ return `terminated by signal ${res.signal}`;
54
+ return `exited with code ${res.exit_code}`;
55
+ }
56
+ // Execute a hook script (POSIX `sh -lc`). Returns result so callers can decide on failure
57
+ // semantics (§9.4).
58
+ export async function runHookScript(script, cwd, timeoutMs) {
59
+ return new Promise((resolve) => {
60
+ const child = spawn('sh', ['-lc', script], {
61
+ cwd,
62
+ stdio: ['ignore', 'pipe', 'pipe'],
63
+ env: process.env,
64
+ });
65
+ let stdout = '';
66
+ let stderr = '';
67
+ let timedOut = false;
68
+ child.stdout?.on('data', (b) => {
69
+ stdout += b.toString('utf8');
70
+ if (stdout.length > 65_536)
71
+ stdout = stdout.slice(0, 65_536);
72
+ });
73
+ child.stderr?.on('data', (b) => {
74
+ stderr += b.toString('utf8');
75
+ if (stderr.length > 65_536)
76
+ stderr = stderr.slice(0, 65_536);
77
+ });
78
+ const t = setTimeout(() => {
79
+ timedOut = true;
80
+ child.kill('SIGKILL');
81
+ }, timeoutMs);
82
+ child.on('error', () => {
83
+ clearTimeout(t);
84
+ resolve({ ran: true, exit_code: null, signal: null, timed_out: timedOut, stdout, stderr });
85
+ });
86
+ child.on('close', (code, signal) => {
87
+ clearTimeout(t);
88
+ resolve({
89
+ ran: true,
90
+ exit_code: code,
91
+ signal: signal ?? null,
92
+ timed_out: timedOut,
93
+ stdout,
94
+ stderr,
95
+ });
96
+ });
97
+ });
98
+ }
99
+ export class WorkspaceManager {
100
+ cfg;
101
+ constructor(cfg) {
102
+ this.cfg = cfg;
103
+ }
104
+ updateConfig(cfg) {
105
+ this.cfg = cfg;
106
+ }
107
+ workspacePathFor(identifier) {
108
+ const key = sanitizeWorkspaceKey(identifier);
109
+ if (key.length === 0) {
110
+ throw new WorkspaceError('invalid_workspace_key', `cannot sanitize identifier: ${identifier}`);
111
+ }
112
+ return path.join(this.cfg.workspace.root, key);
113
+ }
114
+ // Ensure the per-issue workspace directory exists. Runs after_create when created_now.
115
+ async ensureFor(identifier) {
116
+ const workspaceRoot = this.cfg.workspace.root;
117
+ await mkdir(workspaceRoot, { recursive: true });
118
+ const wsPath = this.workspacePathFor(identifier);
119
+ assertContained(workspaceRoot, wsPath);
120
+ let createdNow = false;
121
+ try {
122
+ // Use lstat so symlinks at the workspace path are rejected: a symlink could redirect
123
+ // hook execution and the returned cwd outside the workspace root, which violates the
124
+ // §9.5 containment invariant.
125
+ const st = await lstat(wsPath);
126
+ if (st.isSymbolicLink()) {
127
+ throw new WorkspaceError('workspace_path_is_symlink', `workspace path ${wsPath} is a symlink; refusing to use`);
128
+ }
129
+ if (!st.isDirectory()) {
130
+ throw new WorkspaceError('workspace_path_not_directory', `expected directory at ${wsPath}, found a non-directory`);
131
+ }
132
+ }
133
+ catch (err) {
134
+ if (err.code === 'ENOENT') {
135
+ await mkdir(wsPath, { recursive: true });
136
+ createdNow = true;
137
+ }
138
+ else {
139
+ throw err;
140
+ }
141
+ }
142
+ if (createdNow && this.cfg.hooks.after_create) {
143
+ const res = await runHookScript(this.cfg.hooks.after_create, wsPath, this.cfg.hooks.timeout_ms);
144
+ if (hookFailed(res)) {
145
+ // §9.4: after_create failure is fatal — also unwind the partially prepared directory.
146
+ try {
147
+ await rm(wsPath, { recursive: true, force: true });
148
+ }
149
+ catch {
150
+ // Best-effort cleanup.
151
+ }
152
+ throw new WorkspaceError('after_create_failed', `after_create hook ${hookFailureReason(res)}`);
153
+ }
154
+ }
155
+ return {
156
+ path: wsPath,
157
+ workspace_key: sanitizeWorkspaceKey(identifier),
158
+ created_now: createdNow,
159
+ };
160
+ }
161
+ // Run before_run; throw on failure/timeout (§9.4).
162
+ async runBeforeRun(workspacePath, hooks) {
163
+ if (!hooks.before_run)
164
+ return;
165
+ const res = await runHookScript(hooks.before_run, workspacePath, hooks.timeout_ms);
166
+ if (hookFailed(res)) {
167
+ throw new WorkspaceError('before_run_failed', `before_run hook ${hookFailureReason(res)}`);
168
+ }
169
+ }
170
+ // Best-effort after_run hook (§9.4: failure logged and ignored — caller logs).
171
+ async runAfterRunBestEffort(workspacePath, hooks) {
172
+ if (!hooks.after_run)
173
+ return null;
174
+ return runHookScript(hooks.after_run, workspacePath, hooks.timeout_ms);
175
+ }
176
+ // Best-effort before_remove + filesystem removal (§9.4).
177
+ async remove(identifier, hooks) {
178
+ const wsPath = this.workspacePathFor(identifier);
179
+ assertContained(this.cfg.workspace.root, wsPath);
180
+ let hookResult = null;
181
+ try {
182
+ const st = await lstat(wsPath);
183
+ if (st.isSymbolicLink() || !st.isDirectory())
184
+ return null;
185
+ }
186
+ catch {
187
+ return null;
188
+ }
189
+ if (hooks.before_remove) {
190
+ hookResult = await runHookScript(hooks.before_remove, wsPath, hooks.timeout_ms);
191
+ }
192
+ await rm(wsPath, { recursive: true, force: true });
193
+ return hookResult;
194
+ }
195
+ }
196
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}