nightralph 0.0.2 → 0.0.4

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 (93) hide show
  1. package/README.md +113 -34
  2. package/dist/index.js +80 -22
  3. package/dist/index.js.map +2 -2
  4. package/dist/merge.js +194 -0
  5. package/dist/merge.js.map +7 -0
  6. package/dist/meta.json +189 -17
  7. package/dist/orchestrator.js +538 -45
  8. package/dist/orchestrator.js.map +2 -2
  9. package/dist/progress.js +164 -0
  10. package/dist/progress.js.map +7 -0
  11. package/dist/resolve.js +16 -8
  12. package/dist/resolve.js.map +2 -2
  13. package/dist/setup.js +33 -5
  14. package/dist/setup.js.map +2 -2
  15. package/dist/src/index.d.ts.map +1 -1
  16. package/dist/src/merge.d.ts +25 -0
  17. package/dist/src/merge.d.ts.map +1 -0
  18. package/dist/src/orchestrator.d.ts +29 -3
  19. package/dist/src/orchestrator.d.ts.map +1 -1
  20. package/dist/src/progress.d.ts +27 -0
  21. package/dist/src/progress.d.ts.map +1 -0
  22. package/dist/src/resolve.d.ts +2 -1
  23. package/dist/src/resolve.d.ts.map +1 -1
  24. package/dist/src/setup.d.ts +1 -0
  25. package/dist/src/setup.d.ts.map +1 -1
  26. package/dist/src/worktree.d.ts +18 -0
  27. package/dist/src/worktree.d.ts.map +1 -0
  28. package/dist/worktree.js +139 -0
  29. package/dist/worktree.js.map +7 -0
  30. package/package.json +8 -4
  31. package/.claude/settings.local.json +0 -5
  32. package/.github/dependabot.yml +0 -28
  33. package/.github/workflows/nodejs.yml +0 -30
  34. package/AGENTS.md +0 -60
  35. package/CLAUDE.md +0 -1
  36. package/PROMPT.md +0 -95
  37. package/WIP.md +0 -5
  38. package/dist/test/integration.test.js +0 -848
  39. package/dist/test/integration.test.js.map +0 -7
  40. package/dist/test/orchestrator.test.js +0 -749
  41. package/dist/test/orchestrator.test.js.map +0 -7
  42. package/dist/test/setup.test.js +0 -574
  43. package/dist/test/setup.test.js.map +0 -7
  44. package/docs/README.md +0 -12
  45. package/docs/agents/domain.md +0 -36
  46. package/docs/agents/issue-tracker.md +0 -30
  47. package/docs/agents/triage-labels.md +0 -15
  48. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase-2-future-work.md +0 -144
  49. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase_01.md +0 -292
  50. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase_02.md +0 -212
  51. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/test-requirements.md +0 -203
  52. package/docs/skills.md +0 -58
  53. package/docs/test-plans/2026-08-27-issue-tracker-choice.md +0 -95
  54. package/eslint.config.js +0 -142
  55. package/lib.es5.d.ts +0 -19
  56. package/progress.log +0 -190
  57. package/ralph_claude.sh +0 -263
  58. package/scripts/clone-skills.sh +0 -52
  59. package/specs/prd.json +0 -172
  60. package/src/docs-templates/domain.md +0 -36
  61. package/src/docs-templates/issue-tracker-github.md +0 -228
  62. package/src/docs-templates/issue-tracker.md +0 -30
  63. package/src/docs-templates/triage-labels.md +0 -15
  64. package/src/index.ts +0 -184
  65. package/src/orchestrator.ts +0 -324
  66. package/src/resolve.ts +0 -73
  67. package/src/setup.ts +0 -157
  68. package/src/skills/domain-modeling/ADR-FORMAT.md +0 -47
  69. package/src/skills/domain-modeling/CONTEXT-FORMAT.md +0 -60
  70. package/src/skills/domain-modeling/SKILL.md +0 -74
  71. package/src/skills/domain-modeling/agents/openai.yaml +0 -3
  72. package/src/skills/grill/SKILL.md +0 -7
  73. package/src/skills/grill/agents/openai.yaml +0 -5
  74. package/src/skills/grilling/SKILL.md +0 -28
  75. package/src/skills/grilling/agents/openai.yaml +0 -3
  76. package/src/skills/tdd/SKILL.md +0 -38
  77. package/src/skills/tdd/agents/openai.yaml +0 -3
  78. package/src/skills/tdd/mocking.md +0 -59
  79. package/src/skills/tdd/tests.md +0 -77
  80. package/src/skills/to-spec/SKILL.md +0 -75
  81. package/src/skills/to-spec/agents/openai.yaml +0 -5
  82. package/src/skills/to-tickets/SKILL.md +0 -105
  83. package/src/skills/to-tickets/agents/openai.yaml +0 -5
  84. package/src/skills/upstream.json +0 -5
  85. package/tasks/prd-integration-test-coverage.md +0 -243
  86. package/test/integration.test.ts +0 -636
  87. package/test/mock-agent-echo-args.js +0 -4
  88. package/test/mock-agent-fail.js +0 -3
  89. package/test/mock-agent-pass.js +0 -3
  90. package/test/orchestrator.test.ts +0 -609
  91. package/test/setup.test.ts +0 -417
  92. package/tsconfig.build.json +0 -7
  93. package/tsconfig.json +0 -31
