@jaybeeuu/agent-cortex 1.20.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 (154) hide show
  1. package/.beads/README.md +81 -0
  2. package/.beads/config.yaml +1 -0
  3. package/.beads/issues.jsonl +236 -0
  4. package/.beads/metadata.json +7 -0
  5. package/.claude-plugin/marketplace.json +16 -0
  6. package/.github/workflows/ci.test.ts +217 -0
  7. package/.github/workflows/ci.yml +35 -0
  8. package/.github/workflows/publish.yml +36 -0
  9. package/.junie/guidelines.md +87 -0
  10. package/.junie/mcp/mcp.json +10 -0
  11. package/AGENTS.md +102 -0
  12. package/CHANGELOG.md +705 -0
  13. package/README.md +209 -0
  14. package/agents/README.md +235 -0
  15. package/agents/plan.agent.md +56 -0
  16. package/agents/ralph-plan.agent.md +119 -0
  17. package/agents/ralph.agent.md +305 -0
  18. package/agents/strategy.agent.md +109 -0
  19. package/agents-native/ralph.md +193 -0
  20. package/bin/agent-cortex.mjs +27 -0
  21. package/claude/.claude-plugin/plugin.json +11 -0
  22. package/claude/.mcp.json +18 -0
  23. package/claude/agents/plan.md +56 -0
  24. package/claude/agents/ralph-plan.md +119 -0
  25. package/claude/agents/ralph.md +193 -0
  26. package/claude/agents/strategy.md +109 -0
  27. package/claude/hooks.json +23 -0
  28. package/claude/scripts/statusline-command.sh +124 -0
  29. package/docs/ideas/auto-model-selection.md +75 -0
  30. package/docs/ideas/improve-pi-system-prompt.md +34 -0
  31. package/docs/ideas/model-selector.md +40 -0
  32. package/docs/ideas/pi-task-memory.md +34 -0
  33. package/docs/ideas/qa-extension.md +43 -0
  34. package/docs/inspirations.md +33 -0
  35. package/docs/research/gas-city-research.md +256 -0
  36. package/docs/research/skill-design-research.md +286 -0
  37. package/docs/research/skill-improvements-analysis.md +117 -0
  38. package/docs/research/skill-patterns-research.md +24 -0
  39. package/docs/skills/skill-anatomy.md +149 -0
  40. package/docs/user-preferences.md +17 -0
  41. package/extensions/agent-modes/index.ts +507 -0
  42. package/extensions/auto-name.ts +107 -0
  43. package/extensions/context-loader.md +35 -0
  44. package/extensions/context-loader.ts +65 -0
  45. package/extensions/lib/tiny-model.ts +212 -0
  46. package/extensions/notify/index.ts +293 -0
  47. package/extensions/session-start.ts +44 -0
  48. package/extensions/skill-stats/README.md +74 -0
  49. package/extensions/skill-stats/context-loader.test.ts +107 -0
  50. package/extensions/skill-stats/discover.ts +119 -0
  51. package/extensions/skill-stats/format.ts +13 -0
  52. package/extensions/skill-stats/index.test.ts +452 -0
  53. package/extensions/skill-stats/index.ts +222 -0
  54. package/extensions/skill-stats/package.json +19 -0
  55. package/extensions/skill-stats/pnpm-lock.yaml +329 -0
  56. package/extensions/skill-stats/record.ts +48 -0
  57. package/extensions/skill-stats/store.ts +104 -0
  58. package/extensions/skill-stats/tsconfig.json +12 -0
  59. package/extensions/subagent/README.md +175 -0
  60. package/extensions/subagent/agents/planner.md +37 -0
  61. package/extensions/subagent/agents/reviewer.md +35 -0
  62. package/extensions/subagent/agents/scout.md +50 -0
  63. package/extensions/subagent/agents/worker.md +24 -0
  64. package/extensions/subagent/agents.ts +126 -0
  65. package/extensions/subagent/index.ts +1138 -0
  66. package/extensions/subagent/prompts/implement-and-review.md +10 -0
  67. package/extensions/subagent/prompts/implement.md +10 -0
  68. package/extensions/subagent/prompts/scout-and-plan.md +9 -0
  69. package/hooks.json +10 -0
  70. package/lib/cli.mjs +37 -0
  71. package/package.json +39 -0
  72. package/pi/keybindings.json +3 -0
  73. package/pi/settings.json +29 -0
  74. package/plugin.json +35 -0
  75. package/pnpm-workspace.yaml +7 -0
  76. package/scripts/build-claude-agents.mjs +179 -0
  77. package/scripts/install-instructions.sh +82 -0
  78. package/skills/engineering/design-an-interface/SKILL.md +94 -0
  79. package/skills/engineering/grill-with-docs/SKILL.md +88 -0
  80. package/skills/engineering/improve-codebase-architecture/REFERENCE.md +78 -0
  81. package/skills/engineering/improve-codebase-architecture/SKILL.md +81 -0
  82. package/skills/engineering/tdd/SKILL.md +150 -0
  83. package/skills/engineering/tdd/deep-modules.md +33 -0
  84. package/skills/engineering/tdd/interface-design.md +31 -0
  85. package/skills/engineering/tdd/mocking.md +59 -0
  86. package/skills/engineering/tdd/refactoring.md +10 -0
  87. package/skills/engineering/tdd/tests.md +61 -0
  88. package/skills/engineering/technical-direction/SKILL.md +86 -0
  89. package/skills/planning/classify-bead/SKILL.md +67 -0
  90. package/skills/planning/create-task/SKILL.md +96 -0
  91. package/skills/planning/create-task/pipeline.json +33 -0
  92. package/skills/planning/create-task/scripts/create-chores.ts +112 -0
  93. package/skills/planning/create-task/scripts/package.json +14 -0
  94. package/skills/planning/create-task/scripts/pnpm-lock.yaml +342 -0
  95. package/skills/planning/create-task/scripts/tsconfig.json +12 -0
  96. package/skills/planning/create-task/templates/code.md +40 -0
  97. package/skills/planning/create-task/templates/document.md +40 -0
  98. package/skills/planning/create-task/templates/fix.md +27 -0
  99. package/skills/planning/create-task/templates/review.md +36 -0
  100. package/skills/planning/create-task/templates/verify.md +43 -0
  101. package/skills/planning/prd-to-tasks/SKILL.md +227 -0
  102. package/skills/planning/record-idea/SKILL.md +62 -0
  103. package/skills/planning/record-idea/scripts/new-idea.sh +89 -0
  104. package/skills/planning/request-refactor-plan/SKILL.md +73 -0
  105. package/skills/planning/write-a-prd/SKILL.md +74 -0
  106. package/skills/planning/write-a-ticket/SKILL.md +97 -0
  107. package/skills/productivity/bd-tool/SKILL.md +90 -0
  108. package/skills/productivity/grill-me/SKILL.md +10 -0
  109. package/skills/productivity/handoff/SKILL.md +15 -0
  110. package/skills/productivity/init-beads/SKILL.md +93 -0
  111. package/skills/productivity/teach/GLOSSARY-FORMAT.md +35 -0
  112. package/skills/productivity/teach/LEARNING-RECORD-FORMAT.md +46 -0
  113. package/skills/productivity/teach/MISSION-FORMAT.md +31 -0
  114. package/skills/productivity/teach/RESOURCES-FORMAT.md +32 -0
  115. package/skills/productivity/teach/SKILL.md +109 -0
  116. package/skills/productivity/validate-agent-dir/scripts/package.json +15 -0
  117. package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +329 -0
  118. package/skills/productivity/validate-agent-dir/scripts/pnpm-workspace.yaml +2 -0
  119. package/skills/productivity/validate-agent-dir/scripts/tsconfig.json +19 -0
  120. package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.test.ts +317 -0
  121. package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.ts +127 -0
  122. package/skills/productivity/write-a-skill/SKILL.md +74 -0
  123. package/skills/review/maintain-agent-docs/REFERENCE.md +246 -0
  124. package/skills/review/maintain-agent-docs/SKILL.md +83 -0
  125. package/skills/review/refactor-skill/EXAMPLES.md +20 -0
  126. package/skills/review/refactor-skill/SKILL.md +148 -0
  127. package/skills/review/review-security/SKILL.md +107 -0
  128. package/skills/review/review-security/scripts/install-gitleaks.sh +43 -0
  129. package/skills/style/style-code/REFERENCE.md +38 -0
  130. package/skills/style/style-code/SKILL.md +113 -0
  131. package/skills/style/style-comms/SKILL.md +93 -0
  132. package/skills/style/style-documentation/SKILL.md +112 -0
  133. package/skills/style/style-tests/SKILL.md +97 -0
  134. package/skills/workflow/git-workflow/SKILL.md +85 -0
  135. package/skills/workflow/hitl-collab/SKILL.md +29 -0
  136. package/skills/workflow/plan/SKILL.md +272 -0
  137. package/skills/workflow/ralph/REFERENCE.md +202 -0
  138. package/skills/workflow/ralph/SKILL.md +105 -0
  139. package/skills/workflow/run-pipeline-stage/SKILL.md +151 -0
  140. package/skills/workflow/run-pipeline-stage/playbooks/code.md +17 -0
  141. package/skills/workflow/run-pipeline-stage/playbooks/document.md +18 -0
  142. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +17 -0
  143. package/skills/workflow/run-pipeline-stage/playbooks/review.md +19 -0
  144. package/skills/workflow/run-pipeline-stage/playbooks/verify.md +14 -0
  145. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +20 -0
  146. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +783 -0
  147. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +586 -0
  148. package/skills/workflow/run-pipeline-stage/scripts/package.json +15 -0
  149. package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +342 -0
  150. package/skills/workflow/run-pipeline-stage/scripts/pnpm-workspace.yaml +2 -0
  151. package/skills/workflow/run-pipeline-stage/scripts/tsconfig.json +12 -0
  152. package/skills/workflow/using-agent-skills/SKILL.md +109 -0
  153. package/skills/workflow/using-agent-skills/scripts/validate-skill-structure.test.ts +73 -0
  154. package/test/cli.test.mjs +149 -0
