nightralph 0.0.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 (101) hide show
  1. package/.claude/settings.local.json +5 -0
  2. package/AGENTS.md +60 -0
  3. package/CLAUDE.md +1 -0
  4. package/PROMPT.md +95 -0
  5. package/README.md +138 -0
  6. package/WIP.md +5 -0
  7. package/dist/docs-templates/domain.md +36 -0
  8. package/dist/docs-templates/issue-tracker-github.md +228 -0
  9. package/dist/docs-templates/issue-tracker.md +30 -0
  10. package/dist/docs-templates/triage-labels.md +15 -0
  11. package/dist/index.js +154 -0
  12. package/dist/index.js.map +7 -0
  13. package/dist/meta.json +207 -0
  14. package/dist/orchestrator.js +273 -0
  15. package/dist/orchestrator.js.map +7 -0
  16. package/dist/resolve.js +71 -0
  17. package/dist/resolve.js.map +7 -0
  18. package/dist/setup.js +151 -0
  19. package/dist/setup.js.map +7 -0
  20. package/dist/skills/domain-modeling/ADR-FORMAT.md +47 -0
  21. package/dist/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  22. package/dist/skills/domain-modeling/SKILL.md +74 -0
  23. package/dist/skills/domain-modeling/agents/openai.yaml +3 -0
  24. package/dist/skills/grill/SKILL.md +7 -0
  25. package/dist/skills/grill/agents/openai.yaml +5 -0
  26. package/dist/skills/grilling/SKILL.md +28 -0
  27. package/dist/skills/grilling/agents/openai.yaml +3 -0
  28. package/dist/skills/tdd/SKILL.md +38 -0
  29. package/dist/skills/tdd/agents/openai.yaml +3 -0
  30. package/dist/skills/tdd/mocking.md +59 -0
  31. package/dist/skills/tdd/tests.md +77 -0
  32. package/dist/skills/to-spec/SKILL.md +75 -0
  33. package/dist/skills/to-spec/agents/openai.yaml +5 -0
  34. package/dist/skills/to-tickets/SKILL.md +105 -0
  35. package/dist/skills/to-tickets/agents/openai.yaml +5 -0
  36. package/dist/skills/upstream.json +5 -0
  37. package/dist/src/index.d.ts +4 -0
  38. package/dist/src/index.d.ts.map +1 -0
  39. package/dist/src/orchestrator.d.ts +31 -0
  40. package/dist/src/orchestrator.d.ts.map +1 -0
  41. package/dist/src/resolve.d.ts +10 -0
  42. package/dist/src/resolve.d.ts.map +1 -0
  43. package/dist/src/setup.d.ts +13 -0
  44. package/dist/src/setup.d.ts.map +1 -0
  45. package/dist/test/integration.test.js +848 -0
  46. package/dist/test/integration.test.js.map +7 -0
  47. package/dist/test/orchestrator.test.js +749 -0
  48. package/dist/test/orchestrator.test.js.map +7 -0
  49. package/dist/test/setup.test.js +574 -0
  50. package/dist/test/setup.test.js.map +7 -0
  51. package/docs/README.md +12 -0
  52. package/docs/agents/domain.md +36 -0
  53. package/docs/agents/issue-tracker.md +30 -0
  54. package/docs/agents/triage-labels.md +15 -0
  55. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase-2-future-work.md +144 -0
  56. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase_01.md +292 -0
  57. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase_02.md +212 -0
  58. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/test-requirements.md +203 -0
  59. package/docs/skills.md +58 -0
  60. package/docs/test-plans/2026-08-27-issue-tracker-choice.md +95 -0
  61. package/eslint.config.js +142 -0
  62. package/lib.es5.d.ts +19 -0
  63. package/package.json +36 -0
  64. package/progress.log +190 -0
  65. package/ralph_claude.sh +263 -0
  66. package/scripts/clone-skills.sh +52 -0
  67. package/specs/prd.json +172 -0
  68. package/src/docs-templates/domain.md +36 -0
  69. package/src/docs-templates/issue-tracker-github.md +228 -0
  70. package/src/docs-templates/issue-tracker.md +30 -0
  71. package/src/docs-templates/triage-labels.md +15 -0
  72. package/src/index.ts +184 -0
  73. package/src/orchestrator.ts +324 -0
  74. package/src/resolve.ts +73 -0
  75. package/src/setup.ts +157 -0
  76. package/src/skills/domain-modeling/ADR-FORMAT.md +47 -0
  77. package/src/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  78. package/src/skills/domain-modeling/SKILL.md +74 -0
  79. package/src/skills/domain-modeling/agents/openai.yaml +3 -0
  80. package/src/skills/grill/SKILL.md +7 -0
  81. package/src/skills/grill/agents/openai.yaml +5 -0
  82. package/src/skills/grilling/SKILL.md +28 -0
  83. package/src/skills/grilling/agents/openai.yaml +3 -0
  84. package/src/skills/tdd/SKILL.md +38 -0
  85. package/src/skills/tdd/agents/openai.yaml +3 -0
  86. package/src/skills/tdd/mocking.md +59 -0
  87. package/src/skills/tdd/tests.md +77 -0
  88. package/src/skills/to-spec/SKILL.md +75 -0
  89. package/src/skills/to-spec/agents/openai.yaml +5 -0
  90. package/src/skills/to-tickets/SKILL.md +105 -0
  91. package/src/skills/to-tickets/agents/openai.yaml +5 -0
  92. package/src/skills/upstream.json +5 -0
  93. package/tasks/prd-integration-test-coverage.md +243 -0
  94. package/test/integration.test.ts +636 -0
  95. package/test/mock-agent-echo-args.js +4 -0
  96. package/test/mock-agent-fail.js +3 -0
  97. package/test/mock-agent-pass.js +3 -0
  98. package/test/orchestrator.test.ts +609 -0
  99. package/test/setup.test.ts +417 -0
  100. package/tsconfig.build.json +7 -0
  101. package/tsconfig.json +31 -0
