freeharness 0.4.1
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/LICENSE +21 -0
- package/NOTICE +108 -0
- package/README.md +134 -0
- package/canonical/HARVEST.yaml +858 -0
- package/canonical/PROVENANCE.yaml +740 -0
- package/canonical/agents/README.md +95 -0
- package/canonical/agents/agentic-architect.md +18 -0
- package/canonical/agents/database-reviewer.md +41 -0
- package/canonical/agents/explorer-ai-engineer-analyst.md +65 -0
- package/canonical/agents/pr-reviewer.md +96 -0
- package/canonical/agents/python-reviewer.md +55 -0
- package/canonical/agents/report-formatter.md +19 -0
- package/canonical/agents/security-reviewer.md +53 -0
- package/canonical/agents/test-writer.md +34 -0
- package/canonical/commands/fh-context.md +37 -0
- package/canonical/evals/promptfoo.redteam.yaml +108 -0
- package/canonical/hooks/cost-prices.json +14 -0
- package/canonical/hooks/freeharness-auto-memory.mjs +158 -0
- package/canonical/hooks/freeharness-config-guard.mjs +162 -0
- package/canonical/hooks/freeharness-context-monitor.mjs +198 -0
- package/canonical/hooks/freeharness-converge.mjs +227 -0
- package/canonical/hooks/freeharness-cost-tracker.mjs +1027 -0
- package/canonical/hooks/freeharness-memory-guard.mjs +57 -0
- package/canonical/hooks/freeharness-output-pruner.mjs +333 -0
- package/canonical/hooks/freeharness-precompact.mjs +323 -0
- package/canonical/hooks/freeharness-repeat-tool.mjs +208 -0
- package/canonical/hooks/freeharness-security-guidance.mjs +164 -0
- package/canonical/hooks/freeharness-session-start +583 -0
- package/canonical/hooks/hooks.auto-memory.claude-code.json +16 -0
- package/canonical/hooks/hooks.claude-code.json +17 -0
- package/canonical/hooks/hooks.config-guard.claude-code.json +16 -0
- package/canonical/hooks/hooks.context-monitor.claude-code.json +15 -0
- package/canonical/hooks/hooks.converge.claude-code.json +15 -0
- package/canonical/hooks/hooks.cost-tracker.claude-code.json +37 -0
- package/canonical/hooks/hooks.memory-guard.claude-code.json +16 -0
- package/canonical/hooks/hooks.output-pruner.claude-code.json +16 -0
- package/canonical/hooks/hooks.precompact.claude-code.json +15 -0
- package/canonical/hooks/hooks.repeat-tool.claude-code.json +25 -0
- package/canonical/hooks/hooks.security-guidance.claude-code.json +16 -0
- package/canonical/mcp/servers.json +20 -0
- package/canonical/openspec/config.base.yaml +89 -0
- package/canonical/openspec/schema.spec-driven.yaml +277 -0
- package/canonical/openspec/templates/data-contract.md +36 -0
- package/canonical/openspec/templates/design.md +84 -0
- package/canonical/openspec/templates/eval-plan.md +33 -0
- package/canonical/openspec/templates/follow-ups.md +2 -0
- package/canonical/openspec/templates/proposal.md +45 -0
- package/canonical/openspec/templates/spec.md +42 -0
- package/canonical/openspec/templates/tasks.md +38 -0
- package/canonical/profiles/local-llamacpp.LOCAL-MODELS.md +47 -0
- package/canonical/profiles/local-llamacpp.json +27 -0
- package/canonical/profiles/local-ollama.json +20 -0
- package/canonical/profiles/mcp.json +91 -0
- package/canonical/rules/CLAUDE.md +78 -0
- package/canonical/rules/project-CLAUDE.template.md +62 -0
- package/canonical/rules/routing.md +20 -0
- package/canonical/rules/safety.md +41 -0
- package/canonical/settings/settings.cache-hygiene.claude-code.json +5 -0
- package/canonical/skills/agent-evaluation/SKILL.md +102 -0
- package/canonical/skills/agent-evaluation/assets/evaluation_report_template.md +206 -0
- package/canonical/skills/agent-evaluation/evals/cases.yaml +106 -0
- package/canonical/skills/agent-evaluation/references/dataset-preparation.md +351 -0
- package/canonical/skills/agent-evaluation/references/scorers-constraints.md +165 -0
- package/canonical/skills/agent-evaluation/references/scorers.md +431 -0
- package/canonical/skills/agent-evaluation/references/setup-guide.md +252 -0
- package/canonical/skills/agent-evaluation/references/tracing-integration.md +164 -0
- package/canonical/skills/agent-evaluation/references/troubleshooting.md +514 -0
- package/canonical/skills/agent-evaluation/scripts/analyze_results.py +462 -0
- package/canonical/skills/agent-evaluation/scripts/create_dataset_template.py +382 -0
- package/canonical/skills/agent-evaluation/scripts/list_datasets.py +273 -0
- package/canonical/skills/agent-evaluation/scripts/run_evaluation_template.py +309 -0
- package/canonical/skills/agent-evaluation/scripts/setup_mlflow.py +353 -0
- package/canonical/skills/agent-evaluation/scripts/utils/__init__.py +27 -0
- package/canonical/skills/agent-evaluation/scripts/utils/env_validation.py +123 -0
- package/canonical/skills/agent-evaluation/scripts/utils/tracing_utils.py +108 -0
- package/canonical/skills/agent-evaluation/scripts/validate_agent_tracing.py +148 -0
- package/canonical/skills/agent-evaluation/scripts/validate_auth.py +240 -0
- package/canonical/skills/agent-evaluation/scripts/validate_environment.py +185 -0
- package/canonical/skills/agent-evaluation/scripts/validate_tracing_runtime.py +318 -0
- package/canonical/skills/agentic-architecture/SKILL.md +41 -0
- package/canonical/skills/agentic-architecture/evals/cases.yaml +94 -0
- package/canonical/skills/agentic-architecture/reference/context-engineering.md +75 -0
- package/canonical/skills/agentic-architecture/reference/patterns.md +76 -0
- package/canonical/skills/agentic-architecture/reference/reliability-observability.md +94 -0
- package/canonical/skills/agentic-architecture/reference/review-framework.md +59 -0
- package/canonical/skills/code-review/SKILL.md +52 -0
- package/canonical/skills/code-review/evals/cases.yaml +197 -0
- package/canonical/skills/git-workflow/SKILL.md +41 -0
- package/canonical/skills/git-workflow/evals/cases.yaml +92 -0
- package/canonical/skills/local-code/SKILL.md +24 -0
- package/canonical/skills/local-code/evals/cases.yaml +85 -0
- package/canonical/skills/local-code/scripts/query_llama.py +68 -0
- package/canonical/skills/report-formatting/SKILL.md +62 -0
- package/canonical/skills/report-formatting/evals/cases.yaml +83 -0
- package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +135 -0
- package/canonical/skills/report-formatting/reference/HELPERS.md +120 -0
- package/canonical/skills/report-formatting/reference/PPTX.md +136 -0
- package/canonical/skills/report-formatting/reference/RELEASE.md +99 -0
- package/canonical/skills/report-formatting/reference/TEMPLATES.md +48 -0
- package/canonical/skills/report-formatting/reference/authoring.md +66 -0
- package/canonical/skills/report-formatting/scripts/architecture-template.md +271 -0
- package/canonical/skills/report-formatting/scripts/assets/claro-logo.png +0 -0
- package/canonical/skills/report-formatting/scripts/assets/claro-wordmark.svg +1 -0
- package/canonical/skills/report-formatting/scripts/build-architecture.js +57 -0
- package/canonical/skills/report-formatting/scripts/build-md-claro.js +224 -0
- package/canonical/skills/report-formatting/scripts/build-release.js +51 -0
- package/canonical/skills/report-formatting/scripts/check-env.js +58 -0
- package/canonical/skills/report-formatting/scripts/docmodel.js +283 -0
- package/canonical/skills/report-formatting/scripts/example-build.js +119 -0
- package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +195 -0
- package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +114 -0
- package/canonical/skills/report-formatting/scripts/package.json +17 -0
- package/canonical/skills/report-formatting/scripts/pptx/example_build_StatusReport_pptx.py +223 -0
- package/canonical/skills/report-formatting/scripts/pptx/example_build_WeeklyStatus_pptx.py +245 -0
- package/canonical/skills/report-formatting/scripts/pptx/pptx_office.py +144 -0
- package/canonical/skills/report-formatting/scripts/pptx/requirements.txt +7 -0
- package/canonical/skills/report-formatting/scripts/pptx/status_report_blocks.py +193 -0
- package/canonical/skills/report-formatting/scripts/pptx/theme_claro_pptx.py +473 -0
- package/canonical/skills/report-formatting/scripts/release-template.md +80 -0
- package/canonical/skills/report-formatting/scripts/render-mermaid.js +105 -0
- package/canonical/skills/report-formatting/scripts/theme-claro.js +403 -0
- package/canonical/skills/subagent-driven-development/SKILL.md +60 -0
- package/canonical/skills/subagent-driven-development/evals/cases.yaml +208 -0
- package/canonical/skills/subagent-driven-development/reference/brief.md +91 -0
- package/canonical/skills/subagent-driven-development/reference/handoff.md +118 -0
- package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +850 -0
- package/canonical/skills/systematic-debugging/SKILL.md +44 -0
- package/canonical/skills/systematic-debugging/evals/cases.yaml +90 -0
- package/canonical/skills/test-driven-development/SKILL.md +42 -0
- package/canonical/skills/test-driven-development/evals/cases.yaml +86 -0
- package/canonical/skills/test-driven-development/reference/writing-good-tests.md +52 -0
- package/canonical/skills/verification-before-completion/SKILL.md +53 -0
- package/canonical/skills/verification-before-completion/evals/cases.yaml +107 -0
- package/dist/adapters/content/language-lint.d.ts +46 -0
- package/dist/adapters/content/language-lint.js +191 -0
- package/dist/adapters/harness/claude-code.d.ts +57 -0
- package/dist/adapters/harness/claude-code.js +385 -0
- package/dist/adapters/harness/index.d.ts +3 -0
- package/dist/adapters/harness/index.js +17 -0
- package/dist/adapters/harness/opencode.d.ts +7 -0
- package/dist/adapters/harness/opencode.js +166 -0
- package/dist/adapters/harness/plugin.d.ts +22 -0
- package/dist/adapters/harness/plugin.js +257 -0
- package/dist/adapters/memory/doctor.d.ts +480 -0
- package/dist/adapters/memory/doctor.js +1217 -0
- package/dist/adapters/memory/vendored.d.ts +150 -0
- package/dist/adapters/memory/vendored.js +487 -0
- package/dist/adapters/package/node.d.ts +9 -0
- package/dist/adapters/package/node.js +20 -0
- package/dist/adapters/prompt/readline.d.ts +19 -0
- package/dist/adapters/prompt/readline.js +53 -0
- package/dist/adapters/sync/diff.d.ts +43 -0
- package/dist/adapters/sync/diff.js +380 -0
- package/dist/cli/cleanup.d.ts +86 -0
- package/dist/cli/cleanup.js +382 -0
- package/dist/cli/cost.d.ts +304 -0
- package/dist/cli/cost.js +501 -0
- package/dist/cli/doctor.d.ts +205 -0
- package/dist/cli/doctor.js +654 -0
- package/dist/cli/executor.d.ts +5 -0
- package/dist/cli/executor.js +48 -0
- package/dist/cli/plugin-validate.d.ts +37 -0
- package/dist/cli/plugin-validate.js +256 -0
- package/dist/cli/prefix.d.ts +68 -0
- package/dist/cli/prefix.js +218 -0
- package/dist/cli/profile.d.ts +170 -0
- package/dist/cli/profile.js +285 -0
- package/dist/cli/runner.d.ts +10 -0
- package/dist/cli/runner.js +27 -0
- package/dist/cli/uninstall.d.ts +65 -0
- package/dist/cli/uninstall.js +147 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +989 -0
- package/dist/infra/dogfood.d.ts +31 -0
- package/dist/infra/dogfood.js +51 -0
- package/dist/infra/fsutil.d.ts +40 -0
- package/dist/infra/fsutil.js +143 -0
- package/dist/infra/manifest.d.ts +76 -0
- package/dist/infra/manifest.js +92 -0
- package/dist/infra/paths.d.ts +19 -0
- package/dist/infra/paths.js +74 -0
- package/dist/infra/routing.d.ts +4 -0
- package/dist/infra/routing.js +7 -0
- package/node_modules/@freeharness/core/dist/context.d.ts +30 -0
- package/node_modules/@freeharness/core/dist/context.js +1 -0
- package/node_modules/@freeharness/core/dist/index.d.ts +5 -0
- package/node_modules/@freeharness/core/dist/index.js +6 -0
- package/node_modules/@freeharness/core/dist/planner.d.ts +13 -0
- package/node_modules/@freeharness/core/dist/planner.js +18 -0
- package/node_modules/@freeharness/core/dist/ports.d.ts +90 -0
- package/node_modules/@freeharness/core/dist/ports.js +1 -0
- package/node_modules/@freeharness/core/dist/registry.d.ts +41 -0
- package/node_modules/@freeharness/core/dist/registry.js +124 -0
- package/node_modules/@freeharness/core/dist/tiers.d.ts +30 -0
- package/node_modules/@freeharness/core/dist/tiers.js +99 -0
- package/node_modules/@freeharness/core/package.json +34 -0
- package/node_modules/@freeharness/sdd/PROVENANCE.yaml +175 -0
- package/node_modules/@freeharness/sdd/dist/src/bin/openspec.d.ts +2 -0
- package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +166 -0
- package/node_modules/@freeharness/sdd/dist/src/index.d.ts +14 -0
- package/node_modules/@freeharness/sdd/dist/src/index.js +11 -0
- package/node_modules/@freeharness/sdd/dist/src/init.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/src/init.js +190 -0
- package/node_modules/@freeharness/sdd/dist/src/root-resolver.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/src/root-resolver.js +32 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +81 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +483 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/context.d.ts +4 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/context.js +48 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +57 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +279 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +67 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +460 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +5 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/list.js +95 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/new-change.d.ts +6 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +150 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/schemas.d.ts +4 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/schemas.js +23 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +56 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +140 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/status.js +85 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +6 -0
- package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +229 -0
- package/node_modules/@freeharness/sdd/dist/src/validate-change.d.ts +40 -0
- package/node_modules/@freeharness/sdd/dist/src/validate-change.js +114 -0
- package/node_modules/@freeharness/sdd/dist/src/validate.d.ts +24 -0
- package/node_modules/@freeharness/sdd/dist/src/validate.js +72 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.d.ts +130 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +981 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.d.ts +46 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.js +128 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +26 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +32 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.d.ts +50 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.js +394 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.d.ts +15 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.js +49 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.d.ts +71 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.js +164 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +21 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.d.ts +102 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.js +230 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +18 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +138 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.d.ts +82 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.js +333 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.js +110 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.d.ts +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.js +32 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.d.ts +33 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +149 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +49 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.js +31 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.d.ts +10 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.js +10 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.js +26 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.d.ts +28 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.js +41 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.d.ts +23 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.js +25 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.d.ts +72 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.js +76 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.js +53 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.d.ts +62 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.js +7 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.d.ts +35 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.js +47 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.d.ts +33 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.js +55 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.d.ts +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.js +11 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.d.ts +48 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.js +99 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.d.ts +19 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.js +18 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.d.ts +18 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.js +4 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.d.ts +19 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +207 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +409 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.js +673 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.js +230 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +550 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.js +107 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.js +228 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.js +147 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.js +571 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +322 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.d.ts +7 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.js +7 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +518 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +176 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.d.ts +9 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.js +344 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +54 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.d.ts +35 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.js +171 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +27 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +210 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.d.ts +14 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.js +48 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.d.ts +22 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +186 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +65 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +409 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +55 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +98 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.d.ts +8 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +77 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.d.ts +44 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +116 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.d.ts +12 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.js +17 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.d.ts +72 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.js +30 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.d.ts +3 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.js +3 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.d.ts +17 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.js +14 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +39 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +114 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +45 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +105 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.d.ts +15 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.js +56 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.d.ts +17 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.js +1 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +94 -0
- package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +756 -0
- package/node_modules/@freeharness/sdd/package.json +57 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/LICENSE.upstream +22 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +232 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/README.md +19 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +187 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +181 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +338 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +117 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +342 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +116 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +76 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +560 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +162 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +261 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +90 -0
- package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +174 -0
- package/package.json +70 -0
- package/provenance/canonical.PROVENANCE.yaml +740 -0
- package/provenance/claude-mem.LICENSE.upstream +202 -0
- package/provenance/memory.PROVENANCE.yaml +399 -0
- package/provenance/sdd.PROVENANCE.yaml +175 -0
- package/vendor-licenses/caveman.LICENSE +27 -0
- package/vendor-licenses/deepseek-harness.LICENSE +21 -0
- package/vendor-licenses/ecc.LICENSE +21 -0
- package/vendor-licenses/pi.LICENSE +21 -0
- package/vendor-licenses/superpowers.LICENSE +21 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* theme-claro.js — "Claro" theme library for docx reports (docx-js).
|
|
4
|
+
*
|
|
5
|
+
* House typography, applied by the helpers: two fonts only (Arial prose, Consolas
|
|
6
|
+
* code); justified body at 1.15 line spacing with widow/orphan control; headings
|
|
7
|
+
* keep with the next paragraph; table rows never split and short tables, code
|
|
8
|
+
* blocks and callouts stay on one page. Usage and API: reference/HELPERS.md.
|
|
9
|
+
* Requires: npm i docx image-size
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require("fs");
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const {
|
|
15
|
+
Document, Paragraph, TextRun, Table, TableRow, TableCell,
|
|
16
|
+
Header, Footer, AlignmentType, BorderStyle, WidthType, ShadingType,
|
|
17
|
+
VerticalAlign, PageNumber, ImageRun, PageBreak,
|
|
18
|
+
} = require("docx");
|
|
19
|
+
|
|
20
|
+
// ---- DESIGN TOKENS ----
|
|
21
|
+
const FONT = "Arial";
|
|
22
|
+
const MONO = "Consolas";
|
|
23
|
+
// Claro institutional palette (aligned with theme_claro_pptx.py). Red anchors,
|
|
24
|
+
// gray hierarchy, red table headers with white text.
|
|
25
|
+
const C = {
|
|
26
|
+
title: "B8000D", subtitle: "333333", h1: "B8000D", h2: "333333", h3: "666666",
|
|
27
|
+
accent: "E2000F", muted: "666666", body: "333333",
|
|
28
|
+
red: "E2000F", deepRed: "B8000D", green: "2E7D32", amber: "B36B00",
|
|
29
|
+
tblHeadFill: "B8000D", tblHeadText: "FFFFFF", tblBorder: "E5D3D3",
|
|
30
|
+
zebra: "F7F1F1", white: "FFFFFF",
|
|
31
|
+
noteFill: "FFF2CC", dangerFill: "FFE0E0", successFill: "E2EFDA", infoFill: "FBEDED",
|
|
32
|
+
rule: "E2000F", codeFill: "F5F5F5", codeText: "1F1F1F", codeBar: "555555",
|
|
33
|
+
};
|
|
34
|
+
// A4 portrait. Geometry per layout (DXA): "report" is the classic page (2 cm all
|
|
35
|
+
// round); "compact" is the release page — 1 cm lateral margins, tight top/bottom,
|
|
36
|
+
// header and footer close to the page edge. Blocks (tables, code, callouts,
|
|
37
|
+
// images) span exactly the text width and are centered, so their edges meet the
|
|
38
|
+
// justified text. Select the layout with T.configure({ layout }) BEFORE building
|
|
39
|
+
// blocks: the usable width depends on it.
|
|
40
|
+
const PAGE = { width: 11906, height: 16838, margin: 1134, header: 708, footer: 708 };
|
|
41
|
+
const LAYOUTS = {
|
|
42
|
+
report: { top: 1134, bottom: 1134, left: 1134, right: 1134, header: 708, footer: 708 },
|
|
43
|
+
compact: { top: 767, bottom: 586, left: 567, right: 567, header: 177, footer: 162 },
|
|
44
|
+
};
|
|
45
|
+
const CONTENT_W = 9640; // legacy constant (report layout); prefer contentWidth()
|
|
46
|
+
const EMU_PER_PX = 9525;
|
|
47
|
+
// Font sizes in half-points: body 11 pt, code 9 pt, table cell 10 pt, cell code 8.5 pt.
|
|
48
|
+
const SZ = { body: 22, mono: 18, cell: 20, cellMono: 17 };
|
|
49
|
+
// Claro logo asset (transparent PNG), resolved relative to this file.
|
|
50
|
+
const LOGO_PATH = path.join(__dirname, "assets", "claro-logo.png");
|
|
51
|
+
|
|
52
|
+
// Mutable house defaults; T.configure({ justify: false }) opts out for a build.
|
|
53
|
+
// Justified text needs automatic hyphenation to avoid rivers of white space.
|
|
54
|
+
const DEFAULTS = { justify: true, hyphenate: true, line: 276, lang: "pt-BR", layout: "report", page: {} };
|
|
55
|
+
/** Override the house defaults (layout, page overrides, justify, hyphenate, line, lang) for the current build. */
|
|
56
|
+
function configure(o = {}) { Object.assign(DEFAULTS, o); }
|
|
57
|
+
/** Page geometry of the configured layout, with DEFAULTS.page overrides applied. */
|
|
58
|
+
const geometry = () => ({ ...(LAYOUTS[DEFAULTS.layout] || LAYOUTS.report), ...DEFAULTS.page });
|
|
59
|
+
/** Usable text width (DXA) for the configured layout. */
|
|
60
|
+
const contentWidth = () => { const g = geometry(); return PAGE.width - g.left - g.right; };
|
|
61
|
+
/** Scale column widths so they sum to the usable width (keeps old 9640-based tables aligned). */
|
|
62
|
+
function fitCols(cols) {
|
|
63
|
+
const W = contentWidth(), sum = cols.reduce((a, b) => a + b, 0);
|
|
64
|
+
if (!sum || sum === W) return cols;
|
|
65
|
+
const out = cols.map((c) => Math.floor(c * W / sum));
|
|
66
|
+
out[out.length - 1] += W - out.reduce((a, b) => a + b, 0);
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
const jc = () => (DEFAULTS.justify ? AlignmentType.JUSTIFIED : undefined);
|
|
70
|
+
|
|
71
|
+
/** ImageRun of the Claro logo at a pixel height; null when the asset is missing. */
|
|
72
|
+
function logoRun({ height = 28 } = {}) {
|
|
73
|
+
if (!fs.existsSync(LOGO_PATH)) return null;
|
|
74
|
+
const data = fs.readFileSync(LOGO_PATH);
|
|
75
|
+
let w = height;
|
|
76
|
+
try {
|
|
77
|
+
const s = require("image-size");
|
|
78
|
+
const d = s.imageSize ? s.imageSize(data) : s(data);
|
|
79
|
+
w = Math.round(height * d.width / d.height);
|
|
80
|
+
} catch (e) { w = Math.round(height * 543 / 490); }
|
|
81
|
+
return new ImageRun({ type: "png", data, transformation: { width: w, height } });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ---- RUNS ----
|
|
85
|
+
/** Body TextRun (Arial); o = extra TextRun options. */
|
|
86
|
+
const t = (text, o = {}) => new TextRun({ text, font: FONT, ...o });
|
|
87
|
+
/** Monospaced (Consolas) run for commands/identifiers; sz in half-points. */
|
|
88
|
+
const mono = (text, sz = SZ.mono) => new TextRun({ text, font: MONO, size: sz, color: C.codeText });
|
|
89
|
+
/** Bold colored label run that opens a callout or paragraph. */
|
|
90
|
+
const cap = (label, color = C.accent) => t(label + " ", { size: SZ.cell, bold: true, color });
|
|
91
|
+
|
|
92
|
+
/** Markdown-lite inline parser: `code` -> mono run, **bold** (may wrap code), *italic*; the rest is body text. */
|
|
93
|
+
function rich(text, { size = SZ.body, monoSize = SZ.mono, color = C.body } = {}) {
|
|
94
|
+
const runs = [];
|
|
95
|
+
const emit = (seg, bold) => {
|
|
96
|
+
for (const part of seg.split(/(`[^`]+`)/g)) {
|
|
97
|
+
if (!part) continue;
|
|
98
|
+
if (part.length >= 2 && part.startsWith("`") && part.endsWith("`")) { runs.push(new TextRun({ text: part.slice(1, -1), font: MONO, size: monoSize, color: C.codeText, bold })); continue; }
|
|
99
|
+
for (const it of part.split(/(\*[^*\s][^*]*\*)/g)) {
|
|
100
|
+
if (!it) continue;
|
|
101
|
+
if (it.length >= 3 && it.startsWith("*") && it.endsWith("*")) runs.push(t(it.slice(1, -1), { size, italics: true, bold, color }));
|
|
102
|
+
else runs.push(t(it, { size, bold, color }));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
for (const b of String(text).split(/(\*\*[^*]+(?:\*(?!\*)[^*]*)*\*\*)/g)) {
|
|
107
|
+
if (!b) continue;
|
|
108
|
+
if (b.length >= 4 && b.startsWith("**") && b.endsWith("**")) emit(b.slice(2, -2), true);
|
|
109
|
+
else emit(b, false);
|
|
110
|
+
}
|
|
111
|
+
return runs;
|
|
112
|
+
}
|
|
113
|
+
/** rich() at table-cell sizes (10 pt / 8.5 pt mono). */
|
|
114
|
+
const rc = (text) => rich(text, { size: SZ.cell, monoSize: SZ.cellMono });
|
|
115
|
+
|
|
116
|
+
// ---- TEXT BLOCKS ----
|
|
117
|
+
const asRuns = (runs, size = SZ.body) => (Array.isArray(runs) ? runs : [t(runs, { size, color: C.body })]);
|
|
118
|
+
|
|
119
|
+
/** Body paragraph (justified, 1.15). o = Paragraph options plus `before` (DXA), e.g. { keepNext: true } before a code block. */
|
|
120
|
+
function body(runs, { before, ...o } = {}) {
|
|
121
|
+
return new Paragraph({ alignment: jc(), spacing: { before, after: 120, line: DEFAULTS.line }, children: asRuns(runs), ...o });
|
|
122
|
+
}
|
|
123
|
+
/** body() over rich() text. */
|
|
124
|
+
const p = (text, o = {}) => body(rich(text), o);
|
|
125
|
+
|
|
126
|
+
const heading = (text, { size, color, before, after, o = {} }) => new Paragraph({
|
|
127
|
+
spacing: { before, after, line: DEFAULTS.line }, keepNext: true, keepLines: true,
|
|
128
|
+
children: [t(text, { bold: true, color, size })], ...o,
|
|
129
|
+
});
|
|
130
|
+
/** Heading 1; o e.g. { pageBreakBefore: true }. */
|
|
131
|
+
const h1 = (text, o = {}) => heading(text, { size: 30, color: C.h1, before: 300, after: 120, o: { outlineLevel: 0, ...o } });
|
|
132
|
+
/** Heading 2. */
|
|
133
|
+
const h2 = (text, o = {}) => heading(text, { size: 25, color: C.h2, before: 220, after: 80, o: { outlineLevel: 1, ...o } });
|
|
134
|
+
/** Heading 3. */
|
|
135
|
+
const h3 = (text, o = {}) => heading(text, { size: 23, color: C.h3, before: 160, after: 60, o: { outlineLevel: 2, ...o } });
|
|
136
|
+
/** Italic grey caption (figure/table legend). */
|
|
137
|
+
const caption = (text, opts = {}) => new Paragraph({ spacing: { before: 40, after: 220, line: DEFAULTS.line }, keepLines: true, alignment: opts.center ? AlignmentType.CENTER : undefined, children: [t(text, { italics: true, color: C.muted, size: SZ.cell })] });
|
|
138
|
+
/** Empty paragraph used as vertical space (DXA). */
|
|
139
|
+
const spacer = (after = 120) => new Paragraph({ spacing: { after }, children: [] });
|
|
140
|
+
/** Hard page break. */
|
|
141
|
+
const pageBreak = () => new Paragraph({ children: [new PageBreak()] });
|
|
142
|
+
|
|
143
|
+
/** Bulleted list item; lvl 0 or 1. */
|
|
144
|
+
function bullet(runs, lvl = 0, o = {}) {
|
|
145
|
+
return new Paragraph({ alignment: jc(), numbering: { reference: "bullets", level: lvl }, spacing: { after: 70, line: DEFAULTS.line }, children: asRuns(runs), ...o });
|
|
146
|
+
}
|
|
147
|
+
/** bullet() over rich() text. */
|
|
148
|
+
const li = (text, lvl = 0, o = {}) => bullet(rich(text), lvl, o);
|
|
149
|
+
|
|
150
|
+
/** Numbered list item; each distinct instance restarts at 1 (instance 0 is shared). */
|
|
151
|
+
function numItem(runs, opts = 0, o = {}) {
|
|
152
|
+
const { instance = 0, lvl = 0 } = typeof opts === "number" ? { instance: opts } : opts;
|
|
153
|
+
return new Paragraph({ alignment: jc(), numbering: { reference: "nums", level: lvl, instance }, spacing: { after: 80, line: DEFAULTS.line }, children: asRuns(runs), ...o });
|
|
154
|
+
}
|
|
155
|
+
/** numItem() over rich() text. */
|
|
156
|
+
const num = (text, opts = 0, o = {}) => numItem(rich(text), opts, o);
|
|
157
|
+
/** Whole numbered list (1..n) from rich() strings, as its own instance. */
|
|
158
|
+
const numbered = (items, instance) => items.map((s) => num(s, instance));
|
|
159
|
+
|
|
160
|
+
// ---- TABLES ----
|
|
161
|
+
const cb = { style: BorderStyle.SINGLE, size: 1, color: C.tblBorder };
|
|
162
|
+
const cellBorders = { top: cb, bottom: cb, left: cb, right: cb };
|
|
163
|
+
|
|
164
|
+
/** One table cell; keepNext holds the row with the next one (whole-table keep). */
|
|
165
|
+
function cell(content, { fill, w, align, header = false, valign, keepNext = false } = {}) {
|
|
166
|
+
let kids;
|
|
167
|
+
if (Array.isArray(content) && content[0] instanceof Paragraph) kids = content;
|
|
168
|
+
else {
|
|
169
|
+
const rpr = header ? { bold: true, color: C.tblHeadText, size: SZ.cell } : { size: SZ.cell, color: C.body };
|
|
170
|
+
kids = [new Paragraph({ alignment: align, keepNext, spacing: { line: DEFAULTS.line }, children: typeof content === "string" ? [t(content, rpr)] : content })];
|
|
171
|
+
}
|
|
172
|
+
return new TableCell({
|
|
173
|
+
borders: cellBorders, width: { size: w, type: WidthType.DXA },
|
|
174
|
+
shading: { fill: fill || (header ? C.tblHeadFill : C.white), type: ShadingType.CLEAR },
|
|
175
|
+
margins: { top: 70, bottom: 70, left: 120, right: 120 },
|
|
176
|
+
verticalAlign: valign || VerticalAlign.CENTER, children: kids,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Data table: red header (repeats per page), zebra rows, rows never split; keepTogether defaults to rows <= 12; rich parses string cells. */
|
|
181
|
+
function makeTable(cols, head, rows, { keepTogether, rich: useRich = false } = {}) {
|
|
182
|
+
cols = fitCols(cols);
|
|
183
|
+
const keep = keepTogether === undefined ? rows.length <= 12 : keepTogether;
|
|
184
|
+
const last = rows.length - 1;
|
|
185
|
+
const txt = (s) => (useRich ? rc(s) : [t(s, { size: SZ.cell, color: C.body })]);
|
|
186
|
+
const headRow = new TableRow({ tableHeader: true, cantSplit: true, children: head.map((h, i) => cell(h, { w: cols[i], header: true, keepNext: keep })) });
|
|
187
|
+
const bodyRows = rows.map((r, ri) => new TableRow({
|
|
188
|
+
cantSplit: true,
|
|
189
|
+
children: r.map((cv, ci) => {
|
|
190
|
+
const zebra = ri % 2 === 1 ? C.zebra : C.white;
|
|
191
|
+
const keepNext = keep && ri < last;
|
|
192
|
+
if (cv && typeof cv === "object" && !Array.isArray(cv)) {
|
|
193
|
+
const fill = cv.fill || zebra;
|
|
194
|
+
const runs = typeof cv.runs === "string" ? txt(cv.runs) : cv.runs;
|
|
195
|
+
return cell([new Paragraph({ alignment: cv.align, keepNext, spacing: { line: DEFAULTS.line }, children: runs })], { w: cols[ci], fill, valign: VerticalAlign.TOP });
|
|
196
|
+
}
|
|
197
|
+
return cell(useRich ? txt(cv) : cv, { w: cols[ci], fill: zebra, valign: VerticalAlign.TOP, keepNext });
|
|
198
|
+
}),
|
|
199
|
+
}));
|
|
200
|
+
return new Table({ alignment: AlignmentType.CENTER, width: { size: contentWidth(), type: WidthType.DXA }, columnWidths: cols, borders: cellBorders, rows: [headRow, ...bodyRows] });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Two-column metadata (memo) table: column 1 is a highlighted label, column 2 the value. Always held together on one page. */
|
|
204
|
+
function metaTable(rows, col1 = 2500) {
|
|
205
|
+
const cols = [col1, contentWidth() - col1];
|
|
206
|
+
const last = rows.length - 1;
|
|
207
|
+
return new Table({
|
|
208
|
+
alignment: AlignmentType.CENTER, width: { size: contentWidth(), type: WidthType.DXA }, columnWidths: cols, borders: cellBorders,
|
|
209
|
+
rows: rows.map((r, i) => new TableRow({ cantSplit: true, children: [
|
|
210
|
+
cell(r[0], { w: cols[0], fill: C.tblHeadFill, header: true, keepNext: i < last }),
|
|
211
|
+
cell([new Paragraph({ keepNext: i < last, spacing: { line: DEFAULTS.line }, children: typeof r[1] === "string" ? rc(r[1]) : r[1] })], { w: cols[1], fill: C.white }),
|
|
212
|
+
] })),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ---- CALLOUTS ----
|
|
217
|
+
const CALLOUT_KINDS = {
|
|
218
|
+
info: { fill: C.infoFill, bar: C.accent },
|
|
219
|
+
note: { fill: C.noteFill, bar: C.amber },
|
|
220
|
+
danger: { fill: C.dangerFill, bar: C.red },
|
|
221
|
+
success: { fill: C.successFill, bar: C.green },
|
|
222
|
+
};
|
|
223
|
+
/** A callout box: one bordered cell with a colored left bar and tinted fill. The box never splits across pages. */
|
|
224
|
+
function callout(paras, kindOrFill = "info", barColor) {
|
|
225
|
+
let fill, bar;
|
|
226
|
+
if (CALLOUT_KINDS[kindOrFill]) { ({ fill, bar } = CALLOUT_KINDS[kindOrFill]); }
|
|
227
|
+
else { fill = kindOrFill; bar = barColor || C.rule; }
|
|
228
|
+
const arr = typeof paras === "string" ? [p(paras, { spacing: { after: 0, line: DEFAULTS.line } })] : Array.isArray(paras) ? paras : [paras];
|
|
229
|
+
const W = contentWidth();
|
|
230
|
+
return new Table({
|
|
231
|
+
alignment: AlignmentType.CENTER, width: { size: W, type: WidthType.DXA }, columnWidths: [W], borders: cellBorders,
|
|
232
|
+
rows: [new TableRow({ cantSplit: true, children: [new TableCell({
|
|
233
|
+
borders: { ...cellBorders, left: { style: BorderStyle.SINGLE, size: 18, color: bar } },
|
|
234
|
+
width: { size: W, type: WidthType.DXA },
|
|
235
|
+
shading: { fill, type: ShadingType.CLEAR },
|
|
236
|
+
margins: { top: 120, bottom: 120, left: 200, right: 180 }, children: arr,
|
|
237
|
+
})] })],
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/** One-line "Label: text" callout; text accepts rich() syntax. */
|
|
241
|
+
function calloutLine(label, text, kind = "info", labelColor) {
|
|
242
|
+
const bar = CALLOUT_KINDS[kind] ? CALLOUT_KINDS[kind].bar : C.accent;
|
|
243
|
+
return callout([new Paragraph({ alignment: jc(), spacing: { line: DEFAULTS.line }, children: [cap(label, labelColor || bar), ...rich(text, { size: SZ.cell, monoSize: SZ.cellMono })] })], kind);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ---- CODE / LOG BLOCK ----
|
|
247
|
+
/** Monospaced code/log block with a grey bar, held on one page. */
|
|
248
|
+
function codeBlock(lines) {
|
|
249
|
+
const arr = Array.isArray(lines) ? lines : String(lines).split("\n");
|
|
250
|
+
const W = contentWidth();
|
|
251
|
+
return new Table({
|
|
252
|
+
alignment: AlignmentType.CENTER, width: { size: W, type: WidthType.DXA }, columnWidths: [W], borders: cellBorders,
|
|
253
|
+
rows: [new TableRow({ cantSplit: true, children: [new TableCell({
|
|
254
|
+
borders: { ...cellBorders, left: { style: BorderStyle.SINGLE, size: 18, color: C.codeBar } },
|
|
255
|
+
width: { size: W, type: WidthType.DXA },
|
|
256
|
+
shading: { fill: C.codeFill, type: ShadingType.CLEAR },
|
|
257
|
+
margins: { top: 100, bottom: 100, left: 160, right: 140 },
|
|
258
|
+
children: arr.map((ln, i) => new Paragraph({
|
|
259
|
+
keepNext: i < arr.length - 1, keepLines: true,
|
|
260
|
+
spacing: { after: i === arr.length - 1 ? 0 : 20, line: 240 },
|
|
261
|
+
children: [mono(ln.length ? ln : " ", SZ.cellMono)],
|
|
262
|
+
})),
|
|
263
|
+
})] })],
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ---- STAT CARDS ----
|
|
268
|
+
/** Row of equal-width stat cards: big number over a small label. */
|
|
269
|
+
function statCards(cards) {
|
|
270
|
+
const W = contentWidth();
|
|
271
|
+
const w = Math.floor(W / cards.length);
|
|
272
|
+
return new Table({
|
|
273
|
+
alignment: AlignmentType.CENTER, width: { size: W, type: WidthType.DXA }, columnWidths: cards.map(() => w), borders: cellBorders,
|
|
274
|
+
rows: [new TableRow({ cantSplit: true, children: cards.map((c) => new TableCell({
|
|
275
|
+
borders: cellBorders, width: { size: w, type: WidthType.DXA },
|
|
276
|
+
shading: { fill: c.fill || C.infoFill, type: ShadingType.CLEAR },
|
|
277
|
+
margins: { top: 120, bottom: 120, left: 90, right: 90 }, verticalAlign: VerticalAlign.CENTER,
|
|
278
|
+
children: [
|
|
279
|
+
new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 20 }, children: [t(c.value, { bold: true, size: 32, color: c.color || C.title })] }),
|
|
280
|
+
new Paragraph({ alignment: AlignmentType.CENTER, children: [t(c.label, { size: 15, color: C.muted })] }),
|
|
281
|
+
],
|
|
282
|
+
})) })],
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ---- IMAGES / DIAGRAMS ----
|
|
287
|
+
/** Centered PNG scaled to fit the text width and ~half a page height; keepNext glues it to its caption. */
|
|
288
|
+
function image(filePath, maxWidthEmu, { keepNext = true, maxHeightEmu } = {}) {
|
|
289
|
+
if (!maxWidthEmu) maxWidthEmu = contentWidth() * 635; // full text width
|
|
290
|
+
const g = geometry();
|
|
291
|
+
if (!maxHeightEmu) maxHeightEmu = Math.round((PAGE.height - g.top - g.bottom) * 635 * 0.55); // never taller than ~half a page
|
|
292
|
+
const data = fs.readFileSync(filePath);
|
|
293
|
+
let width, height;
|
|
294
|
+
try {
|
|
295
|
+
const sizeOf = require("image-size");
|
|
296
|
+
const dim = sizeOf.imageSize ? sizeOf.imageSize(data) : sizeOf(data);
|
|
297
|
+
width = dim.width; height = dim.height;
|
|
298
|
+
} catch (e) {
|
|
299
|
+
width = 1600; height = 900; // reasonable fallback when image-size is missing
|
|
300
|
+
}
|
|
301
|
+
const wEmu = width * EMU_PER_PX, hEmu = height * EMU_PER_PX;
|
|
302
|
+
const scale = Math.min(1, maxWidthEmu / wEmu, maxHeightEmu / hEmu);
|
|
303
|
+
return new Paragraph({
|
|
304
|
+
spacing: { before: 120, after: 60 }, alignment: AlignmentType.CENTER, keepNext,
|
|
305
|
+
children: [new ImageRun({ type: "png", data, transformation: { width: Math.round(wEmu / EMU_PER_PX * scale), height: Math.round(hEmu / EMU_PER_PX * scale) } })],
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ---- COVER ----
|
|
310
|
+
/** Build the cover page block (centered logo, title, subtitle, tagline, org, meta lines). Falls back to a spacer when the logo asset is missing. */
|
|
311
|
+
function coverBlock({ title, subtitle, tagline, org, metaLines = [], rule = true }) {
|
|
312
|
+
const out = [spacer(40)];
|
|
313
|
+
const lr = logoRun({ height: 96 });
|
|
314
|
+
if (lr) out.push(new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 200 }, children: [lr] }));
|
|
315
|
+
else out.push(spacer(60));
|
|
316
|
+
out.push(spacer(40));
|
|
317
|
+
out.push(new Paragraph({ spacing: { after: 120 }, alignment: AlignmentType.CENTER, children: [t(title, { bold: true, color: C.title, size: 44 })] }));
|
|
318
|
+
if (subtitle) out.push(new Paragraph({ spacing: { after: 80 }, alignment: AlignmentType.CENTER, children: [t(subtitle, { color: C.subtitle, size: 30 })] }));
|
|
319
|
+
if (tagline) out.push(new Paragraph({ spacing: { after: 60 }, alignment: AlignmentType.CENTER, children: [t(tagline, { italics: true, color: C.muted, size: 24 })] }));
|
|
320
|
+
if (org) out.push(new Paragraph({ spacing: { after: 400 }, alignment: AlignmentType.CENTER, children: [t(org, { color: C.muted, size: SZ.body })] }));
|
|
321
|
+
if (rule) out.push(new Paragraph({ spacing: { after: 200 }, border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: C.rule, space: 1 } }, children: [] }));
|
|
322
|
+
metaLines.forEach((s) => out.push(new Paragraph({ spacing: { after: 60 }, alignment: AlignmentType.CENTER, children: [t(s, { italics: true, color: C.muted, size: SZ.cell })] })));
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ---- AUTHORSHIP BLOCK ----
|
|
327
|
+
/** Authorship block closing the document; heading defaults to "ELABORAÇÃO E ANÁLISE". */
|
|
328
|
+
function authorBlock({ heading: hd = "ELABORAÇÃO E ANÁLISE", name, role, area, project } = {}) {
|
|
329
|
+
const out = [];
|
|
330
|
+
const line = (text, o) => new Paragraph({ alignment: AlignmentType.CENTER, keepNext: true, keepLines: true, spacing: o.spacing, children: [t(text, o.run)] });
|
|
331
|
+
out.push(spacer(240));
|
|
332
|
+
out.push(new Paragraph({ keepNext: true, spacing: { before: 160, after: 120 }, border: { top: { style: BorderStyle.SINGLE, size: 6, color: C.rule, space: 1 } }, children: [] }));
|
|
333
|
+
out.push(line(hd, { spacing: { after: 60 }, run: { bold: true, color: C.h1, size: SZ.cell } }));
|
|
334
|
+
if (name) out.push(line(name, { spacing: { after: 30 }, run: { bold: true, size: 26, color: C.subtitle } }));
|
|
335
|
+
if (role) out.push(line(role, { spacing: { after: 20 }, run: { size: SZ.body, color: C.body } }));
|
|
336
|
+
if (area) out.push(line(area, { spacing: { after: 20 }, run: { size: SZ.cell, color: C.muted } }));
|
|
337
|
+
if (project) out.push(line(project, { spacing: { after: 0 }, run: { size: SZ.cell, color: C.muted } }));
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ---- DOCUMENT ----
|
|
342
|
+
/** Final Document: A4, header/footer, lists, house defaults; layout "report" | "compact", page = DXA overrides. */
|
|
343
|
+
function buildDocument({ children, headerText = "", footerAuthor = "", footerNote = "Confidencial – Uso Interno", layout, page, updateFields = false }) {
|
|
344
|
+
if ((layout && layout !== DEFAULTS.layout) || page) {
|
|
345
|
+
console.warn("theme-claro: pass layout/page to T.configure() before building blocks; buildDocument() applies them to the page only");
|
|
346
|
+
configure({ layout: layout || DEFAULTS.layout, page: page || DEFAULTS.page });
|
|
347
|
+
}
|
|
348
|
+
const geo = geometry();
|
|
349
|
+
const W = contentWidth();
|
|
350
|
+
const hLogo = logoRun({ height: 24 });
|
|
351
|
+
const headerChildren = [t(headerText, { italics: true, color: C.muted, size: 18 })];
|
|
352
|
+
if (hLogo) headerChildren.push(t("\t", { size: 18 }), hLogo);
|
|
353
|
+
const header = new Header({ children: [new Paragraph({
|
|
354
|
+
spacing: { after: 100 }, border: { bottom: { style: BorderStyle.SINGLE, size: 3, color: C.tblBorder, space: 1 } },
|
|
355
|
+
tabStops: [{ type: "right", position: W }],
|
|
356
|
+
children: headerChildren,
|
|
357
|
+
})] });
|
|
358
|
+
const footer = new Footer({ children: [new Paragraph({
|
|
359
|
+
spacing: { before: 100 }, border: { top: { style: BorderStyle.SINGLE, size: 3, color: C.tblBorder, space: 1 } },
|
|
360
|
+
tabStops: [{ type: "right", position: W }],
|
|
361
|
+
children: [
|
|
362
|
+
t(footerAuthor, { color: C.muted, size: 18 }),
|
|
363
|
+
t(`\t${footerNote} | Página `, { color: C.muted, size: 18 }),
|
|
364
|
+
new TextRun({ children: [PageNumber.CURRENT], font: FONT, color: C.muted, size: 18 }),
|
|
365
|
+
t(" de ", { color: C.muted, size: 18 }),
|
|
366
|
+
new TextRun({ children: [PageNumber.TOTAL_PAGES], font: FONT, color: C.muted, size: 18 }),
|
|
367
|
+
],
|
|
368
|
+
})] });
|
|
369
|
+
|
|
370
|
+
return new Document({
|
|
371
|
+
features: { updateFields }, // true when a TOC field must refresh on open
|
|
372
|
+
hyphenation: { autoHyphenation: DEFAULTS.hyphenate, doNotHyphenateCaps: true, consecutiveHyphenLimit: 2 },
|
|
373
|
+
styles: { default: { document: {
|
|
374
|
+
run: { font: FONT, size: SZ.body, color: C.body, language: { value: DEFAULTS.lang } },
|
|
375
|
+
paragraph: { spacing: { line: DEFAULTS.line }, widowControl: true },
|
|
376
|
+
} } },
|
|
377
|
+
numbering: { config: [
|
|
378
|
+
{ reference: "bullets", levels: [{ level: 0, format: "bullet", text: "•", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 540, hanging: 280 } } } },
|
|
379
|
+
{ level: 1, format: "bullet", text: "◦", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 1080, hanging: 280 } } } }] },
|
|
380
|
+
{ reference: "nums", levels: [{ level: 0, format: "decimal", text: "%1.", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 540, hanging: 320 } } } },
|
|
381
|
+
{ level: 1, format: "lowerLetter", text: "%2)", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 1080, hanging: 320 } } } }] },
|
|
382
|
+
] },
|
|
383
|
+
sections: [{
|
|
384
|
+
properties: { page: { size: { width: PAGE.width, height: PAGE.height }, margin: { top: geo.top, right: geo.right, bottom: geo.bottom, left: geo.left, header: geo.header, footer: geo.footer } } },
|
|
385
|
+
headers: { default: header }, footers: { default: footer }, children,
|
|
386
|
+
}],
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
module.exports = {
|
|
391
|
+
// tokens
|
|
392
|
+
C, FONT, MONO, SZ, CONTENT_W, PAGE, LAYOUTS, DEFAULTS, configure, contentWidth, geometry, fitCols,
|
|
393
|
+
// runs
|
|
394
|
+
t, mono, cap, rich, rc,
|
|
395
|
+
// blocks
|
|
396
|
+
body, p, h1, h2, h3, caption, spacer, pageBreak, bullet, li, numItem, num, numbered,
|
|
397
|
+
// tables
|
|
398
|
+
makeTable, metaTable, cell,
|
|
399
|
+
// highlights
|
|
400
|
+
callout, calloutLine, codeBlock, statCards,
|
|
401
|
+
// media / structure
|
|
402
|
+
image, logoRun, coverBlock, authorBlock, buildDocument, LOGO_PATH,
|
|
403
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: subagent-driven-development
|
|
3
|
+
description: Use when executing an approved tasks.md from an OpenSpec change: one brief per task under .freeharness/sdd/<change>/, a fresh implementer per dispatch with an explicit tier and a disjoint write scope, a JSON handoff, the lead's own test run and diff review, one combined task reviewer, a 5-round circuit breaker and one final branch review via code-review. Not for ad-hoc one-file edits.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Subagent-Driven Development Protocol
|
|
7
|
+
|
|
8
|
+
<orchestrator_directive>
|
|
9
|
+
The primary session is the lead: it dispatches, evaluates and rules; it never writes production code while executing `tasks.md`. A feature starts at `/opsx:propose`; this skill runs the approved `tasks.md` after `/opsx:apply`. Continuous execution: no "should I continue?" between tasks; the stop conditions below are the only pauses.
|
|
10
|
+
</orchestrator_directive>
|
|
11
|
+
|
|
12
|
+
<workspace>
|
|
13
|
+
- Artifacts live in `.freeharness/sdd/<change>/` (gitignored; `init --project` creates it): `<task>.brief.md` and `<task>.review.md`. Files survive compaction; after compaction trust the review packages, `tasks.md` checkboxes and `git log`, never recollection.
|
|
14
|
+
- Templates: `reference/brief.md`, `reference/handoff.md`. The validator `scripts/validate-handoff.mjs` has six subcommands: `briefs <dir|file...>` (header lines, Spec = change id, digest budget, write-scope overlap), `handoff <file> [--base <sha>] [--brief <brief.md>] [--in-flight <brief.md>...] [--lead <path>...]` (schema plus the diff guards; `--lead` excludes the lead's own paths), `budget <ledger.jsonl> <task> [--ceiling <n>]`, `ledger <change-dir>`, `recover <transcript.jsonl> <report> [--force]` and `name <dispatch-name>` (checks a dispatch name and prints the corrected form).
|
|
15
|
+
- Worker rules, restated in every brief: never `git stash`, `git checkout --` or `git reset` in the shared working tree (prove RED by writing the tests first or against a temp copy), and never dispatch a subagent.
|
|
16
|
+
- Before task 1: read `tasks.md` once, list the tasks, note Global Constraints; scan pairs of tasks that share a file or an interface and rule on conflicts (spec is the authority) in a `## Preflight` note of the first review package.
|
|
17
|
+
</workspace>
|
|
18
|
+
|
|
19
|
+
<dispatch>
|
|
20
|
+
1. Brief: write `<task>.brief.md` (template). Header `Spec:` is the OpenSpec change id, never a copied spec; `Tier:` is explicit on every dispatch (fast for transcription of complete plan text or one-file mechanical edits, standard for multi-file integration, strong for design judgment; an omitted tier silently inherits the session model). Write scope names every file the worker may touch.
|
|
21
|
+
2. Disjoint write scopes: run `validate-handoff.mjs briefs` over the batch; any overlap refuses the whole batch naming the file. Two implementers never run in parallel on intersecting scopes.
|
|
22
|
+
3. Batch small same-shape tasks (the same one-line edit or field across files) into one brief and one dispatch; work that needs its own tests, judgment or review surface gets its own dispatch.
|
|
23
|
+
4. Dispatch a fresh implementer with the brief path, the report path and the interfaces earlier tasks produced; nothing from the session history. The implementer follows `test-driven-development`; dispatch `test-writer` for the RED step when the failing tests are non-trivial. Record `Base:` (`git rev-parse HEAD`) before dispatching.
|
|
24
|
+
5. At most 3 implementers in flight; a fix-round resumption counts as one. The fourth task waits for a slot; more than three needs a user ask recorded in the review package.
|
|
25
|
+
6. Dispatch names follow `<role>-<task>[-r<round>][-<slug>]`: `impl-2_3`, `fix-2_3-r2`, `impl-1_3b` (a batch), `review-final-r1` (the final review) and `review-final-r1-security` (one of that round's parallel reviewers, the slug naming its lens). Write `_` for `.` because the Agent tool rejects a dot in a name; the ledger stores the dotted id and reads role, task and round through the slug. The lens slug is lowercase letters, digits and hyphens (`review-final-r1-lenses-b`); any other character leaves role and task null in the ledger. Before every dispatch, run `validate-handoff.mjs name <dispatch-name>` and use the printed corrected form.
|
|
26
|
+
7. Budget: run `validate-handoff.mjs budget <ledger.jsonl> <task>` before every dispatch of a task, and again when its handoff is accepted; the brief's `Ceiling:` header overrides the default of 25,000,000 cache-read tokens for that task.
|
|
27
|
+
8. Rewrite the brief's `## Why and rulings` digest before every re-dispatch (a fix round, a re-brief after `partial` or `blocked`) so it still matches the current decisions; a deviation the handoff does not cite is a reviewer P0 tagged `why-digest`.
|
|
28
|
+
9. No nested subagents: a worker never dispatches helpers or reviewers; a worker-spawned reviewer is a defect, not rigor.
|
|
29
|
+
</dispatch>
|
|
30
|
+
|
|
31
|
+
<handoff>
|
|
32
|
+
The worker returns only the JSON block (schema in `reference/handoff.md`): `task`, `status: completed|partial|blocked`, `files_changed`, `tests_run` (command, result, summary), `evidence` (one line per Verify item), `partial_output` (label of what is missing; required when partial), `blocked_reason` (stop token then detail; required when blocked), `concerns`. Stop tokens end the dispatch at the first one: `too-big`, `needs-confirm`, `ambiguous`, `regressed`, `scope`. Handle: `partial` -> re-dispatch with the label as the task; `blocked` -> fix the cause (context, tier, split, ruling) and re-dispatch; never re-run the same dispatch unchanged.
|
|
33
|
+
On a missing, empty or block-less reply the first step is `validate-handoff.mjs recover <transcript.jsonl> <report>` over `~/.claude/projects/<project>/<session>/subagents/agent-<id>.jsonl`, never a re-dispatch: it rebuilds the handoff from the last assistant-authored json block and writes it as the head of the review package.
|
|
34
|
+
</handoff>
|
|
35
|
+
|
|
36
|
+
<acceptance>
|
|
37
|
+
- Worker reports are not acceptance. The lead reviews the final diff (`git diff <base>..HEAD`) and runs the Verify commands itself, then appends `## Lead evaluation` to the review package with the commands and their summary lines. A task with only the worker's claim is never marked done.
|
|
38
|
+
- Guards before the reviewer: run `validate-handoff.mjs handoff <report> --base <Base> --brief <brief.md>`, adding `--in-flight <brief.md>` for every other brief still running so a peer's files are not charged to this worker, and `--lead <path>` for the lead's own paths (the change's `tasks.md`, any review package outside `.freeharness/`) so they are not charged either; a `claimed-unchanged`, `changed-unclaimed`, `scope`, `peer-scope` or `lead-path` failure returns to the worker as findings (a round), never straight to the reviewer; `peer-scope` means the worker claimed a file another dispatch owns, `lead-path` means it claimed one of the lead's own paths, neither ever worth passing on.
|
|
39
|
+
- One combined task reviewer per task (spec compliance + code quality in one dispatch, tier explicit) reads the brief, the review package and the diff file; it treats the report as unverified claims. Findings follow the reviewer contract: `path:line: P0|P1|P2: problem. fix.` At most 3 reviewer dispatches per round; a fourth waits for a second round unless a user ask for more is recorded in the review package.
|
|
40
|
+
- No finding suppression: never tell a reviewer what not to flag, never downgrade a finding for a stated rationale, never drop a finding silently; disagreement is a written ruling.
|
|
41
|
+
- `test-driven-development` proof (failing run, then passing run) is part of the evidence; coverage numbers are not.
|
|
42
|
+
</acceptance>
|
|
43
|
+
|
|
44
|
+
<fix_loop>
|
|
45
|
+
- A fix round = one fix dispatch + one scoped re-review of the fix diff only. Rounds 1-3 resume the same implementer with the findings verbatim; rounds 4-5 dispatch a fresh implementer one tier up with the brief, the report and the findings.
|
|
46
|
+
- Circuit breaker: after round 5 with findings still open, stop dispatching. Write `## Controller ruling` to the review package for every open finding (real and load-bearing: smallest unblocking change, carried into the next brief; real and deferred, or contested: parked with the reason and the cost if wrong). Then ask the user before the next task; a structural defect that leaves every path a guess stops the run.
|
|
47
|
+
- Second breaker: the budget ceiling. When `budget` reports `FAIL ceiling reached` for the task, stop dispatching it and write the same `## Controller ruling` as at round 5, one entry per open finding, each ruling carrying an id in the `R:<task>.<n>` form so the next brief's digest can cite it.
|
|
48
|
+
- Every round appends `round <n>/5: <addressed>/<open>` to the review package. The lead never fixes findings itself.
|
|
49
|
+
</fix_loop>
|
|
50
|
+
|
|
51
|
+
<completion>
|
|
52
|
+
- Per task: lead evaluation present, review clean (or rulings written at the cap), `verification-before-completion` evidence recorded, then tick `[x]` in `tasks.md`.
|
|
53
|
+
- After the last task: one final branch review via `code-review` over `git merge-base` to HEAD (domain reviewers + `pr-reviewer`, strong tier), under the same cap of 3 reviewer dispatches per round unless a user ask for more is recorded in the review package; one fix dispatch for the whole findings list, one scoped re-review, rulings for residuals. Then `git-workflow` for commit and PR; `/opsx:archive` when the change is done, with its compound step (retrospective line, telemetry file, rules or skill delta, memory observation).
|
|
54
|
+
- Every deferred item (a parked ruling, a reviewer finding carried forward, a machine-only measurement) is recorded with `openspec follow-up add <change-id> "<text>" --from <task>`, never as prose; archive prints the unclaimed items.
|
|
55
|
+
- Final message lists every ruling made (what, why, cost if wrong) and the `validate-handoff.mjs ledger <change-dir>` summary of dispatches and cache-read spend per task: a ruling that dies in the workspace was a decision made in secret.
|
|
56
|
+
</completion>
|
|
57
|
+
|
|
58
|
+
<stop_conditions>
|
|
59
|
+
Stop and ask the user only for: an irreversible or destructive operation; a security-sensitive action; a side effect outside the worktree (merge, push to a shared branch, publish); a task flagged "Ask first" in the proposal; the circuit breaker; a plan so broken that every path forward is a guess. Everything else is a ruling, written down, and the run continues.
|
|
60
|
+
</stop_conditions>
|