@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,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Antigravity payload/decision adapter for the Cross-Harness Hook Runner (design.md C2's
|
|
5
|
+
* Payload Adapter / Decision Adapter seam, D2).
|
|
6
|
+
*
|
|
7
|
+
* Antigravity's own native contracts — evidenced by core/harnesses/antigravity/hooks/*.sh (the
|
|
8
|
+
* shims src/adapters/antigravity/index.js actually projects today) and
|
|
9
|
+
* src/adapters/antigravity/index.js's own GATE_MATCHER/hookGroups — are NOT uniform across
|
|
10
|
+
* events. Only PreToolUse and Stop are wired live there today:
|
|
11
|
+
*
|
|
12
|
+
* PreToolUse : stdin { toolCall: { name, args }, conversationId, workspacePaths, stepIdx }
|
|
13
|
+
* stdout { decision: "allow"|"deny"|"ask"|"force_ask", reason?, overwrite? }
|
|
14
|
+
* Stop : stdin { executionNum, terminationReason, fullyIdle, transcriptPath }
|
|
15
|
+
* stdout { decision: "continue", reason } to block the stop; NO positive field at
|
|
16
|
+
* all (silence) to let it proceed — confirmed by
|
|
17
|
+
* core/harnesses/antigravity/hooks/stop-check.sh's own header ("FAIL-OPEN
|
|
18
|
+
* DOCTRINE... silence lets the session end"). This is a different decision
|
|
19
|
+
* vocabulary than PreToolUse's allow/deny/ask/force_ask, not an oversight.
|
|
20
|
+
*
|
|
21
|
+
* SessionStart and PostToolUse have no dedicated Antigravity-native shim in
|
|
22
|
+
* src/adapters/antigravity/index.js's live projection; core/.antigravity-plugin/hooks.json (a
|
|
23
|
+
* separate, read-only-to-this-task artifact) documents both routed directly to the *Gemini*
|
|
24
|
+
* session-start.sh / post-edit-lint.sh scripts, which read the Claude/Gemini-style
|
|
25
|
+
* session_id/cwd/tool_name/tool_input field names, not the toolCall envelope above — this
|
|
26
|
+
* adapter honors that evidence for those two events rather than guessing at a toolCall shape
|
|
27
|
+
* with no corroborating source. No Phase A canonical policy owns PostToolUse today (only
|
|
28
|
+
* session-context, pre-implementation-gate, mcp-tool-guard, stop-check, pre-bash-guard exist),
|
|
29
|
+
* so its native shape is an ack passthrough either way.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const { FILE_PATH_ARG_FIELDS, COMMAND_ARG_FIELDS, firstArgField } = require('./arg-fields');
|
|
33
|
+
|
|
34
|
+
function toCanonical(event, payload) {
|
|
35
|
+
const safePayload = payload && typeof payload === 'object' ? payload : {};
|
|
36
|
+
|
|
37
|
+
switch (event) {
|
|
38
|
+
case 'SessionStart':
|
|
39
|
+
return { session_id: safePayload.session_id || '', cwd: safePayload.cwd || '' };
|
|
40
|
+
|
|
41
|
+
case 'PreToolUse': {
|
|
42
|
+
const toolCall = safePayload.toolCall || {};
|
|
43
|
+
const args = toolCall.args || {};
|
|
44
|
+
return {
|
|
45
|
+
tool_name: toolCall.name || '',
|
|
46
|
+
tool_input: {
|
|
47
|
+
file_path: firstArgField(args, FILE_PATH_ARG_FIELDS),
|
|
48
|
+
command: firstArgField(args, COMMAND_ARG_FIELDS),
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
case 'PostToolUse':
|
|
54
|
+
// No Phase A policy consumes this event — canonical shape kept for symmetry only.
|
|
55
|
+
return {
|
|
56
|
+
tool_name: safePayload.tool_name || '',
|
|
57
|
+
session_id: safePayload.session_id || '',
|
|
58
|
+
tool_input: { file_path: (safePayload.tool_input && safePayload.tool_input.file_path) || '' },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
case 'Stop':
|
|
62
|
+
return {
|
|
63
|
+
session_id: safePayload.session_id || '',
|
|
64
|
+
transcript_path: safePayload.transcriptPath || safePayload.transcript_path || '',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
case 'PreInvocation':
|
|
68
|
+
// No Phase A policy — ack only (injectSteps handled entirely in toNative).
|
|
69
|
+
return {};
|
|
70
|
+
|
|
71
|
+
default:
|
|
72
|
+
return safePayload;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toNative(event, decision) {
|
|
77
|
+
const safeDecision = decision || { decision: 'allow' };
|
|
78
|
+
|
|
79
|
+
switch (event) {
|
|
80
|
+
case 'PreToolUse':
|
|
81
|
+
if (safeDecision.decision === 'deny') {
|
|
82
|
+
return { decision: 'deny', reason: safeDecision.reason };
|
|
83
|
+
}
|
|
84
|
+
return { decision: 'allow' };
|
|
85
|
+
|
|
86
|
+
case 'PostToolUse':
|
|
87
|
+
// Preserve the existing empty-ack contract — no policy decision to report.
|
|
88
|
+
return {};
|
|
89
|
+
|
|
90
|
+
case 'Stop':
|
|
91
|
+
if (safeDecision.decision === 'deny') {
|
|
92
|
+
return { decision: 'continue', reason: safeDecision.reason };
|
|
93
|
+
}
|
|
94
|
+
// Silence (no positive field) lets the session stop, per Antigravity's own documented
|
|
95
|
+
// Stop contract — not the allow/deny vocabulary PreToolUse uses.
|
|
96
|
+
return {};
|
|
97
|
+
|
|
98
|
+
case 'PreInvocation':
|
|
99
|
+
return { injectSteps: [] };
|
|
100
|
+
|
|
101
|
+
case 'SessionStart':
|
|
102
|
+
// Side-effect-only event; Antigravity's own SessionStart routing writes no structured
|
|
103
|
+
// stdout today (routed directly to bash, which produces none).
|
|
104
|
+
return {};
|
|
105
|
+
|
|
106
|
+
default:
|
|
107
|
+
return { decision: 'allow' };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = { toCanonical, toNative };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared toolCall.args field-name lookup for the toolCall/args envelope adapters
|
|
5
|
+
* (antigravity.js, gemini.js's fallback path) both read when mapping to canonical
|
|
6
|
+
* file_path/command. Extracted because both adapters carried an identical copy.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const FILE_PATH_ARG_FIELDS = ['AbsolutePath', 'TargetFile', 'Path', 'file_path', 'path'];
|
|
10
|
+
const COMMAND_ARG_FIELDS = ['CommandLine', 'command'];
|
|
11
|
+
|
|
12
|
+
function firstArgField(args, fields) {
|
|
13
|
+
for (const field of fields) {
|
|
14
|
+
if (args && args[field]) return args[field];
|
|
15
|
+
}
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { FILE_PATH_ARG_FIELDS, COMMAND_ARG_FIELDS, firstArgField };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gemini CLI payload/decision adapter for the Cross-Harness Hook Runner (design.md C2's
|
|
5
|
+
* Payload Adapter / Decision Adapter seam, D2).
|
|
6
|
+
*
|
|
7
|
+
* Gemini's own native contract — evidenced by core/harnesses/gemini/hooks/*.sh and
|
|
8
|
+
* core/harnesses/gemini/hooks/hooks.json, all currently invoked directly by bash rather than
|
|
9
|
+
* through this runner — already speaks field names close to Claude/Codex/Kiro's, NOT
|
|
10
|
+
* Antigravity's toolCall/args envelope:
|
|
11
|
+
*
|
|
12
|
+
* SessionStart : stdin { session_id, cwd } (session-start.sh)
|
|
13
|
+
* BeforeTool (~PreToolUse): stdin { tool_name, tool_input: { file_path, command } }
|
|
14
|
+
* stdout { decision: "allow"|"deny", reason } — TOP-LEVEL, not
|
|
15
|
+
* nested under hookSpecificOutput.permissionDecision like
|
|
16
|
+
* Claude/Codex (confirmed in gemini/hooks/pre-bash-guard.sh's header).
|
|
17
|
+
* AfterTool (~PostToolUse): stdin { tool_name, tool_input: { file_path }, session_id }
|
|
18
|
+
* (post-edit-lint.sh) — stdout {} (ack; no Phase A policy owns this
|
|
19
|
+
* event, post-edit-lint.sh's collector role is out of FR-001's scope)
|
|
20
|
+
* Stop : NOT a documented Gemini lifecycle event — gemini/hooks/
|
|
21
|
+
* post-edit-lint.sh's own comment states "Gemini has no
|
|
22
|
+
* Stop-equivalent event," and no stop-check.sh ships under
|
|
23
|
+
* gemini/hooks/ today. Handled defensively below (same field-name
|
|
24
|
+
* union stop-check.sh itself accepts) in case a future Gemini
|
|
25
|
+
* version adds one, or in case core/harnesses/shared/hooks/hooks.json's
|
|
26
|
+
* existing (currently dangling) Stop entry is corrected to a real target.
|
|
27
|
+
*
|
|
28
|
+
* NFR-002 note: core/harnesses/shared/hooks/hooks.json has historically routed PreToolUse through
|
|
29
|
+
* this runner using Antigravity's { toolCall: { name, args } } envelope — inherited from this
|
|
30
|
+
* runner's original Antigravity-only design (see the runner's own prior header comment), not
|
|
31
|
+
* verified against Gemini's own documented schema above. toCanonical() below reads the
|
|
32
|
+
* tool_name/tool_input shape first (Gemini's own evidenced contract) and falls back to the
|
|
33
|
+
* toolCall envelope only if that shape isn't present, so this adapter is correct once that
|
|
34
|
+
* wiring is corrected without silently breaking before it is.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const { FILE_PATH_ARG_FIELDS, COMMAND_ARG_FIELDS, firstArgField } = require('./arg-fields');
|
|
38
|
+
|
|
39
|
+
function toCanonical(event, payload) {
|
|
40
|
+
const safePayload = payload && typeof payload === 'object' ? payload : {};
|
|
41
|
+
|
|
42
|
+
switch (event) {
|
|
43
|
+
case 'SessionStart':
|
|
44
|
+
return { session_id: safePayload.session_id || '', cwd: safePayload.cwd || '' };
|
|
45
|
+
|
|
46
|
+
case 'PreToolUse': {
|
|
47
|
+
if (safePayload.tool_name !== undefined || safePayload.tool_input !== undefined) {
|
|
48
|
+
const toolInput = safePayload.tool_input || {};
|
|
49
|
+
return {
|
|
50
|
+
tool_name: safePayload.tool_name || '',
|
|
51
|
+
tool_input: {
|
|
52
|
+
file_path: toolInput.file_path || '',
|
|
53
|
+
command: toolInput.command || '',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Defensive fallback: Antigravity-shaped envelope (see header note).
|
|
58
|
+
const toolCall = safePayload.toolCall || {};
|
|
59
|
+
const args = toolCall.args || {};
|
|
60
|
+
return {
|
|
61
|
+
tool_name: toolCall.name || '',
|
|
62
|
+
tool_input: {
|
|
63
|
+
file_path: firstArgField(args, FILE_PATH_ARG_FIELDS),
|
|
64
|
+
command: firstArgField(args, COMMAND_ARG_FIELDS),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
case 'PostToolUse':
|
|
70
|
+
return {
|
|
71
|
+
tool_name: safePayload.tool_name || '',
|
|
72
|
+
session_id: safePayload.session_id || '',
|
|
73
|
+
tool_input: { file_path: (safePayload.tool_input && safePayload.tool_input.file_path) || '' },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
case 'Stop':
|
|
77
|
+
return {
|
|
78
|
+
session_id: safePayload.session_id || '',
|
|
79
|
+
transcript_path: safePayload.transcript_path || safePayload.transcriptPath || '',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
default:
|
|
83
|
+
return safePayload;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function toNative(event, decision) {
|
|
88
|
+
const safeDecision = decision || { decision: 'allow' };
|
|
89
|
+
|
|
90
|
+
switch (event) {
|
|
91
|
+
case 'PreToolUse':
|
|
92
|
+
if (safeDecision.decision === 'deny') {
|
|
93
|
+
return { decision: 'deny', reason: safeDecision.reason };
|
|
94
|
+
}
|
|
95
|
+
return { decision: 'allow' };
|
|
96
|
+
|
|
97
|
+
case 'PostToolUse':
|
|
98
|
+
return {};
|
|
99
|
+
|
|
100
|
+
case 'Stop':
|
|
101
|
+
if (safeDecision.decision === 'deny') {
|
|
102
|
+
return { decision: 'deny', reason: safeDecision.reason };
|
|
103
|
+
}
|
|
104
|
+
return { decision: 'allow' };
|
|
105
|
+
|
|
106
|
+
case 'SessionStart':
|
|
107
|
+
return {};
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
return { decision: 'allow' };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = { toCanonical, toNative };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "DoFlow shared lifecycle hooks schema for Antigravity, Gemini, and Claude.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "bash \"$DOFLOW_PROJECT_DIR/.gemini/hooks/session-start.sh\""
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"PreToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "^(run_command|run_shell_command|replace_file_content|write_to_file|multi_replace_file_content|edit_file|Edit|Write)$",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "node \"$DOFLOW_PROJECT_DIR/.doflow/scripts/stream-hook-runner.js\""
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"PostToolUse": [
|
|
26
|
+
{
|
|
27
|
+
"matcher": "^(replace_file_content|write_to_file|multi_replace_file_content|edit_file|Edit|Write)$",
|
|
28
|
+
"hooks": [
|
|
29
|
+
{
|
|
30
|
+
"type": "command",
|
|
31
|
+
"command": "bash \"$DOFLOW_PROJECT_DIR/.gemini/hooks/post-edit-lint.sh\""
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"Stop": [
|
|
37
|
+
{
|
|
38
|
+
"hooks": [
|
|
39
|
+
{
|
|
40
|
+
"type": "command",
|
|
41
|
+
"command": "bash \"$DOFLOW_PROJECT_DIR/.gemini/hooks/stop-check.sh\""
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# blocked-patterns.conf — Dangerous command patterns for pre-bash-guard.sh
|
|
2
|
+
#
|
|
3
|
+
# Format (TAB-separated):
|
|
4
|
+
# regex<TAB>reason shown to the harness<TAB>exclude_regex (optional)
|
|
5
|
+
#
|
|
6
|
+
# Rules:
|
|
7
|
+
# - Lines beginning with # are comments (skipped)
|
|
8
|
+
# - Empty lines are skipped
|
|
9
|
+
# - Regex is POSIX Extended Regular Expression (ERE, as used by `grep -E`),
|
|
10
|
+
# matched case-insensitively against the full command string (RM and GIT run
|
|
11
|
+
# on a case-insensitive filesystem such as the macOS default), which
|
|
12
|
+
# includes any expanded heredocs or -m "..." arguments. Git and rm
|
|
13
|
+
# patterns use a command-context anchor:
|
|
14
|
+
# (^|[[:space:]]*(&&|\|\||;)[[:space:]]*)
|
|
15
|
+
# so they only fire when the dangerous text is an actual invocation,
|
|
16
|
+
# not when it appears as text inside a commit message or other argument.
|
|
17
|
+
# - Anchored patterns (those beginning with "(^|") are matched against the
|
|
18
|
+
# command with quoted text blanked out (pre-bash-guard.sh scrub_quotes),
|
|
19
|
+
# so echo "x && rm -rf /" or git commit -m "git reset --hard" is not a
|
|
20
|
+
# command. The argument of sh -c, bash -c, zsh -c and eval is NOT blanked
|
|
21
|
+
# (it executes). Every other pattern is matched against the full text.
|
|
22
|
+
# - The rm lines use a wider command position than the others: start of a
|
|
23
|
+
# line or after ; & | ( or a backtick, then optional sudo/command/time/
|
|
24
|
+
# nohup/exec/env (with options, VAR=x and, per wrapper, the options that take
|
|
25
|
+
# a separate argument: sudo -u/-g/-C/-h/-p/-r/-t/-U/-D/-R and --user/--group
|
|
26
|
+
# root, xargs -n/-I/-L/-P/-s/-d/-E/-a, env -u/-C/-S)/xargs/eval/then/do/else, then rm,
|
|
27
|
+
# \rm, /bin/rm or /usr/bin/rm. "git rm" and "echo rm -rf /" are therefore
|
|
28
|
+
# not matched. pre-bash-guard.sh's hardcoded floor uses the same rule.
|
|
29
|
+
# Matching is case-insensitive, so an uppercase flag-only option that shares a
|
|
30
|
+
# letter with a value-taking one (sudo -H beside -h, xargs -p beside -P) is
|
|
31
|
+
# treated as value-taking: a false deny, the fail-safe direction.
|
|
32
|
+
# - The git patterns accept git's global options before the subcommand
|
|
33
|
+
# (git -C dir push, git -c k=v push). The force-push rules block -f (also
|
|
34
|
+
# inside a flag cluster such as -uf), --force and a +refspec; the
|
|
35
|
+
# --force-with-lease form stays allowed, as the reason text advises, but a
|
|
36
|
+
# +refspec still blocks next to a lease (git push --force-with-lease origin +main).
|
|
37
|
+
# - The find rule blocks -delete, and -exec rm, off the root, a home directory
|
|
38
|
+
# or a system directory (among other start paths, find or \find or
|
|
39
|
+
# /usr/bin/find) when only -type, -maxdepth/-mindepth N, -mount, -xdev,
|
|
40
|
+
# -depth, -noleaf, -follow or -ignore_readdir_race follow the path: none of
|
|
41
|
+
# those narrows what is deleted. Any other predicate (-name, -path, -newer,
|
|
42
|
+
# -mtime, -size, -user, -empty ...) counts as scoping, so
|
|
43
|
+
# find ~ -name '*.pyc' -delete is allowed.
|
|
44
|
+
# - SQL patterns are intentionally NOT anchored — DROP/DELETE/TRUNCATE
|
|
45
|
+
# inside heredoc-to-psql pipelines are real execution and must be caught.
|
|
46
|
+
# - The optional third column is an exclude_regex: when present and the
|
|
47
|
+
# command ALSO matches it, the pattern line is skipped (not blocked).
|
|
48
|
+
# This is how negative-lookahead behavior (unsupported in POSIX ERE) is
|
|
49
|
+
# approximated — e.g. "git push --force" blocks force pushes, but the
|
|
50
|
+
# exclude_regex "--force-with-lease" lets that safer variant through.
|
|
51
|
+
# - First matching pattern wins — order matters
|
|
52
|
+
# - A malformed regex on any line is skipped (guard continues safely)
|
|
53
|
+
#
|
|
54
|
+
# Add project-specific patterns at the bottom of this file.
|
|
55
|
+
|
|
56
|
+
# ── Dangerous git operations ──────────────────────────────────────────────────
|
|
57
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)git([[:space:]]+(-[Cc][[:space:]]+[^[:space:];&|]+|--(git-dir|work-tree|namespace|exec-path)[[:space:]]+[^[:space:];&|]+|-[^[:space:];&|]+))*[[:space:]]+push([[:space:]]+[^[:space:];&|]+)*[[:space:]]+(--force|-[a-zA-Z]*f[a-zA-Z]*)([^-[:alnum:]]|$) Force push blocked — use --force-with-lease or confirm with user first
|
|
58
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)git([[:space:]]+(-[Cc][[:space:]]+[^[:space:];&|]+|--(git-dir|work-tree|namespace|exec-path)[[:space:]]+[^[:space:];&|]+|-[^[:space:];&|]+))*[[:space:]]+push([[:space:]]+[^[:space:];&|]+)*[[:space:]]+\+[^[:space:];&|]+ Force push blocked — use --force-with-lease or confirm with user first
|
|
59
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)git([[:space:]]+(-[Cc][[:space:]]+[^[:space:];&|]+|--(git-dir|work-tree|namespace|exec-path)[[:space:]]+[^[:space:];&|]+|-[^[:space:];&|]+))*[[:space:]]+reset --hard Destructive reset blocked — commit or stash changes before resetting
|
|
60
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)git([[:space:]]+(-[Cc][[:space:]]+[^[:space:];&|]+|--(git-dir|work-tree|namespace|exec-path)[[:space:]]+[^[:space:];&|]+|-[^[:space:];&|]+))*[[:space:]]+clean -fd Irreversible clean blocked — use --dry-run to preview what would be deleted
|
|
61
|
+
|
|
62
|
+
# ── Filesystem catastrophes ───────────────────────────────────────────────────
|
|
63
|
+
(^|[;&|(`])[[:space:]]*((sudo([[:space:]]+(-[ugChprtUDR][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|--(user|group|host|prompt|role|type|chdir)[[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|xargs([[:space:]]+(-[nILPsdEa][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|env([[:space:]]+(-[uCS][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|(command|time|nohup|exec|eval|then|do|else)([[:space:]]+(-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*)[[:space:]]+)*(\\|/(usr/)?bin/)?rm([[:space:]]+[^[:space:];&|]+)*[[:space:]]+((-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)([[:space:]]+[^[:space:];&|]+)*[[:space:]]+(/+\*{0,2})([[:space:];&|)`]|$)|(/+\*{0,2})([[:space:]]+[^[:space:];&|]+)*[[:space:]]+(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)([[:space:];&|)`]|$)) Catastrophic delete blocked — recursive rm of the root directory (/)
|
|
64
|
+
(^|[;&|(`])[[:space:]]*((sudo([[:space:]]+(-[ugChprtUDR][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|--(user|group|host|prompt|role|type|chdir)[[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|xargs([[:space:]]+(-[nILPsdEa][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|env([[:space:]]+(-[uCS][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|(command|time|nohup|exec|eval|then|do|else)([[:space:]]+(-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*)[[:space:]]+)*(\\|/(usr/)?bin/)?rm([[:space:]]+[^[:space:];&|]+)*[[:space:]]+((-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)([[:space:]]+[^[:space:];&|]+)*[[:space:]]+((~[A-Za-z_][A-Za-z0-9_.-]*|~|\$HOME|\$\{HOME\})(/\*{0,2})?)([[:space:];&|)`]|$)|((~[A-Za-z_][A-Za-z0-9_.-]*|~|\$HOME|\$\{HOME\})(/\*{0,2})?)([[:space:]]+[^[:space:];&|]+)*[[:space:]]+(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)([[:space:];&|)`]|$)) Catastrophic delete blocked — recursive rm of the home directory
|
|
65
|
+
(^|[;&|(`])[[:space:]]*((sudo([[:space:]]+(-[ugChprtUDR][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|--(user|group|host|prompt|role|type|chdir)[[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|xargs([[:space:]]+(-[nILPsdEa][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|env([[:space:]]+(-[uCS][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|(command|time|nohup|exec|eval|then|do|else)([[:space:]]+(-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*)[[:space:]]+)*(\\|/(usr/)?bin/)?rm([[:space:]]+[^[:space:];&|]+)*[[:space:]]+((-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)([[:space:]]+[^[:space:];&|]+)*[[:space:]]+(/(Users|home|etc|usr|bin|sbin|var|opt|System|Library|Applications|Volumes|private|root|boot|lib|dev|proc)(/\*{0,2})?)([[:space:];&|)`]|$)|(/(Users|home|etc|usr|bin|sbin|var|opt|System|Library|Applications|Volumes|private|root|boot|lib|dev|proc)(/\*{0,2})?)([[:space:]]+[^[:space:];&|]+)*[[:space:]]+(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)([[:space:];&|)`]|$)) Catastrophic delete blocked — recursive rm of a system directory
|
|
66
|
+
(^|[;&|(`])[[:space:]]*((sudo([[:space:]]+(-[ugChprtUDR][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|--(user|group|host|prompt|role|type|chdir)[[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|xargs([[:space:]]+(-[nILPsdEa][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|env([[:space:]]+(-[uCS][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|(command|time|nohup|exec|eval|then|do|else)([[:space:]]+(-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*)[[:space:]]+)*(\\|/(usr/)?bin/)?find([[:space:]]+-[HLP])*([[:space:]]+[^-[:space:];&|][^[:space:];&|]*)*[[:space:]]+(/+\*{0,2}|(~[A-Za-z_][A-Za-z0-9_.-]*|~|\$HOME|\$\{HOME\})(/\*{0,2})?|/(Users|home|etc|usr|bin|sbin|var|opt|System|Library|Applications|Volumes|private|root|boot|lib|dev|proc)(/\*{0,2})?)([[:space:]]+([^-[:space:];&|][^[:space:];&|]*|-(mount|xdev|depth|noleaf|follow|ignore_readdir_race)|-(type|maxdepth|mindepth)[[:space:]]+[^[:space:];&|]+))*[[:space:]]+(-delete([[:space:];&|)`]|$)|-exec(dir)?[[:space:]]+(\\|/(usr/)?bin/)?rm([[:space:];&|)`]|$)) Catastrophic delete blocked — find -delete or -exec rm from the root, home or a system directory with no name, path or time predicate to scope it
|
|
67
|
+
|
|
68
|
+
# ── SQL destructive statements (no anchor — must catch inside psql heredocs) ──
|
|
69
|
+
DROP[[:space:]]+(TABLE|DATABASE|SCHEMA)[[:space:]] Destructive DDL blocked — confirm with user before dropping
|
|
70
|
+
DELETE[[:space:]]+FROM[[:space:]]+[[:alnum:]_]+[[:space:]]*; Unscoped DELETE blocked — this would affect all rows, add a WHERE clause
|
|
71
|
+
TRUNCATE[[:space:]]+TABLE Irreversible truncate blocked — confirm with user before truncating
|
|
72
|
+
|
|
73
|
+
# ── Code execution from untrusted network sources ─────────────────────────────
|
|
74
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)(curl|wget)[[:space:]]+[^[:space:]]+.*\|[[:space:]]*(ba)?sh Pipe-to-shell blocked — download and review the script before executing
|
|
75
|
+
|
|
76
|
+
# ── Broad permission grants ───────────────────────────────────────────────────
|
|
77
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)chmod[[:space:]]+-R[[:space:]]+777 chmod -R 777 blocked — grants world-write access recursively; use targeted permissions (e.g. chmod 755) instead
|
|
78
|
+
|
|
79
|
+
# ── Disk device operations ────────────────────────────────────────────────────
|
|
80
|
+
(^|[[:space:]]*(&&|\|\||;)[[:space:]]*)dd[[:space:]]+if=/dev/ dd from block device blocked — can wipe or clone disks; confirm with user before any raw device operation
|
|
81
|
+
|
|
82
|
+
# ── Known limitation (not a pattern — comment only) ──────────────────────────
|
|
83
|
+
# eval-based indirection (e.g. CMD="git push --force"; eval "$CMD") bypasses all
|
|
84
|
+
# static pattern matching above. This is an inherent limitation of text-based
|
|
85
|
+
# guards. For high-security environments, supplement with branch protection
|
|
86
|
+
# rules and code review rather than relying solely on this guard.
|
|
87
|
+
#
|
|
88
|
+
# Variables other than HOME ($B, "$DIR") are not blocked: an empty or unset
|
|
89
|
+
# variable cannot be known statically, so rm -rf "$B"/ is allowed. Only the
|
|
90
|
+
# literal targets in the rm rule above are judged (root, home, and the system
|
|
91
|
+
# directories listed; subpaths such as /tmp/x or /Users/kai/x are allowed).
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# capture-failure.sh — Canonical Policy Library: failure capture helper (feature 046, IC-018, DEC-032)
|
|
3
|
+
#
|
|
4
|
+
# Defines doflow_capture_failure <policy> <point>, which appends one IC-011 line to the machine-wide
|
|
5
|
+
# DoFlow failure list when a guard policy fails open because DoFlow's own install is broken (for
|
|
6
|
+
# example its pattern file is missing). It exists only to be sourced, in a subshell with all output
|
|
7
|
+
# discarded, from inside a branch where the policy already fails open:
|
|
8
|
+
#
|
|
9
|
+
# ( . "$(dirname "$0")/capture-failure.sh"; doflow_capture_failure pre-bash-guard patterns-missing ) >/dev/null 2>&1 || true
|
|
10
|
+
#
|
|
11
|
+
# The subshell keeps anything this file does away from the policy, which runs with `set -uo pipefail`,
|
|
12
|
+
# does not source lib.sh and would change exit codes under `set -e`. So this file:
|
|
13
|
+
# - sets no shell option and installs no trap (DEC-018), and is written to be safe under the
|
|
14
|
+
# caller's `set -u` and `pipefail`;
|
|
15
|
+
# - reads no stdin and writes nothing to stdout or stderr;
|
|
16
|
+
# - never rotates the file (rotation is done by the Node writers only, DEC-019);
|
|
17
|
+
# - never blocks, never changes the policy's decision, and swallows every error.
|
|
18
|
+
# The line holds only the policy name and the point name from DoFlow's own code, the working
|
|
19
|
+
# directory, the harness name and the install version: never the tool call, its arguments or stdin.
|
|
20
|
+
# It is a no-op when no failure home can be resolved (HOME unset, or XDG_CONFIG_HOME relative) and
|
|
21
|
+
# while capture is off (the `off` sentinel file wins; DOFLOW_FAILURE_CAPTURE=off|0|false|no also
|
|
22
|
+
# turns it off), the same rules the Node writer follows (IC-011, IC-014).
|
|
23
|
+
|
|
24
|
+
doflow_capture_failure() {
|
|
25
|
+
local policy="${1:-}" point="${2:-}"
|
|
26
|
+
local LC_ALL=C # byte-wise lengths and cuts; scoped to this function
|
|
27
|
+
local home="" setting="" version="" harness="" project="" cwd="" hp="" at="" line="" here="" dir=""
|
|
28
|
+
|
|
29
|
+
if [ -n "${XDG_CONFIG_HOME:-}" ]; then
|
|
30
|
+
case "$XDG_CONFIG_HOME" in
|
|
31
|
+
/*) home="$XDG_CONFIG_HOME/doflow/failures" ;;
|
|
32
|
+
*) return 0 ;;
|
|
33
|
+
esac
|
|
34
|
+
else
|
|
35
|
+
case "${HOME:-}" in
|
|
36
|
+
/*) home="$HOME/.config/doflow/failures" ;;
|
|
37
|
+
*) return 0 ;;
|
|
38
|
+
esac
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Case-insensitive, whitespace trimmed at the ends only: the same reading the Node writer has.
|
|
42
|
+
setting="$(printf '%s' "${DOFLOW_FAILURE_CAPTURE:-}" | tr '[:upper:]' '[:lower:]')" || return 0
|
|
43
|
+
setting="${setting#"${setting%%[![:space:]]*}"}"
|
|
44
|
+
setting="${setting%"${setting##*[![:space:]]}"}"
|
|
45
|
+
case "$setting" in
|
|
46
|
+
off|0|false|no) return 0 ;;
|
|
47
|
+
esac
|
|
48
|
+
[ -f "$home/off" ] && return 0
|
|
49
|
+
|
|
50
|
+
[[ "$policy" =~ ^[a-z][a-z0-9-]{0,39}$ ]] || policy="unknown"
|
|
51
|
+
[[ "$point" =~ ^[A-Za-z][A-Za-z0-9._:-]{0,39}$ ]] || return 0
|
|
52
|
+
|
|
53
|
+
harness="${DOFLOW_AGENT:-}"
|
|
54
|
+
[[ "$harness" =~ ^[A-Za-z0-9._-]{1,40}$ ]] || harness="none"
|
|
55
|
+
|
|
56
|
+
# script_version of the nearest install manifest: walking up from this file, then the global one.
|
|
57
|
+
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)" || here=""
|
|
58
|
+
dir="$here"
|
|
59
|
+
while [ -n "$dir" ] && [ -z "$version" ]; do
|
|
60
|
+
if [ -f "$dir/.doflow/.install-manifest.json" ]; then
|
|
61
|
+
version="$(sed -n 's/^[[:space:]]*"script_version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$dir/.doflow/.install-manifest.json" | head -n 1)" || version=""
|
|
62
|
+
fi
|
|
63
|
+
[ "$dir" = "/" ] && break
|
|
64
|
+
dir="$(dirname "$dir")"
|
|
65
|
+
done
|
|
66
|
+
if [ -z "$version" ] && [ -f "${HOME:-}/.doflow/.install-manifest.json" ]; then
|
|
67
|
+
version="$(sed -n 's/^[[:space:]]*"script_version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$HOME/.doflow/.install-manifest.json" | head -n 1)" || version=""
|
|
68
|
+
fi
|
|
69
|
+
[[ "$version" =~ ^[A-Za-z0-9._+-]{1,40}$ ]] || version="unknown"
|
|
70
|
+
|
|
71
|
+
# The working directory with the home prefix as `~`, cut to 200 bytes, control characters turned
|
|
72
|
+
# into spaces and every quote and backslash escaped, so the line stays one valid JSON string.
|
|
73
|
+
cwd="$(pwd 2>/dev/null)" || cwd=""
|
|
74
|
+
hp="${HOME:-}"
|
|
75
|
+
hp="${hp%/}"
|
|
76
|
+
if [ -n "$hp" ]; then
|
|
77
|
+
case "$cwd" in
|
|
78
|
+
"$hp") cwd="~" ;;
|
|
79
|
+
"$hp"/*) cwd="~${cwd#"$hp"}" ;;
|
|
80
|
+
esac
|
|
81
|
+
fi
|
|
82
|
+
project="$(printf '%s' "${cwd:0:200}" | tr '\001-\037\177' ' ')" || project=""
|
|
83
|
+
project="${project//\\/\\\\}"
|
|
84
|
+
project="${project//\"/\\\"}"
|
|
85
|
+
|
|
86
|
+
at="$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" || return 0
|
|
87
|
+
line="{\"v\":1,\"at\":\"$at\",\"source\":\"hook\",\"command\":\"$policy\",\"harness\":\"$harness\",\"version\":\"$version\",\"project\":\"$project\",\"kind\":\"$point\",\"message\":\"\",\"frame\":null,\"exit\":null}"
|
|
88
|
+
if [ "${#line}" -gt 999 ]; then
|
|
89
|
+
line="{\"v\":1,\"at\":\"$at\",\"source\":\"hook\",\"command\":\"$policy\",\"harness\":\"$harness\",\"version\":\"$version\",\"project\":\"\",\"kind\":\"$point\",\"message\":\"\",\"frame\":null,\"exit\":null}"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
(umask 077; mkdir -p "$home") || return 0
|
|
93
|
+
# Only ever append to a regular file: opening a FIFO for append would block forever.
|
|
94
|
+
[ ! -e "$home/events.jsonl" ] || [ -f "$home/events.jsonl" ] || return 0
|
|
95
|
+
( umask 077; printf '%s\n' "$line" >>"$home/events.jsonl" ) || return 0
|
|
96
|
+
return 0
|
|
97
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# deny-json.sh — shared PreToolUse deny-JSON emitters for front-door dispatchers.
|
|
3
|
+
#
|
|
4
|
+
# Deliberately carries no `set` directive (unlike lib.sh, which sets -euo
|
|
5
|
+
# pipefail on source): a front door needs `set -e` OFF while it captures a
|
|
6
|
+
# policy script's exit code via `REASON=$(bash "$POLICY" ...); CODE=$?` — under
|
|
7
|
+
# `set -e` that assignment's own nonzero exit status (the deny case) would abort
|
|
8
|
+
# the front door right there, before it ever reached the code below that emits
|
|
9
|
+
# the deny JSON. Sourcing this file must never change the caller's shell options.
|
|
10
|
+
#
|
|
11
|
+
# Usage: source "$(dirname "$0")/../../shared/hooks/policies/deny-json.sh"
|
|
12
|
+
|
|
13
|
+
# Claude/Codex shape: nested under hookSpecificOutput.permissionDecision.
|
|
14
|
+
emit_pretooluse_deny_nested() {
|
|
15
|
+
local reason="$1"
|
|
16
|
+
jq -n --arg reason "$reason" '{
|
|
17
|
+
hookSpecificOutput: {
|
|
18
|
+
hookEventName: "PreToolUse",
|
|
19
|
+
permissionDecision: "deny",
|
|
20
|
+
permissionDecisionReason: $reason
|
|
21
|
+
}
|
|
22
|
+
}'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Gemini shape: flat {decision, reason} (packages/core/src/hooks/types.ts).
|
|
26
|
+
emit_pretooluse_deny_flat() {
|
|
27
|
+
local reason="$1"
|
|
28
|
+
jq -n --arg reason "$reason" '{decision: "deny", reason: $reason}'
|
|
29
|
+
}
|