@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,353 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The fold (IC-003, IC-004): every lifecycle event file, ordered by `at` then `id`, reduced to the
|
|
7
|
+
* follow-ups, tracked features, goals and release records they describe. The function is pure: no
|
|
8
|
+
* file or git access, so two clones holding the same files produce the same result, and a writer
|
|
9
|
+
* can test one more event against the state it would join (`applyEvent`) before anything is
|
|
10
|
+
* written. A transition that is illegal at its place in the order is not applied and is listed in
|
|
11
|
+
* `conflicts` as `{event, type, reason}`; `code` is the same finding as a word for the callers that
|
|
12
|
+
* must refuse a write with it.
|
|
13
|
+
*
|
|
14
|
+
* "A taken item whose feature finished is done" is NOT decided here: it needs git (IC-021), so the
|
|
15
|
+
* fold leaves such an item `taken` and `withDerivedDone` applies the derived statuses on read.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const SETTLE_AS = ['kept', 'dismissed', 'fix', 'done'];
|
|
19
|
+
|
|
20
|
+
function byOrder(a , b ) {
|
|
21
|
+
const delta = Date.parse(a.at) - Date.parse(b.at);
|
|
22
|
+
if (delta !== 0) return delta;
|
|
23
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isText(value ) { return typeof value === 'string' && value.trim() !== ''; }
|
|
27
|
+
function isIdList(value ) { return Array.isArray(value) && value.length > 0 && value.every(isText); }
|
|
28
|
+
|
|
29
|
+
/** DEC-045: an event dated further ahead than this stays out of the fold and is listed as a conflict. */
|
|
30
|
+
const FUTURE_LIMIT_MS = 24 * 60 * 60 * 1000;
|
|
31
|
+
|
|
32
|
+
function newState({ now = new Date() } = {}) {
|
|
33
|
+
return {
|
|
34
|
+
cutoff: now.getTime() + FUTURE_LIMIT_MS,
|
|
35
|
+
items: new Map(),
|
|
36
|
+
final: new Set(),
|
|
37
|
+
tracked: new Map(),
|
|
38
|
+
merged: new Map(),
|
|
39
|
+
goals: new Map(),
|
|
40
|
+
releases: new Map(),
|
|
41
|
+
conflicts: [],
|
|
42
|
+
newestAt: null,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function conflict(event , code , reason ) {
|
|
47
|
+
return { event: event.id, type: event.type, reason, code };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function touch(item , event ) {
|
|
51
|
+
item.history.push({ event: event.id, type: event.type, at: event.at, by: event.by });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function itemFor(state , event , id ) {
|
|
55
|
+
const item = state.items.get(id);
|
|
56
|
+
if (!item) return { problem: conflict(event, 'unknown-id', `${id} is not a follow-up`) };
|
|
57
|
+
if (state.final.has(id)) return { problem: conflict(event, 'illegal-transition', `${id} is done and accepts no later event`) };
|
|
58
|
+
return { item };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── follow-ups ─────────────────────────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
function applyAdded(state , event ) {
|
|
64
|
+
const d = event.data;
|
|
65
|
+
if (!isText(d.id) || !isText(d.statement) || !d.source || typeof d.source !== 'object' || !isText(d.source.kind)) {
|
|
66
|
+
return [conflict(event, 'malformed', 'followup.added needs id, statement and source.kind')];
|
|
67
|
+
}
|
|
68
|
+
if (state.items.has(d.id)) return [conflict(event, 'illegal-transition', `${d.id} was already added`)];
|
|
69
|
+
const item = {
|
|
70
|
+
id: d.id,
|
|
71
|
+
statement: d.statement,
|
|
72
|
+
source: d.source,
|
|
73
|
+
state: 'open',
|
|
74
|
+
takenBy: null,
|
|
75
|
+
intent: null,
|
|
76
|
+
fix: null,
|
|
77
|
+
added: event.at.slice(0, 10),
|
|
78
|
+
excerpt: typeof d.excerpt === 'string' ? d.excerpt : null,
|
|
79
|
+
body: null,
|
|
80
|
+
history: [],
|
|
81
|
+
};
|
|
82
|
+
if (d.source.kind === 'report') {
|
|
83
|
+
item.bodyRef = typeof d.bodyRef === 'string' ? d.bodyRef : null;
|
|
84
|
+
item.bodyBytes = Number.isInteger(d.bodyBytes) ? d.bodyBytes : null;
|
|
85
|
+
}
|
|
86
|
+
touch(item, event);
|
|
87
|
+
state.items.set(d.id, item);
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function applyTaken(state , event ) {
|
|
92
|
+
const d = event.data;
|
|
93
|
+
if (!isIdList(d.ids) || !isText(d.feature)) return [conflict(event, 'malformed', 'followup.taken needs ids and feature')];
|
|
94
|
+
const problems = [];
|
|
95
|
+
for (const id of d.ids) {
|
|
96
|
+
const { item, problem } = itemFor(state, event, id);
|
|
97
|
+
if (problem) { problems.push(problem); continue; }
|
|
98
|
+
if (item.state !== 'open') { problems.push(conflict(event, 'illegal-transition', `${id} is ${item.state}; only an open item can be taken`)); continue; }
|
|
99
|
+
if (!state.tracked.has(d.feature)) { problems.push(conflict(event, 'untracked-feature', `${d.feature} is not a tracked feature`)); continue; }
|
|
100
|
+
item.state = 'taken';
|
|
101
|
+
item.takenBy = d.feature;
|
|
102
|
+
touch(item, event);
|
|
103
|
+
}
|
|
104
|
+
return problems;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function settleOne(state , event , id ) {
|
|
108
|
+
const d = event.data;
|
|
109
|
+
const { item, problem } = itemFor(state, event, id);
|
|
110
|
+
if (problem) return problem;
|
|
111
|
+
const refuse = (reason ) => conflict(event, 'illegal-transition', reason);
|
|
112
|
+
switch (d.as) {
|
|
113
|
+
case 'kept':
|
|
114
|
+
// IC-003: a reason is required when a taken item is released or a dismissed one reopens, not for an open one.
|
|
115
|
+
if (item.state !== 'open' && !isText(d.reason)) return conflict(event, 'reason-required', `settling ${id} as kept needs a reason`);
|
|
116
|
+
if (item.state === 'taken') item.takenBy = null;
|
|
117
|
+
item.state = 'open';
|
|
118
|
+
break;
|
|
119
|
+
case 'dismissed':
|
|
120
|
+
if (item.state !== 'open') return refuse(`${id} is ${item.state}; only an open item can be dismissed`);
|
|
121
|
+
if (!isText(d.reason)) return conflict(event, 'reason-required', `dismissing ${id} needs a reason`);
|
|
122
|
+
item.state = 'dismissed';
|
|
123
|
+
break;
|
|
124
|
+
case 'fix':
|
|
125
|
+
if (item.state !== 'open') return refuse(`${id} is ${item.state}; only an open item can be routed to a fix`);
|
|
126
|
+
if (!isText(d.reason)) return conflict(event, 'reason-required', `routing ${id} to a fix needs a reason naming where`);
|
|
127
|
+
item.fix = d.reason;
|
|
128
|
+
break;
|
|
129
|
+
case 'done':
|
|
130
|
+
if (item.state !== 'open') return refuse(`${id} is ${item.state}; only an open item can be settled as done`);
|
|
131
|
+
if (!isText(d.evidence)) return conflict(event, 'evidence-required', `settling ${id} as done needs evidence`);
|
|
132
|
+
item.state = 'done';
|
|
133
|
+
state.final.add(id);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
return conflict(event, 'malformed', `followup.settled needs as to be one of ${SETTLE_AS.join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
touch(item, event);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function applySettled(state , event ) {
|
|
143
|
+
const d = event.data;
|
|
144
|
+
// The legacy single-id shape (`id`) and the batch shape (`ids`) both fold; the verb writes one event per id.
|
|
145
|
+
const ids = isText(d.id) ? [d.id] : d.ids;
|
|
146
|
+
if (!isIdList(ids)) return [conflict(event, 'malformed', 'followup.settled needs an id')];
|
|
147
|
+
return ids.map((id ) => settleOne(state, event, id)).filter(Boolean);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function applyPromoted(state , event ) {
|
|
151
|
+
const d = event.data;
|
|
152
|
+
if (!isIdList(d.ids) || !isText(d.intent)) return [conflict(event, 'malformed', 'followup.promoted needs ids and intent')];
|
|
153
|
+
const problems = [];
|
|
154
|
+
for (const id of d.ids) {
|
|
155
|
+
const { item, problem } = itemFor(state, event, id);
|
|
156
|
+
if (problem) { problems.push(problem); continue; }
|
|
157
|
+
if (item.state !== 'open') { problems.push(conflict(event, 'illegal-transition', `${id} is ${item.state}; only an open item can be promoted`)); continue; }
|
|
158
|
+
if (item.intent) { problems.push(conflict(event, 'intent-exists', `${id} was already promoted to ${item.intent}`)); continue; }
|
|
159
|
+
item.intent = d.intent;
|
|
160
|
+
touch(item, event);
|
|
161
|
+
}
|
|
162
|
+
return problems;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ── features, goals, releases ──────────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
function applyTracked(state , event ) {
|
|
168
|
+
const slug = event.data.slug;
|
|
169
|
+
if (!isText(slug)) return [conflict(event, 'malformed', 'feature.tracked needs a slug')];
|
|
170
|
+
// The earliest event counts; a later one from another clone changes nothing and is no conflict.
|
|
171
|
+
if (!state.tracked.has(slug)) state.tracked.set(slug, { slug, trackedAt: event.at, goal: null });
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function applyMerged(state , event ) {
|
|
176
|
+
const { slug, reason } = event.data;
|
|
177
|
+
if (!isText(slug)) return [conflict(event, 'malformed', 'feature.merged needs a slug')];
|
|
178
|
+
if (!state.merged.has(slug)) state.merged.set(slug, { slug, reason: typeof reason === 'string' ? reason : '', at: event.at });
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function goalFor(state , event , id ) {
|
|
183
|
+
const goal = state.goals.get(id);
|
|
184
|
+
return goal ? { goal } : { problem: conflict(event, 'unknown-goal', `${id} is not a goal`) };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function applyGoalAdded(state , event ) {
|
|
188
|
+
const d = event.data;
|
|
189
|
+
if (!isText(d.goal) || !Array.isArray(d.items)) return [conflict(event, 'malformed', 'goal.added needs goal and items')];
|
|
190
|
+
// A second `goal.added` for one id, as another clone may write, loses: the first wins.
|
|
191
|
+
if (state.goals.has(d.goal)) return [conflict(event, 'goal-exists', `${d.goal} already exists`)];
|
|
192
|
+
state.goals.set(d.goal, {
|
|
193
|
+
goal: d.goal,
|
|
194
|
+
outcome: typeof d.outcome === 'string' ? d.outcome : '',
|
|
195
|
+
status: 'open',
|
|
196
|
+
reason: null,
|
|
197
|
+
added: event.at.slice(0, 10),
|
|
198
|
+
items: d.items.filter((i ) => i && isText(i.id)).map((i ) => ({ id: i.id, text: String(i.text ?? ''), met: false, evidence: null })),
|
|
199
|
+
});
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function applyGoalItemAdded(state , event ) {
|
|
204
|
+
const d = event.data;
|
|
205
|
+
const { goal, problem } = goalFor(state, event, d.goal);
|
|
206
|
+
if (problem) return [problem];
|
|
207
|
+
if (!d.item || !isText(d.item.id)) return [conflict(event, 'malformed', 'goal.item-added needs item.id')];
|
|
208
|
+
if (goal.items.some((i ) => i.id === d.item.id)) return [conflict(event, 'illegal-transition', `${d.goal} already has item ${d.item.id}`)];
|
|
209
|
+
goal.items.push({ id: d.item.id, text: String(d.item.text ?? ''), met: false, evidence: null });
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function applyGoalChecked(state , event ) {
|
|
214
|
+
const d = event.data;
|
|
215
|
+
const { goal, problem } = goalFor(state, event, d.goal);
|
|
216
|
+
if (problem) return [problem];
|
|
217
|
+
const item = goal.items.find((i ) => i.id === d.item);
|
|
218
|
+
if (!item) return [conflict(event, 'unknown-item', `${d.goal} has no item ${d.item}`)];
|
|
219
|
+
if (!isText(d.evidence)) return [conflict(event, 'evidence-required', 'goal.checked needs evidence')];
|
|
220
|
+
item.met = d.met === true;
|
|
221
|
+
item.evidence = d.evidence;
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function applyGoalLinked(state , event ) {
|
|
226
|
+
const d = event.data;
|
|
227
|
+
const { problem } = goalFor(state, event, d.goal);
|
|
228
|
+
if (problem) return [problem];
|
|
229
|
+
const feature = state.tracked.get(d.slug);
|
|
230
|
+
if (!feature) return [conflict(event, 'untracked-feature', `${d.slug} is not a tracked feature`)];
|
|
231
|
+
if (feature.goal && feature.goal !== d.goal && d.replace !== true) {
|
|
232
|
+
return [conflict(event, 'goal-already-linked', `${d.slug} already serves ${feature.goal}`)];
|
|
233
|
+
}
|
|
234
|
+
feature.goal = d.goal;
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function applyGoalDone(state , event ) {
|
|
239
|
+
const d = event.data;
|
|
240
|
+
const { goal, problem } = goalFor(state, event, d.goal);
|
|
241
|
+
if (problem) return [problem];
|
|
242
|
+
goal.status = 'done';
|
|
243
|
+
goal.reason = typeof d.reason === 'string' && d.reason !== '' ? d.reason : null;
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function applyReleaseRecorded(state , event ) {
|
|
248
|
+
const d = event.data;
|
|
249
|
+
if (!isText(d.tag)) return [conflict(event, 'malformed', 'release.recorded needs a tag')];
|
|
250
|
+
let release = state.releases.get(d.tag);
|
|
251
|
+
if (!release) {
|
|
252
|
+
release = { tag: d.tag, commit: null, features: new Map(), excluded: new Set() };
|
|
253
|
+
state.releases.set(d.tag, release);
|
|
254
|
+
}
|
|
255
|
+
if (isText(d.commit)) release.commit = d.commit;
|
|
256
|
+
for (const f of Array.isArray(d.features) ? d.features : []) {
|
|
257
|
+
if (f && isText(f.slug) && !release.features.has(f.slug)) release.features.set(f.slug, { slug: f.slug, evidence: f.evidence ?? null, ref: f.ref ?? null });
|
|
258
|
+
}
|
|
259
|
+
for (const slug of Array.isArray(d.excluded) ? d.excluded : []) if (isText(slug)) release.excluded.add(slug);
|
|
260
|
+
return [];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const APPLY = {
|
|
264
|
+
'followup.added': applyAdded,
|
|
265
|
+
'followup.taken': applyTaken,
|
|
266
|
+
'followup.settled': applySettled,
|
|
267
|
+
'followup.promoted': applyPromoted,
|
|
268
|
+
'feature.tracked': applyTracked,
|
|
269
|
+
'feature.merged': applyMerged,
|
|
270
|
+
'goal.added': applyGoalAdded,
|
|
271
|
+
'goal.item-added': applyGoalItemAdded,
|
|
272
|
+
'goal.checked': applyGoalChecked,
|
|
273
|
+
'goal.linked': applyGoalLinked,
|
|
274
|
+
'goal.done': applyGoalDone,
|
|
275
|
+
'release.recorded': applyReleaseRecorded,
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/** The event types this fold understands; any other type is kept out of the state, not a conflict. */
|
|
279
|
+
const EVENT_TYPES = Object.keys(APPLY);
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Applies one event to a state, recording what is illegal. Callers that write use the returned
|
|
283
|
+
* conflicts to refuse before anything is written.
|
|
284
|
+
* @returns {Array<{event:string,type:string,reason:string,code:string}>} the conflicts this event raised
|
|
285
|
+
*/
|
|
286
|
+
function applyEvent(state , event , { checkFuture = true } = {}) {
|
|
287
|
+
const at = Date.parse(event.at);
|
|
288
|
+
if (checkFuture && at > state.cutoff) {
|
|
289
|
+
// Left out of the stamping floor and of every tracking bound: one wrong clock must not move them.
|
|
290
|
+
const raised = [conflict(event, 'future-event', 'dated more than 24 hours in the future; left out of the fold')];
|
|
291
|
+
state.conflicts.push(...raised);
|
|
292
|
+
return raised;
|
|
293
|
+
}
|
|
294
|
+
if (state.newestAt === null || at > state.newestAt) state.newestAt = at;
|
|
295
|
+
const apply = APPLY[event.type];
|
|
296
|
+
if (!apply) return [];
|
|
297
|
+
const data = event.data && typeof event.data === 'object' ? event.data : {};
|
|
298
|
+
const raised = apply(state, { ...event, data });
|
|
299
|
+
state.conflicts.push(...raised);
|
|
300
|
+
return raised;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** @param {Array<Object>} events IC-002 envelopes, in any order */
|
|
304
|
+
function foldInto(events , options = {}) {
|
|
305
|
+
const state = newState(options);
|
|
306
|
+
if (options.shouldStop?.()) { state.incomplete = true; return state; }
|
|
307
|
+
const ordered = [...events].sort(byOrder);
|
|
308
|
+
if (options.shouldStop?.()) { state.incomplete = true; return state; }
|
|
309
|
+
for (const event of ordered) {
|
|
310
|
+
if (options.shouldStop?.()) { state.incomplete = true; break; }
|
|
311
|
+
applyEvent(state, event);
|
|
312
|
+
}
|
|
313
|
+
if (options.shouldStop?.()) state.incomplete = true;
|
|
314
|
+
return state;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** The result of a fold, as plain data. `hasBody(item)` tells a report whose body is on this machine. */
|
|
318
|
+
function finalize(state , { hasBody = () => false } = {}) {
|
|
319
|
+
const followups = [...state.items.values()].map((item ) => (
|
|
320
|
+
item.source.kind === 'report' ? { ...item, body: hasBody(item) ? 'on-this-machine' : 'not-on-this-machine' } : item));
|
|
321
|
+
const releases = [...state.releases.values()].map((r ) => {
|
|
322
|
+
const excluded = [...r.excluded];
|
|
323
|
+
return { tag: r.tag, commit: r.commit, features: [...r.features.values()].filter((f ) => !r.excluded.has(f.slug)), excluded };
|
|
324
|
+
});
|
|
325
|
+
return {
|
|
326
|
+
followups,
|
|
327
|
+
features: [...state.tracked.values()].map((f ) => ({ ...f })),
|
|
328
|
+
merged: [...state.merged.values()],
|
|
329
|
+
goals: [...state.goals.values()],
|
|
330
|
+
releases,
|
|
331
|
+
conflicts: state.conflicts,
|
|
332
|
+
newestAt: state.newestAt === null ? null : new Date(state.newestAt).toISOString(),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** @returns {ReturnType<typeof finalize>} */
|
|
337
|
+
function foldEvents(events , options = {}) {
|
|
338
|
+
return finalize(foldInto(events, options), options);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* A taken item whose feature derives `finished` (IC-021) shows as `done`. Derived on read and never
|
|
343
|
+
* written: a later read that derives anything else shows the item as `taken` again (design R9).
|
|
344
|
+
* @param {Array<Object>} followups folded items
|
|
345
|
+
* @param {Object<string,string>|Map<string,string>} statuses feature slug to derived status
|
|
346
|
+
*/
|
|
347
|
+
function withDerivedDone(followups , statuses ) {
|
|
348
|
+
const statusOf = (slug ) => (statuses instanceof Map ? statuses.get(slug) : statuses[slug]);
|
|
349
|
+
return followups.map((item ) => (
|
|
350
|
+
item.state === 'taken' && statusOf(item.takenBy) === 'finished' ? { ...item, state: 'done', derived: true } : item));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
module.exports = { foldEvents, foldInto, finalize, applyEvent, newState, withDerivedDone, byOrder, EVENT_TYPES, SETTLE_AS };
|