@khoavu882/doflow 2.0.0-beta.4 → 2.0.0
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/README.md +12 -11
- package/bin/doflow.js +21 -11
- package/core/.antigravity-plugin/plugin.json +1 -3
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/lib.sh +43 -24
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
- package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
- package/core/harnesses/claude/hooks/post-compact.sh +35 -32
- package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
- package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
- package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
- package/core/harnesses/claude/hooks/session-end.sh +23 -10
- package/core/harnesses/claude/hooks/session-start.sh +5 -3
- package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
- package/core/harnesses/claude/hooks/stop-check.sh +5 -3
- package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
- package/core/harnesses/claude/settings/settings.json +18 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
- package/core/harnesses/codex/agents/core-implementer.toml +1 -0
- package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
- package/core/harnesses/codex/agents/research-writer.toml +1 -1
- package/core/harnesses/codex/agents/reviewer.toml +10 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
- package/core/harnesses/codex/agents/system-architect.toml +1 -1
- package/core/harnesses/codex/hooks/lib.sh +44 -25
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
- package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
- package/core/harnesses/codex/hooks/session-start.sh +5 -3
- package/core/harnesses/codex/hooks/stop-check.sh +6 -5
- package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
- package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
- package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow.json +57 -0
- package/core/harnesses/kiro/agents/doflow.json +1 -1
- package/core/harnesses/kiro/hooks/lib.sh +26 -6
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
- package/core/harnesses/kiro/hooks/session-start.sh +12 -5
- package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
- package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
- package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
- package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
- package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
- package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
- package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
- package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
- package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
- package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
- package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
- package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
- package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
- package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
- package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
- package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
- package/core/harnesses/shared/locator/doflow-run +2 -3
- package/core/registry/advice.json +3 -3
- package/core/registry/assets.json +72 -80
- package/core/registry/capabilities.json +12 -0
- package/core/registry/contracts.json +60 -33
- package/core/registry/contribution-points.json +32 -0
- package/core/registry/gates.json +32 -0
- package/core/registry/guidance-caps.json +40 -0
- package/core/registry/harnesses.json +1542 -277
- package/core/registry/lifecycle.json +2837 -37
- package/core/registry/mcp.json +5 -1
- package/core/registry/models.json +7 -1
- package/core/registry/package-templates/README.md +19 -0
- package/core/registry/package-templates/agent/files/agent.md +9 -0
- package/core/registry/package-templates/agent/template.json +4 -0
- package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
- package/core/registry/package-templates/capability-provider/template.json +11 -0
- package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
- package/core/registry/package-templates/debate-preset/template.json +4 -0
- package/core/registry/package-templates/review-preset/files/preset.json +30 -0
- package/core/registry/package-templates/review-preset/template.json +4 -0
- package/core/registry/package-templates/skill/files/SKILL.md +8 -0
- package/core/registry/package-templates/skill/template.json +4 -0
- package/core/registry/package-templates/worker/files/worker.json +92 -0
- package/core/registry/package-templates/worker/template.json +11 -0
- package/core/registry/packages/doflow/doflow-package.json +15 -0
- package/core/registry/packages/doflow/presets/debate-3.json +26 -0
- package/core/registry/protocols.json +61 -0
- package/core/registry/routes.json +17 -0
- package/core/registry/rules.json +431 -0
- package/core/registry/settings.json +276 -0
- package/core/registry/storage.json +701 -30
- package/core/registry/telemetry.json +236 -0
- package/core/registry/transcripts.json +142 -0
- package/core/registry/verification.json +76 -1
- package/core/registry/workflows.json +55 -0
- package/core/shared/agent-specs/core-implementer.md +3 -0
- package/core/shared/agent-specs/delivery-lead.md +68 -0
- package/core/shared/agent-specs/quality-guardian.md +5 -1
- package/core/shared/agent-specs/research-writer.md +10 -3
- package/core/shared/agent-specs/reviewer.md +53 -0
- package/core/shared/agent-specs/spec-analyst.md +5 -6
- package/core/shared/agent-specs/system-architect.md +5 -1
- package/core/shared/guidance/DOFLOW_CORE.md +1 -5
- package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
- package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
- package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
- package/core/shared/guidance/pointers/codex.md +1 -4
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
- package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
- package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
- package/core/shared/guidance/rules/RULES.md +45 -0
- package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
- package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
- package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
- package/core/shared/scripts/doflow/bin/doflow-run +154 -35
- package/core/shared/skills/do/SKILL.md +12 -10
- package/core/shared/skills/do/references/advice_calls.md +26 -0
- package/core/shared/skills/do/references/pm_routing.md +1 -2
- package/core/shared/skills/do/references/program_mode.md +31 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
- package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
- package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
- package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
- package/core/shared/skills/do-code-review/SKILL.md +41 -144
- package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
- package/core/shared/skills/do-code-review/references/tools.md +90 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
- package/core/shared/skills/do-design/SKILL.md +24 -23
- package/core/shared/skills/do-diagnose/SKILL.md +14 -4
- package/core/shared/skills/do-document/SKILL.md +11 -1
- package/core/shared/skills/do-document/references/deep_research.md +1 -2
- package/core/shared/skills/do-document/references/embedded-research.md +18 -6
- package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
- package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
- package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
- package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
- package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
- package/core/shared/skills/do-flow/SKILL.md +8 -9
- package/core/shared/skills/do-flow/references/task_classes.md +2 -2
- package/core/shared/skills/do-git/SKILL.md +4 -0
- package/core/shared/skills/do-implement/SKILL.md +7 -9
- package/core/shared/skills/do-plan/SKILL.md +29 -19
- package/core/shared/skills/do-test/SKILL.md +7 -4
- package/core/shared/templates/doflow/constitution-template.md +9 -3
- package/core/shared/templates/doflow/data-model-template.md +1 -1
- package/core/shared/templates/doflow/design-template.md +113 -16
- package/core/shared/templates/doflow/plan-template.md +11 -10
- package/core/shared/templates/doflow/question-log-template.md +14 -2
- package/core/shared/templates/doflow/requirement-template.md +1 -1
- package/core/worker-evidence/antigravity/checks.json +14 -0
- package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
- package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
- package/core/worker-evidence/codex/checks.json +38 -0
- package/package.json +10 -6
- package/src/adapters/antigravity/index.js +226 -113
- package/src/adapters/claude/index.js +39 -5
- package/src/adapters/codex/agents.js +25 -15
- package/src/adapters/codex/hooks.js +40 -5
- package/src/adapters/codex/index.js +100 -22
- package/src/adapters/codex/native-projection.js +6 -2
- package/src/adapters/copilot/index.js +58 -23
- package/src/adapters/copy-tree.js +294 -48
- package/src/adapters/guidance-manifest.js +71 -0
- package/src/adapters/guidance-pointer.js +19 -0
- package/src/adapters/hook-commands.js +6 -10
- package/src/adapters/index.js +1 -0
- package/src/adapters/kiro/index.js +38 -13
- package/src/adapters/opencode/index.js +8 -8
- package/src/adapters/pi/hooks.js +120 -0
- package/src/adapters/pi/index.js +48 -16
- package/src/adapters/resolve-source.js +26 -2
- package/src/cli/commands/install.js +3 -2
- package/src/cli/commands/reconcile.js +53 -9
- package/src/cli/commands/remove.js +2 -2
- package/src/cli/commands/rollback.js +6 -3
- package/src/cli/commands/self-update.js +18 -9
- package/src/cli/commands/status.js +21 -2
- package/src/cli/commands/ui.js +99 -0
- package/src/cli/commands/update.js +3 -2
- package/src/cli/index.js +338 -33
- package/src/cli/runtime-commands.js +243 -52
- package/src/cli/shared.js +0 -2
- package/src/helper/git.js +1 -1
- package/src/helper/guardrails.js +1 -1
- package/src/helper/marker-merge.js +31 -13
- package/src/helper/package-ids.js +37 -0
- package/src/helper/semver.js +94 -0
- package/src/install/backup.js +105 -15
- package/src/install/context.js +1 -1
- package/src/install/targets.js +31 -16
- package/src/lifecycle/coverage.js +74 -0
- package/src/lifecycle/hook-step.js +61 -0
- package/src/lifecycle/hook-tier.js +160 -0
- package/src/lifecycle/index.js +434 -86
- package/src/lifecycle/retired-harnesses.js +318 -0
- package/src/lifecycle/view.js +35 -15
- package/src/registry/index.js +686 -32
- package/src/registry/worker-ids.js +45 -0
- package/src/release/build-package.js +0 -3
- package/src/release/docs-blocks.js +492 -0
- package/src/release/preflight.js +425 -0
- package/src/release/rehearse.js +401 -0
- package/src/release/release-workflow.js +733 -0
- package/src/release/sync-plugin-versions.js +43 -7
- package/src/runtime/advice/bench-gate.js +25 -0
- package/src/runtime/advice/cli.js +59 -16
- package/src/runtime/advice/client.js +32 -9
- package/src/runtime/advice/config.js +98 -133
- package/src/runtime/advice/doctor.js +1 -1
- package/src/runtime/advice/elevation.js +97 -0
- package/src/runtime/advice/endpoint-guard.js +9 -3
- package/src/runtime/advice/mode.js +37 -0
- package/src/runtime/advice/record.js +18 -5
- package/src/runtime/advice/registry.js +4 -1
- package/src/runtime/advice/shadow-config.js +229 -0
- package/src/runtime/advice/shadow-dispatcher.js +276 -0
- package/src/runtime/brief-rules.js +81 -0
- package/src/runtime/brief-tools.js +111 -34
- package/src/runtime/candidate.js +514 -0
- package/src/runtime/capabilities/executor.js +450 -0
- package/src/runtime/capabilities/loopback.js +41 -0
- package/src/runtime/capabilities/sanitizer.js +88 -0
- package/src/runtime/capability-router.js +135 -3
- package/src/runtime/checkouts.js +73 -11
- package/src/runtime/claims.js +27 -12
- package/src/runtime/cli-result.js +11 -4
- package/src/runtime/cli.js +221 -277
- package/src/runtime/config-home.js +42 -0
- package/src/runtime/context/arbitrate.js +767 -0
- package/src/runtime/context/budget.js +203 -0
- package/src/runtime/context/compose.js +1367 -0
- package/src/runtime/context/delivery-store.js +100 -0
- package/src/runtime/context/emission-rules.js +118 -0
- package/src/runtime/context/identity.js +227 -0
- package/src/runtime/context/mandatory.js +594 -0
- package/src/runtime/context/pointer.js +142 -0
- package/src/runtime/context/primary-command.js +117 -0
- package/src/runtime/context/primary.js +344 -0
- package/src/runtime/context/summary-store.js +655 -0
- package/src/runtime/context-pack.js +1106 -245
- package/src/runtime/decision-register.js +13 -4
- package/src/runtime/dispatch/admission.js +392 -0
- package/src/runtime/dispatch/attempt-end.js +274 -0
- package/src/runtime/dispatch/command.js +628 -0
- package/src/runtime/dispatch/controls.js +904 -0
- package/src/runtime/dispatch/envelope.js +276 -0
- package/src/runtime/dispatch/grants.js +310 -0
- package/src/runtime/dispatch/integrate.js +617 -0
- package/src/runtime/dispatch/loop.js +1835 -0
- package/src/runtime/dispatch/store.js +352 -0
- package/src/runtime/dispatch/verify-run.js +201 -0
- package/src/runtime/evidence-fields.js +39 -0
- package/src/runtime/evidence-ledger.js +41 -7
- package/src/runtime/failure/capture.js +3 -1
- package/src/runtime/failure/cli.js +25 -9
- package/src/runtime/failure/home.js +57 -30
- package/src/runtime/failure/store.js +7 -2
- package/src/runtime/feature-pointer.js +174 -0
- package/src/runtime/feature-resolve.js +13 -2
- package/src/runtime/fleet/command.js +77 -0
- package/src/runtime/fleet/projects.js +178 -0
- package/src/runtime/fleet/tree.js +383 -0
- package/src/runtime/freshness.js +77 -10
- package/src/runtime/git-memo.js +46 -0
- package/src/runtime/guidance/ablation.js +427 -0
- package/src/runtime/health.js +565 -17
- package/src/runtime/history-compactor.js +13 -3
- package/src/runtime/implementation-gate.js +277 -22
- package/src/runtime/inventory/coverage.js +1 -1
- package/src/runtime/inventory/index.js +1 -1
- package/src/runtime/inventory/precedence.js +2 -2
- package/src/runtime/inventory/siblings.js +6 -4
- package/src/runtime/knowledge/code-corpus.js +277 -0
- package/src/runtime/knowledge/code-lexical.js +130 -0
- package/src/runtime/knowledge/code-retrieval.js +307 -0
- package/src/runtime/knowledge/code-validation.js +106 -0
- package/src/runtime/knowledge/gp3-gate.js +74 -0
- package/src/runtime/knowledge/graph-adapter.js +288 -0
- package/src/runtime/knowledge/graph-fallback.js +394 -0
- package/src/runtime/knowledge/hybrid.js +136 -8
- package/src/runtime/knowledge/retrieval.js +34 -1
- package/src/runtime/knowledge/rtk-compress.js +77 -0
- package/src/runtime/knowledge/semble-bridge.py +106 -0
- package/src/runtime/knowledge/semble-lifecycle.js +114 -0
- package/src/runtime/knowledge/semble-provider.js +365 -0
- package/src/runtime/lifecycle/cli.js +16 -6
- package/src/runtime/lifecycle/event-store.js +8 -6
- package/src/runtime/lifecycle/followup.js +6 -1
- package/src/runtime/lifecycle/overview.js +24 -1
- package/src/runtime/lifecycle/report-store.js +8 -10
- package/src/runtime/lifecycle/retention.js +95 -31
- package/src/runtime/lifecycle/root.js +9 -1
- package/src/runtime/lifecycle/status.js +34 -17
- package/src/runtime/lifecycle/store-upkeep.js +56 -7
- package/src/runtime/mask.js +134 -7
- package/src/runtime/mcp-consultations.js +40 -6
- package/src/runtime/model-router.js +79 -7
- package/src/runtime/models/catalogue.js +191 -0
- package/src/runtime/models/command.js +153 -0
- package/src/runtime/off-words.js +12 -0
- package/src/runtime/outcome.js +3 -3
- package/src/runtime/packages/command.js +1009 -0
- package/src/runtime/packages/contributions.js +116 -0
- package/src/runtime/packages/digest.js +132 -0
- package/src/runtime/packages/fetch.js +182 -0
- package/src/runtime/packages/grants.js +192 -0
- package/src/runtime/packages/index-file.js +134 -0
- package/src/runtime/packages/instruction.js +90 -0
- package/src/runtime/packages/manifest.js +331 -0
- package/src/runtime/packages/points.js +477 -0
- package/src/runtime/packages/programs.js +216 -0
- package/src/runtime/packages/scaffold.js +277 -0
- package/src/runtime/packages/source.js +90 -0
- package/src/runtime/packages/state.js +164 -0
- package/src/runtime/packages/store.js +449 -0
- package/src/runtime/packages/tar.js +106 -0
- package/src/runtime/packages/view.js +406 -0
- package/src/runtime/plan-check.js +59 -0
- package/src/runtime/plan-content.js +324 -0
- package/src/runtime/policy-init.js +118 -0
- package/src/runtime/profiles/doctor.js +96 -0
- package/src/runtime/profiles/resolve.js +244 -0
- package/src/runtime/profiles/rollback.js +254 -0
- package/src/runtime/profiles/sampler.js +41 -0
- package/src/runtime/readiness-record.js +16 -11
- package/src/runtime/readiness.js +127 -16
- package/src/runtime/research-request.js +50 -25
- package/src/runtime/retrieval-plan.js +402 -73
- package/src/runtime/retrieval-record.js +293 -0
- package/src/runtime/review/command.js +246 -0
- package/src/runtime/review/dominance.js +68 -0
- package/src/runtime/review/findings.js +434 -0
- package/src/runtime/review/identity.js +255 -0
- package/src/runtime/review/protocol-command.js +109 -0
- package/src/runtime/review/protocols.js +405 -0
- package/src/runtime/review/resolve-protocol.js +302 -0
- package/src/runtime/review/start.js +530 -0
- package/src/runtime/roadmap/facts.js +479 -0
- package/src/runtime/roadmap/gates.js +270 -0
- package/src/runtime/roadmap/loop.js +1636 -0
- package/src/runtime/roadmap/merge.js +381 -0
- package/src/runtime/roadmap/rows.js +1113 -0
- package/src/runtime/roadmap/seed.js +951 -0
- package/src/runtime/rules-report.js +336 -0
- package/src/runtime/scaffold/artifacts.js +63 -9
- package/src/runtime/scaffold/generate.js +21 -9
- package/src/runtime/settings/autopilot.js +106 -0
- package/src/runtime/settings/cli.js +280 -0
- package/src/runtime/settings/config-write.js +314 -0
- package/src/runtime/settings/files.js +271 -0
- package/src/runtime/settings/legacy.js +154 -0
- package/src/runtime/settings/lexical.js +56 -0
- package/src/runtime/settings/prepared-run.js +269 -0
- package/src/runtime/settings/project-layers.js +118 -0
- package/src/runtime/settings/refs.js +288 -0
- package/src/runtime/settings/registry.js +553 -0
- package/src/runtime/settings/resolve.js +713 -0
- package/src/runtime/settings/shared.js +37 -0
- package/src/runtime/settings/worker-billing.js +107 -0
- package/src/runtime/settings/write.js +269 -0
- package/src/runtime/slot-command.js +78 -0
- package/src/runtime/slots.js +671 -0
- package/src/runtime/source-version.js +290 -0
- package/src/runtime/state-root.js +217 -0
- package/src/runtime/storage/cli.js +12 -5
- package/src/runtime/storage/engine.js +9 -2
- package/src/runtime/storage/registry.js +14 -1
- package/src/runtime/storage/roots.js +66 -16
- package/src/runtime/storage/rules.js +82 -10
- package/src/runtime/storage/upkeep.js +10 -2
- package/src/runtime/storage/work-status.js +245 -26
- package/src/runtime/task-attempts.js +589 -69
- package/src/runtime/task-classifier.js +47 -11
- package/src/runtime/task-graph.js +373 -0
- package/src/runtime/task-run.js +778 -0
- package/src/runtime/task-scope.js +202 -56
- package/src/runtime/task-sources.js +147 -0
- package/src/runtime/task-state.js +440 -65
- package/src/runtime/team/admission.js +301 -0
- package/src/runtime/team/envelope.js +324 -0
- package/src/runtime/team/review-guard.js +156 -0
- package/src/runtime/trace/analyze.js +427 -0
- package/src/runtime/trace/baseline.js +770 -0
- package/src/runtime/trace/ledger.js +63 -140
- package/src/runtime/trace/otlp-export.js +568 -0
- package/src/runtime/trace/otlp-map.js +481 -0
- package/src/runtime/trace/spans.js +745 -0
- package/src/runtime/trace/telemetry.js +225 -0
- package/src/runtime/trace/views.js +1 -0
- package/src/runtime/transcripts/command.js +98 -0
- package/src/runtime/transcripts/cursor.js +326 -0
- package/src/runtime/transcripts/read.js +126 -0
- package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
- package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
- package/src/runtime/transcripts/readers/copilot-events.js +90 -0
- package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
- package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
- package/src/runtime/transcripts/registry.js +161 -0
- package/src/runtime/transcripts/stats.js +161 -0
- package/src/runtime/verification/check-key.js +628 -0
- package/src/runtime/verification/contract-runner.js +546 -11
- package/src/runtime/verification/engine.js +499 -9
- package/src/runtime/verification/impact.js +617 -0
- package/src/runtime/verification/inflight.js +205 -0
- package/src/runtime/verification/registry.js +176 -0
- package/src/runtime/verification/reuse.js +184 -0
- package/src/runtime/verification/telemetry-emit.js +254 -0
- package/src/runtime/verification/test-selection.js +67 -7
- package/src/runtime/worker/active.js +90 -0
- package/src/runtime/worker/cancel.js +222 -0
- package/src/runtime/worker/catalogue.js +122 -0
- package/src/runtime/worker/command.js +677 -0
- package/src/runtime/worker/evidence.js +288 -0
- package/src/runtime/worker/launch.js +288 -0
- package/src/runtime/worker/models.js +137 -0
- package/src/runtime/worker/parsers.js +218 -0
- package/src/runtime/worker/probes/index.js +706 -0
- package/src/runtime/worker/process-tree.js +415 -0
- package/src/runtime/worker/quota.js +43 -0
- package/src/runtime/worker/readiness.js +713 -0
- package/src/runtime/worker/run-store.js +166 -0
- package/src/runtime/worker/supervisor.js +541 -0
- package/src/runtime/worker/worktree-check.js +252 -0
- package/src/runtime/workflow-engine.js +5 -1
- package/src/runtime/workflow-orchestrator.js +578 -63
- package/src/runtime/worktree.js +149 -22
- package/src/state/index.js +1 -1
- package/src/state/lockfile.js +64 -10
- package/src/state/run-lock.js +1 -1
- package/types/node-commonjs.d.ts +106 -7
- package/core/.antigravity-plugin/hooks.json +0 -39
- package/core/harnesses/gemini/hooks/hooks.json +0 -77
- package/core/harnesses/gemini/hooks/lib.sh +0 -302
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
- package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
- package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
- package/core/harnesses/gemini/hooks/session-end.sh +0 -5
- package/core/harnesses/gemini/hooks/session-start.sh +0 -5
- package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
- package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
- package/core/harnesses/shared/hooks/hooks.json +0 -47
- package/core/shared/guidance/FLAGS.md +0 -25
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
- package/src/adapters/gemini/hooks.js +0 -210
- package/src/adapters/gemini/index.js +0 -390
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
-
|
|
5
|
-
// Gemini CLI adapter. Native settings are JSON and Gemini's extension installation is a host
|
|
6
|
-
// workflow, so this adapter deliberately plans only safe instruction projection while exposing
|
|
7
|
-
// settings/MCP/extensions as first-class native-surface results for the lifecycle UI.
|
|
8
|
-
const fs = require('node:fs');
|
|
9
|
-
const path = require('node:path');
|
|
10
|
-
const { planTree, applyTree, removeTree, verifyTree, copyTreeAssets, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, readJson, sourceDirFor, resolveTransform } = require('../copy-tree.js');
|
|
11
|
-
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
|
|
12
|
-
const { planGeminiHooks, deployGeminiHooks, planRemoveGeminiHooks, deployRemoveGeminiHooks } = require('./hooks.js');
|
|
13
|
-
|
|
14
|
-
const MARKER_START = '<!-- doflow:start -->';
|
|
15
|
-
const MARKER_END = '<!-- doflow:end -->';
|
|
16
|
-
/**
|
|
17
|
-
* Residue (not a path fact): the one non-path native fact this harness still reads from its own
|
|
18
|
-
* fixture file — how extensions are installed ("native-host-workflow"), reported verbatim in plan
|
|
19
|
-
* surfaces. The file-name facts that used to live beside it (instructionFile, settingsFile) are now
|
|
20
|
-
* declared in core/registry/harnesses.json "paths" and resolve below like every other harness.
|
|
21
|
-
*/
|
|
22
|
-
const DEFAULTS_FILE = path.resolve(__dirname, '../../../core/harnesses/gemini/settings/adapter-defaults.json');
|
|
23
|
-
const HARNESS = 'gemini';
|
|
24
|
-
|
|
25
|
-
function defaults({ fsImpl = fs } = {}) { return JSON.parse(fsImpl.readFileSync(DEFAULTS_FILE, 'utf8')); }
|
|
26
|
-
|
|
27
|
-
/** Pure string helper (no path facts): replace only the span between DoFlow's markers in an
|
|
28
|
-
* existing GEMINI.md body. An existing file with no DoFlow section is refused rather than appended
|
|
29
|
-
* to — GEMINI.md is shared with the user and other tools. */
|
|
30
|
-
function managedInstruction(existing , rendered ) {
|
|
31
|
-
if (existing === null) return { ok: true, operation: 'create', content: rendered };
|
|
32
|
-
const start = existing.indexOf(MARKER_START);
|
|
33
|
-
const end = existing.indexOf(MARKER_END);
|
|
34
|
-
if (start === -1 && end === -1) return { ok: false, conflict: 'GEMINI.md exists without a DoFlow managed section' };
|
|
35
|
-
if (start === -1 || end === -1 || end < start) return { ok: false, conflict: 'GEMINI.md has malformed DoFlow managed-section markers' };
|
|
36
|
-
const content = `${existing.slice(0, start)}${rendered}${existing.slice(end + MARKER_END.length).replace(/^\n?/, '')}`;
|
|
37
|
-
return { ok: true, operation: content === existing ? 'none' : 'merge', content };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Server names in one settings read, or null when the file is absent or unreadable. */
|
|
41
|
-
function settingsServerNames(read ) {
|
|
42
|
-
if (!read.exists || read.error || !read.value || typeof read.value !== 'object') return null;
|
|
43
|
-
const servers = read.value.mcpServers;
|
|
44
|
-
return Object.keys(servers && typeof servers === 'object' ? servers : {});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* The server names DoFlow can see for Gemini at a scope (`mcpConfigured`): the scope's settings, and
|
|
49
|
-
* at project scope the user's `~/.gemini/settings.json` too, since Gemini merges both. `null` while
|
|
50
|
-
* neither can be read. Gemini also merges system settings and extension servers, which DoFlow does
|
|
51
|
-
* not read, so the view is never complete (`mcpComplete: false`) and absence is never proof.
|
|
52
|
-
*/
|
|
53
|
-
function configuredGeminiMcp({ scope, settings, homeDir, fsImpl } ) {
|
|
54
|
-
const own = settingsServerNames(settings);
|
|
55
|
-
const user = scope === 'project' && homeDir ? settingsServerNames(readJson(path.join(homeDir, '.gemini', 'settings.json'), { fsImpl })) : null;
|
|
56
|
-
const mcpConfigured = own || user ? [...new Set([...(own || []), ...(user || [])])].sort() : null;
|
|
57
|
-
return { mcpConfigured, mcpComplete: false };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Native path facts live in core/registry/harnesses.json under this harness's "paths" section and
|
|
62
|
-
* resolve through the shared harness-paths resolver: project-scope config follows the Antigravity
|
|
63
|
-
* customization convention (.agents/) while user-scope config lives under ~/.gemini/config/.
|
|
64
|
-
* createGeminiAdapter({ declaredPaths }) is the injection point buildAdapterRegistry() uses;
|
|
65
|
-
* module-level exports delegate to a default-configured instance so direct callers keep their
|
|
66
|
-
* historical shape.
|
|
67
|
-
*/
|
|
68
|
-
function createGeminiAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS] } = {}) {
|
|
69
|
-
function nativePaths({ scope, scopeRoot, homeDir, fsImpl = fs } ) {
|
|
70
|
-
const resolved = resolveHarnessPaths(declaredPaths, { scope, scopeRoot, homeDir });
|
|
71
|
-
// Non-path native fact carried alongside the resolved surfaces (see DEFAULTS_FILE residue note).
|
|
72
|
-
return { ...resolved, extensionMode: defaults({ fsImpl }).extensionInstall };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function discover({ scope, scopeRoot, context = {}, fsImpl = fs } ) {
|
|
76
|
-
const paths = nativePaths({ scope, scopeRoot, homeDir: context.homeDir, fsImpl });
|
|
77
|
-
const instruction = fsImpl.existsSync(paths.instruction) ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
78
|
-
// Gemini takes no servers from DoFlow's MCP catalog.
|
|
79
|
-
const settings = readJson(paths.settings, { fsImpl });
|
|
80
|
-
const { mcpConfigured, mcpComplete } = configuredGeminiMcp({ scope, settings, homeDir: context.homeDir, fsImpl });
|
|
81
|
-
return { paths, instruction, settings, mcpOwned: [], mcpConfigured, mcpComplete };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function render({ content = '' } = {}) {
|
|
85
|
-
const body = String(content).trimEnd();
|
|
86
|
-
return `${MARKER_START}\n${body}\n${MARKER_END}\n`;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Rewrite the pointer's guidance import so it resolves from wherever the instruction file
|
|
91
|
-
* actually lands. The shared pointer source carries one hardcoded `../`, which is correct only
|
|
92
|
-
* when the instruction file sits one level below the install root — true for Gemini's global
|
|
93
|
-
* scope (`.gemini/GEMINI.md`) and false for its project scope, where Gemini reads `GEMINI.md`
|
|
94
|
-
* from the workspace root itself. A static prefix cannot satisfy both, because the depth varies
|
|
95
|
-
* by scope rather than by harness, so it is computed here instead. Left unrewritten, the import
|
|
96
|
-
* pointed above the install root and the whole guidance chain silently failed to load.
|
|
97
|
-
*
|
|
98
|
-
* Logic residue: the relative prefix depends on the DISTANCE between two declared surfaces
|
|
99
|
-
* (instruction vs. the guidance tree), not on any single declared path — expressible only by
|
|
100
|
-
* joining and diffing, which is computation, not declaration.
|
|
101
|
-
*/
|
|
102
|
-
function geminiDestDir(paths , asset ) {
|
|
103
|
-
if (asset.nativeDir && asset.nativeDir.startsWith('../')) {
|
|
104
|
-
const dest = path.join(paths.root, asset.nativeDir.slice(3));
|
|
105
|
-
const rel = path.relative(paths.root, dest);
|
|
106
|
-
if (rel === '..' || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) {
|
|
107
|
-
throw new Error(`gemini nativeDir escapes the scope root: ${asset.nativeDir}`);
|
|
108
|
-
}
|
|
109
|
-
return dest;
|
|
110
|
-
}
|
|
111
|
-
return copyTreeDestDir(paths.configDir, asset);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function rewriteGuidanceImport(content , assets , paths ) {
|
|
115
|
-
const guidance = assets.find((item ) => item.id === 'guidance.context-layer');
|
|
116
|
-
if (!guidance?.nativeDir || !paths?.instruction || !paths?.configDir) return content;
|
|
117
|
-
const guidanceDir = geminiDestDir(paths, guidance);
|
|
118
|
-
const rel = path.relative(path.dirname(paths.instruction), guidanceDir).split(path.sep).join('/');
|
|
119
|
-
if (!rel) return content;
|
|
120
|
-
// `./` is added explicitly for a same-directory descent: the bare form starts with the dot of
|
|
121
|
-
// `.doflow`, which reads as an extension rather than a path segment.
|
|
122
|
-
const prefix = rel.startsWith('../') ? rel : `./${rel}`;
|
|
123
|
-
return content.replace(/@\S*?(DOFLOW_CORE\.md)/g, `@${prefix}/$1`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function instructionContent({ assets, context, paths, fsImpl = fs } ) {
|
|
127
|
-
if (context.instructionContent !== undefined) return String(context.instructionContent);
|
|
128
|
-
const asset = assets.find((item ) => item.id === 'guidance.core');
|
|
129
|
-
if (!asset || !context.repoRoot) return null;
|
|
130
|
-
const source = path.resolve(context.repoRoot, asset.source);
|
|
131
|
-
if (!fsImpl.existsSync(source)) return null;
|
|
132
|
-
return rewriteGuidanceImport(fsImpl.readFileSync(source, 'utf8'), assets, paths);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function policyStatuses(policies = []) {
|
|
136
|
-
return policies.map((policy ) => ({ id: policy.id, status: 'unavailable', fallback: 'guidance', reason: 'Gemini policy automation is not rendered by this adapter' }));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// ---- copy-tree assets (rules, skills, agents, modes, references) ----
|
|
140
|
-
|
|
141
|
-
function planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing, fsImpl = fs } ) {
|
|
142
|
-
const paths = nativePaths({ scope, scopeRoot, homeDir: context.homeDir, fsImpl });
|
|
143
|
-
const changes = [];
|
|
144
|
-
const conflicts = [];
|
|
145
|
-
const treeResults = [];
|
|
146
|
-
const notices = [];
|
|
147
|
-
for (const asset of copyTreeAssets(assets)) {
|
|
148
|
-
const destDir = geminiDestDir(paths, asset);
|
|
149
|
-
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Gemini');
|
|
150
|
-
const previousResources = ledgerFileResources(ledger?.resources, HARNESS, asset.id);
|
|
151
|
-
const result = planTree({ sourceDir, destDir, previousResources, siblingFingerprints: ledgerSiblingFingerprints(ledger?.resources, HARNESS), operation: removing ? 'remove' : 'apply', fsImpl, layout: asset.layout, transform: asset.transform, keepModified: !removing,
|
|
152
|
-
// Was `force: context?.force`, ungated. Gemini was one of only two adapters forwarding force
|
|
153
|
-
// at all, so it looked like the reference implementation — but it handed force to the remove
|
|
154
|
-
// path too, where copy-tree deliberately stays strict: force heals drift on apply, and a
|
|
155
|
-
// hand-edited file is never deleted, forced or not (codex/index.ts states the rule in full).
|
|
156
|
-
// Found by the guard written for the six adapters that forwarded nothing.
|
|
157
|
-
force: !removing && context?.force === true });
|
|
158
|
-
treeResults.push(result);
|
|
159
|
-
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
160
|
-
// A hand-edited file at a path DoFlow no longer writes (the agents folder layout) is the
|
|
161
|
-
// user's: it stays, only its ownership row is released.
|
|
162
|
-
notices.push(...result.kept.map((item ) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
|
|
163
|
-
for (const change of result.changes) {
|
|
164
|
-
changes.push({
|
|
165
|
-
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
166
|
-
ownershipIdentity: `doflow:gemini:copy-tree:${asset.id}:${change.relPath}`,
|
|
167
|
-
kind: 'copy-tree-file', identity: change.relPath,
|
|
168
|
-
afterFingerprint: change.fingerprint, fingerprint: change.fingerprint, sourceVersion: 'registry-v1',
|
|
169
|
-
transformName: asset.transform || null,
|
|
170
|
-
...(change.kept ? { retained: true, retainedFor: [] } : {}),
|
|
171
|
-
projection: { renderer: 'copy-tree' },
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return { changes, conflicts, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function applyCopyTreeAssets(changes , { fsImpl = fs } = {}) {
|
|
179
|
-
let applied = 0;
|
|
180
|
-
const grouped = new Map();
|
|
181
|
-
for (const change of changes) {
|
|
182
|
-
if (change.projection?.renderer !== 'copy-tree' || change.operation === 'remove') continue;
|
|
183
|
-
const key = change.transformName || null;
|
|
184
|
-
if (!grouped.has(key)) grouped.set(key, []);
|
|
185
|
-
grouped.get(key).push({ relPath: change.identity, target: change.target, source: change.source, operation: change.operation, fingerprint: change.fingerprint });
|
|
186
|
-
}
|
|
187
|
-
for (const [transformName, treeChanges] of grouped) {
|
|
188
|
-
applied += applyTree({ changes: treeChanges, fsImpl, transform: resolveTransform(transformName) }).applied;
|
|
189
|
-
}
|
|
190
|
-
return applied;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function removeCopyTreeAssets(changes , { fsImpl = fs } = {}) {
|
|
194
|
-
const treeChanges = changes.filter((change ) => change.projection?.renderer === 'copy-tree' && change.operation === 'remove' && !change.retained)
|
|
195
|
-
.map((change ) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
|
|
196
|
-
return removeTree({ changes: treeChanges, fsImpl }).removed;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl = fs } ) {
|
|
200
|
-
const paths = nativePaths({ scope, scopeRoot, homeDir: context.homeDir, fsImpl });
|
|
201
|
-
const statuses = [];
|
|
202
|
-
const resources = [];
|
|
203
|
-
const conflicts = [];
|
|
204
|
-
for (const asset of copyTreeAssets(assets)) {
|
|
205
|
-
const destDir = geminiDestDir(paths, asset);
|
|
206
|
-
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Gemini');
|
|
207
|
-
const result = verifyTree({ sourceDir, destDir, fsImpl, layout: asset.layout, transform: asset.transform, plannedWrites: context?.plannedWrites });
|
|
208
|
-
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
209
|
-
for (const resource of result.resources) {
|
|
210
|
-
resources.push({
|
|
211
|
-
assetId: asset.id, target: resource.target, ownershipIdentity: `doflow:gemini:copy-tree:${asset.id}:${resource.relPath}`,
|
|
212
|
-
kind: 'copy-tree-file', identity: resource.relPath,
|
|
213
|
-
fingerprint: resource.fingerprint, sourceVersion: 'registry-v1',
|
|
214
|
-
projection: { renderer: 'copy-tree' },
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
statuses.push({ assetId: asset.id, capability: asset.capability, status: result.ok ? 'managed' : 'conflict', target: destDir });
|
|
218
|
-
}
|
|
219
|
-
return { statuses, resources, conflicts };
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// ---- shared adapter contract ----
|
|
223
|
-
|
|
224
|
-
// Hooks are a pseudo-component, not a registry-declared asset (like Codex's own hooks
|
|
225
|
-
// integration) — the lifecycle layer's normalizeChange() requires every change's assetId to
|
|
226
|
-
// match a real registered asset, so this piggybacks on guidance.core's id the same way Codex's
|
|
227
|
-
// assetIdFor(options, 'hooks') does, rather than inventing an unregistered 'hooks' id.
|
|
228
|
-
function hooksAssetId(assets ) {
|
|
229
|
-
return assets.find((asset ) => asset.id === 'guidance.core')?.id ?? assets[0]?.id;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** Plan the hooks pseudo-component's single change (or none), mirroring the {changes, conflicts}
|
|
233
|
-
* shape planCopyTreeAssets already returns so plan() can fold it in the same way. The hook
|
|
234
|
-
* scripts directory beside settings.json is declared (paths.hooksDirectory); the merge/remove
|
|
235
|
-
* planning itself lives in ./hooks.ts. */
|
|
236
|
-
function planHooksChange({ removing, found, context, assets, fsImpl } ) {
|
|
237
|
-
if (found.settings.error) return { changes: [], conflicts: [] };
|
|
238
|
-
const hooksPlan = removing
|
|
239
|
-
? planRemoveGeminiHooks({ settingsFile: found.paths.settings, fsImpl })
|
|
240
|
-
: (context.geminiHooksSourceFile
|
|
241
|
-
? planGeminiHooks({ sourceFile: context.geminiHooksSourceFile, sourceHooksDir: context.geminiHooksSourceDir,
|
|
242
|
-
settingsFile: found.paths.settings, destinationHooksDir: found.paths.hooksDirectory, trusted: context.hooksTrusted, fsImpl })
|
|
243
|
-
: null);
|
|
244
|
-
if (hooksPlan && !hooksPlan.ok) return { changes: [], conflicts: hooksPlan.errors || [] };
|
|
245
|
-
if (hooksPlan?.status !== 'change') return { changes: [], conflicts: [] };
|
|
246
|
-
return { changes: [{ assetId: hooksAssetId(assets), target: hooksPlan.settingsFile, operation: removing ? 'remove' : (hooksPlan.changes[0]?.type ?? 'update'),
|
|
247
|
-
ownershipIdentity: 'gemini:hooks', nativeComponent: 'hooks', nativePlan: hooksPlan, projection: { renderer: 'gemini-hooks' },
|
|
248
|
-
companionTargets: removing ? [] : (hooksPlan.companionTargets ?? []) }], conflicts: [] };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function plan({ scope, scopeRoot, assets = [], mcp = [], discovery, context = {}, ledger, fsImpl = fs } ) {
|
|
252
|
-
const found = discovery || discover({ scope, scopeRoot, context, fsImpl });
|
|
253
|
-
const changes = []; const conflicts = [];
|
|
254
|
-
const removing = context.operation === 'remove';
|
|
255
|
-
if (removing) {
|
|
256
|
-
// Removal only ever targets a section this adapter itself owns — a foreign or absent
|
|
257
|
-
// GEMINI.md yields no change, never a forced deletion of user content.
|
|
258
|
-
const owns = found.instruction !== null && found.instruction.includes(MARKER_START) && found.instruction.includes(MARKER_END);
|
|
259
|
-
if (assets.some((asset ) => asset.id === 'guidance.core') && owns) {
|
|
260
|
-
changes.push({ assetId: 'guidance.core', target: found.paths.instruction, operation: 'remove', ownershipIdentity: 'gemini:instructions', projection: { renderer: 'gemini-instructions' } });
|
|
261
|
-
}
|
|
262
|
-
} else {
|
|
263
|
-
const content = instructionContent({ assets, context, paths: found.paths, fsImpl });
|
|
264
|
-
if (content !== null) {
|
|
265
|
-
const next = managedInstruction(found.instruction, render({ content }));
|
|
266
|
-
if (!next.ok) conflicts.push(next.conflict);
|
|
267
|
-
else if (next.operation !== 'none') changes.push({ assetId: 'guidance.core', target: found.paths.instruction, operation: next.operation, ownershipIdentity: 'gemini:instructions', afterFingerprint: fingerprint(next.content), content: next.content, projection: { renderer: 'gemini-instructions' } });
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const copyTree = planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing, fsImpl });
|
|
271
|
-
changes.push(...copyTree.changes); conflicts.push(...copyTree.conflicts);
|
|
272
|
-
if (found.settings.error) conflicts.push(found.settings.error);
|
|
273
|
-
const hooks = planHooksChange({ removing, found, context, assets, fsImpl });
|
|
274
|
-
changes.push(...hooks.changes); conflicts.push(...hooks.conflicts);
|
|
275
|
-
return {
|
|
276
|
-
changes, conflicts, prerequisites: [], notices: copyTree.notices,
|
|
277
|
-
surfaces: {
|
|
278
|
-
instructions: { status: 'supported', target: found.paths.instruction },
|
|
279
|
-
settings: { status: found.settings.error ? 'invalid' : 'supported', target: found.paths.settings },
|
|
280
|
-
mcp: { status: found.settings.error ? 'blocked' : 'supported', target: found.paths.settings, selected: mcp.map((item ) => item.id) },
|
|
281
|
-
extensions: { status: 'different', mode: found.paths.extensionMode, action: 'use Gemini CLI extension management' },
|
|
282
|
-
policies: policyStatuses(context.policies),
|
|
283
|
-
},
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function atomicWrite(file , content , { fsImpl = fs } = {}) {
|
|
288
|
-
fsImpl.mkdirSync(path.dirname(file), { recursive: true });
|
|
289
|
-
const temp = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${Date.now()}.tmp`);
|
|
290
|
-
try {
|
|
291
|
-
fsImpl.writeFileSync(temp, content, { encoding: 'utf8', flag: 'wx' });
|
|
292
|
-
fsImpl.renameSync(temp, file);
|
|
293
|
-
} finally {
|
|
294
|
-
if (fsImpl.existsSync(temp)) fsImpl.rmSync(temp, { force: true });
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
function apply({ changes = [], fsImpl = fs } ) {
|
|
298
|
-
for (const change of changes) if (change.content !== undefined) atomicWrite(change.target, change.content, { fsImpl });
|
|
299
|
-
const hooksChange = changes.find((change ) => change.nativeComponent === 'hooks');
|
|
300
|
-
if (hooksChange?.nativePlan) deployGeminiHooks(hooksChange.nativePlan, { fsImpl });
|
|
301
|
-
applyCopyTreeAssets(changes, { fsImpl });
|
|
302
|
-
// An update that relocates an asset (the agents folder layout -> flat files) carries the old
|
|
303
|
-
// rows as removals inside the apply batch; the lifecycle calls remove() only for `doflow remove`.
|
|
304
|
-
removeCopyTreeAssets(changes, { fsImpl });
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/** Strip only the DoFlow-managed span, exactly like the Claude adapter's removeManagedSection —
|
|
308
|
-
* a file with user content before/after the managed section must keep that content. Only delete
|
|
309
|
-
* the file outright once nothing but the managed section (and its separator) remains. */
|
|
310
|
-
function removeManagedSection(file , { fsImpl = fs } = {}) {
|
|
311
|
-
if (!fsImpl.existsSync(file)) return false;
|
|
312
|
-
const existing = fsImpl.readFileSync(file, 'utf8');
|
|
313
|
-
const start = existing.indexOf(MARKER_START);
|
|
314
|
-
if (start === -1) return false;
|
|
315
|
-
const end = existing.indexOf(MARKER_END, start + MARKER_START.length);
|
|
316
|
-
if (end === -1 || existing.indexOf(MARKER_START, end + MARKER_END.length) !== -1) {
|
|
317
|
-
throw new Error(`Refusing to remove malformed DoFlow markers in ${file}`);
|
|
318
|
-
}
|
|
319
|
-
let after = end + MARKER_END.length;
|
|
320
|
-
if (existing[after] === '\n') after += 1;
|
|
321
|
-
let next = existing.slice(0, start) + existing.slice(after);
|
|
322
|
-
if (next === '\n') next = '';
|
|
323
|
-
if (next === '') fsImpl.rmSync(file, { force: true });
|
|
324
|
-
else fsImpl.writeFileSync(file, next);
|
|
325
|
-
return true;
|
|
326
|
-
}
|
|
327
|
-
function remove({ changes = [], fsImpl = fs } ) {
|
|
328
|
-
for (const change of changes) if (change.target && change.projection?.renderer === 'gemini-instructions') removeManagedSection(change.target, { fsImpl });
|
|
329
|
-
const hooksChange = changes.find((change ) => change.nativeComponent === 'hooks');
|
|
330
|
-
if (hooksChange?.nativePlan) deployRemoveGeminiHooks(hooksChange.nativePlan, { fsImpl });
|
|
331
|
-
removeCopyTreeAssets(changes, { fsImpl });
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
function verify({ scope, scopeRoot, assets = [], context = {}, fsImpl = fs } ) {
|
|
335
|
-
const found = discover({ scope, scopeRoot, context, fsImpl });
|
|
336
|
-
const resources = [];
|
|
337
|
-
if (assets.some((asset ) => asset.id === 'guidance.core') && found.instruction?.includes(MARKER_START) && found.instruction.includes(MARKER_END)) {
|
|
338
|
-
resources.push({ assetId: 'guidance.core', target: found.paths.instruction, ownershipIdentity: 'gemini:instructions', fingerprint: fingerprint(found.instruction), sourceVersion: context.sourceVersion ?? 'unknown', projection: { renderer: 'gemini-instructions' } });
|
|
339
|
-
}
|
|
340
|
-
const copyTree = verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl });
|
|
341
|
-
resources.push(...copyTree.resources);
|
|
342
|
-
let hooksStatus = null; const conflicts = [...(found.settings.error ? [found.settings.error] : []), ...copyTree.conflicts];
|
|
343
|
-
if (context.geminiHooksSourceFile && !found.settings.error) {
|
|
344
|
-
const hooksPlan = planGeminiHooks({ sourceFile: context.geminiHooksSourceFile, sourceHooksDir: context.geminiHooksSourceDir,
|
|
345
|
-
settingsFile: found.paths.settings, destinationHooksDir: found.paths.hooksDirectory, trusted: context.hooksTrusted, fsImpl });
|
|
346
|
-
hooksStatus = hooksPlan.ok && hooksPlan.status === 'unchanged' ? 'managed' : (hooksPlan.ok ? 'missing' : 'conflict');
|
|
347
|
-
if (!hooksPlan.ok) conflicts.push(...(hooksPlan.errors || []));
|
|
348
|
-
if (hooksStatus === 'managed') {
|
|
349
|
-
resources.push({ assetId: hooksAssetId(assets), target: hooksPlan.settingsFile, ownershipIdentity: 'gemini:hooks',
|
|
350
|
-
fingerprint: fingerprint(hooksPlan.merged.hooks), sourceVersion: context.sourceVersion ?? 'unknown', projection: { renderer: 'gemini-hooks' } });
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return { ok: !found.settings.error && copyTree.conflicts.length === 0 && hooksStatus !== 'conflict', resources,
|
|
354
|
-
statuses: { settings: found.settings.error ? 'invalid' : 'supported', extensions: 'different', policies: policyStatuses(context.policies), copyTree: copyTree.statuses, hooks: hooksStatus },
|
|
355
|
-
conflicts };
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return { nativePaths, discover, render, plan, apply, remove, verify };
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const singleton = createGeminiAdapter();
|
|
362
|
-
|
|
363
|
-
/** Gemini's hooks trust, observed for a lifecycle target. Trust is not a static registry
|
|
364
|
-
* prerequisite the way Codex's `trusted-project`/`hook-review` are: Gemini fingerprints hook
|
|
365
|
-
* name/command and warns before running one that changed, so trust is computed live against the
|
|
366
|
-
* current hooks.json source and the harness's current settings.json. This is the adapter's own
|
|
367
|
-
* API for that observation (review A3 — lifecycle used to import planGeminiHooks and re-derive
|
|
368
|
-
* the plan itself, which put Gemini's hook semantics on the lifecycle side of the boundary).
|
|
369
|
-
* Read-only and side-effect free; returns the trust value or null when unobservable.
|
|
370
|
-
* @param {Object} target a lifecycle status target ({adapterInput, discovery})
|
|
371
|
-
* @returns {*} the plan's trust, or null
|
|
372
|
-
*/
|
|
373
|
-
function hookTrustFor(target ) {
|
|
374
|
-
const context = target.adapterInput?.context || {};
|
|
375
|
-
const settingsFile = target.discovery?.paths?.settings;
|
|
376
|
-
if (!context.geminiHooksSourceFile || !settingsFile || target.discovery?.settings?.error) return null;
|
|
377
|
-
const plan = planGeminiHooks({
|
|
378
|
-
sourceFile: context.geminiHooksSourceFile, sourceHooksDir: context.geminiHooksSourceDir,
|
|
379
|
-
settingsFile, trusted: context.hooksTrusted,
|
|
380
|
-
});
|
|
381
|
-
return plan.ok ? (plan.trust ?? null) : null;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
module.exports = {
|
|
385
|
-
MARKER_START, MARKER_END,
|
|
386
|
-
nativePaths: singleton.nativePaths, discover: singleton.discover, render: singleton.render,
|
|
387
|
-
managedInstruction, plan: singleton.plan, apply: singleton.apply, remove: singleton.remove,
|
|
388
|
-
verify: singleton.verify, planGeminiHooks, hookTrustFor,
|
|
389
|
-
createGeminiAdapter,
|
|
390
|
-
};
|