@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,413 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
// GitHub Copilot CLI adapter.
|
|
6
|
+
//
|
|
7
|
+
// Copilot has no single native root the way Claude's `.claude` is one — instructions, skills,
|
|
8
|
+
// agents, and MCP each live under a different path, split further by scope. Skills and agents are
|
|
9
|
+
// both trees materialised via the shared copy-tree engine in ../copy-tree.ts; the single instruction
|
|
10
|
+
// pointer is a marker-merged section in a shared file, the same shape opencode/pi/gemini already use;
|
|
11
|
+
// MCP servers are entries of one JSON map that DoFlow owns one at a time through ../mcp-entries.ts,
|
|
12
|
+
// never touching an entry it does not own.
|
|
13
|
+
//
|
|
14
|
+
// Native paths (see design.md §4's harness-native-surfaces table):
|
|
15
|
+
// instructions -> <projectRoot>/.github/copilot-instructions.md (project only — Copilot documents
|
|
16
|
+
// no global instructions file, so global scope installs nothing for this asset)
|
|
17
|
+
// skills -> ~/.agents/skills (global) / <projectRoot>/.agents/skills (project)
|
|
18
|
+
// agents -> ~/.copilot/agents (global) / <projectRoot>/.github/agents (project)
|
|
19
|
+
// mcp -> ~/.copilot/mcp-config.json (global) / <projectRoot>/.mcp.json (project)
|
|
20
|
+
//
|
|
21
|
+
// Evidence: https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot,
|
|
22
|
+
// https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills,
|
|
23
|
+
// https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-custom-agents-for-cli,
|
|
24
|
+
// https://docs.github.com/en/copilot/reference/custom-agents-configuration
|
|
25
|
+
const fs = require('node:fs');
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
|
|
28
|
+
const { MARKER_START, MARKER_END } = require('../../helper/marker-merge.ts');
|
|
29
|
+
const { planTree, applyTree, removeTree, verifyTree, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, fingerprint, sourceDirFor, resolveTransform } = require('../copy-tree.ts');
|
|
30
|
+
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.ts');
|
|
31
|
+
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.ts');
|
|
32
|
+
|
|
33
|
+
const HARNESS = 'copilot';
|
|
34
|
+
/** Message text naming the instruction file the declared paths.instruction surface installs.
|
|
35
|
+
* Prose inside conflict messages and a config-payload literal — not an install destination. */
|
|
36
|
+
const INSTRUCTION_FILE = 'copilot-instructions.md';
|
|
37
|
+
const MCP_CONTAINER = 'mcpServers';
|
|
38
|
+
const MCP_RENDERER = 'copilot-mcp';
|
|
39
|
+
// Releases up to 1.18.0 recorded one row for the whole server map, which cannot say which entries
|
|
40
|
+
// DoFlow wrote; every plan releases it, and the entries are adopted per server instead.
|
|
41
|
+
const LEGACY_MCP_REGISTRATION = `${HARNESS}:mcp:registration`;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Native path facts live in core/registry/harnesses.json under this harness's "paths" section and
|
|
45
|
+
* resolve through the shared harness-paths resolver. Unlike Claude/Codex/Kiro, Copilot has no
|
|
46
|
+
* single root: every capability resolves against its own conventional directory.
|
|
47
|
+
* - `skillsConfigDir` is the parent of `skills/` and is identical in shape across scopes
|
|
48
|
+
* (`.agents`, rooted at whichever `root` the scope resolves to) — Copilot's skills discovery
|
|
49
|
+
* list per https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills.
|
|
50
|
+
* - `agentsConfigDir` is genuinely asymmetric: `~/.copilot` globally, `.github` at project scope,
|
|
51
|
+
* because that is where Copilot's own custom-agents documentation places each.
|
|
52
|
+
* - `instruction` is project-only: Copilot documents no global instructions file, so no user-scope
|
|
53
|
+
* rule is declared and it resolves to null rather than inventing a path with no reader.
|
|
54
|
+
* createCopilotAdapter({ declaredPaths }) is the injection point buildAdapterRegistry() uses;
|
|
55
|
+
* module-level exports delegate to a default-configured instance so direct callers keep their
|
|
56
|
+
* historical shape.
|
|
57
|
+
*/
|
|
58
|
+
function createCopilotAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS] } = {}) {
|
|
59
|
+
// Parity note: Copilot's historical nativePaths() derived even its user-scope root from scopeRoot
|
|
60
|
+
// (the CLI passes $HOME there for -g installs), never from a separate homeDir argument — so the
|
|
61
|
+
// resolver is fed no homeDir and "root" keeps resolving exactly as before.
|
|
62
|
+
function nativePaths({ scope, scopeRoot }: any = {}) {
|
|
63
|
+
return resolveHarnessPaths(declaredPaths, { scope, scopeRoot });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Discovery keeps the MCP files as plan read them (`mcpSnapshot`), which verify compares against,
|
|
67
|
+
* and reports the servers DoFlow owns in Copilot's MCP config now (`mcpOwned`). */
|
|
68
|
+
function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, fsImpl = fs }: any) {
|
|
69
|
+
const paths = nativePaths({ scope, scopeRoot });
|
|
70
|
+
const instruction = paths.instruction && fsImpl.existsSync(paths.instruction) ? fsImpl.readFileSync(paths.instruction, 'utf8') : null;
|
|
71
|
+
const entries = mcpEntriesInput({ paths, mcp, mcpAdoptable, ledger });
|
|
72
|
+
const mcpSnapshot = readMcpFiles({ file: entries.file, ownRows: entries.ownRows, container: MCP_CONTAINER, fsImpl });
|
|
73
|
+
const read = mcpSnapshot[entries.file];
|
|
74
|
+
// `null` while the file is absent, unreadable or has no server map; every name in it otherwise, whoever wrote it.
|
|
75
|
+
const mcpConfigured = read?.ok && read.servers ? Object.keys(read.servers).sort() : null;
|
|
76
|
+
return { paths, instruction, mcpSnapshot, mcpOwned: ownedMcpIds({ ...entries, files: mcpSnapshot }), mcpConfigured };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function render({ content = '' }: any = {}) {
|
|
80
|
+
return `${MARKER_START}\n${String(content).trimEnd()}\n${MARKER_END}\n`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Replace only the span between DoFlow's markers. A copilot-instructions.md that exists with no
|
|
84
|
+
* DoFlow section is refused rather than appended to — the same policy opencode/pi/gemini apply to
|
|
85
|
+
* their own shared instruction files, and for the same reason: where DoFlow's content belongs in a
|
|
86
|
+
* file it doesn't fully own is a decision for the file's owner, not a guess for the installer. Add
|
|
87
|
+
* an empty marker pair to opt in. */
|
|
88
|
+
function managedInstruction(existing: any, rendered: any) {
|
|
89
|
+
if (existing === null) return { ok: true, operation: 'create', content: rendered };
|
|
90
|
+
const start = existing.indexOf(MARKER_START);
|
|
91
|
+
const end = existing.indexOf(MARKER_END);
|
|
92
|
+
if (start === -1 && end === -1) return { ok: false, conflict: `${INSTRUCTION_FILE} exists without a DoFlow managed section` };
|
|
93
|
+
if (start === -1 || end === -1 || end < start) return { ok: false, conflict: `${INSTRUCTION_FILE} has malformed DoFlow managed-section markers` };
|
|
94
|
+
const content = `${existing.slice(0, start)}${rendered}${existing.slice(end + MARKER_END.length).replace(/^\n?/, '')}`;
|
|
95
|
+
return { ok: true, operation: content === existing ? 'none' : 'merge', content };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Strip DoFlow's span, leaving the rest of a shared copilot-instructions.md intact. Returns null
|
|
99
|
+
* when there is nothing to do, so plan() can skip the change entirely. */
|
|
100
|
+
function strippedInstruction(existing: any) {
|
|
101
|
+
if (typeof existing !== 'string') return null;
|
|
102
|
+
const start = existing.indexOf(MARKER_START);
|
|
103
|
+
const end = existing.indexOf(MARKER_END);
|
|
104
|
+
if (start === -1 || end === -1 || end < start) return null;
|
|
105
|
+
let after = end + MARKER_END.length;
|
|
106
|
+
if (existing[after] === '\n') after += 1;
|
|
107
|
+
return `${existing.slice(0, start)}${existing.slice(after)}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Plan the single instructions change (or none). Global scope always yields no change and no
|
|
111
|
+
* conflict — Copilot documents no global instructions file, so there is nothing to skip *to*,
|
|
112
|
+
* mirroring how other adapters skip a capability with no native equivalent for a given scope. */
|
|
113
|
+
function planInstructionsChange({ assets, found, context, removing, fsImpl }: any) {
|
|
114
|
+
if (!found.paths.instruction) return { changes: [], conflicts: [] };
|
|
115
|
+
// The marker-managed instruction file is one specific asset: exclude tree-projected rule
|
|
116
|
+
// assets (copilot-rule-instructions), whose `source` is a directory, not a file.
|
|
117
|
+
const guidance = assets.find((asset: any) => asset.capability === 'instructions' && asset.renderer !== 'copilot-rule-instructions');
|
|
118
|
+
if (!guidance) return { changes: [], conflicts: [] };
|
|
119
|
+
const outcome = removing
|
|
120
|
+
? { ok: true, operation: 'remove', content: strippedInstruction(found.instruction) }
|
|
121
|
+
: managedInstruction(found.instruction, render({ content: fsImpl.readFileSync(path.resolve(context.repoRoot, guidance.source), 'utf8') }));
|
|
122
|
+
if (!outcome.ok) return { changes: [], conflicts: [outcome.conflict] };
|
|
123
|
+
if (outcome.operation === 'none' || outcome.content === null) return { changes: [], conflicts: [] };
|
|
124
|
+
return {
|
|
125
|
+
changes: [{
|
|
126
|
+
assetId: guidance.id, target: found.paths.instruction, operation: outcome.operation,
|
|
127
|
+
content: outcome.content, ownershipIdentity: `${HARNESS}:instructions:managed-section`,
|
|
128
|
+
fingerprint: fingerprint(outcome.content), harness: HARNESS, projection: { renderer: 'copilot-instructions' },
|
|
129
|
+
}],
|
|
130
|
+
conflicts: [],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---- copy-tree assets (skills, agents) ----
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Rename `<name>.md` to `<name>.agent.md` on the way out. Copilot's custom-agent reference
|
|
138
|
+
* (https://docs.github.com/en/copilot/reference/custom-agents-configuration) requires the
|
|
139
|
+
* `.agent.md` extension, while `core/shared/agent-specs/*.md` — already `name`/`description`
|
|
140
|
+
* YAML-frontmatter files, the same shape `.agent.md` expects — carries a plain `.md` extension.
|
|
141
|
+
* This is the same class of shape mismatch Gemini/Antigravity's `dir-per-file:agent.md` layout in
|
|
142
|
+
* copy-tree.ts already solves for a directory-per-agent requirement; here the mismatch is only the
|
|
143
|
+
* extension, so a flat rename is enough and no directory restructuring is needed. Declared as a
|
|
144
|
+
* function (rather than a name registered in copy-tree.ts's LAYOUTS) because it is specific to this
|
|
145
|
+
* one adapter's asset, not a shape another harness also needs. Format logic, not a path fact —
|
|
146
|
+
* it stays code rather than moving into the registry's path declarations.
|
|
147
|
+
*/
|
|
148
|
+
function agentFileLayout(sourceRel: any) {
|
|
149
|
+
const ext = path.extname(sourceRel);
|
|
150
|
+
const base = sourceRel.slice(0, sourceRel.length - ext.length);
|
|
151
|
+
return `${base}.agent${ext || '.md'}`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function planTreeAssets({ assets, renderer, destRoot, scopeRoot, layout, context, ledger, removing, fsImpl = fs }: any) {
|
|
155
|
+
const changes = [];
|
|
156
|
+
const conflicts = [];
|
|
157
|
+
const treeResults = [];
|
|
158
|
+
const notices = [];
|
|
159
|
+
for (const asset of treeAssetsFor(assets, renderer)) {
|
|
160
|
+
const destDir = copyTreeDestDir(destRoot, asset);
|
|
161
|
+
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Copilot');
|
|
162
|
+
const previousResources = ledgerFileResources(ledger?.resources, HARNESS, asset.id);
|
|
163
|
+
const result = planTree({ sourceDir, destDir, previousResources, siblingFingerprints: ledgerSiblingFingerprints(ledger?.resources, HARNESS), operation: removing ? 'remove' : 'apply', fsImpl, layout: layout || asset.layout, transform: asset.transform, keepModified: !removing,
|
|
164
|
+
// Forwarded so the CLI's --force reaches planTree's conflict check; omitting it let
|
|
165
|
+
// planTree's own `force = false` default stand in silently. Gated on `!removing` for the
|
|
166
|
+
// reason codex/index.ts states in full: force heals drift on apply, but a hand-edited file
|
|
167
|
+
// is never deleted on removal, forced or not.
|
|
168
|
+
force: !removing && context?.force === true, });
|
|
169
|
+
treeResults.push(result);
|
|
170
|
+
conflicts.push(...result.conflicts.map((reason: any) => `${asset.id}: ${reason}`));
|
|
171
|
+
// A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
|
|
172
|
+
// ownership row is released.
|
|
173
|
+
notices.push(...result.kept.map((item: any) => `kept hand-edited ${path.relative(scopeRoot, item.target)}; DoFlow no longer manages it`));
|
|
174
|
+
for (const change of result.changes) {
|
|
175
|
+
changes.push({
|
|
176
|
+
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
177
|
+
ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${change.relPath}`,
|
|
178
|
+
kind: 'copy-tree-file', identity: change.relPath,
|
|
179
|
+
afterFingerprint: change.fingerprint, fingerprint: change.fingerprint, sourceVersion: 'registry-v1',
|
|
180
|
+
transformName: asset.transform || null,
|
|
181
|
+
...(change.kept ? { retained: true, retainedFor: [] } : {}),
|
|
182
|
+
projection: { renderer: 'copy-tree' },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return { changes, conflicts, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function applyCopyTreeAssets(changes: any, { fsImpl = fs }: any = {}) {
|
|
190
|
+
let applied = 0;
|
|
191
|
+
const grouped = new Map();
|
|
192
|
+
for (const change of changes) {
|
|
193
|
+
if (change.projection?.renderer !== 'copy-tree' || change.operation === 'remove') continue;
|
|
194
|
+
const key = change.transformName || null;
|
|
195
|
+
if (!grouped.has(key)) grouped.set(key, []);
|
|
196
|
+
grouped.get(key).push({ relPath: change.identity, target: change.target, source: change.source, operation: change.operation, fingerprint: change.fingerprint });
|
|
197
|
+
}
|
|
198
|
+
for (const [transformName, treeChanges] of grouped) {
|
|
199
|
+
applied += applyTree({ changes: treeChanges, fsImpl, transform: resolveTransform(transformName) }).applied;
|
|
200
|
+
}
|
|
201
|
+
return applied;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function removeCopyTreeAssets(changes: any, { fsImpl = fs }: any = {}) {
|
|
205
|
+
const treeChanges = changes.filter((change: any) => change.projection?.renderer === 'copy-tree' && change.operation === 'remove' && !change.retained)
|
|
206
|
+
.map((change: any) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
|
|
207
|
+
return removeTree({ changes: treeChanges, fsImpl }).removed;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function verifyTreeAssets({ assets, renderer, destRoot, layout, context, fsImpl = fs }: any) {
|
|
211
|
+
const statuses = [];
|
|
212
|
+
const resources = [];
|
|
213
|
+
const conflicts = [];
|
|
214
|
+
for (const asset of treeAssetsFor(assets, renderer)) {
|
|
215
|
+
const destDir = copyTreeDestDir(destRoot, asset);
|
|
216
|
+
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Copilot');
|
|
217
|
+
const result = verifyTree({ sourceDir, destDir, fsImpl, layout: layout || asset.layout, transform: asset.transform, plannedWrites: context?.plannedWrites });
|
|
218
|
+
conflicts.push(...result.conflicts.map((reason: any) => `${asset.id}: ${reason}`));
|
|
219
|
+
for (const resource of result.resources) {
|
|
220
|
+
resources.push({
|
|
221
|
+
assetId: asset.id, target: resource.target, ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${resource.relPath}`,
|
|
222
|
+
kind: 'copy-tree-file', identity: resource.relPath,
|
|
223
|
+
fingerprint: resource.fingerprint, sourceVersion: 'registry-v1',
|
|
224
|
+
projection: { renderer: 'copy-tree' },
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
statuses.push({ harness: HARNESS, assetId: asset.id, capability: asset.capability, status: result.ok ? 'managed' : 'conflict', target: destDir });
|
|
228
|
+
}
|
|
229
|
+
return { statuses, resources, conflicts };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ---- mcp (.mcp.json project / ~/.copilot/mcp-config.json global) ----
|
|
233
|
+
|
|
234
|
+
/** Copilot's own per-server shape. The file may be shared with another tool (Claude Code reads the
|
|
235
|
+
* same project `.mcp.json`), so DoFlow only ever writes the entries it owns. */
|
|
236
|
+
function buildServerEntry(server: any) {
|
|
237
|
+
return {
|
|
238
|
+
command: server.command,
|
|
239
|
+
...(server.args?.length ? { args: [...server.args] } : {}),
|
|
240
|
+
...(server.env && Object.keys(server.env).length ? { env: { ...server.env } } : {}),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function ownershipIdentity(id: any) { return `doflow:${HARNESS}:mcp-server:${id}`; }
|
|
245
|
+
|
|
246
|
+
/** Everything the shared entry-ownership rules (../mcp-entries.ts) need from this adapter. */
|
|
247
|
+
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], ledger, assets = [] }: any) {
|
|
248
|
+
const rendered = (servers: any) => servers.map((server: any) => ({ id: server.id, entry: buildServerEntry(server) }));
|
|
249
|
+
const rows = (ledger?.resources || []).filter((row: any) => row.kind === 'mcp-server');
|
|
250
|
+
return {
|
|
251
|
+
file: paths.mcp, selected: rendered(mcp), adoptable: rendered(mcpAdoptable),
|
|
252
|
+
ownRows: rows.filter((row: any) => row.harness === HARNESS).map((row: any) => ({
|
|
253
|
+
identity: row.identity, target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: row.ownershipIdentity, legacy: false,
|
|
254
|
+
})),
|
|
255
|
+
foreignRows: rows.filter((row: any) => row.harness !== HARNESS).map((row: any) => ({ harness: row.harness, identity: row.identity, target: row.target })),
|
|
256
|
+
identityFor: ownershipIdentity, assetId: pseudoAssetId(assets), renderer: MCP_RENDERER, label: 'Copilot MCP',
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** The release of the 1.18.0 whole-map row, under the asset id it was recorded with so the ledger
|
|
261
|
+
* drops exactly that row. The file is not touched. */
|
|
262
|
+
function legacyRegistrationReleases(ledger: any) {
|
|
263
|
+
return (ledger?.resources || []).filter((row: any) => row.harness === HARNESS && row.ownershipIdentity === LEGACY_MCP_REGISTRATION)
|
|
264
|
+
.map((row: any) => ({ assetId: row.assetId, target: row.target, operation: 'remove', release: true,
|
|
265
|
+
ownershipIdentity: row.ownershipIdentity, harness: HARNESS, projection: { renderer: MCP_RENDERER } }));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Copilot's MCP entry changes have no asset of their own in core/registry/assets.json (they are a
|
|
269
|
+
* registration side-effect of the selected MCP servers, not a projected asset), so they piggyback
|
|
270
|
+
* on a real asset id already routed to this harness — the same "pseudo-component" technique
|
|
271
|
+
* src/adapters/gemini/index.ts#hooksAssetId and src/adapters/kiro/index.ts#pseudoAssetId use. The
|
|
272
|
+
* lifecycle layer validates every change's assetId against the harness's actual asset list, so an
|
|
273
|
+
* invented id like a literal 'copilot.mcp' string is rejected as unknown. */
|
|
274
|
+
function pseudoAssetId(assets: any) {
|
|
275
|
+
return assets.find((asset: any) => asset.capability === 'instructions')?.id ?? assets[0]?.id;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ---- shared adapter contract ----
|
|
279
|
+
|
|
280
|
+
function plan({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, context = {}, ledger, fsImpl = fs }: any) {
|
|
281
|
+
const found = discovery || discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, fsImpl });
|
|
282
|
+
const changes = [];
|
|
283
|
+
const conflicts = [];
|
|
284
|
+
const removing = context.operation === 'remove';
|
|
285
|
+
|
|
286
|
+
const instructions = planInstructionsChange({ assets, found, context, removing, fsImpl });
|
|
287
|
+
changes.push(...instructions.changes);
|
|
288
|
+
conflicts.push(...instructions.conflicts);
|
|
289
|
+
|
|
290
|
+
const skills = planTreeAssets({ assets, renderer: 'copy-tree', scopeRoot, destRoot: found.paths.skillsConfigDir, layout: null, context, ledger, removing, fsImpl });
|
|
291
|
+
changes.push(...skills.changes);
|
|
292
|
+
conflicts.push(...skills.conflicts);
|
|
293
|
+
|
|
294
|
+
const agents = planTreeAssets({ assets, renderer: 'copilot-agents', scopeRoot, destRoot: found.paths.agentsConfigDir, layout: agentFileLayout, context, ledger, removing, fsImpl });
|
|
295
|
+
changes.push(...agents.changes);
|
|
296
|
+
conflicts.push(...agents.conflicts);
|
|
297
|
+
|
|
298
|
+
const rules = planTreeAssets({ assets, renderer: 'copilot-rule-instructions', scopeRoot, destRoot: found.paths.ruleInstructionsConfigDir, context, ledger, removing, fsImpl });
|
|
299
|
+
changes.push(...rules.changes);
|
|
300
|
+
conflicts.push(...rules.conflicts);
|
|
301
|
+
|
|
302
|
+
const mcpPlan = planMcpEntries({
|
|
303
|
+
...mcpEntriesInput({ paths: found.paths, mcp, mcpAdoptable, ledger, assets }), files: found.mcpSnapshot, removing,
|
|
304
|
+
});
|
|
305
|
+
changes.push(...legacyRegistrationReleases(ledger), ...mcpPlan.changes);
|
|
306
|
+
conflicts.push(...mcpPlan.conflicts);
|
|
307
|
+
|
|
308
|
+
return { changes, conflicts, notices: [...skills.notices, ...agents.notices, ...rules.notices, ...mcpPlan.notices], paths: found.paths };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function writeChange(change: any, fsImpl: any) {
|
|
312
|
+
fsImpl.mkdirSync(path.dirname(change.target), { recursive: true });
|
|
313
|
+
fsImpl.writeFileSync(change.target, change.content, 'utf8');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function apply({ changes = [], fsImpl = fs }: any) {
|
|
317
|
+
let applied = 0;
|
|
318
|
+
for (const change of changes) {
|
|
319
|
+
if (change.operation === 'remove') continue;
|
|
320
|
+
if (change.projection?.renderer === 'copy-tree' || change.kind === 'mcp-server') continue;
|
|
321
|
+
writeChange(change, fsImpl);
|
|
322
|
+
applied += 1;
|
|
323
|
+
}
|
|
324
|
+
applied += writeMcpEntries(changes, { container: MCP_CONTAINER, fsImpl });
|
|
325
|
+
applied += applyCopyTreeAssets(changes, { fsImpl });
|
|
326
|
+
// An update that drops a copy-tree asset carries its rows as removals inside the apply batch;
|
|
327
|
+
// the lifecycle calls remove() only for `doflow remove`.
|
|
328
|
+
removeCopyTreeAssets(changes, { fsImpl });
|
|
329
|
+
return { applied };
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function remove({ changes = [], fsImpl = fs }: any) {
|
|
333
|
+
let removed = 0;
|
|
334
|
+
for (const change of changes) {
|
|
335
|
+
if (change.operation !== 'remove') continue;
|
|
336
|
+
if (change.projection?.renderer === 'copy-tree' || change.kind === 'mcp-server') continue;
|
|
337
|
+
if (typeof change.content !== 'string') continue;
|
|
338
|
+
writeChange(change, fsImpl);
|
|
339
|
+
removed += 1;
|
|
340
|
+
}
|
|
341
|
+
removed += writeMcpEntries(changes, { container: MCP_CONTAINER, fsImpl });
|
|
342
|
+
removed += removeCopyTreeAssets(changes, { fsImpl });
|
|
343
|
+
return { removed };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function verify({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {}, fsImpl = fs }: any) {
|
|
347
|
+
const found = discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, fsImpl });
|
|
348
|
+
const statuses = [];
|
|
349
|
+
const resources = [];
|
|
350
|
+
const conflicts = [];
|
|
351
|
+
|
|
352
|
+
if (found.paths.instruction) {
|
|
353
|
+
// The marker-managed instruction file is one specific asset: exclude tree-projected rule
|
|
354
|
+
// assets (copilot-rule-instructions), whose `source` is a directory, not a file.
|
|
355
|
+
const guidance = assets.find((asset: any) => asset.capability === 'instructions' && asset.renderer !== 'copilot-rule-instructions');
|
|
356
|
+
const hasSection = typeof found.instruction === 'string' && found.instruction.includes(MARKER_START) && found.instruction.includes(MARKER_END);
|
|
357
|
+
const assetId = guidance?.id ?? 'guidance.codex-pointer';
|
|
358
|
+
statuses.push({ harness: HARNESS, assetId, capability: 'instructions',
|
|
359
|
+
status: hasSection ? 'managed' : 'absent', target: found.paths.instruction,
|
|
360
|
+
ownershipIdentity: `${HARNESS}:instructions:managed-section` });
|
|
361
|
+
if (hasSection) {
|
|
362
|
+
resources.push({ assetId, target: found.paths.instruction,
|
|
363
|
+
ownershipIdentity: `${HARNESS}:instructions:managed-section`, fingerprint: fingerprint(found.instruction),
|
|
364
|
+
sourceVersion: context.sourceVersion ?? 'unknown', projection: { renderer: 'copilot-instructions' } });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const skills = verifyTreeAssets({ assets, renderer: 'copy-tree', destRoot: found.paths.skillsConfigDir, layout: null, context, fsImpl });
|
|
369
|
+
resources.push(...skills.resources);
|
|
370
|
+
statuses.push(...skills.statuses);
|
|
371
|
+
conflicts.push(...skills.conflicts);
|
|
372
|
+
|
|
373
|
+
const agents = verifyTreeAssets({ assets, renderer: 'copilot-agents', destRoot: found.paths.agentsConfigDir, layout: agentFileLayout, context, fsImpl });
|
|
374
|
+
resources.push(...agents.resources);
|
|
375
|
+
statuses.push(...agents.statuses);
|
|
376
|
+
conflicts.push(...agents.conflicts);
|
|
377
|
+
|
|
378
|
+
const rules = verifyTreeAssets({ assets, renderer: 'copilot-rule-instructions', destRoot: found.paths.ruleInstructionsConfigDir, context, fsImpl });
|
|
379
|
+
resources.push(...rules.resources);
|
|
380
|
+
statuses.push(...rules.statuses);
|
|
381
|
+
conflicts.push(...rules.conflicts);
|
|
382
|
+
|
|
383
|
+
const mcpResult = verifyMcpEntries({
|
|
384
|
+
...mcpEntriesInput({ paths: found.paths, mcp, mcpAdoptable, ledger, assets }), files: found.mcpSnapshot,
|
|
385
|
+
snapshot: discovery?.mcpSnapshot ?? found.mcpSnapshot, removing: (operation ?? context.operation) === 'remove',
|
|
386
|
+
harness: HARNESS, sourceVersion: context.sourceVersion ?? 'unknown',
|
|
387
|
+
});
|
|
388
|
+
resources.push(...mcpResult.resources);
|
|
389
|
+
statuses.push(...mcpResult.statuses);
|
|
390
|
+
conflicts.push(...mcpResult.conflicts);
|
|
391
|
+
|
|
392
|
+
return { ok: conflicts.length === 0 && !statuses.some((s) => s.status === 'invalid' || s.status === 'conflict'), resources, statuses, conflicts };
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return { nativePaths, discover, render, plan, apply, remove, verify,
|
|
396
|
+
managedInstruction, strippedInstruction,
|
|
397
|
+
agentFileLayout };
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function treeAssetsFor(assets: any, renderer: any) {
|
|
401
|
+
return (assets || []).filter((asset: any) => asset?.renderer === renderer);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const singleton = createCopilotAdapter();
|
|
405
|
+
|
|
406
|
+
module.exports = {
|
|
407
|
+
HARNESS, MARKER_START, MARKER_END,
|
|
408
|
+
nativePaths: singleton.nativePaths, discover: singleton.discover, render: singleton.render,
|
|
409
|
+
plan: singleton.plan, apply: singleton.apply, remove: singleton.remove, verify: singleton.verify,
|
|
410
|
+
managedInstruction: singleton.managedInstruction, strippedInstruction: singleton.strippedInstruction,
|
|
411
|
+
agentFileLayout: singleton.agentFileLayout,
|
|
412
|
+
createCopilotAdapter,
|
|
413
|
+
};
|