@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,441 @@
|
|
|
1
|
+
# `--scaffold` — turning the plan into a reviewable code scaffold
|
|
2
|
+
|
|
3
|
+
Read this file only when `/do-execute-plan --scaffold` is the active invocation. It is step 3 of
|
|
4
|
+
`do-execute-plan`'s Behavioral Flow, factored out here per Anthropic's progressive-disclosure
|
|
5
|
+
guidance so the other invocation modes (`--scope next|phase:N|all|resume`, and the `--review`
|
|
6
|
+
modifier) don't pay the token cost of this algorithm on every invocation.
|
|
7
|
+
|
|
8
|
+
It answers one question: *what shape does my plan imply, before any of it reaches my code?* The
|
|
9
|
+
cross-service frames in Part 2 are one case of that, not the headline.
|
|
10
|
+
|
|
11
|
+
`plan.md`'s task list is already resolved by the time this runs. This produces a distinct deliverable
|
|
12
|
+
from the task-execution loop in step 4 — it runs standalone (no task-selection mode required), to
|
|
13
|
+
completion, then stops. Idempotent: safe to re-run, and re-running an unchanged plan produces no
|
|
14
|
+
diff at all.
|
|
15
|
+
|
|
16
|
+
## What it produces
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
agent-docs/doflow/<slug>/scaffold/
|
|
20
|
+
├── MANIFEST.md # what was generated, from which artifact, and what was SKIPPED
|
|
21
|
+
├── src/<path>.<ext>.stub # mirrors the intended source layout — signatures only
|
|
22
|
+
├── test/<FR-id>.test.<ext>.stub # test stubs derived from acceptance criteria
|
|
23
|
+
└── contracts/<service>/… # external-dependency frames (Part 2)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Part 1's files all carry a `.stub` suffix, and that is load-bearing rather than decorative:
|
|
27
|
+
`node --test` collects *any* `.js` under a directory named `test`, and pytest and `go test ./...`
|
|
28
|
+
sweep just as broadly, so a stub emitted as plain `FR-001.test.js` under that directory would
|
|
29
|
+
silently join the host project's own test run and fail it. One suffix on everything is a stronger
|
|
30
|
+
guarantee than a per-toolchain exclusion list — nothing in Part 1's output is loadable by anything
|
|
31
|
+
until someone deliberately drops the suffix. Part 2's `contracts/` frames do not carry it: `default/` exists to be compiled against,
|
|
32
|
+
and its tree holds no directory a runner sweeps.
|
|
33
|
+
|
|
34
|
+
| Property | Rule |
|
|
35
|
+
|---|---|
|
|
36
|
+
| Source tree | Never written to. `git status` outside the feature directory is unchanged by a run, and the host project's test run is unaffected |
|
|
37
|
+
| Content | Signatures, types, stubs. **No implementation logic** |
|
|
38
|
+
| Traceability | Every file header names its originating FR / component / task |
|
|
39
|
+
| Idempotency | Re-running produces no diff |
|
|
40
|
+
| Human edits | Detected by fingerprint and reported, never overwritten |
|
|
41
|
+
| Invocation | Explicit only — never inferred from plan contents |
|
|
42
|
+
|
|
43
|
+
Two rules deserve their reasoning, because both are easy to "improve" into a defect:
|
|
44
|
+
|
|
45
|
+
- **No implementation logic, ever.** The artifact exists so an engineer can judge the shape a plan
|
|
46
|
+
implies. Generated logic nobody has verified is exactly the false confidence this scaffold is
|
|
47
|
+
supposed to remove — a body that looks finished stops being reviewed. Every emitted body is one
|
|
48
|
+
fixed "not implemented" signal from the Default-Implementation Grammar in Part 2, and nothing else.
|
|
49
|
+
- **What was skipped matters as much as what was produced.** A reader who cannot see the gaps reads
|
|
50
|
+
the tree as the whole shape of the plan. So a scaffold built from an artifact the generator could
|
|
51
|
+
not read or parse says so in `MANIFEST.md` and exits non-zero — it never degrades into a thin tree
|
|
52
|
+
that reads as complete.
|
|
53
|
+
|
|
54
|
+
## Two cases, one output tree
|
|
55
|
+
|
|
56
|
+
| | Part 1 — in-scope | Part 2 — external dependency |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| Input | `requirement.md`, `design.md`, `plan.md` | a `depends-on:` value with no owning task |
|
|
59
|
+
| Produced by | `src/runtime/scaffold/generate.js`, deterministically | this file's algorithm, executed by you |
|
|
60
|
+
| Lands in | `scaffold/src/`, `scaffold/test/`, `scaffold/MANIFEST.md` | `scaffold/contracts/<service>/` |
|
|
61
|
+
| Answers | what shape does my own plan imply | what shape must I code against at the boundary |
|
|
62
|
+
|
|
63
|
+
They meet in one place: the generator partitions every `depends-on:` value and reports the result in
|
|
64
|
+
`MANIFEST.md`'s **External dependencies** table. It deliberately does *not* derive service
|
|
65
|
+
boundaries itself — the walk-up rules in Part 2 handle nested `.git` boundaries, non-local vendors
|
|
66
|
+
and `external-contract:` targets, and a second implementation of that walk would be one more thing to
|
|
67
|
+
keep in sync. Read the table, then run Part 2 for every row whose disposition is `external`.
|
|
68
|
+
|
|
69
|
+
## Part 1 — in-scope scaffold from the three artifacts
|
|
70
|
+
|
|
71
|
+
Deterministic, so it is executed rather than reasoned through. Run it, then report what it returns —
|
|
72
|
+
do not restate its counts from memory or re-derive them by reading the tree.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# `$DOFLOW` is already resolved by step 1. One verb, like every other runtime call — the seam
|
|
76
|
+
# resolves the active feature itself, so nothing here interpolates a path or a slug.
|
|
77
|
+
"$DOFLOW" scaffold --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Run it from the project root: the verb resolves which feature is active exactly the way `paths`
|
|
81
|
+
does, from the working directory. The one case worth knowing about is a non-git root holding more
|
|
82
|
+
than one feature directory — there the resolver cannot choose, and exits 2 naming every candidate.
|
|
83
|
+
Ask the user which one via `AskUserQuestion` and re-run as `"$DOFLOW" scaffold --slug=<chosen>
|
|
84
|
+
--json`; do not pick for them.
|
|
85
|
+
|
|
86
|
+
Exit codes follow the runtime's uniform contract: `0` complete, `1` a finding you must report to the
|
|
87
|
+
user, `2` a usage or resolution error. **Branch on `status`, not on the presence of output** — a
|
|
88
|
+
`BLOCKED` run still writes `MANIFEST.md`, because a report naming what it could not read is more
|
|
89
|
+
useful than no report at all.
|
|
90
|
+
|
|
91
|
+
What the generator does, so you can read its output rather than guess at it:
|
|
92
|
+
|
|
93
|
+
1. **Reads all three artifacts** and records each one's SHA-256 in `MANIFEST.md`. A missing one, or
|
|
94
|
+
a `plan.md` with no parseable task list, is `BLOCKED`: no source files are written.
|
|
95
|
+
2. **Builds the traceability chain** — a task's `[US#]` resolves through `requirement.md`'s FR index
|
|
96
|
+
to its requirements, and through `design.md` §3 to the components serving them. That chain is
|
|
97
|
+
what puts a real FR / component / task in every file header instead of a generic banner.
|
|
98
|
+
3. **Mirrors the intended source layout** from every task's `files:` value into `scaffold/src/`,
|
|
99
|
+
keeping each path exactly as the plan wrote it and appending `.stub`. In a repository whose code
|
|
100
|
+
already lives in `src/`, that reads as `scaffold/src/src/runtime/thing.js.stub`; the doubling is
|
|
101
|
+
deliberate, so a path can never collide with `MANIFEST.md` or `contracts/`.
|
|
102
|
+
4. **Emits per-file frames** in the language of the file's own extension — the plan already stated
|
|
103
|
+
it, so nothing is inferred. Where `design.md` §4 declares an interface for the file's component,
|
|
104
|
+
that block is carried through verbatim as a quoted comment; where it does not, the file gets one
|
|
105
|
+
clearly labelled placeholder signature and is listed under **Emitted without a declared shape**.
|
|
106
|
+
No API nobody wrote down is ever invented.
|
|
107
|
+
5. **Emits test stubs** from `requirement.md`'s acceptance criteria, one file per requirement. Each
|
|
108
|
+
stub fails until implemented, deliberately: a stub that passes asserts nothing and reads as
|
|
109
|
+
coverage. The stub language comes from the repository's own manifest, detected by
|
|
110
|
+
`command-detect.ts` — the same detector the verification engine uses, not a second one.
|
|
111
|
+
6. **Protects hand edits.** Every generated file carries a fingerprint of its own body. A body that
|
|
112
|
+
no longer matches, or a file with no fingerprint at all, is treated as hand-authored: reported
|
|
113
|
+
under **Preserved**, never rewritten. This includes `MANIFEST.md` — delete it to refresh it.
|
|
114
|
+
Files from an earlier run that the plan no longer implies are reported as **Orphaned** and left
|
|
115
|
+
in place; deleting work someone may have started is the worse failure.
|
|
116
|
+
|
|
117
|
+
### What Part 1 does not cover
|
|
118
|
+
|
|
119
|
+
Named here rather than discovered later, because each one appears in `MANIFEST.md` as a skip and a
|
|
120
|
+
reader is entitled to know whether it is a gap or a decision:
|
|
121
|
+
|
|
122
|
+
- **Content files.** Markdown, YAML, JSON and the rest have no signature to emit. Skipped benignly;
|
|
123
|
+
they do not affect the exit code.
|
|
124
|
+
- **Directories.** A `files:` value naming a directory has no single signature behind it.
|
|
125
|
+
- **Languages with no emitter.** The generator emits JavaScript, TypeScript, Python, Go and Rust.
|
|
126
|
+
Java, Kotlin, C#, Swift and Objective-C are covered by Part 2's Default-Implementation Grammar,
|
|
127
|
+
which you execute, but not by the generator; shell and everything else are covered by neither.
|
|
128
|
+
Each case is skipped with its own wording and pushes the run to a non-zero exit, because a plan
|
|
129
|
+
whose main language the generator cannot emit has not been scaffolded in any useful sense.
|
|
130
|
+
- **Applying the scaffold.** Moving anything into the source tree stays a deliberate human act, or
|
|
131
|
+
`/do-execute-plan`'s ordinary job. Nothing here promotes itself.
|
|
132
|
+
|
|
133
|
+
## Part 2 — external dependencies (cross-service contract frames)
|
|
134
|
+
|
|
135
|
+
For every `depends-on:` value `MANIFEST.md` dispositions as `external`. Steps are numbered within
|
|
136
|
+
this Part; `scaffold/contracts/<service>/` is the only place any of it may write.
|
|
137
|
+
|
|
138
|
+
1. **Derive service identity** — applies identically to two kinds of input: a task's `files:`
|
|
139
|
+
value (finds what it *owns* — step 2's in-scope side) and a `depends-on:` value that has no
|
|
140
|
+
owning task in this plan (finds what it *references* — step 2's dependency side; this is the
|
|
141
|
+
algorithm's primary use case, not an afterthought — a genuine dependency owns no task, so it
|
|
142
|
+
only ever reaches a service identity through this path, never through the `files:` path above).
|
|
143
|
+
A `files:` value is a file — start from its containing directory. A `depends-on:` value is
|
|
144
|
+
already a directory reference — start from that directory itself.
|
|
145
|
+
|
|
146
|
+
From the starting directory, walk up, stopping *strictly before* the consuming repo's own root
|
|
147
|
+
— that root's own `.git`/manifest is not a valid signal here, it only confirms we're inside
|
|
148
|
+
this repo, not where an internal service boundary starts. The nearest ancestor strictly between
|
|
149
|
+
the starting directory and the consuming repo's root that is either a distinct git repo (a
|
|
150
|
+
*nested* `.git` — either a `.git` directory or a `.git` *file*, so a submodule/worktree gitlink
|
|
151
|
+
still counts — never the consuming repo's own) or contains one of the known build/package
|
|
152
|
+
manifest files listed in step 4 below (the same signal, not a separate list — reused, not
|
|
153
|
+
duplicated) becomes the service boundary; its path *relative to the consuming repo's root* is
|
|
154
|
+
the service identity, always — no special case for a nested `.git`, which would otherwise
|
|
155
|
+
degenerate to a meaningless self-relative `.`.
|
|
156
|
+
|
|
157
|
+
If no such ancestor exists anywhere in that range, the service identity falls back to the
|
|
158
|
+
starting directory itself, exactly as given — trusting the plan author's own already-specific
|
|
159
|
+
path as the evidence, not guessing a workspace-convention depth — **unless the starting
|
|
160
|
+
directory is the consuming repo's own root itself** (a `files:` value that's a root-level file,
|
|
161
|
+
e.g. `package.json`, or a `depends-on:` value naming the repo root directly), in which case the
|
|
162
|
+
path is excluded from service-identity derivation entirely: the same treatment the original
|
|
163
|
+
fixed-root-list version gave paths outside its known roots. Not every path needs to resolve to
|
|
164
|
+
a service, and silently naming the whole consuming repo "the service" would collapse every such
|
|
165
|
+
path into one colliding identity. A `depends-on:` value that degenerates this way simply
|
|
166
|
+
produces no contract for that dependency — reported to the user as an advisory notice naming
|
|
167
|
+
the skipped dependency, not an error. This works in any consuming repo's directory
|
|
168
|
+
layout, not only one shaped like a specific multi-service container workspace.
|
|
169
|
+
|
|
170
|
+
This entire derivation — walk-up *and* the no-signal fallback — only ever applies to a
|
|
171
|
+
`depends-on:` value whose starting directory actually exists on disk (a `files:` value always
|
|
172
|
+
qualifies; it names a path the plan legitimately intends to touch). A `depends-on:` value that
|
|
173
|
+
names no real directory at all — an external vendor, SaaS, or organization label with nothing
|
|
174
|
+
to walk up from, e.g. a partner's name rather than a path — never reaches a service identity
|
|
175
|
+
through this step. Step 2 routes that case to a different outcome, not this one; don't apply the
|
|
176
|
+
no-signal fallback to it (that fallback is for a real, existing, merely manifest-less
|
|
177
|
+
directory — a fundamentally different situation from a value that isn't a path at all).
|
|
178
|
+
|
|
179
|
+
2. **Partition touched services** into:
|
|
180
|
+
- **in-scope** — owns a task (being built for real in this same plan) — no contract needed.
|
|
181
|
+
- **dependency (local)** — named in some task's `depends-on:`, owns no task, and step 1 derived
|
|
182
|
+
a real service identity for it.
|
|
183
|
+
- **dependency (non-local)** — named in some task's `depends-on:`, owns no task, and step 1
|
|
184
|
+
derived *no* service identity for it — either because its starting directory doesn't exist on
|
|
185
|
+
disk at all, or because it degenerated to the consuming repo's own root (step 1's exclusion
|
|
186
|
+
case). Both sub-cases collapse into the same outcome here, since either way there is no local
|
|
187
|
+
boundary to generate from:
|
|
188
|
+
- has an `external-contract:` field on the same task → **documented dependency**, routed to
|
|
189
|
+
step 5's external-contract generation path (below) instead of local language inference,
|
|
190
|
+
which has nothing to scan. That is what the field name states: no local repo exists, so the
|
|
191
|
+
document is the only contract there is.
|
|
192
|
+
- no `external-contract:` → excluded entirely, same as today — no contract generated, surfaced
|
|
193
|
+
via the existing advisory notice, not an error.
|
|
194
|
+
|
|
195
|
+
A non-local dependency name can be referenced by more than one task, same as a local one
|
|
196
|
+
(`manifest.yaml`'s `source_task_ids` already supports multiple contributing tasks) — treat every
|
|
197
|
+
task naming the same non-local value as one entity, not one per task. Their `external-contract:`
|
|
198
|
+
fields MUST agree: either all of them set to the same target, or none of them set at all. If
|
|
199
|
+
they disagree (some set, some not; or set to different targets), surface an explicit warning
|
|
200
|
+
naming the conflicting tasks and their differing `external-contract:` values — never silently
|
|
201
|
+
pick one, same "don't guess" posture as everywhere else in this algorithm.
|
|
202
|
+
|
|
203
|
+
An `external-contract:` field set on a task whose `depends-on:` value *does* resolve to a local
|
|
204
|
+
identity (a "dependency (local)" case, not non-local) is simply unused — local dependencies are
|
|
205
|
+
generated from the local repo, never from a doc, regardless of whether `external-contract:` is
|
|
206
|
+
present. Not an error and not warned about; the field only has an effect in the non-local case.
|
|
207
|
+
|
|
208
|
+
3. **Classify each local dependency's integration style**, derived from *how* step 1 found its
|
|
209
|
+
boundary, not from a named-root or known-monolith list:
|
|
210
|
+
- `network` — the boundary is a distinct git repo (its own `.git`) — an independently
|
|
211
|
+
deployable unit.
|
|
212
|
+
- `in-process` — the boundary was matched via a manifest file only, within the same repo as the
|
|
213
|
+
consuming task.
|
|
214
|
+
- `network` (default) — when step 1's no-signal fallback applies: `in-process` requires
|
|
215
|
+
positive evidence (a same-repo manifest match); its absence defaults to treating the
|
|
216
|
+
dependency as separate rather than silently downgrading it.
|
|
217
|
+
|
|
218
|
+
A **documented (non-local) dependency** never went through step 1 at all, so none of the above
|
|
219
|
+
applies — it's always `network`, unconditionally: it has no local repo by definition (that's
|
|
220
|
+
what made it non-local in the first place), so it can never be `in-process`.
|
|
221
|
+
|
|
222
|
+
4. **Infer each local dependency's language** (a documented dependency has no repo to infer from
|
|
223
|
+
here — step 5's "Documented dependencies" case infers a *rendering* language from the consumer
|
|
224
|
+
instead, reusing this same manifest-detection logic on a different starting point) — check, in
|
|
225
|
+
order, for a known build/package manifest file in the service's repo root: `pom.xml` → Java,
|
|
226
|
+
`build.gradle`/`.kts` → Java unless
|
|
227
|
+
`.kt` source files are present (→ Kotlin), `package.json` → JavaScript unless `tsconfig.json` or
|
|
228
|
+
`.ts`/`.tsx` files are present (→ TypeScript), `Package.swift` → Swift, `Podfile` → Swift unless
|
|
229
|
+
`.m`/`.h` outnumber `.swift` files (→ Objective-C), `Cargo.toml` → Rust, `go.mod` → Go,
|
|
230
|
+
`pyproject.toml`/`requirements.txt` → Python, `*.csproj` → C#. If none found, fall back to
|
|
231
|
+
file-extension frequency among source files (excluding `node_modules/`, `.git/`, `build/`,
|
|
232
|
+
`dist/`, `target/`). If still inconclusive, record `inferred_language: unresolved` — this step
|
|
233
|
+
only determines the language, it does not write anything; the placeholder write (if needed)
|
|
234
|
+
happens in step 5, gated by that step's idempotency check like every other write. Read-only —
|
|
235
|
+
never write into the dependency service's own repo.
|
|
236
|
+
|
|
237
|
+
5. **Per local dependency, three outcomes** based on
|
|
238
|
+
`agent-docs/doflow/<slug>/scaffold/contracts/<service>/manifest.yaml` (always under the active feature's
|
|
239
|
+
own dir — never elsewhere). `generation_hash` covers source task text *and* the inferred
|
|
240
|
+
language *and* which signal produced it (manifest file vs. extension-frequency) *and*
|
|
241
|
+
`default/`'s generated content — a change in any of the four counts as stale, not just a
|
|
242
|
+
task-text change:
|
|
243
|
+
- **Doesn't exist** → generate, in the inferred language:
|
|
244
|
+
`code/` — an interface/client declaration with the method signature(s) implied by the
|
|
245
|
+
consuming task's `depends-on:` relationship (a clearly-labeled placeholder signature if not
|
|
246
|
+
enough information exists to infer one) — signatures only, zero implementation.
|
|
247
|
+
`data/` — native-language type/DTO declarations for the referenced data shape(s) — fields
|
|
248
|
+
only, no schema file.
|
|
249
|
+
`mock/` — an unfilled skeleton mirroring `code/`'s interface shape — signature-only, same as
|
|
250
|
+
`code/`, not a working fake with canned responses.
|
|
251
|
+
`default/` — a compilable **default implementation** of `code/`'s interface, so a reviewer (or
|
|
252
|
+
the consuming task's own code) has something to read/compile against immediately, not just a
|
|
253
|
+
shape to hand-implement first: one file per `code/` interface file, same naming convention,
|
|
254
|
+
every method resolving to a single pinned, language-family-specific "not implemented" signal
|
|
255
|
+
(see the Default-Implementation Grammar table below) — never real business logic, never a
|
|
256
|
+
guessed behavior. Generated only when `inferred_language` resolves to a real language; the
|
|
257
|
+
pseudocode fallback immediately below covers `code/`/`data/`/`mock/` but never `default/` —
|
|
258
|
+
pseudocode has no execution semantics to carry a "not implemented" signal, so an
|
|
259
|
+
`inferred_language: unresolved` service gets no `default/` artifact at all, not a pseudocode
|
|
260
|
+
stand-in.
|
|
261
|
+
|
|
262
|
+
**Default-Implementation Grammar** — one pinned rule per language family (never invented per
|
|
263
|
+
service), each producing an explicit, idiomatic "not implemented" signal and nothing else. The
|
|
264
|
+
message text is a fixed template (`"<Service> default implementation — not implemented"`,
|
|
265
|
+
substituted only with the service name) so two generations of the same interface produce
|
|
266
|
+
byte-identical output:
|
|
267
|
+
|
|
268
|
+
| Language family | Mechanism | Example shape |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| Java / Kotlin | throw an unchecked "unsupported operation" exception | `throw new UnsupportedOperationException("<Service> default implementation — not implemented")` |
|
|
271
|
+
| JavaScript / TypeScript | throw an `Error` | `throw new Error("<Service> default implementation — not implemented")` |
|
|
272
|
+
| Python | raise `NotImplementedError` | `raise NotImplementedError("<Service> default implementation — not implemented")` |
|
|
273
|
+
| C# | throw `NotImplementedException` | `throw new NotImplementedException("<Service> default implementation — not implemented")` |
|
|
274
|
+
| Swift | trap via the language's fatal-error function | `fatalError("<Service> default implementation — not implemented")` |
|
|
275
|
+
| Objective-C | trap via an always-failing assertion | `NSAssert(NO, @"<Service> default implementation — not implemented")` |
|
|
276
|
+
| Rust | the language's own "unimplemented" macro | `unimplemented!("<Service> default implementation — not implemented")` |
|
|
277
|
+
| Go (no exceptions — idiomatic error return, not a trap) | zero value + non-nil error | `return <zero-value>, errors.New("<Service> default implementation — not implemented")` |
|
|
278
|
+
|
|
279
|
+
This table's language-family set is exactly step 4's existing manifest-detection set
|
|
280
|
+
(`pom.xml`/`build.gradle`→Java/Kotlin, `package.json`→JS/TS, `Package.swift`/`Podfile`→
|
|
281
|
+
Swift/Objective-C, `Cargo.toml`→Rust, `go.mod`→Go, `pyproject.toml`/`requirements.txt`→Python,
|
|
282
|
+
`*.csproj`→C#) — no language reaches `default/` generation that step 4 doesn't already resolve
|
|
283
|
+
to, so this table never needs a language step 4 itself doesn't cover.
|
|
284
|
+
|
|
285
|
+
A service whose language couldn't be inferred (`inferred_language: unresolved`) gets a
|
|
286
|
+
structurally-valid **generic pseudocode** frame instead — never a real-language extension, so
|
|
287
|
+
no editor mistakes it for compilable code, and never freeform prose. Every file opens with the
|
|
288
|
+
same banner comment; the grammar is fixed, not improvised per service:
|
|
289
|
+
```text
|
|
290
|
+
// GENERIC PSEUDOCODE — fallback notation, not a real target language.
|
|
291
|
+
// <service>'s implementation language could not be inferred; do not attempt to compile this.
|
|
292
|
+
interface <Service>Client {
|
|
293
|
+
<method1>(<param1>: <Param1Type>, <param2>: <Param2Type>): <Return1Type>
|
|
294
|
+
<method2>(<param1>: <Param1Type>): <Return2Type>
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
one line per method, comma-separated params on the same line, no line between methods —
|
|
298
|
+
`code/interface.pseudo` is this interface with one line per method signature implied by the
|
|
299
|
+
consuming task's `depends-on:` relationship (a clearly-labeled placeholder signature if not
|
|
300
|
+
enough information exists to infer one).
|
|
301
|
+
`data/types.pseudo` — the same banner, then one `type <Name> = { <field1>: <type1>,
|
|
302
|
+
<field2>: <type2> }` block per referenced data shape (comma-separated fields, same style as
|
|
303
|
+
the interface's params), and one `enum <Name> { <VALUE_A>, <VALUE_B> }` block per referenced
|
|
304
|
+
enum-shaped supporting type (comma-separated variants — same delimiter style as `type`, no
|
|
305
|
+
format switch between the two) — fields/variants only, no schema file.
|
|
306
|
+
`mock/interface.pseudo` — byte-identical to `code/interface.pseudo`'s interface block (same
|
|
307
|
+
banner, same `interface <Service>Client { ... }` signature, no method bodies — a pseudocode
|
|
308
|
+
`interface` cannot carry one) — same "signature-only, same as `code/`, not a working fake"
|
|
309
|
+
rule the resolved-language case already uses for `mock/`, just in pseudocode instead of the
|
|
310
|
+
inferred language. Also write `manifest.yaml`:
|
|
311
|
+
```yaml
|
|
312
|
+
service: sources/otp-service # derived service identity
|
|
313
|
+
source: local-inference # local-inference | external-contract (documented dependencies, below)
|
|
314
|
+
integration_style: network # network | in-process
|
|
315
|
+
inferred_language: java # or "unresolved" if inference failed
|
|
316
|
+
inference_signal: build.gradle # which manifest file, "extension-frequency", or "none" if unresolved
|
|
317
|
+
generated_from_plan: agent-docs/doflow/<slug>/plan.md
|
|
318
|
+
source_task_ids: ["T-004", "T-007"] # plan.md tasks whose depends-on: produced this entry
|
|
319
|
+
generation_hash: <sha256 of source_task_ids' full task text + inferred_language + inference_signal + default/'s generated content>
|
|
320
|
+
generated_at: <ISO-8601 timestamp>
|
|
321
|
+
```
|
|
322
|
+
- **Exists, `generation_hash` matches** → skip (already current).
|
|
323
|
+
- **Exists, `generation_hash` mismatches** (source tasks, inferred language, inference signal, or
|
|
324
|
+
`default/`'s generated content changed since last generation — including a manifest generated
|
|
325
|
+
before `default/` existed at all) → do NOT auto-overwrite; surface a warning naming the service
|
|
326
|
+
and stale manifest path so the user can reconcile manually — the existing
|
|
327
|
+
`code`/`data`/`mock`/`default` content may hold manual edits that a silent regeneration would
|
|
328
|
+
destroy.
|
|
329
|
+
|
|
330
|
+
**Documented dependencies** (an `external-contract:` field is present — step 2's non-local case)
|
|
331
|
+
are
|
|
332
|
+
generated the same way, in the same `manifest.yaml`-driven three-outcome shape, but from a
|
|
333
|
+
different source — the `external-contract:` target, not local repo scanning (there is none to scan):
|
|
334
|
+
- **Doesn't exist** → first validate the `external-contract:` target: does it contain a `## Methods`
|
|
335
|
+
section with at least one grammar-conformant `interface` block (the same grammar as the
|
|
336
|
+
pseudocode example above)? `## Types` must also be present.
|
|
337
|
+
- **Not compliant** (missing `## Methods`, missing `## Types`, or `## Methods` has no valid
|
|
338
|
+
`interface` block) → surface an explicit warning naming the dependency, the `external-contract:`
|
|
339
|
+
path, and what's missing — no frame generated. Never silently skip without saying why, and
|
|
340
|
+
never generate a frame from a doc that doesn't meet the bar.
|
|
341
|
+
- **Compliant** → parse `## Methods` (→ `code/`) and `## Types` (→ `data/`); if `## Webhook`
|
|
342
|
+
is present, its type block is also written into `data/`, alongside (not merged with) the
|
|
343
|
+
`## Types` blocks — a webhook payload is still just a data shape, not a new artifact
|
|
344
|
+
category, but its declaration stays textually separate from `## Types`' own blocks. A
|
|
345
|
+
`## Webhook` type sharing a name with a `## Types` block is an `external-contract:` authoring
|
|
346
|
+
error (a naming collision the doc author must avoid); this algorithm does not attempt to
|
|
347
|
+
detect or rename it. Infer the *rendering* language from the **consuming task's own repo**
|
|
348
|
+
— reuse step 4's manifest-detection logic starting from the consumer's `files:` path,
|
|
349
|
+
walking up *all the way to and including* the consuming repo's own root this time (unlike
|
|
350
|
+
step 1's identity derivation, which stops short of it — that exclusion exists to prevent
|
|
351
|
+
multiple *service identities* from colliding on the repo root, a concern that doesn't apply
|
|
352
|
+
to language detection at all: many root-level tasks correctly sharing "this repo's own
|
|
353
|
+
language" is the right outcome, not a collision). Render `code/`, `data/`, `mock/` in that
|
|
354
|
+
language — or in this step's pseudocode grammar if even the consuming repo's own root has
|
|
355
|
+
no recognizable manifest — same zero-implementation, signature/shape-only rule `code/`,
|
|
356
|
+
`data/`, and `mock/` share everywhere else in this algorithm (`default/`, next, follows a
|
|
357
|
+
different rule); `mock/` mirrors `code/`, unfilled, same rule as always. Also render
|
|
358
|
+
`default/` in that same resolved language, using the
|
|
359
|
+
Default-Implementation Grammar table above, applying the same exclusion it already states:
|
|
360
|
+
skip `default/` entirely (not a pseudocode stand-in) when even the consuming repo's own root
|
|
361
|
+
has no recognizable manifest. Also write `manifest.yaml`:
|
|
362
|
+
```yaml
|
|
363
|
+
service: notification-vendor # the literal depends-on: value; no local path to derive from
|
|
364
|
+
source: external-contract
|
|
365
|
+
external_contract_path: agent-docs/doflow/<slug>/notification-vendor-api.md
|
|
366
|
+
integration_style: network # always, per step 3 — no local repo, never in-process
|
|
367
|
+
inferred_language: java # the CONSUMING task's inferred language, not the dependency's
|
|
368
|
+
inference_signal: build.gradle # same step-4 signal, applied to the consumer's repo
|
|
369
|
+
generated_from_plan: agent-docs/doflow/<slug>/plan.md
|
|
370
|
+
source_task_ids: ["T-004"]
|
|
371
|
+
generation_hash: <sha256 of source_task_ids full task text plus the external-contract target's full file content plus inferred_language plus default/'s generated content>
|
|
372
|
+
generated_at: <ISO-8601 timestamp>
|
|
373
|
+
```
|
|
374
|
+
- **Exists, `generation_hash` matches** → skip (already current) — same rule as above.
|
|
375
|
+
- **Exists, `generation_hash` mismatches** (source tasks, the `external-contract:` target's content,
|
|
376
|
+
the consumer's inferred language, or `default/`'s generated content changed since last
|
|
377
|
+
generation — including a manifest generated before `default/` existed at all) → do NOT
|
|
378
|
+
auto-overwrite; same warn-don't-clobber rule as above — a doc edit is real drift and must be
|
|
379
|
+
caught, not silently missed.
|
|
380
|
+
|
|
381
|
+
6. **Report** — N services generated, M skipped (already current), K flagged stale (mismatch, not
|
|
382
|
+
overwritten), the in-scope services with no contract generated (expected outcome, not an error),
|
|
383
|
+
and, separately, J documented-dependency frames generated from `external-contract:` (step 5's
|
|
384
|
+
"Documented dependencies" case) — state this breakdown explicitly so a documented-dependency
|
|
385
|
+
frame doesn't read as an ordinary local-inference one, or vice versa. Also state, separately
|
|
386
|
+
again, how many of the generated/current services got a `default/` artifact vs. how many were
|
|
387
|
+
skipped because `inferred_language` is `unresolved` (step 5's pseudocode-fallback case never
|
|
388
|
+
producing `default/`) — a `default/`-skip is an expected outcome of that case, not an error,
|
|
389
|
+
but must be named so it doesn't read as an omission.
|
|
390
|
+
|
|
391
|
+
## Constraints (carried from the design — do not relax these)
|
|
392
|
+
|
|
393
|
+
The first applies to both Parts. Every other constraint here is Part 2's, and its bare step numbers
|
|
394
|
+
are Part 2's steps — Part 1's equivalents are enforced by `src/runtime/scaffold/generate.js` and its guard
|
|
395
|
+
rather than restated as prose.
|
|
396
|
+
|
|
397
|
+
- Never write outside `agent-docs/doflow/<slug>/scaffold/` — not into the source tree, and not
|
|
398
|
+
into a target service's own repo (including the dependency service scanned for language
|
|
399
|
+
inference in Part 2 step 4 — read-only). This is the one property the whole artifact rests on, and
|
|
400
|
+
`test/guards/scaffold.test.js` enforces it by running the generator against a filesystem that can
|
|
401
|
+
only reach the feature directory.
|
|
402
|
+
- `code/`/`data/`/`mock/` content is pinned, not freeform: signatures and type/data shapes only,
|
|
403
|
+
zero implementation logic — in the inferred language, or the pinned generic-pseudocode grammar
|
|
404
|
+
(`.pseudo` files, step 5) when language inference fails. `mock/` mirrors `code/`'s interface
|
|
405
|
+
shape; it is not a working fake, in either case.
|
|
406
|
+
- `default/` content is pinned too, but under a different rule than `code/`/`data/`/`mock/`: zero
|
|
407
|
+
*real* implementation, not zero implementation, period — every method body is one fixed,
|
|
408
|
+
language-family-specific "not implemented" signal (the Default-Implementation Grammar table,
|
|
409
|
+
step 5), never freeform, never a guessed behavior, and never generated at all for the
|
|
410
|
+
pseudocode-fallback case (no `.pseudo` equivalent — step 5 states this explicitly).
|
|
411
|
+
- Service-boundary detection (Part 2 step 1) is walk-up-based (nearest `.git` or manifest ancestor, or
|
|
412
|
+
the starting directory itself — from a `files:` path or a `depends-on:` value alike — as a
|
|
413
|
+
last-resort fallback) — never a fixed list of named root directories, so Part 2 works in any
|
|
414
|
+
consuming repo's layout. Known accepted
|
|
415
|
+
limitation: two dependencies that both lack any `.git`/manifest signal can fall back to distinct
|
|
416
|
+
but nested directories (e.g. `legacy/mod` and `legacy/mod/util`), generating two separate
|
|
417
|
+
`contracts/` entries for what may be one logical service — no automatic consolidation; this is
|
|
418
|
+
the same class of ambiguity NFR-002 already accepts elsewhere in Part 2 rather than
|
|
419
|
+
guessing. Sharper case of the same limitation: if a nested fallback identity's final path
|
|
420
|
+
segment is literally `code`, `data`, `mock`, or `default` (e.g. `legacy/mod` and
|
|
421
|
+
`legacy/mod/code`), the inner service's `manifest.yaml` lands inside the outer service's own
|
|
422
|
+
generated `code/`/`data/`/`mock/`/`default/` output directory — still not a write outside
|
|
423
|
+
`agent-docs/doflow/<slug>/scaffold/` (the first Constraint above still holds), but visually
|
|
424
|
+
confusing; not auto-detected or renamed.
|
|
425
|
+
- The one hard gate is `do-execute-plan` step 1 (`"$DOFLOW" prereqs --require-plan`) — neither Part
|
|
426
|
+
of this file adds a gate of its own. The advisory notice Part 2 raises for a dependency it cannot
|
|
427
|
+
resolve is non-blocking, and Part 1's non-zero exit is a finding to report, not a stop.
|
|
428
|
+
- A `depends-on:` value whose starting directory does not exist on disk at all is excluded from
|
|
429
|
+
service-identity derivation *entirely* (Part 2 step 1) — it never reaches Part 2 step 5's local
|
|
430
|
+
generation path. It gets a frame only if the same task also carries an `external-contract:` field
|
|
431
|
+
(step 2's
|
|
432
|
+
"documented dependency" case); with neither, it stays silently skipped, same as today's default.
|
|
433
|
+
- `external-contract:` targets MUST follow the pinned structure in
|
|
434
|
+
`templates/doflow/external-contract-template.md` — a `## Methods` section with at least one
|
|
435
|
+
grammar-conformant `interface` block, plus a `## Types` section (`## Webhook` is optional). A
|
|
436
|
+
non-compliant target gets an explicit warning, never a silently-empty or guessed frame — Part 2
|
|
437
|
+
does not attempt free-form prose extraction anywhere.
|
|
438
|
+
- A documented dependency's frame renders in the *consuming* task's own inferred language (Part 2
|
|
439
|
+
step 4,
|
|
440
|
+
reused unchanged, applied to the consumer's repo) — never a language inferred from the
|
|
441
|
+
dependency itself, which has no local repo to infer one from.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Task attempts
|
|
2
|
+
|
|
3
|
+
A task is done when the ledger says so, never from a `[x]` box or a `state.md` row. Every call takes
|
|
4
|
+
`--slug "<slug>"` (step 1's `feature_slug`) and `--json`; `<task id>` is the plan id (`A.1`).
|
|
5
|
+
|
|
6
|
+
**At resume**, read `"$DOFLOW" task-attempt --action status --slug "<slug>" --json` and branch on
|
|
7
|
+
each task's `derived`: `done` skip; `ready` claim; `running` inspect `active` (owner, start) and
|
|
8
|
+
release it if that worker is gone; `blocked` report it; `pending` an earlier phase is open. A task in
|
|
9
|
+
`unclaimedChecked` is ticked without a COMPLETED attempt: claim and verify it, or untick it.
|
|
10
|
+
|
|
11
|
+
**Before dispatch**, claim. `--mode` is `subagent`, `sequential` or `manual`:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
"$DOFLOW" task-attempt --action claim --slug "<slug>" --task "<task id>" --owner "<agent>" --mode subagent --json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`claimed` returns the `token`; keep it. A refusal (exit 1) means do not dispatch: `active-attempt`,
|
|
18
|
+
`already-done`, `unmet-phase` (an earlier-phase task lacks a COMPLETED attempt; `unmet` lists them)
|
|
19
|
+
or `unknown-task`.
|
|
20
|
+
|
|
21
|
+
**After the agent returns**, verify in the parent run, record the result as evidence after the
|
|
22
|
+
claim (`--kind test-result --observed-command "<cmd>" --observed-exit <n>`, schema in the guidance
|
|
23
|
+
tree's `references/EVIDENCE_LEDGER.md`), then finish with the evidence id it returned:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
"$DOFLOW" task-attempt --action finish --slug "<slug>" --task "<task id>" --token <token> --result COMPLETED --evidence-id "<id>" --json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
COMPLETED needs an active, non-stale `test-result` that exited 0, is bound to the slug or the task
|
|
30
|
+
id, and was observed no earlier than the claim. The refusal names the reason; fix it and finish again.
|
|
31
|
+
`plan-changed` means the task's plan line was edited after the claim: release, reread, claim again.
|
|
32
|
+
|
|
33
|
+
**Otherwise** finish with `BLOCKED`, `ABANDONED` or `INCONCLUSIVE` (no evidence needed), or abandon a
|
|
34
|
+
dispatch with `--action release --token <token> --reason "<why>"`. `stale` (exit 1) means the token
|
|
35
|
+
is no longer the active one, so a late result from an abandoned dispatch changed nothing; read
|
|
36
|
+
`status`. There is no lease: a crashed claimer is cleared only by an explicit release.
|
|
37
|
+
|
|
38
|
+
**Before step 10**, read `status`; `complete: true` means every plan task has a COMPLETED attempt.
|
|
39
|
+
`orchestrate` refuses to complete this stage while a ledger exists and is incomplete, and records
|
|
40
|
+
`unverified` when the feature has no ledger. Exit 2 (malformed input, torn or newer-version store)
|
|
41
|
+
leaves the file unchanged: report it, do not repair it.
|