@@ -0,0 +1,27 @@
1
+ import type { Ticket } from './orchestrator.js';
2
+ export type TicketProgress = {
3
+ num: number;
4
+ slug: string;
5
+ filename: string;
6
+ done: boolean;
7
+ branch: string | null;
8
+ exitCode: number | null;
9
+ completedAt: string | null;
10
+ };
11
+ export type ProgressData = {
12
+ feature: string;
13
+ startedAt: string;
14
+ tickets: Array<TicketProgress>;
15
+ };
16
+ export declare function generateProgress(feature: string, tickets: ReadonlyArray<Ticket>): ProgressData;
17
+ export declare function readProgress(progressPath: string): ProgressData | null;
18
+ export declare function mergeProgress(fresh: ProgressData, existing: ProgressData | null): ProgressData;
19
+ export declare function renderProgress(data: ProgressData): string;
20
+ export declare function checkTicket(data: ProgressData, ticketNum: number, result: {
21
+ branch: string;
22
+ exitCode: number;
23
+ done?: boolean;
24
+ }): void;
25
+ export declare function writeProgress(progressPath: string, data: ProgressData): void;
26
+ export declare function commitProgress(repoRoot: string, progressPath: string, message: string): Promise<void>;
27
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/progress.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAM/C,MAAM,MAAM,cAAc,GAAG;IACzB,GAAG,EAAC,MAAM,CAAA;IACV,IAAI,EAAC,MAAM,CAAA;IACX,QAAQ,EAAC,MAAM,CAAA;IACf,IAAI,EAAC,OAAO,CAAA;IACZ,MAAM,EAAC,MAAM,GAAC,IAAI,CAAA;IAClB,QAAQ,EAAC,MAAM,GAAC,IAAI,CAAA;IACpB,WAAW,EAAC,MAAM,GAAC,IAAI,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACvB,OAAO,EAAC,MAAM,CAAA;IACd,SAAS,EAAC,MAAM,CAAA;IAChB,OAAO,EAAC,KAAK,CAAC,cAAc,CAAC,CAAA;CAChC,CAAA;AAED,wBAAgB,gBAAgB,CAC5B,OAAO,EAAC,MAAM,EACd,OAAO,EAAC,aAAa,CAAC,MAAM,CAAC,GAC/B,YAAY,CAcb;AAED,wBAAgB,YAAY,CACxB,YAAY,EAAC,MAAM,GACrB,YAAY,GAAC,IAAI,CAwDlB;AAED,wBAAgB,aAAa,CACzB,KAAK,EAAC,YAAY,EAClB,QAAQ,EAAC,YAAY,GAAC,IAAI,GAC5B,YAAY,CAcb;AAED,wBAAgB,cAAc,CAAE,IAAI,EAAC,YAAY,GAAE,MAAM,CAgCxD;AAED,wBAAgB,WAAW,CACvB,IAAI,EAAC,YAAY,EACjB,SAAS,EAAC,MAAM,EAChB,MAAM,EAAC;IAAE,MAAM,EAAC,MAAM,CAAC;IAAC,QAAQ,EAAC,MAAM,CAAC;IAAC,IAAI,CAAC,EAAC,OAAO,CAAA;CAAE,GAC1D,IAAI,CAYL;AAED,wBAAgB,aAAa,CACzB,YAAY,EAAC,MAAM,EACnB,IAAI,EAAC,YAAY,GACnB,IAAI,CAKL;AAED,wBAAsB,cAAc,CAChC,QAAQ,EAAC,MAAM,EACf,YAAY,EAAC,MAAM,EACnB,OAAO,EAAC,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAYd"}
@@ -1,9 +1,10 @@
1
+ export declare function getScriptDir(metaUrl: string): string;
1
2
  export declare function findFeatureDirs(cwd: string): {
2
3
  name: string;
3
4
  dir: string;
4
5
  spec: string;
5
6
  }[];
