@wildorder/nightshift 0.5.0 → 0.7.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 (72) hide show
  1. package/LICENSE +21 -21
  2. package/dist/author.d.ts +13 -0
  3. package/dist/author.d.ts.map +1 -1
  4. package/dist/author.js +46 -13
  5. package/dist/author.js.map +1 -1
  6. package/dist/ci-init.d.ts +51 -0
  7. package/dist/ci-init.d.ts.map +1 -0
  8. package/dist/ci-init.js +274 -0
  9. package/dist/ci-init.js.map +1 -0
  10. package/dist/cli.js +99 -11
  11. package/dist/cli.js.map +1 -1
  12. package/dist/decide.d.ts +13 -5
  13. package/dist/decide.d.ts.map +1 -1
  14. package/dist/decide.js +50 -35
  15. package/dist/decide.js.map +1 -1
  16. package/dist/decider-review.d.ts +68 -1
  17. package/dist/decider-review.d.ts.map +1 -1
  18. package/dist/decider-review.js +211 -3
  19. package/dist/decider-review.js.map +1 -1
  20. package/dist/decision-ledger.d.ts +79 -1
  21. package/dist/decision-ledger.d.ts.map +1 -1
  22. package/dist/decision-ledger.js +118 -11
  23. package/dist/decision-ledger.js.map +1 -1
  24. package/dist/decision-view.d.ts +41 -0
  25. package/dist/decision-view.d.ts.map +1 -0
  26. package/dist/decision-view.js +264 -0
  27. package/dist/decision-view.js.map +1 -0
  28. package/dist/exit-codes.d.ts +44 -0
  29. package/dist/exit-codes.d.ts.map +1 -0
  30. package/dist/exit-codes.js +49 -0
  31. package/dist/exit-codes.js.map +1 -0
  32. package/dist/findings.d.ts +3 -0
  33. package/dist/findings.d.ts.map +1 -1
  34. package/dist/findings.js.map +1 -1
  35. package/dist/index.d.ts +7 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +6 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/manifest.d.ts +2 -2
  40. package/dist/program-branch.d.ts +65 -0
  41. package/dist/program-branch.d.ts.map +1 -0
  42. package/dist/program-branch.js +123 -0
  43. package/dist/program-branch.js.map +1 -0
  44. package/dist/programs-dir.d.ts +27 -0
  45. package/dist/programs-dir.d.ts.map +1 -0
  46. package/dist/programs-dir.js +52 -0
  47. package/dist/programs-dir.js.map +1 -0
  48. package/dist/publish.d.ts +105 -0
  49. package/dist/publish.d.ts.map +1 -0
  50. package/dist/publish.js +528 -0
  51. package/dist/publish.js.map +1 -0
  52. package/dist/report-path.d.ts +7 -0
  53. package/dist/report-path.d.ts.map +1 -0
  54. package/dist/report-path.js +10 -0
  55. package/dist/report-path.js.map +1 -0
  56. package/dist/review-pass.d.ts +33 -1
  57. package/dist/review-pass.d.ts.map +1 -1
  58. package/dist/review-pass.js +94 -42
  59. package/dist/review-pass.js.map +1 -1
  60. package/dist/run-program.d.ts +29 -3
  61. package/dist/run-program.d.ts.map +1 -1
  62. package/dist/run-program.js +431 -47
  63. package/dist/run-program.js.map +1 -1
  64. package/dist/run-publish.d.ts +41 -0
  65. package/dist/run-publish.d.ts.map +1 -0
  66. package/dist/run-publish.js +33 -0
  67. package/dist/run-publish.js.map +1 -0
  68. package/package.json +5 -4
  69. package/skills/plan-program/SKILL.md +14 -0
  70. package/templates/AGENTS.md +29 -29
  71. package/templates/CLAUDE.md +7 -7
  72. package/templates/vision.md +46 -46