@@ -0,0 +1,329 @@
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+
9
+ .:
10
+ devDependencies:
11
+ '@types/node':
12
+ specifier: ^22.20.1
13
+ version: 22.20.1
14
+ tsx:
15
+ specifier: ^4.23.0
16
+ version: 4.23.5
17
+ typescript:
18
+ specifier: ^5.0.0
19
+ version: 5.9.3
20
+
21
+ packages:
22
+
23
+ '@esbuild/aix-ppc64@0.28.1':
24
+ resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
25
+ engines: {node: '>=18'}
26
+ cpu: [ppc64]
27
+ os: [aix]
28
+
29
+ '@esbuild/android-arm64@0.28.1':
30
+ resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
31
+ engines: {node: '>=18'}
32
+ cpu: [arm64]
33
+ os: [android]
34
+
35
+ '@esbuild/android-arm@0.28.1':
36
+ resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
37
+ engines: {node: '>=18'}
38
+ cpu: [arm]
39
+ os: [android]
40
+
41
+ '@esbuild/android-x64@0.28.1':
42
+ resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
43
+ engines: {node: '>=18'}
44
+ cpu: [x64]
45
+ os: [android]
46
+
47
+ '@esbuild/darwin-arm64@0.28.1':
48
+ resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
49
+ engines: {node: '>=18'}
50
+ cpu: [arm64]
51
+ os: [darwin]
52
+
53
+ '@esbuild/darwin-x64@0.28.1':
54
+ resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
55
+ engines: {node: '>=18'}
56
+ cpu: [x64]
57
+ os: [darwin]
58
+
59
+ '@esbuild/freebsd-arm64@0.28.1':
60
+ resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
61
+ engines: {node: '>=18'}
62
+ cpu: [arm64]
63
+ os: [freebsd]
64
+
65
+ '@esbuild/freebsd-x64@0.28.1':
66
+ resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
67
+ engines: {node: '>=18'}
68
+ cpu: [x64]
69
+ os: [freebsd]
70
+
71
+ '@esbuild/linux-arm64@0.28.1':
72
+ resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
73
+ engines: {node: '>=18'}
74
+ cpu: [arm64]
75
+ os: [linux]
76
+
77
+ '@esbuild/linux-arm@0.28.1':
78
+ resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
79
+ engines: {node: '>=18'}
80
+ cpu: [arm]
81
+ os: [linux]
82
+
83
+ '@esbuild/linux-ia32@0.28.1':
84
+ resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
85
+ engines: {node: '>=18'}
86
+ cpu: [ia32]
87
+ os: [linux]
88
+
89
+ '@esbuild/linux-loong64@0.28.1':
90
+ resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
91
+ engines: {node: '>=18'}
92
+ cpu: [loong64]
93
+ os: [linux]
94
+
95
+ '@esbuild/linux-mips64el@0.28.1':
96
+ resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
97
+ engines: {node: '>=18'}
98
+ cpu: [mips64el]
99
+ os: [linux]
100
+
101
+ '@esbuild/linux-ppc64@0.28.1':
102
+ resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
103
+ engines: {node: '>=18'}
104
+ cpu: [ppc64]
105
+ os: [linux]
106
+
107
+ '@esbuild/linux-riscv64@0.28.1':
108
+ resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
109
+ engines: {node: '>=18'}
110
+ cpu: [riscv64]
111
+ os: [linux]
112
+
113
+ '@esbuild/linux-s390x@0.28.1':
114
+ resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
115
+ engines: {node: '>=18'}
116
+ cpu: [s390x]
117
+ os: [linux]
118
+
119
+ '@esbuild/linux-x64@0.28.1':
120
+ resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
121
+ engines: {node: '>=18'}
122
+ cpu: [x64]
123
+ os: [linux]
124
+
125
+ '@esbuild/netbsd-arm64@0.28.1':
126
+ resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
127
+ engines: {node: '>=18'}
128
+ cpu: [arm64]
129
+ os: [netbsd]
130
+
131
+ '@esbuild/netbsd-x64@0.28.1':
132
+ resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
133
+ engines: {node: '>=18'}
134
+ cpu: [x64]
135
+ os: [netbsd]
136
+
137
+ '@esbuild/openbsd-arm64@0.28.1':
138
+ resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
139
+ engines: {node: '>=18'}
140
+ cpu: [arm64]
141
+ os: [openbsd]
142
+
143
+ '@esbuild/openbsd-x64@0.28.1':
144
+ resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
145
+ engines: {node: '>=18'}
146
+ cpu: [x64]
147
+ os: [openbsd]
148
+
149
+ '@esbuild/openharmony-arm64@0.28.1':
150
+ resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
151
+ engines: {node: '>=18'}
152
+ cpu: [arm64]
153
+ os: [openharmony]
154
+
155
+ '@esbuild/sunos-x64@0.28.1':
156
+ resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
157
+ engines: {node: '>=18'}
158
+ cpu: [x64]
159
+ os: [sunos]
160
+
161
+ '@esbuild/win32-arm64@0.28.1':
162
+ resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
163
+ engines: {node: '>=18'}
164
+ cpu: [arm64]
165
+ os: [win32]
166
+
167
+ '@esbuild/win32-ia32@0.28.1':
168
+ resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
169
+ engines: {node: '>=18'}
170
+ cpu: [ia32]
171
+ os: [win32]
172
+
173
+ '@esbuild/win32-x64@0.28.1':
174
+ resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
175
+ engines: {node: '>=18'}
176
+ cpu: [x64]
177
+ os: [win32]
178
+
179
+ '@types/node@22.20.1':
180
+ resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==}
181
+
182
+ esbuild@0.28.1:
183
+ resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
184
+ engines: {node: '>=18'}
185
+ hasBin: true
186
+
187
+ fsevents@2.3.3:
188
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
189
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
190
+ os: [darwin]
191
+
192
+ tsx@4.23.5:
193
+ resolution: {integrity: sha512-rw55FUaqOoI7RvlQwLbhO4nSDApnQ4/CykPuiQ/EPvtrX3WA9Ig55jIt9VvbBJbzJuj12ueRu4PMZ2SxPVbihg==}
194
+ engines: {node: '>=18.0.0'}
195
+ hasBin: true
196
+
197
+ typescript@5.9.3:
198
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
199
+ engines: {node: '>=14.17'}
200
+ hasBin: true
201
+
202
+ undici-types@6.21.0:
203
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
204
+
205
+ snapshots:
206
+
207
+ '@esbuild/aix-ppc64@0.28.1':
208
+ optional: true
209
+
210
+ '@esbuild/android-arm64@0.28.1':
211
+ optional: true
212
+
213
+ '@esbuild/android-arm@0.28.1':
214
+ optional: true
215
+
216
+ '@esbuild/android-x64@0.28.1':
217
+ optional: true
218
+
219
+ '@esbuild/darwin-arm64@0.28.1':
220
+ optional: true
221
+
222
+ '@esbuild/darwin-x64@0.28.1':
223
+ optional: true
224
+
225
+ '@esbuild/freebsd-arm64@0.28.1':
226
+ optional: true
227
+
228
+ '@esbuild/freebsd-x64@0.28.1':
229
+ optional: true
230
+
231
+ '@esbuild/linux-arm64@0.28.1':
232
+ optional: true
233
+
234
+ '@esbuild/linux-arm@0.28.1':
235
+ optional: true
236
+
237
+ '@esbuild/linux-ia32@0.28.1':
238
+ optional: true
239
+
240
+ '@esbuild/linux-loong64@0.28.1':
241
+ optional: true
242
+
243
+ '@esbuild/linux-mips64el@0.28.1':
244
+ optional: true
245
+
246
+ '@esbuild/linux-ppc64@0.28.1':
247
+ optional: true
248
+
249
+ '@esbuild/linux-riscv64@0.28.1':
250
+ optional: true
251
+
252
+ '@esbuild/linux-s390x@0.28.1':
253
+ optional: true
254
+
255
+ '@esbuild/linux-x64@0.28.1':
256
+ optional: true
257
+
258
+ '@esbuild/netbsd-arm64@0.28.1':
259
+ optional: true
260
+
261
+ '@esbuild/netbsd-x64@0.28.1':
262
+ optional: true
263
+
264
+ '@esbuild/openbsd-arm64@0.28.1':
265
+ optional: true
266
+
267
+ '@esbuild/openbsd-x64@0.28.1':
268
+ optional: true
269
+
270
+ '@esbuild/openharmony-arm64@0.28.1':
271
+ optional: true
272
+
273
+ '@esbuild/sunos-x64@0.28.1':
274
+ optional: true
275
+
276
+ '@esbuild/win32-arm64@0.28.1':
277
+ optional: true
278
+
279
+ '@esbuild/win32-ia32@0.28.1':
280
+ optional: true
281
+
282
+ '@esbuild/win32-x64@0.28.1':
283
+ optional: true
284
+
285
+ '@types/node@22.20.1':
286
+ dependencies:
287
+ undici-types: 6.21.0
288
+
289
+ esbuild@0.28.1:
290
+ optionalDependencies:
291
+ '@esbuild/aix-ppc64': 0.28.1
292
+ '@esbuild/android-arm': 0.28.1
293
+ '@esbuild/android-arm64': 0.28.1
294
+ '@esbuild/android-x64': 0.28.1
295
+ '@esbuild/darwin-arm64': 0.28.1
296
+ '@esbuild/darwin-x64': 0.28.1
297
+ '@esbuild/freebsd-arm64': 0.28.1
298
+ '@esbuild/freebsd-x64': 0.28.1
299
+ '@esbuild/linux-arm': 0.28.1
300
+ '@esbuild/linux-arm64': 0.28.1
301
+ '@esbuild/linux-ia32': 0.28.1
302
+ '@esbuild/linux-loong64': 0.28.1
303
+ '@esbuild/linux-mips64el': 0.28.1
304
+ '@esbuild/linux-ppc64': 0.28.1
305
+ '@esbuild/linux-riscv64': 0.28.1
306
+ '@esbuild/linux-s390x': 0.28.1
307
+ '@esbuild/linux-x64': 0.28.1
308
+ '@esbuild/netbsd-arm64': 0.28.1
309
+ '@esbuild/netbsd-x64': 0.28.1
310
+ '@esbuild/openbsd-arm64': 0.28.1
311
+ '@esbuild/openbsd-x64': 0.28.1
312
+ '@esbuild/openharmony-arm64': 0.28.1
313
+ '@esbuild/sunos-x64': 0.28.1
314
+ '@esbuild/win32-arm64': 0.28.1
315
+ '@esbuild/win32-ia32': 0.28.1
316
+ '@esbuild/win32-x64': 0.28.1
317
+
318
+ fsevents@2.3.3:
319
+ optional: true
320
+
321
+ tsx@4.23.5:
322
+ dependencies:
323
+ esbuild: 0.28.1
324
+ optionalDependencies:
325
+ fsevents: 2.3.3
326
+
327
+ typescript@5.9.3: {}
328
+
329
+ undici-types@6.21.0: {}
@@ -0,0 +1,2 @@
1
+ allowBuilds:
2
+ esbuild: true
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "allowImportingTsExtensions": true,
11
+ "noEmit": true,
12
+ "outDir": "./dist",
13
+ "rootDir": ".",
14
+ "declaration": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["*.ts"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }
@@ -0,0 +1,317 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+
7
+ import {
8
+ validateFrontmatter,
9
+ validateAgentDir,
10
+ type AgentDir,
11
+ type Frontmatter,
12
+ } from "./validate-agent-dir.ts";
13
+
14
+ // ─── Fixtures ─────────────────────────────────────────────────────────────────
15
+
16
+ function makeFrontmatter(overrides: Partial<Frontmatter> = {}): Frontmatter {
17
+ return {
18
+ name: "agent-cortex:ralph",
19
+ description: "Parallel task orchestration agent",
20
+ tools: ["bash", "task", "read_agent"],
21
+ ...overrides,
22
+ };
23
+ }
24
+
25
+ function createAgentDir(
26
+ tmpDir: string,
27
+ name: string,
28
+ frontmatter: Frontmatter,
29
+ body: string = "# Shared body\n\nYou are an agent.",
30
+ sections?: Record<string, string>
31
+ ): void {
32
+ const agentDir = join(tmpDir, "agents", name);
33
+ mkdirSync(agentDir, { recursive: true });
34
+
35
+ // Write agent.md
36
+ writeFileSync(join(agentDir, "agent.md"), body, "utf-8");
37
+
38
+ // Write frontmatter.json for PI harness
39
+ const piDir = join(agentDir, "pi");
40
+ mkdirSync(piDir, { recursive: true });
41
+ writeFileSync(join(piDir, "frontmatter.json"), JSON.stringify(frontmatter), "utf-8");
42
+
43
+ // Write optional sections
44
+ if (sections) {
45
+ for (const [filename, content] of Object.entries(sections)) {
46
+ writeFileSync(join(piDir, filename), content, "utf-8");
47
+ }
48
+ }
49
+ }
50
+
51
+ // ─── Behavior 1: validate frontmatter.json ────────────────────────────────────
52
+
53
+ describe("validateFrontmatter", () => {
54
+ it("accepts valid frontmatter with required fields", () => {
55
+ const fm = makeFrontmatter();
56
+ const result = validateFrontmatter(fm);
57
+ assert.equal(result.ok, true);
58
+ });
59
+
60
+ it("accepts frontmatter with optional model field", () => {
61
+ const fm = makeFrontmatter({ model: "claude-sonnet-4-5" });
62
+ const result = validateFrontmatter(fm);
63
+ assert.equal(result.ok, true);
64
+ });
65
+
66
+ it("accepts frontmatter with optional argumentHint field", () => {
67
+ const fm = makeFrontmatter({ argumentHint: "Run all pending beads" });
68
+ const result = validateFrontmatter(fm);
69
+ assert.equal(result.ok, true);
70
+ });
71
+
72
+ it("rejects frontmatter missing name", () => {
73
+ const fm = { description: "desc", tools: ["bash"] } as any;
74
+ const result = validateFrontmatter(fm);
75
+ assert.equal(result.ok, false);
76
+ assert.ok(result.errors.some((e) => e.includes("name")));
77
+ });
78
+
79
+ it("rejects frontmatter missing description", () => {
80
+ const fm = { name: "test", tools: ["bash"] } as any;
81
+ const result = validateFrontmatter(fm);
82
+ assert.equal(result.ok, false);
83
+ assert.ok(result.errors.some((e) => e.includes("description")));
84
+ });
85
+
86
+ it("rejects frontmatter missing tools", () => {
87
+ const fm = { name: "test", description: "desc" } as any;
88
+ const result = validateFrontmatter(fm);
89
+ assert.equal(result.ok, false);
90
+ assert.ok(result.errors.some((e) => e.includes("tools")));
91
+ });
92
+
93
+ it("rejects frontmatter with non-array tools", () => {
94
+ const fm = { name: "test", description: "desc", tools: "bash" } as any;
95
+ const result = validateFrontmatter(fm);
96
+ assert.equal(result.ok, false);
97
+ assert.ok(result.errors.some((e) => e.includes("tools")));
98
+ });
99
+
100
+ it("rejects frontmatter with empty name", () => {
101
+ const fm = makeFrontmatter({ name: "" });
102
+ const result = validateFrontmatter(fm);
103
+ assert.equal(result.ok, false);
104
+ assert.ok(result.errors.some((e) => e.includes("name")));
105
+ });
106
+
107
+ it("rejects frontmatter with empty description", () => {
108
+ const fm = makeFrontmatter({ description: "" });
109
+ const result = validateFrontmatter(fm);
110
+ assert.equal(result.ok, false);
111
+ assert.ok(result.errors.some((e) => e.includes("description")));
112
+ });
113
+
114
+ it("rejects frontmatter with empty tools array", () => {
115
+ const fm = makeFrontmatter({ tools: [] });
116
+ const result = validateFrontmatter(fm);
117
+ assert.equal(result.ok, false);
118
+ assert.ok(result.errors.some((e) => e.includes("tools")));
119
+ });
120
+
121
+ it("rejects frontmatter with unknown fields", () => {
122
+ const fm = makeFrontmatter({ unknownField: "value" } as any);
123
+ const result = validateFrontmatter(fm);
124
+ assert.equal(result.ok, false);
125
+ assert.ok(result.errors.some((e) => e.includes("unknown")));
126
+ });
127
+ });
128
+
129
+ // ─── Behavior 2: validate agent directory structure ───────────────────────────
130
+
131
+ describe("validateAgentDir", () => {
132
+ let tmpDir: string;
133
+
134
+ it("accepts valid agent directory with agent.md and pi/frontmatter.json", () => {
135
+ tmpDir = mkdtempSync(join(tmpdir(), "agent-dir-test-"));
136
+ try {
137
+ createAgentDir(tmpDir, "ralph", makeFrontmatter());
138
+ const result = validateAgentDir(join(tmpDir, "agents", "ralph"));
139
+ assert.equal(result.ok, true);
140
+ } finally {
141
+ rmSync(tmpDir, { recursive: true, force: true });
142
+ }
143
+ });
144
+
145
+ it("accepts agent directory with multiple harness subdirectories", () => {
146
+ tmpDir = mkdtempSync(join(tmpdir(), "agent-dir-test-"));
147
+ try {
148
+ const agentDir = join(tmpDir, "agents", "ralph");
149
+ mkdirSync(agentDir, { recursive: true });
150
+ writeFileSync(join(agentDir, "agent.md"), "# Body", "utf-8");
151
+
152
+ // PI harness
153
+ const piDir = join(agentDir, "pi");
154
+ mkdirSync(piDir, { recursive: true });
155
+ writeFileSync(
156
+ join(piDir, "frontmatter.json"),
157
+ JSON.stringify(makeFrontmatter({ tools: ["bash", "task"] })),
158
+ "utf-8"
159
+ );
160
+
161
+ // Claude harness
162
+ const claudeDir = join(agentDir, "claude");
163
+ mkdirSync(claudeDir, { recursive: true });
164
+ writeFileSync(
165
+ join(claudeDir, "frontmatter.json"),
166
+ JSON.stringify(makeFrontmatter({ tools: ["bash", "task"] })),
167
+ "utf-8"
168
+ );
169
+
170
+ const result = validateAgentDir(agentDir);
171
+ assert.equal(result.ok, true);
172
+ } finally {
173
+ rmSync(tmpDir, { recursive: true, force: true });
174
+ }
175
+ });
176
+
177
+ it("accepts agent directory with section files", () => {
178
+ tmpDir = mkdtempSync(join(tmpdir(), "agent-dir-test-"));
179
+ try {
180
+ createAgentDir(
181
+ tmpDir,
182
+ "ralph",
183
+ makeFrontmatter(),
184
+ "# Body\n\n{{SECTION:polling}}",
185
+ { "polling.md": "# Polling loop\n\nYou poll every 2 minutes." }
186
+ );
187
+ const result = validateAgentDir(join(tmpDir, "agents", "ralph"));
188
+ assert.equal(result.ok, true);
189
+ } finally {
190
+ rmSync(tmpDir, { recursive: true, force: true });
191
+ }
192
+ });
193
+
194
+ it("rejects agent directory missing agent.md", () => {
195
+ tmpDir = mkdtempSync(join(tmpdir(), "agent-dir-test-"));
196
+ try {
197
+ const agentDir = join(tmpDir, "agents", "ralph");
198
+ mkdirSync(agentDir, { recursive: true });
199
+ mkdirSync(join(agentDir, "pi"), { recursive: true });
200
+ writeFileSync(
201
+ join(agentDir, "pi", "frontmatter.json"),
202
+ JSON.stringify(makeFrontmatter()),
203
+ "utf-8"
204
+ );
205
+
206
+ const result = validateAgentDir(agentDir);
207
+ assert.equal(result.ok, false);
208
+ assert.ok(result.errors.some((e) => e.includes("agent.md")));
209
+ } finally {
210
+ rmSync(tmpDir, { recursive: true, force: true });
211
+ }
212
+ });
213
+
214
+ it("rejects agent directory with no harness subdirectories", () => {
215
+ tmpDir = mkdtempSync(join(tmpdir(), "agent-dir-test-"));
216
+ try {
217
+ const agentDir = join(tmpDir, "agents", "ralph");
218
+ mkdirSync(agentDir, { recursive: true });
219
+ writeFileSync(join(agentDir, "agent.md"), "# Body", "utf-8");
220
+
221
+ const result = validateAgentDir(agentDir);
222
+ assert.equal(result.ok, false);
223
+ assert.ok(result.errors.some((e) => e.includes("harness")));
224
+ } finally {
225
+ rmSync(tmpDir, { recursive: true, force: true });
226
+ }
227
+ });
228
+
229
+ it("rejects agent directory with invalid frontmatter in harness", () => {
230
+ tmpDir = mkdtempSync(join(tmpdir(), "agent-dir-test-"));
231
+ try {
232
+ const agentDir = join(tmpDir, "agents", "ralph");
233
+ mkdirSync(agentDir, { recursive: true });
234
+ writeFileSync(join(agentDir, "agent.md"), "# Body", "utf-8");
235
+
236
+ const piDir = join(agentDir, "pi");
237
+ mkdirSync(piDir, { recursive: true });
238
+ // Invalid frontmatter: missing tools
239
+ writeFileSync(
240
+ join(piDir, "frontmatter.json"),
241
+ JSON.stringify({ name: "test", description: "desc" }),
242
+ "utf-8"
243
+ );
244
+
245
+ const result = validateAgentDir(agentDir);
246
+ assert.equal(result.ok, false);
247
+ assert.ok(result.errors.some((e) => e.includes("tools")));
248
+ } finally {
249
+ rmSync(tmpDir, { recursive: true, force: true });
250
+ }
251
+ });
252
+ });
253
+
254
+ // ─── Behavior 3: token format validation ──────────────────────────────────────
255
+
256
+ describe("token format in agent.md body", () => {
257
+ it("accepts valid {{TOOL:name}} tokens", () => {
258
+ const body = "# Body\n\nUse {{TOOL:task}} to spawn subagents.";
259
+ const tokens = extractTokens(body);
260
+ assert.deepEqual(tokens.tools, ["task"]);
261
+ });
262
+
263
+ it("accepts valid {{PATH:name}} tokens", () => {
264
+ const body = "# Body\n\nRead {{PATH:skills/workflow/plan/SKILL.md}}";
265
+ const tokens = extractTokens(body);
266
+ assert.deepEqual(tokens.paths, ["skills/workflow/plan/SKILL.md"]);
267
+ });
268
+
269
+ it("accepts valid {{SECTION:name}} tokens", () => {
270
+ const body = "# Body\n\n{{SECTION:polling}}";
271
+ const tokens = extractTokens(body);
272
+ assert.deepEqual(tokens.sections, ["polling"]);
273
+ });
274
+
275
+ it("extracts multiple tokens of different types", () => {
276
+ const body = `
277
+ # Body
278
+
279
+ Use {{TOOL:task}} to spawn.
280
+ Read {{PATH:skills/plan/SKILL.md}}.
281
+ {{SECTION:polling}}
282
+ `;
283
+ const tokens = extractTokens(body);
284
+ assert.deepEqual(tokens.tools, ["task"]);
285
+ assert.deepEqual(tokens.paths, ["skills/plan/SKILL.md"]);
286
+ assert.deepEqual(tokens.sections, ["polling"]);
287
+ });
288
+ });
289
+
290
+ // ─── Helper: extract tokens from markdown ─────────────────────────────────────
291
+
292
+ function extractTokens(body: string): {
293
+ tools: string[];
294
+ paths: string[];
295
+ sections: string[];
296
+ } {
297
+ const toolPattern = /\{\{TOOL:([^}]+)\}\}/g;
298
+ const pathPattern = /\{\{PATH:([^}]+)\}\}/g;
299
+ const sectionPattern = /\{\{SECTION:([^}]+)\}\}/g;
300
+
301
+ const tools: string[] = [];
302
+ const paths: string[] = [];
303
+ const sections: string[] = [];
304
+
305
+ let match;
306
+ while ((match = toolPattern.exec(body)) !== null) {
307
+ tools.push(match[1]!);
308
+ }
309
+ while ((match = pathPattern.exec(body)) !== null) {
310
+ paths.push(match[1]!);
311
+ }
312
+ while ((match = sectionPattern.exec(body)) !== null) {
313
+ sections.push(match[1]!);
314
+ }
315
+
316
+ return { tools, paths, sections };
317
+ }