@wildorder/nightshift 0.12.0 → 0.14.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/README.md +46 -19
- package/dist/agent-probe.d.ts +21 -2
- package/dist/agent-probe.d.ts.map +1 -1
- package/dist/agent-probe.js +76 -22
- package/dist/agent-probe.js.map +1 -1
- package/dist/agent-runner.d.ts +90 -2
- package/dist/agent-runner.d.ts.map +1 -1
- package/dist/agent-runner.js +382 -24
- package/dist/agent-runner.js.map +1 -1
- package/dist/agent-summary.d.ts +15 -0
- package/dist/agent-summary.d.ts.map +1 -1
- package/dist/agent-summary.js +32 -2
- package/dist/agent-summary.js.map +1 -1
- package/dist/as-built.d.ts +6 -0
- package/dist/as-built.d.ts.map +1 -1
- package/dist/as-built.js +7 -0
- package/dist/as-built.js.map +1 -1
- package/dist/author.d.ts +9 -0
- package/dist/author.d.ts.map +1 -1
- package/dist/author.js +161 -24
- package/dist/author.js.map +1 -1
- package/dist/ci-init.d.ts.map +1 -1
- package/dist/ci-init.js +17 -12
- package/dist/ci-init.js.map +1 -1
- package/dist/cli.js +144 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/crash-report.d.ts +58 -0
- package/dist/crash-report.d.ts.map +1 -0
- package/dist/crash-report.js +115 -0
- package/dist/crash-report.js.map +1 -0
- package/dist/decide.js +1 -1
- package/dist/decide.js.map +1 -1
- package/dist/decider-review.d.ts +33 -5
- package/dist/decider-review.d.ts.map +1 -1
- package/dist/decider-review.js +55 -9
- package/dist/decider-review.js.map +1 -1
- package/dist/decision-ledger.d.ts +54 -1
- package/dist/decision-ledger.d.ts.map +1 -1
- package/dist/decision-ledger.js +53 -1
- package/dist/decision-ledger.js.map +1 -1
- package/dist/decision-view.d.ts +10 -1
- package/dist/decision-view.d.ts.map +1 -1
- package/dist/decision-view.js +41 -0
- package/dist/decision-view.js.map +1 -1
- package/dist/exit-codes.d.ts +16 -2
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +17 -2
- package/dist/exit-codes.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +68 -14
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +301 -22
- package/dist/manifest.js.map +1 -1
- package/dist/permits.d.ts +135 -0
- package/dist/permits.d.ts.map +1 -0
- package/dist/permits.js +397 -0
- package/dist/permits.js.map +1 -0
- package/dist/preflight.d.ts +73 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +225 -0
- package/dist/preflight.js.map +1 -0
- package/dist/publish.d.ts +71 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +319 -1
- package/dist/publish.js.map +1 -1
- package/dist/run-program.d.ts +70 -2
- package/dist/run-program.d.ts.map +1 -1
- package/dist/run-program.js +677 -60
- package/dist/run-program.js.map +1 -1
- package/dist/skill-roots.d.ts +11 -3
- package/dist/skill-roots.d.ts.map +1 -1
- package/dist/skill-roots.js +59 -12
- package/dist/skill-roots.js.map +1 -1
- package/dist/whole-program-review.d.ts +4 -0
- package/dist/whole-program-review.d.ts.map +1 -1
- package/dist/whole-program-review.js +9 -1
- package/dist/whole-program-review.js.map +1 -1
- package/package.json +2 -2
- package/skills/plan-program/SKILL.md +125 -5
- package/dist/verify-allowlist.d.ts +0 -23
- package/dist/verify-allowlist.d.ts.map +0 -1
- package/dist/verify-allowlist.js +0 -46
- package/dist/verify-allowlist.js.map +0 -1
package/dist/permits.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { rmSync } from "node:fs";
|
|
3
|
+
import { rm as nodeRm, writeFile as nodeWriteFile } from "node:fs/promises";
|
|
4
|
+
import { platform as osPlatform, tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import crossSpawn from "cross-spawn";
|
|
7
|
+
/**
|
|
8
|
+
* Fixed per-role postures — mirrors the write/exec split `agent-probe.ts`
|
|
9
|
+
* already encoded as WRITE_ROLES/EXEC_ROLES. Exported so the probe sources
|
|
10
|
+
* its write/read split from here rather than keeping a second copy that can
|
|
11
|
+
* drift.
|
|
12
|
+
*/
|
|
13
|
+
export const ROLE_POSTURE = {
|
|
14
|
+
agent: "workspace",
|
|
15
|
+
recoveryAgent: "workspace",
|
|
16
|
+
authorAgent: "workspace",
|
|
17
|
+
deciderAgent: "read-only",
|
|
18
|
+
reviewerAgent: "read-only",
|
|
19
|
+
};
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Explicit flags win (SC-05)
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const CLAUDE_PERMISSION_FLAGS = [
|
|
24
|
+
"--permission-mode",
|
|
25
|
+
"--allowedTools",
|
|
26
|
+
"--allowed-tools",
|
|
27
|
+
"--disallowedTools",
|
|
28
|
+
"--dangerously-skip-permissions",
|
|
29
|
+
"--settings",
|
|
30
|
+
];
|
|
31
|
+
const CODEX_SANDBOX_FLAG = "--sandbox";
|
|
32
|
+
function permissionFlagsFor(command) {
|
|
33
|
+
if (command === "claude")
|
|
34
|
+
return CLAUDE_PERMISSION_FLAGS;
|
|
35
|
+
if (command === "codex")
|
|
36
|
+
return [CODEX_SANDBOX_FLAG];
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Command transcript observability (WS-02)
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
const OUTPUT_FORMAT_FLAG = "--output-format";
|
|
43
|
+
/** True when the agent's own args already pin an output format — an operator
|
|
44
|
+
* who chose one (stream-json or otherwise) keeps it untouched. */
|
|
45
|
+
function hasOutputFormatFlag(agent) {
|
|
46
|
+
return agent.args.some((arg) => {
|
|
47
|
+
const token = arg.includes("=") ? arg.slice(0, arg.indexOf("=")) : arg;
|
|
48
|
+
return token === OUTPUT_FORMAT_FLAG;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The two flags that turn a Claude spawn's stdout into the NDJSON stream
|
|
53
|
+
* `src/agent-runner.ts`'s demultiplexer reads (WS-02). `--verbose` is
|
|
54
|
+
* required alongside `--output-format stream-json`: in print mode the CLI
|
|
55
|
+
* emits only the final result event unless `--verbose` is set, and the
|
|
56
|
+
* demultiplexer needs the intermediate `tool_use` events. Empty when the
|
|
57
|
+
* agent already pins its own output format — this derivation only adds
|
|
58
|
+
* flags, it never overrides one an operator wrote.
|
|
59
|
+
*/
|
|
60
|
+
function observabilityFlags(agent) {
|
|
61
|
+
return hasOutputFormatFlag(agent) ? [] : [OUTPUT_FORMAT_FLAG, "stream-json", "--verbose"];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* True when the agent's own args already carry a permission-bearing flag —
|
|
65
|
+
* `--flag value` and `--flag=value` both match. An agent that trips this is
|
|
66
|
+
* spawned untouched and labeled operator-configured; rewriting an operator's
|
|
67
|
+
* authored flags is the override the charter forbids.
|
|
68
|
+
*/
|
|
69
|
+
export function hasExplicitPermissionFlag(agent) {
|
|
70
|
+
const flags = permissionFlagsFor(agent.command);
|
|
71
|
+
if (flags.length === 0)
|
|
72
|
+
return false;
|
|
73
|
+
return agent.args.some((arg) => {
|
|
74
|
+
const token = arg.includes("=") ? arg.slice(0, arg.indexOf("=")) : arg;
|
|
75
|
+
return flags.includes(token);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// permits config -> settings file content
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/** One `--allowedTools`/settings allow entry per configured verify command. Relocated from verify-allowlist.ts. */
|
|
82
|
+
export function claudeVerifyAllowedTools(verify) {
|
|
83
|
+
return Object.values(verify).map((command) => `Bash(${command}:*)`);
|
|
84
|
+
}
|
|
85
|
+
function baseAllowDeny(verify, permits) {
|
|
86
|
+
return {
|
|
87
|
+
allow: [...claudeVerifyAllowedTools(verify), ...(permits?.allow ?? [])],
|
|
88
|
+
deny: [...(permits?.deny ?? [])],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** The workspace settings file: verify rules + permits.allow/deny, plus a sandbox block on darwin/linux. */
|
|
92
|
+
export function workspaceSettingsContent(verify, permits, platform) {
|
|
93
|
+
const { allow, deny } = baseAllowDeny(verify, permits);
|
|
94
|
+
const settings = { permissions: { allow, deny } };
|
|
95
|
+
if (platform === "darwin" || platform === "linux") {
|
|
96
|
+
settings.sandbox = { enabled: true, autoAllowBashIfSandboxed: true };
|
|
97
|
+
}
|
|
98
|
+
return JSON.stringify(settings, null, 2);
|
|
99
|
+
}
|
|
100
|
+
/** The read-only settings file: same allow/deny lists, never a sandbox block. */
|
|
101
|
+
export function readOnlySettingsContent(verify, permits) {
|
|
102
|
+
const { allow, deny } = baseAllowDeny(verify, permits);
|
|
103
|
+
return JSON.stringify({ permissions: { allow, deny } }, null, 2);
|
|
104
|
+
}
|
|
105
|
+
const UNDETECTED_CAPABILITIES = {
|
|
106
|
+
detected: false,
|
|
107
|
+
autoMode: false,
|
|
108
|
+
dontAskMode: false,
|
|
109
|
+
permissionPrompts: false,
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Turns a finished `--help` spawn into its text or a rejection. Exported so
|
|
113
|
+
* the nonzero-exit-code case (a `claude` on PATH that fails, rather than a
|
|
114
|
+
* missing command) is unit-testable without an actual child process: a
|
|
115
|
+
* nonzero exit must be reported as a detection failure, never parsed as if
|
|
116
|
+
* it were successful help output.
|
|
117
|
+
*/
|
|
118
|
+
export function helpRunnerOutcome(code, output) {
|
|
119
|
+
if (code === 0)
|
|
120
|
+
return output;
|
|
121
|
+
throw new Error(`claude --help exited with code ${code ?? "null"}: ${output.slice(0, 500)}`);
|
|
122
|
+
}
|
|
123
|
+
export const defaultClaudeHelpRunner = (command) => new Promise((resolvePromise, rejectPromise) => {
|
|
124
|
+
let output = "";
|
|
125
|
+
const child = crossSpawn(command, ["--help"], {
|
|
126
|
+
windowsHide: true,
|
|
127
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
128
|
+
});
|
|
129
|
+
child.stdout?.setEncoding("utf8");
|
|
130
|
+
child.stderr?.setEncoding("utf8");
|
|
131
|
+
child.stdout?.on("data", (chunk) => (output += chunk));
|
|
132
|
+
child.stderr?.on("data", (chunk) => (output += chunk));
|
|
133
|
+
child.on("error", rejectPromise);
|
|
134
|
+
child.on("close", (code) => {
|
|
135
|
+
try {
|
|
136
|
+
resolvePromise(helpRunnerOutcome(code, output));
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
rejectPromise(error);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
/** The `--permission-mode` option's own text, up to the next `--flag` line. */
|
|
144
|
+
function optionBlock(helpText, flag) {
|
|
145
|
+
const idx = helpText.indexOf(flag);
|
|
146
|
+
if (idx === -1)
|
|
147
|
+
return "";
|
|
148
|
+
const rest = helpText.slice(idx + flag.length);
|
|
149
|
+
const stop = rest.match(/\n[^\S\r\n]*--/u);
|
|
150
|
+
return stop?.index === undefined ? rest : rest.slice(0, stop.index);
|
|
151
|
+
}
|
|
152
|
+
/** Parses `claude --help` text into capabilities. Exported for fixture-driven tests. */
|
|
153
|
+
export function parseClaudeHelp(helpText) {
|
|
154
|
+
const modeBlock = optionBlock(helpText, "--permission-mode");
|
|
155
|
+
return {
|
|
156
|
+
detected: true,
|
|
157
|
+
autoMode: /"auto"/u.test(modeBlock),
|
|
158
|
+
dontAskMode: /"dontAsk"/u.test(modeBlock),
|
|
159
|
+
permissionPrompts: /--permission-prompts\b/u.test(helpText),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Detects once per process per resolved command string, caching the promise
|
|
164
|
+
* so concurrent derivations for the same command share one spawn. Detection
|
|
165
|
+
* failure (not on PATH, a throwing help runner) is reported as
|
|
166
|
+
* `detected: false`, never thrown — the derivation then takes the fallback.
|
|
167
|
+
*/
|
|
168
|
+
const capabilityCache = new Map();
|
|
169
|
+
export function detectClaudeCapabilities(command, helpRunner = defaultClaudeHelpRunner) {
|
|
170
|
+
let cached = capabilityCache.get(command);
|
|
171
|
+
if (!cached) {
|
|
172
|
+
cached = helpRunner(command).then(parseClaudeHelp).catch(() => UNDETECTED_CAPABILITIES);
|
|
173
|
+
capabilityCache.set(command, cached);
|
|
174
|
+
}
|
|
175
|
+
return cached;
|
|
176
|
+
}
|
|
177
|
+
/** Test-only: clears the process-wide capability cache between fixture scenarios. */
|
|
178
|
+
export function resetClaudeCapabilityCacheForTests() {
|
|
179
|
+
capabilityCache.clear();
|
|
180
|
+
}
|
|
181
|
+
function deriveClaude(input) {
|
|
182
|
+
const { agent, role, containmentEnv, platform, claudeCapabilities, workspaceSettingsPath, readOnlySettingsPath } = input;
|
|
183
|
+
const posture = ROLE_POSTURE[role];
|
|
184
|
+
const caps = claudeCapabilities ?? UNDETECTED_CAPABILITIES;
|
|
185
|
+
const observability = observabilityFlags(agent);
|
|
186
|
+
if (posture === "read-only") {
|
|
187
|
+
if (caps.dontAskMode) {
|
|
188
|
+
const args = [...agent.args, "--permission-mode", "dontAsk", "--settings", readOnlySettingsPath];
|
|
189
|
+
if (caps.permissionPrompts)
|
|
190
|
+
args.push("--permission-prompts", "none");
|
|
191
|
+
args.push(...observability);
|
|
192
|
+
return {
|
|
193
|
+
agent: { ...agent, args },
|
|
194
|
+
label: "read-only",
|
|
195
|
+
operatorConfigured: false,
|
|
196
|
+
settingsPath: readOnlySettingsPath,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const args = [
|
|
200
|
+
...agent.args,
|
|
201
|
+
"--permission-mode",
|
|
202
|
+
"default",
|
|
203
|
+
"--settings",
|
|
204
|
+
readOnlySettingsPath,
|
|
205
|
+
...observability,
|
|
206
|
+
];
|
|
207
|
+
return {
|
|
208
|
+
agent: { ...agent, args },
|
|
209
|
+
label: caps.detected ? "read-only fallback (default+verify)" : "read-only fallback (detection failed)",
|
|
210
|
+
operatorConfigured: false,
|
|
211
|
+
settingsPath: readOnlySettingsPath,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// workspace posture
|
|
215
|
+
if (containmentEnv === "ephemeral") {
|
|
216
|
+
const args = [
|
|
217
|
+
...agent.args,
|
|
218
|
+
"--dangerously-skip-permissions",
|
|
219
|
+
"--settings",
|
|
220
|
+
workspaceSettingsPath,
|
|
221
|
+
...observability,
|
|
222
|
+
];
|
|
223
|
+
return {
|
|
224
|
+
agent: { ...agent, args },
|
|
225
|
+
label: "ephemeral",
|
|
226
|
+
operatorConfigured: false,
|
|
227
|
+
settingsPath: workspaceSettingsPath,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (caps.autoMode) {
|
|
231
|
+
const args = [...agent.args, "--permission-mode", "auto", "--settings", workspaceSettingsPath];
|
|
232
|
+
if (caps.permissionPrompts)
|
|
233
|
+
args.push("--permission-prompts", "none");
|
|
234
|
+
args.push(...observability);
|
|
235
|
+
const sandboxed = platform === "darwin" || platform === "linux";
|
|
236
|
+
return {
|
|
237
|
+
agent: { ...agent, args },
|
|
238
|
+
label: sandboxed ? "auto+sandbox" : "auto",
|
|
239
|
+
operatorConfigured: false,
|
|
240
|
+
settingsPath: workspaceSettingsPath,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const args = [
|
|
244
|
+
...agent.args,
|
|
245
|
+
"--permission-mode",
|
|
246
|
+
"acceptEdits",
|
|
247
|
+
"--settings",
|
|
248
|
+
workspaceSettingsPath,
|
|
249
|
+
...observability,
|
|
250
|
+
];
|
|
251
|
+
return {
|
|
252
|
+
agent: { ...agent, args },
|
|
253
|
+
label: caps.detected ? "fallback (acceptEdits+verify)" : "fallback (detection failed)",
|
|
254
|
+
operatorConfigured: false,
|
|
255
|
+
settingsPath: workspaceSettingsPath,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
const CODEX_DENY_NOTE = "codex has no per-command deny rules; permits.deny does not bind on this seat.";
|
|
259
|
+
function deriveCodex(input) {
|
|
260
|
+
const { agent, role, containmentEnv, platform } = input;
|
|
261
|
+
const posture = ROLE_POSTURE[role];
|
|
262
|
+
if (posture === "read-only") {
|
|
263
|
+
// Said explicitly, never assumed: `codex exec` ships read-only by
|
|
264
|
+
// default, but a user config can widen that default (a Windows
|
|
265
|
+
// `sandbox = "elevated"` setting, a trusted-project entry), and a seat
|
|
266
|
+
// labeled read-only that can write is the legibility failure this
|
|
267
|
+
// module exists to prevent. Independent of containment — a read-only
|
|
268
|
+
// seat has no reason to escalate on an ephemeral host either.
|
|
269
|
+
const args = [...agent.args, "--sandbox", "read-only"];
|
|
270
|
+
return { agent: { ...agent, args }, label: "read-only", operatorConfigured: false, note: CODEX_DENY_NOTE };
|
|
271
|
+
}
|
|
272
|
+
if (containmentEnv === "ephemeral") {
|
|
273
|
+
// Left at its own sandbox — an ephemeral host has no reason to escalate
|
|
274
|
+
// codex further, and codex ships no skip-permissions equivalent.
|
|
275
|
+
return { agent, label: "ephemeral", operatorConfigured: false, note: CODEX_DENY_NOTE };
|
|
276
|
+
}
|
|
277
|
+
const args = [...agent.args, "--sandbox", "workspace-write"];
|
|
278
|
+
const sandboxed = platform === "darwin" || platform === "linux";
|
|
279
|
+
return {
|
|
280
|
+
agent: { ...agent, args },
|
|
281
|
+
label: sandboxed ? "auto+sandbox" : "auto",
|
|
282
|
+
operatorConfigured: false,
|
|
283
|
+
note: CODEX_DENY_NOTE,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The whole derivation, pure: role + posture + containment + capabilities +
|
|
288
|
+
* the agent's existing args -> the flags to spawn with. No I/O — capability
|
|
289
|
+
* detection and the settings-file write happen in the context builder below.
|
|
290
|
+
*/
|
|
291
|
+
export function deriveAgentInvocation(input) {
|
|
292
|
+
if (hasExplicitPermissionFlag(input.agent)) {
|
|
293
|
+
return { agent: input.agent, label: "operator-configured", operatorConfigured: true };
|
|
294
|
+
}
|
|
295
|
+
if (input.agent.command === "claude")
|
|
296
|
+
return deriveClaude(input);
|
|
297
|
+
if (input.agent.command === "codex")
|
|
298
|
+
return deriveCodex(input);
|
|
299
|
+
// Any other provider: no known flag vocabulary — deriving the wrong flag
|
|
300
|
+
// is worse than deriving none.
|
|
301
|
+
return { agent: input.agent, label: "unmanaged", operatorConfigured: false };
|
|
302
|
+
}
|
|
303
|
+
const realPermitsFs = {
|
|
304
|
+
writeFile: (path, content) => nodeWriteFile(path, content, "utf8"),
|
|
305
|
+
rm: (path) => nodeRm(path, { force: true }),
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* Settings files written by contexts that have not been disposed yet. One
|
|
309
|
+
* exit hook, registered on first use, removes them synchronously — the only
|
|
310
|
+
* kind of work an `exit` handler can do — so a run that crashes mid-way, a
|
|
311
|
+
* test process, or a command that never reaches its own dispose still leaves
|
|
312
|
+
* the temp directory as it found it.
|
|
313
|
+
*/
|
|
314
|
+
const undisposedSettingsPaths = new Set();
|
|
315
|
+
let exitHookRegistered = false;
|
|
316
|
+
function registerExitCleanup() {
|
|
317
|
+
if (exitHookRegistered)
|
|
318
|
+
return;
|
|
319
|
+
exitHookRegistered = true;
|
|
320
|
+
process.on("exit", () => {
|
|
321
|
+
for (const path of undisposedSettingsPaths) {
|
|
322
|
+
try {
|
|
323
|
+
rmSync(path, { force: true });
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// Best effort at exit; nothing useful can be reported from here.
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
undisposedSettingsPaths.clear();
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Builds the run's (or doctor probe's, or as-built refresh's) one
|
|
334
|
+
* `PermitsContext`: writes the two settings files once under `os.tmpdir()`
|
|
335
|
+
* and returns a `derive` function that detects claude's capabilities on
|
|
336
|
+
* first use per command string and applies the pure derivation above.
|
|
337
|
+
*/
|
|
338
|
+
export async function buildPermitsContext(options) {
|
|
339
|
+
const platform = options.platform ?? osPlatform();
|
|
340
|
+
const containmentEnv = options.containmentEnv ?? process.env.NIGHTSHIFT_CONTAINMENT;
|
|
341
|
+
const helpRunner = options.helpRunner ?? defaultClaudeHelpRunner;
|
|
342
|
+
const fs = options.fs ?? realPermitsFs;
|
|
343
|
+
const nonce = randomBytes(4).toString("hex");
|
|
344
|
+
const workspaceSettingsPath = join(tmpdir(), `nightshift-permits-${nonce}-workspace.json`);
|
|
345
|
+
const readOnlySettingsPath = join(tmpdir(), `nightshift-permits-${nonce}-read-only.json`);
|
|
346
|
+
await fs.writeFile(workspaceSettingsPath, workspaceSettingsContent(options.config.verify, options.config.permits, platform));
|
|
347
|
+
await fs.writeFile(readOnlySettingsPath, readOnlySettingsContent(options.config.verify, options.config.permits));
|
|
348
|
+
// Only real files are tracked for exit cleanup; an injected fake fs wrote
|
|
349
|
+
// nowhere the hook could (or should) remove.
|
|
350
|
+
const tracked = options.fs === undefined;
|
|
351
|
+
if (tracked) {
|
|
352
|
+
registerExitCleanup();
|
|
353
|
+
undisposedSettingsPaths.add(workspaceSettingsPath);
|
|
354
|
+
undisposedSettingsPaths.add(readOnlySettingsPath);
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
workspaceSettingsPath,
|
|
358
|
+
readOnlySettingsPath,
|
|
359
|
+
async dispose() {
|
|
360
|
+
for (const path of [workspaceSettingsPath, readOnlySettingsPath]) {
|
|
361
|
+
undisposedSettingsPaths.delete(path);
|
|
362
|
+
await fs.rm?.(path);
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
async derive(role, agent) {
|
|
366
|
+
const claudeCapabilities = agent.command === "claude" ? await detectClaudeCapabilities(agent.command, helpRunner) : undefined;
|
|
367
|
+
return deriveAgentInvocation({
|
|
368
|
+
role,
|
|
369
|
+
agent,
|
|
370
|
+
containmentEnv,
|
|
371
|
+
platform,
|
|
372
|
+
claudeCapabilities,
|
|
373
|
+
workspaceSettingsPath,
|
|
374
|
+
readOnlySettingsPath,
|
|
375
|
+
});
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* A context that appends nothing and detects nothing — the injectable
|
|
381
|
+
* default for options that accept `permits` optionally, so a test exercising
|
|
382
|
+
* unrelated logic spawns exactly as it did before this workstream. Every
|
|
383
|
+
* real entry point (`run`, `doctor --agents`, `nightshift author`,
|
|
384
|
+
* `nightshift as-built`/`publish`) builds and passes a real context instead
|
|
385
|
+
* of relying on this default.
|
|
386
|
+
*/
|
|
387
|
+
export const NOOP_PERMITS_CONTEXT = {
|
|
388
|
+
workspaceSettingsPath: "",
|
|
389
|
+
readOnlySettingsPath: "",
|
|
390
|
+
derive(_role, agent) {
|
|
391
|
+
return Promise.resolve({ agent, label: "operator-configured", operatorConfigured: true });
|
|
392
|
+
},
|
|
393
|
+
dispose() {
|
|
394
|
+
return Promise.resolve();
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
//# sourceMappingURL=permits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permits.js","sourceRoot":"","sources":["../src/permits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { LedgerEvent } from "./decision-ledger.js";
|
|
2
|
+
import type { ProgramManifest } from "./manifest.js";
|
|
3
|
+
/**
|
|
4
|
+
* The preflight stage: at run start, before baseline verification and any
|
|
5
|
+
* agent spawn, executes every *pending* prerequisite's `verifyCommand` as a
|
|
6
|
+
* deterministic, bounded subprocess. Exit zero flips it to `satisfied` (in
|
|
7
|
+
* memory — the caller decides when to persist); anything else — nonzero
|
|
8
|
+
* exit, spawn failure, timeout — uniformly means unmet, with a captured
|
|
9
|
+
* reason, and never throws out of this module. See
|
|
10
|
+
* `tasks/human-prerequisites/ws-02-*.md` for the full design.
|
|
11
|
+
*/
|
|
12
|
+
/** The wall-clock ceiling on a single prerequisite check. A deterministic
|
|
13
|
+
* check that has not answered in this long is treated as unmet, and the
|
|
14
|
+
* process tree is killed so it can never outlive the run. A constant, never
|
|
15
|
+
* a config key — the charter keeps tuning knobs off the config surface. */
|
|
16
|
+
export declare const PREREQUISITE_TIMEOUT_MS = 60000;
|
|
17
|
+
export interface PrerequisiteRun {
|
|
18
|
+
exitCode: number;
|
|
19
|
+
output: string;
|
|
20
|
+
/** True when the process tree was killed for exceeding the timeout. */
|
|
21
|
+
timedOut: boolean;
|
|
22
|
+
}
|
|
23
|
+
export type PrerequisiteRunner = (command: string, cwd: string) => Promise<PrerequisiteRun>;
|
|
24
|
+
/**
|
|
25
|
+
* Builds a bounded, process-tree-killing `PrerequisiteRunner`. Fixing the
|
|
26
|
+
* timeout inside a `(command, cwd)` runner would leave a timeout test no
|
|
27
|
+
* choice but to wait out the real production ceiling; this factory keeps the
|
|
28
|
+
* ceiling a test seam while {@link defaultPrerequisiteRunner} wires the
|
|
29
|
+
* production constant once.
|
|
30
|
+
*/
|
|
31
|
+
export declare function makePrerequisiteRunner(timeoutMs?: number): PrerequisiteRunner;
|
|
32
|
+
/** The production runner: the 60 s ceiling, wired once. */
|
|
33
|
+
export declare const defaultPrerequisiteRunner: PrerequisiteRunner;
|
|
34
|
+
export interface PrerequisiteCheck {
|
|
35
|
+
id: string;
|
|
36
|
+
met: boolean;
|
|
37
|
+
/** Captured reason when unmet — always non-empty so the report never
|
|
38
|
+
* renders a blank line. The tailed verify output on a nonzero exit; on a
|
|
39
|
+
* nonzero exit that emitted no output, a fallback naming the exit code;
|
|
40
|
+
* the spawn error message (or a generic notice) on a spawn failure; a
|
|
41
|
+
* notice naming the ceiling on a timeout. Absent only when met. */
|
|
42
|
+
reason?: string;
|
|
43
|
+
/** True when this run's preflight flipped it pending → satisfied. False
|
|
44
|
+
* for an already-satisfied prerequisite (not re-run) and for an unmet
|
|
45
|
+
* one. */
|
|
46
|
+
newlySatisfied: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface PreflightResult {
|
|
49
|
+
checks: PrerequisiteCheck[];
|
|
50
|
+
/** Ledger events for the prerequisites this run newly satisfied. The
|
|
51
|
+
* caller appends these once its own baseline verification admits the run
|
|
52
|
+
* — see run-program.ts's staged-persistence wiring. */
|
|
53
|
+
events: LedgerEvent[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Runs every pending prerequisite's `verifyCommand` once. Mutates
|
|
57
|
+
* `manifest.prerequisites` in place on a met check (pending → satisfied);
|
|
58
|
+
* the caller decides when (and whether) to persist that mutation to disk. An
|
|
59
|
+
* already-`satisfied` prerequisite is never re-run — settled facts stay
|
|
60
|
+
* settled (SC-06). No `verifyCommand` outcome can throw out of this
|
|
61
|
+
* function or halt the run (SC-03): a thrown spawn failure is caught here.
|
|
62
|
+
*/
|
|
63
|
+
export declare function runPreflight(args: {
|
|
64
|
+
manifest: ProgramManifest;
|
|
65
|
+
cwd: string;
|
|
66
|
+
runner: PrerequisiteRunner;
|
|
67
|
+
now: () => Date;
|
|
68
|
+
/** The run's identity, stamped on each `prerequisite-verified` event. */
|
|
69
|
+
runId: string;
|
|
70
|
+
runStartCommit: string | undefined;
|
|
71
|
+
log: (line: string) => void;
|
|
72
|
+
}): Promise<PreflightResult>;
|
|
73
|
+
//# sourceMappingURL=preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrD;;;;;;;;GAQG;AAEH;;;4EAG4E;AAC5E,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAe9C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,KACR,OAAO,CAAC,eAAe,CAAC,CAAC;AAiD9B;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,GAAE,MAAgC,GAC1C,kBAAkB,CAqEpB;AAED,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB,EAAE,kBACd,CAAC;AAE3B,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,OAAO,CAAC;IACb;;;;wEAIoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;eAEW;IACX,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B;;4DAEwD;IACxD,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,QAAQ,EAAE,eAAe,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,kBAAkB,CAAC;IAC3B,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B,GAAG,OAAO,CAAC,eAAe,CAAC,CA0E3B"}
|