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,52 @@
1
+ ---
2
+ description: "Documents how blockTool() outputs { decision: 'block' } but hook-runner assertHookBlocked expects { continue: false }, requiring raw JSON assertions for PostToolUse tests."
3
+ title: "blockTool() output format mismatch with hook-runner assertHookBlocked helper"
4
+ date: "2026-01-30"
5
+ milestone: "feature/validation-tooling-practice"
6
+ problem_type: integration_issue
7
+ component: "hook-runner"
8
+ symptoms:
9
+ - "assertHookBlocked assertion fails on PostToolUse hooks that correctly block"
10
+ - "Hook blocks tool but test assertion reports allowed"
11
+ - "PostToolUse test needs raw JSON inspection instead of helper assertions"
12
+ root_cause: wrong_api_usage
13
+ severity: medium
14
+ tags:
15
+ - "blocktool"
16
+ - "hook-runner"
17
+ - "post-tool-use"
18
+ - "assertion"
19
+ - "test-harness"
20
+ - "format-mismatch"
21
+ - "integration-testing"
22
+ source: agent-inferred
23
+ ---
24
+
25
+ # blockTool Output Format Mismatch — Hook Runner
26
+
27
+ ## Problem
28
+
29
+ The `blockTool()` helper in [ref:hooks/shared.ts] outputs `{ decision: 'block', reason: '...' }` for PostToolUse hooks. However, the hook-runner test harness's `assertHookBlocked` helper expects `{ continue: false }`. This means PostToolUse block assertions fail even when the hook correctly blocks the tool.
30
+
31
+ Discovered in Prompt 07 (attempt 2) when writing integration tests for the `schema` PostToolUse validation hook.
32
+
33
+ ## Investigation
34
+
35
+ Used `assertHookBlocked(result)` — the standard helper for verifying hook blocking behavior. This checks for `{ continue: false }` in the parsed output, which `blockTool()` does not produce. Required 3 attempts on Prompt 07 to work around this.
36
+
37
+ ## Solution
38
+
39
+ Assert directly against the raw JSON output:
40
+ ```typescript
41
+ expect(result.json.decision).toBe('block');
42
+ ```
43
+
44
+ This bypasses the `assertHookBlocked` helper and checks the actual output format that `blockTool()` produces.
45
+
46
+ ## Prevention
47
+
48
+ The hook-runner assertion helpers should be updated to handle both PostToolUse output formats (`{ decision: 'block' }` and `{ continue: false }`), or `blockTool()` should be updated to output the format the helpers expect. This is a known harness inconsistency tracked in memories.
49
+
50
+ ## Related
51
+
52
+ - See `docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md` for the broader consolidation context that led to this discovery.
@@ -0,0 +1,66 @@
1
+ ---
2
+ description: "Documents how hooks/validation.ts and lib/schema.ts had 4 behavioral divergences in schema validation, and how consolidation by delegating hooks to lib resolved all divergences."
3
+ title: "Dual validation path divergence between hooks/validation.ts and lib/schema.ts"
4
+ date: "2026-01-30"
5
+ milestone: "feature/validation-tooling-practice"
6
+ problem_type: integration_issue
7
+ component: "schema-validation"
8
+ symptoms:
9
+ - "Frontmatter accepted by hooks but rejected by lib (or vice versa)"
10
+ - "Boolean/date/object fields silently pass hooks validation without type checking"
11
+ - "extractFrontmatter returns null for content without trailing newline after closing ---"
12
+ - "Different error shapes between validation paths (ValidationResult vs ValidationError[])"
13
+ root_cause: incomplete_implementation
14
+ severity: high
15
+ tags:
16
+ - "schema"
17
+ - "validation"
18
+ - "divergence"
19
+ - "consolidation"
20
+ - "hooks"
21
+ - "dual-path"
22
+ - "frontmatter"
23
+ - "type-checking"
24
+ - "deduplication"
25
+ source: agent-inferred
26
+ ---
27
+
28
+ # Dual Validation Path Divergence — Schema Enforcement
29
+
30
+ ## Problem
31
+
32
+ Two independent implementations of schema validation existed in the harness:
33
+ - [ref:lib/schema.ts] — the canonical validation library with 7 type branches, caching, and `ValidationResult` return type
34
+ - [ref:hooks/validation.ts] — the hook enforcement layer with its own `parseFrontmatter`, `loadSchema`, and `validateFrontmatter` implementations
35
+
36
+ These paths diverged in 4 specific ways, discovered via stability tests in Prompt 10:
37
+
38
+ 1. **Frontmatter regex**: lib requires trailing newline after closing `---`; hooks does not
39
+ 2. **Type branch coverage**: hooks handles string/integer/enum/array but NOT boolean/date/object — these silently pass
40
+ 3. **Return type shape**: lib returns `{ valid, errors }`, hooks returns `ValidationError[]`
41
+ 4. **schema.fields fallback**: lib uses `schema.frontmatter || schema.fields || {}`; hooks returns empty array if `!schema.frontmatter`
42
+
43
+ ## Investigation
44
+
45
+ - Prompt 04: Added array item-type validation to BOTH paths (first indication of duplication)
46
+ - Prompt 06: Unit tests for [ref:lib/schema.ts] revealed comprehensive type branch coverage
47
+ - Prompt 07: Integration tests for hooks revealed the `blockTool` format mismatch (separate issue) and hook behavior
48
+ - Prompt 10: Deliberately documented all 4 divergences with paired tests showing each path's behavior on identical input
49
+
50
+ ## Solution
51
+
52
+ Jury Review item #8: Refactored [ref:hooks/validation.ts] to import and delegate to [ref:lib/schema.ts] for `loadSchema`, `extractFrontmatter`, and `validateFrontmatter`. Removed local `SchemaDefinition`, `ValidationError` types, and all local validation functions. This eliminated all 4 divergences in one consolidation.
53
+
54
+ Jury Review item #9 extended this to [ref:commands/validation-tools.ts], replacing its local `extractFrontmatter` with the lib import.
55
+
56
+ Prompt 11 (PR review fix) completed consolidation by replacing the manual `Array.isArray` guard in `listValidationSuites()` with `validateFrontmatter()` delegation.
57
+
58
+ ## Prevention
59
+
60
+ - Schema validation should have a single source of truth ([ref:lib/schema.ts]). Other modules import, never reimplement.
61
+ - When adding new validation logic (like array item-type checking), the need to update multiple files is a code smell indicating duplication.
62
+ - Stability tests that document divergences between parallel implementations create a consolidation roadmap.
63
+
64
+ ## Related
65
+
66
+ - See `docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md` for the separate hook-runner assertion issue discovered during the same investigation chain.
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: "Unsanitized domain value used in path.join enables path traversal"
3
+ date: "2026-01-31"
4
+ milestone: feature/workflow-domain-configuration
5
+ problem_type: security_issue
6
+ component: harness-tui
7
+ symptoms:
8
+ - "User-selected domain value passed directly to path.join()"
9
+ - "No validation that domain value is a known domain"
10
+ - "Path construction could resolve to arbitrary filesystem locations"
11
+ root_cause: missing_validation
12
+ severity: high
13
+ tags:
14
+ - path-traversal
15
+ - path-join
16
+ - input-validation
17
+ - domain-allowlist
18
+ - template-variables
19
+ - tui-actions
20
+ - workflow-domain
21
+ source: review-fix
22
+ ---
23
+
24
+ ## Problem
25
+
26
+ Three path construction sites in the harness accepted domain values (from spec frontmatter and TUI modal selection) and used them directly in `path.join()` to resolve workflow domain config file paths:
27
+
28
+ - `buildTemplateContext()` in `tmux.ts`: `path.join(workflowsDir, domain + '.md')`
29
+ - `openNewInitiativeModal()` in `tui/index.ts`: similar path construction
30
+ - `openSteeringDomainModal()` in `tui/index.ts`: context override path
31
+
32
+ A crafted `initial_workflow_domain` value like `../../etc/passwd` in spec frontmatter could resolve to arbitrary filesystem paths. The initiative-steering context override path additionally lacked an `existsSync` guard, meaning it would pass a nonexistent path as a template variable.
33
+
34
+ ## Investigation
35
+
36
+ Jury review's Security reviewer and 1 additional reviewer flagged this as P1 — the path traversal vector existed at all 3 sites and the `existsSync` guard was missing only on the steering override.
37
+
38
+ ## Solution
39
+
40
+ Prompt 11 implemented:
41
+
42
+ 1. **Domain allowlist** (`VALID_WORKFLOW_DOMAINS`): Constant array of valid domain values derived from the `SpecType` union type in `specs.ts`
43
+ 2. **Shared utility** (`getWorkflowDomain()`): Centralized function that reads `initial_workflow_domain` from spec frontmatter via `parseFrontmatter()`, validates against the allowlist, and returns `milestone` as fallback for unknown values
44
+ 3. **`existsSync` guard** on initiative-steering context override path: Only applies the override if the resolved path exists on disk
45
+ 4. All 3 path construction sites now use the validated domain from `getWorkflowDomain()` or the TUI modal's constrained selection
46
+
47
+ ## Prevention
48
+
49
+ - When constructing filesystem paths from user-controlled or file-controlled values, validate against an allowlist before `path.join()`
50
+ - Use centralized utility functions for domain-to-path resolution to ensure validation cannot be bypassed
51
+ - Add `existsSync` guards when resolved paths are passed to downstream consumers that assume validity
52
+ - The `VALID_WORKFLOW_DOMAINS` constant is derived from the TypeScript union type, ensuring schema and runtime validation stay in sync
@@ -0,0 +1,63 @@
1
+ ---
2
+ description: "Solution for event loop test failures caused by checkAgentWindows running before checkPromptLoop in each tick, requiring listWindows mock to return executor windows to prevent state reconciliation."
3
+ title: "Event loop tests fail due to checkAgentWindows reconciliation clearing spawn timestamps"
4
+ date: "2026-01-30"
5
+ milestone: "feature/unified-workflow-orchestration"
6
+ problem_type: test_failure
7
+ component: "event-loop"
8
+ symptoms:
9
+ - "Cooldown timer tests fail unexpectedly"
10
+ - "Spawn callback fires when cooldown should prevent it"
11
+ - "lastExecutorSpawnTime reset between tick phases"
12
+ - "Event loop tests pass individually but fail in sequence"
13
+ root_cause: timing_issue
14
+ severity: medium
15
+ tags:
16
+ - event-loop-testing
17
+ - vitest-mocking
18
+ - checkAgentWindows
19
+ - checkPromptLoop
20
+ - spawn-cooldown
21
+ - tick-ordering
22
+ - listWindows-mock
23
+ ---
24
+
25
+ ## Problem
26
+
27
+ When writing unit tests for [ref:.allhands/harness/src/lib/event-loop.ts:checkPromptLoop], cooldown timer tests failed because `lastExecutorSpawnTime` was being cleared between test assertions. The root cause: each `forceTick()` call runs `checkAgentWindows()` before `checkPromptLoop()`. If `listWindows` mock returns no windows, `checkAgentWindows` reconciles by clearing `activeExecutorPrompts` and resetting spawn-related timestamps, invalidating cooldown state before `checkPromptLoop` can check it.
28
+
29
+ ## Root Cause
30
+
31
+ The event loop tick has two phases executed sequentially:
32
+ 1. `checkAgentWindows()` — reconciles tracked state against actual tmux windows
33
+ 2. `checkPromptLoop()` — makes spawn decisions based on state
34
+
35
+ When `listWindows` returns an empty array (the default mock), phase 1 treats all tracked executors as departed and resets state. Phase 2 then sees clean state and makes incorrect spawn decisions.
36
+
37
+ ## Solution
38
+
39
+ Configure `listWindows` mock to return executor window entries matching the expected active executors:
40
+
41
+ ```typescript
42
+ vi.mocked(listWindows).mockResolvedValue([
43
+ { name: 'executor-01', active: true }
44
+ ]);
45
+ ```
46
+
47
+ This prevents reconciliation from clearing state, allowing `checkPromptLoop` to see the correct timestamps and cooldown values.
48
+
49
+ ## Prevention
50
+
51
+ When testing any event loop decision logic:
52
+ 1. Always configure `listWindows` to return windows matching the expected active state
53
+ 2. Remember tick ordering: agent window reconciliation runs first
54
+ 3. For cooldown tests specifically, ensure executor windows persist across ticks
55
+
56
+ ## Failed Approaches
57
+
58
+ - Mocking only `loadAllPrompts` without `listWindows` — reconciliation clears state
59
+ - Running cooldown tests without any active windows — timestamps reset each tick
60
+
61
+ ## Related
62
+
63
+ None yet.
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: "Index of sync CLI documentation covering the CLI entry point, sync/push/pull-manifest commands, and shared systems (manifest, git/GitHub, path resolution, interactive UI)."
3
+ ---
4
+
5
+ # Sync CLI
6
+
7
+ CLI for distributing the all-hands framework to other repositories and contributing changes back upstream.
8
+
9
+ ## Entry Point
10
+
11
+ `docs/sync-cli/cli-entrypoint-and-commands.md` — Top-level CLI structure, yargs registration, and dependency checks.
12
+
13
+ ## Commands
14
+
15
+ See `docs/sync-cli/commands/README.md` for the full list.
16
+
17
+ ## Systems
18
+
19
+ Shared libraries used across commands. See `docs/sync-cli/systems/README.md`.
@@ -0,0 +1,39 @@
1
+ ---
2
+ description: "Top-level CLI entrypoint that registers sync, push, and pull-manifest commands via yargs, with git dependency gating at startup"
3
+ ---
4
+
5
+ # CLI Entrypoint and Command Registration
6
+
7
+ The sync-cli is the distribution tool for the allhands framework. It handles moving framework files between the upstream source and target repositories, managing conflicts, and contributing changes back.
8
+
9
+ ## Startup Sequence
10
+
11
+ ```mermaid
12
+ flowchart TD
13
+ A[main] --> B{git installed?}
14
+ B -- No --> C[Exit 1: git required]
15
+ B -- Yes --> D[Parse argv via yargs]
16
+ D --> E{command?}
17
+ E -- sync --> F[cmdSync]
18
+ E -- push --> G[cmdPush]
19
+ E -- pull-manifest --> H[cmdPullManifest]
20
+ E -- none --> I[Exit: demandCommand error]
21
+ ```
22
+
23
+ [ref:src/sync-cli.ts:main:d536164] gates on [ref:src/lib/git.ts:checkGitInstalled:70a743c] before any command parsing occurs. This is the only dependency check at the entrypoint level -- the `push` command performs its own additional prerequisite checks (gh CLI, auth, repo detection).
24
+
25
+ ## Command Surface
26
+
27
+ | Command | Entry | Purpose |
28
+ |---|---|---|
29
+ | `sync [target]` | [ref:src/sync-cli.ts:syncHandler:d536164] | Initialize or update allhands in a target repo |
30
+ | `push` | [ref:src/commands/push.ts:cmdPush:e7d51e3] | Contribute local changes back upstream via fork + PR |
31
+ | `pull-manifest` | [ref:src/commands/pull-manifest.ts:cmdPullManifest:92ad739] | Scaffold the sync config file for push customization |
32
+
33
+ ## Key Design Decision: Separated Builder/Handler
34
+
35
+ [ref:src/sync-cli.ts:syncBuilder:d536164] and [ref:src/sync-cli.ts:syncHandler:d536164] are extracted as named functions rather than inlined in the yargs `.command()` call. This enables reuse if the sync command needs to be composed or tested independently. The other commands inline their builders since they have no reuse need.
36
+
37
+ ## Process Exit Convention
38
+
39
+ Every command handler resolves to a numeric exit code (`Promise<number>`). The entrypoint calls `process.exit(code)` after awaiting the handler. This keeps command implementations testable (they return codes, not call exit themselves) while ensuring the CLI process terminates cleanly.
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: "Index of sync CLI command documentation covering sync (framework installation/update), push (upstream contribution), and pull-manifest (config scaffolding)."
3
+ ---
4
+
5
+ # Sync CLI Commands
6
+
7
+ | Command | Purpose | Doc |
8
+ |---|---|---|
9
+ | sync | Initialize or update the allhands framework with conflict resolution | `docs/sync-cli/commands/sync-command.md` |
10
+ | push | Contribute local changes back upstream via GitHub fork and PR | `docs/sync-cli/commands/push-command.md` |
11
+ | pull-manifest | Scaffold the sync config file for push customization | `docs/sync-cli/commands/pull-manifest-command.md` |
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: "Pull-manifest command that scaffolds the sync config file for customizing which files are included or excluded during push operations"
3
+ ---
4
+
5
+ # Pull-Manifest Command
6
+
7
+ [ref:src/commands/pull-manifest.ts:cmdPullManifest:92ad739] is the simplest command in the CLI -- it writes a template configuration file that lets repositories customize their push behavior.
8
+
9
+ ## Intent
10
+
11
+ The push command needs to know which additional files to include and which to exclude when creating upstream PRs. Rather than requiring users to always pass `--include` and `--exclude` flags, the sync config file persists these preferences in version control.
12
+
13
+ ## Guard Rails
14
+
15
+ The command enforces two preconditions:
16
+ - Must be in a git repository (checked via [ref:src/lib/git.ts:isGitRepo:70a743c])
17
+ - Config file must not already exist (prevents accidental overwrite of user customizations)
18
+
19
+ If the file exists, the user is told to remove it first and re-run. This is intentional -- there's no merge logic for config files, so regeneration should be a conscious choice.
20
+
21
+ ## Config File Shape
22
+
23
+ The template is defined as [ref:src/lib/constants.ts:SYNC_CONFIG_TEMPLATE:61d6025] and written to the path defined by [ref:src/lib/constants.ts:SYNC_CONFIG_FILENAME:61d6025] (`.allhands-sync-config.json`):
24
+
25
+ ```
26
+ {
27
+ "$comment": "Customization for claude-all-hands push command",
28
+ "includes": [],
29
+ "excludes": []
30
+ }
31
+ ```
32
+
33
+ - **includes** -- Glob patterns for additional files to push beyond the standard distributable set
34
+ - **excludes** -- Glob patterns for files to skip, even if they differ from upstream
35
+
36
+ The config file itself is in [ref:src/lib/constants.ts:PUSH_BLOCKLIST:61d6025], so it is never pushed back upstream -- it's purely a local customization mechanism.
@@ -0,0 +1,84 @@
1
+ ---
2
+ description: "Push command that contributes local allhands changes back to upstream via GitHub fork, temp clone, and pull request creation"
3
+ ---
4
+
5
+ # Push Command
6
+
7
+ The push command enables downstream consumers to contribute their local allhands modifications back to the upstream repository. It uses a fork-based workflow -- forking the upstream repo, cloning to a temp directory, copying changed files, and opening a pull request.
8
+
9
+ ## Contribution Flow
10
+
11
+ ```mermaid
12
+ sequenceDiagram
13
+ participant User
14
+ participant CLI as cmdPush
15
+ participant GH as GitHub API
16
+ participant TempDir as Temp Clone
17
+
18
+ CLI->>CLI: checkPrerequisites (gh, auth, repo)
19
+ CLI->>CLI: loadSyncConfig
20
+ CLI->>CLI: collectFilesToPush
21
+
22
+ alt dry-run
23
+ CLI->>User: Print file list, exit
24
+ end
25
+
26
+ CLI->>User: Prompt for title/body
27
+ CLI->>GH: Check for existing fork
28
+
29
+ alt no fork
30
+ CLI->>GH: Fork upstream
31
+ CLI->>GH: waitForFork (poll up to 30s)
32
+ end
33
+
34
+ CLI->>TempDir: Clone fork (depth=1)
35
+ CLI->>TempDir: Add upstream remote
36
+ CLI->>TempDir: Fetch upstream/main
37
+ CLI->>TempDir: Create branch from upstream/main
38
+ CLI->>TempDir: Copy changed files from CWD
39
+ CLI->>TempDir: git add + commit
40
+ CLI->>GH: Push branch to fork
41
+ CLI->>GH: Create PR against upstream
42
+ CLI->>User: Print PR URL
43
+ CLI->>TempDir: Cleanup temp directory
44
+ ```
45
+
46
+ ## File Collection Logic
47
+
48
+ [ref:src/commands/push.ts:collectFilesToPush:e7d51e3] determines which files to include in the PR through a layered filtering pipeline:
49
+
50
+ 1. **Distributable files** -- Gets the upstream manifest's distributable set via [ref:src/lib/manifest.ts:Manifest:e06b487]
51
+ 2. **Blocklist filter** -- Removes files in [ref:src/lib/constants.ts:PUSH_BLOCKLIST:61d6025] (e.g., `CLAUDE.project.md`, sync config)
52
+ 3. **Exclude filter** -- Removes files matching user-provided or config-defined exclude patterns
53
+ 4. **Gitignore filter** -- Skips files not tracked by git in the user's repo
54
+ 5. **Diff filter** -- Only includes files where [ref:src/lib/manifest.ts:filesAreDifferent:e06b487] detects byte-level changes
55
+ 6. **Include expansion** -- [ref:src/commands/push.ts:expandGlob:e7d51e3] adds extra files matching include patterns that aren't already queued
56
+
57
+ Files are classified as `M` (modified upstream file) or `A` (additional file via includes).
58
+
59
+ ## Sync Config Integration
60
+
61
+ [ref:src/commands/push.ts:loadSyncConfig:e7d51e3] reads `.allhands-sync-config.json` if present. CLI flags (`--include`, `--exclude`) take precedence over config values. This allows repositories to persist their push customization in version control while still supporting one-off overrides.
62
+
63
+ ## Prerequisite Checks
64
+
65
+ [ref:src/commands/push.ts:checkPrerequisites:e7d51e3] validates four conditions before any work begins:
66
+
67
+ | Check | Failure |
68
+ |---|---|
69
+ | `gh` CLI installed | [ref:src/lib/gh.ts:checkGhInstalled:64ba656] |
70
+ | `gh` authenticated | [ref:src/lib/gh.ts:checkGhAuth:64ba656] |
71
+ | Current directory is a git repo | [ref:src/lib/git.ts:isGitRepo:70a743c] |
72
+ | GitHub username resolvable | [ref:src/lib/gh.ts:getGhUser:64ba656] |
73
+
74
+ ## Fork Readiness Polling
75
+
76
+ [ref:src/commands/push.ts:waitForFork:e7d51e3] handles GitHub's async fork creation by polling the fork's existence via the gh API every 2 seconds for up to 30 seconds (15 attempts). This avoids race conditions where the CLI tries to clone a fork that hasn't propagated yet.
77
+
78
+ ## Branch Naming Convention
79
+
80
+ Branches are created as `contrib/<github-user>/<timestamp>`, ensuring uniqueness across multiple pushes from the same user without collision. The branch is based on `upstream/main` regardless of the fork's default branch state.
81
+
82
+ ## Temp Directory Lifecycle
83
+
84
+ The entire git operation (clone, branch, copy, commit, push) happens in a temp directory under `os.tmpdir()`. The directory is cleaned up in a `finally` block via [ref:src/commands/push.ts:createPullRequest:e7d51e3], ensuring no orphaned clones accumulate even on failure.
@@ -0,0 +1,71 @@
1
+ ---
2
+ description: "Sync command that initializes or updates the allhands framework in a target repository, handling conflict resolution, dotfile restoration, target-line injection, and ah CLI shim installation"
3
+ ---
4
+
5
+ # Sync Command
6
+
7
+ The sync command is the primary distribution mechanism. It copies distributable files from the allhands package source into a target repository, detecting whether this is a first-time initialization or an incremental update, and handling conflicts accordingly.
8
+
9
+ ## Lifecycle
10
+
11
+ ```mermaid
12
+ stateDiagram-v2
13
+ [*] --> ResolveTarget
14
+ ResolveTarget --> DetectMode: target exists
15
+ ResolveTarget --> Error: target missing
16
+ DetectMode --> FirstTimeInit: no .allhands/ dir
17
+ DetectMode --> IncrementalUpdate: .allhands/ exists
18
+
19
+ FirstTimeInit --> CopyFiles
20
+
21
+ IncrementalUpdate --> StagedCheck
22
+ StagedCheck --> Error: staged conflicts in managed files
23
+ StagedCheck --> DetectConflicts: no staged conflicts
24
+ DetectConflicts --> AskResolution: conflicts found
25
+ DetectConflicts --> CopyFiles: no conflicts
26
+ AskResolution --> CreateBackups: user picks backup
27
+ AskResolution --> CopyFiles: user picks overwrite
28
+ AskResolution --> Abort: user cancels
29
+
30
+ CopyFiles --> RestoreDotfiles
31
+ RestoreDotfiles --> HandleDeletedFiles: update mode
32
+ RestoreDotfiles --> SyncTargetLines: init mode
33
+ HandleDeletedFiles --> SyncTargetLines
34
+ SyncTargetLines --> CopyEnvExamples
35
+ CopyEnvExamples --> SetupShim: init mode
36
+ CopyEnvExamples --> Done: update mode
37
+ SetupShim --> Done
38
+ Done --> [*]
39
+ ```
40
+
41
+ ## Conflict Resolution Strategy
42
+
43
+ [ref:src/commands/sync.ts:cmdSync:ca521c9] employs a two-phase conflict detection approach:
44
+
45
+ 1. **Staged file guard** -- Before any file operations, checks if the target repo has staged git changes that overlap with managed files. This prevents the sync from silently overwriting work the user intends to commit. Uses [ref:src/lib/manifest.ts:Manifest:e06b487] to determine the managed file set and [ref:src/lib/git.ts:getStagedFiles:70a743c] to detect staging conflicts.
46
+
47
+ 2. **Content-level diff** -- Iterates all distributable files and uses [ref:src/lib/manifest.ts:filesAreDifferent:e06b487] (byte-level comparison) to identify files that differ between source and target. The user is then presented with three options via [ref:src/lib/ui.ts:askConflictResolution:6374626]:
48
+
49
+ | Resolution | Behavior |
50
+ |---|---|
51
+ | **Backup** | Creates `file.backup_N.ext` via [ref:src/lib/ui.ts:getNextBackupPath:6374626], then overwrites |
52
+ | **Overwrite** | Replaces target files directly (local changes lost) |
53
+ | **Cancel** | Aborts with no changes made |
54
+
55
+ The `--yes` flag forces overwrite mode, skipping all interactive prompts.
56
+
57
+ ## Post-Copy Processing
58
+
59
+ After file copying, three post-processing steps run in sequence:
60
+
61
+ - **Dotfile restoration** -- [ref:src/lib/dotfiles.ts:restoreDotfiles:8d2662f] renames npm-safe names back to dotfiles (e.g., `gitignore` to `.gitignore`). This is necessary because npm strips dotfiles during package publishing.
62
+ - **Target-line injection** -- [ref:src/lib/target-lines.ts:ensureTargetLines:c2f18b9] appends required lines to target-repo files (like `.gitignore`, `CLAUDE.md`, `.tldrignore`) without duplicating existing entries.
63
+ - **Deleted file cleanup** (update only) -- Detects files that exist in the target but were removed from the source, prompting the user to delete them.
64
+
65
+ ## The `ah` CLI Shim
66
+
67
+ On first-time init, [ref:src/commands/sync.ts:setupAhShim:ca521c9] installs a bash shim to `~/.local/bin/ah`. The shim walks up the directory tree from `$PWD` looking for `.allhands/harness/ah`, enabling project-local `ah` invocation from anywhere within a synced repository. It warns if `~/.local/bin` is not in `PATH`.
68
+
69
+ ## Full Replace Alternative
70
+
71
+ [ref:src/lib/full-replace.ts:fullReplace:827a9fa] provides a wholesale directory replacement strategy as an alternative to the file-by-file approach in `cmdSync`. It backs up entire `.allhands` and `.claude` directories with timestamped names via [ref:src/lib/full-replace.ts:getBackupDirName:827a9fa], then restores preserved items (like `node_modules` and `settings.local.json`) from the backup. [ref:src/lib/full-replace.ts:checkPreservedFiles:827a9fa] identifies root-level files that should never be overwritten (`.env`, `.env.ai`, `.env.local`).
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: "Index of sync CLI shared system documentation covering manifest/distribution, git/GitHub integration, path resolution, and interactive UI."
3
+ ---
4
+
5
+ # Sync CLI Systems
6
+
7
+ Shared libraries used across sync CLI commands.
8
+
9
+ | System | Purpose | Doc |
10
+ |---|---|---|
11
+ | Manifest & distribution | File classification (distributable, internal, gitignored) | `docs/sync-cli/systems/manifest-and-distribution.md` |
12
+ | Git & GitHub integration | Structured wrappers for git and gh CLI operations | `docs/sync-cli/systems/git-and-github-integration.md` |
13
+ | Path resolution | Allhands root discovery via env var or package-relative lookup | `docs/sync-cli/systems/path-resolution.md` |
14
+ | Interactive UI | Terminal prompts, conflict resolution, backup path generation | `docs/sync-cli/systems/interactive-ui.md` |
@@ -0,0 +1,49 @@
1
+ ---
2
+ description: "Git and GitHub CLI wrapper layers that provide structured result types for repo detection, file listing, authentication checks, and API calls"
3
+ ---
4
+
5
+ # Git and GitHub Integration
6
+
7
+ The sync-cli wraps both `git` and `gh` (GitHub CLI) behind thin abstraction layers that normalize output into structured result types. These wrappers are consumed across all three commands.
8
+
9
+ ## Result Type Convention
10
+
11
+ Both [ref:src/lib/git.ts:git:70a743c] and [ref:src/lib/gh.ts:gh:64ba656] return the same shape:
12
+
13
+ | Field | Type | Meaning |
14
+ |---|---|---|
15
+ | `success` | `boolean` | Exit code === 0 |
16
+ | `stdout` | `string` | Trimmed stdout |
17
+ | `stderr` | `string` | Trimmed stderr |
18
+
19
+ Both use `spawnSync` (not `execSync`) for structured access to exit codes and stderr without try/catch. The 10MB max buffer accommodates large repos with many files.
20
+
21
+ ## Git Operations
22
+
23
+ [ref:src/lib/git.ts::70a743c] exposes four capabilities:
24
+
25
+ | Function | Used By | Purpose |
26
+ |---|---|---|
27
+ | [ref:src/lib/git.ts:checkGitInstalled:70a743c] | CLI entrypoint | Pre-flight: is `git` available? |
28
+ | [ref:src/lib/git.ts:isGitRepo:70a743c] | sync, push, pull-manifest | Guards commands that require a repo context |
29
+ | [ref:src/lib/git.ts:getStagedFiles:70a743c] | sync | Detects staged changes that would conflict with sync |
30
+ | [ref:src/lib/git.ts:getGitFiles:70a743c] | push | Lists tracked + untracked-but-not-ignored files |
31
+
32
+ [ref:src/lib/git.ts:getGitFiles:70a743c] combines `git ls-files` (tracked) with `git ls-files --others --exclude-standard` (untracked, not ignored) to produce a complete view of files the user's repo considers relevant. This is critical for the push command's gitignore-respecting file collection.
33
+
34
+ ## GitHub CLI Operations
35
+
36
+ [ref:src/lib/gh.ts::64ba656] provides authentication and identity primitives:
37
+
38
+ | Function | Used By | Purpose |
39
+ |---|---|---|
40
+ | [ref:src/lib/gh.ts:checkGhInstalled:64ba656] | push | Pre-flight: is `gh` available? |
41
+ | [ref:src/lib/gh.ts:checkGhAuth:64ba656] | push | Is the user authenticated with GitHub? |
42
+ | [ref:src/lib/gh.ts:getGhUser:64ba656] | push | Resolves the authenticated GitHub username |
43
+ | [ref:src/lib/gh.ts:gh:64ba656] | push (fork, clone, PR) | General-purpose gh command runner |
44
+
45
+ The push command is the sole consumer of the gh layer -- sync and pull-manifest only need local git operations.
46
+
47
+ ## Design Trade-off: Synchronous Execution
48
+
49
+ Both wrappers use `spawnSync` (blocking). This simplifies control flow throughout the CLI since commands execute sequentially. The trade-off is that long-running git operations (like cloning in the push command) block the event loop, but this is acceptable for a CLI tool where the user is waiting for completion anyway.
@@ -0,0 +1,43 @@
1
+ ---
2
+ description: "Terminal prompt utilities for yes/no confirmation, conflict resolution menus, free-text questions, and incrementing backup path generation"
3
+ ---
4
+
5
+ # Interactive UI
6
+
7
+ [ref:src/lib/ui.ts::6374626] provides the interactive terminal layer for the sync-cli. It wraps Node's `readline` interface into purpose-built prompt functions used across the sync and push commands.
8
+
9
+ ## Prompt Functions
10
+
11
+ | Function | Returns | Used By |
12
+ |---|---|---|
13
+ | [ref:src/lib/ui.ts:askQuestion:6374626] | `string` | push (PR title) |
14
+ | [ref:src/lib/ui.ts:confirm:6374626] | `boolean` | sync (continue, delete), push (create PR) |
15
+ | [ref:src/lib/ui.ts:askConflictResolution:6374626] | `ConflictResolution` | sync (conflict handling) |
16
+
17
+ Each function creates and closes its own `readline.Interface` instance. This avoids keeping a persistent readline open, which would interfere with process exit.
18
+
19
+ ## Conflict Resolution Menu
20
+
21
+ [ref:src/lib/ui.ts:askConflictResolution:6374626] presents a three-option menu when the sync command detects files that differ between source and target:
22
+
23
+ - **`b` (backup)** -- Create numbered backup files before overwriting
24
+ - **`o` (overwrite)** -- Replace directly, losing local changes
25
+ - **`c` (cancel)** -- Abort the entire sync with no changes
26
+
27
+ The menu loops on invalid input, requiring an explicit valid choice. This is the only multi-option prompt in the CLI -- all other interactions are simple yes/no via [ref:src/lib/ui.ts:confirm:6374626].
28
+
29
+ ## Backup Path Generation
30
+
31
+ [ref:src/lib/ui.ts:getNextBackupPath:6374626] generates non-colliding backup filenames using an incrementing counter:
32
+
33
+ ```
34
+ original.ts -> original.backup_1.ts
35
+ -> original.backup_2.ts
36
+ -> original.backup_3.ts
37
+ ```
38
+
39
+ It scans the directory for existing backup files matching the pattern `<base>.backup_<N><ext>` and selects `N+1`. The regex is built with escaped characters from the original filename to avoid glob injection from filenames containing special characters.
40
+
41
+ ## Design Choice: No Persistent State
42
+
43
+ The UI module is stateless -- no prompt history, no saved preferences. The `--yes` flag on sync and the `--title`/`--body` flags on push bypass interactive prompts entirely, enabling non-interactive CI usage. This separation means the UI layer is purely a human interface concern that can be skipped wholesale in automation.