@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,631 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
// Antigravity CLI adapter (#8). Scope follows the surfaces verified against Antigravity's own
|
|
6
|
+
// docs (antigravity.google/docs/cli/*):
|
|
7
|
+
// instructions — marker-managed section in PROJECT AGENTS.md only. Global memory is
|
|
8
|
+
// ~/.gemini/GEMINI.md, shared with the Gemini CLI harness; two adapters writing one file with
|
|
9
|
+
// one marker pair would fight, so global instructions are reported, never written.
|
|
10
|
+
// skills — folder-form copy-tree into project .agents/skills or user ~/.gemini/config/skills.
|
|
11
|
+
// agents — copy-tree into project .agents/agents or user ~/.gemini/config/agents.
|
|
12
|
+
// mcp — entries of the mcpServers object in .agents/mcp_config.json (workspace) or
|
|
13
|
+
// ~/.gemini/config/mcp_config.json (user), owned one at a time through ../mcp-entries.ts;
|
|
14
|
+
// remote url/httpUrl projects to serverUrl.
|
|
15
|
+
// hooks — native-payload shims (bash + jq translating Antigravity's stdin/stdout
|
|
16
|
+
// {decision} contract): the pre-implementation gate on PreToolUse and the stop check on Stop,
|
|
17
|
+
// each registered under its own named hooks.json group.
|
|
18
|
+
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const os = require('node:os');
|
|
21
|
+
const path = require('node:path');
|
|
22
|
+
|
|
23
|
+
const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.ts');
|
|
24
|
+
const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor } = require('../copy-tree.ts');
|
|
25
|
+
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.ts');
|
|
26
|
+
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.ts');
|
|
27
|
+
|
|
28
|
+
const HARNESS = 'antigravity';
|
|
29
|
+
const MCP_CONTAINER = 'mcpServers';
|
|
30
|
+
const MCP_RENDERER = 'antigravity-mcp';
|
|
31
|
+
|
|
32
|
+
/** copy-tree's readJson distinguishes absent/unparseable via an {exists,value,error} envelope;
|
|
33
|
+
* every caller here wants the plain object or {}. */
|
|
34
|
+
function readJsonObject(file: any, { fsImpl = fs }: any = {}) {
|
|
35
|
+
const result = readJson(file, { fsImpl });
|
|
36
|
+
if (!result || !result.exists || result.error) return {};
|
|
37
|
+
return result.value ?? {};
|
|
38
|
+
}
|
|
39
|
+
// Precedent: Codex rides its pointer asset's id for every managed row (instructions-section and
|
|
40
|
+
// mcp-server alike). The antigravity projection shares that same pointer asset, so its rows do too.
|
|
41
|
+
const POINTER_ASSET_ID = 'guidance.codex-pointer';
|
|
42
|
+
const HOOKS_ASSET_ID = 'hooks.antigravity';
|
|
43
|
+
// One owned hooks.json group per DoFlow policy (the Kiro doflow.json precedent): the two gates
|
|
44
|
+
// stay independently removable/enablable, and a user's own groups are never touched. The Stop
|
|
45
|
+
// registration is matcher-free — Antigravity documents handlers sitting directly under the event
|
|
46
|
+
// key for PreInvocation/PostInvocation/Stop ("the matcher is ignored").
|
|
47
|
+
const HOOK_SCRIPTS = ['pre-implementation-gate.sh', 'stop-check.sh'];
|
|
48
|
+
const HOOKS_GROUP = 'doflow-pre-implementation-gate';
|
|
49
|
+
const STOP_HOOKS_GROUP = 'doflow-stop-check';
|
|
50
|
+
// Antigravity's documented file-mutation tools (docs/hooks, Supported Tools) — the exact set the
|
|
51
|
+
// gate is meaningful for.
|
|
52
|
+
const GATE_MATCHER = 'write_to_file|replace_file_content|multi_replace_file_content';
|
|
53
|
+
|
|
54
|
+
/** Build DoFlow's hooks.json groups from the projected scripts' on-disk locations. Absolute command
|
|
55
|
+
* path: the docs' own examples use relative ./scripts paths whose resolution base is not stated,
|
|
56
|
+
* and an absolute path is unambiguous for a per-workspace install. */
|
|
57
|
+
function hookGroups({ gateCommand, stopCommand }: any) {
|
|
58
|
+
return {
|
|
59
|
+
[HOOKS_GROUP]: { PreToolUse: [{ matcher: GATE_MATCHER, hooks: [{ type: 'command', command: gateCommand }] }] },
|
|
60
|
+
[STOP_HOOKS_GROUP]: { Stop: [{ type: 'command', command: stopCommand }] },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hookScriptTarget(identity: any, paths: any) {
|
|
65
|
+
return identity === 'pre-implementation-gate.sh' ? paths.hookScript : paths.stopHookScript;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function planHooks({ paths, scope, neutralResources, removing, repoRoot, fsImpl = fs }: any) {
|
|
69
|
+
const changes: any[] = [];
|
|
70
|
+
const conflicts: any[] = [];
|
|
71
|
+
if (scope !== 'project') {
|
|
72
|
+
// The shims resolve the workspace via git/transcriptPath; a user-scope hooks.json would fire
|
|
73
|
+
// against every project including non-git ones. Project-only until a documented user story exists.
|
|
74
|
+
return { changes, conflicts };
|
|
75
|
+
}
|
|
76
|
+
const target = paths.hooksJson;
|
|
77
|
+
const scriptSource = sourceDirFor({ source: 'core/harnesses/antigravity/hooks' }, { repoRoot }, fsImpl, HARNESS);
|
|
78
|
+
|
|
79
|
+
const previousHookRows = (neutralResources || []).filter((r: any) => r.harness === HARNESS && r.assetId === HOOKS_ASSET_ID && r.kind === 'hooks-json');
|
|
80
|
+
const previousScriptRows = (neutralResources || []).filter((r: any) => r.harness === HARNESS && r.assetId === HOOKS_ASSET_ID && r.kind === 'copy-tree-file');
|
|
81
|
+
const docRow = previousHookRows.find((r: any) => r.target === target);
|
|
82
|
+
|
|
83
|
+
if (removing) {
|
|
84
|
+
if (docRow || fsImpl.existsSync(target)) {
|
|
85
|
+
changes.push({ assetId: HOOKS_ASSET_ID, target, operation: 'remove',
|
|
86
|
+
ownershipIdentity: `${HARNESS}:hooks:registration`, kind: 'hooks-json',
|
|
87
|
+
fingerprint: fingerprint('{}'), managed: null,
|
|
88
|
+
projection: { renderer: 'antigravity-hooks' } });
|
|
89
|
+
}
|
|
90
|
+
for (const identity of HOOK_SCRIPTS) {
|
|
91
|
+
const scriptTarget = hookScriptTarget(identity, paths);
|
|
92
|
+
const scriptRow = previousScriptRows.find((r: any) => r.identity === identity);
|
|
93
|
+
if (scriptRow && fsImpl.existsSync(scriptTarget)) {
|
|
94
|
+
const current = sha256File(fsImpl, scriptTarget);
|
|
95
|
+
if (current === scriptRow.fingerprint) {
|
|
96
|
+
changes.push({ assetId: HOOKS_ASSET_ID, target: scriptTarget, source: path.join(scriptSource, identity),
|
|
97
|
+
operation: 'remove', ownershipIdentity: `${HARNESS}:copy-tree:${HOOKS_ASSET_ID}:${identity}`,
|
|
98
|
+
kind: 'copy-tree-file', identity,
|
|
99
|
+
fingerprint: current, projection: { renderer: 'antigravity-hooks' } });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { changes, conflicts };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Scripts first: the JSON references them, so apply order must never leave a dangling reference.
|
|
107
|
+
for (const identity of HOOK_SCRIPTS) {
|
|
108
|
+
const scriptTarget = hookScriptTarget(identity, paths);
|
|
109
|
+
const scriptText = fsImpl.readFileSync(path.join(scriptSource, identity), 'utf8');
|
|
110
|
+
const scriptFp = fingerprint(scriptText);
|
|
111
|
+
if (!fsImpl.existsSync(scriptTarget) || sha256File(fsImpl, scriptTarget) !== scriptFp) {
|
|
112
|
+
changes.push({ assetId: HOOKS_ASSET_ID, target: scriptTarget, source: path.join(scriptSource, identity),
|
|
113
|
+
operation: fsImpl.existsSync(scriptTarget) ? 'update' : 'create',
|
|
114
|
+
ownershipIdentity: `${HARNESS}:copy-tree:${HOOKS_ASSET_ID}:${identity}`,
|
|
115
|
+
kind: 'copy-tree-file', identity,
|
|
116
|
+
afterFingerprint: scriptFp, fingerprint: scriptFp,
|
|
117
|
+
_text: scriptText, projection: { renderer: 'antigravity-hooks' } });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const currentDoc = readJsonObject(target, { fsImpl }) ?? {};
|
|
122
|
+
const next = { ...currentDoc, ...hookGroups({ gateCommand: paths.hookScript, stopCommand: paths.stopHookScript }) };
|
|
123
|
+
if (JSON.stringify(next) !== JSON.stringify(currentDoc)) {
|
|
124
|
+
changes.push({ assetId: HOOKS_ASSET_ID, target, operation: fsImpl.existsSync(target) ? 'update' : 'create',
|
|
125
|
+
content: `${JSON.stringify(next, null, 2)}\n`,
|
|
126
|
+
ownershipIdentity: `${HARNESS}:hooks:registration`, kind: 'hooks-json',
|
|
127
|
+
fingerprint: fingerprint(next), harness: HARNESS,
|
|
128
|
+
projection: { renderer: 'antigravity-hooks' } });
|
|
129
|
+
}
|
|
130
|
+
return { changes, conflicts };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function sha256File(fsImpl: any, file: any) {
|
|
134
|
+
return require('node:crypto').createHash('sha256').update(fsImpl.readFileSync(file)).digest('hex');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Native paths per scope, resolved from the declaration in core/registry/harnesses.json
|
|
138
|
+
* ("paths"): project customization lives at <root>/.agents, global config at ~/.gemini/config
|
|
139
|
+
* (the shared-customization root); instructions and skills are project-only surfaces, so no user
|
|
140
|
+
* rule is declared for them and they resolve to null there. */
|
|
141
|
+
function resolveNativePaths(declaredPaths: any, { scope, scopeRoot, homeDir }: any = {}) {
|
|
142
|
+
if (scope !== 'project' && scope !== 'global') throw new Error(`Unsupported Antigravity scope '${scope}'`);
|
|
143
|
+
const resolved = resolveHarnessPaths(declaredPaths, { scope, scopeRoot, homeDir });
|
|
144
|
+
return {
|
|
145
|
+
scope,
|
|
146
|
+
root: resolved.root,
|
|
147
|
+
configDir: resolved.configDir,
|
|
148
|
+
instruction: resolved.instruction,
|
|
149
|
+
mcpFile: resolved.mcpFile,
|
|
150
|
+
skillsDir: resolved.skillsDir,
|
|
151
|
+
agentsDir: resolved.agentsDir,
|
|
152
|
+
// Declared project-scope hook surfaces (null at user scope — see the paths declaration).
|
|
153
|
+
hooksJson: resolved.hooksJson,
|
|
154
|
+
hookScript: resolved.hookScript,
|
|
155
|
+
stopHookScript: resolved.stopHookScript,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const DEFAULT_DECLARED_PATHS = declaredHarnessPaths()[HARNESS];
|
|
160
|
+
|
|
161
|
+
function nativePaths(options = {}) {
|
|
162
|
+
return resolveNativePaths(DEFAULT_DECLARED_PATHS, options);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* createAntigravityAdapter({ declaredPaths }) is the injection point buildAdapterRegistry() uses:
|
|
167
|
+
* it rebinds the contract methods to the given declaration. Unlike the smaller adapters this one
|
|
168
|
+
* keeps its planners module-level (they already thread resolved `paths` explicitly), so injection
|
|
169
|
+
* flows through an optional `impl.nativePaths` seam instead of a full closure rewrite.
|
|
170
|
+
*/
|
|
171
|
+
function createAntigravityAdapter({ declaredPaths = DEFAULT_DECLARED_PATHS }: any = {}) {
|
|
172
|
+
const nativePathsFor = (options: any) => resolveNativePaths(declaredPaths, options);
|
|
173
|
+
return {
|
|
174
|
+
nativePaths: nativePathsFor,
|
|
175
|
+
discover: (options: any, impl = {}) => discover(options, { ...impl, nativePaths: nativePathsFor }),
|
|
176
|
+
render,
|
|
177
|
+
plan: (options: any, impl = {}) => plan(options, { ...impl, nativePaths: nativePathsFor }),
|
|
178
|
+
apply,
|
|
179
|
+
remove,
|
|
180
|
+
verify: (options: any, impl = {}) => verify(options, { ...impl, nativePaths: nativePathsFor }),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const singleton = createAntigravityAdapter();
|
|
185
|
+
|
|
186
|
+
/** The scope's paths exactly as plan() and verify() resolve them, so discovery reads the same files. */
|
|
187
|
+
function scopePaths(options: any, resolvePaths = singleton.nativePaths) {
|
|
188
|
+
return resolvePaths({ ...options, scope: options.scope ?? 'project', homeDir: options.context?.homeDir });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function ledgerResources(options: any) {
|
|
192
|
+
return options.ledger?.resources ?? options.managedResources ?? [];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Discovery keeps the MCP files as plan read them (`mcpSnapshot`), which verify compares against,
|
|
196
|
+
* and reports the servers DoFlow owns in mcp_config.json now (`mcpOwned`). */
|
|
197
|
+
function discover(options: any, { fsImpl = fs, nativePaths: resolvePaths = singleton.nativePaths }: any = {}) {
|
|
198
|
+
const paths = scopePaths(options, resolvePaths);
|
|
199
|
+
const instruction = paths.instruction && fsImpl.existsSync(paths.instruction)
|
|
200
|
+
? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
201
|
+
const entries = mcpEntriesInput({ paths, mcp: options.mcp, mcpAdoptable: options.mcpAdoptable, resources: ledgerResources(options) });
|
|
202
|
+
const mcpSnapshot = readMcpFiles({ file: entries.file, ownRows: entries.ownRows, container: MCP_CONTAINER, fsImpl });
|
|
203
|
+
const read = mcpSnapshot[entries.file];
|
|
204
|
+
// `null` while the file is absent, unreadable or has no server map; every name in it otherwise, whoever wrote it.
|
|
205
|
+
const mcpConfigured = read?.ok && read.servers ? Object.keys(read.servers).sort() : null;
|
|
206
|
+
return { paths, instruction, mcpSnapshot, mcpOwned: ownedMcpIds({ ...entries, files: mcpSnapshot }), mcpConfigured };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function render({ content = '' }: any = {}) {
|
|
210
|
+
return `${MARKER_START}\n${String(content).trimEnd()}\n${MARKER_END}\n`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function managedInstruction(existing: any, rendered: any) {
|
|
214
|
+
if (existing === null) return { ok: true, operation: 'create', content: rendered };
|
|
215
|
+
const start = existing.indexOf(MARKER_START);
|
|
216
|
+
const end = existing.indexOf(MARKER_END);
|
|
217
|
+
if (start === -1 && end === -1) {
|
|
218
|
+
const separator = existing === '' || existing.endsWith('\n') ? '\n' : '\n\n';
|
|
219
|
+
const content = `${existing}${separator}${rendered}`;
|
|
220
|
+
return { ok: true, operation: 'merge', content };
|
|
221
|
+
}
|
|
222
|
+
if (start === -1 || end === -1 || end < start) return { ok: false, conflict: 'AGENTS.md has malformed DoFlow managed-section markers' };
|
|
223
|
+
const content = `${existing.slice(0, start)}${rendered}${existing.slice(end + MARKER_END.length).replace(/^\n?/, '')}`;
|
|
224
|
+
return { ok: true, operation: content === existing ? 'none' : 'merge', content };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function strippedInstruction(existing: any) {
|
|
228
|
+
if (typeof existing !== 'string') return null;
|
|
229
|
+
const start = existing.indexOf(MARKER_START);
|
|
230
|
+
const end = existing.indexOf(MARKER_END);
|
|
231
|
+
if (start === -1 || end === -1 || end < start) return null;
|
|
232
|
+
let after = end + MARKER_END.length;
|
|
233
|
+
if (existing[after] === '\n') after += 1;
|
|
234
|
+
return `${existing.slice(0, start)}${existing.slice(after)}`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ---- copy-tree components (skills, agents, locator) ----
|
|
238
|
+
|
|
239
|
+
/** Scope policy mirrors the registry notes, resolved from each asset's own flat nativeDir:
|
|
240
|
+
* ../x or .agents/x or .doflow/x → rooted at the install root (project scope)
|
|
241
|
+
* plain names (bin, agents) → inside the scope's config dir (.agents | ~/.gemini/config) */
|
|
242
|
+
function treeDestFor(asset: any, paths: any, scope: any) {
|
|
243
|
+
const nativeDir = asset.nativeDir;
|
|
244
|
+
if (!nativeDir) return null;
|
|
245
|
+
if (asset.id === 'skills.doflow') {
|
|
246
|
+
return paths.skillsDir || path.join(paths.configDir, nativeDir);
|
|
247
|
+
}
|
|
248
|
+
if (asset.id === 'rules.antigravity' || asset.id === 'workflows.antigravity') {
|
|
249
|
+
// Workspace-scope surfaces under .agents/: Antigravity documents workspace rules
|
|
250
|
+
// (.agents/rules) and workflows (.agents/workflows) with no user-scope home — a global
|
|
251
|
+
// install deliberately projects neither rather than guessing one. These nativeDirs are
|
|
252
|
+
// config-relative.
|
|
253
|
+
return scope === 'project' ? path.join(paths.configDir, nativeDir) : null;
|
|
254
|
+
}
|
|
255
|
+
if (asset.id === 'agents.shared') {
|
|
256
|
+
return scope === 'project' ? path.join(paths.root, nativeDir) : path.join(paths.configDir, 'agents');
|
|
257
|
+
}
|
|
258
|
+
if (asset.id === 'locator.doflow') {
|
|
259
|
+
return path.join(paths.configDir, nativeDir);
|
|
260
|
+
}
|
|
261
|
+
if (nativeDir.startsWith('../')) return path.join(paths.root, nativeDir.replace(/^\.\.\//, ''));
|
|
262
|
+
if (nativeDir.startsWith('.')) return path.join(paths.root, nativeDir);
|
|
263
|
+
return path.join(paths.configDir, nativeDir);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function planTrees({ assets, paths, scope, neutralResources, removing, repoRoot, force = false, fsImpl = fs }: any) {
|
|
267
|
+
const changes = [];
|
|
268
|
+
const conflicts = [];
|
|
269
|
+
const treeResults = [];
|
|
270
|
+
const notices = [];
|
|
271
|
+
const targets = [];
|
|
272
|
+
for (const asset of copyTreeAssets(assets)) {
|
|
273
|
+
const destDir = treeDestFor(asset, paths, scope);
|
|
274
|
+
if (!destDir) continue;
|
|
275
|
+
targets.push({ asset, destDir });
|
|
276
|
+
}
|
|
277
|
+
for (const { asset, destDir } of targets) {
|
|
278
|
+
const sourceDir = sourceDirFor(asset, { repoRoot }, fsImpl, HARNESS);
|
|
279
|
+
const previousResources = ledgerFileResources(neutralResources, HARNESS, asset.id);
|
|
280
|
+
const result = planTree({ sourceDir, destDir, previousResources, siblingFingerprints: ledgerSiblingFingerprints(neutralResources, HARNESS), operation: removing ? 'remove' : 'apply', fsImpl, layout: asset.layout, keepModified: !removing,
|
|
281
|
+
// Forwarded so the CLI's --force reaches planTree's conflict check; omitting it let
|
|
282
|
+
// planTree's own `force = false` default stand in silently. Gated on `!removing` for the
|
|
283
|
+
// reason codex/index.ts states in full: force heals drift on apply, but a hand-edited file
|
|
284
|
+
// is never deleted on removal, forced or not. This adapter needed `force` threaded through
|
|
285
|
+
// planTrees as well, since its signature did not carry the context the others already had.
|
|
286
|
+
force: !removing && force === true });
|
|
287
|
+
treeResults.push(result);
|
|
288
|
+
conflicts.push(...result.conflicts.map((reason: any) => `${asset.id}: ${reason}`));
|
|
289
|
+
// A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
|
|
290
|
+
// ownership row is released.
|
|
291
|
+
notices.push(...result.kept.map((item: any) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
|
|
292
|
+
for (const change of result.changes) {
|
|
293
|
+
changes.push({
|
|
294
|
+
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
295
|
+
ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${change.relPath}`,
|
|
296
|
+
kind: 'copy-tree-file', identity: change.relPath,
|
|
297
|
+
afterFingerprint: change.fingerprint, fingerprint: change.fingerprint, sourceVersion: 'registry-v1',
|
|
298
|
+
...(change.kept ? { retained: true, retainedFor: [] } : {}),
|
|
299
|
+
projection: { renderer: 'copy-tree' },
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return { changes, conflicts, targets, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function runTreeChanges(changes: any, mode: any) {
|
|
307
|
+
// Route by what each change IS, not by which verb invoked us: remove() delegates here with a
|
|
308
|
+
// plan full of operation:'remove' changes, and applyTree deliberately skips those — so routing
|
|
309
|
+
// everything through one engine call silently deleted nothing (verification then correctly
|
|
310
|
+
// refused to journal the no-op). Writes go to applyTree, removals to removeTree, always.
|
|
311
|
+
void mode;
|
|
312
|
+
const treeChanges = changes
|
|
313
|
+
.filter((c: any) => c.projection?.renderer === 'copy-tree' || c.kind === 'copy-tree-file')
|
|
314
|
+
.map((c: any) => ({ relPath: c.identity ?? c.relPath, target: c.target,
|
|
315
|
+
source: c._text ? undefined : c.source, operation: c.operation,
|
|
316
|
+
fingerprint: c.fingerprint, pruneGuard: c.pruneGuard, ...(c._text ? { _text: c._text } : {}) }));
|
|
317
|
+
// Content-managed tree files (hook scripts): write rendered text with +x, not a byte copy.
|
|
318
|
+
for (const t of treeChanges) {
|
|
319
|
+
if (t._text === undefined) continue;
|
|
320
|
+
if (t.operation === 'remove') { fs.rmSync(t.target, { force: true }); continue; }
|
|
321
|
+
fs.mkdirSync(path.dirname(t.target), { recursive: true });
|
|
322
|
+
fs.writeFileSync(t.target, t._text);
|
|
323
|
+
fs.chmodSync(t.target, 0o755);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
applied: 0, removed: 0,
|
|
327
|
+
...(function (): any {
|
|
328
|
+
const plain = treeChanges.filter((t: any) => t._text === undefined);
|
|
329
|
+
const writes = plain.filter((c: any) => c.operation !== 'remove');
|
|
330
|
+
const removals = plain.filter((c: any) => c.operation === 'remove');
|
|
331
|
+
const applied = writes.length ? applyTree({ changes: writes }).applied : 0;
|
|
332
|
+
const removed = removals.length ? removeTree({ changes: removals }).removed : 0;
|
|
333
|
+
return { applied, removed };
|
|
334
|
+
})(),
|
|
335
|
+
};
|
|
336
|
+
const writes = treeChanges.filter((c: any) => c.operation !== 'remove');
|
|
337
|
+
const removals = treeChanges.filter((c: any) => c.operation === 'remove');
|
|
338
|
+
const applied = writes.length ? applyTree({ changes: writes }).applied : 0;
|
|
339
|
+
const removed = removals.length ? removeTree({ changes: removals }).removed : 0;
|
|
340
|
+
return { applied, removed };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ---- instructions component ----
|
|
344
|
+
|
|
345
|
+
function planInstructions({ paths, assets, removing, repoRoot, fsImpl = fs }: any) {
|
|
346
|
+
if (scopeOf(paths) !== 'project') return { changes: [], conflicts: [] };
|
|
347
|
+
void repoRoot;
|
|
348
|
+
if (removing) {
|
|
349
|
+
// Removal must strip the section DoFlow owns while leaving foreign bytes untouched — same
|
|
350
|
+
// contract as the other AGENTS-style adapters.
|
|
351
|
+
if (!fsImpl.existsSync(paths.instruction)) return { changes: [], conflicts: [] };
|
|
352
|
+
const text = fsImpl.readFileSync(paths.instruction, 'utf8');
|
|
353
|
+
if (!text.includes(MARKER_START)) return { changes: [], conflicts: [] };
|
|
354
|
+
return {
|
|
355
|
+
changes: [{
|
|
356
|
+
assetId: POINTER_ASSET_ID, target: paths.instruction, operation: 'remove',
|
|
357
|
+
ownershipIdentity: `doflow:${HARNESS}:instructions:managed-section`,
|
|
358
|
+
kind: 'instructions-section', identity: 'AGENTS.md',
|
|
359
|
+
projection: { renderer: 'antigravity-instructions' },
|
|
360
|
+
}],
|
|
361
|
+
conflicts: [],
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const sourceText = pointerBody(fsImpl);
|
|
365
|
+
if (!sourceText) return { changes: [], conflicts: [] };
|
|
366
|
+
const existing = fsImpl.existsSync(paths.instruction) ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
367
|
+
const outcome = managedInstruction(existing, render({ content: sourceText }));
|
|
368
|
+
if (!outcome.ok) return { changes: [], conflicts: [outcome.conflict] };
|
|
369
|
+
if (outcome.operation === 'none') return { changes: [], conflicts: [] };
|
|
370
|
+
return {
|
|
371
|
+
changes: [{
|
|
372
|
+
assetId: POINTER_ASSET_ID, target: paths.instruction, operation: existing === null ? 'create' : 'update',
|
|
373
|
+
ownershipIdentity: `doflow:${HARNESS}:instructions:managed-section`,
|
|
374
|
+
kind: 'instructions-section', identity: 'AGENTS.md',
|
|
375
|
+
afterFingerprint: fingerprint(outcome.content), sourceVersion: 'registry-v1',
|
|
376
|
+
projection: { renderer: 'antigravity-instructions' },
|
|
377
|
+
_content: outcome.content,
|
|
378
|
+
}],
|
|
379
|
+
conflicts: [],
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function pointerBody(fsImpl: any) {
|
|
384
|
+
// The shared pointer prose ships once; read it through the same repo-relative anchor the other
|
|
385
|
+
// AGENTS-style adapters use.
|
|
386
|
+
try {
|
|
387
|
+
return fsImpl.readFileSync(path.resolve(__dirname, '../../../core/shared/guidance/pointers/codex.md'), 'utf8').trimEnd();
|
|
388
|
+
} catch { return null; }
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function scopeOf(paths: any) { return paths.scope; }
|
|
392
|
+
|
|
393
|
+
// ---- MCP component ----
|
|
394
|
+
|
|
395
|
+
function mcpDefinitionFor(server: any) {
|
|
396
|
+
// Remote transports project url/httpUrl -> serverUrl per the current Antigravity schema.
|
|
397
|
+
if (server.transport === 'stdio') {
|
|
398
|
+
return { command: server.command, ...(server.args?.length ? { args: server.args } : {}) };
|
|
399
|
+
}
|
|
400
|
+
return { serverUrl: server.url ?? server.httpUrl };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function ownershipIdentity(id: any) { return `doflow:${HARNESS}:mcp-server:${id}`; }
|
|
404
|
+
|
|
405
|
+
/** Everything the shared entry-ownership rules (../mcp-entries.ts) need from this adapter. Rows
|
|
406
|
+
* recorded before entries were fingerprinted carry `fingerprint: null`; such a row owns its entry
|
|
407
|
+
* only while the entry still equals DoFlow's rendering. */
|
|
408
|
+
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], resources = [] }: any) {
|
|
409
|
+
const rendered = (servers: any) => servers.map((server: any) => ({ id: server.id, entry: mcpDefinitionFor(server) }));
|
|
410
|
+
const rows = resources.filter((row: any) => row.kind === 'mcp-server');
|
|
411
|
+
return {
|
|
412
|
+
file: paths.mcpFile, selected: rendered(mcp), adoptable: rendered(mcpAdoptable),
|
|
413
|
+
ownRows: rows.filter((row: any) => row.harness === HARNESS).map((row: any) => ({
|
|
414
|
+
identity: row.identity, target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: row.ownershipIdentity, legacy: false,
|
|
415
|
+
})),
|
|
416
|
+
foreignRows: rows.filter((row: any) => row.harness !== HARNESS).map((row: any) => ({ harness: row.harness, identity: row.identity, target: row.target })),
|
|
417
|
+
identityFor: ownershipIdentity, assetId: POINTER_ASSET_ID, renderer: MCP_RENDERER, label: 'Antigravity MCP',
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ---- required six-function surface ----
|
|
422
|
+
|
|
423
|
+
function plan(options: any = {}, impl: any = {}) {
|
|
424
|
+
const fsImpl = impl.fsImpl || fs;
|
|
425
|
+
const context = options.context ?? {};
|
|
426
|
+
const scope = options.scope ?? 'project';
|
|
427
|
+
const paths = (impl.nativePaths ?? singleton.nativePaths)({ ...options, scope, homeDir: context.homeDir });
|
|
428
|
+
const removing = context.operation === 'remove';
|
|
429
|
+
const neutralResources = ledgerResources(options);
|
|
430
|
+
const selectedServers = Array.isArray(options.mcp) ? options.mcp : [];
|
|
431
|
+
const discovery = options.discovery ?? discover(options, impl);
|
|
432
|
+
|
|
433
|
+
const instructions = planInstructions({ paths, assets: options.assets, removing, repoRoot: context.repoRoot, fsImpl });
|
|
434
|
+
const trees = planTrees({ assets: options.assets, paths, scope, neutralResources, removing, repoRoot: context.repoRoot, force: context.force === true, fsImpl });
|
|
435
|
+
const mcp = planMcpEntries({
|
|
436
|
+
...mcpEntriesInput({ paths, mcp: selectedServers, mcpAdoptable: options.mcpAdoptable, resources: neutralResources }),
|
|
437
|
+
files: discovery.mcpSnapshot, removing,
|
|
438
|
+
});
|
|
439
|
+
const hooksPlan = planHooks({ paths, scope, neutralResources, removing, repoRoot: context.repoRoot, fsImpl });
|
|
440
|
+
|
|
441
|
+
const changes = [...instructions.changes, ...trees.changes, ...mcp.changes, ...hooksPlan.changes];
|
|
442
|
+
const conflicts = [...instructions.conflicts, ...trees.conflicts, ...mcp.conflicts, ...hooksPlan.conflicts];
|
|
443
|
+
return {
|
|
444
|
+
changes,
|
|
445
|
+
conflicts,
|
|
446
|
+
prerequisites: [],
|
|
447
|
+
requiredNativeResources: changes,
|
|
448
|
+
notices: [...trees.notices, ...mcp.notices],
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function apply(options: any = {}, impl: any = {}) {
|
|
453
|
+
const fsImpl = impl.fsImpl || fs;
|
|
454
|
+
// apply()/verify() are reached through the lifecycle with the same scope inputs plan() saw, so
|
|
455
|
+
// they re-derive paths instead of trusting plan-private state. `paths` itself is unused here —
|
|
456
|
+
// every change carries its own absolute target — but resolving it keeps scope validation (and
|
|
457
|
+
// the fail-loud contract) identical to plan().
|
|
458
|
+
(impl.nativePaths ?? singleton.nativePaths)(options);
|
|
459
|
+
const changes = options.changes ?? [];
|
|
460
|
+
|
|
461
|
+
for (const change of changes.filter((c: any) => c.projection?.renderer === 'antigravity-instructions')) {
|
|
462
|
+
if (change.operation === 'remove') {
|
|
463
|
+
// pi precedent: strip only the managed span; the file survives even when nothing remains.
|
|
464
|
+
if (!fsImpl.existsSync(change.target)) continue;
|
|
465
|
+
const next = strippedInstruction(fsImpl.readFileSync(change.target, 'utf8'));
|
|
466
|
+
if (next !== null) fsImpl.writeFileSync(change.target, next, 'utf8');
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
|
|
470
|
+
fsImpl.writeFileSync(change.target, change._content ?? render({ content: '' }), 'utf8');
|
|
471
|
+
}
|
|
472
|
+
for (const change of changes.filter((c: any) => c.projection?.renderer === 'antigravity-hooks')) {
|
|
473
|
+
if (change.kind === 'copy-tree-file') continue; // handled by runTreeChanges below
|
|
474
|
+
if (change.operation === 'remove') {
|
|
475
|
+
// Unmerge only DoFlow's groups (one per policy); a user's own hook groups survive.
|
|
476
|
+
if (!fsImpl.existsSync(change.target)) continue;
|
|
477
|
+
let doc = readJsonObject(change.target, { fsImpl });
|
|
478
|
+
if (!doc) continue;
|
|
479
|
+
for (const group of [HOOKS_GROUP, STOP_HOOKS_GROUP]) delete doc[group];
|
|
480
|
+
if (Object.keys(doc).length === 0) fsImpl.rmSync(change.target, { force: true });
|
|
481
|
+
else { const tmp = `${change.target}.${process.pid}.tmp`;
|
|
482
|
+
fsImpl.writeFileSync(tmp, `${JSON.stringify(doc, null, 2)}\n`, 'utf8'); fsImpl.renameSync(tmp, change.target); }
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (change.content !== undefined) {
|
|
486
|
+
fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
|
|
487
|
+
const tmp = `${change.target}.${process.pid}.tmp`;
|
|
488
|
+
fsImpl.writeFileSync(tmp, change.content, 'utf8'); fsImpl.renameSync(tmp, change.target);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
// Projected hook scripts ride the copy-tree engine (kind copy-tree-file), but their renderer is
|
|
492
|
+
// ours; teach the tree router to include them.
|
|
493
|
+
runTreeChanges(changes, 'all');
|
|
494
|
+
|
|
495
|
+
// Script writes carry pre-rendered text (_text) because they are content-managed, not mirrored:
|
|
496
|
+
// execute them after the generic tree pass so the executable bit lands last and survives.
|
|
497
|
+
|
|
498
|
+
writeMcpEntries(changes, { container: MCP_CONTAINER, keepEmptyContainer: true, fsImpl });
|
|
499
|
+
return { applied: changes.length };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Removal flows through apply(): plan(context.operation='remove') emits operation:'remove'
|
|
503
|
+
// changes, and the branches above already know how to execute each kind. The six-function
|
|
504
|
+
// contract still requires the verb itself.
|
|
505
|
+
function remove(options: any = {}, impl: any = {}) {
|
|
506
|
+
return apply(options, impl);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function verify(options: any = {}, impl: any = {}) {
|
|
510
|
+
const fsImpl = impl.fsImpl || fs;
|
|
511
|
+
const context = options.context ?? {};
|
|
512
|
+
const scope = options.scope ?? 'project';
|
|
513
|
+
const paths = (impl.nativePaths ?? singleton.nativePaths)({ ...options, scope, homeDir: context.homeDir });
|
|
514
|
+
const removing = (context.operation ?? options.operation) === 'remove';
|
|
515
|
+
const statuses = [];
|
|
516
|
+
const resources = [];
|
|
517
|
+
|
|
518
|
+
const instruction = paths.instruction && fsImpl.existsSync(paths.instruction)
|
|
519
|
+
? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
520
|
+
const managed = instruction !== null && instruction.includes(MARKER_START) && instruction.includes(MARKER_END);
|
|
521
|
+
if (paths.instruction) {
|
|
522
|
+
// Removal verification asks "did our section go away?"; install/update asks "is it managed?".
|
|
523
|
+
statuses.push({
|
|
524
|
+
assetId: POINTER_ASSET_ID, capability: 'instructions',
|
|
525
|
+
status: removing ? (managed ? 'retained' : 'absent') : (managed ? 'managed' : 'missing'),
|
|
526
|
+
target: paths.instruction,
|
|
527
|
+
});
|
|
528
|
+
if (managed && !removing) {
|
|
529
|
+
resources.push({
|
|
530
|
+
assetId: POINTER_ASSET_ID, target: paths.instruction,
|
|
531
|
+
ownershipIdentity: `doflow:${HARNESS}:instructions:managed-section`,
|
|
532
|
+
kind: 'instructions-section', identity: 'AGENTS.md',
|
|
533
|
+
fingerprint: fingerprint(instruction), sourceVersion: 'registry-v1',
|
|
534
|
+
projection: { renderer: 'antigravity-instructions' },
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
for (const asset of copyTreeAssets(options.assets ?? [])) {
|
|
540
|
+
const destDir = treeDestFor(asset, paths, scope);
|
|
541
|
+
if (!destDir) continue;
|
|
542
|
+
const sourceDir = sourceDirFor(asset, { repoRoot: context.repoRoot }, fsImpl, HARNESS);
|
|
543
|
+
const result = verifyTree({ sourceDir, destDir, fsImpl, layout: asset.layout, plannedWrites: context.plannedWrites });
|
|
544
|
+
conflictsToStatuses(result.conflicts, asset.id, statuses);
|
|
545
|
+
for (const resource of result.resources) {
|
|
546
|
+
resources.push({
|
|
547
|
+
assetId: asset.id, target: resource.target,
|
|
548
|
+
ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${resource.relPath}`,
|
|
549
|
+
kind: 'copy-tree-file', identity: resource.relPath,
|
|
550
|
+
fingerprint: resource.fingerprint, sourceVersion: 'registry-v1',
|
|
551
|
+
projection: { renderer: 'copy-tree' },
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const entries = mcpEntriesInput({ paths, mcp: options.mcp, mcpAdoptable: options.mcpAdoptable, resources: ledgerResources(options) });
|
|
557
|
+
const mcpFiles = readMcpFiles({ file: entries.file, ownRows: entries.ownRows, container: MCP_CONTAINER, fsImpl });
|
|
558
|
+
const mcp = verifyMcpEntries({
|
|
559
|
+
...entries, files: mcpFiles, snapshot: options.discovery?.mcpSnapshot ?? mcpFiles, removing,
|
|
560
|
+
harness: HARNESS, sourceVersion: context.sourceVersion ?? 'unknown',
|
|
561
|
+
});
|
|
562
|
+
statuses.push(...mcp.statuses);
|
|
563
|
+
resources.push(...mcp.resources);
|
|
564
|
+
|
|
565
|
+
// Hooks projection (project scope): the shims' bytes and the registered groups.
|
|
566
|
+
if (scope === 'project') {
|
|
567
|
+
const hooksTarget = paths.hooksJson;
|
|
568
|
+
const scriptTargets: Record<string, any> = {
|
|
569
|
+
'pre-implementation-gate.sh': paths.hookScript,
|
|
570
|
+
'stop-check.sh': paths.stopHookScript,
|
|
571
|
+
};
|
|
572
|
+
// Source-side residue: reads the shims from THIS checkout (the authored source of the
|
|
573
|
+
// projection, not an install destination — the destination is declared as the paths above).
|
|
574
|
+
const scriptSourceDir = path.join(path.resolve(registryRepoRoot(options)), 'core', 'harnesses', 'antigravity', 'hooks');
|
|
575
|
+
const removingOp = (context.operation ?? options.operation ?? '') === 'remove';
|
|
576
|
+
const fingerprints: Record<string, any> = {};
|
|
577
|
+
let scriptsOk = true;
|
|
578
|
+
let anyPresent = false;
|
|
579
|
+
for (const identity of HOOK_SCRIPTS) {
|
|
580
|
+
let sourceFp = null;
|
|
581
|
+
try { sourceFp = sha256File(fsImpl, path.join(scriptSourceDir, identity)); } catch { /* checkout without that shim */ }
|
|
582
|
+
fingerprints[identity] = sourceFp;
|
|
583
|
+
const target = scriptTargets[identity];
|
|
584
|
+
const current = fsImpl.existsSync(target) ? sha256File(fsImpl, target) : null;
|
|
585
|
+
if (current !== null) anyPresent = true;
|
|
586
|
+
if (current === null || current !== sourceFp) scriptsOk = false;
|
|
587
|
+
}
|
|
588
|
+
const doc = readJsonObject(hooksTarget, { fsImpl });
|
|
589
|
+
const gate = doc?.[HOOKS_GROUP];
|
|
590
|
+
const stop = doc?.[STOP_HOOKS_GROUP];
|
|
591
|
+
const gateOk = Boolean(gate?.PreToolUse?.[0]?.hooks?.[0]?.command)
|
|
592
|
+
&& gate.PreToolUse[0].hooks[0].command === scriptTargets['pre-implementation-gate.sh']
|
|
593
|
+
&& gate.PreToolUse[0].matcher === GATE_MATCHER;
|
|
594
|
+
// Stop registration is matcher-free: handlers sit directly under the event key.
|
|
595
|
+
const stopOk = Array.isArray(stop?.Stop) && stop.Stop.length > 0
|
|
596
|
+
&& stop.Stop[0]?.command === scriptTargets['stop-check.sh'];
|
|
597
|
+
const groupsOk = gateOk && stopOk;
|
|
598
|
+
statuses.push({ assetId: HOOKS_ASSET_ID, capability: 'hooks', status:
|
|
599
|
+
removingOp ? (!anyPresent && !groupsOk ? 'absent' : 'retained')
|
|
600
|
+
: (scriptsOk && groupsOk ? 'managed' : (!anyPresent && !groupsOk ? 'absent' : 'missing')),
|
|
601
|
+
ownershipIdentity: `${HARNESS}:hooks:registration`, target: hooksTarget });
|
|
602
|
+
if (!removingOp && scriptsOk && groupsOk) {
|
|
603
|
+
resources.push({ assetId: HOOKS_ASSET_ID, target: hooksTarget,
|
|
604
|
+
ownershipIdentity: `${HARNESS}:hooks:registration`, kind: 'hooks-json',
|
|
605
|
+
fingerprint: fingerprint(JSON.stringify(doc)), sourceVersion: 'registry-v1',
|
|
606
|
+
projection: { renderer: 'antigravity-hooks' } });
|
|
607
|
+
for (const identity of HOOK_SCRIPTS) {
|
|
608
|
+
resources.push({ assetId: HOOKS_ASSET_ID, target: scriptTargets[identity],
|
|
609
|
+
ownershipIdentity: `${HARNESS}:copy-tree:${HOOKS_ASSET_ID}:${identity}`,
|
|
610
|
+
kind: 'copy-tree-file', identity, fingerprint: fingerprints[identity],
|
|
611
|
+
sourceVersion: 'registry-v1', projection: { renderer: 'antigravity-hooks' } });
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const conflicts = [...statuses.filter((s) => s.status === 'conflict').map((s) => s.reason ?? s.identity), ...mcp.conflicts];
|
|
617
|
+
return { ok: conflicts.length === 0, statuses, resources, conflicts };
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function registryRepoRoot(options: any) {
|
|
621
|
+
return options.registry?.repoRoot ?? process.cwd();
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function conflictsToStatuses(conflicts: any, assetId: any, statuses: any) {
|
|
625
|
+
for (const reason of conflicts) statuses.push({ assetId, capability: 'scripts', status: 'conflict', reason });
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
module.exports = {
|
|
629
|
+
HARNESS, nativePaths: singleton.nativePaths, discover, render, plan, apply, remove, verify,
|
|
630
|
+
createAntigravityAdapter,
|
|
631
|
+
};
|