@wildorder/nightshift 0.17.0 → 0.18.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.
Files changed (99) hide show
  1. package/README.md +269 -1
  2. package/dist/agent-runner.d.ts +41 -3
  3. package/dist/agent-runner.d.ts.map +1 -1
  4. package/dist/agent-runner.js +197 -12
  5. package/dist/agent-runner.js.map +1 -1
  6. package/dist/agent-session.d.ts +123 -0
  7. package/dist/agent-session.d.ts.map +1 -0
  8. package/dist/agent-session.js +114 -0
  9. package/dist/agent-session.js.map +1 -0
  10. package/dist/atomic-write.d.ts +18 -0
  11. package/dist/atomic-write.d.ts.map +1 -0
  12. package/dist/atomic-write.js +74 -0
  13. package/dist/atomic-write.js.map +1 -0
  14. package/dist/author.d.ts +112 -6
  15. package/dist/author.d.ts.map +1 -1
  16. package/dist/author.js +597 -137
  17. package/dist/author.js.map +1 -1
  18. package/dist/causal-analysis.d.ts +6 -2
  19. package/dist/causal-analysis.d.ts.map +1 -1
  20. package/dist/causal-analysis.js +55 -2
  21. package/dist/causal-analysis.js.map +1 -1
  22. package/dist/cli.js +22 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/concurrency.d.ts +24 -0
  25. package/dist/concurrency.d.ts.map +1 -0
  26. package/dist/concurrency.js +28 -0
  27. package/dist/concurrency.js.map +1 -0
  28. package/dist/decider-review.d.ts +10 -3
  29. package/dist/decider-review.d.ts.map +1 -1
  30. package/dist/decider-review.js +6 -4
  31. package/dist/decider-review.js.map +1 -1
  32. package/dist/decision-ledger.d.ts +7 -0
  33. package/dist/decision-ledger.d.ts.map +1 -1
  34. package/dist/decision-ledger.js +25 -10
  35. package/dist/decision-ledger.js.map +1 -1
  36. package/dist/detect-package-manager.d.ts +10 -0
  37. package/dist/detect-package-manager.d.ts.map +1 -1
  38. package/dist/detect-package-manager.js +12 -0
  39. package/dist/detect-package-manager.js.map +1 -1
  40. package/dist/index.d.ts +3 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +3 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/manifest.d.ts +24 -5
  45. package/dist/manifest.d.ts.map +1 -1
  46. package/dist/manifest.js +254 -108
  47. package/dist/manifest.js.map +1 -1
  48. package/dist/permits.d.ts +18 -0
  49. package/dist/permits.d.ts.map +1 -1
  50. package/dist/permits.js +155 -0
  51. package/dist/permits.js.map +1 -1
  52. package/dist/preflight.d.ts +2 -2
  53. package/dist/preflight.d.ts.map +1 -1
  54. package/dist/preflight.js.map +1 -1
  55. package/dist/review-pass.d.ts +52 -10
  56. package/dist/review-pass.d.ts.map +1 -1
  57. package/dist/review-pass.js +114 -30
  58. package/dist/review-pass.js.map +1 -1
  59. package/dist/run-analytics-report.d.ts +114 -1
  60. package/dist/run-analytics-report.d.ts.map +1 -1
  61. package/dist/run-analytics-report.js +606 -14
  62. package/dist/run-analytics-report.js.map +1 -1
  63. package/dist/run-analytics.d.ts +107 -1
  64. package/dist/run-analytics.d.ts.map +1 -1
  65. package/dist/run-analytics.js +257 -25
  66. package/dist/run-analytics.js.map +1 -1
  67. package/dist/run-log.d.ts +16 -0
  68. package/dist/run-log.d.ts.map +1 -0
  69. package/dist/run-log.js +32 -0
  70. package/dist/run-log.js.map +1 -0
  71. package/dist/run-program.d.ts +203 -7
  72. package/dist/run-program.d.ts.map +1 -1
  73. package/dist/run-program.js +1526 -320
  74. package/dist/run-program.js.map +1 -1
  75. package/dist/scheduler.d.ts +75 -0
  76. package/dist/scheduler.d.ts.map +1 -0
  77. package/dist/scheduler.js +126 -0
  78. package/dist/scheduler.js.map +1 -0
  79. package/dist/verify-cache.d.ts +64 -0
  80. package/dist/verify-cache.d.ts.map +1 -0
  81. package/dist/verify-cache.js +56 -0
  82. package/dist/verify-cache.js.map +1 -0
  83. package/dist/whole-program-review.d.ts +2 -2
  84. package/dist/whole-program-review.d.ts.map +1 -1
  85. package/dist/whole-program-review.js.map +1 -1
  86. package/dist/worktree.d.ts +124 -0
  87. package/dist/worktree.d.ts.map +1 -0
  88. package/dist/worktree.js +397 -0
  89. package/dist/worktree.js.map +1 -0
  90. package/dist/write-queue.d.ts +25 -0
  91. package/dist/write-queue.d.ts.map +1 -0
  92. package/dist/write-queue.js +52 -0
  93. package/dist/write-queue.js.map +1 -0
  94. package/package.json +2 -2
  95. package/skills/plan-program/SKILL.md +37 -5
  96. package/dist/worktree-guard.d.ts +0 -40
  97. package/dist/worktree-guard.d.ts.map +0 -1
  98. package/dist/worktree-guard.js +0 -91
  99. package/dist/worktree-guard.js.map +0 -1