@@ -0,0 +1,417 @@
1
+ import { test } from '@substrate-system/tapzero'
2
+ import {
3
+ mkdtempSync, mkdirSync, writeFileSync, existsSync,
4
+ lstatSync, readlinkSync, readFileSync,
5
+ } from 'node:fs'
6
+ import { join } from 'node:path'
7
+ import { tmpdir } from 'node:os'
8
+ import {
9
+ setup, SKILL_DIRS, DOC_TEMPLATES, checkGhAuth,
10
+ } from '../src/setup.js'
11
+
12
+ function makeTempProject ():{
13
+ projectDir:string;
14
+ bundledSkillsDir:string;
15
+ docsTemplatesDir:string;
16
+ } {
17
+ const base = mkdtempSync(
18
+ join(tmpdir(), 'nightralph-test-')
19
+ )
20
+ const projectDir = join(base, 'project')
21
+ mkdirSync(projectDir, { recursive:true })
22
+
23
+ const bundledSkillsDir = join(base, 'bundled')
24
+ mkdirSync(bundledSkillsDir, { recursive:true })
25
+
26
+ writeFileSync(
27
+ join(bundledSkillsDir, 'upstream.json'),
28
+ JSON.stringify({
29
+ repo:'test/repo',
30
+ commit:'abc123',
31
+ })
32
+ )
33
+
34
+ for (const skill of SKILL_DIRS) {
35
+ const dir = join(bundledSkillsDir, skill)
36
+ mkdirSync(dir, { recursive:true })
37
+ writeFileSync(
38
+ join(dir, 'SKILL.md'),
39
+ `# ${skill}`
40
+ )
41
+ }
42
+
43
+ const docsTemplatesDir = join(base, 'docs-templates')
44
+ mkdirSync(docsTemplatesDir, { recursive:true })
45
+ for (const tmpl of DOC_TEMPLATES) {
46
+ writeFileSync(
47
+ join(docsTemplatesDir, tmpl),
48
+ `# ${tmpl}`
49
+ )
50
+ }
51
+ writeFileSync(
52
+ join(docsTemplatesDir, 'issue-tracker.md'),
53
+ '# issue-tracker.md'
54
+ )
55
+ writeFileSync(
56
+ join(docsTemplatesDir, 'issue-tracker-github.md'),
57
+ '# issue-tracker-github.md'
58
+ )
59
+
60
+ return { projectDir, bundledSkillsDir, docsTemplatesDir }
61
+ }
62
+
63
+ test('setup copies skills to .agents/skills', t => {
64
+ const {
65
+ projectDir, bundledSkillsDir, docsTemplatesDir,
66
+ } = makeTempProject()
67
+
68
+ setup({
69
+ bundledSkillsDir,
70
+ docsTemplatesDir,
71
+ projectDir,
72
+ tracker:'local',
73
+ })
74
+
75
+ for (const skill of SKILL_DIRS) {
76
+ const dest = join(
77
+ projectDir, '.agents', 'skills', skill
78
+ )
79
+ t.ok(
80
+ existsSync(dest),
81
+ `${skill}/ should exist in .agents/skills`
82
+ )
83
+ t.ok(
84
+ existsSync(join(dest, 'SKILL.md')),
85
+ `${skill}/SKILL.md should be copied`
86
+ )
87
+ }
88
+ })
89
+
90
+ test('setup does NOT create .claude/skills by default', t => {
91
+ const {
92
+ projectDir, bundledSkillsDir, docsTemplatesDir,
93
+ } = makeTempProject()
94
+
95
+ setup({
96
+ bundledSkillsDir,
97
+ docsTemplatesDir,
98
+ projectDir,
99
+ tracker:'local',
100
+ })
101
+
102
+ const claudeSkills = join(
103
+ projectDir, '.claude', 'skills'
104
+ )
105
+ t.ok(
106
+ !existsSync(claudeSkills),
107
+ '.claude/skills should not exist without --claude'
108
+ )
109
+ })
110
+
111
+ test('setup --claude creates symlinks in .claude/skills', t => {
112
+ const {
113
+ projectDir, bundledSkillsDir, docsTemplatesDir,
114
+ } = makeTempProject()
115
+
116
+ setup({
117
+ bundledSkillsDir,
118
+ docsTemplatesDir,
119
+ projectDir,
120
+ claude:true,
121
+ tracker:'local',
122
+ })
123
+
124
+ for (const skill of SKILL_DIRS) {
125
+ const agentsDest = join(
126
+ projectDir, '.agents', 'skills', skill
127
+ )
128
+ t.ok(
129
+ existsSync(agentsDest),
130
+ `${skill}/ should exist in .agents/skills`
131
+ )
132
+
133
+ const claudeDest = join(
134
+ projectDir, '.claude', 'skills', skill
135
+ )
136
+ t.ok(
137
+ existsSync(claudeDest),
138
+ `${skill}/ should exist in .claude/skills`
139
+ )
140
+
141
+ if (!existsSync(claudeDest)) {
142
+ t.fail(`symlink missing for ${skill}`)
143
+ continue
144
+ }
145
+
146
+ const stat = lstatSync(claudeDest)
147
+ t.ok(
148
+ stat.isSymbolicLink(),
149
+ `.claude/skills/${skill} should be a symlink`
150
+ )
151
+
152
+ const target = readlinkSync(claudeDest)
153
+ const expected = join(
154
+ '..', '..', '.agents', 'skills', skill
155
+ )
156
+ t.equal(
157
+ target,
158
+ expected,
159
+ `symlink should point to ${expected}`
160
+ )
161
+ }
162
+ })
163
+
164
+ test('setup creates docs/agents/ templates', t => {
165
+ const {
166
+ projectDir, bundledSkillsDir, docsTemplatesDir,
167
+ } = makeTempProject()
168
+
169
+ setup({
170
+ bundledSkillsDir,
171
+ docsTemplatesDir,
172
+ projectDir,
173
+ tracker:'local',
174
+ })
175
+
176
+ for (const tmpl of DOC_TEMPLATES) {
177
+ const dest = join(
178
+ projectDir, 'docs', 'agents', tmpl
179
+ )
180
+ t.ok(
181
+ existsSync(dest),
182
+ `docs/agents/${tmpl} should be created`
183
+ )
184
+ }
185
+ })
186
+
187
+ test('setup does not overwrite non-tracker docs', t => {
188
+ const {
189
+ projectDir, bundledSkillsDir, docsTemplatesDir,
190
+ } = makeTempProject()
191
+ const triagePath = join(
192
+ projectDir, 'docs', 'agents', 'triage-labels.md'
193
+ )
194
+ mkdirSync(join(projectDir, 'docs', 'agents'), {
195
+ recursive:true,
196
+ })
197
+ writeFileSync(triagePath, 'custom triage content')
198
+
199
+ setup({
200
+ bundledSkillsDir,
201
+ docsTemplatesDir,
202
+ projectDir,
203
+ tracker:'local',
204
+ })
205
+
206
+ const content = readFileSync(triagePath, 'utf8')
207
+ t.equal(
208
+ content,
209
+ 'custom triage content',
210
+ 'should preserve existing triage-labels.md'
211
+ )
212
+ })
213
+
214
+ test('setup is idempotent', t => {
215
+ const {
216
+ projectDir, bundledSkillsDir, docsTemplatesDir,
217
+ } = makeTempProject()
218
+ const opts = {
219
+ bundledSkillsDir,
220
+ docsTemplatesDir,
221
+ projectDir,
222
+ claude:true,
223
+ tracker:'local' as const,
224
+ }
225
+
226
+ setup(opts)
227
+ setup(opts)
228
+
229
+ for (const skill of SKILL_DIRS) {
230
+ const agentsDest = join(
231
+ projectDir, '.agents', 'skills', skill
232
+ )
233
+ t.ok(
234
+ existsSync(agentsDest),
235
+ `${skill}/ should still exist after second run`
236
+ )
237
+
238
+ const claudeDest = join(
239
+ projectDir, '.claude', 'skills', skill
240
+ )
241
+ if (!existsSync(claudeDest)) {
242
+ t.fail(`symlink missing for ${skill}`)
243
+ continue
244
+ }
245
+ const stat = lstatSync(claudeDest)
246
+ t.ok(
247
+ stat.isSymbolicLink(),
248
+ `${skill} symlink should still be valid`
249
+ )
250
+ }
251
+
252
+ for (const tmpl of DOC_TEMPLATES) {
253
+ const dest = join(
254
+ projectDir, 'docs', 'agents', tmpl
255
+ )
256
+ t.ok(
257
+ existsSync(dest),
258
+ `docs/agents/${tmpl} should still exist`
259
+ )
260
+ }
261
+ })
262
+
263
+ test('checkGhAuth exists and is callable', t => {
264
+ t.equal(
265
+ typeof checkGhAuth,
266
+ 'function',
267
+ 'checkGhAuth should be a function'
268
+ )
269
+ })
270
+
271
+ test('setup with tracker:local copies local markdown template', t => {
272
+ const {
273
+ projectDir, bundledSkillsDir, docsTemplatesDir,
274
+ } = makeTempProject()
275
+
276
+ setup({
277
+ bundledSkillsDir,
278
+ docsTemplatesDir,
279
+ projectDir,
280
+ tracker:'local',
281
+ })
282
+
283
+ const trackerPath = join(
284
+ projectDir, 'docs', 'agents', 'issue-tracker.md'
285
+ )
286
+ t.ok(
287
+ existsSync(trackerPath),
288
+ 'docs/agents/issue-tracker.md should exist'
289
+ )
290
+ const content = readFileSync(trackerPath, 'utf8')
291
+ t.ok(
292
+ content.includes('# issue-tracker.md'),
293
+ 'should copy local markdown template'
294
+ )
295
+ })
296
+
297
+ test('setup with tracker:github copies github template', t => {
298
+ const {
299
+ projectDir, bundledSkillsDir, docsTemplatesDir,
300
+ } = makeTempProject()
301
+
302
+ setup({
303
+ bundledSkillsDir,
304
+ docsTemplatesDir,
305
+ projectDir,
306
+ tracker:'github',
307
+ })
308
+
309
+ const trackerPath = join(
310
+ projectDir, 'docs', 'agents', 'issue-tracker.md'
311
+ )
312
+ t.ok(
313
+ existsSync(trackerPath),
314
+ 'docs/agents/issue-tracker.md should exist'
315
+ )
316
+ const content = readFileSync(trackerPath, 'utf8')
317
+ t.ok(
318
+ content.includes('# issue-tracker-github.md'),
319
+ 'should copy github template'
320
+ )
321
+ })
322
+
323
+ test('setup creates AGENTS.md with local markdown text', t => {
324
+ const {
325
+ projectDir, bundledSkillsDir, docsTemplatesDir,
326
+ } = makeTempProject()
327
+
328
+ setup({
329
+ bundledSkillsDir,
330
+ docsTemplatesDir,
331
+ projectDir,
332
+ tracker:'local',
333
+ })
334
+
335
+ const agentsMdPath = join(projectDir, 'AGENTS.md')
336
+ t.ok(
337
+ existsSync(agentsMdPath),
338
+ 'AGENTS.md should exist'
339
+ )
340
+ const content = readFileSync(agentsMdPath, 'utf8')
341
+ t.ok(
342
+ content.includes('local markdown files'),
343
+ 'should mention local markdown'
344
+ )
345
+ })
346
+
347
+ test('setup creates AGENTS.md with GitHub Issues text', t => {
348
+ const {
349
+ projectDir, bundledSkillsDir, docsTemplatesDir,
350
+ } = makeTempProject()
351
+
352
+ setup({
353
+ bundledSkillsDir,
354
+ docsTemplatesDir,
355
+ projectDir,
356
+ tracker:'github',
357
+ })
358
+
359
+ const agentsMdPath = join(projectDir, 'AGENTS.md')
360
+ t.ok(
361
+ existsSync(agentsMdPath),
362
+ 'AGENTS.md should exist'
363
+ )
364
+ const content = readFileSync(agentsMdPath, 'utf8')
365
+ t.ok(
366
+ content.includes('GitHub Issues'),
367
+ 'should mention GitHub Issues'
368
+ )
369
+ })
370
+
371
+ test(
372
+ 'tracker template overwrites when switching trackers',
373
+ t => {
374
+ const {
375
+ projectDir, bundledSkillsDir,
376
+ docsTemplatesDir,
377
+ } = makeTempProject()
378
+
379
+ setup({
380
+ bundledSkillsDir,
381
+ docsTemplatesDir,
382
+ projectDir,
383
+ tracker:'local',
384
+ })
385
+
386
+ const trackerPath = join(
387
+ projectDir, 'docs', 'agents',
388
+ 'issue-tracker.md'
389
+ )
390
+ const localContent = readFileSync(
391
+ trackerPath, 'utf8'
392
+ )
393
+ t.ok(
394
+ localContent.includes('# issue-tracker.md'),
395
+ 'should have local template initially'
396
+ )
397
+
398
+ setup({
399
+ bundledSkillsDir,
400
+ docsTemplatesDir,
401
+ projectDir,
402
+ tracker:'github',
403
+ })
404
+
405
+ const githubContent = readFileSync(
406
+ trackerPath, 'utf8'
407
+ )
408
+ t.ok(
409
+ githubContent.includes('# issue-tracker-github.md'),
410
+ 'should overwrite with GitHub template'
411
+ )
412
+ t.ok(
413
+ !githubContent.includes('# issue-tracker.md'),
414
+ 'should not contain local template anymore'
415
+ )
416
+ }
417
+ )
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": [
4
+ "example",
5
+ "test"
6
+ ]
7
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ "listFiles": true,
4
+ "module": "NodeNext",
5
+ "target": "ES2022",
6
+ "moduleResolution": "NodeNext",
7
+ "esModuleInterop": true,
8
+ "lib": ["ES2021"],
9
+ "types": ["node"],
10
+ "allowJs": false,
11
+ "skipLibCheck": true,
12
+ "rootDir": ".",
13
+ "outDir": "dist",
14
+ "allowSyntheticDefaultImports": true,
15
+ "experimentalDecorators": true,
16
+ "emitDecoratorMetadata": true,
17
+ "strict": true,
18
+ "sourceMap": true,
19
+ "forceConsistentCasingInFileNames": true,
20
+ "isolatedModules": true,
21
+ "noImplicitAny": false,
22
+ "declaration": true,
23
+ "declarationDir": "dist",
24
+ "declarationMap": true
25
+ },
26
+ "include": [
27
+ "src",
28
+ "test",
29
+ "lib.es5.d.ts"
30
+ ]
31
+ }