all-hands-cli 0.1.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 (305) hide show
  1. package/.allhands/README.md +75 -0
  2. package/.allhands/agents/compounder.yaml +15 -0
  3. package/.allhands/agents/coordinator.yaml +17 -0
  4. package/.allhands/agents/documentor.yaml +15 -0
  5. package/.allhands/agents/e2e-test-planner.yaml +17 -0
  6. package/.allhands/agents/emergent.yaml +22 -0
  7. package/.allhands/agents/executor.yaml +14 -0
  8. package/.allhands/agents/ideation.yaml +11 -0
  9. package/.allhands/agents/initiative-steering.yaml +19 -0
  10. package/.allhands/agents/judge.yaml +13 -0
  11. package/.allhands/agents/planner.yaml +19 -0
  12. package/.allhands/agents/pr-reviewer.yaml +15 -0
  13. package/.allhands/docs.json +5 -0
  14. package/.allhands/docs.local.json +26 -0
  15. package/.allhands/flows/COMPOUNDING.md +203 -0
  16. package/.allhands/flows/COORDINATION.md +89 -0
  17. package/.allhands/flows/CORE.md +87 -0
  18. package/.allhands/flows/DOCUMENTATION.md +218 -0
  19. package/.allhands/flows/E2E_TEST_PLAN_BUILDING.md +140 -0
  20. package/.allhands/flows/EMERGENT_PLANNING.md +57 -0
  21. package/.allhands/flows/IDEATION_SCOPING.md +154 -0
  22. package/.allhands/flows/INITIATIVE_STEERING.md +110 -0
  23. package/.allhands/flows/JUDGE_REVIEWING.md +79 -0
  24. package/.allhands/flows/PROMPT_TASK_EXECUTION.md +68 -0
  25. package/.allhands/flows/PR_REVIEWING.md +43 -0
  26. package/.allhands/flows/SPEC_PLANNING.md +216 -0
  27. package/.allhands/flows/harness/WRITING_HARNESS_FLOWS.md +27 -0
  28. package/.allhands/flows/harness/WRITING_HARNESS_KNOWLEDGE.md +27 -0
  29. package/.allhands/flows/harness/WRITING_HARNESS_ORCHESTRATION.md +27 -0
  30. package/.allhands/flows/harness/WRITING_HARNESS_SKILLS.md +27 -0
  31. package/.allhands/flows/harness/WRITING_HARNESS_TOOLS.md +27 -0
  32. package/.allhands/flows/harness/WRITING_HARNESS_VALIDATION_TOOLING.md +27 -0
  33. package/.allhands/flows/shared/CODEBASE_UNDERSTANDING.md +72 -0
  34. package/.allhands/flows/shared/CREATE_HARNESS_SPEC.md +48 -0
  35. package/.allhands/flows/shared/CREATE_SPEC.md +41 -0
  36. package/.allhands/flows/shared/CREATE_VALIDATION_TOOLING_SPEC.md +70 -0
  37. package/.allhands/flows/shared/DOCUMENTATION_DISCOVERY.md +123 -0
  38. package/.allhands/flows/shared/DOCUMENTATION_WRITER.md +101 -0
  39. package/.allhands/flows/shared/EMERGENT_REFINEMENT_ANALYSIS.md +76 -0
  40. package/.allhands/flows/shared/EXTERNAL_TECH_GUIDANCE.md +97 -0
  41. package/.allhands/flows/shared/IDEATION_CODEBASE_GROUNDING.md +49 -0
  42. package/.allhands/flows/shared/PLAN_DEEPENING.md +152 -0
  43. package/.allhands/flows/shared/PROMPT_TASKS_CURATION.md +113 -0
  44. package/.allhands/flows/shared/PROMPT_VALIDATION_REVIEW.MD +99 -0
  45. package/.allhands/flows/shared/QUICK_PREMORTEM.md +70 -0
  46. package/.allhands/flows/shared/RESEARCH_GUIDANCE.md +38 -0
  47. package/.allhands/flows/shared/REVIEW_OPTIONS_BREAKDOWN.md +68 -0
  48. package/.allhands/flows/shared/SKILL_EXTRACTION.md +84 -0
  49. package/.allhands/flows/shared/SPEC_FLOW_ANALYSIS.md +119 -0
  50. package/.allhands/flows/shared/TDD_WORKFLOW.md +109 -0
  51. package/.allhands/flows/shared/UTILIZE_VALIDATION_TOOLING.md +84 -0
  52. package/.allhands/flows/shared/WRITING_HARNESS_FLOWS.md +11 -0
  53. package/.allhands/flows/shared/WRITING_HARNESS_MCP_TOOLS.md +84 -0
  54. package/.allhands/flows/shared/jury/ARCHITECTURE_REVIEW.md +91 -0
  55. package/.allhands/flows/shared/jury/BEST_PRACTICES_REVIEW.md +80 -0
  56. package/.allhands/flows/shared/jury/CLAIM_VERIFICATION_REVIEW.md +101 -0
  57. package/.allhands/flows/shared/jury/EXPECTATIONS_FIT_REVIEW.md +78 -0
  58. package/.allhands/flows/shared/jury/MAINTAINABILITY_REVIEW.md +110 -0
  59. package/.allhands/flows/shared/jury/PROMPTS_EXPECTATIONS_FIT.md +74 -0
  60. package/.allhands/flows/shared/jury/PROMPTS_FLOW_ANALYSIS.md +92 -0
  61. package/.allhands/flows/shared/jury/PROMPTS_YAGNI.md +78 -0
  62. package/.allhands/flows/shared/jury/PROMPT_PREMORTEM.md +125 -0
  63. package/.allhands/flows/shared/jury/SECURITY_REVIEW.md +86 -0
  64. package/.allhands/flows/shared/jury/YAGNI_REVIEW.md +82 -0
  65. package/.allhands/flows/wip/DEBUG_INVESTIGATION.md +162 -0
  66. package/.allhands/flows/wip/MEMORY_RECALL.md +62 -0
  67. package/.allhands/harness/ah +131 -0
  68. package/.allhands/harness/package-lock.json +5292 -0
  69. package/.allhands/harness/package.json +52 -0
  70. package/.allhands/harness/src/__tests__/e2e/commands.test.ts +307 -0
  71. package/.allhands/harness/src/__tests__/e2e/event-loop.test.ts +539 -0
  72. package/.allhands/harness/src/__tests__/e2e/hooks.test.ts +427 -0
  73. package/.allhands/harness/src/__tests__/e2e/new-initiative-routing.test.ts +137 -0
  74. package/.allhands/harness/src/__tests__/e2e/run-e2e.ts +109 -0
  75. package/.allhands/harness/src/__tests__/e2e/specs-type.test.ts +210 -0
  76. package/.allhands/harness/src/__tests__/e2e/validation-hooks.test.ts +669 -0
  77. package/.allhands/harness/src/__tests__/e2e/validation-path-consistency.test.ts +354 -0
  78. package/.allhands/harness/src/__tests__/e2e/validation.test.ts +528 -0
  79. package/.allhands/harness/src/__tests__/harness/assertions.ts +318 -0
  80. package/.allhands/harness/src/__tests__/harness/cli-runner.ts +359 -0
  81. package/.allhands/harness/src/__tests__/harness/fixture.ts +384 -0
  82. package/.allhands/harness/src/__tests__/harness/hook-runner.ts +411 -0
  83. package/.allhands/harness/src/__tests__/harness/index.ts +122 -0
  84. package/.allhands/harness/src/cli.ts +36 -0
  85. package/.allhands/harness/src/commands/complexity.ts +177 -0
  86. package/.allhands/harness/src/commands/context7.ts +202 -0
  87. package/.allhands/harness/src/commands/docs.ts +557 -0
  88. package/.allhands/harness/src/commands/hooks.ts +24 -0
  89. package/.allhands/harness/src/commands/index.ts +51 -0
  90. package/.allhands/harness/src/commands/knowledge.ts +382 -0
  91. package/.allhands/harness/src/commands/memories.ts +302 -0
  92. package/.allhands/harness/src/commands/notify.ts +61 -0
  93. package/.allhands/harness/src/commands/oracle.ts +158 -0
  94. package/.allhands/harness/src/commands/perplexity.ts +220 -0
  95. package/.allhands/harness/src/commands/planning.ts +245 -0
  96. package/.allhands/harness/src/commands/schema.ts +73 -0
  97. package/.allhands/harness/src/commands/skills.ts +128 -0
  98. package/.allhands/harness/src/commands/solutions.ts +353 -0
  99. package/.allhands/harness/src/commands/spawn.ts +158 -0
  100. package/.allhands/harness/src/commands/specs.ts +532 -0
  101. package/.allhands/harness/src/commands/tavily.ts +226 -0
  102. package/.allhands/harness/src/commands/tools.ts +579 -0
  103. package/.allhands/harness/src/commands/trace.ts +327 -0
  104. package/.allhands/harness/src/commands/tui.ts +960 -0
  105. package/.allhands/harness/src/commands/validate.ts +143 -0
  106. package/.allhands/harness/src/commands/validation-tools.ts +108 -0
  107. package/.allhands/harness/src/hooks/context.ts +1442 -0
  108. package/.allhands/harness/src/hooks/enforcement.ts +170 -0
  109. package/.allhands/harness/src/hooks/index.ts +54 -0
  110. package/.allhands/harness/src/hooks/lifecycle.ts +229 -0
  111. package/.allhands/harness/src/hooks/notification.ts +104 -0
  112. package/.allhands/harness/src/hooks/observability.ts +551 -0
  113. package/.allhands/harness/src/hooks/session.ts +88 -0
  114. package/.allhands/harness/src/hooks/shared.ts +815 -0
  115. package/.allhands/harness/src/hooks/transcript-parser.ts +208 -0
  116. package/.allhands/harness/src/hooks/validation.ts +617 -0
  117. package/.allhands/harness/src/lib/__tests__/ctags.test.ts +244 -0
  118. package/.allhands/harness/src/lib/__tests__/docs-validation.test.ts +344 -0
  119. package/.allhands/harness/src/lib/__tests__/mcp-runtime.test.ts +190 -0
  120. package/.allhands/harness/src/lib/__tests__/schema.test.ts +861 -0
  121. package/.allhands/harness/src/lib/base-command.ts +198 -0
  122. package/.allhands/harness/src/lib/cli-daemon.ts +343 -0
  123. package/.allhands/harness/src/lib/compaction.ts +313 -0
  124. package/.allhands/harness/src/lib/ctags.ts +497 -0
  125. package/.allhands/harness/src/lib/docs-validation.ts +907 -0
  126. package/.allhands/harness/src/lib/event-loop.ts +662 -0
  127. package/.allhands/harness/src/lib/flows.ts +155 -0
  128. package/.allhands/harness/src/lib/git.ts +276 -0
  129. package/.allhands/harness/src/lib/knowledge-worker.ts +72 -0
  130. package/.allhands/harness/src/lib/knowledge.ts +810 -0
  131. package/.allhands/harness/src/lib/llm.ts +255 -0
  132. package/.allhands/harness/src/lib/mcp-client.ts +432 -0
  133. package/.allhands/harness/src/lib/mcp-daemon.ts +486 -0
  134. package/.allhands/harness/src/lib/mcp-runtime.ts +418 -0
  135. package/.allhands/harness/src/lib/notification.ts +115 -0
  136. package/.allhands/harness/src/lib/opencode/index.ts +70 -0
  137. package/.allhands/harness/src/lib/opencode/profiles.ts +300 -0
  138. package/.allhands/harness/src/lib/opencode/prompts/codesearch.md +98 -0
  139. package/.allhands/harness/src/lib/opencode/prompts/knowledge-aggregator.md +67 -0
  140. package/.allhands/harness/src/lib/opencode/runner.ts +281 -0
  141. package/.allhands/harness/src/lib/oracle.ts +926 -0
  142. package/.allhands/harness/src/lib/planning-utils.ts +150 -0
  143. package/.allhands/harness/src/lib/planning.ts +605 -0
  144. package/.allhands/harness/src/lib/pr-review.ts +225 -0
  145. package/.allhands/harness/src/lib/prompts.ts +522 -0
  146. package/.allhands/harness/src/lib/schema.ts +418 -0
  147. package/.allhands/harness/src/lib/schemas/agent-profile.ts +141 -0
  148. package/.allhands/harness/src/lib/schemas/template-vars.ts +138 -0
  149. package/.allhands/harness/src/lib/session.ts +164 -0
  150. package/.allhands/harness/src/lib/specs.ts +348 -0
  151. package/.allhands/harness/src/lib/tldr.ts +829 -0
  152. package/.allhands/harness/src/lib/tmux.ts +1051 -0
  153. package/.allhands/harness/src/lib/trace-store.ts +714 -0
  154. package/.allhands/harness/src/mcp/__tests__/index.test.ts +46 -0
  155. package/.allhands/harness/src/mcp/_template.ts +47 -0
  156. package/.allhands/harness/src/mcp/filesystem.ts +33 -0
  157. package/.allhands/harness/src/mcp/index.ts +69 -0
  158. package/.allhands/harness/src/mcp/playwright.ts +34 -0
  159. package/.allhands/harness/src/mcp/xcodebuild.ts +29 -0
  160. package/.allhands/harness/src/schemas/docs.schema.json +44 -0
  161. package/.allhands/harness/src/schemas/settings.schema.json +214 -0
  162. package/.allhands/harness/src/tui/actions.ts +227 -0
  163. package/.allhands/harness/src/tui/file-viewer-modal.ts +270 -0
  164. package/.allhands/harness/src/tui/index.ts +1574 -0
  165. package/.allhands/harness/src/tui/modal.ts +232 -0
  166. package/.allhands/harness/src/tui/prompts-pane.ts +186 -0
  167. package/.allhands/harness/src/tui/status-pane.ts +434 -0
  168. package/.allhands/harness/tsconfig.json +22 -0
  169. package/.allhands/harness/vitest.config.ts +13 -0
  170. package/.allhands/pillars.md +33 -0
  171. package/.allhands/principles.md +88 -0
  172. package/.allhands/schemas/alignment.yaml +51 -0
  173. package/.allhands/schemas/documentation.yaml +10 -0
  174. package/.allhands/schemas/prompt.yaml +92 -0
  175. package/.allhands/schemas/skill.yaml +34 -0
  176. package/.allhands/schemas/solution.yaml +131 -0
  177. package/.allhands/schemas/spec.yaml +67 -0
  178. package/.allhands/schemas/validation-suite.yaml +49 -0
  179. package/.allhands/schemas/workflow.yaml +51 -0
  180. package/.allhands/settings.json +57 -0
  181. package/.allhands/skills/claude-code-patterns/SKILL.md +60 -0
  182. package/.allhands/skills/claude-code-patterns/docs/context-hygiene.md +19 -0
  183. package/.allhands/skills/harness-maintenance/SKILL.md +449 -0
  184. package/.allhands/skills/harness-maintenance/references/core-architecture.md +187 -0
  185. package/.allhands/skills/harness-maintenance/references/harness-skills.md +87 -0
  186. package/.allhands/skills/harness-maintenance/references/knowledge-compounding.md +78 -0
  187. package/.allhands/skills/harness-maintenance/references/tools-commands-mcp-hooks.md +115 -0
  188. package/.allhands/skills/harness-maintenance/references/validation-tooling.md +77 -0
  189. package/.allhands/skills/harness-maintenance/references/writing-flows.md +84 -0
  190. package/.allhands/validation/browser-automation.md +109 -0
  191. package/.allhands/validation/xcode-automation.md +195 -0
  192. package/.allhands/workflows/documentation.md +86 -0
  193. package/.allhands/workflows/investigation.md +81 -0
  194. package/.allhands/workflows/milestone.md +91 -0
  195. package/.allhands/workflows/optimization.md +85 -0
  196. package/.allhands/workflows/refactor.md +99 -0
  197. package/.allhands/workflows/triage.md +81 -0
  198. package/.claude/README.md +1 -0
  199. package/.claude/agents/explorer.md +10 -0
  200. package/.claude/agents/researcher.md +11 -0
  201. package/.claude/agents/task-runner.md +8 -0
  202. package/.claude/settings.json +231 -0
  203. package/.env.ai.example +7 -0
  204. package/.github/workflows/npm-publish.yml +69 -0
  205. package/.internal.json +45 -0
  206. package/.tldr/config.json +11 -0
  207. package/.tldrignore +90 -0
  208. package/CLAUDE.md +6 -0
  209. package/README.md +98 -0
  210. package/bin/sync-cli.js +7552 -0
  211. package/concerns.md +7 -0
  212. package/docs/README.md +41 -0
  213. package/docs/agents/README.md +24 -0
  214. package/docs/agents/agent-configuration-system.md +86 -0
  215. package/docs/agents/execution-agents.md +50 -0
  216. package/docs/agents/knowledge-agents.md +61 -0
  217. package/docs/agents/orchestration-agent.md +57 -0
  218. package/docs/agents/planning-agents.md +84 -0
  219. package/docs/agents/quality-review-agents.md +67 -0
  220. package/docs/agents/workflow-agent-orchestration.md +69 -0
  221. package/docs/flows/README.md +44 -0
  222. package/docs/flows/compounding.md +126 -0
  223. package/docs/flows/coordination.md +72 -0
  224. package/docs/flows/core-harness-integration.md +63 -0
  225. package/docs/flows/documentation-orchestration.md +98 -0
  226. package/docs/flows/e2e-test-plan-building.md +83 -0
  227. package/docs/flows/emergent-refinement.md +104 -0
  228. package/docs/flows/flow-authoring-and-mcp-tools.md +89 -0
  229. package/docs/flows/judge-reviewing.md +112 -0
  230. package/docs/flows/plan-deepening-and-research.md +107 -0
  231. package/docs/flows/plan-review-jury.md +114 -0
  232. package/docs/flows/pr-reviewing.md +54 -0
  233. package/docs/flows/prompt-task-execution.md +119 -0
  234. package/docs/flows/spec-planning.md +162 -0
  235. package/docs/flows/type-specific-scoping-flows.md +49 -0
  236. package/docs/flows/validation-and-skills-integration.md +145 -0
  237. package/docs/flows/wip/wip-flows.md +102 -0
  238. package/docs/harness/README.md +23 -0
  239. package/docs/harness/agent-profiles.md +84 -0
  240. package/docs/harness/cli/README.md +24 -0
  241. package/docs/harness/cli/cli-entry-and-command-discovery.md +91 -0
  242. package/docs/harness/cli/docs-command.md +87 -0
  243. package/docs/harness/cli/knowledge-command.md +91 -0
  244. package/docs/harness/cli/minor-cli-commands.md +65 -0
  245. package/docs/harness/cli/oracle-command.md +113 -0
  246. package/docs/harness/cli/planning-command.md +95 -0
  247. package/docs/harness/cli/schema-and-validation-commands.md +154 -0
  248. package/docs/harness/cli/search-commands.md +97 -0
  249. package/docs/harness/cli/spawn-command.md +136 -0
  250. package/docs/harness/cli/specs-command.md +102 -0
  251. package/docs/harness/cli/tools-command.md +122 -0
  252. package/docs/harness/cli/trace-command.md +122 -0
  253. package/docs/harness/cli-daemon.md +92 -0
  254. package/docs/harness/event-loop.md +184 -0
  255. package/docs/harness/hooks/README.md +15 -0
  256. package/docs/harness/hooks/context-hooks.md +96 -0
  257. package/docs/harness/hooks/lifecycle-and-observability-hooks.md +135 -0
  258. package/docs/harness/hooks/validation-hooks.md +97 -0
  259. package/docs/harness/test-harness.md +149 -0
  260. package/docs/harness/tui.md +176 -0
  261. package/docs/memories.md +20 -0
  262. package/docs/solutions/agentic-issues/premature-agent-deletion-tui-action-dependency-20260130.md +49 -0
  263. package/docs/solutions/agentic-issues/ref-anchor-scope-mismatch-skill-references-20260131.md +55 -0
  264. package/docs/solutions/agentic-issues/tautological-tests-routing-20260131.md +52 -0
  265. package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md +52 -0
  266. package/docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md +66 -0
  267. package/docs/solutions/security-issues/unsanitized-domain-path-join-20260131.md +52 -0
  268. package/docs/solutions/test-failures/event-loop-mock-ordering-checkAgentWindows-20260130.md +63 -0
  269. package/docs/sync-cli/README.md +19 -0
  270. package/docs/sync-cli/cli-entrypoint-and-commands.md +39 -0
  271. package/docs/sync-cli/commands/README.md +11 -0
  272. package/docs/sync-cli/commands/pull-manifest-command.md +36 -0
  273. package/docs/sync-cli/commands/push-command.md +84 -0
  274. package/docs/sync-cli/commands/sync-command.md +71 -0
  275. package/docs/sync-cli/systems/README.md +14 -0
  276. package/docs/sync-cli/systems/git-and-github-integration.md +49 -0
  277. package/docs/sync-cli/systems/interactive-ui.md +43 -0
  278. package/docs/sync-cli/systems/manifest-and-distribution.md +51 -0
  279. package/docs/sync-cli/systems/path-resolution.md +42 -0
  280. package/package.json +46 -0
  281. package/scripts/install-shim.sh +40 -0
  282. package/scripts/pre-pack.sh +25 -0
  283. package/specs/harness-maintenance-skill.spec.md +138 -0
  284. package/specs/roadmap/git-spec-lifecycle-management.spec.md +113 -0
  285. package/specs/sync-init-flag.spec.md +117 -0
  286. package/specs/unified-workflow-orchestration.spec.md +250 -0
  287. package/specs/validation-tooling-practice.spec.md +98 -0
  288. package/specs/workflow-domain-configuration.spec.md +265 -0
  289. package/src/commands/pull-manifest.ts +31 -0
  290. package/src/commands/push.ts +344 -0
  291. package/src/commands/sync.ts +289 -0
  292. package/src/lib/constants.ts +10 -0
  293. package/src/lib/dotfiles.ts +36 -0
  294. package/src/lib/fs-utils.ts +18 -0
  295. package/src/lib/gh.ts +40 -0
  296. package/src/lib/git.ts +63 -0
  297. package/src/lib/gitignore.ts +167 -0
  298. package/src/lib/manifest.ts +121 -0
  299. package/src/lib/marker-sync.ts +39 -0
  300. package/src/lib/paths.ts +38 -0
  301. package/src/lib/target-lines.ts +66 -0
  302. package/src/lib/ui.ts +78 -0
  303. package/src/sync-cli.ts +120 -0
  304. package/target-lines.json +23 -0
  305. package/tsconfig.json +20 -0
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Ephemeral Test Fixture Creation
3
+ *
4
+ * Creates temporary project directories with the proper structure
5
+ * for testing harness functionality in isolation.
6
+ */
7
+
8
+ import { mkdirSync, writeFileSync, rmSync, cpSync, existsSync, readFileSync } from 'fs';
9
+ import { join, dirname } from 'path';
10
+ import { tmpdir } from 'os';
11
+ import { randomBytes } from 'crypto';
12
+ import { execSync } from 'child_process';
13
+
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+ // Types
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+
18
+ export interface FixtureOptions {
19
+ /** Unique name for the fixture (auto-generated if not provided) */
20
+ name?: string;
21
+ /** Whether to copy the real harness from .allhands/ */
22
+ copyHarness?: boolean;
23
+ /** Whether to initialize as a git repo */
24
+ initGit?: boolean;
25
+ /** Initial files to create (path -> content) */
26
+ files?: Record<string, string>;
27
+ /** Environment variables to set when running commands */
28
+ env?: Record<string, string>;
29
+ }
30
+
31
+ export interface TestFixture {
32
+ /** Root directory of the fixture */
33
+ root: string;
34
+ /** Path to .allhands directory */
35
+ allhands: string;
36
+ /** Path to .planning directory */
37
+ planning: string;
38
+ /** Path to specs directory */
39
+ specs: string;
40
+ /** Path to src directory */
41
+ src: string;
42
+ /** Environment variables for this fixture */
43
+ env: Record<string, string>;
44
+ /** Write a file relative to fixture root */
45
+ writeFile: (relativePath: string, content: string) => void;
46
+ /** Read a file relative to fixture root */
47
+ readFile: (relativePath: string) => string;
48
+ /** Check if file exists relative to fixture root */
49
+ exists: (relativePath: string) => boolean;
50
+ /** Clean up the fixture */
51
+ cleanup: () => void;
52
+ }
53
+
54
+ // ─────────────────────────────────────────────────────────────────────────────
55
+ // Fixture Templates
56
+ // ─────────────────────────────────────────────────────────────────────────────
57
+
58
+ /** Prompt file template matching .allhands/schemas/prompt.yaml */
59
+ export const PROMPT_TEMPLATE = (
60
+ status: 'pending' | 'in_progress' | 'done' = 'pending',
61
+ title: string = 'Test Task',
62
+ number: number = 1
63
+ ) => `---
64
+ number: ${number}
65
+ title: "${title.replace(/"/g, '\\"')}"
66
+ type: planned
67
+ planning_session: 1
68
+ status: ${status}
69
+ dependencies: []
70
+ attempts: 0
71
+ commits: []
72
+ validation_suites: []
73
+ skills: []
74
+ ---
75
+
76
+ # Tasks
77
+
78
+ - Implement the feature
79
+ - Add tests
80
+
81
+ # Acceptance Criteria
82
+
83
+ - Feature works as expected
84
+ - Tests pass
85
+ `;
86
+
87
+ /** Alignment doc template matching .allhands/schemas/alignment.yaml */
88
+ export const ALIGNMENT_TEMPLATE = (
89
+ specName: string = 'test-spec',
90
+ specPath: string = 'specs/test.spec.md'
91
+ ) => `---
92
+ spec_name: ${specName}
93
+ spec_path: ${specPath}
94
+ planning_session: 1
95
+ ---
96
+
97
+ # Overview
98
+
99
+ Test alignment document.
100
+
101
+ # Hard User Requirements
102
+
103
+ - Must follow existing patterns
104
+ `;
105
+
106
+ /** Spec file template matching .allhands/schemas/spec.yaml */
107
+ export const SPEC_TEMPLATE = (
108
+ name: string = 'test-spec',
109
+ domainName: string = 'test-domain'
110
+ ) => `---
111
+ name: ${name}
112
+ domain_name: ${domainName}
113
+ status: roadmap
114
+ dependencies: []
115
+ ---
116
+
117
+ # Motivation
118
+
119
+ Test specification motivation.
120
+
121
+ # Goals
122
+
123
+ - Goal 1
124
+ - Goal 2
125
+ `;
126
+
127
+ /** Sample Python file for edit/validation tests */
128
+ export const PYTHON_SAMPLE = `"""Sample Python module for testing."""
129
+
130
+ def hello(name: str) -> str:
131
+ """Return a greeting."""
132
+ return f"Hello, {name}!"
133
+
134
+ class Calculator:
135
+ """Simple calculator class."""
136
+
137
+ def add(self, a: int, b: int) -> int:
138
+ """Add two numbers."""
139
+ return a + b
140
+
141
+ def subtract(self, a: int, b: int) -> int:
142
+ """Subtract b from a."""
143
+ return a - b
144
+ `;
145
+
146
+ /** Sample TypeScript file */
147
+ export const TYPESCRIPT_SAMPLE = `/**
148
+ * Sample TypeScript module for testing.
149
+ */
150
+
151
+ export interface User {
152
+ id: string;
153
+ name: string;
154
+ email: string;
155
+ }
156
+
157
+ export function greet(user: User): string {
158
+ return \`Hello, \${user.name}!\`;
159
+ }
160
+
161
+ export class UserService {
162
+ private users: Map<string, User> = new Map();
163
+
164
+ add(user: User): void {
165
+ this.users.set(user.id, user);
166
+ }
167
+
168
+ get(id: string): User | undefined {
169
+ return this.users.get(id);
170
+ }
171
+ }
172
+ `;
173
+
174
+ // ─────────────────────────────────────────────────────────────────────────────
175
+ // Fixture Creation
176
+ // ─────────────────────────────────────────────────────────────────────────────
177
+
178
+ /**
179
+ * Get the real harness directory (for copying to fixtures).
180
+ */
181
+ function getRealHarnessDir(): string {
182
+ // Navigate from this file to the harness root
183
+ return join(dirname(dirname(dirname(__dirname))));
184
+ }
185
+
186
+ /**
187
+ * Get the real .allhands directory.
188
+ */
189
+ function getRealAllhandsDir(): string {
190
+ return join(getRealHarnessDir(), '..');
191
+ }
192
+
193
+ /**
194
+ * Create an ephemeral test fixture.
195
+ */
196
+ export function createFixture(options: FixtureOptions = {}): TestFixture {
197
+ const {
198
+ name = `ah-test-${randomBytes(4).toString('hex')}`,
199
+ copyHarness = false,
200
+ initGit = true,
201
+ files = {},
202
+ env = {},
203
+ } = options;
204
+
205
+ // Create temp directory
206
+ const root = join(tmpdir(), name);
207
+
208
+ // Clean up if exists from previous failed run
209
+ if (existsSync(root)) {
210
+ rmSync(root, { recursive: true, force: true });
211
+ }
212
+
213
+ mkdirSync(root, { recursive: true });
214
+
215
+ // Create standard directories
216
+ const allhands = join(root, '.allhands');
217
+ const planning = join(root, '.planning');
218
+ const specs = join(root, 'specs');
219
+ const src = join(root, 'src');
220
+
221
+ mkdirSync(allhands, { recursive: true });
222
+ mkdirSync(planning, { recursive: true });
223
+ mkdirSync(specs, { recursive: true });
224
+ mkdirSync(src, { recursive: true });
225
+
226
+ // Copy real harness if requested
227
+ if (copyHarness) {
228
+ const realAllhands = getRealAllhandsDir();
229
+ cpSync(realAllhands, allhands, { recursive: true });
230
+ } else {
231
+ // Create minimal harness structure
232
+ mkdirSync(join(allhands, 'harness'), { recursive: true });
233
+ mkdirSync(join(allhands, 'flows'), { recursive: true });
234
+ mkdirSync(join(allhands, 'schemas'), { recursive: true });
235
+ mkdirSync(join(allhands, 'validation'), { recursive: true });
236
+
237
+ // Create minimal schema files
238
+ writeFileSync(
239
+ join(allhands, 'schemas', 'prompt.yaml'),
240
+ `# Prompt schema\nrequired:\n - status\nproperties:\n status:\n type: string\n enum: [pending, in_progress, completed, blocked]\n`
241
+ );
242
+
243
+ writeFileSync(
244
+ join(allhands, 'schemas', 'alignment.yaml'),
245
+ `# Alignment schema\nrequired:\n - spec_name\nproperties:\n spec_name:\n type: string\n`
246
+ );
247
+
248
+ writeFileSync(
249
+ join(allhands, 'schemas', 'spec.yaml'),
250
+ `# Spec schema\nrequired:\n - name\n - version\nproperties:\n name:\n type: string\n version:\n type: integer\n`
251
+ );
252
+ }
253
+
254
+ // Initialize git repo if requested
255
+ if (initGit) {
256
+ execSync('git init', { cwd: root, stdio: 'pipe' });
257
+ execSync('git config user.email "test@example.com"', { cwd: root, stdio: 'pipe' });
258
+ execSync('git config user.name "Test User"', { cwd: root, stdio: 'pipe' });
259
+ }
260
+
261
+ // Write initial files
262
+ for (const [relativePath, content] of Object.entries(files)) {
263
+ const fullPath = join(root, relativePath);
264
+ mkdirSync(dirname(fullPath), { recursive: true });
265
+ writeFileSync(fullPath, content);
266
+ }
267
+
268
+ // Build fixture object
269
+ const fixture: TestFixture = {
270
+ root,
271
+ allhands,
272
+ planning,
273
+ specs,
274
+ src,
275
+ env: {
276
+ CLAUDE_PROJECT_DIR: root,
277
+ ...env,
278
+ },
279
+ writeFile: (relativePath: string, content: string) => {
280
+ const fullPath = join(root, relativePath);
281
+ mkdirSync(dirname(fullPath), { recursive: true });
282
+ writeFileSync(fullPath, content);
283
+ },
284
+ readFile: (relativePath: string) => {
285
+ return readFileSync(join(root, relativePath), 'utf-8');
286
+ },
287
+ exists: (relativePath: string) => {
288
+ return existsSync(join(root, relativePath));
289
+ },
290
+ cleanup: () => {
291
+ rmSync(root, { recursive: true, force: true });
292
+ },
293
+ };
294
+
295
+ return fixture;
296
+ }
297
+
298
+ /**
299
+ * Create a fixture with a complete spec structure.
300
+ */
301
+ export function createSpecFixture(
302
+ specName: string = 'test-spec',
303
+ promptCount: number = 3
304
+ ): TestFixture {
305
+ const files: Record<string, string> = {
306
+ // Spec file
307
+ [`specs/${specName}.spec.md`]: SPEC_TEMPLATE(specName, 'test-domain'),
308
+ // Alignment doc
309
+ [`.planning/${specName}/alignment.md`]: ALIGNMENT_TEMPLATE(
310
+ specName,
311
+ `specs/${specName}.spec.md`
312
+ ),
313
+ // Sample source files
314
+ ['src/sample.py']: PYTHON_SAMPLE,
315
+ ['src/sample.ts']: TYPESCRIPT_SAMPLE,
316
+ };
317
+
318
+ // Add prompts
319
+ for (let i = 1; i <= promptCount; i++) {
320
+ const num = i.toString().padStart(2, '0');
321
+ files[`.planning/${specName}/prompts/${num}.md`] = PROMPT_TEMPLATE(
322
+ i === 1 ? 'in_progress' : 'pending',
323
+ `Task ${i}: Implement feature ${i}`,
324
+ i
325
+ );
326
+ }
327
+
328
+ return createFixture({
329
+ name: `ah-spec-${specName}`,
330
+ files,
331
+ env: {
332
+ SPEC_NAME: specName,
333
+ },
334
+ });
335
+ }
336
+
337
+ /**
338
+ * Alias for createSpecFixture (used in E2E tests).
339
+ */
340
+ export const createMilestoneFixture = createSpecFixture;
341
+
342
+ /**
343
+ * Create a fixture with multiple spec files (no prompts).
344
+ */
345
+ export function createMultiSpecFixture(specs: string[] = ['api', 'data-model']): TestFixture {
346
+ const files: Record<string, string> = {};
347
+
348
+ for (const spec of specs) {
349
+ files[`specs/${spec}.spec.md`] = SPEC_TEMPLATE(spec, 'test-domain');
350
+ }
351
+
352
+ return createFixture({
353
+ name: 'ah-specs-test',
354
+ files,
355
+ });
356
+ }
357
+
358
+ // ─────────────────────────────────────────────────────────────────────────────
359
+ // Fixture Pool (for reuse across tests)
360
+ // ─────────────────────────────────────────────────────────────────────────────
361
+
362
+ const fixturePool: Map<string, TestFixture> = new Map();
363
+
364
+ /**
365
+ * Get or create a named fixture from the pool.
366
+ * Useful for sharing fixtures across tests in the same file.
367
+ */
368
+ export function getPooledFixture(name: string, factory: () => TestFixture): TestFixture {
369
+ if (!fixturePool.has(name)) {
370
+ fixturePool.set(name, factory());
371
+ }
372
+ return fixturePool.get(name)!;
373
+ }
374
+
375
+ /**
376
+ * Clean up all pooled fixtures.
377
+ * Call this in afterAll() hooks.
378
+ */
379
+ export function cleanupPool(): void {
380
+ for (const fixture of fixturePool.values()) {
381
+ fixture.cleanup();
382
+ }
383
+ fixturePool.clear();
384
+ }