@khoavu882/doflow 0.0.0-stage → 2.0.0-beta.4
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/README.md +132 -2
- package/bin/doflow.js +44 -0
- package/core/.antigravity-plugin/hooks.json +39 -0
- package/core/.antigravity-plugin/mcp_config.json +18 -0
- package/core/.antigravity-plugin/plugin.json +31 -0
- package/core/.claude-plugin/marketplace.json +20 -0
- package/core/.claude-plugin/plugin.json +21 -0
- package/core/.codex-plugin/marketplace.json +20 -0
- package/core/.codex-plugin/plugin.json +35 -0
- package/core/.plugin/plugin.json +19 -0
- package/core/harnesses/antigravity/hooks/pre-implementation-gate.sh +9 -0
- package/core/harnesses/antigravity/hooks/stop-check.sh +10 -0
- package/core/harnesses/claude/hooks/lib.sh +304 -0
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +20 -0
- package/core/harnesses/claude/hooks/permission-audit.sh +47 -0
- package/core/harnesses/claude/hooks/post-compact.sh +74 -0
- package/core/harnesses/claude/hooks/post-edit-lint.sh +36 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +47 -0
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +20 -0
- package/core/harnesses/claude/hooks/pre-compact.sh +43 -0
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +21 -0
- package/core/harnesses/claude/hooks/session-end.sh +89 -0
- package/core/harnesses/claude/hooks/session-start.sh +5 -0
- package/core/harnesses/claude/hooks/skill-config-audit.sh +39 -0
- package/core/harnesses/claude/hooks/stop-check.sh +5 -0
- package/core/harnesses/claude/hooks/subagent-audit.sh +7 -0
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -0
- package/core/harnesses/claude/settings/keybindings.json +20 -0
- package/core/harnesses/claude/settings/settings.json +201 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +49 -0
- package/core/harnesses/codex/agents/core-implementer.toml +7 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +8 -0
- package/core/harnesses/codex/agents/research-writer.toml +8 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +8 -0
- package/core/harnesses/codex/agents/system-architect.toml +9 -0
- package/core/harnesses/codex/config/config.toml +10 -0
- package/core/harnesses/codex/hooks/hooks.json +122 -0
- package/core/harnesses/codex/hooks/lib.sh +335 -0
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +18 -0
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +52 -0
- package/core/harnesses/codex/hooks/post-edit-lint.sh +6 -0
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +18 -0
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +46 -0
- package/core/harnesses/codex/hooks/pre-compact.sh +9 -0
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +19 -0
- package/core/harnesses/codex/hooks/session-end.impl.sh +92 -0
- package/core/harnesses/codex/hooks/session-end.sh +5 -0
- package/core/harnesses/codex/hooks/session-start.sh +5 -0
- package/core/harnesses/codex/hooks/stop-check.sh +8 -0
- package/core/harnesses/codex/hooks/subagent-audit.sh +8 -0
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +6 -0
- package/core/harnesses/gemini/hooks/hooks.json +77 -0
- package/core/harnesses/gemini/hooks/lib.sh +302 -0
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +21 -0
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +39 -0
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +21 -0
- package/core/harnesses/gemini/hooks/pre-compact.sh +38 -0
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +22 -0
- package/core/harnesses/gemini/hooks/session-end.impl.sh +89 -0
- package/core/harnesses/gemini/hooks/session-end.sh +5 -0
- package/core/harnesses/gemini/hooks/session-start.sh +5 -0
- package/core/harnesses/gemini/settings/adapter-defaults.json +4 -0
- package/core/harnesses/kiro/agents/doflow.json +58 -0
- package/core/harnesses/kiro/hooks/doflow.json +53 -0
- package/core/harnesses/kiro/hooks/lib.sh +324 -0
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +9 -0
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +9 -0
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +9 -0
- package/core/harnesses/kiro/hooks/session-start.sh +9 -0
- package/core/harnesses/kiro/hooks/stop-check.sh +43 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +39 -0
- package/core/harnesses/shared/hooks/adapters/antigravity.js +111 -0
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +19 -0
- package/core/harnesses/shared/hooks/adapters/gemini.js +114 -0
- package/core/harnesses/shared/hooks/hooks.json +47 -0
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +91 -0
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +97 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +29 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +501 -0
- package/core/harnesses/shared/hooks/policies/mcp-policy.conf +21 -0
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +91 -0
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +328 -0
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +496 -0
- package/core/harnesses/shared/hooks/policies/prompt-nudge.jq +131 -0
- package/core/harnesses/shared/hooks/policies/session-context.sh +141 -0
- package/core/harnesses/shared/hooks/policies/stop-check.sh +264 -0
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +46 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +235 -0
- package/core/harnesses/shared/hooks/stream-hook-runner.js +590 -0
- package/core/harnesses/shared/locator/doflow-run +87 -0
- package/core/registry/advice.json +101 -0
- package/core/registry/assets.json +792 -0
- package/core/registry/capabilities.json +120 -0
- package/core/registry/contracts.json +189 -0
- package/core/registry/external-tools.json +191 -0
- package/core/registry/harnesses.json +2062 -0
- package/core/registry/lifecycle.json +231 -0
- package/core/registry/mcp.json +18 -0
- package/core/registry/models.json +79 -0
- package/core/registry/readiness-templates.json +118 -0
- package/core/registry/routes.json +47 -0
- package/core/registry/storage.json +1061 -0
- package/core/registry/verification.json +258 -0
- package/core/registry/workflows.json +790 -0
- package/core/shared/agent-specs/core-implementer.md +73 -0
- package/core/shared/agent-specs/quality-guardian.md +28 -0
- package/core/shared/agent-specs/research-writer.md +31 -0
- package/core/shared/agent-specs/spec-analyst.md +33 -0
- package/core/shared/agent-specs/system-architect.md +29 -0
- package/core/shared/guidance/DOFLOW_CORE.md +8 -0
- package/core/shared/guidance/FLAGS.md +25 -0
- package/core/shared/guidance/PRINCIPLES.md +61 -0
- package/core/shared/guidance/VERSION +1 -0
- package/core/shared/guidance/mcp/MCP_Context7.md +18 -0
- package/core/shared/guidance/mcp/MCP_Sequential.md +17 -0
- package/core/shared/guidance/modes/MODE_Brainstorming.md +46 -0
- package/core/shared/guidance/modes/MODE_DeepResearch.md +69 -0
- package/core/shared/guidance/modes/MODE_Introspection.md +33 -0
- package/core/shared/guidance/modes/MODE_Orchestration.md +57 -0
- package/core/shared/guidance/modes/MODE_Task_Management.md +74 -0
- package/core/shared/guidance/pointers/claude-gemini.md +2 -0
- package/core/shared/guidance/pointers/codex.md +6 -0
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +373 -0
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +104 -0
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +47 -0
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +161 -0
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +87 -0
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +93 -0
- package/core/shared/guidance/references/MODEL_SELECTION.md +74 -0
- package/core/shared/guidance/references/ORCHESTRATION.md +36 -0
- package/core/shared/guidance/references/RESEARCH_CONFIG.md +21 -0
- package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +81 -0
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +25 -0
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +23 -0
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +14 -0
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +46 -0
- package/core/shared/scripts/doflow/assets/mermaid-theme.json +46 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +167 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +546 -0
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +208 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +347 -0
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +66 -0
- package/core/shared/scripts/doflow/bash/do-review-package.sh +127 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +698 -0
- package/core/shared/scripts/doflow/bash/render-audit.sh +224 -0
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +177 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +223 -0
- package/core/shared/scripts/doflow/bash/sync-context.sh +66 -0
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +526 -0
- package/core/shared/scripts/doflow/bin/doflow-run +592 -0
- package/core/shared/skills/do/SKILL.md +128 -0
- package/core/shared/skills/do/references/estimation.md +13 -0
- package/core/shared/skills/do/references/pm_routing.md +25 -0
- package/core/shared/skills/do/references/tool_matrix.md +52 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +252 -0
- package/core/shared/skills/do-code-review/README.md +49 -0
- package/core/shared/skills/do-code-review/SKILL.md +333 -0
- package/core/shared/skills/do-code-review/assets/sample_c_clean.c +71 -0
- package/core/shared/skills/do-code-review/assets/sample_c_smells.c +66 -0
- package/core/shared/skills/do-code-review/assets/sample_cpp_shift.cpp +19 -0
- package/core/shared/skills/do-code-review/assets/sample_csharp_clean.cs +100 -0
- package/core/shared/skills/do-code-review/assets/sample_csharp_smells.cs +78 -0
- package/core/shared/skills/do-code-review/assets/sample_java_clean.java +55 -0
- package/core/shared/skills/do-code-review/assets/sample_java_smells.java +56 -0
- package/core/shared/skills/do-code-review/assets/sample_json_clean.json +7 -0
- package/core/shared/skills/do-code-review/assets/sample_markdown_clean.md +30 -0
- package/core/shared/skills/do-code-review/assets/sample_markdown_smells.md +29 -0
- package/core/shared/skills/do-code-review/assets/sample_shell_heredoc.sh +38 -0
- package/core/shared/skills/do-code-review/assets/sample_shell_smells.sh +15 -0
- package/core/shared/skills/do-code-review/assets/sample_typescript_strings.ts +36 -0
- package/core/shared/skills/do-code-review/assets/sample_yaml_smells.yaml +6 -0
- package/core/shared/skills/do-code-review/content-types/config.md +83 -0
- package/core/shared/skills/do-code-review/content-types/markdown.md +132 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_c_clean_quality.json +79 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_c_smells_quality.json +169 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_cpp_shift_quality.json +49 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_clean_quality.json +149 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_smells_quality.json +157 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_java_clean_quality.json +67 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_java_smells_quality.json +97 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_json_clean_quality.json +33 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_clean_quality.json +1 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_smells_quality.json +16 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_shell_heredoc_quality.json +54 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_shell_smells_quality.json +91 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_typescript_strings_quality.json +60 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_yaml_smells_quality.json +46 -0
- package/core/shared/skills/do-code-review/languages/c.md +103 -0
- package/core/shared/skills/do-code-review/languages/cpp.md +103 -0
- package/core/shared/skills/do-code-review/languages/csharp.md +97 -0
- package/core/shared/skills/do-code-review/languages/dart.md +108 -0
- package/core/shared/skills/do-code-review/languages/go.md +92 -0
- package/core/shared/skills/do-code-review/languages/java.md +103 -0
- package/core/shared/skills/do-code-review/languages/kotlin.md +88 -0
- package/core/shared/skills/do-code-review/languages/php.md +109 -0
- package/core/shared/skills/do-code-review/languages/python.md +94 -0
- package/core/shared/skills/do-code-review/languages/ruby.md +105 -0
- package/core/shared/skills/do-code-review/languages/rust.md +99 -0
- package/core/shared/skills/do-code-review/languages/shell.md +90 -0
- package/core/shared/skills/do-code-review/languages/swift.md +88 -0
- package/core/shared/skills/do-code-review/languages/typescript.md +97 -0
- package/core/shared/skills/do-code-review/review-policy.json +47 -0
- package/core/shared/skills/do-code-review/rules/universal.md +49 -0
- package/core/shared/skills/do-code-review/scripts/code_quality_checker.py +1696 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +532 -0
- package/core/shared/skills/do-code-review/scripts/pr_analyzer.py +620 -0
- package/core/shared/skills/do-code-review/scripts/review_report_generator.py +505 -0
- package/core/shared/skills/do-constitution/SKILL.md +72 -0
- package/core/shared/skills/do-design/SKILL.md +212 -0
- package/core/shared/skills/do-diagnose/SKILL.md +156 -0
- package/core/shared/skills/do-diagnose/references/code_audit.md +15 -0
- package/core/shared/skills/do-diagnose/references/refactoring.md +12 -0
- package/core/shared/skills/do-diagnose/references/root_cause.md +17 -0
- package/core/shared/skills/do-document/SKILL.md +81 -0
- package/core/shared/skills/do-document/references/api-reference.md +42 -0
- package/core/shared/skills/do-document/references/deep_research.md +18 -0
- package/core/shared/skills/do-document/references/embedded-research.md +11 -0
- package/core/shared/skills/do-document/references/implementation-flow.md +105 -0
- package/core/shared/skills/do-document/references/index_generator.md +9 -0
- package/core/shared/skills/do-document/references/user-guide.md +22 -0
- package/core/shared/skills/do-execute-plan/SKILL.md +261 -0
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +57 -0
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +92 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +155 -0
- package/core/shared/skills/do-execute-plan/references/run_position.md +63 -0
- package/core/shared/skills/do-execute-plan/references/scaffold.md +441 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +41 -0
- package/core/shared/skills/do-flow/SKILL.md +186 -0
- package/core/shared/skills/do-flow/references/task_classes.md +134 -0
- package/core/shared/skills/do-git/SKILL.md +115 -0
- package/core/shared/skills/do-git/references/hotfix-ritual.md +44 -0
- package/core/shared/skills/do-git/references/lifecycle-policy.md +54 -0
- package/core/shared/skills/do-git/references/release-ritual.md +64 -0
- package/core/shared/skills/do-implement/SKILL.md +222 -0
- package/core/shared/skills/do-plan/SKILL.md +219 -0
- package/core/shared/skills/do-test/SKILL.md +113 -0
- package/core/shared/templates/doflow/constitution-template.md +28 -0
- package/core/shared/templates/doflow/data-model-template.md +169 -0
- package/core/shared/templates/doflow/design-template.md +193 -0
- package/core/shared/templates/doflow/external-contract-template.md +35 -0
- package/core/shared/templates/doflow/intent-template.md +45 -0
- package/core/shared/templates/doflow/plan-template.md +151 -0
- package/core/shared/templates/doflow/question-log-template.md +51 -0
- package/core/shared/templates/doflow/requirement-template.md +126 -0
- package/core/shared/templates/doflow/specs-template.md +55 -0
- package/core/shared/templates/doflow/state-template.md +59 -0
- package/core/shared/workflows/do-flow-chain.md +17 -0
- package/package.json +48 -4
- package/src/adapters/antigravity/index.js +631 -0
- package/src/adapters/claude/index.js +548 -0
- package/src/adapters/claude/mcp.js +94 -0
- package/src/adapters/codex/agents.js +208 -0
- package/src/adapters/codex/config.js +272 -0
- package/src/adapters/codex/hooks.js +203 -0
- package/src/adapters/codex/index.js +707 -0
- package/src/adapters/codex/mcp.js +271 -0
- package/src/adapters/codex/native-projection.js +34 -0
- package/src/adapters/copilot/index.js +413 -0
- package/src/adapters/copy-tree.js +620 -0
- package/src/adapters/gemini/hooks.js +210 -0
- package/src/adapters/gemini/index.js +390 -0
- package/src/adapters/hook-commands.js +60 -0
- package/src/adapters/index.js +106 -0
- package/src/adapters/kiro/index.js +310 -0
- package/src/adapters/mcp-entries.js +331 -0
- package/src/adapters/opencode/index.js +466 -0
- package/src/adapters/pi/index.js +279 -0
- package/src/adapters/pi/json-members.js +185 -0
- package/src/adapters/pi/mcp.js +373 -0
- package/src/adapters/resolve-source.js +19 -0
- package/src/cli/commands/install.js +218 -0
- package/src/cli/commands/list-backups.js +21 -0
- package/src/cli/commands/reconcile.js +120 -0
- package/src/cli/commands/remove.js +82 -0
- package/src/cli/commands/rollback.js +172 -0
- package/src/cli/commands/self-update.js +33 -0
- package/src/cli/commands/status.js +138 -0
- package/src/cli/commands/tools.js +92 -0
- package/src/cli/commands/update.js +162 -0
- package/src/cli/index.js +568 -0
- package/src/cli/runtime-commands.js +281 -0
- package/src/cli/shared.js +218 -0
- package/src/helper/bash-helper.js +34 -0
- package/src/helper/git.js +24 -0
- package/src/helper/guardrails.js +49 -0
- package/src/helper/harness-paths.js +140 -0
- package/src/helper/marker-merge.js +116 -0
- package/src/helper/prompt.js +61 -0
- package/src/helper/repo-root.js +29 -0
- package/src/helper/settings-merge.js +151 -0
- package/src/helper/settings-scope.js +33 -0
- package/src/helper/toml.js +244 -0
- package/src/install/backup-set.js +149 -0
- package/src/install/backup.js +724 -0
- package/src/install/context.js +58 -0
- package/src/install/manifest.js +145 -0
- package/src/install/mcp.js +254 -0
- package/src/install/paths.js +84 -0
- package/src/install/targets.js +90 -0
- package/src/install/tool-lifecycle.js +151 -0
- package/src/lifecycle/bash-availability.js +25 -0
- package/src/lifecycle/index.js +812 -0
- package/src/lifecycle/mcp-index.js +28 -0
- package/src/lifecycle/policies.js +73 -0
- package/src/lifecycle/view.js +175 -0
- package/src/registry/index.js +611 -0
- package/src/release/build-package.js +91 -0
- package/src/release/changelog-section.js +70 -0
- package/src/release/sync-plugin-versions.js +66 -0
- package/src/runtime/advice/cli.js +283 -0
- package/src/runtime/advice/client.js +324 -0
- package/src/runtime/advice/config.js +189 -0
- package/src/runtime/advice/doctor.js +169 -0
- package/src/runtime/advice/endpoint-guard.js +134 -0
- package/src/runtime/advice/kinds.js +154 -0
- package/src/runtime/advice/providers/ollama-systemone.js +209 -0
- package/src/runtime/advice/record.js +166 -0
- package/src/runtime/advice/registry.js +170 -0
- package/src/runtime/advice/strength.js +66 -0
- package/src/runtime/brief-tools.js +342 -0
- package/src/runtime/c4-project.js +371 -0
- package/src/runtime/capability-router.js +484 -0
- package/src/runtime/checkouts.js +170 -0
- package/src/runtime/claims.js +468 -0
- package/src/runtime/cli-result.js +55 -0
- package/src/runtime/cli.js +678 -0
- package/src/runtime/command-detect.js +516 -0
- package/src/runtime/context-pack.js +492 -0
- package/src/runtime/decision-register.js +493 -0
- package/src/runtime/evidence-ledger.js +338 -0
- package/src/runtime/failure/capture.js +272 -0
- package/src/runtime/failure/classifier.js +68 -0
- package/src/runtime/failure/cli.js +178 -0
- package/src/runtime/failure/home.js +64 -0
- package/src/runtime/failure/store.js +226 -0
- package/src/runtime/feature-resolve.js +79 -0
- package/src/runtime/freshness.js +177 -0
- package/src/runtime/health.js +863 -0
- package/src/runtime/history-compactor.js +237 -0
- package/src/runtime/implementation-gate.js +321 -0
- package/src/runtime/inventory/coverage.js +218 -0
- package/src/runtime/inventory/identity.js +65 -0
- package/src/runtime/inventory/index.js +705 -0
- package/src/runtime/inventory/precedence.js +134 -0
- package/src/runtime/inventory/read-scopes.js +131 -0
- package/src/runtime/inventory/siblings.js +192 -0
- package/src/runtime/knowledge/chunker.js +124 -0
- package/src/runtime/knowledge/hybrid.js +149 -0
- package/src/runtime/knowledge/index-store.js +145 -0
- package/src/runtime/knowledge/retrieval.js +194 -0
- package/src/runtime/leak-scan.js +185 -0
- package/src/runtime/lifecycle/cli.js +276 -0
- package/src/runtime/lifecycle/event-store.js +340 -0
- package/src/runtime/lifecycle/fold.js +353 -0
- package/src/runtime/lifecycle/followup.js +432 -0
- package/src/runtime/lifecycle/goal.js +249 -0
- package/src/runtime/lifecycle/intent-writer.js +86 -0
- package/src/runtime/lifecycle/overview.js +292 -0
- package/src/runtime/lifecycle/release.js +241 -0
- package/src/runtime/lifecycle/report-store.js +221 -0
- package/src/runtime/lifecycle/retention.js +212 -0
- package/src/runtime/lifecycle/root.js +71 -0
- package/src/runtime/lifecycle/status.js +353 -0
- package/src/runtime/lifecycle/store-upkeep.js +393 -0
- package/src/runtime/locator-resolve.js +158 -0
- package/src/runtime/mask.js +210 -0
- package/src/runtime/mcp-consultations.js +412 -0
- package/src/runtime/mcp-reach.js +157 -0
- package/src/runtime/model-router.js +153 -0
- package/src/runtime/outcome.js +467 -0
- package/src/runtime/reach.js +148 -0
- package/src/runtime/readiness-record.js +150 -0
- package/src/runtime/readiness.js +435 -0
- package/src/runtime/recovery.js +282 -0
- package/src/runtime/research-request.js +231 -0
- package/src/runtime/retrieval-plan.js +578 -0
- package/src/runtime/scaffold/artifacts.js +217 -0
- package/src/runtime/scaffold/fingerprint.js +56 -0
- package/src/runtime/scaffold/generate.js +911 -0
- package/src/runtime/scaffold/languages.js +245 -0
- package/src/runtime/storage/cli.js +64 -0
- package/src/runtime/storage/engine.js +249 -0
- package/src/runtime/storage/registry.js +130 -0
- package/src/runtime/storage/roots.js +63 -0
- package/src/runtime/storage/rules.js +282 -0
- package/src/runtime/storage/upkeep.js +243 -0
- package/src/runtime/storage/work-status.js +326 -0
- package/src/runtime/task-attempts.js +415 -0
- package/src/runtime/task-classifier.js +550 -0
- package/src/runtime/task-scope.js +130 -0
- package/src/runtime/task-state.js +176 -0
- package/src/runtime/trace/indicators.js +235 -0
- package/src/runtime/trace/ledger.js +626 -0
- package/src/runtime/trace/render.js +76 -0
- package/src/runtime/trace/views.js +459 -0
- package/src/runtime/verification/contract-runner.js +341 -0
- package/src/runtime/verification/engine.js +1461 -0
- package/src/runtime/verification/registry.js +130 -0
- package/src/runtime/verification/scope-bound.js +418 -0
- package/src/runtime/verification/test-selection.js +172 -0
- package/src/runtime/workflow-engine.js +588 -0
- package/src/runtime/workflow-orchestrator.js +953 -0
- package/src/runtime/worktree.js +340 -0
- package/src/state/index.js +193 -0
- package/src/state/lockfile.js +136 -0
- package/src/state/run-lock.js +408 -0
- package/types/node-commonjs.d.ts +68 -0
- package/types/runtime.d.ts +91 -0
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# do-task-brief.sh — compose one task's brief or a group's brief into files the implementer reads.
|
|
3
|
+
#
|
|
4
|
+
# A doflow task is a single checklist line, and plan.md has no "global constraints"
|
|
5
|
+
# section, so a brief cannot be sliced out of one place the way it can when tasks are
|
|
6
|
+
# prose sections. It is COMPOSED from six sources (design §5.2), plus specs.md when the
|
|
7
|
+
# feature has one:
|
|
8
|
+
#
|
|
9
|
+
# where this fits plan.md §1 Approach + the task's own "### Phase X" heading
|
|
10
|
+
# requirements requirement.md §3 FR detail for the FRs the task's [US#] traces
|
|
11
|
+
# why requirement.md §2 story text for that [US#]
|
|
12
|
+
# global constraints requirement.md §4 — ALL NFR detail; NFRs bind every task
|
|
13
|
+
# component boundary design.md §3 detail for components serving those FRs
|
|
14
|
+
# verification bar plan.md §7 rows for those FRs + the phase's Checkpoints line
|
|
15
|
+
# interface contracts specs.md §1 in full — only when the resolver reports has_specs
|
|
16
|
+
#
|
|
17
|
+
# The brief becomes the single source of the task's exact values, so no subagent needs
|
|
18
|
+
# to open the plan — which is what keeps the context discipline real rather than
|
|
19
|
+
# aspirational.
|
|
20
|
+
#
|
|
21
|
+
# Sections are located by HEADING TEXT, never by ordinal, so inserting a section does
|
|
22
|
+
# not silently shift the parse. Anything that could not be resolved is reported in
|
|
23
|
+
# `missing[]` rather than yielding a quietly thin brief the implementer cannot tell
|
|
24
|
+
# is incomplete.
|
|
25
|
+
#
|
|
26
|
+
# Every brief also closes with a tier, tools and report-format block (IC-017) that the
|
|
27
|
+
# `brief-tools` verb composes from the registries and this machine's probes; this script reads the
|
|
28
|
+
# task line's `owner:` and `tier:`, calls the dispatcher once per brief and writes the block plus
|
|
29
|
+
# the `*-brief.json` record (IC-018) beside the brief. It names no tool, provider, server or tier.
|
|
30
|
+
# It fails open (IC-019): a missing dispatcher, a non-zero exit or output that is not the expected
|
|
31
|
+
# JSON gives a "Not generated" line and a static report-format block, a `missing[]` note, no
|
|
32
|
+
# record, and the exit status the brief would otherwise have had.
|
|
33
|
+
#
|
|
34
|
+
# Usage:
|
|
35
|
+
# do-task-brief.sh --task=<id> [--harness=<id>] [--slug=<slug>] [--json]
|
|
36
|
+
# do-task-brief.sh --group=<phase>:<owner> --tasks=<id,id,...> [--harness=<id>] [--slug=<slug>] [--json]
|
|
37
|
+
#
|
|
38
|
+
# Emits for task mode: {path, lines, record, traced:{story, frs[], nfrs[], components[]}, missing[]}
|
|
39
|
+
# Emits for group mode: {path, lines, record, tasks[], traced:{frs[], nfrs[], components[]}, missing[]}
|
|
40
|
+
|
|
41
|
+
set -uo pipefail
|
|
42
|
+
|
|
43
|
+
task_id=""
|
|
44
|
+
group_id=""
|
|
45
|
+
tasks_csv=""
|
|
46
|
+
slug_override=""
|
|
47
|
+
harness=""
|
|
48
|
+
mode=""
|
|
49
|
+
|
|
50
|
+
for arg in "$@"; do
|
|
51
|
+
case "$arg" in
|
|
52
|
+
--task=*)
|
|
53
|
+
task_id="${arg#--task=}"
|
|
54
|
+
mode="task"
|
|
55
|
+
;;
|
|
56
|
+
--group=*)
|
|
57
|
+
group_id="${arg#--group=}"
|
|
58
|
+
mode="group"
|
|
59
|
+
;;
|
|
60
|
+
--tasks=*)
|
|
61
|
+
tasks_csv="${arg#--tasks=}"
|
|
62
|
+
;;
|
|
63
|
+
--slug=*)
|
|
64
|
+
slug_override="${arg#--slug=}"
|
|
65
|
+
;;
|
|
66
|
+
--harness=*)
|
|
67
|
+
harness="${arg#--harness=}"
|
|
68
|
+
;;
|
|
69
|
+
--json) ;;
|
|
70
|
+
*) ;;
|
|
71
|
+
esac
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
75
|
+
printf '{"error":"jq-not-found","path":null}\n'
|
|
76
|
+
exit 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
validate_id() {
|
|
80
|
+
local id="$1"
|
|
81
|
+
case "$id" in
|
|
82
|
+
*/*|*\\*|..*|*..|"") return 1 ;;
|
|
83
|
+
*) return 0 ;;
|
|
84
|
+
esac
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if [ "$mode" = "group" ]; then
|
|
88
|
+
if [ -z "$group_id" ] || [ -z "$tasks_csv" ]; then
|
|
89
|
+
jq -n '{error:"missing-group-args", hint:"pass --group=<phase>:<owner> and --tasks=<id,id,...>"}'
|
|
90
|
+
exit 2
|
|
91
|
+
fi
|
|
92
|
+
if ! validate_id "$group_id"; then
|
|
93
|
+
jq -n --arg id "$group_id" '{error:"invalid-group", group_id:$id, hint:"a group id must be phase-dotted with a safe owner name"}'
|
|
94
|
+
exit 2
|
|
95
|
+
fi
|
|
96
|
+
elif [ "$mode" = "task" ]; then
|
|
97
|
+
if [ -z "$task_id" ]; then
|
|
98
|
+
jq -n '{error:"missing-task", hint:"pass --task=<id>, e.g. --task=A.1"}'
|
|
99
|
+
exit 2
|
|
100
|
+
fi
|
|
101
|
+
if ! validate_id "$task_id"; then
|
|
102
|
+
jq -n --arg id "$task_id" '{error:"invalid-task", task_id:$id, hint:"a task id is phase-dotted, e.g. A.1 — no path separators"}'
|
|
103
|
+
exit 2
|
|
104
|
+
fi
|
|
105
|
+
else
|
|
106
|
+
jq -n '{error:"missing-task", hint:"pass --task=<id>, e.g. --task=A.1"}'
|
|
107
|
+
exit 2
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
script_dir="$(cd "$(dirname "$0")" && pwd)"
|
|
111
|
+
paths=""
|
|
112
|
+
if [ "$mode" = "group" ]; then
|
|
113
|
+
paths="$(bash "$script_dir/do-exec-paths.sh" --group="$group_id" --tasks="$tasks_csv" ${slug_override:+--slug="$slug_override"} 2>/dev/null)"
|
|
114
|
+
brief_rel="$(printf '%s' "$paths" | jq -r '.group_brief // empty')"
|
|
115
|
+
else
|
|
116
|
+
paths="$(bash "$script_dir/do-exec-paths.sh" --task="$task_id" ${slug_override:+--slug="$slug_override"} 2>/dev/null)"
|
|
117
|
+
brief_rel="$(printf '%s' "$paths" | jq -r '.brief // empty')"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
if [ -z "$brief_rel" ]; then
|
|
121
|
+
# Not "${paths:-{...}}": bash ends the expansion at the first unescaped `}`, so the default word
|
|
122
|
+
# is `{"error":"paths-unresolved"` and the final `}` is emitted *outside* it — appending a stray
|
|
123
|
+
# brace to $paths whenever $paths is non-empty. Every error passthrough here (a rejected task id,
|
|
124
|
+
# or simply running with no active feature) therefore produced JSON that `jq` refuses to parse.
|
|
125
|
+
if [ -n "$paths" ]; then
|
|
126
|
+
printf '%s\n' "$paths"
|
|
127
|
+
else
|
|
128
|
+
printf '%s\n' '{"error":"paths-unresolved"}'
|
|
129
|
+
fi
|
|
130
|
+
exit 2
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
resolved="$(bash "$script_dir/do-paths.sh" --json ${slug_override:+--slug="$slug_override"} 2>/dev/null)"
|
|
134
|
+
repo_root="$(printf '%s' "$resolved" | jq -r '.repo_root // empty')"
|
|
135
|
+
plan_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.plan // empty')"
|
|
136
|
+
req_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.requirement // empty')"
|
|
137
|
+
des_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.design // empty')"
|
|
138
|
+
specs_abs="$repo_root/$(printf '%s' "$resolved" | jq -r '.specs // empty')"
|
|
139
|
+
has_specs="$(printf '%s' "$resolved" | jq -r '.has_specs // false')"
|
|
140
|
+
brief_abs="$repo_root/$brief_rel"
|
|
141
|
+
record_rel="$(printf '%s' "$paths" | jq -r '.brief_record // empty')"
|
|
142
|
+
feature_slug="$(printf '%s' "$resolved" | jq -r '.feature_slug // empty')"
|
|
143
|
+
|
|
144
|
+
# The preamble names specs.md only when this feature actually has one: a legacy-layout brief
|
|
145
|
+
# stays byte-identical to what it was before specs.md existed, rather than advertising a source
|
|
146
|
+
# the reader will not find a section for.
|
|
147
|
+
composed_from="plan.md, requirement.md and design.md"
|
|
148
|
+
if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
|
|
149
|
+
composed_from="plan.md, requirement.md, design.md and specs.md"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
missing=()
|
|
153
|
+
[ -f "$plan_abs" ] || missing+=("plan.md not readable")
|
|
154
|
+
[ -f "$req_abs" ] || missing+=("requirement.md not readable")
|
|
155
|
+
[ -f "$des_abs" ] || missing+=("design.md not readable")
|
|
156
|
+
|
|
157
|
+
if [ ! -f "$plan_abs" ]; then
|
|
158
|
+
jq -n --arg p "$brief_rel" '{error:"no-plan", path:$p, hint:"a brief is composed from plan.md; there is nothing to compose"}'
|
|
159
|
+
exit 2
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# ── section extractor: by heading TEXT, stopping at the next same-level heading ─
|
|
163
|
+
section() { # section <file> <heading-regex>
|
|
164
|
+
awk -v want="$2" '
|
|
165
|
+
$0 ~ want { inside = 1; next }
|
|
166
|
+
inside && /^## / { exit }
|
|
167
|
+
inside { print }
|
|
168
|
+
' "$1"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
detail_for() { # detail_for <file> <section-regex> <id>
|
|
172
|
+
section "$1" "$2" | awk -v id="$3" '
|
|
173
|
+
$0 ~ "^- \\*\\*" id "([^A-Za-z0-9]|$)" { inside = 1; print; next }
|
|
174
|
+
inside && /^- \*\*/ { exit }
|
|
175
|
+
inside { print }
|
|
176
|
+
'
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
to_json_array() {
|
|
180
|
+
local input="${1:-}"
|
|
181
|
+
if [ -z "$input" ]; then
|
|
182
|
+
echo '[]'
|
|
183
|
+
else
|
|
184
|
+
printf '%s\n' "$input" | sed '/^$/d' | jq -R . | jq -s 'if length == 0 then [] else . end'
|
|
185
|
+
fi
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# ── tier, tools and report format (IC-017 to IC-019) ─────────────────────────
|
|
189
|
+
# A task line field is "; <name>: <value>" or "— <name>: <value>"; the value is one safe word.
|
|
190
|
+
task_field() { # task_field <task line> <name>
|
|
191
|
+
printf '%s' "$1" | sed -nE "s/.*(; |— )$2: *([A-Za-z0-9_-]+).*/\\2/p"
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Sets bt_md and bt_record on success, bt_reason on every failure; never exits.
|
|
195
|
+
bt_call() { # bt_call <owner> <tier> <heading level> <task ids>
|
|
196
|
+
bt_md=""; bt_record=""; bt_reason=""
|
|
197
|
+
local dispatcher="$script_dir/../bin/doflow-run" out rc
|
|
198
|
+
if [ -z "$1" ]; then bt_reason="the task line names no owner"; return 0; fi
|
|
199
|
+
if [ ! -f "$dispatcher" ]; then bt_reason="the dispatcher was not found"; return 0; fi
|
|
200
|
+
out="$(cd "${repo_root:-.}" 2>/dev/null && bash "$dispatcher" brief-tools --json --owner "$1" \
|
|
201
|
+
${2:+--tier "$2"} ${harness:+--harness "$harness"} ${feature_slug:+--slug "$feature_slug"} \
|
|
202
|
+
--heading-level "$3" ${4:+--tasks "$4"} </dev/null 2>/dev/null)"
|
|
203
|
+
rc=$?
|
|
204
|
+
if [ "$rc" -ne 0 ]; then bt_reason="brief-tools exited $rc"; return 0; fi
|
|
205
|
+
if ! printf '%s' "$out" | jq -e '(.markdown | type == "string" and length > 0) and (.record | type == "object")' >/dev/null 2>&1; then
|
|
206
|
+
bt_reason="brief-tools printed unparseable output"; return 0
|
|
207
|
+
fi
|
|
208
|
+
bt_md="$(printf '%s' "$out" | jq -r '.markdown')"
|
|
209
|
+
bt_record="$(printf '%s' "$out" | jq -c '.record')"
|
|
210
|
+
return 0
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# The block for the brief: the verb's markdown, or the static fallback (no tool names).
|
|
214
|
+
bt_emit() { # bt_emit <heading level>
|
|
215
|
+
local h="##" who="your report"
|
|
216
|
+
if [ "$1" = "3" ]; then h="###"; who="each task's report"; fi
|
|
217
|
+
if [ -n "$bt_md" ]; then
|
|
218
|
+
printf '%s\n' "$bt_md"
|
|
219
|
+
return 0
|
|
220
|
+
fi
|
|
221
|
+
printf '%s Tier and tools\n\nNot generated: %s. Name the tier and tools in the dispatch.\n\n' "$h" "$bt_reason"
|
|
222
|
+
printf '%s Report format\n\nEnd %s with one line naming every tool and MCP server you used:\n' "$h" "$who"
|
|
223
|
+
printf '%s\n' '`Tools used: <name>[=used|nothing-usable|unavailable|skipped:<reason>], ...`'
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# Writes the record beside the brief with its tasks filled in; sets record_out to its path, or to ""
|
|
227
|
+
# when there is nothing to write or the write failed.
|
|
228
|
+
record_out=""
|
|
229
|
+
bt_write_record() { # bt_write_record <tasks json>
|
|
230
|
+
record_out=""
|
|
231
|
+
[ -n "$bt_record" ] || return 0
|
|
232
|
+
[ -n "$record_rel" ] || { missing+=("brief-tools: no record path from do-exec-paths.sh"); return 0; }
|
|
233
|
+
if printf '%s' "$bt_record" | jq --argjson tasks "$1" '. + {tasks: $tasks}' > "$repo_root/$record_rel" 2>/dev/null; then
|
|
234
|
+
record_out="$record_rel"
|
|
235
|
+
else
|
|
236
|
+
rm -f "$repo_root/$record_rel" 2>/dev/null
|
|
237
|
+
missing+=("brief-tools: the record could not be written")
|
|
238
|
+
fi
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
nfrs=""
|
|
242
|
+
if [ -f "$req_abs" ]; then
|
|
243
|
+
nfrs="$(section "$req_abs" '^## 4[.]' | grep -o '^| *NFR-[0-9]*' | tr -d '| ')"
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
# Parse task list
|
|
247
|
+
task_ids=()
|
|
248
|
+
if [ "$mode" = "group" ]; then
|
|
249
|
+
IFS=',' read -ra raw_task_ids <<< "$tasks_csv"
|
|
250
|
+
for tid in "${raw_task_ids[@]}"; do
|
|
251
|
+
tid="$(echo "$tid" | tr -d ' ')"
|
|
252
|
+
[ -n "$tid" ] && task_ids+=("$tid")
|
|
253
|
+
done
|
|
254
|
+
else
|
|
255
|
+
task_ids=("$task_id")
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
# In single task mode: check if task exists
|
|
259
|
+
if [ "$mode" = "task" ]; then
|
|
260
|
+
task_line="$(awk -v id="$task_id" '
|
|
261
|
+
$0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print; exit }' "$plan_abs")"
|
|
262
|
+
if [ -z "$task_line" ]; then
|
|
263
|
+
jq -n --arg id "$task_id" '{error:"task-not-found", task_id:$id, hint:"no \"- [ ] <id>\" line in plan.md section 8"}'
|
|
264
|
+
exit 3
|
|
265
|
+
fi
|
|
266
|
+
phase_heading="$(awk -v id="$task_id" '
|
|
267
|
+
/^### Phase / { h = $0 }
|
|
268
|
+
$0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print h; exit }' "$plan_abs")"
|
|
269
|
+
phase_letter="$(printf '%s' "$phase_heading" | awk '{print $3}')"
|
|
270
|
+
|
|
271
|
+
story="$(printf '%s' "$task_line" | grep -o '\[US[0-9]\+\]' | head -1 | tr -d '[]')"
|
|
272
|
+
files_field="$(printf '%s' "$task_line" | sed -n 's/.*files: \([^;]*\).*/\1/p')"
|
|
273
|
+
[ -n "$story" ] || missing+=("task line carries no [US#] trace")
|
|
274
|
+
|
|
275
|
+
frs=""
|
|
276
|
+
if [ -n "$story" ] && [ -f "$req_abs" ]; then
|
|
277
|
+
frs="$(section "$req_abs" '^## 3[.]' | awk -F'|' -v s="$story" '
|
|
278
|
+
/^\| *FR-/ {
|
|
279
|
+
id = $2; sto = $4
|
|
280
|
+
gsub(/^[ \t]+|[ \t]+$/, "", id); gsub(/^[ \t]+|[ \t]+$/, "", sto)
|
|
281
|
+
if (sto == s) print id
|
|
282
|
+
}')"
|
|
283
|
+
fi
|
|
284
|
+
[ -n "$frs" ] || missing+=("no FR in requirement.md section 3 traces to ${story:-this task}")
|
|
285
|
+
|
|
286
|
+
components=""
|
|
287
|
+
if [ -n "$frs" ] && [ -f "$des_abs" ]; then
|
|
288
|
+
components="$(for fr in $frs; do
|
|
289
|
+
section "$des_abs" '^## 3[.]' | awk -F'|' -v fr="$fr" '
|
|
290
|
+
/^\| *CMP/ { if ($5 ~ fr) { id = $2; gsub(/^[ \t]+|[ \t]+$/, "", id); print id } }'
|
|
291
|
+
done | sort -u)"
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
bt_call "$(task_field "$task_line" owner)" "$(task_field "$task_line" tier)" 2 "$task_id"
|
|
295
|
+
[ -z "$bt_reason" ] || missing+=("brief-tools: $bt_reason")
|
|
296
|
+
|
|
297
|
+
# Compose brief
|
|
298
|
+
write_ok=1
|
|
299
|
+
{
|
|
300
|
+
echo "# Task brief: $task_id"
|
|
301
|
+
echo
|
|
302
|
+
echo "> Composed from $composed_from. This brief is your requirements —"
|
|
303
|
+
echo "> use the exact values it gives, verbatim. You do not need to open the plan."
|
|
304
|
+
echo
|
|
305
|
+
echo "## The task"
|
|
306
|
+
echo
|
|
307
|
+
echo "${task_line#- \[ \] }"
|
|
308
|
+
echo
|
|
309
|
+
[ -n "$phase_heading" ] && { echo "Phase: ${phase_heading#\#\#\# }"; echo; }
|
|
310
|
+
[ -n "$files_field" ] && { echo "Files you own: $files_field"; echo; }
|
|
311
|
+
|
|
312
|
+
echo "## Where this fits"
|
|
313
|
+
echo
|
|
314
|
+
section "$plan_abs" '^## 1[.]' | sed '/^$/d' | head -8
|
|
315
|
+
echo
|
|
316
|
+
|
|
317
|
+
if [ -n "$story" ] && [ -f "$req_abs" ]; then
|
|
318
|
+
echo "## Why (user story)"
|
|
319
|
+
echo
|
|
320
|
+
section "$req_abs" '^## 2[.]' | awk -v s="$story" '
|
|
321
|
+
$0 ~ ("^- \\*\\*" s "([^0-9]|$)") { inside = 1; sub(/^- /, ""); print; next }
|
|
322
|
+
inside && /^- \*\*/ { exit }
|
|
323
|
+
inside { print }' || true
|
|
324
|
+
echo
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
if [ -n "$frs" ]; then
|
|
328
|
+
echo "## Requirements — build exactly these"
|
|
329
|
+
echo
|
|
330
|
+
for fr in $frs; do detail_for "$req_abs" '^## 3[.]' "$fr"; done
|
|
331
|
+
echo
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
if [ -f "$req_abs" ]; then
|
|
335
|
+
echo "## Global constraints — these bind every task"
|
|
336
|
+
echo
|
|
337
|
+
section "$req_abs" '^## 4[.]' | awk '/^- \*\*NFR-/ { p = 1 } p' | sed '/^$/d'
|
|
338
|
+
echo
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
if [ -n "$components" ]; then
|
|
342
|
+
echo "## Component boundary"
|
|
343
|
+
echo
|
|
344
|
+
printf '%s\n' "$components" | while read -r cmp; do
|
|
345
|
+
[ -n "$cmp" ] && detail_for "$des_abs" '^## 3[.]' "$cmp"
|
|
346
|
+
done
|
|
347
|
+
echo
|
|
348
|
+
fi
|
|
349
|
+
|
|
350
|
+
if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
|
|
351
|
+
echo "## Interface contracts"
|
|
352
|
+
echo
|
|
353
|
+
# §1 IN FULL, deliberately unfiltered: an IC-### entry carries no FR or component
|
|
354
|
+
# linkage field, so there is nothing to filter it by the way "component boundary"
|
|
355
|
+
# above filters design.md §3 rows on the FRs they name.
|
|
356
|
+
section "$specs_abs" '^## 1[.]' | awk 'NF { p = 1 } p'
|
|
357
|
+
echo
|
|
358
|
+
fi
|
|
359
|
+
|
|
360
|
+
echo "## Verification bar"
|
|
361
|
+
echo
|
|
362
|
+
for fr in $frs; do
|
|
363
|
+
section "$plan_abs" '^## 7[.]' | grep -F "| $fr |" || true
|
|
364
|
+
done
|
|
365
|
+
[ -n "$phase_letter" ] && grep -F "After Phase $phase_letter:" "$plan_abs" || true
|
|
366
|
+
echo
|
|
367
|
+
bt_emit 2
|
|
368
|
+
} > "$brief_abs" || write_ok=0
|
|
369
|
+
|
|
370
|
+
if [ "${write_ok:-1}" -eq 0 ] || [ ! -s "$brief_abs" ]; then
|
|
371
|
+
jq -n --arg path "$brief_rel" \
|
|
372
|
+
'{error:"write-failed", path:$path, hint:"the task brief could not be written — check the workspace is writable"}'
|
|
373
|
+
exit 2
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
lines="$(wc -l < "$brief_abs" | tr -d ' ')"
|
|
377
|
+
|
|
378
|
+
bt_write_record "$(jq -nc --arg id "$task_id" --arg report "$(printf '%s' "$paths" | jq -r '.report // empty')" '[{id:$id, report:$report}]')"
|
|
379
|
+
|
|
380
|
+
jq -n \
|
|
381
|
+
--arg path "$brief_rel" \
|
|
382
|
+
--arg record "$record_out" \
|
|
383
|
+
--argjson lines "${lines:-0}" \
|
|
384
|
+
--arg story "$story" \
|
|
385
|
+
--argjson frs "$(to_json_array "$frs")" \
|
|
386
|
+
--argjson nfrs "$(to_json_array "$nfrs")" \
|
|
387
|
+
--argjson components "$(to_json_array "$components")" \
|
|
388
|
+
--argjson missing "$(to_json_array "$(printf '%s\n' "${missing[@]+"${missing[@]}"}" | sed '/^$/d')")" \
|
|
389
|
+
'{path:$path, lines:$lines, record:(if $record=="" then null else $record end),
|
|
390
|
+
traced:{story:(if $story=="" then null else $story end), frs:$frs, nfrs:$nfrs, components:$components},
|
|
391
|
+
missing:$missing}'
|
|
392
|
+
exit 0
|
|
393
|
+
|
|
394
|
+
else
|
|
395
|
+
# Group mode
|
|
396
|
+
num_tasks="${#task_ids[@]}"
|
|
397
|
+
|
|
398
|
+
# For each task in group, collect details into arrays
|
|
399
|
+
declare -a task_lines=()
|
|
400
|
+
declare -a task_phases=()
|
|
401
|
+
declare -a task_phase_letters=()
|
|
402
|
+
declare -a task_stories=()
|
|
403
|
+
declare -a task_files=()
|
|
404
|
+
declare -a task_fr_lists=()
|
|
405
|
+
all_frs_raw=""
|
|
406
|
+
all_comps_raw=""
|
|
407
|
+
|
|
408
|
+
for tid in "${task_ids[@]}"; do
|
|
409
|
+
t_line="$(awk -v id="$tid" '
|
|
410
|
+
$0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print; exit }' "$plan_abs")"
|
|
411
|
+
if [ -z "$t_line" ]; then
|
|
412
|
+
missing+=("$tid: task line not found in plan.md")
|
|
413
|
+
task_lines+=("")
|
|
414
|
+
task_phases+=("")
|
|
415
|
+
task_phase_letters+=("")
|
|
416
|
+
task_stories+=("")
|
|
417
|
+
task_files+=("")
|
|
418
|
+
task_fr_lists+=("")
|
|
419
|
+
continue
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
t_phase="$(awk -v id="$tid" '
|
|
423
|
+
/^### Phase / { h = $0 }
|
|
424
|
+
$0 ~ "^- \\[[ x]\\] " id "([^0-9]|$)" { print h; exit }' "$plan_abs")"
|
|
425
|
+
t_phase_let="$(printf '%s' "$t_phase" | awk '{print $3}')"
|
|
426
|
+
t_files="$(printf '%s' "$t_line" | sed -n 's/.*files: \([^;]*\).*/\1/p')"
|
|
427
|
+
t_story="$(printf '%s' "$t_line" | grep -o '\[US[0-9]\+\]' | head -1 | tr -d '[]')"
|
|
428
|
+
|
|
429
|
+
[ -n "$t_story" ] || missing+=("$tid: task line carries no [US#] trace")
|
|
430
|
+
|
|
431
|
+
t_frs=""
|
|
432
|
+
if [ -n "$t_story" ] && [ -f "$req_abs" ]; then
|
|
433
|
+
t_frs="$(section "$req_abs" '^## 3[.]' | awk -F'|' -v s="$t_story" '
|
|
434
|
+
/^\| *FR-/ {
|
|
435
|
+
id = $2; sto = $4
|
|
436
|
+
gsub(/^[ \t]+|[ \t]+$/, "", id); gsub(/^[ \t]+|[ \t]+$/, "", sto)
|
|
437
|
+
if (sto == s) print id
|
|
438
|
+
}')"
|
|
439
|
+
fi
|
|
440
|
+
[ -n "$t_frs" ] || missing+=("$tid: no FR in requirement.md section 3 traces to ${t_story:-this task}")
|
|
441
|
+
|
|
442
|
+
for f in $t_frs; do
|
|
443
|
+
all_frs_raw="${all_frs_raw}${f}"$'\n'
|
|
444
|
+
done
|
|
445
|
+
|
|
446
|
+
task_lines+=("$t_line")
|
|
447
|
+
task_phases+=("$t_phase")
|
|
448
|
+
task_phase_letters+=("$t_phase_let")
|
|
449
|
+
task_stories+=("$t_story")
|
|
450
|
+
task_files+=("$t_files")
|
|
451
|
+
task_fr_lists+=("$t_frs")
|
|
452
|
+
done
|
|
453
|
+
|
|
454
|
+
# Union of FRs
|
|
455
|
+
all_frs="$(printf '%s' "$all_frs_raw" | sed '/^$/d' | sort -u)"
|
|
456
|
+
|
|
457
|
+
# Union of components serving those FRs
|
|
458
|
+
if [ -n "$all_frs" ] && [ -f "$des_abs" ]; then
|
|
459
|
+
all_comps_raw="$(for fr in $all_frs; do
|
|
460
|
+
section "$des_abs" '^## 3[.]' | awk -F'|' -v fr="$fr" '
|
|
461
|
+
/^\| *CMP/ { if ($5 ~ fr) { id = $2; gsub(/^[ \t]+|[ \t]+$/, "", id); print id } }'
|
|
462
|
+
done | sort -u)"
|
|
463
|
+
fi
|
|
464
|
+
|
|
465
|
+
# The group's owner is the part of --group after the phase; its tier is the tasks' shared tier.
|
|
466
|
+
group_owner=""
|
|
467
|
+
case "$group_id" in *:*) group_owner="${group_id#*:}" ;; esac
|
|
468
|
+
group_tier=""
|
|
469
|
+
for idx in "${!task_ids[@]}"; do
|
|
470
|
+
t_tier="$(task_field "${task_lines[$idx]}" tier)"
|
|
471
|
+
if [ "$idx" -eq 0 ]; then group_tier="$t_tier"
|
|
472
|
+
elif [ "$t_tier" != "$group_tier" ]; then group_tier=""; break; fi
|
|
473
|
+
done
|
|
474
|
+
bt_level=3
|
|
475
|
+
[ "$num_tasks" -eq 1 ] && bt_level=2
|
|
476
|
+
bt_call "$group_owner" "$group_tier" "$bt_level" "$(IFS=,; printf '%s' "${task_ids[*]}")"
|
|
477
|
+
[ -z "$bt_reason" ] || missing+=("brief-tools: $bt_reason")
|
|
478
|
+
|
|
479
|
+
write_ok=1
|
|
480
|
+
if [ "$num_tasks" -eq 1 ]; then
|
|
481
|
+
# Single-task group: byte-identical output to --task=
|
|
482
|
+
t_id="${task_ids[0]}"
|
|
483
|
+
t_line="${task_lines[0]}"
|
|
484
|
+
t_phase="${task_phases[0]}"
|
|
485
|
+
t_phase_let="${task_phase_letters[0]}"
|
|
486
|
+
t_story="${task_stories[0]}"
|
|
487
|
+
t_files="${task_files[0]}"
|
|
488
|
+
t_frs="${task_fr_lists[0]}"
|
|
489
|
+
|
|
490
|
+
t_comps=""
|
|
491
|
+
if [ -n "$t_frs" ] && [ -f "$des_abs" ]; then
|
|
492
|
+
t_comps="$(for fr in $t_frs; do
|
|
493
|
+
section "$des_abs" '^## 3[.]' | awk -F'|' -v fr="$fr" '
|
|
494
|
+
/^\| *CMP/ { if ($5 ~ fr) { id = $2; gsub(/^[ \t]+|[ \t]+$/, "", id); print id } }'
|
|
495
|
+
done | sort -u)"
|
|
496
|
+
fi
|
|
497
|
+
|
|
498
|
+
{
|
|
499
|
+
echo "# Task brief: $t_id"
|
|
500
|
+
echo
|
|
501
|
+
echo "> Composed from $composed_from. This brief is your requirements —"
|
|
502
|
+
echo "> use the exact values it gives, verbatim. You do not need to open the plan."
|
|
503
|
+
echo
|
|
504
|
+
echo "## The task"
|
|
505
|
+
echo
|
|
506
|
+
echo "${t_line#- \[ \] }"
|
|
507
|
+
echo
|
|
508
|
+
[ -n "$t_phase" ] && { echo "Phase: ${t_phase#\#\#\# }"; echo; }
|
|
509
|
+
[ -n "$t_files" ] && { echo "Files you own: $t_files"; echo; }
|
|
510
|
+
|
|
511
|
+
echo "## Where this fits"
|
|
512
|
+
echo
|
|
513
|
+
section "$plan_abs" '^## 1[.]' | sed '/^$/d' | head -8
|
|
514
|
+
echo
|
|
515
|
+
|
|
516
|
+
if [ -n "$t_story" ] && [ -f "$req_abs" ]; then
|
|
517
|
+
echo "## Why (user story)"
|
|
518
|
+
echo
|
|
519
|
+
section "$req_abs" '^## 2[.]' | awk -v s="$t_story" '
|
|
520
|
+
$0 ~ ("^- \\*\\*" s "([^0-9]|$)") { inside = 1; sub(/^- /, ""); print; next }
|
|
521
|
+
inside && /^- \*\*/ { exit }
|
|
522
|
+
inside { print }' || true
|
|
523
|
+
echo
|
|
524
|
+
fi
|
|
525
|
+
|
|
526
|
+
if [ -n "$t_frs" ]; then
|
|
527
|
+
echo "## Requirements — build exactly these"
|
|
528
|
+
echo
|
|
529
|
+
for fr in $t_frs; do detail_for "$req_abs" '^## 3[.]' "$fr"; done
|
|
530
|
+
echo
|
|
531
|
+
fi
|
|
532
|
+
|
|
533
|
+
if [ -f "$req_abs" ]; then
|
|
534
|
+
echo "## Global constraints — these bind every task"
|
|
535
|
+
echo
|
|
536
|
+
section "$req_abs" '^## 4[.]' | awk '/^- \*\*NFR-/ { p = 1 } p' | sed '/^$/d'
|
|
537
|
+
echo
|
|
538
|
+
fi
|
|
539
|
+
|
|
540
|
+
if [ -n "$t_comps" ]; then
|
|
541
|
+
echo "## Component boundary"
|
|
542
|
+
echo
|
|
543
|
+
printf '%s\n' "$t_comps" | while read -r cmp; do
|
|
544
|
+
[ -n "$cmp" ] && detail_for "$des_abs" '^## 3[.]' "$cmp"
|
|
545
|
+
done
|
|
546
|
+
echo
|
|
547
|
+
fi
|
|
548
|
+
|
|
549
|
+
if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
|
|
550
|
+
echo "## Interface contracts"
|
|
551
|
+
echo
|
|
552
|
+
# §1 IN FULL, deliberately unfiltered — see the --task= path above: an IC-### entry
|
|
553
|
+
# carries no FR or component linkage field to filter it by.
|
|
554
|
+
section "$specs_abs" '^## 1[.]' | awk 'NF { p = 1 } p'
|
|
555
|
+
echo
|
|
556
|
+
fi
|
|
557
|
+
|
|
558
|
+
echo "## Verification bar"
|
|
559
|
+
echo
|
|
560
|
+
for fr in $t_frs; do
|
|
561
|
+
section "$plan_abs" '^## 7[.]' | grep -F "| $fr |" || true
|
|
562
|
+
done
|
|
563
|
+
[ -n "$t_phase_let" ] && grep -F "After Phase $t_phase_let:" "$plan_abs" || true
|
|
564
|
+
echo
|
|
565
|
+
bt_emit 2
|
|
566
|
+
} > "$brief_abs" || write_ok=0
|
|
567
|
+
|
|
568
|
+
else
|
|
569
|
+
# Multi-task group: shared preamble once + one block per task
|
|
570
|
+
{
|
|
571
|
+
echo "# Group brief: $group_id"
|
|
572
|
+
echo
|
|
573
|
+
echo "> Composed from $composed_from. This brief covers multiple tasks that share an owner."
|
|
574
|
+
echo
|
|
575
|
+
echo "## Shared context"
|
|
576
|
+
echo
|
|
577
|
+
echo "### Where this fits"
|
|
578
|
+
echo
|
|
579
|
+
section "$plan_abs" '^## 1[.]' | sed '/^$/d' | head -8
|
|
580
|
+
echo
|
|
581
|
+
|
|
582
|
+
if [ -f "$req_abs" ]; then
|
|
583
|
+
echo "### Global constraints — these bind every task"
|
|
584
|
+
echo
|
|
585
|
+
section "$req_abs" '^## 4[.]' | awk '/^- \*\*NFR-/ { p = 1 } p' | sed '/^$/d'
|
|
586
|
+
echo
|
|
587
|
+
fi
|
|
588
|
+
|
|
589
|
+
if [ -n "$all_comps_raw" ]; then
|
|
590
|
+
echo "### Component boundary"
|
|
591
|
+
echo
|
|
592
|
+
printf '%s\n' "$all_comps_raw" | while read -r cmp; do
|
|
593
|
+
[ -n "$cmp" ] && detail_for "$des_abs" '^## 3[.]' "$cmp"
|
|
594
|
+
done
|
|
595
|
+
echo
|
|
596
|
+
fi
|
|
597
|
+
|
|
598
|
+
if [ "$has_specs" = "true" ] && [ -f "$specs_abs" ]; then
|
|
599
|
+
echo "### Interface contracts"
|
|
600
|
+
echo
|
|
601
|
+
# §1 IN FULL, deliberately unfiltered — see the --task= path above: an IC-### entry
|
|
602
|
+
# carries no FR or component linkage field to filter it by. Shared context, since
|
|
603
|
+
# every task in the group is bound by the same contracts.
|
|
604
|
+
section "$specs_abs" '^## 1[.]' | awk 'NF { p = 1 } p'
|
|
605
|
+
echo
|
|
606
|
+
fi
|
|
607
|
+
|
|
608
|
+
bt_emit 3
|
|
609
|
+
echo
|
|
610
|
+
|
|
611
|
+
echo "## Task order"
|
|
612
|
+
echo
|
|
613
|
+
task_order=""
|
|
614
|
+
for tid in "${task_ids[@]}"; do
|
|
615
|
+
if [ -n "$task_order" ]; then
|
|
616
|
+
task_order="$task_order → $tid"
|
|
617
|
+
else
|
|
618
|
+
task_order="$tid"
|
|
619
|
+
fi
|
|
620
|
+
done
|
|
621
|
+
echo "$task_order (write each task's report before starting the next)"
|
|
622
|
+
echo
|
|
623
|
+
|
|
624
|
+
for idx in "${!task_ids[@]}"; do
|
|
625
|
+
tid="${task_ids[$idx]}"
|
|
626
|
+
t_line="${task_lines[$idx]}"
|
|
627
|
+
t_phase="${task_phases[$idx]}"
|
|
628
|
+
t_phase_let="${task_phase_letters[$idx]}"
|
|
629
|
+
t_story="${task_stories[$idx]}"
|
|
630
|
+
t_files="${task_files[$idx]}"
|
|
631
|
+
t_frs="${task_fr_lists[$idx]}"
|
|
632
|
+
|
|
633
|
+
echo "## Task $tid"
|
|
634
|
+
echo
|
|
635
|
+
echo "${t_line#- \[ \] }"
|
|
636
|
+
echo
|
|
637
|
+
|
|
638
|
+
if [ -n "$t_story" ] && [ -f "$req_abs" ]; then
|
|
639
|
+
echo "### Why (user story)"
|
|
640
|
+
echo
|
|
641
|
+
section "$req_abs" '^## 2[.]' | awk -v s="$t_story" '
|
|
642
|
+
$0 ~ ("^- \\*\\*" s "([^0-9]|$)") { inside = 1; sub(/^- /, ""); print; next }
|
|
643
|
+
inside && /^- \*\*/ { exit }
|
|
644
|
+
inside { print }' || true
|
|
645
|
+
echo
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
if [ -n "$t_frs" ]; then
|
|
649
|
+
echo "### Requirements — build exactly these"
|
|
650
|
+
echo
|
|
651
|
+
for fr in $t_frs; do detail_for "$req_abs" '^## 3[.]' "$fr"; done
|
|
652
|
+
echo
|
|
653
|
+
fi
|
|
654
|
+
|
|
655
|
+
if [ -n "$t_files" ]; then
|
|
656
|
+
echo "### Files you own"
|
|
657
|
+
echo
|
|
658
|
+
echo "$t_files"
|
|
659
|
+
echo
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
echo "### Verification bar"
|
|
663
|
+
echo
|
|
664
|
+
for fr in $t_frs; do
|
|
665
|
+
section "$plan_abs" '^## 7[.]' | grep -F "| $fr |" || true
|
|
666
|
+
done
|
|
667
|
+
[ -n "$t_phase_let" ] && grep -F "After Phase $t_phase_let:" "$plan_abs" || true
|
|
668
|
+
echo
|
|
669
|
+
done
|
|
670
|
+
} > "$brief_abs" || write_ok=0
|
|
671
|
+
fi
|
|
672
|
+
|
|
673
|
+
if [ "${write_ok:-1}" -eq 0 ] || [ ! -s "$brief_abs" ]; then
|
|
674
|
+
jq -n --arg path "$brief_rel" \
|
|
675
|
+
'{error:"write-failed", path:$path, hint:"the task brief could not be written — check the workspace is writable"}'
|
|
676
|
+
exit 2
|
|
677
|
+
fi
|
|
678
|
+
|
|
679
|
+
lines="$(wc -l < "$brief_abs" | tr -d ' ')"
|
|
680
|
+
|
|
681
|
+
bt_write_record "$(jq -nc --argjson reports "$(printf '%s' "$paths" | jq -c '.reports // []')" \
|
|
682
|
+
'$ARGS.positional as $ids | [range(0; $ids | length) | {id: $ids[.], report: ($reports[.] // null)}]' \
|
|
683
|
+
--args "${task_ids[@]}")"
|
|
684
|
+
|
|
685
|
+
jq -n \
|
|
686
|
+
--arg path "$brief_rel" \
|
|
687
|
+
--arg record "$record_out" \
|
|
688
|
+
--argjson lines "${lines:-0}" \
|
|
689
|
+
--argjson frs "$(to_json_array "$all_frs")" \
|
|
690
|
+
--argjson nfrs "$(to_json_array "$nfrs")" \
|
|
691
|
+
--argjson components "$(to_json_array "$all_comps_raw")" \
|
|
692
|
+
--argjson missing "$(to_json_array "$(printf '%s\n' "${missing[@]+"${missing[@]}"}" | sed '/^$/d')")" \
|
|
693
|
+
'{path:$path, lines:$lines, record:(if $record=="" then null else $record end), tasks:$ARGS.positional,
|
|
694
|
+
traced:{frs:$frs, nfrs:$nfrs, components:$components},
|
|
695
|
+
missing:$missing}' \
|
|
696
|
+
--args "${task_ids[@]}"
|
|
697
|
+
exit 0
|
|
698
|
+
fi
|