@@ -0,0 +1,123 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const execFileAsync = promisify(execFile);
4
+ /**
5
+ * The fixed prefix for every program branch. Not a config key — the charter
6
+ * keeps tuning knobs off the config surface, and a second source of truth
7
+ * next to this function is exactly what this module exists to prevent.
8
+ */
9
+ export const PROGRAM_BRANCH_PREFIX = "program/";
10
+ /**
11
+ * The one place a program ID becomes a branch name. The runner's
12
+ * preconditions and the branch command both call this; nothing else derives
13
+ * a branch name anywhere in the codebase.
14
+ */
15
+ export function programBranchName(programId) {
16
+ return `${PROGRAM_BRANCH_PREFIX}${programId}`;
17
+ }
18
+ export const defaultProgramBranchGit = {
19
+ async isRepository(cwd) {
20
+ try {
21
+ await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd });
22
+ return true;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ },
28
+ async currentBranch(cwd) {
29
+ try {
30
+ const { stdout } = await execFileAsync("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { cwd });
31
+ return stdout.trim();
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ },
37
+ async localBranchExists(cwd, branch) {
38
+ try {
39
+ await execFileAsync("git", ["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], { cwd });
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ },
46
+ async originHeadBranch(cwd) {
47
+ try {
48
+ const { stdout } = await execFileAsync("git", ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"], { cwd });
49
+ const ref = stdout.trim();
50
+ return ref.startsWith("origin/") ? ref.slice("origin/".length) : ref;
51
+ }
52
+ catch {
53
+ return undefined;
54
+ }
55
+ },
56
+ async configDefaultBranch(cwd) {
57
+ try {
58
+ const { stdout } = await execFileAsync("git", ["config", "--get", "init.defaultBranch"], { cwd });
59
+ const value = stdout.trim();
60
+ return value === "" ? undefined : value;
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ },
66
+ async switchTo(cwd, branch) {
67
+ await execFileAsync("git", ["switch", branch], { cwd });
68
+ },
69
+ async createAndSwitch(cwd, branch) {
70
+ await execFileAsync("git", ["switch", "-c", branch], { cwd });
71
+ },
72
+ };
73
+ /**
74
+ * Creates a program's branch and switches to it, or switches to it when a
75
+ * prior run already made it, and reports which. Never discards uncommitted
76
+ * work: creating carries the working tree onto the new branch, and switching
77
+ * to an existing branch with conflicting local changes surfaces git's own
78
+ * refusal rather than overriding it.
79
+ */
80
+ export async function createOrSwitchProgramBranch(programId, options) {
81
+ const cwd = options?.cwd ?? process.cwd();
82
+ const git = options?.git ?? defaultProgramBranchGit;
83
+ const branch = programBranchName(programId);
84
+ if (!(await git.isRepository(cwd))) {
85
+ throw new Error(`${cwd} is not a git repository; run \`git init\` or plan from inside your repository.`);
86
+ }
87
+ const current = await git.currentBranch(cwd);
88
+ if (current === undefined) {
89
+ throw new Error("HEAD is detached; check out your default branch, then re-run.");
90
+ }
91
+ if (await git.localBranchExists(cwd, branch)) {
92
+ await git.switchTo(cwd, branch);
93
+ return { action: "switched", branch };
94
+ }
95
+ await git.createAndSwitch(cwd, branch);
96
+ return { action: "created", branch };
97
+ }
98
+ /**
99
+ * Resolves the repository's default branch name, in order: `origin/HEAD`,
100
+ * then the first of `main`/`master` that exists locally, then
101
+ * `init.defaultBranch`, then `"main"`.
102
+ *
103
+ * This is a heuristic, not a guarantee. It is authoritative when
104
+ * `origin/HEAD` is set and correct for the common `main`/`master` local
105
+ * repositories, but it cannot identify a custom default (say `trunk`) with
106
+ * neither `origin/HEAD` nor a matching `init.defaultBranch` — it will return
107
+ * `main` in that case. This does not create a safety hole: the run
108
+ * preconditions in `run-program.ts` never rely on this alone. If this
109
+ * function misnames the default, the wrong-branch precondition still refuses
110
+ * a run on any branch that is not the one derived from the program ID; only
111
+ * the specificity of the refusal message degrades.
112
+ */
113
+ export async function detectDefaultBranch(cwd, git = defaultProgramBranchGit) {
114
+ const originHead = await git.originHeadBranch(cwd);
115
+ if (originHead !== undefined)
116
+ return originHead;
117
+ for (const candidate of ["main", "master"]) {
118
+ if (await git.localBranchExists(cwd, candidate))
119
+ return candidate;
120
+ }
121
+ return (await git.configDefaultBranch(cwd)) ?? "main";
122
+ }
123
+ //# sourceMappingURL=program-branch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program-branch.js","sourceRoot":"","sources":["../src/program-branch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `docs/programs` — the runner's own bookkeeping: the manifest, the append-only
3
+ * decision ledger, and the run report. Nothing an agent is asked to build ever
4
+ * lives here, which is why `diffSince` excludes it from every diff a reviewer
5
+ * or decider sees.
6
+ *
7
+ * It is also the one directory a `git reset --hard` must never take with it.
8
+ * Both rollback seams — `decide`'s replay and the runner's failed-fix reset —
9
+ * roll *code* back to an anchor commit while the journal explaining why must
10
+ * survive: the ledger is append-only by contract, and a rollback that
11
+ * truncated it would erase the very record the human is meant to rule on.
12
+ * Snapshot before the reset, restore after.
13
+ */
14
+ export declare const PROGRAMS_DIR: string;
15
+ export interface FileSnapshot {
16
+ relPath: string;
17
+ content: Buffer;
18
+ }
19
+ /** Every file under `docs/programs`, in memory. A missing directory is an empty snapshot. */
20
+ export declare function snapshotProgramsDir(root: string): Promise<FileSnapshot[]>;
21
+ /**
22
+ * Write a snapshot back. Purely additive: a file the reset removed is
23
+ * restored, a file written after the snapshot is left alone — nothing under
24
+ * `docs/programs` is ever deleted here.
25
+ */
26
+ export declare function restoreProgramsDir(root: string, snapshot: FileSnapshot[]): Promise<void>;
27
+ //# sourceMappingURL=programs-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"programs-dir.d.ts","sourceRoot":"","sources":["../src/programs-dir.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,YAAY,QAA2B,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6FAA6F;AAC7F,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAmB/E;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,YAAY,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -0,0 +1,52 @@
1
+ import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
2
+ import { dirname, join, relative } from "node:path";
3
+ /**
4
+ * `docs/programs` — the runner's own bookkeeping: the manifest, the append-only
5
+ * decision ledger, and the run report. Nothing an agent is asked to build ever
6
+ * lives here, which is why `diffSince` excludes it from every diff a reviewer
7
+ * or decider sees.
8
+ *
9
+ * It is also the one directory a `git reset --hard` must never take with it.
10
+ * Both rollback seams — `decide`'s replay and the runner's failed-fix reset —
11
+ * roll *code* back to an anchor commit while the journal explaining why must
12
+ * survive: the ledger is append-only by contract, and a rollback that
13
+ * truncated it would erase the very record the human is meant to rule on.
14
+ * Snapshot before the reset, restore after.
15
+ */
16
+ export const PROGRAMS_DIR = join("docs", "programs");
17
+ /** Every file under `docs/programs`, in memory. A missing directory is an empty snapshot. */
18
+ export async function snapshotProgramsDir(root) {
19
+ const dir = join(root, PROGRAMS_DIR);
20
+ let entries;
21
+ try {
22
+ entries = await readdir(dir, { recursive: true });
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ const snapshots = [];
28
+ for (const entry of entries) {
29
+ const full = join(dir, entry);
30
+ const info = await stat(full);
31
+ if (!info.isFile())
32
+ continue;
33
+ snapshots.push({
34
+ relPath: relative(root, full),
35
+ content: await readFile(full),
36
+ });
37
+ }
38
+ return snapshots;
39
+ }
40
+ /**
41
+ * Write a snapshot back. Purely additive: a file the reset removed is
42
+ * restored, a file written after the snapshot is left alone — nothing under
43
+ * `docs/programs` is ever deleted here.
44
+ */
45
+ export async function restoreProgramsDir(root, snapshot) {
46
+ for (const file of snapshot) {
47
+ const full = join(root, file.relPath);
48
+ await mkdir(dirname(full), { recursive: true });
49
+ await writeFile(full, file.content);
50
+ }
51
+ }
52
+ //# sourceMappingURL=programs-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"programs-dir.js","sourceRoot":"","sources":["../src/programs-dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;;;;;;;;GAYG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAOrD,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACrC,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,SAAS;QAC7B,SAAS,CAAC,IAAI,CAAC;YACb,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;YAC7B,OAAO,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC;SAC9B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,QAAwB;IAExB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The handover from a finished run to a reviewable pull request: pushes the
3
+ * program branch, opens or updates exactly one draft PR through `gh`,
4
+ * renders the run report as its body (continuing oversized reports into
5
+ * comments), and upserts one comment per escalated decision. Idempotent —
6
+ * re-publishing edits the existing PR and its comments rather than
7
+ * duplicating them.
8
+ *
9
+ * `publish` is deliberately separate from `runProgram`: the runner owns
10
+ * commits and knows nothing about forges, and this command owns the forge
11
+ * and knows nothing about building. Authentication is entirely `gh`'s job —
12
+ * nightshift never reads, stores, or passes a token.
13
+ */
14
+ export declare const GITHUB_PR_BODY_LIMIT = 65536;
15
+ export interface GhComment {
16
+ /** The forge's own comment id, opaque; used to edit or delete it. */
17
+ id: string;
18
+ body: string;
19
+ }
20
+ export interface GhPullRequest {
21
+ number: number;
22
+ url: string;
23
+ /** open | closed | merged — so publish can tell a live handover from history. */
24
+ state: "open" | "closed" | "merged";
25
+ /** Whether the PR is still a draft; asserted by the SC-06 test. */
26
+ isDraft: boolean;
27
+ }
28
+ export interface GhClient {
29
+ /**
30
+ * Preflight: succeeds when `gh` is installed and authenticated, and throws
31
+ * the actionable "not installed" / "not authenticated" errors otherwise.
32
+ * Called once at the very start of publish, before any push or PR work.
33
+ */
34
+ checkAuth(cwd: string): Promise<void>;
35
+ /**
36
+ * The open PR whose head is this branch, or undefined. Returns only an
37
+ * OPEN PR — a closed or merged PR for the branch is history, not the live
38
+ * handover. Never returns two: GitHub permits at most one open PR per
39
+ * head->base pair.
40
+ */
41
+ findOpenPullRequest(cwd: string, headBranch: string): Promise<GhPullRequest | undefined>;
42
+ /** Opens a draft PR; returns its number, url, state, and draft flag. */
43
+ createDraftPullRequest(cwd: string, input: {
44
+ headBranch: string;
45
+ baseBranch: string;
46
+ title: string;
47
+ body: string;
48
+ }): Promise<GhPullRequest>;
49
+ /** Rewrites the body of an existing PR; does not change its draft/ready state. */
50
+ updatePullRequestBody(cwd: string, number: number, body: string): Promise<void>;
51
+ listComments(cwd: string, number: number): Promise<GhComment[]>;
52
+ createComment(cwd: string, number: number, body: string): Promise<void>;
53
+ updateComment(cwd: string, commentId: string, body: string): Promise<void>;
54
+ /** Removes a now-stale nightshift-authored comment. */
55
+ deleteComment(cwd: string, commentId: string): Promise<void>;
56
+ }
57
+ /**
58
+ * Git operations `publish` needs beyond `program-branch.ts`'s derivation —
59
+ * kept local to this module, mirroring `ProgramBranchGit`, so the runner's
60
+ * `GitOps` stays about building, not remotes.
61
+ */
62
+ export interface PublishGit {
63
+ /** The branch HEAD points at, for the provenance check; `git rev-parse --abbrev-ref HEAD`. */
64
+ currentBranch(cwd: string): Promise<string>;
65
+ /** Is the branch ahead of base? `git rev-list --count <base>..<branch>`. */
66
+ commitsAhead(cwd: string, base: string, branch: string): Promise<number>;
67
+ push(cwd: string, remote: string, branch: string): Promise<void>;
68
+ }
69
+ export declare const defaultPublishGit: PublishGit;
70
+ export declare const defaultGhClient: GhClient;
71
+ export interface PublishOptions {
72
+ cwd: string;
73
+ programId: string;
74
+ /** Injected GitHub boundary; default spawns `gh`. */
75
+ gh?: GhClient;
76
+ /** Injected git boundary; default execFile-backed. */
77
+ git?: PublishGit;
78
+ log?: (line: string) => void;
79
+ }
80
+ export interface PublishResult {
81
+ prNumber: number;
82
+ prUrl: string;
83
+ action: "created" | "updated";
84
+ /** Escalation comments upserted this publish. */
85
+ escalationComments: number;
86
+ /** Report-continuation comments upserted this publish (0 when the report fits). */
87
+ continuationComments: number;
88
+ }
89
+ interface ReportChunk {
90
+ /** A verbatim, contiguous slice of the report — never rewritten or decorated. */
91
+ payload: string;
92
+ /** True when this chunk's payload ends mid-section (the degenerate fallback). */
93
+ cutMidSection: boolean;
94
+ }
95
+ /**
96
+ * Splits the run report into chunks whose payloads are verbatim, contiguous
97
+ * slices of the report — concatenating every payload in order reproduces the
98
+ * report byte-for-byte. A report that fits under the limit is a single
99
+ * chunk; an oversized report is packed on section boundaries, falling back
100
+ * to paragraph/character boundaries only for a section too large on its own.
101
+ */
102
+ export declare function splitReportIntoChunks(report: string): ReportChunk[];
103
+ export declare function publish(options: PublishOptions): Promise<PublishResult>;
104
+ export {};
105
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"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"}