@@ -0,0 +1,397 @@
1
+ import { createHash } from "node:crypto";
2
+ import { execFile } from "node:child_process";
3
+ import { mkdir, realpath } from "node:fs/promises";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ import { promisify } from "node:util";
7
+ import { lockfileManager } from "./detect-package-manager.js";
8
+ const execFileAsync = promisify(execFile);
9
+ /** The fixed prefix for every runner-created worktree branch. Not a config key. */
10
+ export const WORKTREE_BRANCH_PREFIX = "nightshift/";
11
+ /** `nightshift/<programId>/<workstreamId>` — a branch under refs/heads/. Ids are lowercased so a case-insensitive filesystem can never make two refs collide. */
12
+ export function worktreeBranchName(programId, workstreamId) {
13
+ return `${WORKTREE_BRANCH_PREFIX}${programId.toLowerCase()}/${workstreamId.toLowerCase()}`;
14
+ }
15
+ /** Every branch this program's worktrees may use, for prefix-matched reaping. */
16
+ export function worktreeBranchPrefix(programId) {
17
+ return `${WORKTREE_BRANCH_PREFIX}${programId.toLowerCase()}/`;
18
+ }
19
+ /** `refs/nightshift/<programId>/<workstreamId>` — where a verified-but-unintegrated commit is retained. */
20
+ export function retainedRefName(programId, workstreamId) {
21
+ return `refs/nightshift/${programId.toLowerCase()}/${workstreamId.toLowerCase()}`;
22
+ }
23
+ function hash8(value) {
24
+ return createHash("sha256").update(value).digest("hex").slice(0, 8);
25
+ }
26
+ /**
27
+ * The realpath of `repoRoot`, falling back to the resolved path when
28
+ * `realpath` cannot be taken (a repository whose parent no longer exists —
29
+ * an edge case, but one this function must not throw on).
30
+ */
31
+ async function repoRealpath(repoRoot) {
32
+ try {
33
+ return await realpath(repoRoot);
34
+ }
35
+ catch {
36
+ return resolve(repoRoot);
37
+ }
38
+ }
39
+ /**
40
+ * Where a workstream's worktree lives: `<base>/<programId>-<hash8>/<workstreamId>`,
41
+ * where `hash8` is derived from the repository's own realpath — see
42
+ * `resolveWorktreeBase`'s doc comment for why this segment is load-bearing.
43
+ */
44
+ export function worktreePathFor(base, programId, workstreamId, repoHash) {
45
+ return join(base, `${programId}-${repoHash}`, workstreamId);
46
+ }
47
+ /**
48
+ * Resolves the base directory under which this run's worktrees are created,
49
+ * once per run: `<dirname(realpath(repoRoot))>/.nightshift-worktrees`, or —
50
+ * when that parent is not writable (a read-only mount, a container) —
51
+ * `<os tmpdir>/nightshift-worktrees`. Eagerly `mkdir -p`s the chosen base so
52
+ * the fallback decision is made once, up front, rather than discovered mid-run.
53
+ *
54
+ * The `hash8(realpath(repoRoot))` segment (folded into every returned path via
55
+ * `repoHash`) is load-bearing, not decoration: without it, two checkouts of
56
+ * the same repository — or two test fixtures sharing an OS temp directory and
57
+ * the same programId — would resolve to the same worktree path and the
58
+ * second `git worktree add` would fail with `already exists`.
59
+ */
60
+ export async function resolveWorktreeBase(repoRoot, override) {
61
+ const realRepoRoot = await repoRealpath(repoRoot);
62
+ const repoHash = hash8(realRepoRoot);
63
+ if (override !== undefined) {
64
+ const base = resolve(override);
65
+ await mkdir(base, { recursive: true });
66
+ return { base, repoHash, usedFallback: false };
67
+ }
68
+ const siblingBase = join(dirname(realRepoRoot), ".nightshift-worktrees");
69
+ if (await insideGitWorkTree(dirname(realRepoRoot))) {
70
+ // The repository itself sits inside another checkout: a sibling
71
+ // directory would land in *that* repository's tracked tree.
72
+ const fallbackBase = join(tmpdir(), "nightshift-worktrees");
73
+ await mkdir(fallbackBase, { recursive: true });
74
+ return { base: fallbackBase, repoHash, usedFallback: true };
75
+ }
76
+ try {
77
+ await mkdir(siblingBase, { recursive: true });
78
+ return { base: siblingBase, repoHash, usedFallback: false };
79
+ }
80
+ catch {
81
+ const fallbackBase = join(tmpdir(), "nightshift-worktrees");
82
+ await mkdir(fallbackBase, { recursive: true });
83
+ return { base: fallbackBase, repoHash, usedFallback: true };
84
+ }
85
+ }
86
+ /** The install command for a worktree, or undefined when there is no lockfile. */
87
+ export function worktreeInstallCommand(worktreeRoot) {
88
+ const manager = lockfileManager(worktreeRoot);
89
+ if (manager === undefined)
90
+ return undefined;
91
+ return installCommandFor(manager);
92
+ }
93
+ function installCommandFor(manager) {
94
+ switch (manager) {
95
+ case "npm":
96
+ return "npm ci";
97
+ case "pnpm":
98
+ return "pnpm install --frozen-lockfile";
99
+ case "yarn":
100
+ return "yarn install";
101
+ case "bun":
102
+ return "bun install --frozen-lockfile";
103
+ }
104
+ }
105
+ /**
106
+ * True for a path the runner owns in the tree being inspected. `git status
107
+ * --porcelain` paths are relative to that tree's root — the root checkout
108
+ * during the report commit, the worktree during a build. In a worktree the
109
+ * runner writes nothing here, so this only ever fires when an agent itself
110
+ * edited planning artifacts, which is equally not the work it was asked to
111
+ * do.
112
+ */
113
+ export function isRunnerOwnedArtifactPath(path) {
114
+ return path.replaceAll("\\", "/").startsWith("docs/programs/");
115
+ }
116
+ async function run(cwd, args) {
117
+ return execFileAsync("git", args, { cwd, maxBuffer: 32 * 1024 * 1024 });
118
+ }
119
+ function outputOf(error) {
120
+ const err = error;
121
+ const streams = `${err.stdout ?? ""}${err.stderr ?? ""}`;
122
+ // A spawn-level failure (git never ran: ENAMETOOLONG on an oversized argv,
123
+ // ENOENT, EPERM) leaves both streams empty. The error's own message is
124
+ // then the only diagnosis there is, and an empty reason is the one thing
125
+ // the caller's report must never render.
126
+ if (streams.trim() !== "")
127
+ return streams;
128
+ return err.message ?? String(error);
129
+ }
130
+ /**
131
+ * `git` with `input` written to stdin — for `--pathspec-from-file=-`, so a
132
+ * pathspec of any length never rides on argv (Windows caps a command line at
133
+ * 32K characters; a workstream touching a few hundred files exceeds it).
134
+ */
135
+ async function runWithStdin(cwd, args, input) {
136
+ return new Promise((resolvePromise, reject) => {
137
+ const child = execFile("git", args, { cwd, maxBuffer: 32 * 1024 * 1024 }, (error, stdout, stderr) => {
138
+ if (error) {
139
+ reject(Object.assign(error, { stdout, stderr }));
140
+ return;
141
+ }
142
+ resolvePromise({ stdout, stderr });
143
+ });
144
+ child.stdin?.on("error", () => undefined);
145
+ child.stdin?.end(input);
146
+ });
147
+ }
148
+ async function insideGitWorkTree(dir) {
149
+ try {
150
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dir });
151
+ return stdout.trim() === "true";
152
+ }
153
+ catch {
154
+ return false;
155
+ }
156
+ }
157
+ function parseWorktreeList(raw) {
158
+ const entries = [];
159
+ let current = {};
160
+ const flush = () => {
161
+ if (current.path !== undefined && current.head !== undefined) {
162
+ entries.push({
163
+ path: current.path,
164
+ head: current.head,
165
+ ...(current.branch === undefined ? {} : { branch: current.branch }),
166
+ ...(current.prunable === true ? { prunable: true } : {}),
167
+ });
168
+ }
169
+ current = {};
170
+ };
171
+ for (const line of raw.split("\n")) {
172
+ if (line === "") {
173
+ flush();
174
+ continue;
175
+ }
176
+ if (line.startsWith("worktree ")) {
177
+ current.path = line.slice("worktree ".length);
178
+ }
179
+ else if (line.startsWith("HEAD ")) {
180
+ current.head = line.slice("HEAD ".length);
181
+ }
182
+ else if (line.startsWith("branch ")) {
183
+ current.branch = line.slice("branch ".length);
184
+ }
185
+ else if (line.startsWith("prunable")) {
186
+ current.prunable = true;
187
+ }
188
+ }
189
+ flush();
190
+ return entries;
191
+ }
192
+ export const defaultWorktreeOps = {
193
+ async add(root, path, branch, commitish) {
194
+ await mkdir(dirname(path), { recursive: true });
195
+ await run(root, ["worktree", "add", "-b", branch, path, commitish]);
196
+ },
197
+ async list(root) {
198
+ const { stdout } = await run(root, ["worktree", "list", "--porcelain"]);
199
+ return parseWorktreeList(stdout);
200
+ },
201
+ async remove(root, path) {
202
+ try {
203
+ await run(root, ["worktree", "remove", "--force", path]);
204
+ }
205
+ catch {
206
+ // Already missing, or git's administrative entry disagrees with the
207
+ // filesystem — either way, there is nothing more to remove.
208
+ }
209
+ },
210
+ async prune(root) {
211
+ try {
212
+ await run(root, ["worktree", "prune"]);
213
+ }
214
+ catch {
215
+ // Best-effort housekeeping; never fatal.
216
+ }
217
+ },
218
+ async branchesUnder(root, prefix) {
219
+ try {
220
+ const { stdout } = await run(root, [
221
+ "for-each-ref",
222
+ "--format=%(refname:short)",
223
+ `refs/heads/${prefix}`,
224
+ ]);
225
+ return stdout
226
+ .split("\n")
227
+ .map((line) => line.trim())
228
+ .filter((line) => line !== "");
229
+ }
230
+ catch {
231
+ return [];
232
+ }
233
+ },
234
+ async deleteBranch(root, branch) {
235
+ try {
236
+ await run(root, ["branch", "-D", branch]);
237
+ }
238
+ catch {
239
+ // Absent branch — nothing to delete.
240
+ }
241
+ },
242
+ async mergeInto(worktree, commitish, message) {
243
+ try {
244
+ const { stdout, stderr } = await run(worktree, ["merge", "--no-edit", "-m", message, commitish]);
245
+ return { ok: true, conflicts: [], output: `${stdout}${stderr}` };
246
+ }
247
+ catch (error) {
248
+ let conflicts = [];
249
+ try {
250
+ const { stdout } = await run(worktree, ["diff", "--name-only", "--diff-filter=U"]);
251
+ conflicts = stdout.split("\n").map((line) => line.trim()).filter((line) => line !== "");
252
+ }
253
+ catch {
254
+ // Nothing more we can learn.
255
+ }
256
+ return { ok: false, conflicts, output: outputOf(error) };
257
+ }
258
+ },
259
+ async abortMerge(worktree) {
260
+ try {
261
+ await run(worktree, ["merge", "--abort"]);
262
+ }
263
+ catch {
264
+ // Nothing to abort, or the abort itself failed — the caller's own
265
+ // recovery path (reset --merge, worktree retention) covers this.
266
+ }
267
+ },
268
+ async squashIntegrate(cwd, commitish, message, paths) {
269
+ try {
270
+ await run(cwd, ["merge", "--squash", commitish]);
271
+ }
272
+ catch (error) {
273
+ try {
274
+ await run(cwd, ["reset", "--merge"]);
275
+ }
276
+ catch {
277
+ // Best-effort recovery; the caller reports the original failure.
278
+ }
279
+ return { ok: false, output: outputOf(error) };
280
+ }
281
+ if (paths.length === 0) {
282
+ // Nothing to stage or commit — an identical branch. Treat as a no-op
283
+ // integration, not a failure: there is no state to recover.
284
+ return { ok: true, commit: undefined };
285
+ }
286
+ try {
287
+ await runWithStdin(cwd, ["commit", "-m", message, "--pathspec-from-file=-", "--pathspec-file-nul"], paths.join(""));
288
+ }
289
+ catch (error) {
290
+ const output = outputOf(error);
291
+ // "nothing to commit" for the given pathspec is not a failure — the
292
+ // squash staged nothing under these paths (can legitimately happen
293
+ // when every incoming path was itself an exclusion).
294
+ if (/nothing to commit|nothing added to commit|no changes added to commit/u.test(output)) {
295
+ return { ok: true, commit: undefined };
296
+ }
297
+ try {
298
+ await run(cwd, ["reset", "--merge"]);
299
+ }
300
+ catch {
301
+ // Best-effort recovery; the caller reports the original failure.
302
+ }
303
+ return { ok: false, output };
304
+ }
305
+ try {
306
+ const { stdout } = await run(cwd, ["rev-parse", "HEAD"]);
307
+ return { ok: true, commit: stdout.trim() };
308
+ }
309
+ catch {
310
+ return { ok: true, commit: undefined };
311
+ }
312
+ },
313
+ async commitEverything(worktree, message) {
314
+ try {
315
+ await run(worktree, ["add", "-A"]);
316
+ try {
317
+ await run(worktree, ["commit", "-m", message]);
318
+ }
319
+ catch (error) {
320
+ if (!/nothing to commit|nothing added to commit|no changes added to commit/u.test(outputOf(error))) {
321
+ throw error;
322
+ }
323
+ }
324
+ const { stdout } = await run(worktree, ["rev-parse", "HEAD"]);
325
+ return stdout.trim();
326
+ }
327
+ catch {
328
+ return undefined;
329
+ }
330
+ },
331
+ async updateRef(root, ref, commit) {
332
+ await run(root, ["update-ref", ref, commit]);
333
+ },
334
+ async isAncestor(root, ancestor, descendant) {
335
+ try {
336
+ await run(root, ["merge-base", "--is-ancestor", ancestor, descendant]);
337
+ return true;
338
+ }
339
+ catch {
340
+ return false;
341
+ }
342
+ },
343
+ async changedPaths(cwd, a, b) {
344
+ try {
345
+ const { stdout } = await run(cwd, ["diff", "--name-only", "-z", "--no-renames", a, b]);
346
+ return stdout.split("\0").filter((path) => path !== "");
347
+ }
348
+ catch {
349
+ return [];
350
+ }
351
+ },
352
+ async resolveCommit(cwd, rev) {
353
+ try {
354
+ const { stdout } = await run(cwd, ["rev-parse", "--verify", `${rev}^{commit}`]);
355
+ return stdout.trim();
356
+ }
357
+ catch {
358
+ return undefined;
359
+ }
360
+ },
361
+ async discardRunnerArtifacts(worktree) {
362
+ let discovered = [];
363
+ try {
364
+ const { stdout } = await run(worktree, [
365
+ "status",
366
+ "--porcelain",
367
+ "-z",
368
+ "--",
369
+ ":(top)docs/programs",
370
+ ]);
371
+ discovered = stdout
372
+ .split("\0")
373
+ .filter((token) => token !== "")
374
+ .map((token) => token.slice(3));
375
+ }
376
+ catch {
377
+ // No tracked or untracked docs/programs paths — nothing to discard.
378
+ }
379
+ if (discovered.length === 0)
380
+ return [];
381
+ try {
382
+ await run(worktree, ["checkout", "--", ":(top)docs/programs"]);
383
+ }
384
+ catch {
385
+ // "did not match any file(s) known to git" is an ordinary case — no
386
+ // tracked file under docs/programs in this worktree.
387
+ }
388
+ try {
389
+ await run(worktree, ["clean", "-fd", "--", ":(top)docs/programs"]);
390
+ }
391
+ catch {
392
+ // Nothing untracked to remove.
393
+ }
394
+ return discovered;
395
+ },
396
+ };
397
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * A per-program serialized write queue: the single door every access to a
3
+ * program's manifest and decision ledger goes through. Manifest saves and
4
+ * ledger appends share one chain keyed by program (not per file) — that
5
+ * costs a few milliseconds of false serialization and buys a total order
6
+ * over a program's runner-owned state, which is what makes "the ledger
7
+ * never describes a manifest state that never existed" true by
8
+ * construction.
9
+ *
10
+ * A queued task may only do filesystem work. It must never spawn an agent,
11
+ * run a verify command, or call another queued API — this queue is not
12
+ * re-entrant, and a re-entrant call (a task that itself calls
13
+ * `enqueueProgramWrite` for the same key and awaits it) self-deadlocks.
14
+ */
15
+ /** Stable key for one program's runner-owned files. */
16
+ export declare function programWriteKey(root: string, programId: string): string;
17
+ /**
18
+ * Runs `task` after everything already queued for `key` has settled, and
19
+ * returns its result. FIFO by call order. A rejected task rejects only its
20
+ * own caller — the chain is never poisoned for the next task.
21
+ */
22
+ export declare function enqueueProgramWrite<T>(key: string, task: () => Promise<T>): Promise<T>;
23
+ /** Resolves when everything currently queued for `key` has settled. */
24
+ export declare function drainProgramWrites(key: string): Promise<void>;
25
+ //# sourceMappingURL=write-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-queue.d.ts","sourceRoot":"","sources":["../src/write-queue.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvE;AAOD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAED,uEAAuE;AACvE,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAInE"}
@@ -0,0 +1,52 @@
1
+ import { resolve } from "node:path";
2
+ /**
3
+ * A per-program serialized write queue: the single door every access to a
4
+ * program's manifest and decision ledger goes through. Manifest saves and
5
+ * ledger appends share one chain keyed by program (not per file) — that
6
+ * costs a few milliseconds of false serialization and buys a total order
7
+ * over a program's runner-owned state, which is what makes "the ledger
8
+ * never describes a manifest state that never existed" true by
9
+ * construction.
10
+ *
11
+ * A queued task may only do filesystem work. It must never spawn an agent,
12
+ * run a verify command, or call another queued API — this queue is not
13
+ * re-entrant, and a re-entrant call (a task that itself calls
14
+ * `enqueueProgramWrite` for the same key and awaits it) self-deadlocks.
15
+ */
16
+ /** Stable key for one program's runner-owned files. */
17
+ export function programWriteKey(root, programId) {
18
+ return `${resolve(root)} ${programId}`;
19
+ }
20
+ // The tail of each key's chain — always a promise that resolves (never
21
+ // rejects), so the next task's `priorTail` is never poisoned by a prior
22
+ // task's failure.
23
+ const tails = new Map();
24
+ /**
25
+ * Runs `task` after everything already queued for `key` has settled, and
26
+ * returns its result. FIFO by call order. A rejected task rejects only its
27
+ * own caller — the chain is never poisoned for the next task.
28
+ */
29
+ export function enqueueProgramWrite(key, task) {
30
+ const priorTail = tails.get(key) ?? Promise.resolve();
31
+ const run = () => task();
32
+ const started = priorTail.then(run, run);
33
+ const settledTail = started.then(() => undefined, () => undefined);
34
+ tails.set(key, settledTail);
35
+ void settledTail.then(() => {
36
+ // Delete the entry only when this task's settlement is still the tail
37
+ // — a long-lived process must not accumulate one entry per program
38
+ // forever, but a newer task queued behind this one must not have its
39
+ // tail yanked out from under it.
40
+ if (tails.get(key) === settledTail)
41
+ tails.delete(key);
42
+ });
43
+ return started;
44
+ }
45
+ /** Resolves when everything currently queued for `key` has settled. */
46
+ export async function drainProgramWrites(key) {
47
+ const tail = tails.get(key);
48
+ if (tail === undefined)
49
+ return;
50
+ await tail;
51
+ }
52
+ //# sourceMappingURL=write-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-queue.js","sourceRoot":"","sources":["../src/write-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,SAAiB;IAC7D,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;AACzC,CAAC;AAED,uEAAuE;AACvE,wEAAwE;AACxE,kBAAkB;AAClB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,IAAsB;IAEtB,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IACtD,MAAM,GAAG,GAAG,GAAe,EAAE,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAC9B,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;IAEF,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC5B,KAAK,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE;QACzB,sEAAsE;QACtE,mEAAmE;QACnE,qEAAqE;QACrE,iCAAiC;QACjC,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,WAAW;YAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO;IAC/B,MAAM,IAAI,CAAC;AACb,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wildorder/nightshift",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "The crew that builds while you're gone: walk-away, CI-dispatched engineering programs with a decision ledger instead of gates",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -59,7 +59,7 @@
59
59
  "@eslint/js": "^10.0.1",
