@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,335 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lib.sh — shared constants and helpers for session lifecycle hooks
|
|
3
|
+
#
|
|
4
|
+
# Usage: source "$(dirname "$0")/lib.sh"
|
|
5
|
+
#
|
|
6
|
+
# All hooks must:
|
|
7
|
+
# 1. source this file at the top
|
|
8
|
+
# 2. call require_jq immediately after
|
|
9
|
+
# 3. capture stdin once: INPUT=$(cat)
|
|
10
|
+
# 4. use: json_field "$INPUT" ".field_name"
|
|
11
|
+
#
|
|
12
|
+
# Deployment:
|
|
13
|
+
# This file is installed by the doflow CLI and overwritten on update — do
|
|
14
|
+
# not edit an installed copy directly.
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
# ── State directories ────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
# XDG-compliant, agent-agnostic store shared by Claude Code, Codex, Gemini, etc.
|
|
21
|
+
DOFLOW_HOME="${XDG_CONFIG_HOME:-$HOME/.config}/doflow"
|
|
22
|
+
STATE_DIR="$DOFLOW_HOME/session-env"
|
|
23
|
+
SESSION_DIR="$STATE_DIR/sessions"
|
|
24
|
+
PROJECTS_DIR="$STATE_DIR/projects"
|
|
25
|
+
# shellcheck disable=SC2034 # used by session-start.sh and session-end.sh which source this file
|
|
26
|
+
SESSIONS_LOG="$DOFLOW_HOME/sessions.log"
|
|
27
|
+
|
|
28
|
+
# Identifies which agent is running. Override via env var for non-Claude agents.
|
|
29
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-unknown}"
|
|
30
|
+
|
|
31
|
+
# ── canonicalize_path ────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
# Print an absolute, symlink-resolved form of $1 when it exists; otherwise
|
|
34
|
+
# print $1 unchanged. Replaces `realpath -e "$1" 2>/dev/null || echo "$1"`,
|
|
35
|
+
# which silently falls back to an uncanonicalized path on stock macOS (BSD
|
|
36
|
+
# realpath has no -e flag). Uses only primitives present on every target
|
|
37
|
+
# (cd, pwd -P, dirname, basename) — no GNU-only flag, no assumed Homebrew
|
|
38
|
+
# coreutils.
|
|
39
|
+
#
|
|
40
|
+
# Hardening notes:
|
|
41
|
+
# - `CDPATH=` resets CDPATH for the internal `cd` so a user's exported
|
|
42
|
+
# CDPATH can't redirect it to an unrelated directory of the same name
|
|
43
|
+
# (and can't make `cd` echo a stray "found via CDPATH" line to stdout).
|
|
44
|
+
# - `--` guards `dirname`/`basename`/`cd` against a path that begins with
|
|
45
|
+
# `-` being parsed as an option.
|
|
46
|
+
# - if the internal `cd` fails for any reason, `||` falls through to the
|
|
47
|
+
# uncanonicalized-path branch instead of aborting under this file's
|
|
48
|
+
# `set -e` (matching the old `realpath ... || echo "$1"` degrade path).
|
|
49
|
+
# - a root-level parent directory ("/") is special-cased so the result
|
|
50
|
+
# never gets a leading `//`, which POSIX leaves undefined and which
|
|
51
|
+
# Cygwin/MSYS2 (a DoFlow target platform) interprets as a UNC path.
|
|
52
|
+
canonicalize_path() {
|
|
53
|
+
local path="$1" dir base
|
|
54
|
+
if [[ -e "$path" ]] \
|
|
55
|
+
&& dir=$(CDPATH= cd -P -- "$(dirname -- "$path")" 2>/dev/null && pwd -P); then
|
|
56
|
+
base=$(basename -- "$path")
|
|
57
|
+
if [[ "$dir" == "/" ]]; then
|
|
58
|
+
printf '/%s\n' "$base"
|
|
59
|
+
else
|
|
60
|
+
printf '%s/%s\n' "$dir" "$base"
|
|
61
|
+
fi
|
|
62
|
+
else
|
|
63
|
+
printf '%s\n' "$path"
|
|
64
|
+
fi
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# ── with_file_lock ───────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
# Internal: break in on $1 (a lock directory) if it looks abandoned — its
|
|
70
|
+
# recorded owner PID is no longer alive, or it's older than 5x the caller's
|
|
71
|
+
# timeout (floored at 30s so short test timeouts don't make legitimately-held
|
|
72
|
+
# locks look stale). Best-effort: mkdir-based locking has no kernel-enforced
|
|
73
|
+
# ownership the way flock did, so a PID can in principle be reused by an
|
|
74
|
+
# unrelated process — the age check is the backstop for that race. The
|
|
75
|
+
# guarded section this protects (session-log trimming) tolerates a rare
|
|
76
|
+
# double-run; this is a soft safety net against a lock leaking forever after
|
|
77
|
+
# its owner is SIGKILLed, not a hard mutual-exclusion guarantee.
|
|
78
|
+
_with_file_lock_break_if_stale() {
|
|
79
|
+
local lockfile="$1"
|
|
80
|
+
local timeout_seconds="$2"
|
|
81
|
+
|
|
82
|
+
local owner_pid=""
|
|
83
|
+
[ -f "$lockfile/pid" ] && owner_pid=$(cat "$lockfile/pid" 2>/dev/null || true)
|
|
84
|
+
local owner_dead=0
|
|
85
|
+
if [ -n "$owner_pid" ] && ! kill -0 "$owner_pid" 2>/dev/null; then
|
|
86
|
+
owner_dead=1
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
local too_old=0
|
|
90
|
+
local mtime
|
|
91
|
+
mtime=$(stat -f %m "$lockfile" 2>/dev/null || stat -c %Y "$lockfile" 2>/dev/null || echo "")
|
|
92
|
+
if [ -n "$mtime" ]; then
|
|
93
|
+
local max_age=$((timeout_seconds * 5))
|
|
94
|
+
[ "$max_age" -lt 30 ] && max_age=30
|
|
95
|
+
if [ $(($(date +%s) - mtime)) -gt "$max_age" ]; then
|
|
96
|
+
too_old=1
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [ "$owner_dead" -eq 1 ] || [ "$too_old" -eq 1 ]; then
|
|
101
|
+
rm -rf "$lockfile" 2>/dev/null || true
|
|
102
|
+
fi
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Acquire a lock via atomic `mkdir` (atomic on every filesystem DoFlow runs
|
|
106
|
+
# on, including NTFS via MSYS2) — replaces `flock -x -w 5 200`, which is
|
|
107
|
+
# util-linux-only and confirmed absent entirely on macOS.
|
|
108
|
+
#
|
|
109
|
+
# Usage: call to acquire, run the guarded section in the same shell/subshell,
|
|
110
|
+
# then call again with "release" to release. The lock is also released
|
|
111
|
+
# automatically on exit (normal or error) via an EXIT trap, so a crashed or
|
|
112
|
+
# early-exiting guarded section never leaves the lock held.
|
|
113
|
+
#
|
|
114
|
+
# if with_file_lock "$LOCK_FILE" 5; then
|
|
115
|
+
# ...guarded section...
|
|
116
|
+
# with_file_lock "$LOCK_FILE" release
|
|
117
|
+
# fi
|
|
118
|
+
#
|
|
119
|
+
# Returns 1 (without acquiring the lock) if timeout_seconds elapses first.
|
|
120
|
+
# A lock whose owner process is gone, or that has sat far longer than the
|
|
121
|
+
# caller's own timeout, is treated as abandoned and broken into rather than
|
|
122
|
+
# waited out (see _with_file_lock_break_if_stale) — a `flock`-held lock was
|
|
123
|
+
# always released by the kernel on process death; a bare `mkdir` lock is not,
|
|
124
|
+
# so this replaces that guarantee instead of silently dropping it.
|
|
125
|
+
#
|
|
126
|
+
# Any EXIT trap the caller already had installed (e.g. its own temp-file
|
|
127
|
+
# cleanup) is preserved: it still runs at real process exit (after this
|
|
128
|
+
# lock's own cleanup), and is still armed as the active EXIT trap after an
|
|
129
|
+
# explicit "release" call — acquiring/releasing this lock never discards it.
|
|
130
|
+
with_file_lock() {
|
|
131
|
+
local lockfile="$1"
|
|
132
|
+
local arg="$2"
|
|
133
|
+
|
|
134
|
+
if [ "$arg" = "release" ]; then
|
|
135
|
+
rm -f "$lockfile/pid" 2>/dev/null || true
|
|
136
|
+
rmdir "$lockfile" 2>/dev/null || true
|
|
137
|
+
if [ -n "${_DOFLOW_LOCK_PREV_TRAP:-}" ]; then
|
|
138
|
+
eval "$_DOFLOW_LOCK_PREV_TRAP"
|
|
139
|
+
else
|
|
140
|
+
trap - EXIT
|
|
141
|
+
fi
|
|
142
|
+
unset _DOFLOW_LOCK_PREV_TRAP
|
|
143
|
+
return 0
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
local timeout_seconds="$arg"
|
|
147
|
+
local waited=0
|
|
148
|
+
while ! mkdir "$lockfile" 2>/dev/null; do
|
|
149
|
+
_with_file_lock_break_if_stale "$lockfile" "$timeout_seconds"
|
|
150
|
+
if [ "$waited" -ge "$timeout_seconds" ]; then
|
|
151
|
+
return 1
|
|
152
|
+
fi
|
|
153
|
+
sleep 1
|
|
154
|
+
waited=$((waited + 1))
|
|
155
|
+
done
|
|
156
|
+
echo "$$" >"$lockfile/pid" 2>/dev/null || true
|
|
157
|
+
|
|
158
|
+
# Capture the caller's existing EXIT trap (if any) so releasing this lock
|
|
159
|
+
# can restore it verbatim, and so real process exit runs both this lock's
|
|
160
|
+
# cleanup and the caller's original cleanup rather than only the latest
|
|
161
|
+
# one registered.
|
|
162
|
+
_DOFLOW_LOCK_PREV_TRAP=$(trap -p EXIT)
|
|
163
|
+
local prev_cmd=""
|
|
164
|
+
if [ -n "$_DOFLOW_LOCK_PREV_TRAP" ]; then
|
|
165
|
+
local prev_body="${_DOFLOW_LOCK_PREV_TRAP#trap -- }"
|
|
166
|
+
prev_body="${prev_body% EXIT}"
|
|
167
|
+
eval "prev_cmd=$prev_body"
|
|
168
|
+
fi
|
|
169
|
+
# shellcheck disable=SC2064 # intentional immediate expansion of $lockfile/$prev_cmd
|
|
170
|
+
trap "rm -f '$lockfile/pid' 2>/dev/null; rmdir '$lockfile' 2>/dev/null; $prev_cmd" EXIT
|
|
171
|
+
return 0
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# ── run_with_timeout ─────────────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
# Run <command...> and terminate it if it exceeds <seconds>. Replaces bare
|
|
177
|
+
# GNU `timeout` calls, which are not installed by default on stock macOS
|
|
178
|
+
# without Homebrew coreutils. When neither a verified-GNU `timeout` nor
|
|
179
|
+
# `gtimeout` (the Homebrew coreutils name) is on PATH, runs the command
|
|
180
|
+
# directly with no enforced budget — a soft safety net, not a correctness
|
|
181
|
+
# requirement.
|
|
182
|
+
#
|
|
183
|
+
# `timeout` is not trusted just because something by that name is on PATH:
|
|
184
|
+
# on Git Bash/MSYS2, PATH can resolve it to Windows' native
|
|
185
|
+
# `System32\timeout.exe`, whose syntax (`timeout /T n`) is incompatible —
|
|
186
|
+
# invoking it the GNU way would fail the command outright instead of just
|
|
187
|
+
# running it unbounded. `timeout --version` is a cheap, side-effect-free way
|
|
188
|
+
# to confirm it's the GNU coreutils build before trusting it (Windows'
|
|
189
|
+
# timeout.exe doesn't understand --version and errors).
|
|
190
|
+
#
|
|
191
|
+
# Usage: run_with_timeout <seconds> -- <command...>
|
|
192
|
+
run_with_timeout() {
|
|
193
|
+
local seconds="$1"
|
|
194
|
+
shift
|
|
195
|
+
if [ "${1:-}" = "--" ]; then
|
|
196
|
+
shift
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
if command -v timeout &>/dev/null && timeout --version &>/dev/null; then
|
|
200
|
+
timeout "$seconds" "$@"
|
|
201
|
+
elif command -v gtimeout &>/dev/null; then
|
|
202
|
+
gtimeout "$seconds" "$@"
|
|
203
|
+
else
|
|
204
|
+
"$@"
|
|
205
|
+
fi
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# ── cwd_hash ─────────────────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
# Derive a stable 16-char hash of an absolute directory path.
|
|
211
|
+
# Used to namespace per-project state (compact summaries, warnings).
|
|
212
|
+
#
|
|
213
|
+
# For a path that is (or resolves to) an existing directory — the case this
|
|
214
|
+
# function exists for — fully resolves it, including a symlink at the path's
|
|
215
|
+
# own leaf component, via `(cd "$1" && pwd -P)`, so equivalent directories
|
|
216
|
+
# always hash identically. Callers that ever pass a non-directory or
|
|
217
|
+
# nonexistent path fall back to the general-purpose canonicalize_path, which
|
|
218
|
+
# — being usable by any file or missing path, not just directories — only
|
|
219
|
+
# resolves symlinks in the parent chain, not the leaf itself.
|
|
220
|
+
#
|
|
221
|
+
# Hash fallback chain: sha256sum -> shasum -a 256 -> cksum (last resort).
|
|
222
|
+
# The cksum branch is normalized via printf '%016x' to the same 16-char
|
|
223
|
+
# hex contract every other branch provides — raw cksum output is a decimal
|
|
224
|
+
# CRC, not hex, and not guaranteed to be 16 characters. Collision risk from
|
|
225
|
+
# the cksum fallback is acceptable here — this is only a cache-key
|
|
226
|
+
# namespace, not security-relevant.
|
|
227
|
+
cwd_hash() {
|
|
228
|
+
local canonical
|
|
229
|
+
if [ -d "$1" ]; then
|
|
230
|
+
canonical=$(cd "$1" && pwd -P)
|
|
231
|
+
else
|
|
232
|
+
canonical=$(canonicalize_path "$1")
|
|
233
|
+
fi
|
|
234
|
+
if command -v sha256sum &>/dev/null; then
|
|
235
|
+
echo "$canonical" | sha256sum | cut -c1-16
|
|
236
|
+
elif command -v shasum &>/dev/null; then
|
|
237
|
+
echo "$canonical" | shasum -a 256 | cut -c1-16
|
|
238
|
+
else
|
|
239
|
+
printf '%016x\n' "$(echo "$canonical" | cksum | cut -d' ' -f1)"
|
|
240
|
+
fi
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
# ── Git state helpers ────────────────────────────────────────────────────────
|
|
244
|
+
#
|
|
245
|
+
# Thin wrappers around `git -C <cwd> ...` with the project's standard 1s
|
|
246
|
+
# timeout. Each echoes git's own output (or nothing/0 on failure) and leaves
|
|
247
|
+
# stderr suppressed -- callers keep their own `|| echo <fallback>` around a
|
|
248
|
+
# call for a script-specific default, exactly as the inline git calls these
|
|
249
|
+
# replace did (022-hooks-remaining-duplication). Kept in this per-harness
|
|
250
|
+
# copy rather than moved to the canonical lib.sh's sourcing path: this
|
|
251
|
+
# script's own with_file_lock/other APIs have not been reconciled with the
|
|
252
|
+
# canonical copy, so repointing the `source` line is a separate, larger
|
|
253
|
+
# change this refactor does not make.
|
|
254
|
+
|
|
255
|
+
is_git_worktree() {
|
|
256
|
+
run_with_timeout 1 -- git -C "$1" rev-parse --is-inside-work-tree &>/dev/null
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
git_branch_of() {
|
|
260
|
+
run_with_timeout 1 -- git -C "$1" branch --show-current 2>/dev/null
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
git_short_sha_of() {
|
|
264
|
+
run_with_timeout 1 -- git -C "$1" rev-parse --short HEAD 2>/dev/null
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
git_uncommitted_count_of() {
|
|
268
|
+
run_with_timeout 1 -- git -C "$1" status --porcelain 2>/dev/null | wc -l | tr -d ' '
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
has_uncommitted_changes() {
|
|
272
|
+
run_with_timeout 1 -- git -C "$1" status --porcelain 2>/dev/null | grep -q .
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# ── Directory helpers ─────────────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
# Create and return the session-scoped state directory for a given session_id.
|
|
278
|
+
# Safe to call multiple times (mkdir -p is idempotent).
|
|
279
|
+
ensure_session_dir() {
|
|
280
|
+
local session_id="$1"
|
|
281
|
+
mkdir -p "$SESSION_DIR/$session_id"
|
|
282
|
+
echo "$SESSION_DIR/$session_id"
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
# Create and return the project-scoped state directory for a given cwd.
|
|
286
|
+
# Shared across all sessions in the same directory.
|
|
287
|
+
ensure_project_dir() {
|
|
288
|
+
local cwd="$1"
|
|
289
|
+
local hash
|
|
290
|
+
hash=$(cwd_hash "$cwd")
|
|
291
|
+
mkdir -p "$PROJECTS_DIR/$hash"
|
|
292
|
+
echo "$PROJECTS_DIR/$hash"
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
# ── JSON helpers ──────────────────────────────────────────────────────────────
|
|
296
|
+
|
|
297
|
+
# Extract a field from a JSON string.
|
|
298
|
+
# Usage: json_field "$INPUT" ".field_name"
|
|
299
|
+
# Returns empty string if field is null or jq fails.
|
|
300
|
+
json_field() {
|
|
301
|
+
local json="$1"
|
|
302
|
+
local query="$2"
|
|
303
|
+
echo "$json" | jq -r "$query // empty" 2>/dev/null || echo ""
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
# ── Dependency guard ──────────────────────────────────────────────────────────
|
|
307
|
+
|
|
308
|
+
# Verify jq is available at runtime. If absent, emit a diagnostic to stderr
|
|
309
|
+
# and exit 0 (never block the harness — degraded operation is preferable to failure).
|
|
310
|
+
require_jq() {
|
|
311
|
+
if ! command -v jq &>/dev/null; then
|
|
312
|
+
echo "[hooks] jq not found — install jq to enable session lifecycle hooks (apt install jq / brew install jq)" >&2
|
|
313
|
+
exit 0
|
|
314
|
+
fi
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
# ── Session role ──────────────────────────────────────────────────────────────
|
|
318
|
+
|
|
319
|
+
# Print `main` or `worker` for this session, read from DOFLOW_SESSION_ROLE (matched
|
|
320
|
+
# case-insensitively). Unset or empty is `main`; a value that is neither `main` nor
|
|
321
|
+
# `worker` is `worker` and writes one line to stderr. A worker never writes or claims the
|
|
322
|
+
# project's compact summary or warning. Always returns 0. bash 3.2 safe (no ${var,,}).
|
|
323
|
+
doflow_session_role() {
|
|
324
|
+
local role
|
|
325
|
+
role=$(printf '%s' "${DOFLOW_SESSION_ROLE:-}" | tr '[:upper:]' '[:lower:]') || role=""
|
|
326
|
+
case "$role" in
|
|
327
|
+
""|main) printf 'main\n' ;;
|
|
328
|
+
worker) printf 'worker\n' ;;
|
|
329
|
+
*)
|
|
330
|
+
echo "[doflow] unknown DOFLOW_SESSION_ROLE; treating session as worker" >&2
|
|
331
|
+
printf 'worker\n'
|
|
332
|
+
;;
|
|
333
|
+
esac
|
|
334
|
+
return 0
|
|
335
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex front door: delegates the mcp-tool-guard decision to the Canonical Policy
|
|
3
|
+
# Library, then translates it into the hookSpecificOutput.permissionDecision deny
|
|
4
|
+
# contract this script's Codex/Claude originals both used — exit code alone is
|
|
5
|
+
# not sufficient here, so this front door is a translator, not a bare exec
|
|
6
|
+
# (unlike session-context/stop-check, which never need this translation).
|
|
7
|
+
set -uo pipefail
|
|
8
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-codex}"
|
|
9
|
+
|
|
10
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
11
|
+
source "$(dirname "$0")/../../.doflow/shared/hooks/policies/deny-json.sh"
|
|
12
|
+
|
|
13
|
+
POLICY="$(dirname "$0")/../../.doflow/shared/hooks/policies/mcp-tool-guard.sh"
|
|
14
|
+
REASON=$(bash "$POLICY" 2>&1 >/dev/null)
|
|
15
|
+
CODE=$?
|
|
16
|
+
|
|
17
|
+
[ "$CODE" -ne 0 ] && emit_pretooluse_deny_nested "${REASON:-MCP tool call blocked by mcp-tool-guard}"
|
|
18
|
+
exit 0
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# post-edit-lint.impl.sh — PostToolUse(Edit|Write|apply_patch) hook, shared across harnesses
|
|
3
|
+
#
|
|
4
|
+
# Pure collector: appends the edited/written file_path to a session-scoped
|
|
5
|
+
# list. The actual lint work happens in stop-check.sh at the end of each
|
|
6
|
+
# turn, where all paths can be batched by extension in one pass.
|
|
7
|
+
#
|
|
8
|
+
# Multi-session safe: writes only to sessions/{session_id}/edited-files.txt.
|
|
9
|
+
# Must complete in <20ms. Must never exit non-zero or produce unexpected output.
|
|
10
|
+
# Emits no stdout, so this script's output has no harness-specific compatibility
|
|
11
|
+
# question (unlike pre-compact.impl.sh) — every harness accepts a silent exit 0.
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
# shellcheck source=lib.sh
|
|
15
|
+
source "$(dirname "$0")/lib.sh"
|
|
16
|
+
require_jq
|
|
17
|
+
|
|
18
|
+
INPUT=$(cat)
|
|
19
|
+
SESSION_ID=$(json_field "$INPUT" ".session_id")
|
|
20
|
+
TOOL_NAME=$(json_field "$INPUT" ".tool_name")
|
|
21
|
+
|
|
22
|
+
# Only handle Edit/Write (Claude, Gemini) and apply_patch (Codex's edit tool name)
|
|
23
|
+
[[ "$TOOL_NAME" != "Edit" && "$TOOL_NAME" != "Write" && "$TOOL_NAME" != "apply_patch" ]] && exit 0
|
|
24
|
+
|
|
25
|
+
# Guard: if we can't determine the session, nothing to do
|
|
26
|
+
[[ -z "$SESSION_ID" ]] && exit 0
|
|
27
|
+
|
|
28
|
+
SESSION_PATH=$(ensure_session_dir "$SESSION_ID")
|
|
29
|
+
|
|
30
|
+
if [[ "$TOOL_NAME" == "apply_patch" ]]; then
|
|
31
|
+
# Codex's apply_patch has no tool_input.file_path — tool_input is
|
|
32
|
+
# {"command": "<raw patch text>"}, a unified-diff-style patch that can touch
|
|
33
|
+
# multiple files via "*** Add File:" / "*** Update File:" / "*** Delete File:"
|
|
34
|
+
# / "*** Move to:" headers (confirmed against codex-rs/core/prompt_with_apply_patch_instructions.md
|
|
35
|
+
# and apply_patch_tests.rs — there is no single file_path field to read).
|
|
36
|
+
PATCH=$(json_field "$INPUT" ".tool_input.command")
|
|
37
|
+
[[ -z "$PATCH" ]] && exit 0
|
|
38
|
+
echo "$PATCH" | grep -oE '^\*\*\* (Add File|Update File|Delete File|Move to): .+' \
|
|
39
|
+
| sed -E 's/^\*\*\* (Add File|Update File|Delete File|Move to): //' \
|
|
40
|
+
>> "$SESSION_PATH/edited-files.txt" || true
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
FILE_PATH=$(json_field "$INPUT" ".tool_input.file_path")
|
|
45
|
+
|
|
46
|
+
# Skip if no file_path (e.g., field absent from input)
|
|
47
|
+
[[ -z "$FILE_PATH" ]] && exit 0
|
|
48
|
+
|
|
49
|
+
# Append path (one per line) — stop-check.sh reads this list atomically
|
|
50
|
+
echo "$FILE_PATH" >> "$SESSION_PATH/edited-files.txt"
|
|
51
|
+
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex adapter: post-edit-lint.impl.sh writes no stdout (session-file collector only),
|
|
3
|
+
# so there is no output-format compatibility question here, unlike pre-compact.sh.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
export DOFLOW_AGENT=codex
|
|
6
|
+
exec bash "$(dirname "$0")/post-edit-lint.impl.sh"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex front door: delegates the pre-bash-guard decision to the Canonical Policy
|
|
3
|
+
# Library, then translates it into the hookSpecificOutput.permissionDecision deny
|
|
4
|
+
# contract this script's Codex/Claude originals both used — exit code alone is
|
|
5
|
+
# not sufficient here, so this front door is a translator, not a bare exec
|
|
6
|
+
# (unlike session-context/stop-check, which never need this translation).
|
|
7
|
+
set -uo pipefail
|
|
8
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-codex}"
|
|
9
|
+
|
|
10
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
11
|
+
source "$(dirname "$0")/../../.doflow/shared/hooks/policies/deny-json.sh"
|
|
12
|
+
|
|
13
|
+
POLICY="$(dirname "$0")/../../.doflow/shared/hooks/policies/pre-bash-guard.sh"
|
|
14
|
+
REASON=$(bash "$POLICY" 2>&1 >/dev/null)
|
|
15
|
+
CODE=$?
|
|
16
|
+
|
|
17
|
+
[ "$CODE" -ne 0 ] && emit_pretooluse_deny_nested "${REASON:-Command blocked by pre-bash-guard}"
|
|
18
|
+
exit 0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pre-compact.impl.sh — PreCompact hook (Codex-specific output shape)
|
|
3
|
+
#
|
|
4
|
+
# Codex's PreCompact output schema (codex-rs/hooks/src/schema.rs::PreCompactCommandOutputWire)
|
|
5
|
+
# flattens only HookUniversalOutputWire (continue/stopReason/suppressOutput/systemMessage) and
|
|
6
|
+
# rejects unknown fields — there is no additionalContext-style field for PreCompact, and the
|
|
7
|
+
# output MUST be valid JSON, unlike Claude's PreCompact hook, which reads a plain string as
|
|
8
|
+
# custom_instructions. This script gathers the same git-state context Claude's pre-compact.sh
|
|
9
|
+
# does, but emits it as a JSON systemMessage instead — the closest available field, though
|
|
10
|
+
# systemMessage's exact downstream effect on compaction content is not confirmed (Claude's
|
|
11
|
+
# custom_instructions is fed directly to the compaction LLM call; Codex's docs do not state that
|
|
12
|
+
# systemMessage receives the same treatment). Treat this as best-effort context surfacing, not a
|
|
13
|
+
# guaranteed compaction-summary injection, until verified against a live Codex session.
|
|
14
|
+
#
|
|
15
|
+
# Must never exit non-zero or block (PreCompact hooks do not support a block decision in Codex).
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
# shellcheck source=lib.sh
|
|
19
|
+
source "$(dirname "$0")/lib.sh"
|
|
20
|
+
require_jq
|
|
21
|
+
|
|
22
|
+
INPUT=$(cat)
|
|
23
|
+
CWD=$(json_field "$INPUT" ".cwd")
|
|
24
|
+
|
|
25
|
+
BRANCH=""
|
|
26
|
+
SHA=""
|
|
27
|
+
UNCOMMITTED=0
|
|
28
|
+
|
|
29
|
+
if [[ -n "$CWD" ]] && is_git_worktree "$CWD"; then
|
|
30
|
+
BRANCH=$(git_branch_of "$CWD" || echo "")
|
|
31
|
+
SHA=$(git_short_sha_of "$CWD" || echo "")
|
|
32
|
+
UNCOMMITTED=$(git_uncommitted_count_of "$CWD" || echo "0")
|
|
33
|
+
RECENT=$(run_with_timeout 1 -- git -C "$CWD" log --format="%h %s" -2 2>/dev/null | paste -sd ' | ' - || echo "")
|
|
34
|
+
|
|
35
|
+
MSG=$(printf 'Include in compact summary:\n- git branch: %s sha: %s\n- recent commits: %s\n- uncommitted files: %s\n- cwd: %s\nPreserve: decisions made, files modified, open questions, planned next steps.' \
|
|
36
|
+
"${BRANCH:-unknown}" "${SHA:-unknown}" "${RECENT:-none}" "$UNCOMMITTED" "${CWD:-unknown}")
|
|
37
|
+
else
|
|
38
|
+
MSG=$(printf 'Include in compact summary:\n- cwd: %s (not a git repository)\nPreserve: decisions made, files modified, open questions, planned next steps.' \
|
|
39
|
+
"${CWD:-unknown}")
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Hard-cap at 490 chars, matching Claude's script, before JSON-encoding.
|
|
43
|
+
MSG="${MSG:0:490}"
|
|
44
|
+
|
|
45
|
+
jq -n --arg systemMessage "$MSG" '{systemMessage: $systemMessage}'
|
|
46
|
+
exit 0
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex adapter: pre-compact.impl.sh is Codex-specific, NOT a shared/impl-reuse of Claude's
|
|
3
|
+
# script — Codex's PreCompact output schema (PreCompactCommandOutputWire) only accepts the
|
|
4
|
+
# universal fields (continue/stopReason/suppressOutput/systemMessage) as JSON, with unknown
|
|
5
|
+
# fields rejected; it has no additionalContext-equivalent and Claude's plain-string output would
|
|
6
|
+
# not parse. See pre-compact.impl.sh for the adapted implementation.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
export DOFLOW_AGENT=codex
|
|
9
|
+
exec bash "$(dirname "$0")/pre-compact.impl.sh"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex front door: delegates the pre-implementation-gate decision to the
|
|
3
|
+
# Canonical Policy Library, then translates it into the
|
|
4
|
+
# hookSpecificOutput.permissionDecision deny contract this script's Codex/Claude
|
|
5
|
+
# originals both used — exit code alone is not sufficient here, so this front
|
|
6
|
+
# door is a translator, not a bare exec (unlike session-context/stop-check,
|
|
7
|
+
# which never need this translation).
|
|
8
|
+
set -uo pipefail
|
|
9
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-codex}"
|
|
10
|
+
|
|
11
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
12
|
+
source "$(dirname "$0")/../../.doflow/shared/hooks/policies/deny-json.sh"
|
|
13
|
+
|
|
14
|
+
POLICY="$(dirname "$0")/../../.doflow/shared/hooks/policies/pre-implementation-gate.sh"
|
|
15
|
+
REASON=$(bash "$POLICY" 2>&1 >/dev/null)
|
|
16
|
+
CODE=$?
|
|
17
|
+
|
|
18
|
+
[ "$CODE" -ne 0 ] && emit_pretooluse_deny_nested "${REASON:-Implementation requires an approved plan.md}"
|
|
19
|
+
exit 0
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# session-end.sh — SessionEnd hook
|
|
3
|
+
#
|
|
4
|
+
# Runs when Claude Code closes a session. Responsibilities:
|
|
5
|
+
# 1. Append END marker to sessions.log
|
|
6
|
+
# 2. Write uncommitted-warning.txt if the working tree is dirty
|
|
7
|
+
# 3. Delete the session-scoped state directory (cleanup)
|
|
8
|
+
# 4. Trim sessions.log to last 500 lines (lock-guarded for parallel safety,
|
|
9
|
+
# via lib.sh's portable with_file_lock — no flock dependency)
|
|
10
|
+
#
|
|
11
|
+
# Multi-session safe: with_file_lock prevents concurrent sessions from
|
|
12
|
+
# corrupting the log trim. Session directory deletion is per session_id so
|
|
13
|
+
# sessions don't interfere.
|
|
14
|
+
# Must never exit non-zero or block (SessionEnd is fire-and-forget).
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
# shellcheck source=lib.sh
|
|
18
|
+
source "$(dirname "$0")/lib.sh"
|
|
19
|
+
require_jq
|
|
20
|
+
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
SESSION_ID=$(json_field "$INPUT" ".session_id")
|
|
23
|
+
CWD=$(json_field "$INPUT" ".cwd")
|
|
24
|
+
|
|
25
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
26
|
+
|
|
27
|
+
# ── 1. Log session end ────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
mkdir -p "$(dirname "$SESSIONS_LOG")"
|
|
30
|
+
echo "$TIMESTAMP END ${SESSION_ID:-unknown} ${CWD:-unknown}" >> "$SESSIONS_LOG"
|
|
31
|
+
|
|
32
|
+
# ── 2. Uncommitted-changes warning ────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
# A worker session never writes the project's warning; it is left for the main session.
|
|
35
|
+
if [[ "$(doflow_session_role || echo main)" != "worker" ]] && [[ -n "$CWD" ]] && is_git_worktree "$CWD"; then
|
|
36
|
+
if has_uncommitted_changes "$CWD"; then
|
|
37
|
+
BRANCH=$(git_branch_of "$CWD" || echo "unknown")
|
|
38
|
+
PROJECT_DIR=$(ensure_project_dir "$CWD")
|
|
39
|
+
echo "Session ${SESSION_ID:-unknown} ended with uncommitted changes on branch ${BRANCH}" \
|
|
40
|
+
> "$PROJECT_DIR/uncommitted-warning.txt"
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# ── 2b. Update meta.json last_active ─────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
if [[ -n "$CWD" ]]; then
|
|
47
|
+
PROJECT_DIR=$(ensure_project_dir "$CWD")
|
|
48
|
+
if [[ -f "$PROJECT_DIR/meta.json" ]]; then
|
|
49
|
+
META_TMP=$(mktemp "$PROJECT_DIR/.meta.XXXXXX")
|
|
50
|
+
jq --arg ts "$TIMESTAMP" '.last_active = $ts' "$PROJECT_DIR/meta.json" \
|
|
51
|
+
> "$META_TMP" && mv "$META_TMP" "$PROJECT_DIR/meta.json" \
|
|
52
|
+
|| rm -f "$META_TMP" 2>/dev/null || true
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# ── 3. Delete session directory ───────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
if [[ -n "$SESSION_ID" ]]; then
|
|
59
|
+
SESSION_PATH="$SESSION_DIR/$SESSION_ID"
|
|
60
|
+
rm -rf "$SESSION_PATH" 2>/dev/null || true
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
(
|
|
64
|
+
SHARED_POLICY_LIB="$(dirname "$0")/../../.doflow/shared/hooks/policies/lib.sh"
|
|
65
|
+
if [[ ! -f "$SHARED_POLICY_LIB" ]]; then
|
|
66
|
+
SHARED_POLICY_LIB="$(dirname "$0")/../../shared/hooks/policies/lib.sh"
|
|
67
|
+
fi
|
|
68
|
+
if [[ -f "$SHARED_POLICY_LIB" ]]; then
|
|
69
|
+
source "$SHARED_POLICY_LIB"
|
|
70
|
+
storage_upkeep_async "$CWD"
|
|
71
|
+
fi
|
|
72
|
+
) >/dev/null 2>&1 || true
|
|
73
|
+
|
|
74
|
+
# ── 4. Trim sessions.log (lock-guarded) ───────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
LOCK_FILE="${SESSIONS_LOG}.lock"
|
|
77
|
+
# Give up after 5s rather than block indefinitely: if the lock is held, skip
|
|
78
|
+
# the trim below and fall through to a normal exit 0 (SessionEnd is
|
|
79
|
+
# fire-and-forget and must never exit non-zero or block).
|
|
80
|
+
if with_file_lock "$LOCK_FILE" 5; then
|
|
81
|
+
if [[ -f "$SESSIONS_LOG" ]]; then
|
|
82
|
+
TMP=$(mktemp "${SESSIONS_LOG}.XXXXXX")
|
|
83
|
+
if tail -n 500 "$SESSIONS_LOG" > "$TMP"; then
|
|
84
|
+
mv "$TMP" "$SESSIONS_LOG" || rm -f "$TMP"
|
|
85
|
+
else
|
|
86
|
+
rm -f "$TMP"
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
with_file_lock "$LOCK_FILE" release
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
exit 0
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex adapter: preserve a blocking exit while returning valid Stop JSON on success.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-codex}"
|
|
5
|
+
rc=0
|
|
6
|
+
bash "$(dirname "$0")/../../.doflow/shared/hooks/policies/stop-check.sh" || rc=$?
|
|
7
|
+
[ "$rc" -eq 2 ] && exit 2
|
|
8
|
+
printf '{}\n'
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex front door: reuse the canonical subagent-audit policy with Codex attribution, then emit
|
|
3
|
+
# the empty-JSON SubagentStop requires on success (022-hooks-remaining-duplication: claude/codex's
|
|
4
|
+
# copies were byte-identical; only this trailing JSON requirement is Codex-specific).
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-codex}"
|
|
7
|
+
bash "$(dirname "$0")/../../.doflow/shared/hooks/policies/subagent-audit.sh"
|
|
8
|
+
printf '{}\n'
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex front door: reuse the canonical context policy with the Codex output envelope.
|
|
3
|
+
# The shared policy selects Codex's hookSpecificOutput shape from this attribution.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
export DOFLOW_AGENT="${DOFLOW_AGENT:-codex}"
|
|
6
|
+
exec bash "$(dirname "$0")/../../.doflow/shared/hooks/policies/user-prompt-submit.sh"
|