@khoavu882/doflow 0.0.0-stage → 2.0.0-beta.3
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 +1057 -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 +46 -4
- package/src/adapters/antigravity/index.ts +631 -0
- package/src/adapters/claude/index.ts +548 -0
- package/src/adapters/claude/mcp.ts +94 -0
- package/src/adapters/codex/agents.ts +208 -0
- package/src/adapters/codex/config.ts +272 -0
- package/src/adapters/codex/hooks.ts +203 -0
- package/src/adapters/codex/index.ts +707 -0
- package/src/adapters/codex/mcp.ts +271 -0
- package/src/adapters/codex/native-projection.ts +34 -0
- package/src/adapters/copilot/index.ts +413 -0
- package/src/adapters/copy-tree.ts +620 -0
- package/src/adapters/gemini/hooks.ts +210 -0
- package/src/adapters/gemini/index.ts +390 -0
- package/src/adapters/hook-commands.ts +60 -0
- package/src/adapters/index.ts +106 -0
- package/src/adapters/kiro/index.ts +310 -0
- package/src/adapters/mcp-entries.ts +331 -0
- package/src/adapters/opencode/index.ts +466 -0
- package/src/adapters/pi/index.ts +279 -0
- package/src/adapters/pi/json-members.ts +185 -0
- package/src/adapters/pi/mcp.ts +373 -0
- package/src/adapters/resolve-source.ts +19 -0
- package/src/cli/commands/install.ts +218 -0
- package/src/cli/commands/list-backups.ts +21 -0
- package/src/cli/commands/reconcile.ts +120 -0
- package/src/cli/commands/remove.ts +82 -0
- package/src/cli/commands/rollback.ts +172 -0
- package/src/cli/commands/self-update.ts +33 -0
- package/src/cli/commands/status.ts +138 -0
- package/src/cli/commands/tools.ts +92 -0
- package/src/cli/commands/update.ts +162 -0
- package/src/cli/index.ts +568 -0
- package/src/cli/runtime-commands.ts +281 -0
- package/src/cli/shared.ts +218 -0
- package/src/helper/bash-helper.ts +34 -0
- package/src/helper/git.ts +24 -0
- package/src/helper/guardrails.ts +49 -0
- package/src/helper/harness-paths.ts +140 -0
- package/src/helper/marker-merge.ts +116 -0
- package/src/helper/prompt.ts +61 -0
- package/src/helper/repo-root.ts +29 -0
- package/src/helper/settings-merge.ts +151 -0
- package/src/helper/settings-scope.ts +33 -0
- package/src/helper/toml.ts +244 -0
- package/src/install/backup-set.ts +149 -0
- package/src/install/backup.ts +724 -0
- package/src/install/context.ts +58 -0
- package/src/install/manifest.ts +145 -0
- package/src/install/mcp.ts +254 -0
- package/src/install/paths.ts +84 -0
- package/src/install/targets.ts +90 -0
- package/src/install/tool-lifecycle.ts +151 -0
- package/src/lifecycle/bash-availability.ts +25 -0
- package/src/lifecycle/index.ts +812 -0
- package/src/lifecycle/mcp-index.ts +28 -0
- package/src/lifecycle/policies.ts +73 -0
- package/src/lifecycle/view.ts +175 -0
- package/src/registry/index.ts +611 -0
- package/src/release/sync-plugin-versions.ts +66 -0
- package/src/runtime/advice/cli.ts +283 -0
- package/src/runtime/advice/client.ts +324 -0
- package/src/runtime/advice/config.ts +189 -0
- package/src/runtime/advice/doctor.ts +169 -0
- package/src/runtime/advice/endpoint-guard.ts +134 -0
- package/src/runtime/advice/kinds.ts +154 -0
- package/src/runtime/advice/providers/ollama-systemone.ts +209 -0
- package/src/runtime/advice/record.ts +166 -0
- package/src/runtime/advice/registry.ts +170 -0
- package/src/runtime/advice/strength.ts +66 -0
- package/src/runtime/brief-tools.ts +342 -0
- package/src/runtime/c4-project.ts +371 -0
- package/src/runtime/capability-router.ts +484 -0
- package/src/runtime/checkouts.ts +170 -0
- package/src/runtime/claims.ts +468 -0
- package/src/runtime/cli-result.ts +55 -0
- package/src/runtime/cli.ts +678 -0
- package/src/runtime/command-detect.ts +516 -0
- package/src/runtime/context-pack.ts +492 -0
- package/src/runtime/decision-register.ts +493 -0
- package/src/runtime/evidence-ledger.ts +338 -0
- package/src/runtime/failure/capture.ts +272 -0
- package/src/runtime/failure/classifier.ts +68 -0
- package/src/runtime/failure/cli.ts +178 -0
- package/src/runtime/failure/home.ts +64 -0
- package/src/runtime/failure/store.ts +226 -0
- package/src/runtime/feature-resolve.ts +79 -0
- package/src/runtime/freshness.ts +177 -0
- package/src/runtime/health.ts +863 -0
- package/src/runtime/history-compactor.ts +237 -0
- package/src/runtime/implementation-gate.ts +321 -0
- package/src/runtime/inventory/coverage.ts +218 -0
- package/src/runtime/inventory/identity.ts +65 -0
- package/src/runtime/inventory/index.ts +705 -0
- package/src/runtime/inventory/precedence.ts +134 -0
- package/src/runtime/inventory/read-scopes.ts +131 -0
- package/src/runtime/inventory/siblings.ts +192 -0
- package/src/runtime/knowledge/chunker.ts +124 -0
- package/src/runtime/knowledge/hybrid.ts +149 -0
- package/src/runtime/knowledge/index-store.ts +145 -0
- package/src/runtime/knowledge/retrieval.ts +194 -0
- package/src/runtime/leak-scan.ts +185 -0
- package/src/runtime/lifecycle/cli.ts +276 -0
- package/src/runtime/lifecycle/event-store.ts +340 -0
- package/src/runtime/lifecycle/fold.ts +353 -0
- package/src/runtime/lifecycle/followup.ts +432 -0
- package/src/runtime/lifecycle/goal.ts +249 -0
- package/src/runtime/lifecycle/intent-writer.ts +86 -0
- package/src/runtime/lifecycle/overview.ts +292 -0
- package/src/runtime/lifecycle/release.ts +241 -0
- package/src/runtime/lifecycle/report-store.ts +221 -0
- package/src/runtime/lifecycle/retention.ts +212 -0
- package/src/runtime/lifecycle/root.ts +71 -0
- package/src/runtime/lifecycle/status.ts +353 -0
- package/src/runtime/lifecycle/store-upkeep.ts +393 -0
- package/src/runtime/locator-resolve.ts +158 -0
- package/src/runtime/mask.ts +210 -0
- package/src/runtime/mcp-consultations.ts +412 -0
- package/src/runtime/mcp-reach.ts +157 -0
- package/src/runtime/model-router.ts +153 -0
- package/src/runtime/outcome.ts +467 -0
- package/src/runtime/reach.ts +148 -0
- package/src/runtime/readiness-record.ts +150 -0
- package/src/runtime/readiness.ts +435 -0
- package/src/runtime/recovery.ts +282 -0
- package/src/runtime/research-request.ts +231 -0
- package/src/runtime/retrieval-plan.ts +578 -0
- package/src/runtime/scaffold/artifacts.ts +217 -0
- package/src/runtime/scaffold/fingerprint.ts +56 -0
- package/src/runtime/scaffold/generate.ts +911 -0
- package/src/runtime/scaffold/languages.ts +245 -0
- package/src/runtime/storage/cli.ts +64 -0
- package/src/runtime/storage/engine.ts +249 -0
- package/src/runtime/storage/registry.ts +130 -0
- package/src/runtime/storage/roots.ts +63 -0
- package/src/runtime/storage/rules.ts +282 -0
- package/src/runtime/storage/upkeep.ts +243 -0
- package/src/runtime/storage/work-status.ts +326 -0
- package/src/runtime/task-attempts.ts +415 -0
- package/src/runtime/task-classifier.ts +550 -0
- package/src/runtime/task-scope.ts +130 -0
- package/src/runtime/task-state.ts +176 -0
- package/src/runtime/trace/indicators.ts +235 -0
- package/src/runtime/trace/ledger.ts +626 -0
- package/src/runtime/trace/render.ts +76 -0
- package/src/runtime/trace/views.ts +459 -0
- package/src/runtime/verification/contract-runner.ts +341 -0
- package/src/runtime/verification/engine.ts +1461 -0
- package/src/runtime/verification/registry.ts +130 -0
- package/src/runtime/verification/scope-bound.ts +418 -0
- package/src/runtime/verification/test-selection.ts +172 -0
- package/src/runtime/workflow-engine.ts +588 -0
- package/src/runtime/workflow-orchestrator.ts +953 -0
- package/src/runtime/worktree.ts +340 -0
- package/src/state/index.ts +193 -0
- package/src/state/lockfile.ts +136 -0
- package/src/state/run-lock.ts +408 -0
- package/types/node-commonjs.d.ts +68 -0
- package/types/runtime.d.ts +91 -0
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# doflow-run — the single runtime seam every skill calls through.
|
|
3
|
+
#
|
|
4
|
+
# One verb namespace (design.md §4.2), one place that decides whether a verb is served by a
|
|
5
|
+
# shell helper or the Node CLI, and one place that records that a verb ran. Callers never learn
|
|
6
|
+
# which side serves a verb, which is what lets a verb move between them without touching skills.
|
|
7
|
+
#
|
|
8
|
+
# Self-resolution is from this file's own REAL path, symlinks followed — never fixed-depth
|
|
9
|
+
# `../../../..` arithmetic. Its predecessor `doflow.sh` did exactly that: installed at
|
|
10
|
+
# ~/.doflow/scripts/doflow/ it computed a repo root of /Users and every Node-backed verb died
|
|
11
|
+
# with "Cannot find module '/Users/bin/doflow.js'". The same script must answer identically from
|
|
12
|
+
# a source checkout, a project-local `.doflow/`, a global `~/.doflow/`, and from a symlink on
|
|
13
|
+
# PATH pointing at any of them.
|
|
14
|
+
#
|
|
15
|
+
# Usage: doflow-run <verb> [args...]
|
|
16
|
+
# Every verb accepts --json. Exit 0 = success, 1 = an actionable finding, 2 = usage or
|
|
17
|
+
# resolution error. Arguments, stdin and exit status pass through the dispatcher unmodified —
|
|
18
|
+
# `sync-context` reads its block body from stdin, so anything that buffered or consumed it here
|
|
19
|
+
# would break that verb rather than merely inconvenience it.
|
|
20
|
+
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
# ------------------------------------------------------------------------------ failure capture
|
|
24
|
+
|
|
25
|
+
# DoFlow's own failures, recorded on this machine (feature 046, IC-011, IC-014, IC-017). A side
|
|
26
|
+
# channel: it never changes what the dispatcher prints or the status it exits with, never blocks
|
|
27
|
+
# anything, and is silent. It runs in a subshell with all output discarded and ends in `|| true`, so
|
|
28
|
+
# `set -euo pipefail` never stops on it; nothing in it can reach the dispatcher's own options or
|
|
29
|
+
# variables. Appends one JSON line of at most 1000 bytes (longer appends from concurrent writers can
|
|
30
|
+
# interleave) and never rotates: rotation is done by the Node writers only (IC-015, DEC-019). It is
|
|
31
|
+
# a no-op when no failure home can be resolved (HOME unset, or XDG_CONFIG_HOME relative) and while
|
|
32
|
+
# capture is off (the `off` sentinel file wins; DOFLOW_FAILURE_CAPTURE=off|0|false|no also turns it
|
|
33
|
+
# off). The line carries only names from DoFlow's own tables and the working directory: never an
|
|
34
|
+
# argument, stdin or the environment.
|
|
35
|
+
# capture_failure <command> <kind> <exit status>
|
|
36
|
+
CAPTURE_VERB=""
|
|
37
|
+
|
|
38
|
+
capture_failure_write() {
|
|
39
|
+
local command="${1:-}" kind="${2:-}" status="${3:-}"
|
|
40
|
+
local home="" setting="" version="" candidate="" project="" harness="" at="" line="" cwd="" hp=""
|
|
41
|
+
export LC_ALL=C
|
|
42
|
+
|
|
43
|
+
if [ -n "${XDG_CONFIG_HOME:-}" ]; then
|
|
44
|
+
case "$XDG_CONFIG_HOME" in
|
|
45
|
+
/*) home="$XDG_CONFIG_HOME/doflow/failures" ;;
|
|
46
|
+
*) return 0 ;;
|
|
47
|
+
esac
|
|
48
|
+
else
|
|
49
|
+
case "${HOME:-}" in
|
|
50
|
+
/*) home="$HOME/.config/doflow/failures" ;;
|
|
51
|
+
*) return 0 ;;
|
|
52
|
+
esac
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Case-insensitive, whitespace trimmed at the ends only: the same reading the Node writer has.
|
|
56
|
+
setting="$(printf '%s' "${DOFLOW_FAILURE_CAPTURE:-}" | tr '[:upper:]' '[:lower:]')" || return 0
|
|
57
|
+
setting="${setting#"${setting%%[![:space:]]*}"}"
|
|
58
|
+
setting="${setting%"${setting##*[![:space:]]}"}"
|
|
59
|
+
case "$setting" in
|
|
60
|
+
off|0|false|no) return 0 ;;
|
|
61
|
+
esac
|
|
62
|
+
[ -f "$home/off" ] && return 0
|
|
63
|
+
|
|
64
|
+
# The command is a verb the dispatcher has already matched against its own tables, or `dispatcher`.
|
|
65
|
+
[[ "$command" =~ ^[a-z][a-z0-9-]{0,39}$ ]] || command="dispatcher"
|
|
66
|
+
[[ "$kind" =~ ^[A-Za-z][A-Za-z0-9._:-]{0,39}$ ]] || return 0
|
|
67
|
+
[[ "$status" =~ ^[0-9]{1,3}$ ]] || status="null"
|
|
68
|
+
|
|
69
|
+
harness="${DOFLOW_AGENT:-}"
|
|
70
|
+
[[ "$harness" =~ ^[A-Za-z0-9._-]{1,40}$ ]] || harness="none"
|
|
71
|
+
|
|
72
|
+
# script_version of the nearest install manifest: the project install first, then the global one.
|
|
73
|
+
for candidate in "${CONFIG_DIR:-}" "${HOME:-}/.doflow"; do
|
|
74
|
+
[ -n "$candidate" ] && [ -f "$candidate/.install-manifest.json" ] || continue
|
|
75
|
+
version="$(sed -n 's/^[[:space:]]*"script_version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$candidate/.install-manifest.json" | head -n 1)" || version=""
|
|
76
|
+
[ -n "$version" ] && break
|
|
77
|
+
done
|
|
78
|
+
[[ "$version" =~ ^[A-Za-z0-9._+-]{1,40}$ ]] || version="unknown"
|
|
79
|
+
|
|
80
|
+
# The working directory, home prefix written as `~`, cut to 200 bytes, control characters turned
|
|
81
|
+
# into spaces and every quote and backslash escaped, so the line stays one valid JSON string.
|
|
82
|
+
cwd="$(pwd 2>/dev/null)" || cwd=""
|
|
83
|
+
hp="${HOME:-}"
|
|
84
|
+
hp="${hp%/}"
|
|
85
|
+
if [ -n "$hp" ]; then
|
|
86
|
+
case "$cwd" in
|
|
87
|
+
"$hp") cwd="~" ;;
|
|
88
|
+
"$hp"/*) cwd="~${cwd#"$hp"}" ;;
|
|
89
|
+
esac
|
|
90
|
+
fi
|
|
91
|
+
project="$(printf '%s' "${cwd:0:200}" | tr '\001-\037\177' ' ')" || project=""
|
|
92
|
+
project="${project//\\/\\\\}"
|
|
93
|
+
project="${project//\"/\\\"}"
|
|
94
|
+
|
|
95
|
+
at="$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" || return 0
|
|
96
|
+
line="{\"v\":1,\"at\":\"$at\",\"source\":\"dispatcher\",\"command\":\"$command\",\"harness\":\"$harness\",\"version\":\"$version\",\"project\":\"$project\",\"kind\":\"$kind\",\"message\":\"\",\"frame\":null,\"exit\":$status}"
|
|
97
|
+
if [ "${#line}" -gt 999 ]; then
|
|
98
|
+
line="{\"v\":1,\"at\":\"$at\",\"source\":\"dispatcher\",\"command\":\"$command\",\"harness\":\"$harness\",\"version\":\"$version\",\"project\":\"\",\"kind\":\"$kind\",\"message\":\"\",\"frame\":null,\"exit\":$status}"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
umask 077
|
|
102
|
+
mkdir -p "$home" || return 0
|
|
103
|
+
# Only ever append to a regular file: opening a FIFO for append would block forever.
|
|
104
|
+
[ ! -e "$home/events.jsonl" ] || [ -f "$home/events.jsonl" ] || return 0
|
|
105
|
+
printf '%s\n' "$line" >>"$home/events.jsonl" || return 0
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
capture_failure() {
|
|
109
|
+
( capture_failure_write "$@" ) >/dev/null 2>&1 || true
|
|
110
|
+
return 0
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# After a verb ran: a status outside {0, 1, 2} is a crash worth recording (a signal, a runtime that
|
|
114
|
+
# died), minus what is not DoFlow's fault (DEC-031): 127 (command not found), 130, 141 and 143
|
|
115
|
+
# (interrupted, broken pipe, terminated) and the task-not-found status 3 of `task-brief`. A Node
|
|
116
|
+
# crash exits 1 and is recorded by the CLI itself, so it is never counted twice.
|
|
117
|
+
capture_exit_status() {
|
|
118
|
+
local verb="${1:-}" status="${2:-0}"
|
|
119
|
+
case "$status" in
|
|
120
|
+
0|1|2|127|130|141|143) return 0 ;;
|
|
121
|
+
3) [ "$verb" = "task-brief" ] && return 0 ;;
|
|
122
|
+
esac
|
|
123
|
+
capture_failure "$verb" "exit-$status" "$status"
|
|
124
|
+
return 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# ---------------------------------------------------------------------------- self-resolution
|
|
128
|
+
|
|
129
|
+
# `readlink -f` is GNU-only and arrived late on BSD; resolve the chain by hand so the dispatcher
|
|
130
|
+
# keeps working on the oldest shell we support (macOS bash 3.2). Bounded, because a symlink loop
|
|
131
|
+
# must produce a message rather than hang.
|
|
132
|
+
resolve_real_dir() {
|
|
133
|
+
local src="$1" dir hops=0
|
|
134
|
+
while [ -L "$src" ]; do
|
|
135
|
+
hops=$((hops + 1))
|
|
136
|
+
if [ "$hops" -gt 40 ]; then
|
|
137
|
+
capture_failure "dispatcher" "symlink-loop" 2
|
|
138
|
+
printf 'doflow-run: symlink loop resolving %s\n' "$1" >&2
|
|
139
|
+
exit 2
|
|
140
|
+
fi
|
|
141
|
+
dir="$(cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd)"
|
|
142
|
+
src="$(readlink "$src")"
|
|
143
|
+
case "$src" in
|
|
144
|
+
/*) ;;
|
|
145
|
+
*) src="$dir/$src" ;;
|
|
146
|
+
esac
|
|
147
|
+
done
|
|
148
|
+
cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
SCRIPT_DIR="$(resolve_real_dir "${BASH_SOURCE[0]}")"
|
|
152
|
+
|
|
153
|
+
# The install root that owns state. Mirrors the locator's resolution order (design.md §4.1) so a
|
|
154
|
+
# verb dispatched inside a project records against that project, not against wherever the
|
|
155
|
+
# dispatcher itself happens to live.
|
|
156
|
+
resolve_config_dir() {
|
|
157
|
+
local dir
|
|
158
|
+
if [ -n "${DOFLOW_CONFIG_DIR:-}" ]; then
|
|
159
|
+
printf '%s' "$DOFLOW_CONFIG_DIR"
|
|
160
|
+
return 0
|
|
161
|
+
fi
|
|
162
|
+
dir="$(pwd -P 2>/dev/null || pwd)"
|
|
163
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
164
|
+
if [ -d "$dir/.doflow" ]; then
|
|
165
|
+
printf '%s' "$dir/.doflow"
|
|
166
|
+
return 0
|
|
167
|
+
fi
|
|
168
|
+
dir="$(dirname "$dir")"
|
|
169
|
+
done
|
|
170
|
+
# No project install above the caller: fall back to the install this dispatcher was copied
|
|
171
|
+
# into, and only then to the global one.
|
|
172
|
+
case "$SCRIPT_DIR" in
|
|
173
|
+
*/.doflow/*) printf '%s' "${SCRIPT_DIR%%/.doflow/*}/.doflow"; return 0 ;;
|
|
174
|
+
esac
|
|
175
|
+
printf '%s' "${HOME:-.}/.doflow"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
CONFIG_DIR="$(resolve_config_dir)"
|
|
179
|
+
|
|
180
|
+
# Shell helpers sit beside this file in every shape shipped today (`.../doflow/bin` next to
|
|
181
|
+
# `.../doflow/bash`); the third candidate covers the dispatcher being relocated to `<config>/bin`
|
|
182
|
+
# without the helpers moving with it.
|
|
183
|
+
resolve_bash_dir() {
|
|
184
|
+
local candidate
|
|
185
|
+
for candidate in \
|
|
186
|
+
"$SCRIPT_DIR/../bash" \
|
|
187
|
+
"$SCRIPT_DIR/bash" \
|
|
188
|
+
"$CONFIG_DIR/scripts/doflow/bash"
|
|
189
|
+
do
|
|
190
|
+
if [ -d "$candidate" ]; then
|
|
191
|
+
(cd -P "$candidate" >/dev/null 2>&1 && pwd)
|
|
192
|
+
return 0
|
|
193
|
+
fi
|
|
194
|
+
done
|
|
195
|
+
return 1
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# A directory is the package root when it holds the CLI this dispatcher would exec AND a
|
|
199
|
+
# package.json claiming the doflow name — `bin/doflow.js` alone would happily match an unrelated
|
|
200
|
+
# project the install happens to sit inside.
|
|
201
|
+
is_package_root() {
|
|
202
|
+
[ -f "$1/bin/doflow.js" ] &&
|
|
203
|
+
[ -f "$1/package.json" ] &&
|
|
204
|
+
grep -q '"name"[[:space:]]*:[[:space:]]*"[^"]*doflow"' "$1/package.json" 2>/dev/null
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Deliberately looser than is_package_root — no package.json check at all. Answers only "does a
|
|
208
|
+
# file literally named bin/doflow.js exist above $PWD or $SCRIPT_DIR", used exclusively to shape
|
|
209
|
+
# the exhaustion-time diagnostic in dispatch_node once every real resolution path in
|
|
210
|
+
# resolve_node_cli has already failed (design.md R3). A strict check here would rarely fire in
|
|
211
|
+
# that situation — after resolve_node_cli's own $PWD/$SCRIPT_DIR walk-ups, a directory that passes
|
|
212
|
+
# the strict check would usually have already resolved successfully — so a false positive here
|
|
213
|
+
# costs a slightly-off suggestion, never a wrong program behavior; the message is phrased as a
|
|
214
|
+
# hedge for exactly that reason.
|
|
215
|
+
has_doflow_marker_nearby() {
|
|
216
|
+
local dir start
|
|
217
|
+
for start in "$(pwd -P 2>/dev/null || pwd)" "$SCRIPT_DIR"; do
|
|
218
|
+
dir="$start"
|
|
219
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
220
|
+
if [ -f "$dir/bin/doflow.js" ]; then
|
|
221
|
+
printf '%s' "$dir/bin/doflow.js"
|
|
222
|
+
return 0
|
|
223
|
+
fi
|
|
224
|
+
dir="$(dirname "$dir")"
|
|
225
|
+
done
|
|
226
|
+
done
|
|
227
|
+
return 1
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
# Order is most-specific-first: an explicit override, then the checkout this file lives in, then
|
|
231
|
+
# the checkout the caller is standing in, then a project- or global-local projected runtime, then
|
|
232
|
+
# a dependency pinned by the project, then whatever is on PATH. Answers through globals rather
|
|
233
|
+
# than stdout, so a path containing whitespace needs no field separator to survive.
|
|
234
|
+
NODE_CLI_KIND="" # "script" = run with node, "bin" = an executable that runs itself
|
|
235
|
+
NODE_CLI_PATH=""
|
|
236
|
+
NODE_CLI_SOURCE="" # which branch below resolved: override / checkout-script-dir /
|
|
237
|
+
# checkout-pwd / project-runtime / global-runtime / node_modules / path
|
|
238
|
+
resolve_node_cli() {
|
|
239
|
+
local dir project_root global_runtime_cli
|
|
240
|
+
if [ -n "${DOFLOW_CLI:-}" ] && [ -f "$DOFLOW_CLI" ]; then
|
|
241
|
+
NODE_CLI_KIND="script"; NODE_CLI_PATH="$DOFLOW_CLI"; NODE_CLI_SOURCE="override"
|
|
242
|
+
return 0
|
|
243
|
+
fi
|
|
244
|
+
dir="$SCRIPT_DIR"
|
|
245
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
246
|
+
if is_package_root "$dir"; then
|
|
247
|
+
NODE_CLI_KIND="script"; NODE_CLI_PATH="$dir/bin/doflow.js"; NODE_CLI_SOURCE="checkout-script-dir"
|
|
248
|
+
return 0
|
|
249
|
+
fi
|
|
250
|
+
dir="$(dirname "$dir")"
|
|
251
|
+
done
|
|
252
|
+
# Same walk-up, started from where the caller is standing rather than where this dispatcher
|
|
253
|
+
# lives — lets a verb resolve correctly when the dispatcher being run is the global one but the
|
|
254
|
+
# caller is standing inside the actual checkout (e.g. dogfooding without `npm link`).
|
|
255
|
+
dir="$(pwd -P 2>/dev/null || pwd)"
|
|
256
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
257
|
+
if is_package_root "$dir"; then
|
|
258
|
+
NODE_CLI_KIND="script"; NODE_CLI_PATH="$dir/bin/doflow.js"; NODE_CLI_SOURCE="checkout-pwd"
|
|
259
|
+
return 0
|
|
260
|
+
fi
|
|
261
|
+
dir="$(dirname "$dir")"
|
|
262
|
+
done
|
|
263
|
+
# The runtime projected alongside this dispatcher. This is the step that makes Node-backed verbs
|
|
264
|
+
# work for someone who ran `npx @khoavu882/doflow install` and nothing else: npx leaves no package
|
|
265
|
+
# behind, the install directory is not inside a checkout, and nothing lands on PATH — so before
|
|
266
|
+
# the `runtime.*` assets shipped, every Node-backed verb answered `cli-not-found` in every real
|
|
267
|
+
# install while passing in every test, because tests run inside a checkout. Layout under
|
|
268
|
+
# runtime/ mirrors the repo (bin/, src/, core/registry/) so the modules' own
|
|
269
|
+
# `path.resolve(__dirname, '..', '..')` finds the registries without any path rewriting.
|
|
270
|
+
if [ -f "$CONFIG_DIR/runtime/bin/doflow.js" ]; then
|
|
271
|
+
NODE_CLI_KIND="script"; NODE_CLI_PATH="$CONFIG_DIR/runtime/bin/doflow.js"; NODE_CLI_SOURCE="project-runtime"
|
|
272
|
+
return 0
|
|
273
|
+
fi
|
|
274
|
+
# Same runtime layout, but under the global install — covers a project-local `.doflow/` that
|
|
275
|
+
# exists but is only partial (e.g. `state/`/`worktrees/` with no `runtime/` of its own), where
|
|
276
|
+
# CONFIG_DIR resolved to that project rather than to $HOME/.doflow. Skipped when it's the exact
|
|
277
|
+
# same path already tried above (CONFIG_DIR already IS $HOME/.doflow), to avoid a redundant stat.
|
|
278
|
+
global_runtime_cli="${HOME:-}/.doflow/runtime/bin/doflow.js"
|
|
279
|
+
if [ -n "${HOME:-}" ] && [ "$global_runtime_cli" != "$CONFIG_DIR/runtime/bin/doflow.js" ] && [ -f "$global_runtime_cli" ]; then
|
|
280
|
+
NODE_CLI_KIND="script"; NODE_CLI_PATH="$global_runtime_cli"; NODE_CLI_SOURCE="global-runtime"
|
|
281
|
+
return 0
|
|
282
|
+
fi
|
|
283
|
+
project_root="$(dirname "$CONFIG_DIR")"
|
|
284
|
+
if [ -f "$project_root/node_modules/@khoavu882/doflow/bin/doflow.js" ]; then
|
|
285
|
+
NODE_CLI_KIND="script"; NODE_CLI_PATH="$project_root/node_modules/@khoavu882/doflow/bin/doflow.js"; NODE_CLI_SOURCE="node_modules"
|
|
286
|
+
return 0
|
|
287
|
+
fi
|
|
288
|
+
if command -v doflow >/dev/null 2>&1; then
|
|
289
|
+
NODE_CLI_KIND="bin"; NODE_CLI_PATH="$(command -v doflow)"; NODE_CLI_SOURCE="path"
|
|
290
|
+
return 0
|
|
291
|
+
fi
|
|
292
|
+
return 1
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
# ---------------------------------------------------------------------------------- reporting
|
|
296
|
+
|
|
297
|
+
wants_json=false
|
|
298
|
+
for _arg in "$@"; do
|
|
299
|
+
[ "$_arg" = "--json" ] && wants_json=true
|
|
300
|
+
done
|
|
301
|
+
|
|
302
|
+
# Dispatcher-level failures answer in the caller's requested shape; a caller that asked for JSON
|
|
303
|
+
# and got a bare English sentence has to special-case the dispatcher, which defeats the uniform
|
|
304
|
+
# contract.
|
|
305
|
+
fail() {
|
|
306
|
+
local code="$1" reason="$2" message="$3" escaped
|
|
307
|
+
# A broken DoFlow install is worth recording; the other reasons are the caller's mistake or the
|
|
308
|
+
# user's environment (DEC-031) and are not.
|
|
309
|
+
case "$reason" in
|
|
310
|
+
helper-missing|helpers-not-found) capture_failure "${CAPTURE_VERB:-dispatcher}" "$reason" "$code" ;;
|
|
311
|
+
esac
|
|
312
|
+
if [ "$wants_json" = true ]; then
|
|
313
|
+
# Messages quote resolved paths, and a path is allowed to contain a quote or a backslash;
|
|
314
|
+
# unescaped, one such path turns an error report into unparseable JSON.
|
|
315
|
+
escaped="${message//\\/\\\\}"
|
|
316
|
+
escaped="${escaped//\"/\\\"}"
|
|
317
|
+
printf '{"ok":false,"error":"%s","message":"%s"}\n' "$reason" "$escaped" >&2
|
|
318
|
+
else
|
|
319
|
+
printf 'doflow-run: %s\n' "$message" >&2
|
|
320
|
+
fi
|
|
321
|
+
exit "$code"
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
usage() {
|
|
325
|
+
cat <<'EOF'
|
|
326
|
+
doflow-run <verb> [args...] — the DoFlow runtime seam
|
|
327
|
+
|
|
328
|
+
Every verb accepts --json and reports on stdout. Exit 0 = success,
|
|
329
|
+
1 = an actionable finding, 2 = a usage or resolution error. sync-context is the
|
|
330
|
+
one verb whose result is a file write rather than a report, so it acknowledges
|
|
331
|
+
in plain text and --json changes nothing.
|
|
332
|
+
|
|
333
|
+
Artifact and repository state:
|
|
334
|
+
paths resolve repo root, branch, feature slug, artifact paths
|
|
335
|
+
validate artifact index/detail consistency check
|
|
336
|
+
render-audit regenerate audit.md from the orchestration journal
|
|
337
|
+
render-diagrams render a chain artifact's mermaid blocks to image files
|
|
338
|
+
render-puml render authored PlantUML sources and project them inline
|
|
339
|
+
git-state branch class and derived branch names
|
|
340
|
+
prereqs stage prerequisite checks
|
|
341
|
+
parallel-check dispatch groups and write-set collisions for one plan phase
|
|
342
|
+
task-brief task brief extraction for execution
|
|
343
|
+
brief-tools tier, tools and report-format block for a brief (called by task-brief)
|
|
344
|
+
advise local decision-model routing, outcomes and configuration
|
|
345
|
+
review-package assemble a review payload
|
|
346
|
+
sync-context write a marker-delimited block (stdin) into an agent context file
|
|
347
|
+
|
|
348
|
+
Workflow and evidence:
|
|
349
|
+
classify validate a proposed task class, return its workflow
|
|
350
|
+
workflow resolve stages, dependencies and gates for a class
|
|
351
|
+
orchestrate start/resume a run: complete stages, skip optional ones, decide gates
|
|
352
|
+
research-request open, list or resolve a feature-stage research question
|
|
353
|
+
task-attempt claim, finish, release or read the attempts on a plan's tasks
|
|
354
|
+
retrieve BM25 search over the installed guidance tree (auto-refreshing index)
|
|
355
|
+
model-role resolve an abstract model role to ranked, availability-annotated providers
|
|
356
|
+
route resolve an information need to a healthy provider
|
|
357
|
+
evidence record a stage's evidence batch, or query the ledger
|
|
358
|
+
claim record or update a claim and its support state
|
|
359
|
+
readiness evaluate readiness; return state and missing items
|
|
360
|
+
context-pack emit the compiled context pack for a stage
|
|
361
|
+
retrieval-plan declare the needs a stage will resolve, then report every declared item
|
|
362
|
+
outcome record a task's terminal state with its basis, or show what was recorded
|
|
363
|
+
scaffold emit the code scaffold the active feature's artifacts imply
|
|
364
|
+
decision register, list or compact the active feature's decisions
|
|
365
|
+
followup record, list, take, settle, promote or report what a feature left unfinished
|
|
366
|
+
lifecycle overview, init, status, release or merged: follow-ups and feature tracking for the project
|
|
367
|
+
goal add, check, link, list or close a goal and its checklist
|
|
368
|
+
failure list, settle or switch off the failures DoFlow captured on this machine
|
|
369
|
+
|
|
370
|
+
Verification and recovery:
|
|
371
|
+
verify compile the contract, run checks, emit the report
|
|
372
|
+
recover classify a failure, return the targeted action
|
|
373
|
+
leak-scan report DoFlow-internal identifiers in shipped files
|
|
374
|
+
|
|
375
|
+
Observability:
|
|
376
|
+
trace current run trajectory
|
|
377
|
+
stats aggregate run usage
|
|
378
|
+
indicators per-stage and per-gate timings from the orchestration record
|
|
379
|
+
discover missed opportunities in recorded runs
|
|
380
|
+
inventory both scopes at once: shadowed assets, drift, unmanaged contenders
|
|
381
|
+
capabilities provider resolution
|
|
382
|
+
doctor installation and provider health
|
|
383
|
+
storage report stored data and its retention bounds
|
|
384
|
+
EOF
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
# ------------------------------------------------------------------------------------- clocks
|
|
388
|
+
|
|
389
|
+
# Millisecond clocks are not portable: EPOCHREALTIME is bash 5+, `date +%N` exists on GNU and on
|
|
390
|
+
# recent BSD but the GNU width modifier `%3N` does not, and older BSD has neither. Probe once and
|
|
391
|
+
# keep the answer. The perl path pays its own interpreter startup inside the measured span, so
|
|
392
|
+
# durations recorded through it read a few milliseconds high — accepted, because the alternative
|
|
393
|
+
# on such a host is whole-second granularity.
|
|
394
|
+
detect_clock() {
|
|
395
|
+
local nanos
|
|
396
|
+
if [ -n "${EPOCHREALTIME:-}" ]; then printf 'bash'; return 0; fi
|
|
397
|
+
# Require exactly nine digits: `%s%N` is only safe to read as one number when %N is
|
|
398
|
+
# zero-padded, and a date that prints a literal "N" fails this test rather than poisoning
|
|
399
|
+
# every duration with a non-numeric suffix.
|
|
400
|
+
nanos="$(date -u +%N 2>/dev/null || true)"
|
|
401
|
+
case "$nanos" in
|
|
402
|
+
[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) printf 'nanos'; return 0 ;;
|
|
403
|
+
esac
|
|
404
|
+
if command -v perl >/dev/null 2>&1; then printf 'perl'; return 0; fi
|
|
405
|
+
printf 'seconds'
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
CLOCK="$(detect_clock)"
|
|
409
|
+
|
|
410
|
+
now_ms() {
|
|
411
|
+
local raw
|
|
412
|
+
case "$CLOCK" in
|
|
413
|
+
bash)
|
|
414
|
+
raw="${EPOCHREALTIME/./}"
|
|
415
|
+
printf '%s' "${raw:0:13}"
|
|
416
|
+
;;
|
|
417
|
+
nanos)
|
|
418
|
+
# One call, not %s then %N, so the reading cannot straddle a second boundary.
|
|
419
|
+
printf '%s' "$(( $(date -u +%s%N) / 1000000 ))"
|
|
420
|
+
;;
|
|
421
|
+
perl)
|
|
422
|
+
perl -MTime::HiRes -e 'printf "%d", Time::HiRes::time() * 1000'
|
|
423
|
+
;;
|
|
424
|
+
*)
|
|
425
|
+
printf '%s' "$(( $(date -u +%s) * 1000 ))"
|
|
426
|
+
;;
|
|
427
|
+
esac
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
# --------------------------------------------------------------------------------- run ledger
|
|
431
|
+
|
|
432
|
+
# One metadata record per dispatched verb (FR-011). Metadata ONLY — the verb name comes from the
|
|
433
|
+
# dispatcher's own table and the argument count is a count, so no argument value, no command
|
|
434
|
+
# output and no file content can reach the ledger (NFR-004).
|
|
435
|
+
#
|
|
436
|
+
# Tracing never changes what a verb returned. Every step is failure-tolerant and the function
|
|
437
|
+
# always succeeds: an unwritable state directory degrades observability, not the run.
|
|
438
|
+
trace_run() {
|
|
439
|
+
local verb="$1" code="$2" duration="$3" argc="$4" started_at="$5"
|
|
440
|
+
local runs_dir="$CONFIG_DIR/state/runs"
|
|
441
|
+
mkdir -p "$runs_dir" 2>/dev/null || return 0
|
|
442
|
+
printf '{"timestamp":"%s","verb":"%s","exit_code":%s,"duration_ms":%s,"arg_count":%s}\n' \
|
|
443
|
+
"$started_at" "$verb" "$code" "$duration" "$argc" \
|
|
444
|
+
>>"$runs_dir/$(date -u +%Y-%m-%d).jsonl" 2>/dev/null || return 0
|
|
445
|
+
return 0
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
# ----------------------------------------------------------------------------------- dispatch
|
|
449
|
+
|
|
450
|
+
# The two arms of the verb table (design.md §4.2). Together they also answer "is this a verb at
|
|
451
|
+
# all", so there is no third list to keep in step.
|
|
452
|
+
#
|
|
453
|
+
# Every helper a *skill* names has to appear here, or that skill has no way to reach it except by
|
|
454
|
+
# inlining its own resolver — the exact pattern C.4 removes. `do-parallel-check.sh` and
|
|
455
|
+
# `sync-context.sh` are here for that reason and no other. `do-exec-paths.sh` deliberately is not:
|
|
456
|
+
# it is called by do-task-brief.sh and do-review-package.sh, never by a skill, so exposing it would
|
|
457
|
+
# widen the public surface without removing a single resolver.
|
|
458
|
+
shell_helper_for() {
|
|
459
|
+
case "$1" in
|
|
460
|
+
paths) printf 'do-paths.sh' ;;
|
|
461
|
+
validate) printf 'validate-artifacts.sh' ;;
|
|
462
|
+
render-audit) printf 'render-audit.sh' ;;
|
|
463
|
+
render-diagrams) printf 'render-diagrams.sh' ;;
|
|
464
|
+
render-puml) printf 'render-puml.sh' ;;
|
|
465
|
+
git-state) printf 'do-git-state.sh' ;;
|
|
466
|
+
prereqs) printf 'do-prereqs.sh' ;;
|
|
467
|
+
parallel-check) printf 'do-parallel-check.sh' ;;
|
|
468
|
+
task-brief) printf 'do-task-brief.sh' ;;
|
|
469
|
+
review-package) printf 'do-review-package.sh' ;;
|
|
470
|
+
sync-context) printf 'sync-context.sh' ;;
|
|
471
|
+
*) return 1 ;;
|
|
472
|
+
esac
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
# The whole Node namespace, including the verbs later phases still have to build. Tracking which
|
|
476
|
+
# of them the CLI implements *today* would mean a second inventory drifting against the CLI's own
|
|
477
|
+
# command list; an unbuilt verb is dispatched and the CLI answers for itself.
|
|
478
|
+
is_node_verb() {
|
|
479
|
+
case "$1" in
|
|
480
|
+
classify|workflow|route|evidence|claim|readiness|context-pack|retrieval-plan|outcome|scaffold|decision|followup|lifecycle|goal|failure|verify|recover|leak-scan|\
|
|
481
|
+
trace|stats|indicators|discover|inventory|capabilities|doctor|orchestrate|research-request|task-attempt|retrieve|model-role|storage|brief-tools|advise) return 0 ;;
|
|
482
|
+
*) return 1 ;;
|
|
483
|
+
esac
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
dispatch_shell() {
|
|
487
|
+
local verb="$1"; shift
|
|
488
|
+
local helper bash_dir script
|
|
489
|
+
helper="$(shell_helper_for "$verb")"
|
|
490
|
+
if ! bash_dir="$(resolve_bash_dir)"; then
|
|
491
|
+
fail 2 "helpers-not-found" \
|
|
492
|
+
"cannot locate the shell helpers; searched $SCRIPT_DIR/../bash, $SCRIPT_DIR/bash and $CONFIG_DIR/scripts/doflow/bash"
|
|
493
|
+
fi
|
|
494
|
+
script="$bash_dir/$helper"
|
|
495
|
+
[ -f "$script" ] || fail 2 "helper-missing" "verb '$verb' needs $script, which does not exist"
|
|
496
|
+
bash "$script" "$@"
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
dispatch_node() {
|
|
500
|
+
local verb="$1"; shift
|
|
501
|
+
local marker tmpfile rc first_line
|
|
502
|
+
if ! resolve_node_cli; then
|
|
503
|
+
if marker="$(has_doflow_marker_nearby)"; then
|
|
504
|
+
fail 2 "unlinked-checkout" \
|
|
505
|
+
"verb '$verb' is served by the Node CLI, which could not be located; a file named bin/doflow.js was found near here ($marker) — if this is a doflow checkout, running \`npm link\` may resolve this"
|
|
506
|
+
fi
|
|
507
|
+
fail 2 "cli-not-found" \
|
|
508
|
+
"verb '$verb' is served by the Node CLI, which could not be located; set DOFLOW_CLI to a doflow.js path, install the package (npm i -g @khoavu882/doflow), or run from a checkout"
|
|
509
|
+
fi
|
|
510
|
+
if [ "$NODE_CLI_KIND" = "script" ]; then
|
|
511
|
+
command -v node >/dev/null 2>&1 || fail 2 "node-not-found" \
|
|
512
|
+
"verb '$verb' needs node on PATH to run $NODE_CLI_PATH"
|
|
513
|
+
case "$NODE_CLI_SOURCE" in
|
|
514
|
+
project-runtime|global-runtime)
|
|
515
|
+
# These two sources are a *projected copy* of the runtime, not the checkout itself, so
|
|
516
|
+
# they can drift out of sync with the working tree's registry. Stdout still streams
|
|
517
|
+
# directly; only stderr is captured, so a version-drift crash can be told apart from a
|
|
518
|
+
# verb legitimately reporting a finding (e.g. readiness's NEEDS_EVIDENCE) before either
|
|
519
|
+
# reaches the caller.
|
|
520
|
+
tmpfile="$(mktemp)"
|
|
521
|
+
trap 'rm -f "$tmpfile" 2>/dev/null || true' EXIT
|
|
522
|
+
rc=0
|
|
523
|
+
node "$NODE_CLI_PATH" "$verb" "$@" 2>"$tmpfile" || rc=$?
|
|
524
|
+
if [ "$rc" -ne 0 ]; then
|
|
525
|
+
first_line=""
|
|
526
|
+
IFS= read -r first_line <"$tmpfile" || true
|
|
527
|
+
# Matched loosely (not anchored to position 0): bin/doflow.js's own top-level catch
|
|
528
|
+
# prepends "[ERROR] " to every thrown message before it ever reaches stderr, so an
|
|
529
|
+
# anchored match against the registry loader's raw prefix never fires in practice.
|
|
530
|
+
case "$first_line" in
|
|
531
|
+
*"Invalid DoFlow registry:"*)
|
|
532
|
+
fail 2 "stale-runtime" \
|
|
533
|
+
"verb '$verb' failed against $NODE_CLI_PATH, which appears out of date relative to the working checkout; reinstall or re-run the doflow installer to refresh it"
|
|
534
|
+
;;
|
|
535
|
+
esac
|
|
536
|
+
fi
|
|
537
|
+
cat "$tmpfile" >&2
|
|
538
|
+
rm -f "$tmpfile"
|
|
539
|
+
trap - EXIT
|
|
540
|
+
return "$rc"
|
|
541
|
+
;;
|
|
542
|
+
*)
|
|
543
|
+
node "$NODE_CLI_PATH" "$verb" "$@"
|
|
544
|
+
;;
|
|
545
|
+
esac
|
|
546
|
+
else
|
|
547
|
+
"$NODE_CLI_PATH" "$verb" "$@"
|
|
548
|
+
fi
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
main() {
|
|
552
|
+
local verb rc started_ms started_at ended_ms argc
|
|
553
|
+
|
|
554
|
+
verb="${1:-}"
|
|
555
|
+
case "$verb" in
|
|
556
|
+
"")
|
|
557
|
+
usage >&2
|
|
558
|
+
fail 2 "no-verb" "no verb given"
|
|
559
|
+
;;
|
|
560
|
+
-h|--help|help)
|
|
561
|
+
usage
|
|
562
|
+
exit 0
|
|
563
|
+
;;
|
|
564
|
+
esac
|
|
565
|
+
shift
|
|
566
|
+
|
|
567
|
+
if ! shell_helper_for "$verb" >/dev/null 2>&1 && ! is_node_verb "$verb"; then
|
|
568
|
+
fail 2 "unknown-verb" "unknown verb '$verb' — run 'doflow-run --help' for the verb list"
|
|
569
|
+
fi
|
|
570
|
+
|
|
571
|
+
CAPTURE_VERB="$verb"
|
|
572
|
+
argc=$#
|
|
573
|
+
started_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
574
|
+
started_ms="$(now_ms)"
|
|
575
|
+
|
|
576
|
+
# `|| rc=$?` rather than a bare call: the verb's exit code is the dispatcher's exit code, and
|
|
577
|
+
# under `set -e` a failing verb would otherwise abort before the run is ever recorded.
|
|
578
|
+
rc=0
|
|
579
|
+
if shell_helper_for "$verb" >/dev/null 2>&1; then
|
|
580
|
+
dispatch_shell "$verb" "$@" || rc=$?
|
|
581
|
+
else
|
|
582
|
+
dispatch_node "$verb" "$@" || rc=$?
|
|
583
|
+
fi
|
|
584
|
+
|
|
585
|
+
ended_ms="$(now_ms)"
|
|
586
|
+
trace_run "$verb" "$rc" "$(( ended_ms - started_ms ))" "$argc" "$started_at" || true
|
|
587
|
+
capture_exit_status "$verb" "$rc"
|
|
588
|
+
|
|
589
|
+
exit "$rc"
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
main "$@"
|