6
- export declare function resolveIssuesDir(dirFlag: string | undefined, specFlag: string | undefined, cwd?: string): Promise<{
7
+ export declare function resolveIssuesDir(specName: string | undefined, cwd?: string): Promise<{
7
8
  dir: string;
8
9
  spec: string;
9
10
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/resolve.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,CAAE,GAAG,EAAC,MAAM,GAAE;IACzC,IAAI,EAAC,MAAM,CAAC;IACZ,GAAG,EAAC,MAAM,CAAC;IACX,IAAI,EAAC,MAAM,CAAA;CACd,EAAE,CAwBF;AAED,wBAAsB,gBAAgB,CAClC,OAAO,EAAC,MAAM,GAAC,SAAS,EACxB,QAAQ,EAAC,MAAM,GAAC,SAAS,EACzB,GAAG,GAAC,MAAsB,GAC5B,OAAO,CAAC;IAAE,GAAG,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAA;CAAE,CAAC,CAkCrC"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/resolve.ts"],"names":[],"mappings":"AAKA,wBAAgB,YAAY,CAAE,OAAO,EAAC,MAAM,GAAE,MAAM,CAEnD;AAED,wBAAgB,eAAe,CAAE,GAAG,EAAC,MAAM,GAAE;IACzC,IAAI,EAAC,MAAM,CAAC;IACZ,GAAG,EAAC,MAAM,CAAC;IACX,IAAI,EAAC,MAAM,CAAA;CACd,EAAE,CAwBF;AAED,wBAAsB,gBAAgB,CAClC,QAAQ,EAAC,MAAM,GAAC,SAAS,EACzB,GAAG,GAAC,MAAsB,GAC5B,OAAO,CAAC;IAAE,GAAG,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAA;CAAE,CAAC,CAmCrC"}
@@ -1,5 +1,6 @@
1
1
  export declare const SKILL_DIRS: readonly ["grill", "grilling", "domain-modeling", "to-spec", "to-tickets", "tdd"];
2
2
  export declare const DOC_TEMPLATES: readonly ["triage-labels.md", "domain.md"];
3
+ export declare function writeManagedSection(filePath: string, content: string): void;
3
4
  export declare function checkGhAuth(): boolean;
4
5
  export type TrackerKind = 'github' | 'local';
