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.
- package/.allhands/README.md +75 -0
- package/.allhands/agents/compounder.yaml +15 -0
- package/.allhands/agents/coordinator.yaml +17 -0
- package/.allhands/agents/documentor.yaml +15 -0
- package/.allhands/agents/e2e-test-planner.yaml +17 -0
- package/.allhands/agents/emergent.yaml +22 -0
- package/.allhands/agents/executor.yaml +14 -0
- package/.allhands/agents/ideation.yaml +11 -0
- package/.allhands/agents/initiative-steering.yaml +19 -0
- package/.allhands/agents/judge.yaml +13 -0
- package/.allhands/agents/planner.yaml +19 -0
- package/.allhands/agents/pr-reviewer.yaml +15 -0
- package/.allhands/docs.json +5 -0
- package/.allhands/docs.local.json +26 -0
- package/.allhands/flows/COMPOUNDING.md +203 -0
- package/.allhands/flows/COORDINATION.md +89 -0
- package/.allhands/flows/CORE.md +87 -0
- package/.allhands/flows/DOCUMENTATION.md +218 -0
- package/.allhands/flows/E2E_TEST_PLAN_BUILDING.md +140 -0
- package/.allhands/flows/EMERGENT_PLANNING.md +57 -0
- package/.allhands/flows/IDEATION_SCOPING.md +154 -0
- package/.allhands/flows/INITIATIVE_STEERING.md +110 -0
- package/.allhands/flows/JUDGE_REVIEWING.md +79 -0
- package/.allhands/flows/PROMPT_TASK_EXECUTION.md +68 -0
- package/.allhands/flows/PR_REVIEWING.md +43 -0
- package/.allhands/flows/SPEC_PLANNING.md +216 -0
- package/.allhands/flows/harness/WRITING_HARNESS_FLOWS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_KNOWLEDGE.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_ORCHESTRATION.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_SKILLS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_TOOLS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_VALIDATION_TOOLING.md +27 -0
- package/.allhands/flows/shared/CODEBASE_UNDERSTANDING.md +72 -0
- package/.allhands/flows/shared/CREATE_HARNESS_SPEC.md +48 -0
- package/.allhands/flows/shared/CREATE_SPEC.md +41 -0
- package/.allhands/flows/shared/CREATE_VALIDATION_TOOLING_SPEC.md +70 -0
- package/.allhands/flows/shared/DOCUMENTATION_DISCOVERY.md +123 -0
- package/.allhands/flows/shared/DOCUMENTATION_WRITER.md +101 -0
- package/.allhands/flows/shared/EMERGENT_REFINEMENT_ANALYSIS.md +76 -0
- package/.allhands/flows/shared/EXTERNAL_TECH_GUIDANCE.md +97 -0
- package/.allhands/flows/shared/IDEATION_CODEBASE_GROUNDING.md +49 -0
- package/.allhands/flows/shared/PLAN_DEEPENING.md +152 -0
- package/.allhands/flows/shared/PROMPT_TASKS_CURATION.md +113 -0
- package/.allhands/flows/shared/PROMPT_VALIDATION_REVIEW.MD +99 -0
- package/.allhands/flows/shared/QUICK_PREMORTEM.md +70 -0
- package/.allhands/flows/shared/RESEARCH_GUIDANCE.md +38 -0
- package/.allhands/flows/shared/REVIEW_OPTIONS_BREAKDOWN.md +68 -0
- package/.allhands/flows/shared/SKILL_EXTRACTION.md +84 -0
- package/.allhands/flows/shared/SPEC_FLOW_ANALYSIS.md +119 -0
- package/.allhands/flows/shared/TDD_WORKFLOW.md +109 -0
- package/.allhands/flows/shared/UTILIZE_VALIDATION_TOOLING.md +84 -0
- package/.allhands/flows/shared/WRITING_HARNESS_FLOWS.md +11 -0
- package/.allhands/flows/shared/WRITING_HARNESS_MCP_TOOLS.md +84 -0
- package/.allhands/flows/shared/jury/ARCHITECTURE_REVIEW.md +91 -0
- package/.allhands/flows/shared/jury/BEST_PRACTICES_REVIEW.md +80 -0
- package/.allhands/flows/shared/jury/CLAIM_VERIFICATION_REVIEW.md +101 -0
- package/.allhands/flows/shared/jury/EXPECTATIONS_FIT_REVIEW.md +78 -0
- package/.allhands/flows/shared/jury/MAINTAINABILITY_REVIEW.md +110 -0
- package/.allhands/flows/shared/jury/PROMPTS_EXPECTATIONS_FIT.md +74 -0
- package/.allhands/flows/shared/jury/PROMPTS_FLOW_ANALYSIS.md +92 -0
- package/.allhands/flows/shared/jury/PROMPTS_YAGNI.md +78 -0
- package/.allhands/flows/shared/jury/PROMPT_PREMORTEM.md +125 -0
- package/.allhands/flows/shared/jury/SECURITY_REVIEW.md +86 -0
- package/.allhands/flows/shared/jury/YAGNI_REVIEW.md +82 -0
- package/.allhands/flows/wip/DEBUG_INVESTIGATION.md +162 -0
- package/.allhands/flows/wip/MEMORY_RECALL.md +62 -0
- package/.allhands/harness/ah +131 -0
- package/.allhands/harness/package-lock.json +5292 -0
- package/.allhands/harness/package.json +52 -0
- package/.allhands/harness/src/__tests__/e2e/commands.test.ts +307 -0
- package/.allhands/harness/src/__tests__/e2e/event-loop.test.ts +539 -0
- package/.allhands/harness/src/__tests__/e2e/hooks.test.ts +427 -0
- package/.allhands/harness/src/__tests__/e2e/new-initiative-routing.test.ts +137 -0
- package/.allhands/harness/src/__tests__/e2e/run-e2e.ts +109 -0
- package/.allhands/harness/src/__tests__/e2e/specs-type.test.ts +210 -0
- package/.allhands/harness/src/__tests__/e2e/validation-hooks.test.ts +669 -0
- package/.allhands/harness/src/__tests__/e2e/validation-path-consistency.test.ts +354 -0
- package/.allhands/harness/src/__tests__/e2e/validation.test.ts +528 -0
- package/.allhands/harness/src/__tests__/harness/assertions.ts +318 -0
- package/.allhands/harness/src/__tests__/harness/cli-runner.ts +359 -0
- package/.allhands/harness/src/__tests__/harness/fixture.ts +384 -0
- package/.allhands/harness/src/__tests__/harness/hook-runner.ts +411 -0
- package/.allhands/harness/src/__tests__/harness/index.ts +122 -0
- package/.allhands/harness/src/cli.ts +36 -0
- package/.allhands/harness/src/commands/complexity.ts +177 -0
- package/.allhands/harness/src/commands/context7.ts +202 -0
- package/.allhands/harness/src/commands/docs.ts +557 -0
- package/.allhands/harness/src/commands/hooks.ts +24 -0
- package/.allhands/harness/src/commands/index.ts +51 -0
- package/.allhands/harness/src/commands/knowledge.ts +382 -0
- package/.allhands/harness/src/commands/memories.ts +302 -0
- package/.allhands/harness/src/commands/notify.ts +61 -0
- package/.allhands/harness/src/commands/oracle.ts +158 -0
- package/.allhands/harness/src/commands/perplexity.ts +220 -0
- package/.allhands/harness/src/commands/planning.ts +245 -0
- package/.allhands/harness/src/commands/schema.ts +73 -0
- package/.allhands/harness/src/commands/skills.ts +128 -0
- package/.allhands/harness/src/commands/solutions.ts +353 -0
- package/.allhands/harness/src/commands/spawn.ts +158 -0
- package/.allhands/harness/src/commands/specs.ts +532 -0
- package/.allhands/harness/src/commands/tavily.ts +226 -0
- package/.allhands/harness/src/commands/tools.ts +579 -0
- package/.allhands/harness/src/commands/trace.ts +327 -0
- package/.allhands/harness/src/commands/tui.ts +960 -0
- package/.allhands/harness/src/commands/validate.ts +143 -0
- package/.allhands/harness/src/commands/validation-tools.ts +108 -0
- package/.allhands/harness/src/hooks/context.ts +1442 -0
- package/.allhands/harness/src/hooks/enforcement.ts +170 -0
- package/.allhands/harness/src/hooks/index.ts +54 -0
- package/.allhands/harness/src/hooks/lifecycle.ts +229 -0
- package/.allhands/harness/src/hooks/notification.ts +104 -0
- package/.allhands/harness/src/hooks/observability.ts +551 -0
- package/.allhands/harness/src/hooks/session.ts +88 -0
- package/.allhands/harness/src/hooks/shared.ts +815 -0
- package/.allhands/harness/src/hooks/transcript-parser.ts +208 -0
- package/.allhands/harness/src/hooks/validation.ts +617 -0
- package/.allhands/harness/src/lib/__tests__/ctags.test.ts +244 -0
- package/.allhands/harness/src/lib/__tests__/docs-validation.test.ts +344 -0
- package/.allhands/harness/src/lib/__tests__/mcp-runtime.test.ts +190 -0
- package/.allhands/harness/src/lib/__tests__/schema.test.ts +861 -0
- package/.allhands/harness/src/lib/base-command.ts +198 -0
- package/.allhands/harness/src/lib/cli-daemon.ts +343 -0
- package/.allhands/harness/src/lib/compaction.ts +313 -0
- package/.allhands/harness/src/lib/ctags.ts +497 -0
- package/.allhands/harness/src/lib/docs-validation.ts +907 -0
- package/.allhands/harness/src/lib/event-loop.ts +662 -0
- package/.allhands/harness/src/lib/flows.ts +155 -0
- package/.allhands/harness/src/lib/git.ts +276 -0
- package/.allhands/harness/src/lib/knowledge-worker.ts +72 -0
- package/.allhands/harness/src/lib/knowledge.ts +810 -0
- package/.allhands/harness/src/lib/llm.ts +255 -0
- package/.allhands/harness/src/lib/mcp-client.ts +432 -0
- package/.allhands/harness/src/lib/mcp-daemon.ts +486 -0
- package/.allhands/harness/src/lib/mcp-runtime.ts +418 -0
- package/.allhands/harness/src/lib/notification.ts +115 -0
- package/.allhands/harness/src/lib/opencode/index.ts +70 -0
- package/.allhands/harness/src/lib/opencode/profiles.ts +300 -0
- package/.allhands/harness/src/lib/opencode/prompts/codesearch.md +98 -0
- package/.allhands/harness/src/lib/opencode/prompts/knowledge-aggregator.md +67 -0
- package/.allhands/harness/src/lib/opencode/runner.ts +281 -0
- package/.allhands/harness/src/lib/oracle.ts +926 -0
- package/.allhands/harness/src/lib/planning-utils.ts +150 -0
- package/.allhands/harness/src/lib/planning.ts +605 -0
- package/.allhands/harness/src/lib/pr-review.ts +225 -0
- package/.allhands/harness/src/lib/prompts.ts +522 -0
- package/.allhands/harness/src/lib/schema.ts +418 -0
- package/.allhands/harness/src/lib/schemas/agent-profile.ts +141 -0
- package/.allhands/harness/src/lib/schemas/template-vars.ts +138 -0
- package/.allhands/harness/src/lib/session.ts +164 -0
- package/.allhands/harness/src/lib/specs.ts +348 -0
- package/.allhands/harness/src/lib/tldr.ts +829 -0
- package/.allhands/harness/src/lib/tmux.ts +1051 -0
- package/.allhands/harness/src/lib/trace-store.ts +714 -0
- package/.allhands/harness/src/mcp/__tests__/index.test.ts +46 -0
- package/.allhands/harness/src/mcp/_template.ts +47 -0
- package/.allhands/harness/src/mcp/filesystem.ts +33 -0
- package/.allhands/harness/src/mcp/index.ts +69 -0
- package/.allhands/harness/src/mcp/playwright.ts +34 -0
- package/.allhands/harness/src/mcp/xcodebuild.ts +29 -0
- package/.allhands/harness/src/schemas/docs.schema.json +44 -0
- package/.allhands/harness/src/schemas/settings.schema.json +214 -0
- package/.allhands/harness/src/tui/actions.ts +227 -0
- package/.allhands/harness/src/tui/file-viewer-modal.ts +270 -0
- package/.allhands/harness/src/tui/index.ts +1574 -0
- package/.allhands/harness/src/tui/modal.ts +232 -0
- package/.allhands/harness/src/tui/prompts-pane.ts +186 -0
- package/.allhands/harness/src/tui/status-pane.ts +434 -0
- package/.allhands/harness/tsconfig.json +22 -0
- package/.allhands/harness/vitest.config.ts +13 -0
- package/.allhands/pillars.md +33 -0
- package/.allhands/principles.md +88 -0
- package/.allhands/schemas/alignment.yaml +51 -0
- package/.allhands/schemas/documentation.yaml +10 -0
- package/.allhands/schemas/prompt.yaml +92 -0
- package/.allhands/schemas/skill.yaml +34 -0
- package/.allhands/schemas/solution.yaml +131 -0
- package/.allhands/schemas/spec.yaml +67 -0
- package/.allhands/schemas/validation-suite.yaml +49 -0
- package/.allhands/schemas/workflow.yaml +51 -0
- package/.allhands/settings.json +57 -0
- package/.allhands/skills/claude-code-patterns/SKILL.md +60 -0
- package/.allhands/skills/claude-code-patterns/docs/context-hygiene.md +19 -0
- package/.allhands/skills/harness-maintenance/SKILL.md +449 -0
- package/.allhands/skills/harness-maintenance/references/core-architecture.md +187 -0
- package/.allhands/skills/harness-maintenance/references/harness-skills.md +87 -0
- package/.allhands/skills/harness-maintenance/references/knowledge-compounding.md +78 -0
- package/.allhands/skills/harness-maintenance/references/tools-commands-mcp-hooks.md +115 -0
- package/.allhands/skills/harness-maintenance/references/validation-tooling.md +77 -0
- package/.allhands/skills/harness-maintenance/references/writing-flows.md +84 -0
- package/.allhands/validation/browser-automation.md +109 -0
- package/.allhands/validation/xcode-automation.md +195 -0
- package/.allhands/workflows/documentation.md +86 -0
- package/.allhands/workflows/investigation.md +81 -0
- package/.allhands/workflows/milestone.md +91 -0
- package/.allhands/workflows/optimization.md +85 -0
- package/.allhands/workflows/refactor.md +99 -0
- package/.allhands/workflows/triage.md +81 -0
- package/.claude/README.md +1 -0
- package/.claude/agents/explorer.md +10 -0
- package/.claude/agents/researcher.md +11 -0
- package/.claude/agents/task-runner.md +8 -0
- package/.claude/settings.json +231 -0
- package/.env.ai.example +7 -0
- package/.github/workflows/npm-publish.yml +69 -0
- package/.internal.json +45 -0
- package/.tldr/config.json +11 -0
- package/.tldrignore +90 -0
- package/CLAUDE.md +6 -0
- package/README.md +98 -0
- package/bin/sync-cli.js +7552 -0
- package/concerns.md +7 -0
- package/docs/README.md +41 -0
- package/docs/agents/README.md +24 -0
- package/docs/agents/agent-configuration-system.md +86 -0
- package/docs/agents/execution-agents.md +50 -0
- package/docs/agents/knowledge-agents.md +61 -0
- package/docs/agents/orchestration-agent.md +57 -0
- package/docs/agents/planning-agents.md +84 -0
- package/docs/agents/quality-review-agents.md +67 -0
- package/docs/agents/workflow-agent-orchestration.md +69 -0
- package/docs/flows/README.md +44 -0
- package/docs/flows/compounding.md +126 -0
- package/docs/flows/coordination.md +72 -0
- package/docs/flows/core-harness-integration.md +63 -0
- package/docs/flows/documentation-orchestration.md +98 -0
- package/docs/flows/e2e-test-plan-building.md +83 -0
- package/docs/flows/emergent-refinement.md +104 -0
- package/docs/flows/flow-authoring-and-mcp-tools.md +89 -0
- package/docs/flows/judge-reviewing.md +112 -0
- package/docs/flows/plan-deepening-and-research.md +107 -0
- package/docs/flows/plan-review-jury.md +114 -0
- package/docs/flows/pr-reviewing.md +54 -0
- package/docs/flows/prompt-task-execution.md +119 -0
- package/docs/flows/spec-planning.md +162 -0
- package/docs/flows/type-specific-scoping-flows.md +49 -0
- package/docs/flows/validation-and-skills-integration.md +145 -0
- package/docs/flows/wip/wip-flows.md +102 -0
- package/docs/harness/README.md +23 -0
- package/docs/harness/agent-profiles.md +84 -0
- package/docs/harness/cli/README.md +24 -0
- package/docs/harness/cli/cli-entry-and-command-discovery.md +91 -0
- package/docs/harness/cli/docs-command.md +87 -0
- package/docs/harness/cli/knowledge-command.md +91 -0
- package/docs/harness/cli/minor-cli-commands.md +65 -0
- package/docs/harness/cli/oracle-command.md +113 -0
- package/docs/harness/cli/planning-command.md +95 -0
- package/docs/harness/cli/schema-and-validation-commands.md +154 -0
- package/docs/harness/cli/search-commands.md +97 -0
- package/docs/harness/cli/spawn-command.md +136 -0
- package/docs/harness/cli/specs-command.md +102 -0
- package/docs/harness/cli/tools-command.md +122 -0
- package/docs/harness/cli/trace-command.md +122 -0
- package/docs/harness/cli-daemon.md +92 -0
- package/docs/harness/event-loop.md +184 -0
- package/docs/harness/hooks/README.md +15 -0
- package/docs/harness/hooks/context-hooks.md +96 -0
- package/docs/harness/hooks/lifecycle-and-observability-hooks.md +135 -0
- package/docs/harness/hooks/validation-hooks.md +97 -0
- package/docs/harness/test-harness.md +149 -0
- package/docs/harness/tui.md +176 -0
- package/docs/memories.md +20 -0
- package/docs/solutions/agentic-issues/premature-agent-deletion-tui-action-dependency-20260130.md +49 -0
- package/docs/solutions/agentic-issues/ref-anchor-scope-mismatch-skill-references-20260131.md +55 -0
- package/docs/solutions/agentic-issues/tautological-tests-routing-20260131.md +52 -0
- package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md +52 -0
- package/docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md +66 -0
- package/docs/solutions/security-issues/unsanitized-domain-path-join-20260131.md +52 -0
- package/docs/solutions/test-failures/event-loop-mock-ordering-checkAgentWindows-20260130.md +63 -0
- package/docs/sync-cli/README.md +19 -0
- package/docs/sync-cli/cli-entrypoint-and-commands.md +39 -0
- package/docs/sync-cli/commands/README.md +11 -0
- package/docs/sync-cli/commands/pull-manifest-command.md +36 -0
- package/docs/sync-cli/commands/push-command.md +84 -0
- package/docs/sync-cli/commands/sync-command.md +71 -0
- package/docs/sync-cli/systems/README.md +14 -0
- package/docs/sync-cli/systems/git-and-github-integration.md +49 -0
- package/docs/sync-cli/systems/interactive-ui.md +43 -0
- package/docs/sync-cli/systems/manifest-and-distribution.md +51 -0
- package/docs/sync-cli/systems/path-resolution.md +42 -0
- package/package.json +46 -0
- package/scripts/install-shim.sh +40 -0
- package/scripts/pre-pack.sh +25 -0
- package/specs/harness-maintenance-skill.spec.md +138 -0
- package/specs/roadmap/git-spec-lifecycle-management.spec.md +113 -0
- package/specs/sync-init-flag.spec.md +117 -0
- package/specs/unified-workflow-orchestration.spec.md +250 -0
- package/specs/validation-tooling-practice.spec.md +98 -0
- package/specs/workflow-domain-configuration.spec.md +265 -0
- package/src/commands/pull-manifest.ts +31 -0
- package/src/commands/push.ts +344 -0
- package/src/commands/sync.ts +289 -0
- package/src/lib/constants.ts +10 -0
- package/src/lib/dotfiles.ts +36 -0
- package/src/lib/fs-utils.ts +18 -0
- package/src/lib/gh.ts +40 -0
- package/src/lib/git.ts +63 -0
- package/src/lib/gitignore.ts +167 -0
- package/src/lib/manifest.ts +121 -0
- package/src/lib/marker-sync.ts +39 -0
- package/src/lib/paths.ts +38 -0
- package/src/lib/target-lines.ts +66 -0
- package/src/lib/ui.ts +78 -0
- package/src/sync-cli.ts +120 -0
- package/target-lines.json +23 -0
- package/tsconfig.json +20 -0
package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md
ADDED
|
@@ -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.
|