@tacuchi/agent-workflow-cli 25.7.0 → 25.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- package/README.md +5 -1
- package/dist/adapters/git-cli.js +311 -24
- package/dist/adapters/git-cli.js.map +1 -1
- package/dist/adapters/node-file-system.js +48 -0
- package/dist/adapters/node-file-system.js.map +1 -1
- package/dist/application/amend-service.js +51 -14
- package/dist/application/amend-service.js.map +1 -1
- package/dist/application/branch-resolver.js +6 -3
- package/dist/application/branch-resolver.js.map +1 -1
- package/dist/application/capability/design-handler.js +124 -43
- package/dist/application/capability/design-handler.js.map +1 -1
- package/dist/application/capability/dispatcher.js +4 -1
- package/dist/application/capability/dispatcher.js.map +1 -1
- package/dist/application/capability/durable-effect.js +3 -0
- package/dist/application/capability/durable-effect.js.map +1 -1
- package/dist/application/capability/readiness.js +26 -10
- package/dist/application/capability/readiness.js.map +1 -1
- package/dist/application/capability/wrapper.js +10 -3
- package/dist/application/capability/wrapper.js.map +1 -1
- package/dist/application/check-branch-service.js +158 -19
- package/dist/application/check-branch-service.js.map +1 -1
- package/dist/application/checkpoint/markdown.js +2 -2
- package/dist/application/checkpoint/markdown.js.map +1 -1
- package/dist/application/checkpoint/state-reader.js +12 -0
- package/dist/application/checkpoint/state-reader.js.map +1 -1
- package/dist/application/checkpoint-service.js +12 -4
- package/dist/application/checkpoint-service.js.map +1 -1
- package/dist/application/checkpoint-write-service.js +91 -17
- package/dist/application/checkpoint-write-service.js.map +1 -1
- package/dist/application/claims-ledger.js +137 -11
- package/dist/application/claims-ledger.js.map +1 -1
- package/dist/application/claims-recovery.js +85 -44
- package/dist/application/claims-recovery.js.map +1 -1
- package/dist/application/database-tool-catalog.js +33 -0
- package/dist/application/database-tool-catalog.js.map +1 -1
- package/dist/application/design/consumer-document.js +2 -2
- package/dist/application/design/consumer-document.js.map +1 -1
- package/dist/application/design/design-content-gate-service.js +20 -2
- package/dist/application/design/design-content-gate-service.js.map +1 -1
- package/dist/application/design/design-gate-service.js +2 -0
- package/dist/application/design/design-gate-service.js.map +1 -1
- package/dist/application/design/design-index-service.js +4 -0
- package/dist/application/design/design-index-service.js.map +1 -1
- package/dist/application/design/design-publish-service.js +1 -4
- package/dist/application/design/design-publish-service.js.map +1 -1
- package/dist/application/design/design-record-service.js +13 -7
- package/dist/application/design/design-record-service.js.map +1 -1
- package/dist/application/design/design-resolver-service.js +22 -3
- package/dist/application/design/design-resolver-service.js.map +1 -1
- package/dist/application/design/design-simple-service.js +24 -5
- package/dist/application/design/design-simple-service.js.map +1 -1
- package/dist/application/design/digest.js +41 -0
- package/dist/application/design/digest.js.map +1 -0
- package/dist/application/dev-only-services.js +171 -27
- package/dist/application/dev-only-services.js.map +1 -1
- package/dist/application/doc-branch-ledger.js +145 -0
- package/dist/application/doc-branch-ledger.js.map +1 -0
- package/dist/application/docs-canon-service.js +1 -1
- package/dist/application/docs-canon-service.js.map +1 -1
- package/dist/application/doctor/dist-integrity.js +113 -0
- package/dist/application/doctor/dist-integrity.js.map +1 -0
- package/dist/application/doctor/hosts.js +5 -2
- package/dist/application/doctor/hosts.js.map +1 -1
- package/dist/application/doctor/prepare.js +4 -1
- package/dist/application/doctor/prepare.js.map +1 -1
- package/dist/application/doctor/provider-installation.js +39 -19
- package/dist/application/doctor/provider-installation.js.map +1 -1
- package/dist/application/doctor/provider-mcps.js +10 -2
- package/dist/application/doctor/provider-mcps.js.map +1 -1
- package/dist/application/doctor/provider-skills.js +25 -0
- package/dist/application/doctor/provider-skills.js.map +1 -1
- package/dist/application/doctor/provider-visibility.js +76 -3
- package/dist/application/doctor/provider-visibility.js.map +1 -1
- package/dist/application/doctor/provider-workspace-block.js +156 -0
- package/dist/application/doctor/provider-workspace-block.js.map +1 -0
- package/dist/application/doctor/repair-runner.js +47 -3
- package/dist/application/doctor/repair-runner.js.map +1 -1
- package/dist/application/doctor/report.js +24 -4
- package/dist/application/doctor/report.js.map +1 -1
- package/dist/application/doctor/skills-toml-migrate.js +76 -0
- package/dist/application/doctor/skills-toml-migrate.js.map +1 -0
- package/dist/application/export-catalog-check.js +200 -0
- package/dist/application/export-catalog-check.js.map +1 -0
- package/dist/application/export-service.js +716 -79
- package/dist/application/export-service.js.map +1 -1
- package/dist/application/fix-git-service.js +285 -64
- package/dist/application/fix-git-service.js.map +1 -1
- package/dist/application/flow/advance.js +241 -30
- package/dist/application/flow/advance.js.map +1 -1
- package/dist/application/flow/annul-service.js +3 -1
- package/dist/application/flow/annul-service.js.map +1 -1
- package/dist/application/flow/batch-commit.js +189 -0
- package/dist/application/flow/batch-commit.js.map +1 -0
- package/dist/application/flow/checkout-observation.js +110 -8
- package/dist/application/flow/checkout-observation.js.map +1 -1
- package/dist/application/flow/close-artifacts.js +105 -0
- package/dist/application/flow/close-artifacts.js.map +1 -0
- package/dist/application/flow/close-at-boundary.js +155 -0
- package/dist/application/flow/close-at-boundary.js.map +1 -0
- package/dist/application/flow/close-document-guidance.js +70 -0
- package/dist/application/flow/close-document-guidance.js.map +1 -0
- package/dist/application/flow/flow-service.js +49 -5
- package/dist/application/flow/flow-service.js.map +1 -1
- package/dist/application/flow/internal-actions.js +361 -80
- package/dist/application/flow/internal-actions.js.map +1 -1
- package/dist/application/flow/internal-drive.js +47 -19
- package/dist/application/flow/internal-drive.js.map +1 -1
- package/dist/application/flow/plan-entry.js +82 -0
- package/dist/application/flow/plan-entry.js.map +1 -0
- package/dist/application/flow/prove.js +32 -1
- package/dist/application/flow/prove.js.map +1 -1
- package/dist/application/flow/quick-checkouts.js +48 -0
- package/dist/application/flow/quick-checkouts.js.map +1 -0
- package/dist/application/flow/reinfer-batch.js +177 -0
- package/dist/application/flow/reinfer-batch.js.map +1 -0
- package/dist/application/flow/reopen-run.js +159 -0
- package/dist/application/flow/reopen-run.js.map +1 -0
- package/dist/application/flow/run-journey.js +11 -8
- package/dist/application/flow/run-journey.js.map +1 -1
- package/dist/application/flow/run-projection.js +16 -5
- package/dist/application/flow/run-projection.js.map +1 -1
- package/dist/application/flow/run-state-service.js +3 -1
- package/dist/application/flow/run-state-service.js.map +1 -1
- package/dist/application/flow/submit.js +731 -154
- package/dist/application/flow/submit.js.map +1 -1
- package/dist/application/generate-launch-service.js +16 -6
- package/dist/application/generate-launch-service.js.map +1 -1
- package/dist/application/git-flow-service.js +34 -3
- package/dist/application/git-flow-service.js.map +1 -1
- package/dist/application/history-publications.js +24 -0
- package/dist/application/history-publications.js.map +1 -1
- package/dist/application/history-reconcile-service.js +45 -0
- package/dist/application/history-reconcile-service.js.map +1 -0
- package/dist/application/history-table.js +61 -12
- package/dist/application/history-table.js.map +1 -1
- package/dist/application/history-update-service.js +25 -4
- package/dist/application/history-update-service.js.map +1 -1
- package/dist/application/hook-branch-check.js +25 -3
- package/dist/application/hook-branch-check.js.map +1 -1
- package/dist/application/hook-git-commit-advisor.js +3 -4
- package/dist/application/hook-git-commit-advisor.js.map +1 -1
- package/dist/application/hook-sql-mutation-guard.js +147 -12
- package/dist/application/hook-sql-mutation-guard.js.map +1 -1
- package/dist/application/hook-turn-start.js +51 -0
- package/dist/application/hook-turn-start.js.map +1 -0
- package/dist/application/host-memory/codex.js +1 -1
- package/dist/application/host-memory/codex.js.map +1 -1
- package/dist/application/hub-registry.js +135 -0
- package/dist/application/hub-registry.js.map +1 -0
- package/dist/application/local-proposal.js +72 -19
- package/dist/application/local-proposal.js.map +1 -1
- package/dist/application/mcp-host-reader.js +1 -1
- package/dist/application/mcp-host-reader.js.map +1 -1
- package/dist/application/mcp-host-writer.js +16 -10
- package/dist/application/mcp-host-writer.js.map +1 -1
- package/dist/application/merge-state-service.js +150 -34
- package/dist/application/merge-state-service.js.map +1 -1
- package/dist/application/multiroot/claude.js +17 -10
- package/dist/application/multiroot/claude.js.map +1 -1
- package/dist/application/multiroot/codex.js +17 -11
- package/dist/application/multiroot/codex.js.map +1 -1
- package/dist/application/multiroot-service.js +52 -28
- package/dist/application/multiroot-service.js.map +1 -1
- package/dist/application/parsers/execution-batches.js +64 -0
- package/dist/application/parsers/execution-batches.js.map +1 -0
- package/dist/application/parsers/phases.js +23 -2
- package/dist/application/parsers/phases.js.map +1 -1
- package/dist/application/parsers/project-block.js +146 -17
- package/dist/application/parsers/project-block.js.map +1 -1
- package/dist/application/parsers/tasks.js +16 -2
- package/dist/application/parsers/tasks.js.map +1 -1
- package/dist/application/parsers/toml.js +19 -0
- package/dist/application/parsers/toml.js.map +1 -0
- package/dist/application/paths-service.js +13 -16
- package/dist/application/paths-service.js.map +1 -1
- package/dist/application/persist-service.js +118 -5
- package/dist/application/persist-service.js.map +1 -1
- package/dist/application/plan-exec-batch-service.js +162 -22
- package/dist/application/plan-exec-batch-service.js.map +1 -1
- package/dist/application/plan-exec-decision-service.js +61 -12
- package/dist/application/plan-exec-decision-service.js.map +1 -1
- package/dist/application/plan-exec-plan-diff.js +105 -0
- package/dist/application/plan-exec-plan-diff.js.map +1 -0
- package/dist/application/plan-lint-service.js +2 -0
- package/dist/application/plan-lint-service.js.map +1 -1
- package/dist/application/plan-passes.js +41 -0
- package/dist/application/plan-passes.js.map +1 -0
- package/dist/application/preparation-receipts.js +58 -0
- package/dist/application/preparation-receipts.js.map +1 -0
- package/dist/application/project-md-upsert-service.js +191 -52
- package/dist/application/project-md-upsert-service.js.map +1 -1
- package/dist/application/project-tab-data.js +40 -10
- package/dist/application/project-tab-data.js.map +1 -1
- package/dist/application/release-data/artifacts.js +15 -7
- package/dist/application/release-data/artifacts.js.map +1 -1
- package/dist/application/release-data/bundles.js +52 -6
- package/dist/application/release-data/bundles.js.map +1 -1
- package/dist/application/release-data/common.js +2 -2
- package/dist/application/release-data/common.js.map +1 -1
- package/dist/application/release-data/rollback.js +7 -0
- package/dist/application/release-data/rollback.js.map +1 -0
- package/dist/application/release-data/sessions.js +2 -2
- package/dist/application/release-data/sessions.js.map +1 -1
- package/dist/application/release-pass-ledger.js +1 -1
- package/dist/application/render/history-row.js +2 -0
- package/dist/application/render/history-row.js.map +1 -1
- package/dist/application/render/project-block.js +28 -11
- package/dist/application/render/project-block.js.map +1 -1
- package/dist/application/reseal-service.js +1 -0
- package/dist/application/reseal-service.js.map +1 -1
- package/dist/application/resume-service.js +55 -8
- package/dist/application/resume-service.js.map +1 -1
- package/dist/application/retirement/apply.js +25 -7
- package/dist/application/retirement/apply.js.map +1 -1
- package/dist/application/retirement/attribution.js +121 -48
- package/dist/application/retirement/attribution.js.map +1 -1
- package/dist/application/retirement/prepare.js +17 -11
- package/dist/application/retirement/prepare.js.map +1 -1
- package/dist/application/retirement/preview.js +2 -1
- package/dist/application/retirement/preview.js.map +1 -1
- package/dist/application/self/codex-plugin.js +1 -1
- package/dist/application/self/codex-plugin.js.map +1 -1
- package/dist/application/self/host-states.js +3 -3
- package/dist/application/self/host-states.js.map +1 -1
- package/dist/application/self/install-hooks.js +1 -1
- package/dist/application/self/install-hooks.js.map +1 -1
- package/dist/application/self/install-skill.js +35 -11
- package/dist/application/self/install-skill.js.map +1 -1
- package/dist/application/self/install-targets.js +73 -2
- package/dist/application/self/install-targets.js.map +1 -1
- package/dist/application/self/mcp-config.js +19 -11
- package/dist/application/self/mcp-config.js.map +1 -1
- package/dist/application/self/opencode-plugin.js +1 -0
- package/dist/application/self/opencode-plugin.js.map +1 -1
- package/dist/application/self/uninstall.js +22 -8
- package/dist/application/self/uninstall.js.map +1 -1
- package/dist/application/semantic-operation/protocol.js +66 -5
- package/dist/application/semantic-operation/protocol.js.map +1 -1
- package/dist/application/session-archive-service.js +113 -0
- package/dist/application/session-archive-service.js.map +1 -0
- package/dist/application/session-binding-service.js +35 -0
- package/dist/application/session-binding-service.js.map +1 -1
- package/dist/application/session-close-service.js +390 -54
- package/dist/application/session-close-service.js.map +1 -1
- package/dist/application/session-create-service.js +97 -5
- package/dist/application/session-create-service.js.map +1 -1
- package/dist/application/session-custody-recorder.js +15 -12
- package/dist/application/session-custody-recorder.js.map +1 -1
- package/dist/application/session-custody-service.js +1 -0
- package/dist/application/session-custody-service.js.map +1 -1
- package/dist/application/session-narrative.js +51 -12
- package/dist/application/session-narrative.js.map +1 -1
- package/dist/application/session-pause-service.js +46 -0
- package/dist/application/session-pause-service.js.map +1 -0
- package/dist/application/session-resolver.js +36 -11
- package/dist/application/session-resolver.js.map +1 -1
- package/dist/application/session-resume-service.js +190 -20
- package/dist/application/session-resume-service.js.map +1 -1
- package/dist/application/sessions-service.js +4 -0
- package/dist/application/sessions-service.js.map +1 -1
- package/dist/application/sessions-sweep-service.js +77 -0
- package/dist/application/sessions-sweep-service.js.map +1 -0
- package/dist/application/settle-service.js +3 -1
- package/dist/application/settle-service.js.map +1 -1
- package/dist/application/skills-resolver-service.js +1 -1
- package/dist/application/skills-resolver-service.js.map +1 -1
- package/dist/application/source-add-service.js +37 -0
- package/dist/application/source-add-service.js.map +1 -0
- package/dist/application/source-boundary-policy.js +97 -8
- package/dist/application/source-boundary-policy.js.map +1 -1
- package/dist/application/source-pipeline.js +68 -0
- package/dist/application/source-pipeline.js.map +1 -0
- package/dist/application/source-remove-service.js +15 -3
- package/dist/application/source-remove-service.js.map +1 -1
- package/dist/application/sources-service.js +71 -16
- package/dist/application/sources-service.js.map +1 -1
- package/dist/application/status-service.js +55 -5
- package/dist/application/status-service.js.map +1 -1
- package/dist/application/unit-dependencies.js +100 -0
- package/dist/application/unit-dependencies.js.map +1 -0
- package/dist/application/unit-membership.js +37 -0
- package/dist/application/unit-membership.js.map +1 -0
- package/dist/application/unit-residue.js +72 -0
- package/dist/application/unit-residue.js.map +1 -0
- package/dist/application/visibility-doctor-service.js +66 -4
- package/dist/application/visibility-doctor-service.js.map +1 -1
- package/dist/application/working-branch-service.js +6 -0
- package/dist/application/working-branch-service.js.map +1 -1
- package/dist/application/workline-graph.js +1 -1
- package/dist/application/workline-graph.js.map +1 -1
- package/dist/application/workline-index-service.js +118 -17
- package/dist/application/workline-index-service.js.map +1 -1
- package/dist/application/workspace-commit-service.js +218 -0
- package/dist/application/workspace-commit-service.js.map +1 -0
- package/dist/application/workspace-init-service.js +64 -34
- package/dist/application/workspace-init-service.js.map +1 -1
- package/dist/application/workspace-local-config.js +90 -0
- package/dist/application/workspace-local-config.js.map +1 -0
- package/dist/application/workspace-materialization-service.js +52 -3
- package/dist/application/workspace-materialization-service.js.map +1 -1
- package/dist/application/workspace-migrate/apply.js +525 -4
- package/dist/application/workspace-migrate/apply.js.map +1 -1
- package/dist/application/workspace-migrate/markers.js +9 -6
- package/dist/application/workspace-migrate/markers.js.map +1 -1
- package/dist/application/workspace-migrate/plan.js +97 -5
- package/dist/application/workspace-migrate/plan.js.map +1 -1
- package/dist/application/workspace-move-service.js +270 -0
- package/dist/application/workspace-move-service.js.map +1 -0
- package/dist/application/workspace-untrack-service.js +28 -0
- package/dist/application/workspace-untrack-service.js.map +1 -0
- package/dist/application/worktree-service.js +654 -105
- package/dist/application/worktree-service.js.map +1 -1
- package/dist/cli/ascii.js +86 -0
- package/dist/cli/ascii.js.map +1 -0
- package/dist/cli/commands/add-source.js +38 -0
- package/dist/cli/commands/add-source.js.map +1 -0
- package/dist/cli/commands/amend.js +14 -2
- package/dist/cli/commands/amend.js.map +1 -1
- package/dist/cli/commands/capability.js +26 -0
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/check-branch.js +1 -0
- package/dist/cli/commands/check-branch.js.map +1 -1
- package/dist/cli/commands/checkpoint-read.js +1 -0
- package/dist/cli/commands/checkpoint-read.js.map +1 -1
- package/dist/cli/commands/checkpoint-write.js +4 -1
- package/dist/cli/commands/checkpoint-write.js.map +1 -1
- package/dist/cli/commands/claims.js +1 -0
- package/dist/cli/commands/claims.js.map +1 -1
- package/dist/cli/commands/code-scan.js +1 -0
- package/dist/cli/commands/code-scan.js.map +1 -1
- package/dist/cli/commands/context-budget.js +1 -0
- package/dist/cli/commands/context-budget.js.map +1 -1
- package/dist/cli/commands/context-plan.js +1 -0
- package/dist/cli/commands/context-plan.js.map +1 -1
- package/dist/cli/commands/cut-intent.js +1 -0
- package/dist/cli/commands/cut-intent.js.map +1 -1
- package/dist/cli/commands/designs.js +15 -5
- package/dist/cli/commands/designs.js.map +1 -1
- package/dist/cli/commands/dev-only.js +22 -5
- package/dist/cli/commands/dev-only.js.map +1 -1
- package/dist/cli/commands/doc-branch.js +184 -0
- package/dist/cli/commands/doc-branch.js.map +1 -0
- package/dist/cli/commands/doctor.js +9 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/export.js +89 -16
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/fix-git.js +89 -13
- package/dist/cli/commands/fix-git.js.map +1 -1
- package/dist/cli/commands/flow.js +129 -13
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/generate-launch.js +15 -2
- package/dist/cli/commands/generate-launch.js.map +1 -1
- package/dist/cli/commands/git-flow.js +1 -0
- package/dist/cli/commands/git-flow.js.map +1 -1
- package/dist/cli/commands/history-update.js +7 -9
- package/dist/cli/commands/history-update.js.map +1 -1
- package/dist/cli/commands/history.js +14 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/hook.js +26 -5
- package/dist/cli/commands/hook.js.map +1 -1
- package/dist/cli/commands/host-doctor.js +1 -0
- package/dist/cli/commands/host-doctor.js.map +1 -1
- package/dist/cli/commands/host-memory.js +2 -9
- package/dist/cli/commands/host-memory.js.map +1 -1
- package/dist/cli/commands/index.js +18 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/mcp.js +30 -4
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/merge-state.js +3 -2
- package/dist/cli/commands/merge-state.js.map +1 -1
- package/dist/cli/commands/multiroot.js +16 -0
- package/dist/cli/commands/multiroot.js.map +1 -1
- package/dist/cli/commands/persist.js +7 -5
- package/dist/cli/commands/persist.js.map +1 -1
- package/dist/cli/commands/plan.js +1 -0
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/plugin-cache.js +4 -0
- package/dist/cli/commands/plugin-cache.js.map +1 -1
- package/dist/cli/commands/plugin-doctor.js +3 -0
- package/dist/cli/commands/plugin-doctor.js.map +1 -1
- package/dist/cli/commands/project-md-upsert.js +8 -3
- package/dist/cli/commands/project-md-upsert.js.map +1 -1
- package/dist/cli/commands/release-data.js +12 -0
- package/dist/cli/commands/release-data.js.map +1 -1
- package/dist/cli/commands/release-pass.js +13 -3
- package/dist/cli/commands/release-pass.js.map +1 -1
- package/dist/cli/commands/remove-source.js +1 -0
- package/dist/cli/commands/remove-source.js.map +1 -1
- package/dist/cli/commands/reseal.js +1 -0
- package/dist/cli/commands/reseal.js.map +1 -1
- package/dist/cli/commands/resume-summary.js +5 -0
- package/dist/cli/commands/resume-summary.js.map +1 -1
- package/dist/cli/commands/resume.js +13 -3
- package/dist/cli/commands/resume.js.map +1 -1
- package/dist/cli/commands/retirement.js +1 -0
- package/dist/cli/commands/retirement.js.map +1 -1
- package/dist/cli/commands/self.js +39 -1
- package/dist/cli/commands/self.js.map +1 -1
- package/dist/cli/commands/session-artifacts.js +1 -0
- package/dist/cli/commands/session-artifacts.js.map +1 -1
- package/dist/cli/commands/session-close.js +185 -31
- package/dist/cli/commands/session-close.js.map +1 -1
- package/dist/cli/commands/session-create.js +4 -1
- package/dist/cli/commands/session-create.js.map +1 -1
- package/dist/cli/commands/session-pause.js +14 -0
- package/dist/cli/commands/session-pause.js.map +1 -0
- package/dist/cli/commands/session-resume.js +1 -0
- package/dist/cli/commands/session-resume.js.map +1 -1
- package/dist/cli/commands/sessions.js +16 -2
- package/dist/cli/commands/sessions.js.map +1 -1
- package/dist/cli/commands/set-branch.js +29 -4
- package/dist/cli/commands/set-branch.js.map +1 -1
- package/dist/cli/commands/set-edit-mode.js +20 -0
- package/dist/cli/commands/set-edit-mode.js.map +1 -0
- package/dist/cli/commands/set-pipeline.js +35 -0
- package/dist/cli/commands/set-pipeline.js.map +1 -0
- package/dist/cli/commands/settle.js +1 -0
- package/dist/cli/commands/settle.js.map +1 -1
- package/dist/cli/commands/skill-index.js +1 -0
- package/dist/cli/commands/skill-index.js.map +1 -1
- package/dist/cli/commands/skills.js +1 -0
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/sources.js +5 -0
- package/dist/cli/commands/sources.js.map +1 -1
- package/dist/cli/commands/stack.js +1 -0
- package/dist/cli/commands/stack.js.map +1 -1
- package/dist/cli/commands/status.js +36 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/tool.js +5 -21
- package/dist/cli/commands/tool.js.map +1 -1
- package/dist/cli/commands/unknown-flags.js +68 -16
- package/dist/cli/commands/unknown-flags.js.map +1 -1
- package/dist/cli/commands/visibility.js +2 -0
- package/dist/cli/commands/visibility.js.map +1 -1
- package/dist/cli/commands/workspace-commit.js +62 -0
- package/dist/cli/commands/workspace-commit.js.map +1 -0
- package/dist/cli/commands/workspace-init.js +51 -2
- package/dist/cli/commands/workspace-init.js.map +1 -1
- package/dist/cli/commands/workspace-migrate.js +31 -14
- package/dist/cli/commands/workspace-migrate.js.map +1 -1
- package/dist/cli/commands/workspace-move.js +42 -0
- package/dist/cli/commands/workspace-move.js.map +1 -0
- package/dist/cli/commands/worktree.js +5 -4
- package/dist/cli/commands/worktree.js.map +1 -1
- package/dist/cli/context-id.js +6 -0
- package/dist/cli/context-id.js.map +1 -1
- package/dist/cli/full-cli.js +555 -0
- package/dist/cli/full-cli.js.map +1 -0
- package/dist/cli/help-groups.js +108 -14
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/hook-stdin-cache.js +12 -0
- package/dist/cli/hook-stdin-cache.js.map +1 -0
- package/dist/cli/main.js +47 -471
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/output-mode.js +11 -2
- package/dist/cli/output-mode.js.map +1 -1
- package/dist/cli/parser.js +18 -5
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/render.js +30 -1
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/tui/app.js +1 -1
- package/dist/cli/tui/app.js.map +1 -1
- package/dist/cli/tui/components/workspace-init-form.js +4 -1
- package/dist/cli/tui/components/workspace-init-form.js.map +1 -1
- package/dist/cli/tui/data/recommended-skills.js +2 -2
- package/dist/cli/tui/data/recommended-skills.js.map +1 -1
- package/dist/cli/tui/data/workflow-content.js +6 -1
- package/dist/cli/tui/data/workflow-content.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab.js +4 -3
- package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
- package/dist/cli/tui/tabs/project-tab.js +7 -2
- package/dist/cli/tui/tabs/project-tab.js.map +1 -1
- package/dist/dist-manifest.json +4117 -0
- package/dist/domain/capability/protocol.js.map +1 -1
- package/dist/domain/decision-note.js +13 -0
- package/dist/domain/decision-note.js.map +1 -1
- package/dist/domain/design/artifact.js +22 -3
- package/dist/domain/design/artifact.js.map +1 -1
- package/dist/domain/design/capability.js +1 -0
- package/dist/domain/design/capability.js.map +1 -1
- package/dist/domain/design/expansion.js +1 -1
- package/dist/domain/design/expansion.js.map +1 -1
- package/dist/domain/design/maturity.js +16 -0
- package/dist/domain/design/maturity.js.map +1 -1
- package/dist/domain/design/reference.js +5 -0
- package/dist/domain/design/reference.js.map +1 -1
- package/dist/domain/doctor/operations.js +28 -2
- package/dist/domain/doctor/operations.js.map +1 -1
- package/dist/domain/effective-contract.js +3 -1
- package/dist/domain/effective-contract.js.map +1 -1
- package/dist/domain/elicitation.js +1 -1
- package/dist/domain/flow/answer.js +273 -130
- package/dist/domain/flow/answer.js.map +1 -1
- package/dist/domain/flow/authority.js +330 -44
- package/dist/domain/flow/authority.js.map +1 -1
- package/dist/domain/flow/batch-review.js +65 -0
- package/dist/domain/flow/batch-review.js.map +1 -0
- package/dist/domain/flow/decision-schema.js +47 -0
- package/dist/domain/flow/decision-schema.js.map +1 -0
- package/dist/domain/flow/directive.js +16 -0
- package/dist/domain/flow/directive.js.map +1 -1
- package/dist/domain/flow/execution-result.js +169 -9
- package/dist/domain/flow/execution-result.js.map +1 -1
- package/dist/domain/flow/route.js.map +1 -1
- package/dist/domain/flow/rules.js +5 -6
- package/dist/domain/flow/rules.js.map +1 -1
- package/dist/domain/flow/run-state.js +531 -47
- package/dist/domain/flow/run-state.js.map +1 -1
- package/dist/domain/flow/test-run-evidence.js +285 -0
- package/dist/domain/flow/test-run-evidence.js.map +1 -0
- package/dist/domain/flow/unchanged-phase.js +15 -0
- package/dist/domain/flow/unchanged-phase.js.map +1 -0
- package/dist/domain/harnesses.js +22 -6
- package/dist/domain/harnesses.js.map +1 -1
- package/dist/domain/isolation-unit.js +2 -2
- package/dist/domain/isolation-unit.js.map +1 -1
- package/dist/domain/lineage.js +7 -2
- package/dist/domain/lineage.js.map +1 -1
- package/dist/domain/obligation-correspondence.js +4 -2
- package/dist/domain/obligation-correspondence.js.map +1 -1
- package/dist/domain/plan-handoff.js +5 -0
- package/dist/domain/plan-handoff.js.map +1 -0
- package/dist/domain/proposal.js +18 -7
- package/dist/domain/proposal.js.map +1 -1
- package/dist/domain/reservation.js +5 -3
- package/dist/domain/reservation.js.map +1 -1
- package/dist/domain/retirement/proposal.js +1 -0
- package/dist/domain/retirement/proposal.js.map +1 -1
- package/dist/domain/session/custody.js +10 -6
- package/dist/domain/session/custody.js.map +1 -1
- package/dist/domain/session/narrative.js +4 -1
- package/dist/domain/session/narrative.js.map +1 -1
- package/dist/domain/skills.js +2 -0
- package/dist/domain/skills.js.map +1 -1
- package/dist/domain/sql-lexer.js +15 -2
- package/dist/domain/sql-lexer.js.map +1 -1
- package/dist/runtime/namespace-resolver.js +4 -0
- package/dist/runtime/namespace-resolver.js.map +1 -1
- package/dist/runtime/workline-marker.js +35 -8
- package/dist/runtime/workline-marker.js.map +1 -1
- package/dist/runtime/workspace-resolution.js +123 -0
- package/dist/runtime/workspace-resolution.js.map +1 -0
- package/package.json +5 -4
- package/skills/w/SKILL.md +3 -1
- package/skills/w/artifacts/artifacts-core/CHECKPOINT.md +1 -1
- package/skills/w/artifacts/artifacts-core/SCRIPTS.rollback.sql +8 -0
- package/skills/w/artifacts/artifacts-core/SCRIPTS.sql +4 -8
- package/skills/w/commands/export-diagrams.md +3 -3
- package/skills/w/commands/export-manuals.md +6 -6
- package/skills/w/commands/export-reports.md +3 -3
- package/skills/w/commands/export-scripts.md +5 -5
- package/skills/w/commands/fix-git.md +12 -13
- package/skills/w/commands/persist.md +2 -2
- package/skills/w/commands/plan-exec.md +4 -2
- package/skills/w/commands/spec-new.md +1 -1
- package/skills/w/commands/workspace-init.md +2 -0
- package/skills/w/context/MANIFEST.json +1 -1
- package/skills/w/exports/export-diagrams/EXPORT.md +3 -3
- package/skills/w/exports/export-manuals/EXPORT.md +14 -16
- package/skills/w/exports/export-reports/EXPORT.md +3 -3
- package/skills/w/exports/export-scripts/EXPORT.md +45 -21
- package/skills/w/harness/HARNESS.md +5 -3
- package/skills/w/hooks/hooks.template.json +6 -4
- package/skills/w/loops/CHASSIS.md +12 -6
- package/skills/w/loops/CODE-POLICIES.md +7 -4
- package/skills/w/loops/plan-exec-loop/LOOP.md +23 -22
- package/skills/w/loops/plan-new-loop/LOOP.md +23 -31
- package/skills/w/loops/plan-refine-loop/LOOP.md +8 -2
- package/skills/w/loops/quick-loop/LOOP.md +6 -5
- package/skills/w/modules/DESIGN-REFERENCES.md +9 -11
- package/skills/w/modules/PLAN-EXECUTION-BATCHES.md +4 -4
- package/skills/w/modules/SESSION-NUMBERING.md +2 -0
- package/skills/w/roles/design/CONTRACT.md +16 -7
- package/skills/w/roles/design/ROLE.md +4 -2
- package/skills/w/roles/git/ROLE.md +16 -9
- package/skills/w/roles/research/ROLE.md +1 -1
- package/skills/w/roles/sql/ROLE.md +16 -14
- package/skills/w/schemas/design/ui-screen.v1.schema.json +9 -0
|
@@ -25,34 +25,42 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { join } from "node:path";
|
|
27
27
|
import { dispositionOf } from "../../domain/flow/route.js";
|
|
28
|
-
import { withPlanExecBatch, withPlanExecBatchLoop, withSettlement, } from "../../domain/flow/run-state.js";
|
|
29
|
-
import {
|
|
28
|
+
import { legacyPlanExecCommits, withPlanExecBatch, withPlanExecBatchBase, withPlanExecBatchLoop, withPlanExecBatchUpdate, withSettlement, } from "../../domain/flow/run-state.js";
|
|
29
|
+
import { approvedValidationOnly } from "../../domain/flow/unchanged-phase.js";
|
|
30
|
+
import { canonicalEol, sealProposal } from "../../domain/proposal.js";
|
|
30
31
|
import { obligationExit } from "../../domain/reconciliation.js";
|
|
31
32
|
import { runArtifactsCommand } from "../artifacts-service.js";
|
|
32
|
-
import { appendClaimEvent, claimKey, claimShapedAmong, completedClaimsIn, ledgerPath,
|
|
33
|
+
import { appendClaimEvent, claimKey, claimShapedAmong, completedClaimsIn, ledgerPath, readClaimEvents, revokedAmong, } from "../claims-ledger.js";
|
|
33
34
|
import { applyLocalProposal } from "../local-proposal.js";
|
|
34
35
|
import { parseMdSectionBilingual } from "../markdown.js";
|
|
35
36
|
import { parsePhases } from "../parsers/phases.js";
|
|
36
|
-
import { parseTasks } from "../parsers/tasks.js";
|
|
37
37
|
import { resolveWorkspaceRoot } from "../paths-service.js";
|
|
38
|
-
import {
|
|
38
|
+
import { inferNextPlanExecBatch, preparePlanExecDoneSeal, publishPlanExecBatch, } from "../plan-exec-batch-service.js";
|
|
39
39
|
import { settlePlanExecObligations } from "../plan-exec-decision-service.js";
|
|
40
|
+
import { sealedPlanPath } from "../plan-exec-plan-diff.js";
|
|
40
41
|
import { readSessionArtifacts } from "../release-data/artifacts.js";
|
|
41
42
|
import { canonicalJson } from "../semantic-operation/protocol.js";
|
|
43
|
+
import { canonicalArtifactPath } from "../session-artifacts.js";
|
|
42
44
|
import { runSessionClose } from "../session-close-service.js";
|
|
43
45
|
import { recordPublication } from "../session-custody-recorder.js";
|
|
46
|
+
import { readCustody } from "../session-custody-service.js";
|
|
44
47
|
import { runStatusCommand } from "../status-service.js";
|
|
45
48
|
import { buildWorklineIndex } from "../workline-index-service.js";
|
|
46
|
-
import {
|
|
49
|
+
import { runWorkspaceCommit } from "../workspace-commit-service.js";
|
|
50
|
+
import { classifyListedUnits, runWorktree } from "../worktree-service.js";
|
|
51
|
+
import { commitBatch, verifyBatchGitState } from "./batch-commit.js";
|
|
52
|
+
import { observeScopedFingerprints, resolveCheckoutCandidates } from "./checkout-observation.js";
|
|
53
|
+
import { preserveBoundaryClose } from "./close-artifacts.js";
|
|
54
|
+
import { closeDocumentGuidance } from "./close-document-guidance.js";
|
|
47
55
|
import { projectRun } from "./run-projection.js";
|
|
48
56
|
import { applyUnderLock, locateRun, readRun } from "./run-state-service.js";
|
|
49
57
|
export function internalActionExecutor(deps) {
|
|
50
58
|
return async (plan, run) => {
|
|
51
59
|
switch (plan.operation) {
|
|
52
60
|
case "workspace.board":
|
|
53
|
-
return board(deps);
|
|
61
|
+
return board(deps, run);
|
|
54
62
|
case "session.artifacts":
|
|
55
|
-
return artifacts(deps, run, plan.dump ?? null);
|
|
63
|
+
return artifacts(deps, run, plan.dump ?? null, run.session.endsWith("-plan-refine"));
|
|
56
64
|
case "session.close":
|
|
57
65
|
return close(deps, run);
|
|
58
66
|
case "worktree.ensure":
|
|
@@ -63,6 +71,8 @@ export function internalActionExecutor(deps) {
|
|
|
63
71
|
return inferBatch(deps, run);
|
|
64
72
|
case "plan-exec.batch-close":
|
|
65
73
|
return closeBatch(deps, run);
|
|
74
|
+
case "plan-exec.batch-commit":
|
|
75
|
+
return commitBatch(deps, run);
|
|
66
76
|
case "plan-exec.plan-done":
|
|
67
77
|
return sealPlanDone(deps, run);
|
|
68
78
|
case "plan-exec.settlement-publish":
|
|
@@ -90,7 +100,7 @@ async function ensureUnits(deps, run) {
|
|
|
90
100
|
return refusal("worktree.ensure", "la corrida no fijó qué fuentes edita: no hay unidad que adquirir", canonicalJson({ scope: null }));
|
|
91
101
|
}
|
|
92
102
|
const acquired = [];
|
|
93
|
-
for (const alias of scope.sources) {
|
|
103
|
+
for (const alias of scope.isolation === "in-place" ? [] : scope.sources) {
|
|
94
104
|
// `workspace` is the documentary/control checkout itself. It is a valid
|
|
95
105
|
// source-bounded proof surface, but never a source repository that needs a
|
|
96
106
|
// per-session Git worktree.
|
|
@@ -108,16 +118,125 @@ async function ensureUnits(deps, run) {
|
|
|
108
118
|
}
|
|
109
119
|
acquired.push(result);
|
|
110
120
|
}
|
|
121
|
+
const based = await recordBatchBase(deps, run, scope.sources);
|
|
122
|
+
if (!based.ok) {
|
|
123
|
+
return refusal("worktree.ensure", `${based.failure.message} — ${based.failure.action}`, canonicalJson({ failure: based.failure, acquired }));
|
|
124
|
+
}
|
|
111
125
|
return {
|
|
112
126
|
ok: true,
|
|
113
|
-
summary:
|
|
127
|
+
summary: scope.isolation === "in-place"
|
|
128
|
+
? "in-place: sin unidad"
|
|
129
|
+
: `unidades de ${run.session}: ${acquired.map((unit) => `${unit.alias} → ${unit.branch}`).join(", ")}`,
|
|
114
130
|
output: canonicalJson({ plan: scope.plan, units: acquired }),
|
|
115
131
|
// The tree IS there, however it got there — the same reading `proposal.publish`
|
|
116
132
|
// makes of a re-entry that finds the bytes already written. Crediting nothing
|
|
117
133
|
// when `created` is false would refuse the resumption this row is idempotent for.
|
|
118
|
-
effects: ["local_additive"],
|
|
134
|
+
effects: ["local_additive", "mutate_overwrite"],
|
|
135
|
+
...(based.state === null ? {} : { state: based.state }),
|
|
119
136
|
};
|
|
120
137
|
}
|
|
138
|
+
/** The batch this iteration walks, while it still has no base. */
|
|
139
|
+
function batchAwaitingBase(state) {
|
|
140
|
+
const iteration = state.batch_loop?.iteration ?? null;
|
|
141
|
+
const batch = (state.batches ?? []).find((entry) => entry.iteration === iteration);
|
|
142
|
+
return batch?.base === undefined ? batch : undefined;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Seal, on the batch this iteration walks, what each of its sources looked like
|
|
146
|
+
* before its work — the base it will have to have changed to be credited.
|
|
147
|
+
*
|
|
148
|
+
* Taken here because this row runs once per iteration, after the previous
|
|
149
|
+
* batch's close and commit: comparing against the previous CREDIT instead would
|
|
150
|
+
* let the plan that close published, or the review's fixes, pass as the next
|
|
151
|
+
* batch's work. The first batch's base is the run's start.
|
|
152
|
+
*/
|
|
153
|
+
async function recordBatchBase(deps, run, sources) {
|
|
154
|
+
// Measuring hashes whole trees, so it happens only when a batch is waiting for
|
|
155
|
+
// its base; the lock below re-checks, and a run that moved fails its CAS.
|
|
156
|
+
const live = await readRun(deps.fs, locateRun(deps.paths, run.session));
|
|
157
|
+
if (live.ok && batchAwaitingBase(live.state) === undefined)
|
|
158
|
+
return { ok: true, state: null };
|
|
159
|
+
const observed = await observeScopedFingerprints(deps.fs, deps.git, deps.paths, run.session, sources);
|
|
160
|
+
if (!observed.ok)
|
|
161
|
+
return observed;
|
|
162
|
+
const legacy = live.ok && legacyPlanExecCommits(live.state);
|
|
163
|
+
const candidates = legacy
|
|
164
|
+
? []
|
|
165
|
+
: await resolveCheckoutCandidates(deps.fs, deps.paths, run.session);
|
|
166
|
+
const snapshot = {};
|
|
167
|
+
for (const alias of legacy ? [] : sources) {
|
|
168
|
+
if (alias === "workspace")
|
|
169
|
+
continue;
|
|
170
|
+
const root = candidates.find((candidate) => candidate.source === alias)?.root;
|
|
171
|
+
if (root === undefined)
|
|
172
|
+
return {
|
|
173
|
+
ok: false,
|
|
174
|
+
failure: {
|
|
175
|
+
code: "PLAN_EXEC_BATCH_UNIT_MISSING",
|
|
176
|
+
message: `falta la unidad de ${alias}`,
|
|
177
|
+
action: "adquirí la unidad antes de iniciar el lote",
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
try {
|
|
181
|
+
const [head, branch, dirty] = await Promise.all([
|
|
182
|
+
deps.git.head(root),
|
|
183
|
+
deps.git.currentBranch(root),
|
|
184
|
+
deps.git.dirtyPaths(root),
|
|
185
|
+
]);
|
|
186
|
+
if (head === null ||
|
|
187
|
+
branch === undefined ||
|
|
188
|
+
(run.scope?.isolation !== "in-place" && dirty.length > 0)) {
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
failure: {
|
|
192
|
+
code: "PLAN_EXEC_BATCH_UNIT_DIRTY",
|
|
193
|
+
message: `${alias}: no puede iniciar el lote con HEAD/rama ausente o rutas sucias: ${dirty.map((entry) => entry.path).join(", ")}`,
|
|
194
|
+
action: "cerrá los cambios del lote anterior antes de iniciar éste",
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
snapshot[alias] = { head, branch, dirty };
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
return {
|
|
202
|
+
ok: false,
|
|
203
|
+
failure: {
|
|
204
|
+
code: "PLAN_EXEC_BATCH_GIT_UNOBSERVABLE",
|
|
205
|
+
message: `${alias}: ${String(error)}`,
|
|
206
|
+
action: "restaurá la lectura de git y reintentá la adquisición",
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const recorded = await applyUnderLock(deps.fs, locateRun(deps.paths, run.session), (current) => {
|
|
212
|
+
if (current === null) {
|
|
213
|
+
return {
|
|
214
|
+
ok: false,
|
|
215
|
+
failure: {
|
|
216
|
+
code: "FLOW_RUN_ABSENT",
|
|
217
|
+
message: "la corrida desapareció antes de sellar la base del batch",
|
|
218
|
+
action: "reanudá la corrida con 'aw flow advance'",
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const batch = batchAwaitingBase(current);
|
|
223
|
+
// Outside plan-exec, before any batch was inferred, or with its base already
|
|
224
|
+
// sealed, there is nothing to seal.
|
|
225
|
+
if (batch === undefined)
|
|
226
|
+
return { ok: true, state: current, value: null, persist: false };
|
|
227
|
+
// A reseated run already holds the work of the batches it re-infers: their
|
|
228
|
+
// base is the one the archived run sealed before that work, not today's tree.
|
|
229
|
+
const inherited = current.inherited_bases?.find((entry) => entry.phases.length === batch.phases.length &&
|
|
230
|
+
entry.phases.every((phase, index) => phase === batch.phases[index]));
|
|
231
|
+
let next = withPlanExecBatchBase(current, batch.id, inherited?.base ?? observed.base);
|
|
232
|
+
if (batch.snapshot === undefined && !legacyPlanExecCommits(current))
|
|
233
|
+
next = withPlanExecBatchUpdate(next, batch.id, (item) => ({ ...item, snapshot }));
|
|
234
|
+
return { ok: true, state: next, value: null, persist: next !== current };
|
|
235
|
+
}, run.state_digest === undefined ? {} : { expectDigest: run.state_digest });
|
|
236
|
+
if (!recorded.ok)
|
|
237
|
+
return recorded;
|
|
238
|
+
return { ok: true, state: recorded.state };
|
|
239
|
+
}
|
|
121
240
|
/**
|
|
122
241
|
* Write the run's approved proposal — all of it, or none of it.
|
|
123
242
|
*
|
|
@@ -158,7 +277,7 @@ async function publish(deps, run) {
|
|
|
158
277
|
ok: true,
|
|
159
278
|
summary: result.already_applied
|
|
160
279
|
? `la propuesta ya estaba aplicada: ${destinations.join(", ")} sin cambios`
|
|
161
|
-
: `publicado: ${result.written.join(", ")}`,
|
|
280
|
+
: `publicado: ${result.written.join(", ")}${result.notice === undefined ? "" : `; aviso: ${result.notice}`}`,
|
|
162
281
|
output: canonicalJson({ ...result, digest: proposal.digest, destinations, claims }),
|
|
163
282
|
// Only what really landed. A re-entry that found the bytes already there
|
|
164
283
|
// credits the same classes — the effect IS applied — and the summary is what
|
|
@@ -176,8 +295,8 @@ async function publish(deps, run) {
|
|
|
176
295
|
* never held up by a ledger it does not depend on — an unreadable ledger must not
|
|
177
296
|
* stop every loop in the system from saving.
|
|
178
297
|
*/
|
|
179
|
-
async function revokedFence(deps, owner, destinations) {
|
|
180
|
-
const read = await readClaimEvents(deps.fs, deps.paths);
|
|
298
|
+
export async function revokedFence(deps, owner, destinations) {
|
|
299
|
+
const read = await readClaimEvents(deps.fs, deps.paths, { lockHeld: true });
|
|
181
300
|
const blocked = revokedAmong(read.events, owner, destinations);
|
|
182
301
|
if (blocked.length > 0) {
|
|
183
302
|
return {
|
|
@@ -187,13 +306,10 @@ async function revokedFence(deps, owner, destinations) {
|
|
|
187
306
|
};
|
|
188
307
|
}
|
|
189
308
|
if (read.unreadable > 0) {
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
// workspace-wide outage rather than the narrow fail-closed this needs to be.
|
|
195
|
-
const mine = new Set(openClaimsOf(read.events, owner).map((claim) => claimKey(claim)));
|
|
196
|
-
const atRisk = claimShapedAmong(owner, destinations).filter((claim) => mine.has(claimKey(claim)));
|
|
309
|
+
// An illegible revoked row may have removed the very open claim a narrowed
|
|
310
|
+
// check would rely on. Every numbered destination is at risk; loose files
|
|
311
|
+
// outside the claim namespace remain unaffected.
|
|
312
|
+
const atRisk = claimShapedAmong(owner, destinations);
|
|
197
313
|
if (atRisk.length > 0) {
|
|
198
314
|
return {
|
|
199
315
|
code: "CLAIM_LEDGER_UNREADABLE",
|
|
@@ -229,6 +345,8 @@ async function recordCompletedClaims(deps, owner, result, destinations) {
|
|
|
229
345
|
const recorded = [];
|
|
230
346
|
try {
|
|
231
347
|
const read = await readClaimEvents(deps.fs, deps.paths);
|
|
348
|
+
if (read.unreadable > 0)
|
|
349
|
+
return { recorded, ledger_unreadable: read.unreadable };
|
|
232
350
|
const completed = completedClaimsIn(read.events, owner, {
|
|
233
351
|
written: result.written,
|
|
234
352
|
already_applied: result.already_applied,
|
|
@@ -255,13 +373,23 @@ async function recordCompletedClaims(deps, owner, result, destinations) {
|
|
|
255
373
|
};
|
|
256
374
|
}
|
|
257
375
|
}
|
|
258
|
-
async function board(deps) {
|
|
376
|
+
async function board(deps, run) {
|
|
259
377
|
const data = await runStatusCommand(deps.fs, deps.env, deps.paths, { git: deps.git });
|
|
260
378
|
const counts = data.counts;
|
|
379
|
+
const custody = run.session.endsWith("-plan-new")
|
|
380
|
+
? await readCustody(deps.fs, locateRun(deps.paths, run.session).dir)
|
|
381
|
+
: null;
|
|
382
|
+
const superseded = custody?.status === "present"
|
|
383
|
+
? data.specs.find((spec) => spec.status === "superseded" &&
|
|
384
|
+
custody.custody.artifacts.some((artifact) => artifact.role === "input" && artifact.path === spec.file))
|
|
385
|
+
: undefined;
|
|
386
|
+
const warning = superseded === undefined
|
|
387
|
+
? null
|
|
388
|
+
: `la spec ${superseded.number} fue reemplazada${superseded.superseded_by ? ` por ${superseded.superseded_by}` : ""}: plan-new debe usar el reemplazo`;
|
|
261
389
|
return {
|
|
262
390
|
ok: true,
|
|
263
|
-
summary: `tablero: ${counts.specs} specs, ${counts.plans} planes, ${counts.sessions_active} sesiones activas, ${counts.pending} pendientes`,
|
|
264
|
-
output: canonicalJson(data),
|
|
391
|
+
summary: `tablero: ${counts.specs} specs, ${counts.plans} planes, ${counts.sessions_active} sesiones activas, ${counts.pending} pendientes${warning ? `; aviso: ${warning}` : ""}`,
|
|
392
|
+
output: canonicalJson(warning ? { ...data, spec_readiness_warning: warning } : data),
|
|
265
393
|
effects: ["read_only"],
|
|
266
394
|
};
|
|
267
395
|
}
|
|
@@ -275,10 +403,13 @@ async function board(deps) {
|
|
|
275
403
|
* says the specific artifacts have content. A dump alone would pass a session
|
|
276
404
|
* whose criteria were never seeded.
|
|
277
405
|
*/
|
|
278
|
-
async function artifacts(deps, run, dump) {
|
|
406
|
+
async function artifacts(deps, run, dump, planRefine = false) {
|
|
279
407
|
// The presence report, without the narrative: this operation checks that the
|
|
280
408
|
// artifacts are THERE, and projecting the session's whole reading to answer
|
|
281
409
|
// that would be work nobody asked for on every advance.
|
|
410
|
+
if (dump?.includes("objetivo") && dump.includes("checkpoint")) {
|
|
411
|
+
await seedMissingCheckpoint(deps, run);
|
|
412
|
+
}
|
|
282
413
|
const report = await runArtifactsCommand(deps.fs, deps.env, deps.paths, {
|
|
283
414
|
code: run.code,
|
|
284
415
|
noNarrative: true,
|
|
@@ -289,22 +420,27 @@ async function artifacts(deps, run, dump) {
|
|
|
289
420
|
if (report.artifacts.session === null) {
|
|
290
421
|
return refusal("session.artifacts", `la sesión '${report.session}' no tiene su SESSION.md`, canonicalJson(report));
|
|
291
422
|
}
|
|
423
|
+
const destination = planRefine ? await refineDestination(deps, run, canonicalJson(report)) : "";
|
|
424
|
+
if (typeof destination !== "string")
|
|
425
|
+
return destination;
|
|
426
|
+
const legacyWarning = destination;
|
|
292
427
|
if (dump === null) {
|
|
293
428
|
return {
|
|
294
429
|
ok: true,
|
|
295
|
-
summary: `sesión ${report.session}: SESSION.md presente, ${report.artifacts.session.criterios_count} criterios, ${report.artifacts.decisiones_count} decisiones`,
|
|
430
|
+
summary: `sesión ${report.session}: SESSION.md presente, ${report.artifacts.session.criterios_count} criterios, ${report.artifacts.decisiones_count} decisiones${legacyWarning}`,
|
|
296
431
|
output: canonicalJson(report),
|
|
297
432
|
effects: SEEDED_EFFECTS,
|
|
298
433
|
};
|
|
299
434
|
}
|
|
300
435
|
const dumped = await readSessionArtifacts(deps.fs, deps.paths, run.code, [...dump], deps.runtime);
|
|
301
|
-
const
|
|
436
|
+
const script = dump.includes("scripts") ? await rootScript(deps, run) : null;
|
|
437
|
+
const output = canonicalJson({ report, dump: dumped, root_script: script });
|
|
302
438
|
if (dumped.error !== undefined) {
|
|
303
439
|
return refusal("session.artifacts", String(dumped.hint ?? dumped.error), output);
|
|
304
440
|
}
|
|
305
|
-
const empty = dump.filter((kind) => !hasContent(dumped[kind]));
|
|
441
|
+
const empty = dump.filter((kind) => !hasContent(dumped[kind]) && !(kind === "scripts" && hasContent(script)));
|
|
306
442
|
if (empty.length > 0) {
|
|
307
|
-
return refusal("session.artifacts", `sin contenido: ${empty.join(", ")}`, output);
|
|
443
|
+
return refusal("session.artifacts", `sin contenido: ${empty.join(", ")}${empty.includes("scripts") ? " (SCRIPTS.sql o scripts/*.sql)" : ""}`, output);
|
|
308
444
|
}
|
|
309
445
|
// `objetivo` is the artifact that carries the success criteria, so demanding it
|
|
310
446
|
// is demanding them: a SESSION.md with a criteria heading and nothing under it
|
|
@@ -316,11 +452,46 @@ async function artifacts(deps, run, dump) {
|
|
|
316
452
|
}
|
|
317
453
|
return {
|
|
318
454
|
ok: true,
|
|
319
|
-
summary: `sesión ${report.session}: ${dump.join(", ")} con contenido, ${report.artifacts.session.criterios_count} criterios`,
|
|
455
|
+
summary: `sesión ${report.session}: ${dump.join(", ")} con contenido, ${report.artifacts.session.criterios_count} criterios${legacyWarning}`,
|
|
320
456
|
output,
|
|
321
457
|
effects: SEEDED_EFFECTS,
|
|
322
458
|
};
|
|
323
459
|
}
|
|
460
|
+
async function seedMissingCheckpoint(deps, run) {
|
|
461
|
+
const folder = join(deps.paths.cwdSessionsDir(), run.session);
|
|
462
|
+
const checkpoint = canonicalArtifactPath(folder, "checkpoint");
|
|
463
|
+
if (await deps.fs.exists(checkpoint))
|
|
464
|
+
return;
|
|
465
|
+
const session = canonicalArtifactPath(folder, "session");
|
|
466
|
+
if (!(await deps.fs.exists(session)))
|
|
467
|
+
return;
|
|
468
|
+
const objective = parseMdSectionBilingual(await deps.fs.readText(session), "Objective")?.trim();
|
|
469
|
+
if (!objective || objective.includes("_[AI:"))
|
|
470
|
+
return;
|
|
471
|
+
await deps.fs.publishTextExclusive(checkpoint, `# CHECKPOINT\n\n## Completed\n\n## Pending / Next\n\n${objective}\n`);
|
|
472
|
+
}
|
|
473
|
+
/** Only this evidence reader accepts the root script; exports keep their dump. */
|
|
474
|
+
async function rootScript(deps, run) {
|
|
475
|
+
const path = canonicalArtifactPath(join(deps.paths.cwdSessionsDir(), run.session), "scripts_sql");
|
|
476
|
+
return (await deps.fs.exists(path)) ? { path, content: await deps.fs.readText(path) } : null;
|
|
477
|
+
}
|
|
478
|
+
/** A new refine must be bound to an existing plan; only pre-custody sessions degrade. */
|
|
479
|
+
async function refineDestination(deps, run, report) {
|
|
480
|
+
const custody = await readCustody(deps.fs, locateRun(deps.paths, run.session).dir);
|
|
481
|
+
if (custody.status === "unreadable") {
|
|
482
|
+
return refusal("session.artifacts", `custodia ilegible: ${custody.reason}`, report);
|
|
483
|
+
}
|
|
484
|
+
if (custody.status === "absent") {
|
|
485
|
+
return "; sesión legada sin custodia: no se puede verificar su plan destino";
|
|
486
|
+
}
|
|
487
|
+
for (const artifact of custody.custody.artifacts) {
|
|
488
|
+
if (artifact.role !== "input" || !/^docs\/plans\/\d{3,}-plan-[^/]+\.md$/.test(artifact.path))
|
|
489
|
+
continue;
|
|
490
|
+
if (await deps.fs.exists(join(deps.paths.workspaceDir(), artifact.path)))
|
|
491
|
+
return "";
|
|
492
|
+
}
|
|
493
|
+
return refusal("session.artifacts", "plan-refine exige un plan destino existente: creá la sesión con --input docs/plans/PPP-plan-<slug>.md o el descriptor <slug>-plan-refine, del que session-create deriva el plan", canonicalJson({ report, custody: custody.custody.artifacts.map((artifact) => artifact.path) }));
|
|
494
|
+
}
|
|
324
495
|
/**
|
|
325
496
|
* What a satisfied artifact reading really attests.
|
|
326
497
|
*
|
|
@@ -399,6 +570,16 @@ async function inferBatch(deps, run) {
|
|
|
399
570
|
}
|
|
400
571
|
const active = (current.batches ?? []).find((batch) => batch.published_plan_digest === undefined);
|
|
401
572
|
if (active !== undefined) {
|
|
573
|
+
if (active.commit_result !== undefined && Object.keys(active.commit_result).length > 0) {
|
|
574
|
+
return {
|
|
575
|
+
ok: false,
|
|
576
|
+
failure: {
|
|
577
|
+
code: "PLAN_EXEC_BATCH_REINFER_COMMITTED",
|
|
578
|
+
message: `${active.id} ya tiene recibos de commit y no puede re-inferirse`,
|
|
579
|
+
action: `revisá los recibos; para reabrir su trabajo usá aw flow annul --session ${run.session} --from ${active.id}`,
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
}
|
|
402
583
|
return {
|
|
403
584
|
ok: true,
|
|
404
585
|
state: current,
|
|
@@ -420,7 +601,7 @@ async function inferBatch(deps, run) {
|
|
|
420
601
|
},
|
|
421
602
|
};
|
|
422
603
|
}
|
|
423
|
-
const next =
|
|
604
|
+
const next = inferNextPlanExecBatch(text, current);
|
|
424
605
|
if (!next.ok) {
|
|
425
606
|
if (next.failure.code !== "PLAN_EXEC_BATCH_NONE_OPEN") {
|
|
426
607
|
return { ok: false, failure: next.failure };
|
|
@@ -437,6 +618,27 @@ async function inferBatch(deps, run) {
|
|
|
437
618
|
value: { batch: null, created: false, no_work: true },
|
|
438
619
|
};
|
|
439
620
|
}
|
|
621
|
+
// Store the exact plan text BEFORE publishing the inferred state. A retry
|
|
622
|
+
// either sees the same addressed copy or refuses rather than losing its base.
|
|
623
|
+
try {
|
|
624
|
+
const snapshot = sealedPlanPath(location.dir, next.batch.plan_digest);
|
|
625
|
+
await deps.fs.mkdirp(join(location.dir, ".plan-seals"));
|
|
626
|
+
const saved = await deps.fs.publishTextExclusive(snapshot, text);
|
|
627
|
+
if (!saved.created &&
|
|
628
|
+
canonicalEol(await deps.fs.readText(snapshot)) !== canonicalEol(text)) {
|
|
629
|
+
throw new Error("la copia direccionada no coincide con el plan inferido");
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
catch (error) {
|
|
633
|
+
return {
|
|
634
|
+
ok: false,
|
|
635
|
+
failure: {
|
|
636
|
+
code: "PLAN_EXEC_BATCH_SNAPSHOT_UNAVAILABLE",
|
|
637
|
+
message: `no se pudo guardar la copia sellada: ${String(error)}`,
|
|
638
|
+
action: "revisá el almacenamiento de la sesión y reintentá la inferencia",
|
|
639
|
+
},
|
|
640
|
+
};
|
|
641
|
+
}
|
|
440
642
|
return {
|
|
441
643
|
ok: true,
|
|
442
644
|
state: withPlanExecBatch(current, next.batch),
|
|
@@ -451,7 +653,7 @@ async function inferBatch(deps, run) {
|
|
|
451
653
|
summary: inferred.value.no_work
|
|
452
654
|
? "el plan ya no tiene tareas abiertas: se omite el batch vacío y se expone la validación final"
|
|
453
655
|
: inferred.value.created
|
|
454
|
-
? `batch ${inferred.value.batch?.id ?? "nuevo"} inferido y sellado antes de implementar`
|
|
656
|
+
? `batch ${inferred.value.batch?.id ?? "nuevo"} inferido y sellado antes de implementar; partición ${canonicalJson(inferred.value.batch?.partition ?? null)}`
|
|
455
657
|
: `batch ${inferred.value.batch?.id ?? "actual"} ya estaba inferido; se conserva su snapshot sellado`,
|
|
456
658
|
output: canonicalJson({ batch: inferred.value.batch, created: inferred.value.created }),
|
|
457
659
|
effects: [],
|
|
@@ -585,7 +787,27 @@ async function closeBatch(deps, run) {
|
|
|
585
787
|
if (batch === undefined) {
|
|
586
788
|
return refusal("plan-exec.batch-close", "no hay un batch inferido para cerrar: la corrida no puede acreditar tareas que no selló antes de implementarlas", canonicalJson({ code: "PLAN_EXEC_BATCH_NOT_INFERRED", plan: run.scope.plan }));
|
|
587
789
|
}
|
|
790
|
+
// A batch born with a base was meant to be credited at its phase validation.
|
|
791
|
+
if (validationOnlyCloseMissing(live.state, batch)) {
|
|
792
|
+
return refusal("plan-exec.batch-close", "el lote de sólo validación carece de aprobación o de evidencia acreditada", canonicalJson({ code: "PLAN_VALIDATION_ONLY_NOT_APPROVED", batch: batch.id }));
|
|
793
|
+
}
|
|
794
|
+
// Reaching the close without that credit — an exhausted validation degraded
|
|
795
|
+
// past, a route that skipped it — would publish its tasks as done on no proof.
|
|
796
|
+
if (batch.base !== undefined && batch.credit === undefined) {
|
|
797
|
+
return refusal("plan-exec.batch-close", `el batch ${batch.id} no tiene acreditación: su validación de fase nunca aceptó una prueba propia del checkout de sus fuentes`, canonicalJson({ code: "PLAN_EXEC_BATCH_UNCREDITED", batch: batch.id, plan: run.scope.plan }));
|
|
798
|
+
}
|
|
588
799
|
const phaseUpdates = phaseUpdatesForClosedBatch(text, batch);
|
|
800
|
+
if (batch.review === undefined && batch.published_plan_digest === undefined) {
|
|
801
|
+
return refusal("plan-exec.batch-close", `el batch ${batch.id} no tiene revisión registrada; completá review-findings con un revisor distinto y las correcciones revisadas`, canonicalJson({ code: "PLAN_EXEC_BATCH_REVIEW_MISSING", batch: batch.id }));
|
|
802
|
+
}
|
|
803
|
+
if (!legacyPlanExecCommits(live.state) && batch.commit_result === undefined) {
|
|
804
|
+
return refusal("plan-exec.batch-close", `el batch ${batch.id} no tiene resultado de commits verificado`, canonicalJson({ code: "PLAN_EXEC_BATCH_COMMIT_MISSING", batch: batch.id }));
|
|
805
|
+
}
|
|
806
|
+
if (!legacyPlanExecCommits(live.state)) {
|
|
807
|
+
const gitFailure = await verifyBatchGitState(deps, run, batch, run.scope?.isolation === "in-place");
|
|
808
|
+
if (gitFailure !== null)
|
|
809
|
+
return refusal("plan-exec.batch-close", gitFailure.message, canonicalJson(gitFailure));
|
|
810
|
+
}
|
|
589
811
|
if (!phaseUpdates.ok) {
|
|
590
812
|
return refusal("plan-exec.batch-close", `${phaseUpdates.failure.message} — ${phaseUpdates.failure.action}`, canonicalJson({ failure: phaseUpdates.failure }));
|
|
591
813
|
}
|
|
@@ -613,11 +835,12 @@ async function closeBatch(deps, run) {
|
|
|
613
835
|
ok: true,
|
|
614
836
|
summary: published.already_applied
|
|
615
837
|
? `batch ${published.batch.id} ya estaba publicado en ${run.scope.plan}`
|
|
616
|
-
: `batch ${published.batch.id} publicado: ${published.written.join(", ")}`,
|
|
838
|
+
: `batch ${published.batch.id} publicado: ${published.written.join(", ")}${published.notice === undefined ? "" : `; aviso: ${published.notice}`}`,
|
|
617
839
|
output: canonicalJson({
|
|
618
840
|
batch: published.batch,
|
|
619
841
|
written: published.written,
|
|
620
842
|
already_applied: published.already_applied,
|
|
843
|
+
...(published.notice === undefined ? {} : { notice: published.notice }),
|
|
621
844
|
}),
|
|
622
845
|
effects: ["mutate_overwrite"],
|
|
623
846
|
state,
|
|
@@ -634,6 +857,10 @@ async function closeBatch(deps, run) {
|
|
|
634
857
|
* already names the NEXT batch — or nothing, when it was the last one. The
|
|
635
858
|
* publisher then confirms it through its own already-applied path.
|
|
636
859
|
*/
|
|
860
|
+
function validationOnlyCloseMissing(state, batch) {
|
|
861
|
+
return (batch.kind === "validation-only" &&
|
|
862
|
+
(!approvedValidationOnly(state, batch) || batch.credit === undefined));
|
|
863
|
+
}
|
|
637
864
|
function batchToClose(state) {
|
|
638
865
|
const batches = state.batches ?? [];
|
|
639
866
|
const open = batches.find((batch) => batch.published_plan_digest === undefined);
|
|
@@ -693,11 +920,21 @@ async function sealPlanDone(deps, run) {
|
|
|
693
920
|
return refusal("plan-exec.plan-done", "la corrida cambió mientras se preparaba el sello final", canonicalJson({ expected: run.state_digest, actual: live.state.digest }));
|
|
694
921
|
}
|
|
695
922
|
const missing = PLAN_DONE_REQUIRED_TRANSITIONS.filter((transition) => {
|
|
923
|
+
if (transition === "plan-exec.final-validation") {
|
|
924
|
+
return (!live.state.applied.includes(transition) ||
|
|
925
|
+
live.state.skipped.includes(transition) ||
|
|
926
|
+
(live.state.degraded ?? []).some((item) => item.transition === transition) ||
|
|
927
|
+
dispositionOf(live.state.route_decisions, transition)?.disposition === "substitute");
|
|
928
|
+
}
|
|
696
929
|
if (live.state.applied.includes(transition))
|
|
697
930
|
return false;
|
|
698
931
|
const disposition = dispositionOf(live.state.route_decisions, transition)?.disposition;
|
|
699
932
|
return disposition !== "omit" && disposition !== "substitute";
|
|
700
933
|
});
|
|
934
|
+
if (!legacyPlanExecCommits(live.state) &&
|
|
935
|
+
(live.state.batches ?? []).some((batch) => batch.commit_result === undefined)) {
|
|
936
|
+
return refusal("plan-exec.plan-done", "hay lotes sin recibo o resultado de commit", canonicalJson({ code: "PLAN_EXEC_DONE_BATCH_COMMIT_MISSING" }));
|
|
937
|
+
}
|
|
701
938
|
if (missing.length > 0) {
|
|
702
939
|
return refusal("plan-exec.plan-done", `todavía falta evidencia de ${missing.join(", ")}`, canonicalJson({ code: "PLAN_EXEC_DONE_PREREQUISITE", missing }));
|
|
703
940
|
}
|
|
@@ -765,6 +1002,12 @@ async function sealPlanDone(deps, run) {
|
|
|
765
1002
|
}
|
|
766
1003
|
/** The plan seal says exactly which evidence was absent or substituted. */
|
|
767
1004
|
function planDoneClosure(state, session) {
|
|
1005
|
+
const destination = state.scope?.isolation === "in-place"
|
|
1006
|
+
? `commits en el checkout (${(state.batches ?? [])
|
|
1007
|
+
.flatMap((batch) => Object.values(batch.commit_result ?? {}).map((receipt) => receipt.branch))
|
|
1008
|
+
.filter((branch) => branch !== null)
|
|
1009
|
+
.join(", ")}); sin integración`
|
|
1010
|
+
: "commits e integración";
|
|
768
1011
|
const decisions = state.route_decisions ?? [];
|
|
769
1012
|
const controls = new Map((state.route_proposal?.controls ?? []).map((control) => [control.transition, control]));
|
|
770
1013
|
const omitted = decisions
|
|
@@ -778,15 +1021,15 @@ function planDoneClosure(state, session) {
|
|
|
778
1021
|
.map((decision) => decision.substitution)
|
|
779
1022
|
.filter((substitution) => substitution !== null);
|
|
780
1023
|
if (state.assurance === "unverified_accepted") {
|
|
781
|
-
return `evidencia omitida en la propuesta aceptada (${omitted.join("; ") || "sin detalle"});
|
|
1024
|
+
return `evidencia omitida en la propuesta aceptada (${omitted.join("; ") || "sin detalle"}); ${destination} acreditados por la corrida ${session}; no se afirma que la validación pasó`;
|
|
782
1025
|
}
|
|
783
1026
|
if (state.assurance === "partially_verified") {
|
|
784
|
-
return `validación sustituta pendiente (${substitutions.map((substitution) => substitution.validation).join(", ") || "sin detalle"}); riesgo aceptado: ${substitutions.map((substitution) => substitution.risk).join(", ") || "assurance parcial"};
|
|
1027
|
+
return `validación sustituta pendiente (${substitutions.map((substitution) => substitution.validation).join(", ") || "sin detalle"}); riesgo aceptado: ${substitutions.map((substitution) => substitution.risk).join(", ") || "assurance parcial"}; ${destination} acreditados por la corrida ${session}`;
|
|
785
1028
|
}
|
|
786
1029
|
if (substitutions.length > 0) {
|
|
787
|
-
return `validación sustituta ejecutada (${substitutions.map((substitution) => substitution.validation).join(", ")});
|
|
1030
|
+
return `validación sustituta ejecutada (${substitutions.map((substitution) => substitution.validation).join(", ")}); ${destination} acreditados por la corrida ${session}`;
|
|
788
1031
|
}
|
|
789
|
-
return `validación final,
|
|
1032
|
+
return `validación final, ${destination} acreditados por la corrida ${session}`;
|
|
790
1033
|
}
|
|
791
1034
|
/** The documentary checks that must pass in the same critical section as done. */
|
|
792
1035
|
export async function planDonePrecondition(deps, path, session) {
|
|
@@ -895,40 +1138,6 @@ function phaseUpdatesForClosedBatch(text, batch) {
|
|
|
895
1138
|
updates: batch.phases.map((phase) => ({ phase, state: "validada" })),
|
|
896
1139
|
};
|
|
897
1140
|
}
|
|
898
|
-
function inferNextBatch(text, state) {
|
|
899
|
-
// `inferPlanExecBatch` itself validates that the phase has real, uniquely
|
|
900
|
-
// labelled Tn.m tasks. We only choose the first still-open phase from the
|
|
901
|
-
// document, which is a deterministic batch boundary rather than a claimed one.
|
|
902
|
-
const openPhase = parseTasks(text).items.find((task) => task.status === "open" && task.phase !== undefined)?.phase;
|
|
903
|
-
if (openPhase === undefined) {
|
|
904
|
-
const unresolved = parsePhases(text).items.find((phase) => phase.state !== "validada");
|
|
905
|
-
if (unresolved !== undefined) {
|
|
906
|
-
return {
|
|
907
|
-
ok: false,
|
|
908
|
-
failure: {
|
|
909
|
-
code: "PLAN_EXEC_BATCH_PHASE_UNRESOLVED",
|
|
910
|
-
message: `F${unresolved.n} sigue '${unresolved.state}' pero no tiene tareas abiertas acreditables`,
|
|
911
|
-
action: "normalizá la fase con plan-refine; no se salta a la validación final sobre una fase no validada",
|
|
912
|
-
},
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
return {
|
|
916
|
-
ok: false,
|
|
917
|
-
failure: {
|
|
918
|
-
code: "PLAN_EXEC_BATCH_NONE_OPEN",
|
|
919
|
-
message: "el plan no tiene una fase con tareas abiertas que este batch pueda acreditar",
|
|
920
|
-
action: "el batch ya está cerrado: reanudá la corrida para que exponga la validación final",
|
|
921
|
-
},
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
const iteration = Math.max(0, ...(state.batches ?? []).map((batch) => batch.iteration)) + 1;
|
|
925
|
-
return inferPlanExecBatch(text, {
|
|
926
|
-
id: `batch-${iteration}`,
|
|
927
|
-
iteration,
|
|
928
|
-
mode: "continuous",
|
|
929
|
-
phases: [openPhase],
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
1141
|
/**
|
|
933
1142
|
* Close the run's session — and refuse to, while it still holds a unit.
|
|
934
1143
|
*
|
|
@@ -940,14 +1149,74 @@ function inferNextBatch(text, state) {
|
|
|
940
1149
|
* notice behind a `.closed` marker that also makes the remedy stop resolving.
|
|
941
1150
|
*/
|
|
942
1151
|
async function close(deps, run) {
|
|
943
|
-
const
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1152
|
+
const read = await readRun(deps.fs, locateRun(deps.paths, run.session));
|
|
1153
|
+
if (!read.ok && read.failure.code !== "FLOW_RUN_ABSENT") {
|
|
1154
|
+
return refusal("session.close", read.failure.message, canonicalJson(read.failure));
|
|
1155
|
+
}
|
|
1156
|
+
const boundaryClose = read.ok && read.state.reentries?.at(-1)?.kind === "close";
|
|
1157
|
+
const listed = await runWorktree({ fs: deps.fs, env: deps.env, git: deps.git, paths: deps.paths }, { action: "list" });
|
|
1158
|
+
if (!("units" in listed)) {
|
|
1159
|
+
return refusal("session.close", "no se pudieron leer las unidades; revisá 'aw worktree list' y reintentá con 'aw flow advance'", canonicalJson(listed));
|
|
1160
|
+
}
|
|
1161
|
+
const classified = await classifyListedUnits(deps, listed.units);
|
|
1162
|
+
const pending = boundaryClose
|
|
1163
|
+
? await preserveBoundaryClose(deps.fs, deps.paths, deps.git, read.state, classified, listed.unreadable ?? [])
|
|
1164
|
+
: [];
|
|
1165
|
+
const documents = read.ok ? await closeDocumentGuidance(deps.fs, deps.paths, read.state) : [];
|
|
1166
|
+
const result = await runSessionClose(deps.fs, deps.paths, {
|
|
1167
|
+
code: run.code,
|
|
1168
|
+
withEvidence: read.ok &&
|
|
1169
|
+
read.state.events.some((event) => event.kind === "executed" && event.operation === "workspace.evidence-approved"),
|
|
1170
|
+
// `Cerrar` and a consented QUICK escalation are explicit human exits:
|
|
1171
|
+
// incomplete criteria travel in BACKLOG, not as an invented completion.
|
|
1172
|
+
force: boundaryClose ||
|
|
1173
|
+
(read.ok &&
|
|
1174
|
+
read.state.flow === "quick" &&
|
|
1175
|
+
read.state.applied.includes("quick.escalation-destination") &&
|
|
1176
|
+
!read.state.skipped.includes("quick.escalation-destination")),
|
|
1177
|
+
requireIntegrated: !boundaryClose,
|
|
1178
|
+
final: !boundaryClose,
|
|
1179
|
+
preserveReservations: boundaryClose
|
|
1180
|
+
? (read.state.proposal?.artifacts.filter((a) => a.reserved).map((a) => a.path) ?? [])
|
|
1181
|
+
: [],
|
|
1182
|
+
}, async () => ({ units: classified, unreadable: listed.unreadable ?? [] }), deps.git, undefined, (alias, folder) => releaseClassifiedUnit(deps, alias, folder));
|
|
1183
|
+
if ("sessionClose" in result) {
|
|
1184
|
+
const approval = read.ok
|
|
1185
|
+
? [...read.state.events]
|
|
1186
|
+
.reverse()
|
|
1187
|
+
.find((event) => event.kind === "executed" && event.operation === "workspace.commit-approved")
|
|
1188
|
+
: undefined;
|
|
1189
|
+
if (approval?.kind === "executed") {
|
|
1190
|
+
if (result.sessionClose.archive_error !== undefined ||
|
|
1191
|
+
result.sessionClose.history_error !== undefined) {
|
|
1192
|
+
result.sessionClose.commit_error = `no se ejecutó el commit: ${result.sessionClose.archive_error ?? result.sessionClose.history_error}`;
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
try {
|
|
1196
|
+
const accepted = JSON.parse(approval.summary);
|
|
1197
|
+
if (typeof accepted === "object" &&
|
|
1198
|
+
accepted !== null &&
|
|
1199
|
+
"approval" in accepted &&
|
|
1200
|
+
typeof accepted.approval === "string") {
|
|
1201
|
+
const commit = await runWorkspaceCommit(deps.fs, deps.git, undefined, deps.paths, {
|
|
1202
|
+
code: run.session,
|
|
1203
|
+
approval: accepted.approval,
|
|
1204
|
+
withEvidence: read.ok &&
|
|
1205
|
+
read.state.events.some((event) => event.kind === "executed" && event.operation === "workspace.evidence-approved"),
|
|
1206
|
+
});
|
|
1207
|
+
if ("committed" in commit && commit.committed)
|
|
1208
|
+
result.sessionClose.commit_receipt = commit.committed;
|
|
1209
|
+
else
|
|
1210
|
+
result.sessionClose.commit_error =
|
|
1211
|
+
"error" in commit ? commit.error : "el commit aprobado no se produjo";
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
catch (error) {
|
|
1215
|
+
result.sessionClose.commit_error = error instanceof Error ? error.message : String(error);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
951
1220
|
if ("sessionHeld" in result) {
|
|
952
1221
|
const held = result.sessionHeld;
|
|
953
1222
|
return refusal("session.close", `${held.reason} — integralas con '${held.integrate}'`, canonicalJson(result));
|
|
@@ -957,15 +1226,27 @@ async function close(deps, run) {
|
|
|
957
1226
|
return refusal("session.close", `la sesión no cerró: ${why}`, canonicalJson(result));
|
|
958
1227
|
}
|
|
959
1228
|
const closed = result.sessionClose;
|
|
1229
|
+
if (documents.length > 0)
|
|
1230
|
+
closed.outdated_documents = documents;
|
|
1231
|
+
if (boundaryClose) {
|
|
1232
|
+
closed.pending_work = pending;
|
|
1233
|
+
closed.reopen = `aw session-resume --code ${run.session} --reopen`;
|
|
1234
|
+
}
|
|
960
1235
|
return {
|
|
961
1236
|
ok: closed.closed,
|
|
962
|
-
summary: `sesión ${closed.folder} cerrada${closed.history === undefined ? " (sin fila de HISTORY)" : ` · HISTORY ${closed.history.action}`}`,
|
|
1237
|
+
summary: `sesión ${closed.folder} cerrada${closed.history === undefined ? " (sin fila de HISTORY)" : ` · HISTORY ${closed.history.action}`}${closed.sql_pending_export === undefined ? "" : ` · sql_pending_export: ${closed.sql_pending_export.files.join(", ")} → ${closed.sql_pending_export.command}`}${pending.length === 0 ? "" : ` · ${pending.join(" ")} · ${closed.reopen}`}${documents.length === 0 ? "" : ` · ${documents.join(" · ")}`}${!boundaryClose && closed.unverifiable_sources?.length ? ` · no verificable: ${closed.unverifiable_sources.map((item) => `${item.alias}: ${item.reason}`).join("; ")}` : ""}${closed.empty_units?.length ? ` · vacías conservadas: ${closed.empty_units.map((item) => item.alias).join(", ")}` : ""}${closed.preserved_units?.length ? ` · preservadas conservadas: ${closed.preserved_units.map((item) => item.alias).join(", ")}` : ""}${closed.released_empty?.length ? ` · vacías liberadas: ${closed.released_empty.map((item) => item.alias).join(", ")}` : ""}${closed.released_preserved?.length ? ` · preservadas liberadas: ${closed.released_preserved.map((item) => item.alias).join(", ")}` : ""}${closed.released_integrated?.length ? ` · integradas liberadas: ${closed.released_integrated.map((item) => item.alias).join(", ")}` : ""}${closed.commit_receipt ? ` · commit ${closed.commit_receipt.after}` : closed.commit_error ? ` · commit pendiente: ${closed.commit_error}` : ""}`,
|
|
963
1238
|
output: canonicalJson(result),
|
|
964
1239
|
// Closing ensures the CHECKPOINT exists and rewrites the session's marker plus
|
|
965
1240
|
// its HISTORY row: additive and overwriting, both real.
|
|
966
1241
|
effects: closed.closed ? ["local_additive", "mutate_overwrite"] : [],
|
|
967
1242
|
};
|
|
968
1243
|
}
|
|
1244
|
+
async function releaseClassifiedUnit(deps, alias, folder) {
|
|
1245
|
+
const result = await runWorktree({ fs: deps.fs, env: deps.env, git: deps.git, paths: deps.paths }, { action: "release", alias, sessionCode: folder });
|
|
1246
|
+
if ("error" in result || "released" in result)
|
|
1247
|
+
return result;
|
|
1248
|
+
return { error: "unit_unresolved", message: `no se pudo liberar ${alias} de ${folder}` };
|
|
1249
|
+
}
|
|
969
1250
|
function refusal(operation, message, output) {
|
|
970
1251
|
return { ok: false, summary: `${operation}: ${message}`, output, effects: [] };
|
|
971
1252
|
}
|