5
6
  export type SetupOpts = {
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/setup.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,UAAU,mFAGb,CAAA;AAEV,eAAO,MAAM,aAAa,4CAGhB,CAAA;AAEV,wBAAgB,WAAW,IAAI,OAAO,CAOrC;AAED,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAC,OAAO,CAAA;AAE1C,MAAM,MAAM,SAAS,GAAG;IACpB,gBAAgB,EAAC,MAAM,CAAA;IACvB,gBAAgB,EAAC,MAAM,CAAA;IACvB,UAAU,EAAC,MAAM,CAAA;IACjB,MAAM,CAAC,EAAC,OAAO,CAAA;IACf,OAAO,EAAC,WAAW,CAAA;CACtB,CAAA;AAOD,wBAAgB,KAAK,CAAE,IAAI,EAAC,SAAS,GAAE,IAAI,CA8G1C"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/setup.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,UAAU,mFAGb,CAAA;AAEV,eAAO,MAAM,aAAa,4CAGhB,CAAA;AAKV,wBAAgB,mBAAmB,CAC/B,QAAQ,EAAC,MAAM,EACf,OAAO,EAAC,MAAM,GAChB,IAAI,CA0BL;AAED,wBAAgB,WAAW,IAAI,OAAO,CAOrC;AAED,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAC,OAAO,CAAA;AAE1C,MAAM,MAAM,SAAS,GAAG;IACpB,gBAAgB,EAAC,MAAM,CAAA;IACvB,gBAAgB,EAAC,MAAM,CAAA;IACvB,UAAU,EAAC,MAAM,CAAA;IACjB,MAAM,CAAC,EAAC,OAAO,CAAA;IACf,OAAO,EAAC,WAAW,CAAA;CACtB,CAAA;AAOD,wBAAgB,KAAK,CAAE,IAAI,EAAC,SAAS,GAAE,IAAI,CA8G1C"}
@@ -0,0 +1,18 @@
1
+ import type { Ticket } from './orchestrator.js';
2
+ export declare function getRepoRoot(): string;
3
+ export declare function getRepoName(): string;
4
+ export declare function getCurrentBranch(): string;
5
+ export declare function createWorktree(opts: {
6
+ repoRoot: string;
7
+ repoName: string;
8
+ baseBranch: string;
9
+ ticket: Ticket;
10
+ }): Promise<{
11
+ worktreePath: string;
12
+ branchName: string;
13
+ }>;
14
+ export declare function removeWorktree(worktreePath: string): Promise<void>;
15
+ export declare function hasNewCommits(repoRoot: string, base: string, branch: string): boolean;
16
+ export declare function isDirty(cwd: string): boolean;
17
+ export declare function listWorktrees(repoRoot: string): Promise<Array<string>>;
18
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/worktree.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAI/C,wBAAgB,WAAW,IAAI,MAAM,CAOpC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAkBD,wBAAsB,cAAc,CAChC,IAAI,EAAC;IACD,QAAQ,EAAC,MAAM,CAAA;IACf,QAAQ,EAAC,MAAM,CAAA;IACf,UAAU,EAAC,MAAM,CAAA;IACjB,MAAM,EAAC,MAAM,CAAA;CAChB,GACH,OAAO,CAAC;IAAE,YAAY,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,CAAA;CAAE,CAAC,CA2DpD;AAED,wBAAsB,cAAc,CAChC,YAAY,EAAC,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAOd;AAED,wBAAgB,aAAa,CACzB,QAAQ,EAAC,MAAM,EACf,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,MAAM,GACf,OAAO,CAOR;AAED,wBAAgB,OAAO,CAAE,GAAG,EAAC,MAAM,GAAE,OAAO,CAO3C;AAED,wBAAsB,aAAa,CAC/B,QAAQ,EAAC,MAAM,GACjB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAWvB"}
@@ -0,0 +1,139 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { execFile, execFileSync } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+ import { basename, join } from "node:path";
6
+ import { existsSync } from "node:fs";
7
+ const execFileAsync = promisify(execFile);
8
+ function getRepoRoot() {
9
+ const stdout = execFileSync(
10
+ "git",
11
+ ["rev-parse", "--show-toplevel"],
12
+ { encoding: "utf8" }
13
+ );
14
+ return stdout.trim();
15
+ }
16
+ __name(getRepoRoot, "getRepoRoot");
17
+ function getRepoName() {
18
+ return basename(getRepoRoot());
19
+ }
20
+ __name(getRepoName, "getRepoName");
21
+ function getCurrentBranch() {
22
+ const stdout = execFileSync(
23
+ "git",
24
+ ["rev-parse", "--abbrev-ref", "HEAD"],
25
+ { encoding: "utf8" }
26
+ );
27
+ return stdout.trim();
28
+ }
29
+ __name(getCurrentBranch, "getCurrentBranch");
30
+ async function branchExists(repoRoot, branchName) {
31
+ try {
32
+ await execFileAsync(
33
+ "git",
34
+ ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`],
35
+ { cwd: repoRoot }
36
+ );
37
+ return true;
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+ __name(branchExists, "branchExists");
43
+ async function createWorktree(opts) {
44
+ const { repoRoot, repoName, baseBranch, ticket } = opts;
45
+ const branchName = `${repoName}/${String(
46
+ ticket.num
47
+ ).padStart(2, "0")}-${ticket.slug}`;
48
+ const worktreePath = join(
49
+ repoRoot,
50
+ "..",
51
+ `${repoName}.${String(
52
+ ticket.num
53
+ ).padStart(2, "0")}-${ticket.slug}`
54
+ );
55
+ if (existsSync(worktreePath)) {
56
+ try {
57
+ await execFileAsync(
58
+ "git",
59
+ ["worktree", "remove", "--force", worktreePath],
60
+ { cwd: repoRoot }
61
+ );
62
+ } catch {
63
+ }
64
+ }
65
+ try {
66
+ await execFileAsync(
67
+ "git",
68
+ ["worktree", "prune"],
69
+ { cwd: repoRoot }
70
+ );
71
+ } catch {
72
+ }
73
+ if (await branchExists(repoRoot, branchName)) {
74
+ await execFileAsync(
75
+ "git",
76
+ ["branch", "-D", branchName],
77
+ { cwd: repoRoot }
78
+ );
79
+ }
80
+ await execFileAsync(
81
+ "git",
82
+ [
83
+ "worktree",
84
+ "add",
85
+ "-b",
86
+ branchName,
87
+ worktreePath,
88
+ baseBranch
89
+ ],
90
+ { cwd: repoRoot }
91
+ );
92
+ return { worktreePath, branchName };
93
+ }
94
+ __name(createWorktree, "createWorktree");
95
+ async function removeWorktree(worktreePath) {
96
+ await execFileAsync(
97
+ "git",
98
+ ["-C", worktreePath, "worktree", "remove", worktreePath]
99
+ );
100
+ }
101
+ __name(removeWorktree, "removeWorktree");
102
+ function hasNewCommits(repoRoot, base, branch) {
103
+ const stdout = execFileSync(
104
+ "git",
105
+ ["rev-list", "--count", `${base}..${branch}`],
106
+ { cwd: repoRoot, encoding: "utf8" }
107
+ );
108
+ return Number(stdout.trim()) > 0;
109
+ }
110
+ __name(hasNewCommits, "hasNewCommits");
111
+ function isDirty(cwd) {
112
+ const stdout = execFileSync(
113
+ "git",
114
+ ["status", "--porcelain"],
115
+ { cwd, encoding: "utf8" }
116
+ );
117
+ return stdout.trim().length > 0;
118
+ }
119
+ __name(isDirty, "isDirty");
120
+ async function listWorktrees(repoRoot) {
121
+ const { stdout } = await execFileAsync(
122
+ "git",
123
+ ["worktree", "list", "--porcelain"],
124
+ { cwd: repoRoot }
125
+ );
126
+ return stdout.trim().split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.substring("worktree ".length));
127
+ }
128
+ __name(listWorktrees, "listWorktrees");
129
+ export {
130
+ createWorktree,
131
+ getCurrentBranch,
132
+ getRepoName,
133
+ getRepoRoot,
134
+ hasNewCommits,
135
+ isDirty,
136
+ listWorktrees,
137
+ removeWorktree
138
+ };
139
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/worktree.ts"],
4
+ "sourcesContent": ["import { execFile, execFileSync } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { basename, join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Ticket } from './orchestrator.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport function getRepoRoot ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--show-toplevel'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nexport function getRepoName ():string {\n return basename(getRepoRoot())\n}\n\nexport function getCurrentBranch ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--abbrev-ref', 'HEAD'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nasync function branchExists (\n repoRoot:string,\n branchName:string\n):Promise<boolean> {\n try {\n await execFileAsync(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branchName}`],\n { cwd:repoRoot }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function createWorktree (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n ticket:Ticket\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, repoName, baseBranch, ticket } = opts\n const branchName = `${repoName}/${String(\n ticket.num\n ).padStart(2, '0')}-${ticket.slug}`\n const worktreePath = join(\n repoRoot,\n '..',\n `${repoName}.${String(\n ticket.num\n ).padStart(2, '0')}-${ticket.slug}`\n )\n\n if (existsSync(worktreePath)) {\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'remove', '--force', worktreePath],\n { cwd:repoRoot }\n )\n } catch {\n // directory may not be a registered worktree anymore;\n // prune stale entries below and let worktree add fail\n // loudly if the path is still unusable\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'prune'],\n { cwd:repoRoot }\n )\n } catch {\n // best-effort cleanup of stale worktree metadata\n }\n\n if (await branchExists(repoRoot, branchName)) {\n await execFileAsync(\n 'git',\n ['branch', '-D', branchName],\n { cwd:repoRoot }\n )\n }\n\n await execFileAsync(\n 'git',\n [\n 'worktree',\n 'add',\n '-b',\n branchName,\n worktreePath,\n baseBranch,\n ],\n { cwd:repoRoot }\n )\n\n return { worktreePath, branchName }\n}\n\nexport async function removeWorktree (\n worktreePath:string\n):Promise<void> {\n // Use git -C to run the command from the worktree directory context\n // so git can resolve the repository\n await execFileAsync(\n 'git',\n ['-C', worktreePath, 'worktree', 'remove', worktreePath]\n )\n}\n\nexport function hasNewCommits (\n repoRoot:string,\n base:string,\n branch:string\n):boolean {\n const stdout = execFileSync(\n 'git',\n ['rev-list', '--count', `${base}..${branch}`],\n { cwd:repoRoot, encoding:'utf8' }\n )\n return Number(stdout.trim()) > 0\n}\n\nexport function isDirty (cwd:string):boolean {\n const stdout = execFileSync(\n 'git',\n ['status', '--porcelain'],\n { cwd, encoding:'utf8' }\n )\n return stdout.trim().length > 0\n}\n\nexport async function listWorktrees (\n repoRoot:string\n):Promise<Array<string>> {\n const { stdout } = await execFileAsync(\n 'git',\n ['worktree', 'list', '--porcelain'],\n { cwd:repoRoot }\n )\n return stdout\n .trim()\n .split('\\n')\n .filter(line => line.startsWith('worktree '))\n .map(line => line.substring('worktree '.length))\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,26 +1,30 @@
1
1
  {
2
2
  "name": "nightralph",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "description": "Orchestrator that runs a single-agent session per issue.",
6
6
  "bin": {
7
7
  "nightralph": "dist/index.js"
8
8
  },
9
+ "files": [
10
+ "dist/**",
11
+ "!dist/test"
12
+ ],
9
13
  "engines": {
10
- "node": ">=18"
14
+ "node": ">=24"
11
15
  },
12
16
  "scripts": {
13
17
  "lint": "eslint \"./**/*.{ts,js}\"",
14
18
  "start": "npm run build && node dist/index.js",
15
19
  "build": "mkdir -p ./dist && rm -rf ./dist/* && npm run build-esm && npm run copy",
16
- "build-esm": "esbuild src/index.ts src/orchestrator.ts src/setup.ts src/resolve.ts --format=esm --metafile=dist/meta.json --keep-names --tsconfig=tsconfig.build.json --outdir=./dist --sourcemap && tsc --emitDeclarationOnly --project tsconfig.build.json",
20
+ "build-esm": "esbuild src/index.ts src/orchestrator.ts src/setup.ts src/resolve.ts src/worktree.ts src/progress.ts src/merge.ts --format=esm --metafile=dist/meta.json --keep-names --tsconfig=tsconfig.build.json --outdir=./dist --sourcemap && tsc --emitDeclarationOnly --project tsconfig.build.json",
17
21
  "copy": "mkdir -p ./dist/skills ./dist/docs-templates && cp -r ./src/skills/* ./dist/skills && cp -r ./src/docs-templates/* ./dist/docs-templates",
18
22
  "clone-skills": "bash scripts/clone-skills.sh",
19
23
  "toc": "markdown-toc --maxdepth 3 -i README.md",
20
24
  "preversion": "npm run lint",
21
25
  "version": "npm run toc",
22
26
  "postversion": "git push --follow-tags && npm publish",
23
- "test": "esbuild test/setup.test.ts test/orchestrator.test.ts test/integration.test.ts --format=esm --bundle --packages=external --outdir=dist/test --sourcemap && node dist/test/setup.test.js && node dist/test/orchestrator.test.js && node dist/test/integration.test.js"
27
+ "test": "esbuild test/setup.test.ts test/orchestrator.test.ts test/worktree.test.ts test/progress.test.ts test/merge.test.ts test/integration.test.ts --format=esm --bundle --packages=external --outdir=dist/test --sourcemap && node dist/test/setup.test.js && node dist/test/orchestrator.test.js && node dist/test/worktree.test.js && node dist/test/progress.test.js && node dist/test/merge.test.js && node dist/test/integration.test.js"
24
28
  },
25
29
  "dependencies": {
26
30
  "@inquirer/prompts": "^8.7.0",
@@ -1,5 +0,0 @@
1
- {
2
- "enabledPlugins": {
3
- "mattpocock-skills@claude-plugins-official": true
4
- }
5
- }
@@ -1,28 +0,0 @@
1
- version: 2
2
- updates:
3
- # Enable version updates for npm
4
- - package-ecosystem: "npm"
5
- # Look for `package.json` and `lock` files in the `root` directory
6
- directory: "/"
7
- # Check the npm registry for updates every day (weekdays)
8
- schedule:
9
- interval: "monthly"
10
- groups:
11
- # This is the name of your group. It will be used in PR titles and branch names
12
- dev-dependencies:
13
- patterns:
14
- - "*"
15
- ignore:
16
- - dependency-name: "eslint"
17
- update-types: ["version-update:semver-major"]
18
- - dependency-name: "eslint*"
19
- update-types: ["version-update:semver-major"]
20
- - dependency-name: "typescript-eslint"
21
- update-types: ["version-update:semver-major"]
22
- - dependency-name: "neostandard"
23
- update-types: ["version-update:semver-major"]
24
- # Enable updates to github actions
25
- - package-ecosystem: "github-actions"
26
- directory: "/"
27
- schedule:
28
- interval: "monthly"
@@ -1,30 +0,0 @@
1
- name: Node CI
2
-
3
- on: [push]
4
-
5
- jobs:
6
- build:
7
-
8
- runs-on: ubuntu-22.04
9
- timeout-minutes: 5
10
-
11
- strategy:
12
- matrix:
13
- node-version: [25.x]
14
-
15
- steps:
16
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
17
- - name: Use Node.js ${{ matrix.node-version }}
18
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
19
- with:
20
- node-version: ${{ matrix.node-version }}
21
- - name: npm install, build
22
- run: |
23
- npm install
24
- npm run build --if-present
25
- npm run lint
26
- env:
27
- CI: true
28
- - name: Run tap tests
29
- run: |
30
- npm test
package/AGENTS.md DELETED
@@ -1,60 +0,0 @@
1
- # nightralph
2
-
3
- Last verified: 2026-08-27
4
-
5
- Small orchestrator that runs a single-agent session per issue.
6
-
7
- ## Tech Stack
8
- - TypeScript, Node >= 18, ESM
9
- - CLI: yargs + @inquirer/prompts
10
- - Testing: @substrate-system/tapzero
11
-
12
- ## Commands
13
- - `npm run build` -- build to dist/
14
- - `npm test` -- build and run tests
15
- - `npm run lint` -- eslint
16
-
17
- ## Project Structure
18
- - `src/index.ts` -- CLI entry point (yargs commands)
19
- - `src/setup.ts` -- project scaffolding module
20
- - `src/orchestrator.ts` -- ticket scanning and wave execution
21
- - `src/skills/` -- bundled skill definitions
22
- - `src/docs-templates/` -- doc templates copied to target projects
23
-
24
- ## Contracts
25
-
26
- ### setup module (`src/setup.ts`)
27
- - **Exposes**: `setup(opts)`, `checkGhAuth()`,
28
- `TrackerKind`, `SetupOpts`, `SKILL_DIRS`, `DOC_TEMPLATES`
29
- - **TrackerKind**: `'github'|'local'`
30
- - **SetupOpts.tracker**: required -- selects which
31
- issue-tracker template is installed and what AGENTS.md
32
- content is generated in the target project
33
- - **checkGhAuth()**: returns true when
34
- `gh auth status` succeeds
35
- - **DOC_TEMPLATES**: `['triage-labels.md', 'domain.md']` --
36
- issue-tracker.md is handled separately via tracker selection
37
- - **Guarantees**: `setup()` always overwrites
38
- `issue-tracker.md` (not skip-if-exists like other
39
- templates); always writes AGENTS.md to the target project
40
-
41
- ### CLI (`src/index.ts`)
42
- - `nightralph setup [--claude]` -- prompts for tracker
43
- format, then scaffolds skills and docs
44
- - `nightralph <provider> [options]` -- executes tickets
45
-
46
- ## Agent skills
47
-
48
- ### Issue tracker
49
-
50
- Issues are tracked as local markdown files under
51
- `.scratch/`. See `docs/agents/issue-tracker.md`.
52
-
53
- ### Triage labels
54
-
55
- Default label vocabulary.
56
- See `docs/agents/triage-labels.md`.
57
-
58
- ### Domain docs
59
-
60
- Single-context layout. See `docs/agents/domain.md`.
package/CLAUDE.md DELETED
@@ -1 +0,0 @@
1
- Read @./AGENTS.md and treat its contents as if they were in CLAUDE.md
package/PROMPT.md DELETED
@@ -1,95 +0,0 @@
1
- # MISSION
2
-
3
- Build and maintain nightralph -- a small orchestrator CLI that runs
4
- single-agent sessions per issue.
5
-
6
- # Role
7
- You are an expert TypeScript/Node.js engineer specializing in CLI tools,
8
- process orchestration, and test automation.
9
-
10
- # Objective
11
-
12
- Develop and test a CLI orchestrator using:
13
-
14
- - Runtime: Node >= 18, ESM
15
- - CLI: yargs for command parsing, @inquirer/prompts for interactive input
16
- - Build: esbuild (ESM output to dist/)
17
- - Testing: @substrate-system/tapzero
18
-
19
- ## META INSTRUCTION
20
-
21
- Before performing any tool call or code change, emit a short, one-line status
22
- update in the terminal starting with 'LOG: [Action]'. This helps me track your
23
- progress in the Ralph Loop.
24
-
25
- ## EXECUTION RULES
26
-
27
- 1. READ: At the start of EVERY session, read `specs/prd.json` and `progress.log`.
28
- 2. SCOPE: Pick the highest-priority task where `passes: false` (or missing).
29
- Work ONLY on that one task. Do not touch or mark any other story.
30
- 3. WRITE TESTS FIRST: Write failing tests for the feature/bug, then implement
31
- until they pass.
32
- 4. TARGETED TESTING WHILE WORKING:
33
- - DO NOT run the full suite (`npm test`) for every minor change.
34
- - DO run only the tests relevant to the file you are editing
35
- (e.g., `npx vitest run path/to/file.spec.ts`).
36
- 5. VERIFY BEFORE COMMIT (and only then run the full suite):
37
- - Run `npm run lint`.
38
- - Run the FULL suite `npm test` ONCE, when you believe the task is complete.
39
- - If lint or the full suite fails, fix it before committing.
40
- (Rules 4 and 5 are complementary: targeted tests during the work, one full
41
- suite run as the final gate. Never run the full suite after every edit.)
42
- 6. DOCUMENT: Append to `progress.log` what changed and any new patterns or
43
- gotchas discovered (these become context for future sessions).
44
- 7. UPDATE PRD: In `specs/prd.json`, set `passes: true` for the completed story
45
- ONLY. Leave every other story untouched.
46
- 8. COMMIT: After the full suite passes, commit with a descriptive message like
47
- `FEATURE: [TaskID] - [Description]`. ALWAYS COMMIT AFTER COMPLETING A TASK —
48
- an uncommitted change does not count as progress.
49
- 9. ATOMICITY: Complete EXACTLY ONE task per session, then STOP.
50
-
51
- ## CRITICAL: NON-INTERACTIVE MODE
52
-
53
- This is an autonomous session. You must NEVER:
54
- - Ask clarifying questions.
55
- - Wait for user input.
56
- - Output questions like 'What would you like me to work on?'
57
- If a detail is genuinely ambiguous, make the most reasonable assumption,
58
- record it in `progress.log`, and proceed.
59
-
60
- ## Strict Constraints
61
-
62
- - Do NOT add new dependencies. If you believe one is truly required, do not
63
- install it -- document the need in `progress.log` and proceed without it.
64
- - Prefer standard Node.js APIs over third-party alternatives wherever possible.
65
- - Stay within the tech stack above. Do not introduce other test runners or
66
- build tools.
67
-
68
- # Technical Constraints
69
-
70
- - CLI entry point: `src/index.ts` (yargs commands)
71
- - Project scaffolding: `src/setup.ts`
72
- - Ticket scanning and wave execution: `src/orchestrator.ts`
73
- - Bundled skills: `src/skills/`
74
- - Doc templates: `src/docs-templates/`
75
- - Build: `npm run build` (esbuild to dist/)
76
- - Test: `npm test` (esbuild + node to run tapzero tests)
77
- - Lint: `npm run lint` (eslint)
78
-
79
- # Error Handling
80
-
81
- If you hit a bug you cannot fix this session, document the failure and what you
82
- tried in `progress.log`, then stop. Do not loop on the same failing approach --
83
- a future session (with stronger reasoning hints) will pick it up.
84
-
85
- ## STOP CONDITION
86
-
87
- Once ALL tasks in `specs/prd.json` have `passes: true`, output the EXACT string
88
- on its own line, as your final message, after the work is verified:
89
-
90
- <promise>COMPLETE</promise>
91
-
92
- Do not emit that string in any other context (e.g., while planning or
93
- explaining) -- the loop treats it as a completion signal only when the PRD also
94
- shows zero pending tasks, so emitting it early just wastes a check. Do not
95
- perform any further work once all tasks are verified.
package/WIP.md DELETED
@@ -1,5 +0,0 @@
1
- # WIP
2
-
3
- ``sh
4
- /ed3d-plan-and-execute:execute-implementation-plan /Users/nick/code/nightralph/docs/implementation-plans/2026-08-27-issue-tracker-choice/ /Users/nick/code/nightralph/
5
- ```