@khoavu882/doflow 0.0.0-stage → 2.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/bin/doflow.js +44 -0
- package/core/.antigravity-plugin/hooks.json +39 -0
- package/core/.antigravity-plugin/mcp_config.json +18 -0
- package/core/.antigravity-plugin/plugin.json +31 -0
- package/core/.claude-plugin/marketplace.json +20 -0
- package/core/.claude-plugin/plugin.json +21 -0
- package/core/.codex-plugin/marketplace.json +20 -0
- package/core/.codex-plugin/plugin.json +35 -0
- package/core/.plugin/plugin.json +19 -0
- package/core/harnesses/antigravity/hooks/pre-implementation-gate.sh +9 -0
- package/core/harnesses/antigravity/hooks/stop-check.sh +10 -0
- package/core/harnesses/claude/hooks/lib.sh +304 -0
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +20 -0
- package/core/harnesses/claude/hooks/permission-audit.sh +47 -0
- package/core/harnesses/claude/hooks/post-compact.sh +74 -0
- package/core/harnesses/claude/hooks/post-edit-lint.sh +36 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +47 -0
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +20 -0
- package/core/harnesses/claude/hooks/pre-compact.sh +43 -0
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +21 -0
- package/core/harnesses/claude/hooks/session-end.sh +89 -0
- package/core/harnesses/claude/hooks/session-start.sh +5 -0
- package/core/harnesses/claude/hooks/skill-config-audit.sh +39 -0
- package/core/harnesses/claude/hooks/stop-check.sh +5 -0
- package/core/harnesses/claude/hooks/subagent-audit.sh +7 -0
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -0
- package/core/harnesses/claude/settings/keybindings.json +20 -0
- package/core/harnesses/claude/settings/settings.json +201 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +49 -0
- package/core/harnesses/codex/agents/core-implementer.toml +7 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +8 -0
- package/core/harnesses/codex/agents/research-writer.toml +8 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +8 -0
- package/core/harnesses/codex/agents/system-architect.toml +9 -0
- package/core/harnesses/codex/config/config.toml +10 -0
- package/core/harnesses/codex/hooks/hooks.json +122 -0
- package/core/harnesses/codex/hooks/lib.sh +335 -0
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +18 -0
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +52 -0
- package/core/harnesses/codex/hooks/post-edit-lint.sh +6 -0
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +18 -0
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +46 -0
- package/core/harnesses/codex/hooks/pre-compact.sh +9 -0
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +19 -0
- package/core/harnesses/codex/hooks/session-end.impl.sh +92 -0
- package/core/harnesses/codex/hooks/session-end.sh +5 -0
- package/core/harnesses/codex/hooks/session-start.sh +5 -0
- package/core/harnesses/codex/hooks/stop-check.sh +8 -0
- package/core/harnesses/codex/hooks/subagent-audit.sh +8 -0
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +6 -0
- package/core/harnesses/gemini/hooks/hooks.json +77 -0
- package/core/harnesses/gemini/hooks/lib.sh +302 -0
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +21 -0
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +39 -0
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +21 -0
- package/core/harnesses/gemini/hooks/pre-compact.sh +38 -0
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +22 -0
- package/core/harnesses/gemini/hooks/session-end.impl.sh +89 -0
- package/core/harnesses/gemini/hooks/session-end.sh +5 -0
- package/core/harnesses/gemini/hooks/session-start.sh +5 -0
- package/core/harnesses/gemini/settings/adapter-defaults.json +4 -0
- package/core/harnesses/kiro/agents/doflow.json +58 -0
- package/core/harnesses/kiro/hooks/doflow.json +53 -0
- package/core/harnesses/kiro/hooks/lib.sh +324 -0
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +9 -0
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +9 -0
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +9 -0
- package/core/harnesses/kiro/hooks/session-start.sh +9 -0
- package/core/harnesses/kiro/hooks/stop-check.sh +43 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +39 -0
- package/core/harnesses/shared/hooks/adapters/antigravity.js +111 -0
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +19 -0
- package/core/harnesses/shared/hooks/adapters/gemini.js +114 -0
- package/core/harnesses/shared/hooks/hooks.json +47 -0
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +91 -0
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +97 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +29 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +501 -0
- package/core/harnesses/shared/hooks/policies/mcp-policy.conf +21 -0
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +91 -0
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +328 -0
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +496 -0
- package/core/harnesses/shared/hooks/policies/prompt-nudge.jq +131 -0
- package/core/harnesses/shared/hooks/policies/session-context.sh +141 -0
- package/core/harnesses/shared/hooks/policies/stop-check.sh +264 -0
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +46 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +235 -0
- package/core/harnesses/shared/hooks/stream-hook-runner.js +590 -0
- package/core/harnesses/shared/locator/doflow-run +87 -0
- package/core/registry/advice.json +101 -0
- package/core/registry/assets.json +792 -0
- package/core/registry/capabilities.json +120 -0
- package/core/registry/contracts.json +189 -0
- package/core/registry/external-tools.json +191 -0
- package/core/registry/harnesses.json +2062 -0
- package/core/registry/lifecycle.json +231 -0
- package/core/registry/mcp.json +18 -0
- package/core/registry/models.json +79 -0
- package/core/registry/readiness-templates.json +118 -0
- package/core/registry/routes.json +47 -0
- package/core/registry/storage.json +1061 -0
- package/core/registry/verification.json +258 -0
- package/core/registry/workflows.json +790 -0
- package/core/shared/agent-specs/core-implementer.md +73 -0
- package/core/shared/agent-specs/quality-guardian.md +28 -0
- package/core/shared/agent-specs/research-writer.md +31 -0
- package/core/shared/agent-specs/spec-analyst.md +33 -0
- package/core/shared/agent-specs/system-architect.md +29 -0
- package/core/shared/guidance/DOFLOW_CORE.md +8 -0
- package/core/shared/guidance/FLAGS.md +25 -0
- package/core/shared/guidance/PRINCIPLES.md +61 -0
- package/core/shared/guidance/VERSION +1 -0
- package/core/shared/guidance/mcp/MCP_Context7.md +18 -0
- package/core/shared/guidance/mcp/MCP_Sequential.md +17 -0
- package/core/shared/guidance/modes/MODE_Brainstorming.md +46 -0
- package/core/shared/guidance/modes/MODE_DeepResearch.md +69 -0
- package/core/shared/guidance/modes/MODE_Introspection.md +33 -0
- package/core/shared/guidance/modes/MODE_Orchestration.md +57 -0
- package/core/shared/guidance/modes/MODE_Task_Management.md +74 -0
- package/core/shared/guidance/pointers/claude-gemini.md +2 -0
- package/core/shared/guidance/pointers/codex.md +6 -0
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +373 -0
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +104 -0
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +47 -0
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +161 -0
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +87 -0
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +93 -0
- package/core/shared/guidance/references/MODEL_SELECTION.md +74 -0
- package/core/shared/guidance/references/ORCHESTRATION.md +36 -0
- package/core/shared/guidance/references/RESEARCH_CONFIG.md +21 -0
- package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +81 -0
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +25 -0
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +23 -0
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +14 -0
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +46 -0
- package/core/shared/scripts/doflow/assets/mermaid-theme.json +46 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +167 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +546 -0
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +208 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +347 -0
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +66 -0
- package/core/shared/scripts/doflow/bash/do-review-package.sh +127 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +698 -0
- package/core/shared/scripts/doflow/bash/render-audit.sh +224 -0
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +177 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +223 -0
- package/core/shared/scripts/doflow/bash/sync-context.sh +66 -0
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +526 -0
- package/core/shared/scripts/doflow/bin/doflow-run +592 -0
- package/core/shared/skills/do/SKILL.md +128 -0
- package/core/shared/skills/do/references/estimation.md +13 -0
- package/core/shared/skills/do/references/pm_routing.md +25 -0
- package/core/shared/skills/do/references/tool_matrix.md +52 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +252 -0
- package/core/shared/skills/do-code-review/README.md +49 -0
- package/core/shared/skills/do-code-review/SKILL.md +333 -0
- package/core/shared/skills/do-code-review/assets/sample_c_clean.c +71 -0
- package/core/shared/skills/do-code-review/assets/sample_c_smells.c +66 -0
- package/core/shared/skills/do-code-review/assets/sample_cpp_shift.cpp +19 -0
- package/core/shared/skills/do-code-review/assets/sample_csharp_clean.cs +100 -0
- package/core/shared/skills/do-code-review/assets/sample_csharp_smells.cs +78 -0
- package/core/shared/skills/do-code-review/assets/sample_java_clean.java +55 -0
- package/core/shared/skills/do-code-review/assets/sample_java_smells.java +56 -0
- package/core/shared/skills/do-code-review/assets/sample_json_clean.json +7 -0
- package/core/shared/skills/do-code-review/assets/sample_markdown_clean.md +30 -0
- package/core/shared/skills/do-code-review/assets/sample_markdown_smells.md +29 -0
- package/core/shared/skills/do-code-review/assets/sample_shell_heredoc.sh +38 -0
- package/core/shared/skills/do-code-review/assets/sample_shell_smells.sh +15 -0
- package/core/shared/skills/do-code-review/assets/sample_typescript_strings.ts +36 -0
- package/core/shared/skills/do-code-review/assets/sample_yaml_smells.yaml +6 -0
- package/core/shared/skills/do-code-review/content-types/config.md +83 -0
- package/core/shared/skills/do-code-review/content-types/markdown.md +132 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_c_clean_quality.json +79 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_c_smells_quality.json +169 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_cpp_shift_quality.json +49 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_clean_quality.json +149 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_smells_quality.json +157 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_java_clean_quality.json +67 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_java_smells_quality.json +97 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_json_clean_quality.json +33 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_clean_quality.json +1 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_smells_quality.json +16 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_shell_heredoc_quality.json +54 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_shell_smells_quality.json +91 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_typescript_strings_quality.json +60 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_yaml_smells_quality.json +46 -0
- package/core/shared/skills/do-code-review/languages/c.md +103 -0
- package/core/shared/skills/do-code-review/languages/cpp.md +103 -0
- package/core/shared/skills/do-code-review/languages/csharp.md +97 -0
- package/core/shared/skills/do-code-review/languages/dart.md +108 -0
- package/core/shared/skills/do-code-review/languages/go.md +92 -0
- package/core/shared/skills/do-code-review/languages/java.md +103 -0
- package/core/shared/skills/do-code-review/languages/kotlin.md +88 -0
- package/core/shared/skills/do-code-review/languages/php.md +109 -0
- package/core/shared/skills/do-code-review/languages/python.md +94 -0
- package/core/shared/skills/do-code-review/languages/ruby.md +105 -0
- package/core/shared/skills/do-code-review/languages/rust.md +99 -0
- package/core/shared/skills/do-code-review/languages/shell.md +90 -0
- package/core/shared/skills/do-code-review/languages/swift.md +88 -0
- package/core/shared/skills/do-code-review/languages/typescript.md +97 -0
- package/core/shared/skills/do-code-review/review-policy.json +47 -0
- package/core/shared/skills/do-code-review/rules/universal.md +49 -0
- package/core/shared/skills/do-code-review/scripts/code_quality_checker.py +1696 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +532 -0
- package/core/shared/skills/do-code-review/scripts/pr_analyzer.py +620 -0
- package/core/shared/skills/do-code-review/scripts/review_report_generator.py +505 -0
- package/core/shared/skills/do-constitution/SKILL.md +72 -0
- package/core/shared/skills/do-design/SKILL.md +212 -0
- package/core/shared/skills/do-diagnose/SKILL.md +156 -0
- package/core/shared/skills/do-diagnose/references/code_audit.md +15 -0
- package/core/shared/skills/do-diagnose/references/refactoring.md +12 -0
- package/core/shared/skills/do-diagnose/references/root_cause.md +17 -0
- package/core/shared/skills/do-document/SKILL.md +81 -0
- package/core/shared/skills/do-document/references/api-reference.md +42 -0
- package/core/shared/skills/do-document/references/deep_research.md +18 -0
- package/core/shared/skills/do-document/references/embedded-research.md +11 -0
- package/core/shared/skills/do-document/references/implementation-flow.md +105 -0
- package/core/shared/skills/do-document/references/index_generator.md +9 -0
- package/core/shared/skills/do-document/references/user-guide.md +22 -0
- package/core/shared/skills/do-execute-plan/SKILL.md +261 -0
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +57 -0
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +92 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +155 -0
- package/core/shared/skills/do-execute-plan/references/run_position.md +63 -0
- package/core/shared/skills/do-execute-plan/references/scaffold.md +441 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +41 -0
- package/core/shared/skills/do-flow/SKILL.md +186 -0
- package/core/shared/skills/do-flow/references/task_classes.md +134 -0
- package/core/shared/skills/do-git/SKILL.md +115 -0
- package/core/shared/skills/do-git/references/hotfix-ritual.md +44 -0
- package/core/shared/skills/do-git/references/lifecycle-policy.md +54 -0
- package/core/shared/skills/do-git/references/release-ritual.md +64 -0
- package/core/shared/skills/do-implement/SKILL.md +222 -0
- package/core/shared/skills/do-plan/SKILL.md +219 -0
- package/core/shared/skills/do-test/SKILL.md +113 -0
- package/core/shared/templates/doflow/constitution-template.md +28 -0
- package/core/shared/templates/doflow/data-model-template.md +169 -0
- package/core/shared/templates/doflow/design-template.md +193 -0
- package/core/shared/templates/doflow/external-contract-template.md +35 -0
- package/core/shared/templates/doflow/intent-template.md +45 -0
- package/core/shared/templates/doflow/plan-template.md +151 -0
- package/core/shared/templates/doflow/question-log-template.md +51 -0
- package/core/shared/templates/doflow/requirement-template.md +126 -0
- package/core/shared/templates/doflow/specs-template.md +55 -0
- package/core/shared/templates/doflow/state-template.md +59 -0
- package/core/shared/workflows/do-flow-chain.md +17 -0
- package/package.json +48 -4
- package/src/adapters/antigravity/index.js +631 -0
- package/src/adapters/claude/index.js +548 -0
- package/src/adapters/claude/mcp.js +94 -0
- package/src/adapters/codex/agents.js +208 -0
- package/src/adapters/codex/config.js +272 -0
- package/src/adapters/codex/hooks.js +203 -0
- package/src/adapters/codex/index.js +707 -0
- package/src/adapters/codex/mcp.js +271 -0
- package/src/adapters/codex/native-projection.js +34 -0
- package/src/adapters/copilot/index.js +413 -0
- package/src/adapters/copy-tree.js +620 -0
- package/src/adapters/gemini/hooks.js +210 -0
- package/src/adapters/gemini/index.js +390 -0
- package/src/adapters/hook-commands.js +60 -0
- package/src/adapters/index.js +106 -0
- package/src/adapters/kiro/index.js +310 -0
- package/src/adapters/mcp-entries.js +331 -0
- package/src/adapters/opencode/index.js +466 -0
- package/src/adapters/pi/index.js +279 -0
- package/src/adapters/pi/json-members.js +185 -0
- package/src/adapters/pi/mcp.js +373 -0
- package/src/adapters/resolve-source.js +19 -0
- package/src/cli/commands/install.js +218 -0
- package/src/cli/commands/list-backups.js +21 -0
- package/src/cli/commands/reconcile.js +120 -0
- package/src/cli/commands/remove.js +82 -0
- package/src/cli/commands/rollback.js +172 -0
- package/src/cli/commands/self-update.js +33 -0
- package/src/cli/commands/status.js +138 -0
- package/src/cli/commands/tools.js +92 -0
- package/src/cli/commands/update.js +162 -0
- package/src/cli/index.js +568 -0
- package/src/cli/runtime-commands.js +281 -0
- package/src/cli/shared.js +218 -0
- package/src/helper/bash-helper.js +34 -0
- package/src/helper/git.js +24 -0
- package/src/helper/guardrails.js +49 -0
- package/src/helper/harness-paths.js +140 -0
- package/src/helper/marker-merge.js +116 -0
- package/src/helper/prompt.js +61 -0
- package/src/helper/repo-root.js +29 -0
- package/src/helper/settings-merge.js +151 -0
- package/src/helper/settings-scope.js +33 -0
- package/src/helper/toml.js +244 -0
- package/src/install/backup-set.js +149 -0
- package/src/install/backup.js +724 -0
- package/src/install/context.js +58 -0
- package/src/install/manifest.js +145 -0
- package/src/install/mcp.js +254 -0
- package/src/install/paths.js +84 -0
- package/src/install/targets.js +90 -0
- package/src/install/tool-lifecycle.js +151 -0
- package/src/lifecycle/bash-availability.js +25 -0
- package/src/lifecycle/index.js +812 -0
- package/src/lifecycle/mcp-index.js +28 -0
- package/src/lifecycle/policies.js +73 -0
- package/src/lifecycle/view.js +175 -0
- package/src/registry/index.js +611 -0
- package/src/release/build-package.js +91 -0
- package/src/release/changelog-section.js +70 -0
- package/src/release/sync-plugin-versions.js +66 -0
- package/src/runtime/advice/cli.js +283 -0
- package/src/runtime/advice/client.js +324 -0
- package/src/runtime/advice/config.js +189 -0
- package/src/runtime/advice/doctor.js +169 -0
- package/src/runtime/advice/endpoint-guard.js +134 -0
- package/src/runtime/advice/kinds.js +154 -0
- package/src/runtime/advice/providers/ollama-systemone.js +209 -0
- package/src/runtime/advice/record.js +166 -0
- package/src/runtime/advice/registry.js +170 -0
- package/src/runtime/advice/strength.js +66 -0
- package/src/runtime/brief-tools.js +342 -0
- package/src/runtime/c4-project.js +371 -0
- package/src/runtime/capability-router.js +484 -0
- package/src/runtime/checkouts.js +170 -0
- package/src/runtime/claims.js +468 -0
- package/src/runtime/cli-result.js +55 -0
- package/src/runtime/cli.js +678 -0
- package/src/runtime/command-detect.js +516 -0
- package/src/runtime/context-pack.js +492 -0
- package/src/runtime/decision-register.js +493 -0
- package/src/runtime/evidence-ledger.js +338 -0
- package/src/runtime/failure/capture.js +272 -0
- package/src/runtime/failure/classifier.js +68 -0
- package/src/runtime/failure/cli.js +178 -0
- package/src/runtime/failure/home.js +64 -0
- package/src/runtime/failure/store.js +226 -0
- package/src/runtime/feature-resolve.js +79 -0
- package/src/runtime/freshness.js +177 -0
- package/src/runtime/health.js +863 -0
- package/src/runtime/history-compactor.js +237 -0
- package/src/runtime/implementation-gate.js +321 -0
- package/src/runtime/inventory/coverage.js +218 -0
- package/src/runtime/inventory/identity.js +65 -0
- package/src/runtime/inventory/index.js +705 -0
- package/src/runtime/inventory/precedence.js +134 -0
- package/src/runtime/inventory/read-scopes.js +131 -0
- package/src/runtime/inventory/siblings.js +192 -0
- package/src/runtime/knowledge/chunker.js +124 -0
- package/src/runtime/knowledge/hybrid.js +149 -0
- package/src/runtime/knowledge/index-store.js +145 -0
- package/src/runtime/knowledge/retrieval.js +194 -0
- package/src/runtime/leak-scan.js +185 -0
- package/src/runtime/lifecycle/cli.js +276 -0
- package/src/runtime/lifecycle/event-store.js +340 -0
- package/src/runtime/lifecycle/fold.js +353 -0
- package/src/runtime/lifecycle/followup.js +432 -0
- package/src/runtime/lifecycle/goal.js +249 -0
- package/src/runtime/lifecycle/intent-writer.js +86 -0
- package/src/runtime/lifecycle/overview.js +292 -0
- package/src/runtime/lifecycle/release.js +241 -0
- package/src/runtime/lifecycle/report-store.js +221 -0
- package/src/runtime/lifecycle/retention.js +212 -0
- package/src/runtime/lifecycle/root.js +71 -0
- package/src/runtime/lifecycle/status.js +353 -0
- package/src/runtime/lifecycle/store-upkeep.js +393 -0
- package/src/runtime/locator-resolve.js +158 -0
- package/src/runtime/mask.js +210 -0
- package/src/runtime/mcp-consultations.js +412 -0
- package/src/runtime/mcp-reach.js +157 -0
- package/src/runtime/model-router.js +153 -0
- package/src/runtime/outcome.js +467 -0
- package/src/runtime/reach.js +148 -0
- package/src/runtime/readiness-record.js +150 -0
- package/src/runtime/readiness.js +435 -0
- package/src/runtime/recovery.js +282 -0
- package/src/runtime/research-request.js +231 -0
- package/src/runtime/retrieval-plan.js +578 -0
- package/src/runtime/scaffold/artifacts.js +217 -0
- package/src/runtime/scaffold/fingerprint.js +56 -0
- package/src/runtime/scaffold/generate.js +911 -0
- package/src/runtime/scaffold/languages.js +245 -0
- package/src/runtime/storage/cli.js +64 -0
- package/src/runtime/storage/engine.js +249 -0
- package/src/runtime/storage/registry.js +130 -0
- package/src/runtime/storage/roots.js +63 -0
- package/src/runtime/storage/rules.js +282 -0
- package/src/runtime/storage/upkeep.js +243 -0
- package/src/runtime/storage/work-status.js +326 -0
- package/src/runtime/task-attempts.js +415 -0
- package/src/runtime/task-classifier.js +550 -0
- package/src/runtime/task-scope.js +130 -0
- package/src/runtime/task-state.js +176 -0
- package/src/runtime/trace/indicators.js +235 -0
- package/src/runtime/trace/ledger.js +626 -0
- package/src/runtime/trace/render.js +76 -0
- package/src/runtime/trace/views.js +459 -0
- package/src/runtime/verification/contract-runner.js +341 -0
- package/src/runtime/verification/engine.js +1461 -0
- package/src/runtime/verification/registry.js +130 -0
- package/src/runtime/verification/scope-bound.js +418 -0
- package/src/runtime/verification/test-selection.js +172 -0
- package/src/runtime/workflow-engine.js +588 -0
- package/src/runtime/workflow-orchestrator.js +953 -0
- package/src/runtime/worktree.js +340 -0
- package/src/state/index.js +193 -0
- package/src/state/lockfile.js +136 -0
- package/src/state/run-lock.js +408 -0
- package/types/node-commonjs.d.ts +68 -0
- package/types/runtime.d.ts +91 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
// Shared hook-command verification — the one piece of codex/hooks.ts and gemini/hooks.ts that
|
|
6
|
+
// proved byte-identical on inspection (unlike SUPPORTED_EVENTS, validateHooksConfig, and
|
|
7
|
+
// classifyClaudeGuardrails, which encode genuine per-harness differences and stay in each
|
|
8
|
+
// adapter). verifyHookCommands and the two private helpers it calls, commandScriptNames and
|
|
9
|
+
// hookHandlers, check that a hook config's command handlers resolve to a real, executable script
|
|
10
|
+
// in the harness's own hooks directory — that check does not vary by harness, so it lives once.
|
|
11
|
+
const fs = require('node:fs');
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
|
|
14
|
+
function commandScriptNames(command ) {
|
|
15
|
+
// DoFlow's wrappers are shell scripts selected from a project or CODEX_HOME hooks directory.
|
|
16
|
+
// Extracting the basename works for both literal and command-substitution based paths.
|
|
17
|
+
return [...new Set((command.match(/[A-Za-z0-9][A-Za-z0-9_-]*\.sh\b/g) || []))];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function hookHandlers(config ) {
|
|
21
|
+
return Object.entries(config.hooks || {}).flatMap(([event, groups] ) =>
|
|
22
|
+
(Array.isArray(groups) ? groups : []).flatMap((group ) =>
|
|
23
|
+
(Array.isArray(group?.hooks) ? group.hooks : []).map((handler ) => ({ event, handler }))));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// On `trusted`: both harnesses gate hook execution behind their own trust prompt — Codex through
|
|
27
|
+
// its config, Gemini by fingerprinting a hook's name and command and warning before running one
|
|
28
|
+
// that changed (geminicli.com/docs/hooks/). DoFlow verifies neither gate live; doing so would need
|
|
29
|
+
// a running CLI session. It reports trust as a prerequisite whose shape it observed, not one it
|
|
30
|
+
// bypassed or assumed satisfied. That reading is identical for both harnesses, which is part of
|
|
31
|
+
// why this function is shared.
|
|
32
|
+
// Windows carries no executable permission bits — statSync().mode always reports 0666/0444 and
|
|
33
|
+
// chmodSync can only toggle the read-only flag — so the POSIX "not executable" failure mode
|
|
34
|
+
// cannot exist there. Requiring the bit would refuse every hooks install on win32 (the scripts
|
|
35
|
+
// are invoked through an explicit `bash <script>` command string, which needs no +x), so the
|
|
36
|
+
// exec-bit half of the check is POSIX-only; existence is checked everywhere.
|
|
37
|
+
const EXEC_BITS_EXIST = process.platform !== 'win32';
|
|
38
|
+
|
|
39
|
+
function verifyHookCommands(config , { scriptsDir, trusted = false, fsImpl = fs } = {}) {
|
|
40
|
+
const checks = [];
|
|
41
|
+
for (const { event, handler } of hookHandlers(config)) {
|
|
42
|
+
if (!handler || handler.type !== 'command' || typeof handler.command !== 'string' || !handler.command.trim()) continue;
|
|
43
|
+
const names = commandScriptNames(handler.command);
|
|
44
|
+
if (names.length === 0) {
|
|
45
|
+
checks.push({ event, command: handler.command, ok: false, reason: 'Command does not identify a hook script', requiresTrust: true, trusted });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
for (const name of names) {
|
|
49
|
+
const file = scriptsDir ? path.join(scriptsDir, name) : null;
|
|
50
|
+
const exists = Boolean(file && fsImpl.existsSync(file));
|
|
51
|
+
const executable = exists && (!EXEC_BITS_EXIST || Boolean(fsImpl.statSync(file).mode & 0o111));
|
|
52
|
+
checks.push({ event, command: handler.command, script: name, file, exists, executable,
|
|
53
|
+
ok: exists && executable, reason: !exists ? 'Hook script is missing' : (!executable ? 'Hook script is not executable' : null),
|
|
54
|
+
requiresTrust: true, trusted });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { ok: checks.every((check ) => check.ok), checks, trust: { required: checks.length > 0, trusted: Boolean(trusted), status: trusted ? 'trusted' : 'review-required' } };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = { commandScriptNames, hookHandlers, verifyHookCommands };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
// Harness adapters own native formats and paths. This module intentionally only
|
|
6
|
+
// validates and resolves that boundary; it never reads or writes harness files.
|
|
7
|
+
const { resolveRegistrySource } = require('./resolve-source.js');
|
|
8
|
+
|
|
9
|
+
const ADAPTER_METHODS = Object.freeze(['discover', 'render', 'plan', 'apply', 'remove', 'verify']);
|
|
10
|
+
|
|
11
|
+
/** Per-adapter native-projection normalizers. Each lives in its adapter's own directory (review
|
|
12
|
+
* A3: the Codex shape used to be inlined here, putting per-harness knowledge on the shared side of
|
|
13
|
+
* the boundary); this module only dispatches by adapter name. An adapter gaining a
|
|
14
|
+
* nativeProjection declaration registers its normalizer here. */
|
|
15
|
+
const NATIVE_PROJECTION_NORMALIZERS = Object.freeze({
|
|
16
|
+
codex: () => require('./codex/native-projection.js').normalizeNativeProjection,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/** Dispatch a harness's nativeProjection declaration to its adapter's own normalizer. */
|
|
20
|
+
function nativeProjectionFor(registry , harness , mcp , context ) {
|
|
21
|
+
if (!harness.nativeProjection) return {};
|
|
22
|
+
const load = NATIVE_PROJECTION_NORMALIZERS[harness.adapter];
|
|
23
|
+
if (!load) {
|
|
24
|
+
throw new Error(`No native projection normalizer is registered for '${harness.adapter}'. `
|
|
25
|
+
+ `Registered: ${Object.keys(NATIVE_PROJECTION_NORMALIZERS).join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
return load()(registry, harness, mcp, context);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Convert validated registry declarations into the only generic payload an
|
|
32
|
+
* adapter receives. Native serializers may add adapter-specific fields, but
|
|
33
|
+
* cannot infer applicability from a missing projection.
|
|
34
|
+
*/
|
|
35
|
+
function projectAdapterInput({ registry, harness, scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], policies = [], context = {} } ) {
|
|
36
|
+
if (!registry || !harness) throw new Error('registry and harness are required for adapter projection');
|
|
37
|
+
const projectAsset = (asset ) => {
|
|
38
|
+
const projection = asset?.projection?.[harness.id];
|
|
39
|
+
if (!projection || typeof projection.renderer !== 'string' || typeof projection.capability !== 'string') {
|
|
40
|
+
throw new Error(`Asset '${asset?.id ?? '?'}' lacks a projection for '${harness.id}'`);
|
|
41
|
+
}
|
|
42
|
+
const capability = harness.capabilities?.[projection.capability];
|
|
43
|
+
if (!capability || capability.status === 'unavailable') {
|
|
44
|
+
throw new Error(`Asset '${asset.id}' cannot project unavailable '${harness.id}' capability '${projection.capability}'`);
|
|
45
|
+
}
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
id: asset.id, kind: asset.kind, source: asset.source, ownership: asset.ownership,
|
|
48
|
+
renderer: projection.renderer, capability: projection.capability,
|
|
49
|
+
capabilityStatus: capability.status, nativeTarget: harness.nativeTargets?.[projection.capability] ?? null,
|
|
50
|
+
nativeDir: asset.nativeDir?.[harness.id] ?? null,
|
|
51
|
+
// Optional destination shape for copy-tree assets. Null for every projection that mirrors
|
|
52
|
+
// source paths, which is all of them except Antigravity's directory-per-agent requirement.
|
|
53
|
+
layout: projection.layout ?? null,
|
|
54
|
+
transform: projection.transform ?? null,
|
|
55
|
+
prerequisites: [...(capability.prerequisites || [])],
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
if (mcp.length && (!harness.capabilities?.mcp || harness.capabilities.mcp.status === 'unavailable')) {
|
|
59
|
+
throw new Error(`Selected MCP servers cannot project to unavailable '${harness.id}' MCP capability`);
|
|
60
|
+
}
|
|
61
|
+
const projection = nativeProjectionFor(registry, harness, mcp, context);
|
|
62
|
+
return Object.freeze({
|
|
63
|
+
harness, scope, scopeRoot, context,
|
|
64
|
+
assets: Object.freeze(assets.map(projectAsset)),
|
|
65
|
+
mcp: Object.freeze(mcp.map((server ) => Object.freeze({ ...server }))),
|
|
66
|
+
// Servers whose existing entries the adapter may take as its own while it holds no MCP row.
|
|
67
|
+
mcpAdoptable: Object.freeze(mcpAdoptable.map((server ) => Object.freeze({ ...server }))),
|
|
68
|
+
policies: Object.freeze(policies.map((policy ) => Object.freeze({ ...policy }))),
|
|
69
|
+
nativeTargets: Object.freeze({ ...harness.nativeTargets }),
|
|
70
|
+
projection: Object.freeze({ ...projection }),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function assertAdapter(adapter , name = 'adapter') {
|
|
75
|
+
if (!adapter || typeof adapter !== 'object') throw new Error(`${name} must be an object`);
|
|
76
|
+
for (const method of ADAPTER_METHODS) {
|
|
77
|
+
if (typeof adapter[method] !== 'function') throw new Error(`${name} must implement ${method}()`);
|
|
78
|
+
}
|
|
79
|
+
return adapter;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function createAdapterRegistry(adapters = {}) {
|
|
83
|
+
const entries = adapters instanceof Map ? [...adapters.entries()] : Object.entries(adapters);
|
|
84
|
+
const resolved = new Map();
|
|
85
|
+
for (const [name, adapter] of entries) {
|
|
86
|
+
if (typeof name !== 'string' || !name.trim()) throw new Error('Adapter names must be non-empty strings');
|
|
87
|
+
resolved.set(name, assertAdapter(adapter, `Adapter '${name}'`));
|
|
88
|
+
}
|
|
89
|
+
return Object.freeze({
|
|
90
|
+
names: () => [...resolved.keys()],
|
|
91
|
+
has: (name ) => resolved.has(name),
|
|
92
|
+
get(name ) {
|
|
93
|
+
const adapter = resolved.get(name);
|
|
94
|
+
if (!adapter) throw new Error(`No registered adapter '${name}'`);
|
|
95
|
+
return adapter;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function resolveAdapter(adapterRegistry , harness ) {
|
|
101
|
+
if (!adapterRegistry || typeof adapterRegistry.get !== 'function') throw new Error('adapterRegistry must expose get(name)');
|
|
102
|
+
if (!harness || typeof harness.adapter !== 'string') throw new Error('Harness must declare an adapter');
|
|
103
|
+
return adapterRegistry.get(harness.adapter);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = { ADAPTER_METHODS, assertAdapter, createAdapterRegistry, resolveAdapter, resolveRegistrySource, nativeProjectionFor, projectAdapterInput };
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
// Kiro adapter.
|
|
6
|
+
//
|
|
7
|
+
// Kiro's native root is symmetric across scopes — `.kiro/` (project) / `~/.kiro/` (global) is the
|
|
8
|
+
// one directory that holds everything Kiro reads: steering, agents, hooks, and settings/mcp.json
|
|
9
|
+
// (see src/targets.js's toolDirs() for the same convention this adapter's own nativePaths()
|
|
10
|
+
// mirrors). Unlike every other harness in this codebase, Kiro receives DoFlow's *full* guidance
|
|
11
|
+
// tree as steering files rather than a single marker-wrapped pointer file plus a separately-copied
|
|
12
|
+
// tree (design.md §4's "research decision D3"): there is no single-file instruction surface here
|
|
13
|
+
// at all, so — unlike src/adapters/gemini or src/adapters/opencode — this adapter never renders a
|
|
14
|
+
// marker-wrapped instruction file.
|
|
15
|
+
//
|
|
16
|
+
// Evidence: https://kiro.dev/docs/steering/, https://kiro.dev/docs/mcp/configuration/,
|
|
17
|
+
// https://kiro.dev/docs/hooks/
|
|
18
|
+
const fs = require('node:fs');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
const { planTree, applyTree, removeTree, verifyTree, resolveTransform, copyTreeAssets, copyTreeDestDir, ledgerFileResources, ledgerSiblingFingerprints, siblingReplacedNotices, sourceDirFor } = require('../copy-tree.js');
|
|
21
|
+
const { readMcpFiles, planMcpEntries, verifyMcpEntries, ownedMcpIds, writeMcpEntries } = require('../mcp-entries.js');
|
|
22
|
+
const { declaredHarnessPaths, resolveHarnessPaths } = require('../../helper/harness-paths.js');
|
|
23
|
+
|
|
24
|
+
const HARNESS = 'kiro';
|
|
25
|
+
const MCP_CONTAINER = 'mcpServers';
|
|
26
|
+
const MCP_RENDERER = 'kiro-mcp';
|
|
27
|
+
// Releases up to 1.18.0 recorded one `kiro:mcp:<id>` row per server (and never a row for the old
|
|
28
|
+
// `kiro:mcp:registration` change); they are read as owned rows until a run replaces them.
|
|
29
|
+
const LEGACY_MCP_PREFIX = `${HARNESS}:mcp:`;
|
|
30
|
+
const LEGACY_MCP_REGISTRATION = `${HARNESS}:mcp:registration`;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Native path facts live in core/registry/harnesses.json under this harness's "paths" section and
|
|
34
|
+
* resolve through the shared harness-paths resolver; `.kiro` (project) / `~/.kiro` (global) is the
|
|
35
|
+
* whole native root and every other path here is a fixed subpath under it.
|
|
36
|
+
* createKiroAdapter({ declaredPaths }) is the injection point buildAdapterRegistry() uses;
|
|
37
|
+
* module-level exports delegate to a default-configured instance so direct callers keep their
|
|
38
|
+
* historical shape.
|
|
39
|
+
*/
|
|
40
|
+
function createKiroAdapter({ declaredPaths = declaredHarnessPaths()[HARNESS] } = {}) {
|
|
41
|
+
// Parity note: Kiro's historical nativePaths() derived even its user-scope root from scopeRoot
|
|
42
|
+
// (the CLI passes $HOME there for -g installs), never from a separate homeDir argument — so the
|
|
43
|
+
// resolver is fed no homeDir and "root" keeps resolving exactly as before.
|
|
44
|
+
function nativePaths({ scope, scopeRoot } = {}) {
|
|
45
|
+
return resolveHarnessPaths(declaredPaths, { scope, scopeRoot });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Discovery keeps the MCP files as plan read them (`mcpSnapshot`), which verify compares against,
|
|
49
|
+
* and reports the servers DoFlow owns in Kiro's mcp.json now (`mcpOwned`). */
|
|
50
|
+
function discover({ scope, scopeRoot, mcp = [], mcpAdoptable = [], ledger, fsImpl = fs } ) {
|
|
51
|
+
const paths = nativePaths({ scope, scopeRoot });
|
|
52
|
+
const entries = mcpEntriesInput({ paths, mcp, mcpAdoptable, ledger });
|
|
53
|
+
const mcpSnapshot = readMcpFiles({ file: entries.file, ownRows: entries.ownRows, container: MCP_CONTAINER, fsImpl });
|
|
54
|
+
const read = mcpSnapshot[entries.file];
|
|
55
|
+
// `null` while the file is absent, unreadable or has no server map; every name in it otherwise, whoever wrote it.
|
|
56
|
+
const mcpConfigured = read?.ok && read.servers ? Object.keys(read.servers).sort() : null;
|
|
57
|
+
return { paths, mcpSnapshot, mcpOwned: ownedMcpIds({ ...entries, files: mcpSnapshot }), mcpConfigured };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Kiro has no single-file, marker-managed instruction surface for this adapter to render into —
|
|
62
|
+
* the guidance tree is projected file-for-file by the copy-tree engine below, once as steering
|
|
63
|
+
* (guidance.context-layer) and once into the shared `.doflow/guidance` (kiro.guidance-tree). Every
|
|
64
|
+
* asset routed to 'kiro' in core/registry/assets.json uses `renderer: copy-tree` or
|
|
65
|
+
* `kiro-agents`, so nothing reaches this function. It is kept as a pure passthrough only to
|
|
66
|
+
* satisfy the six-function adapter contract every harness must implement identically.
|
|
67
|
+
*/
|
|
68
|
+
function render({ content = '' } = {}) {
|
|
69
|
+
return String(content);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---- copy-tree assets (steering tree, agents) ----
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Kiro has a dedicated skills system (https://kiro.dev/docs/skills/): a folder containing
|
|
76
|
+
* `SKILL.md` with YAML frontmatter, optionally alongside scripts/references/assets — the same open
|
|
77
|
+
* Agent Skills standard DoFlow already authors, scanned from `.kiro/skills/` (workspace) and
|
|
78
|
+
* `~/.kiro/skills/` (global). `skills.doflow` therefore materialises like every other harness's
|
|
79
|
+
* skills tree, no exclusion needed.
|
|
80
|
+
*
|
|
81
|
+
* `agents.shared` is included alongside the generic `copy-tree` renderer even though its own
|
|
82
|
+
* projection declares `renderer: 'kiro-agents'` — a distinct name chosen so the registry can tell
|
|
83
|
+
* the two apart. Both materialise through the same engine, but `kiro-agents` declares the
|
|
84
|
+
* `kiro-agent-json` layout and `kiro-agents` transform: kiro-cli discovers agents as
|
|
85
|
+
* `.kiro/agents/<name>.json`, so each shared `<name>.md` spec is rendered, not mirrored.
|
|
86
|
+
*/
|
|
87
|
+
function kiroTreeAssets(assets ) {
|
|
88
|
+
return [...copyTreeAssets(assets), ...(assets || []).filter((asset ) => asset.renderer === 'kiro-agents')];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing, fsImpl = fs } ) {
|
|
92
|
+
const paths = nativePaths({ scope, scopeRoot });
|
|
93
|
+
const changes = [];
|
|
94
|
+
const conflicts = [];
|
|
95
|
+
const treeResults = [];
|
|
96
|
+
const notices = [];
|
|
97
|
+
for (const asset of kiroTreeAssets(assets)) {
|
|
98
|
+
const destDir = copyTreeDestDir(paths.configDir, asset);
|
|
99
|
+
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Kiro');
|
|
100
|
+
const previousResources = ledgerFileResources(ledger?.resources, HARNESS, asset.id);
|
|
101
|
+
const result = planTree({ sourceDir, destDir, previousResources, siblingFingerprints: ledgerSiblingFingerprints(ledger?.resources, HARNESS), operation: removing ? 'remove' : 'apply', fsImpl, layout: asset.layout, transform: asset.transform, keepModified: !removing,
|
|
102
|
+
// Forwarded so the CLI's --force reaches planTree's conflict check; omitting it let
|
|
103
|
+
// planTree's own `force = false` default stand in silently. Gated on `!removing` for the
|
|
104
|
+
// reason codex/index.ts states in full: force heals drift on apply, but a hand-edited file
|
|
105
|
+
// is never deleted on removal, forced or not.
|
|
106
|
+
force: !removing && context?.force === true, });
|
|
107
|
+
treeResults.push(result);
|
|
108
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
109
|
+
// A hand-edited file at a path DoFlow no longer writes is the user's: it stays, only its
|
|
110
|
+
// ownership row is released.
|
|
111
|
+
notices.push(...result.kept.map((item ) => `kept hand-edited ${path.relative(paths.root, item.target)}; DoFlow no longer manages it`));
|
|
112
|
+
for (const change of result.changes) {
|
|
113
|
+
changes.push({
|
|
114
|
+
assetId: asset.id, target: change.target, source: change.source, operation: change.operation,
|
|
115
|
+
ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${change.relPath}`,
|
|
116
|
+
kind: 'copy-tree-file', identity: change.relPath,
|
|
117
|
+
afterFingerprint: change.fingerprint, fingerprint: change.fingerprint, sourceVersion: 'registry-v1',
|
|
118
|
+
transformName: asset.transform || null,
|
|
119
|
+
...(change.kept ? { retained: true, retainedFor: [] } : {}),
|
|
120
|
+
projection: { renderer: asset.renderer },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { changes, conflicts, notices: [...siblingReplacedNotices(treeResults), ...notices] };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function applyCopyTreeAssets(changes , { fsImpl = fs } = {}) {
|
|
128
|
+
let applied = 0;
|
|
129
|
+
const grouped = new Map();
|
|
130
|
+
for (const change of changes) {
|
|
131
|
+
if (change.kind !== 'copy-tree-file' || change.operation === 'remove') continue;
|
|
132
|
+
const key = change.transformName || null;
|
|
133
|
+
if (!grouped.has(key)) grouped.set(key, []);
|
|
134
|
+
grouped.get(key).push({ relPath: change.identity, target: change.target, source: change.source, operation: change.operation, fingerprint: change.fingerprint });
|
|
135
|
+
}
|
|
136
|
+
for (const [transformName, treeChanges] of grouped) {
|
|
137
|
+
applied += applyTree({ changes: treeChanges, fsImpl, transform: resolveTransform(transformName) }).applied;
|
|
138
|
+
}
|
|
139
|
+
return applied;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function removeCopyTreeAssets(changes , { fsImpl = fs } = {}) {
|
|
143
|
+
const treeChanges = changes.filter((change ) => change.kind === 'copy-tree-file' && change.operation === 'remove' && !change.retained)
|
|
144
|
+
.map((change ) => ({ relPath: change.identity, target: change.target, operation: 'remove', fingerprint: change.fingerprint, pruneGuard: change.pruneGuard }));
|
|
145
|
+
return removeTree({ changes: treeChanges, fsImpl }).removed;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl = fs } ) {
|
|
149
|
+
const paths = nativePaths({ scope, scopeRoot });
|
|
150
|
+
const statuses = [];
|
|
151
|
+
const resources = [];
|
|
152
|
+
const conflicts = [];
|
|
153
|
+
for (const asset of kiroTreeAssets(assets)) {
|
|
154
|
+
const destDir = copyTreeDestDir(paths.configDir, asset);
|
|
155
|
+
const sourceDir = sourceDirFor(asset, context, fsImpl, 'Kiro');
|
|
156
|
+
const result = verifyTree({ sourceDir, destDir, fsImpl, layout: asset.layout, transform: asset.transform, plannedWrites: context?.plannedWrites });
|
|
157
|
+
conflicts.push(...result.conflicts.map((reason ) => `${asset.id}: ${reason}`));
|
|
158
|
+
for (const resource of result.resources) {
|
|
159
|
+
resources.push({
|
|
160
|
+
assetId: asset.id, target: resource.target, ownershipIdentity: `doflow:${HARNESS}:copy-tree:${asset.id}:${resource.relPath}`,
|
|
161
|
+
kind: 'copy-tree-file', identity: resource.relPath,
|
|
162
|
+
fingerprint: resource.fingerprint, sourceVersion: 'registry-v1',
|
|
163
|
+
projection: { renderer: asset.renderer },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
statuses.push({ assetId: asset.id, capability: asset.capability, status: result.ok ? 'managed' : 'conflict', target: destDir });
|
|
167
|
+
}
|
|
168
|
+
return { statuses, resources, conflicts };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ---- MCP (.kiro/settings/mcp.json) ----
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Shape one registry MCP server declaration into Kiro's own per-server schema (confirmed against
|
|
175
|
+
* kiro.dev/docs/mcp/configuration/): a local (stdio) server carries `command`/`args`/`env`/
|
|
176
|
+
* `disabled`/`autoApprove`/`disabledTools`; a remote server carries `url`/`headers` instead. The
|
|
177
|
+
* registry (core/registry/mcp.json) only ever declares stdio servers today, so only the fields it
|
|
178
|
+
* actually carries are emitted — this never invents a field the registry doesn't supply.
|
|
179
|
+
*/
|
|
180
|
+
function buildServerEntry(server ) {
|
|
181
|
+
if (server.url) return { url: server.url, ...(server.headers ? { headers: server.headers } : {}) };
|
|
182
|
+
return { command: server.command, ...(server.args?.length ? { args: server.args } : {}) };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function ownershipIdentity(id ) { return `doflow:${HARNESS}:mcp-server:${id}`; }
|
|
186
|
+
|
|
187
|
+
function mcpOwnRows(ledger ) {
|
|
188
|
+
return (ledger?.resources || []).filter((row ) => row.harness === HARNESS).flatMap((row ) => {
|
|
189
|
+
if (row.kind === 'mcp-server') {
|
|
190
|
+
return [{ identity: row.identity, target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: row.ownershipIdentity, legacy: false }];
|
|
191
|
+
}
|
|
192
|
+
const legacyIdentity = row.ownershipIdentity;
|
|
193
|
+
if (typeof legacyIdentity !== 'string' || !legacyIdentity.startsWith(LEGACY_MCP_PREFIX) || legacyIdentity === LEGACY_MCP_REGISTRATION) return [];
|
|
194
|
+
return [{ identity: legacyIdentity.slice(LEGACY_MCP_PREFIX.length), target: row.target, fingerprint: row.fingerprint ?? null, ownershipIdentity: legacyIdentity, legacy: true }];
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Everything the shared entry-ownership rules (../mcp-entries.ts) need from this adapter. */
|
|
199
|
+
function mcpEntriesInput({ paths, mcp = [], mcpAdoptable = [], ledger, assets = [] } ) {
|
|
200
|
+
const rendered = (servers ) => servers.map((server ) => ({ id: server.id, entry: buildServerEntry(server) }));
|
|
201
|
+
return {
|
|
202
|
+
file: paths.mcp, selected: rendered(mcp), adoptable: rendered(mcpAdoptable),
|
|
203
|
+
ownRows: mcpOwnRows(ledger),
|
|
204
|
+
foreignRows: (ledger?.resources || []).filter((row ) => row.kind === 'mcp-server' && row.harness !== HARNESS)
|
|
205
|
+
.map((row ) => ({ harness: row.harness, identity: row.identity, target: row.target })),
|
|
206
|
+
identityFor: ownershipIdentity, assetId: pseudoAssetId(assets), renderer: MCP_RENDERER, label: 'Kiro MCP',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Kiro has no hooks or mcp asset of its own in core/registry/assets.json (mcp servers come from
|
|
211
|
+
* core/registry/mcp.json, not an asset), so an MCP entry change piggybacks on an asset id
|
|
212
|
+
* this harness actually receives — the same "pseudo-component" technique
|
|
213
|
+
* src/adapters/gemini/index.js#hooksAssetId already uses for its own settings-only component. */
|
|
214
|
+
function pseudoAssetId(assets ) {
|
|
215
|
+
return assets.find((asset ) => asset.id === 'guidance.context-layer')?.id ?? assets[0]?.id;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---- shared adapter contract ----
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* `.kiro/hooks/` is now a real, populated native surface: `kiro.hooks-scripts`
|
|
222
|
+
* (core/registry/assets.json) is a copy-tree asset like skills/agents, so `kiroTreeAssets()` above
|
|
223
|
+
* already plans/applies/removes it alongside them. This function only reports the
|
|
224
|
+
* declarative capability surface — same unconditional shape `plan()` already uses for
|
|
225
|
+
* instructions/skills/agents — not whether that asset happens to be present in a given call's
|
|
226
|
+
* `assets` array; per-file installed status for the hooks tree itself is reported through
|
|
227
|
+
* `copyTree.statuses`/`copyTree.resources`, exactly like it is for skills and agents.
|
|
228
|
+
*/
|
|
229
|
+
function hooksSurface(paths ) {
|
|
230
|
+
return { status: 'supported', target: paths.hooks };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function plan({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, context = {}, ledger, fsImpl = fs } ) {
|
|
234
|
+
const found = discovery || discover({ scope, scopeRoot, mcp, mcpAdoptable, ledger, fsImpl });
|
|
235
|
+
const changes = [];
|
|
236
|
+
const conflicts = [];
|
|
237
|
+
const removing = context.operation === 'remove';
|
|
238
|
+
|
|
239
|
+
const copyTree = planCopyTreeAssets({ assets, scope, scopeRoot, context, ledger, removing, fsImpl });
|
|
240
|
+
changes.push(...copyTree.changes);
|
|
241
|
+
conflicts.push(...copyTree.conflicts);
|
|
242
|
+
|
|
243
|
+
const mcpPlan = planMcpEntries({
|
|
244
|
+
...mcpEntriesInput({ paths: found.paths, mcp, mcpAdoptable, ledger, assets }), files: found.mcpSnapshot, removing,
|
|
245
|
+
});
|
|
246
|
+
changes.push(...mcpPlan.changes);
|
|
247
|
+
conflicts.push(...mcpPlan.conflicts);
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
changes, conflicts, prerequisites: [], notices: [...copyTree.notices, ...mcpPlan.notices],
|
|
251
|
+
surfaces: {
|
|
252
|
+
instructions: { status: 'supported', target: found.paths.steering },
|
|
253
|
+
skills: { status: 'supported', target: found.paths.skills },
|
|
254
|
+
agents: { status: 'supported', target: found.paths.agents },
|
|
255
|
+
hooks: hooksSurface(found.paths),
|
|
256
|
+
mcp: { status: found.mcpSnapshot[found.paths.mcp].ok ? 'supported' : 'blocked', target: found.paths.mcp, selected: mcp.map((item ) => item.id) },
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function apply({ changes = [], fsImpl = fs } ) {
|
|
262
|
+
writeMcpEntries(changes, { container: MCP_CONTAINER, fsImpl });
|
|
263
|
+
applyCopyTreeAssets(changes, { fsImpl });
|
|
264
|
+
// An update that no longer ships a copy-tree file carries its rows as removals inside the
|
|
265
|
+
// apply batch; the lifecycle calls remove() only for `doflow remove`.
|
|
266
|
+
removeCopyTreeAssets(changes, { fsImpl });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function remove({ changes = [], fsImpl = fs } ) {
|
|
270
|
+
writeMcpEntries(changes, { container: MCP_CONTAINER, fsImpl });
|
|
271
|
+
removeCopyTreeAssets(changes, { fsImpl });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function verify({ scope, scopeRoot, assets = [], mcp = [], mcpAdoptable = [], discovery, ledger, operation, context = {}, fsImpl = fs } ) {
|
|
275
|
+
const paths = nativePaths({ scope, scopeRoot });
|
|
276
|
+
const resources = [];
|
|
277
|
+
const conflicts = [];
|
|
278
|
+
|
|
279
|
+
const copyTree = verifyCopyTreeAssets({ assets, scope, scopeRoot, context, fsImpl });
|
|
280
|
+
resources.push(...copyTree.resources);
|
|
281
|
+
conflicts.push(...copyTree.conflicts);
|
|
282
|
+
|
|
283
|
+
const entries = mcpEntriesInput({ paths, mcp, mcpAdoptable, ledger, assets });
|
|
284
|
+
const files = readMcpFiles({ file: entries.file, ownRows: entries.ownRows, container: MCP_CONTAINER, fsImpl });
|
|
285
|
+
const mcpResult = verifyMcpEntries({
|
|
286
|
+
...entries, files, snapshot: discovery?.mcpSnapshot ?? files,
|
|
287
|
+
removing: (operation ?? context.operation) === 'remove', harness: HARNESS, sourceVersion: context.sourceVersion ?? 'unknown',
|
|
288
|
+
});
|
|
289
|
+
resources.push(...mcpResult.resources);
|
|
290
|
+
conflicts.push(...mcpResult.conflicts);
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
ok: conflicts.length === 0,
|
|
294
|
+
resources,
|
|
295
|
+
statuses: { copyTree: copyTree.statuses, mcp: mcpResult.statuses, hooks: hooksSurface(paths) },
|
|
296
|
+
conflicts,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { nativePaths, discover, render, plan, apply, remove, verify, buildServerEntry };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const singleton = createKiroAdapter();
|
|
304
|
+
|
|
305
|
+
module.exports = {
|
|
306
|
+
nativePaths: singleton.nativePaths, discover: singleton.discover, render: singleton.render,
|
|
307
|
+
plan: singleton.plan, apply: singleton.apply, remove: singleton.remove, verify: singleton.verify,
|
|
308
|
+
buildServerEntry: singleton.buildServerEntry,
|
|
309
|
+
createKiroAdapter,
|
|
310
|
+
};
|