60
60
  "@types/cross-spawn": "^6.0.6",
61
61
  "@types/node": "^26.1.2",
62
- "@wildorder/nightshift": "^0.16.0",
62
+ "@wildorder/nightshift": "^0.17.0",
63
63
  "eslint": "^10.8.0",
64
64
  "typescript": "^6.0.3",
65
65
  "typescript-eslint": "^8.66.0",
@@ -135,12 +135,28 @@ orchestration is necessary.
135
135
  shared-contract migration requires expand → migrate consumers →
136
136
  contract/delete ordering.
137
137
 
138
+ The runner builds independent workstreams concurrently, bounded by
139
+ `--max-parallel`, and starts a workstream's build as soon as its own spec is
140
+ finished and its dependencies have landed. Material parallelism is therefore
141
+ evidence you can bank, not a hope. **Pipelining pays on chains, too** — a
142
+ shape planners have been told not to expect a win from: a chain of *n*
143
+ workstreams overlaps each spec's authoring with the previous workstream's
144
+ build, so the run's length is roughly `author(1) + Σ build` rather than
145
+ `Σ author + Σ build`. A chain is no longer a reason to prefer `atomic`.
146
+
138
147
  Do not choose orchestrated merely because the feature is important, spans
139
- many files, or has a high estimated token count. State the concrete evidence
140
- in `program.executionModeReason`. In atomic mode create exactly one
141
- workstream covering the entire program, with no dependencies and task file
142
- `tasks/{program-id}/implementation.md`. In orchestrated mode use the
143
- decomposition and checkpoint rules below.
148
+ many files, or has a high estimated token count. And it is still not a
149
+ licence to over-decompose: every workstream carries a spec, a critique
150
+ cycle, a verify pass, and an integration, and two workstreams that edit the
151
+ same file now collide at integration where serially they would have queued.
152
+ `atomic` remains the default when one agent can hold the change coherently.
153
+ State the concrete evidence in `program.executionModeReason`. In atomic mode
154
+ create exactly one workstream covering the entire program, with no
155
+ dependencies and task file `tasks/{program-id}/implementation.md`. In
156
+ orchestrated mode use the decomposition and checkpoint rules below, and name
157
+ the expected **width** (the widest dependency level, by workstream id) and
158
+ the expected **critical path** (the chain of workstreams expected to
159
+ determine the run's length) — one sentence each, in the program document.
144
160
 
145
161
  ## 2.5. Create the program's branch
146
162
 
@@ -253,6 +269,9 @@ when one exists. Otherwise use:
253
269
  ## Execution Mode
254
270
  **Mode:** atomic | orchestrated
255
271
  **Reason:** [Concrete causal evidence for the choice.]
272
+ **Shape:** [Orchestrated only: the widest dependency level (which workstream
273
+ ids run together) and the chain expected to determine the run's length. Omit
274
+ for atomic.]
256
275
 
257
276
  ## Strategic Goals
258
277
  [Three to five outcome-focused bullets.]
@@ -403,6 +422,14 @@ workstream:
403
422
  neighbors might reasonably assume it handles something, say that it does
404
423
  not.
405
424
 
425
+ Under concurrent builds, `excludes` carries one more job: two workstreams
426
+ that both edit a shared file — a barrel like `src/index.ts`, the README, a
427
+ shared test file, a config schema module — no longer queue behind each
428
+ other; they build against the same base and one of them hits a conflict at
429
+ integration. So **name an owner for each shared file one workstream will
430
+ touch and others might**: the owner's `includes` says it owns the file,
431
+ every other workstream's `excludes` says it does not.
432
+
406
433
  ### Every orchestrated workstream is an independently green checkpoint
407
434
 
408
435
  Design the roster so that, starting from a green repository containing only
@@ -423,6 +450,11 @@ For a shared contract migration, prefer an explicit sequence:
423
450
  The destructive cleanup depends on every migration workstream. Do not place
424
451
  foundational deletion first merely because it is conceptually central.
425
452
 
453
+ Green now means green against the program-branch tip **including the
454
+ siblings that landed while this workstream was building**, because the
455
+ runner re-verifies after integration — a checkpoint that is green only
456
+ against the tip it started from is a checkpoint that fails integration.
457
+
426
458
  ## 4.5. Absorb backlog items
427
459
 
428
460
  When any part of this program's scope came from an item captured under
@@ -1,40 +0,0 @@
1
- /**
2
- * A pre-attempt snapshot of the git worktree. Rejected replanner attempts
3
- * were "rolled back" by restoring exactly two files, but the replanner is a
4
- * full agentic CLI that can touch anything — out-of-scope edits and stray
5
- * temp scripts survived the rollback while the progress line claimed a clean
6
- * transaction. This guard makes the claim true: capture the whole tracked
7
- * tree via `git stash create` (which snapshots without touching the
8
- * worktree) and record which paths were untracked, so a restore can revert
9
- * every tracked change and delete files the agent created.
10
- *
11
- * Limits, stated rather than hidden: modifications to files that were
12
- * already untracked at capture time cannot be restored (git has no snapshot
13
- * of them), and gitignored files are invisible to the status listing. In a
14
- * non-git directory `available` is false and callers fall back to the
15
- * legacy two-file restore with a warning.
16
- */
17
- export interface WorktreeCapture {
18
- available: boolean;
19
- /** Git repository toplevel; all recorded paths are relative to it. */
20
- toplevel?: string;
21
- /** Commit whose tree is the captured tracked state. */
22
- source?: string;
23
- /** Paths untracked at capture; never deleted by a restore. */
24
- untracked?: Set<string>;
25
- }
26
- export declare function captureWorktree(root: string): Promise<WorktreeCapture>;
27
- export interface WorktreeRestoreResult {
28
- restored: boolean;
29
- /** Tracked paths whose state drifted from the capture (before restoring). */
30
- drifted: string[];
31
- /** Newly created untracked files that were deleted. */
32
- removed: string[];
33
- }
34
- /**
35
- * Revert the worktree to `capture`, except `preservePaths` (absolute or
36
- * root-relative), which keep their current content. Newly created untracked
37
- * files outside the preserve list are deleted.
38
- */
39
- export declare function restoreWorktree(root: string, capture: WorktreeCapture, preservePaths?: string[]): Promise<WorktreeRestoreResult>;
40
- //# sourceMappingURL=worktree-guard.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worktree-guard.d.ts","sourceRoot":"","sources":["../src/worktree-guard.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAyBD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAc5E;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,eAAe,EACxB,aAAa,GAAE,MAAM,EAAO,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CAwChC"}