@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,468 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const crypto = require('node:crypto');
|
|
8
|
+
// Shared with EvidenceLedger so both stores enforce one definition of a safe task id.
|
|
9
|
+
const { assertSafeTaskId, EvidenceLedger } = require('./evidence-ledger.js');
|
|
10
|
+
const { updateTaskState, readTaskState, mergeRecords } = require('./task-state.js');
|
|
11
|
+
const { taskStoreDir } = require('./task-scope.js');
|
|
12
|
+
const { finishRuntime, usageError } = require('./cli-result.js');
|
|
13
|
+
const { REPO_ROOT } = require('../helper/repo-root.js');
|
|
14
|
+
|
|
15
|
+
const CLAIM_STATUSES = new Set([
|
|
16
|
+
'hypothesis',
|
|
17
|
+
'supported',
|
|
18
|
+
'conflicted',
|
|
19
|
+
// Contradicted with nothing on the other side — a disproven claim, not a disputed one. Ported
|
|
20
|
+
// from `evidence/claim_builder.py`'s REJECTED (plan task B.3): the Python distinguished these
|
|
21
|
+
// and this file did not, folding both into 'conflicted'.
|
|
22
|
+
'rejected',
|
|
23
|
+
'invalidated',
|
|
24
|
+
'unknown',
|
|
25
|
+
// Terminal states (FR-001, FR-002). A human decided this claim no longer stands; that decision
|
|
26
|
+
// outranks any later mechanical re-reading of its evidence, which is why `evaluateClaim` returns
|
|
27
|
+
// early for them rather than recomputing.
|
|
28
|
+
'retracted',
|
|
29
|
+
'superseded',
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* States no evidence walk may leave. `evaluateAll()` runs on every `list`/`status`, and
|
|
34
|
+
* `evaluateClaim` otherwise rewrites `status` from the evidence links — so without this set a
|
|
35
|
+
* retraction would be undone by the very next read and the verb would appear to work while doing
|
|
36
|
+
* nothing (design R1).
|
|
37
|
+
*/
|
|
38
|
+
const TERMINAL_CLAIM_STATUSES = new Set(['retracted', 'superseded']);
|
|
39
|
+
|
|
40
|
+
class ClaimsManager {
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {Object} [options]
|
|
52
|
+
* @param {Object} [options.evidenceLedger]
|
|
53
|
+
* @param {string} [options.repoRoot]
|
|
54
|
+
* @param {string} [options.stateDir] a fixed directory; when given, no feature namespace applies
|
|
55
|
+
* @param {string} [options.slug] feature whose namespace the records live under (see task-scope.js)
|
|
56
|
+
* @param {Object} [options.fsImpl]
|
|
57
|
+
*/
|
|
58
|
+
constructor(options = {}) {
|
|
59
|
+
this.fsImpl = options.fsImpl || fs;
|
|
60
|
+
this.evidenceLedger = options.evidenceLedger || null;
|
|
61
|
+
this.repoRoot = options.repoRoot || REPO_ROOT;
|
|
62
|
+
this.fixedStateDir = options.stateDir || null;
|
|
63
|
+
this.slug = options.slug || null;
|
|
64
|
+
this.stateDir = this.fixedStateDir || path.join(this.repoRoot, '.doflow', 'state', 'evidence');
|
|
65
|
+
this.claimsMap = new Map();
|
|
66
|
+
this.baseline = new Map();
|
|
67
|
+
this.seq = 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Where this task's claims file lives: beside its evidence, in the feature's namespace when it has one. */
|
|
71
|
+
fileFor(taskId ) {
|
|
72
|
+
const dir = this.fixedStateDir
|
|
73
|
+
|| taskStoreDir({ projectRoot: this.repoRoot, store: 'evidence', taskId, slug: this.slug });
|
|
74
|
+
return path.join(dir, `${assertSafeTaskId(taskId)}_claims.json`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
generateId() {
|
|
78
|
+
// Cross-instance unique, same reasoning as EvidenceLedger.generateId: ids key the merge in
|
|
79
|
+
// save(), so a same-millisecond collision between two sessions silently merges two claims.
|
|
80
|
+
this.seq += 1;
|
|
81
|
+
return `claim_${Date.now().toString(36)}_${crypto.randomBytes(4).toString('hex')}_${this.seq.toString(36)}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Registers a new proposition as a claim.
|
|
86
|
+
* Agent inferences start strictly in 'hypothesis' status.
|
|
87
|
+
* @param {Object} item - { statement, taskId, status, id, role }
|
|
88
|
+
* @returns {string} claimId
|
|
89
|
+
*/
|
|
90
|
+
addClaim(item ) {
|
|
91
|
+
if (!item || typeof item !== 'object') {
|
|
92
|
+
throw new Error('Claim item must be an object');
|
|
93
|
+
}
|
|
94
|
+
if (!item.statement || typeof item.statement !== 'string') {
|
|
95
|
+
throw new Error('Claim requires a non-empty statement');
|
|
96
|
+
}
|
|
97
|
+
// The claim's relationship to the task, e.g. 'root-cause'. A readiness template can require a
|
|
98
|
+
// role, so a supported-but-unrelated claim cannot satisfy a requirement it never addressed.
|
|
99
|
+
if (item.role !== undefined && !/^[a-z][a-z0-9-]*$/.test(String(item.role))) {
|
|
100
|
+
throw new Error(`Claim role '${item.role}' must be a lowercase-kebab token, e.g. 'root-cause'`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const id = item.id || this.generateId();
|
|
104
|
+
const taskId = item.taskId || 'default';
|
|
105
|
+
const status = item.status && CLAIM_STATUSES.has(item.status) ? item.status : 'hypothesis';
|
|
106
|
+
|
|
107
|
+
const claimRecord = {
|
|
108
|
+
id,
|
|
109
|
+
taskId,
|
|
110
|
+
statement: item.statement,
|
|
111
|
+
role: item.role || null,
|
|
112
|
+
status,
|
|
113
|
+
supportingEvidence: Array.isArray(item.supportingEvidence) ? [...item.supportingEvidence] : [],
|
|
114
|
+
contradictingEvidence: Array.isArray(item.contradictingEvidence) ? [...item.contradictingEvidence] : [],
|
|
115
|
+
createdAt: item.createdAt || new Date().toISOString(),
|
|
116
|
+
updatedAt: new Date().toISOString(),
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
this.claimsMap.set(id, claimRecord);
|
|
120
|
+
return id;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Retrieves a claim by ID.
|
|
125
|
+
* @param {string} id
|
|
126
|
+
* @returns {Object|null}
|
|
127
|
+
*/
|
|
128
|
+
getClaim(id ) {
|
|
129
|
+
return this.claimsMap.get(id) || null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Links an evidence item to a claim.
|
|
134
|
+
* @param {string} claimId
|
|
135
|
+
* @param {string} evidenceId
|
|
136
|
+
* @param {'supports'|'contradicts'} [relation='supports']
|
|
137
|
+
*/
|
|
138
|
+
linkEvidence(claimId , evidenceId , relation = 'supports') {
|
|
139
|
+
const claim = this.claimsMap.get(claimId);
|
|
140
|
+
if (!claim) {
|
|
141
|
+
throw new Error(`Unknown claim '${claimId}'`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (relation === 'supports') {
|
|
145
|
+
if (!claim.supportingEvidence.includes(evidenceId)) {
|
|
146
|
+
claim.supportingEvidence.push(evidenceId);
|
|
147
|
+
}
|
|
148
|
+
} else if (relation === 'contradicts') {
|
|
149
|
+
if (!claim.contradictingEvidence.includes(evidenceId)) {
|
|
150
|
+
claim.contradictingEvidence.push(evidenceId);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
throw new Error(`Invalid evidence relation '${relation}'. Allowed: supports, contradicts`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Bidirectionally update evidence if ledger attached
|
|
157
|
+
if (this.evidenceLedger) {
|
|
158
|
+
const evidence = this.evidenceLedger.getEvidence(evidenceId);
|
|
159
|
+
if (evidence) {
|
|
160
|
+
if (relation === 'supports' && !evidence.supports.includes(claimId)) {
|
|
161
|
+
evidence.supports.push(claimId);
|
|
162
|
+
} else if (relation === 'contradicts' && !evidence.contradicts.includes(claimId)) {
|
|
163
|
+
evidence.contradicts.push(claimId);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
claim.updatedAt = new Date().toISOString();
|
|
169
|
+
return this.evaluateClaim(claimId);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Evaluates the epistemic state of a claim based on evidence availability and freshness.
|
|
174
|
+
* @param {string} claimId
|
|
175
|
+
* @returns {'hypothesis'|'supported'|'conflicted'|'invalidated'|'unknown'}
|
|
176
|
+
*/
|
|
177
|
+
evaluateClaim(claimId ) {
|
|
178
|
+
const claim = this.claimsMap.get(claimId);
|
|
179
|
+
if (!claim) {
|
|
180
|
+
throw new Error(`Unknown claim '${claimId}'`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// A terminal state is a recorded human decision, not a reading of evidence. Recomputing it here
|
|
184
|
+
// would silently resurrect a retracted claim on the next list (design R1).
|
|
185
|
+
if (TERMINAL_CLAIM_STATUSES.has(claim.status)) {
|
|
186
|
+
return claim.status;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// If no evidence attached, remains a hypothesis
|
|
190
|
+
if (claim.supportingEvidence.length === 0 && claim.contradictingEvidence.length === 0) {
|
|
191
|
+
claim.status = 'hypothesis';
|
|
192
|
+
return claim.status;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let hasFreshSupport = false;
|
|
196
|
+
let hasFreshContradiction = false;
|
|
197
|
+
let hasStaleSupport = false;
|
|
198
|
+
|
|
199
|
+
for (const evId of claim.supportingEvidence) {
|
|
200
|
+
const ev = this.evidenceLedger ? this.evidenceLedger.getEvidence(evId) : null;
|
|
201
|
+
if (!ev || ev.freshness?.status === 'STALE') {
|
|
202
|
+
hasStaleSupport = true;
|
|
203
|
+
} else {
|
|
204
|
+
hasFreshSupport = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const evId of claim.contradictingEvidence) {
|
|
209
|
+
const ev = this.evidenceLedger ? this.evidenceLedger.getEvidence(evId) : null;
|
|
210
|
+
if (ev && ev.freshness?.status !== 'STALE') {
|
|
211
|
+
hasFreshContradiction = true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (hasFreshContradiction) {
|
|
216
|
+
// 'conflicted' means evidence disagrees and a human must reconcile it; 'rejected' means the
|
|
217
|
+
// evidence agrees and the claim is false. Collapsing the second into the first reported a
|
|
218
|
+
// dispute where none existed, and made the readiness gate block on a question already
|
|
219
|
+
// settled. Support that has merely gone stale still counts as support, so a claim that once
|
|
220
|
+
// had backing stays 'conflicted' rather than being declared false on a technicality.
|
|
221
|
+
claim.status = claim.supportingEvidence.length === 0 ? 'rejected' : 'conflicted';
|
|
222
|
+
} else if (hasFreshSupport) {
|
|
223
|
+
claim.status = 'supported';
|
|
224
|
+
} else if (hasStaleSupport && !hasFreshSupport) {
|
|
225
|
+
claim.status = 'invalidated';
|
|
226
|
+
} else {
|
|
227
|
+
claim.status = 'hypothesis';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
claim.updatedAt = new Date().toISOString();
|
|
231
|
+
return claim.status;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Moves a claim to a terminal state, leaving the record and its evidence links untouched.
|
|
236
|
+
* Shared by retract and supersede so the two cannot drift on what "terminal" means.
|
|
237
|
+
* @param {string} claimId
|
|
238
|
+
* @param {'retracted'|'superseded'} status
|
|
239
|
+
* @param {string} [supersededBy]
|
|
240
|
+
* @returns {string} the new status
|
|
241
|
+
*/
|
|
242
|
+
finalizeClaim(claimId , status , supersededBy ) {
|
|
243
|
+
const claim = this.claimsMap.get(claimId);
|
|
244
|
+
if (!claim) {
|
|
245
|
+
throw new Error(`Unknown claim '${claimId}'`);
|
|
246
|
+
}
|
|
247
|
+
if (TERMINAL_CLAIM_STATUSES.has(claim.status)) {
|
|
248
|
+
throw new Error(`Claim '${claimId}' is already '${claim.status}' and cannot be changed again`);
|
|
249
|
+
}
|
|
250
|
+
claim.status = status;
|
|
251
|
+
claim.terminalAt = new Date().toISOString();
|
|
252
|
+
if (supersededBy) claim.supersededBy = supersededBy;
|
|
253
|
+
claim.updatedAt = claim.terminalAt;
|
|
254
|
+
return claim.status;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Records that a claim no longer holds. Nothing is deleted (NFR-003): retraction records that a
|
|
259
|
+
* conclusion was withdrawn, not that it was never drawn.
|
|
260
|
+
* @param {string} claimId
|
|
261
|
+
* @returns {string} the new status
|
|
262
|
+
*/
|
|
263
|
+
retractClaim(claimId ) {
|
|
264
|
+
return this.finalizeClaim(claimId, 'retracted');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Records that a claim was replaced by another, with a forward pointer to it.
|
|
269
|
+
*
|
|
270
|
+
* The replacement must already exist. A pointer to an unrecorded id is worse than no pointer, and
|
|
271
|
+
* this refusal mirrors the one `link` already makes for unrecorded evidence.
|
|
272
|
+
* @param {string} claimId
|
|
273
|
+
* @param {string} replacedBy
|
|
274
|
+
* @returns {string} the new status
|
|
275
|
+
*/
|
|
276
|
+
supersedeClaim(claimId , replacedBy ) {
|
|
277
|
+
// The target is checked first: validating the replacement before the claim being superseded
|
|
278
|
+
// reported a missing replacement when the caller had actually mistyped the target, sending them
|
|
279
|
+
// to fix the wrong id.
|
|
280
|
+
if (!this.claimsMap.has(claimId)) {
|
|
281
|
+
throw new Error(`Unknown claim '${claimId}'`);
|
|
282
|
+
}
|
|
283
|
+
if (!replacedBy) {
|
|
284
|
+
throw new Error('supersede requires the id of the claim that replaces this one');
|
|
285
|
+
}
|
|
286
|
+
if (replacedBy === claimId) {
|
|
287
|
+
throw new Error(`Claim '${claimId}' cannot supersede itself`);
|
|
288
|
+
}
|
|
289
|
+
if (!this.claimsMap.has(replacedBy)) {
|
|
290
|
+
throw new Error(`No claim '${replacedBy}' is recorded — a forward pointer to nothing is worse `
|
|
291
|
+
+ 'than no pointer. Record the replacing claim first: doflow claim --action add --statement ...');
|
|
292
|
+
}
|
|
293
|
+
return this.finalizeClaim(claimId, 'superseded', replacedBy);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Evaluates all claims in memory.
|
|
298
|
+
*/
|
|
299
|
+
evaluateAll() {
|
|
300
|
+
for (const claimId of this.claimsMap.keys()) {
|
|
301
|
+
this.evaluateClaim(claimId);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Queries claims for a specific task.
|
|
307
|
+
* @param {string} [taskId]
|
|
308
|
+
* @returns {Array<Object>}
|
|
309
|
+
*/
|
|
310
|
+
getClaims(taskId ) {
|
|
311
|
+
const results = [];
|
|
312
|
+
for (const claim of this.claimsMap.values()) {
|
|
313
|
+
if (!taskId || claim.taskId === taskId) {
|
|
314
|
+
results.push(claim);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return results;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Persists claims to disk.
|
|
322
|
+
* @param {string} [taskId='default']
|
|
323
|
+
* @returns {string} filePath
|
|
324
|
+
*/
|
|
325
|
+
save(taskId = 'default') {
|
|
326
|
+
const targetFile = this.fileFor(taskId);
|
|
327
|
+
let merged ;
|
|
328
|
+
const file = updateTaskState({
|
|
329
|
+
fsImpl: this.fsImpl,
|
|
330
|
+
file: targetFile,
|
|
331
|
+
build: (disk ) => {
|
|
332
|
+
merged = mergeRecords(this.getClaims(taskId), disk?.claims || [], this.baseline);
|
|
333
|
+
return { taskId, updatedAt: new Date().toISOString(), claimsCount: merged.length, claims: merged };
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
for (const item of merged) {
|
|
337
|
+
this.claimsMap.set(item.id, item);
|
|
338
|
+
this.baseline.set(item.id, JSON.parse(JSON.stringify(item)));
|
|
339
|
+
}
|
|
340
|
+
return file;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Loads claims from disk.
|
|
345
|
+
* @param {string} [taskId='default']
|
|
346
|
+
* @returns {number}
|
|
347
|
+
*/
|
|
348
|
+
load(taskId = 'default') {
|
|
349
|
+
const targetFile = this.fileFor(taskId);
|
|
350
|
+
const data = readTaskState(this.fsImpl, targetFile);
|
|
351
|
+
if (data && Array.isArray(data.claims)) {
|
|
352
|
+
for (const item of data.claims) {
|
|
353
|
+
this.claimsMap.set(item.id, item);
|
|
354
|
+
this.baseline.set(item.id, JSON.parse(JSON.stringify(item)));
|
|
355
|
+
}
|
|
356
|
+
return data.claims.length;
|
|
357
|
+
}
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
clear() {
|
|
362
|
+
this.claimsMap.clear();
|
|
363
|
+
this.baseline.clear();
|
|
364
|
+
this.seq = 0;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Handles `doflow claim` — record a proposition, link evidence to it, or list what is recorded.
|
|
370
|
+
*
|
|
371
|
+
* A claim added here starts as a hypothesis and can only become `supported` through linked
|
|
372
|
+
* evidence (FR-007); this handler exposes no way to declare one supported directly, because a
|
|
373
|
+
* conclusion that becomes fact by assertion is the thing the claims ledger exists to prevent.
|
|
374
|
+
*
|
|
375
|
+
* @param {Object} options
|
|
376
|
+
* @param {string} options.taskId
|
|
377
|
+
* @param {'list'|'add'|'link'|'retract'|'supersede'} [options.action='list']
|
|
378
|
+
* @param {string} [options.statement] `add`
|
|
379
|
+
* @param {string} [options.claimId] `link`
|
|
380
|
+
* @param {string} [options.evidenceId] `link`
|
|
381
|
+
* @param {string} [options.replacedBy] `supersede`: the claim that replaces this one
|
|
382
|
+
* @param {string} [options.relation='supports'] `link`
|
|
383
|
+
* @param {boolean} [options.json=false]
|
|
384
|
+
* @param {string} [options.stateRoot]
|
|
385
|
+
* @param {string} [options.slug] feature the task belongs to, when not the branch's
|
|
386
|
+
* @returns {number} exit code
|
|
387
|
+
*/
|
|
388
|
+
function handleClaimCommand({ taskId, action = 'list', statement, claimId, evidenceId, replacedBy, relation = 'supports', role, json = false, stateRoot, slug } = {}) {
|
|
389
|
+
const root = stateRoot || process.cwd();
|
|
390
|
+
const ledger = new EvidenceLedger({ repoRoot: root, slug });
|
|
391
|
+
ledger.load(taskId);
|
|
392
|
+
const claims = new ClaimsManager({ evidenceLedger: ledger, repoRoot: root, slug });
|
|
393
|
+
claims.load(taskId);
|
|
394
|
+
|
|
395
|
+
let result;
|
|
396
|
+
try {
|
|
397
|
+
if (action === 'add') {
|
|
398
|
+
if (typeof statement !== 'string' || statement.trim() === '') {
|
|
399
|
+
return usageError('claim', '--statement is required for --action add', json);
|
|
400
|
+
}
|
|
401
|
+
const id = claims.addClaim({ statement, taskId, role });
|
|
402
|
+
claims.save(taskId);
|
|
403
|
+
result = { action, taskId, claim: claims.getClaim(id) };
|
|
404
|
+
} else if (action === 'link') {
|
|
405
|
+
if (!claimId || !evidenceId) {
|
|
406
|
+
return usageError('claim', '--claim-id and --evidence-id are both required for --action link', json);
|
|
407
|
+
}
|
|
408
|
+
// Linking an id the ledger does not hold used to succeed. `evaluateClaim` reads a missing
|
|
409
|
+
// evidence item as *stale* support and returns `invalidated` — a verdict about evidence
|
|
410
|
+
// that was never recorded, and the reading that made C.5 conclude `conflicted` (and so
|
|
411
|
+
// `BLOCKED`) was unreachable through the seam. Refuse instead of grading.
|
|
412
|
+
if (!ledger.getEvidence(evidenceId)) {
|
|
413
|
+
return usageError('claim', `no evidence '${evidenceId}' is recorded for task '${taskId}' — linking it would `
|
|
414
|
+
+ 'mark the claim `invalidated` on the strength of an item that does not exist. Record it first: '
|
|
415
|
+
+ `doflow evidence --task-id ${taskId} --action add ...`, json);
|
|
416
|
+
}
|
|
417
|
+
const status = claims.linkEvidence(claimId, evidenceId, relation);
|
|
418
|
+
claims.save(taskId);
|
|
419
|
+
result = { action, taskId, claim: claims.getClaim(claimId), status };
|
|
420
|
+
} else if (action === 'retract') {
|
|
421
|
+
if (!claimId) {
|
|
422
|
+
return usageError('claim', '--claim-id is required for --action retract', json);
|
|
423
|
+
}
|
|
424
|
+
const status = claims.retractClaim(claimId);
|
|
425
|
+
claims.save(taskId);
|
|
426
|
+
result = { action, taskId, claim: claims.getClaim(claimId), status };
|
|
427
|
+
} else if (action === 'supersede') {
|
|
428
|
+
if (!claimId || !replacedBy) {
|
|
429
|
+
return usageError('claim', '--claim-id and --replaced-by are both required for --action supersede', json);
|
|
430
|
+
}
|
|
431
|
+
const status = claims.supersedeClaim(claimId, replacedBy);
|
|
432
|
+
claims.save(taskId);
|
|
433
|
+
result = { action, taskId, claim: claims.getClaim(claimId), status };
|
|
434
|
+
} else if (action === 'list' || action === 'status') {
|
|
435
|
+
claims.evaluateAll();
|
|
436
|
+
result = { action: 'list', taskId, claims: claims.getClaims(taskId) };
|
|
437
|
+
} else {
|
|
438
|
+
return usageError('claim', `unknown --action '${action}'. Valid: list, add, link, retract, supersede`, json);
|
|
439
|
+
}
|
|
440
|
+
} catch (error ) {
|
|
441
|
+
return usageError('claim', error.message, json, error);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (json) { console.log(JSON.stringify(result, null, 2)); }
|
|
445
|
+
else {
|
|
446
|
+
const rows = result.claims || [result.claim];
|
|
447
|
+
console.log(`\nDoFlow Claims [Task: ${taskId}]:`);
|
|
448
|
+
console.log('═'.repeat(78));
|
|
449
|
+
if (rows.length === 0) console.log('No claims recorded for this task.');
|
|
450
|
+
else {
|
|
451
|
+
console.log('ID'.padEnd(24) + 'Status'.padEnd(14) + 'Statement');
|
|
452
|
+
console.log('─'.repeat(78));
|
|
453
|
+
for (const claim of rows) {
|
|
454
|
+
const suffix = claim.supersededBy ? ` → ${claim.supersededBy}` : '';
|
|
455
|
+
console.log(claim.id.padEnd(24) + (claim.status + suffix).padEnd(14) + claim.statement);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
console.log('═'.repeat(78) + '\n');
|
|
459
|
+
}
|
|
460
|
+
return finishRuntime(0);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
module.exports = {
|
|
464
|
+
ClaimsManager,
|
|
465
|
+
CLAIM_STATUSES,
|
|
466
|
+
TERMINAL_CLAIM_STATUSES,
|
|
467
|
+
handleClaimCommand,
|
|
468
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CLI exit and error reporting for runtime verb handlers. These presentation helpers are being
|
|
7
|
+
* factored out as verb handlers move from bin/doflow.js into engine modules. Homed here rather
|
|
8
|
+
* than in cli.js to avoid import cycles, since cli.js already requires claims.js and claims.js
|
|
9
|
+
* is gaining handleClaimCommand. This module requires nothing from src/runtime/ at load time — that
|
|
10
|
+
* is its defining constraint; the failure writer is required lazily, inside the one call that uses
|
|
11
|
+
* it, and requires only the mask module.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sets the process exit code.
|
|
16
|
+
* @param {number} code
|
|
17
|
+
* @returns {number} the code, for chaining
|
|
18
|
+
*/
|
|
19
|
+
function finishRuntime(code ) {
|
|
20
|
+
process.exitCode = code;
|
|
21
|
+
return code;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Records a caught error in the failure store when it is a programming error (IC-010), silently and
|
|
26
|
+
* without changing anything the caller prints or exits with. For a handler that catches an error and
|
|
27
|
+
* reports it itself, so a bug in DoFlow is not swallowed by its own `[ERROR]` line.
|
|
28
|
+
* @param {*} error
|
|
29
|
+
* @param {string} command the verb or installer command name
|
|
30
|
+
* @param {number} exit the exit status the caller is about to produce
|
|
31
|
+
*/
|
|
32
|
+
function captureCaught(error , command , exit ) {
|
|
33
|
+
try { require('./failure/capture.js').captureError(error, { command, exit }); } catch { /* capture is best-effort */ }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Reports an argument the CLI cannot proceed without, in the caller's requested shape.
|
|
38
|
+
*
|
|
39
|
+
* `error` is the thrown error a catch site is turning into this usage result. When it is a
|
|
40
|
+
* programming error (IC-010) it is also recorded in the failure store, silently; the output and
|
|
41
|
+
* the exit status are the same either way (IC-016).
|
|
42
|
+
* @param {string} verb
|
|
43
|
+
* @param {string} message
|
|
44
|
+
* @param {boolean} [json]
|
|
45
|
+
* @param {Error} [error]
|
|
46
|
+
* @returns {number} 2 (USAGE error exit code)
|
|
47
|
+
*/
|
|
48
|
+
function usageError(verb , message , json , error ) {
|
|
49
|
+
if (error !== undefined) captureCaught(error, verb, 2);
|
|
50
|
+
if (json) console.log(JSON.stringify({ ok: false, status: 'USAGE', exitCode: 2, error: 'usage', summary: message }, null, 2));
|
|
51
|
+
else console.error(`doflow ${verb}: ${message}`);
|
|
52
|
+
return finishRuntime(2);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { finishRuntime, usageError, captureCaught };
|