@blxzer/pactile 0.6.0-beta.2 → 0.6.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/README.md +93 -84
- package/README.zh-CN.md +90 -81
- package/dist/bin/compat-warning.d.ts +2 -0
- package/dist/bin/compat-warning.d.ts.map +1 -0
- package/dist/bin/compat-warning.js +8 -0
- package/dist/bin/compat-warning.js.map +1 -0
- package/dist/bin/cstl.d.ts +3 -0
- package/dist/bin/cstl.d.ts.map +1 -0
- package/{bin → dist/bin}/cstl.js +2 -3
- package/dist/bin/cstl.js.map +1 -0
- package/dist/bin/pactile.d.ts +3 -0
- package/dist/bin/pactile.d.ts.map +1 -0
- package/dist/bin/pactile.js +4 -0
- package/dist/bin/pactile.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +77 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/capability.d.ts +3 -0
- package/dist/commands/capability.d.ts.map +1 -0
- package/dist/commands/capability.js +129 -0
- package/dist/commands/capability.js.map +1 -0
- package/dist/commands/codex.d.ts.map +1 -1
- package/dist/commands/codex.js +54 -6
- package/dist/commands/codex.js.map +1 -1
- package/dist/commands/context.d.ts +2 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +367 -41
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/detach.d.ts.map +1 -1
- package/dist/commands/detach.js +5 -4
- package/dist/commands/detach.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +615 -259
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/legacy-task.d.ts +3 -0
- package/dist/commands/legacy-task.d.ts.map +1 -0
- package/dist/commands/legacy-task.js +295 -0
- package/dist/commands/legacy-task.js.map +1 -0
- package/dist/commands/pi.d.ts +3 -2
- package/dist/commands/pi.d.ts.map +1 -1
- package/dist/commands/pi.js +333 -10
- package/dist/commands/pi.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +148 -24
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/task-schedule.d.ts +17 -0
- package/dist/commands/task-schedule.d.ts.map +1 -0
- package/dist/commands/task-schedule.js +395 -0
- package/dist/commands/task-schedule.js.map +1 -0
- package/dist/commands/task-verify-plan.d.ts +3 -0
- package/dist/commands/task-verify-plan.d.ts.map +1 -0
- package/dist/commands/task-verify-plan.js +503 -0
- package/dist/commands/task-verify-plan.js.map +1 -0
- package/dist/commands/task-worktree-close.d.ts +4 -0
- package/dist/commands/task-worktree-close.d.ts.map +1 -0
- package/dist/commands/task-worktree-close.js +81 -0
- package/dist/commands/task-worktree-close.js.map +1 -0
- package/dist/commands/task.d.ts +3 -0
- package/dist/commands/task.d.ts.map +1 -1
- package/dist/commands/task.js +1373 -184
- package/dist/commands/task.js.map +1 -1
- package/dist/commands/tile-selection.d.ts +3 -0
- package/dist/commands/tile-selection.d.ts.map +1 -0
- package/dist/commands/tile-selection.js +174 -0
- package/dist/commands/tile-selection.js.map +1 -0
- package/dist/commands/update.d.ts +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +80 -55
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/worktree.d.ts +4 -0
- package/dist/commands/worktree.d.ts.map +1 -0
- package/dist/commands/worktree.js +198 -0
- package/dist/commands/worktree.js.map +1 -0
- package/dist/configurators/shared.js +1 -1
- package/dist/configurators/shared.js.map +1 -1
- package/dist/core/compat/environment.d.ts +0 -1
- package/dist/core/compat/environment.d.ts.map +1 -1
- package/dist/core/compat/environment.js +1 -9
- package/dist/core/compat/environment.js.map +1 -1
- package/dist/core/pactile/bounded-capabilities.d.ts +127 -0
- package/dist/core/pactile/bounded-capabilities.d.ts.map +1 -0
- package/dist/core/pactile/bounded-capabilities.js +188 -0
- package/dist/core/pactile/bounded-capabilities.js.map +1 -0
- package/dist/core/pactile/index.d.ts +1 -0
- package/dist/core/pactile/index.d.ts.map +1 -1
- package/dist/core/pactile/index.js +1 -0
- package/dist/core/pactile/index.js.map +1 -1
- package/dist/core/task/index.d.ts +4 -2
- package/dist/core/task/index.d.ts.map +1 -1
- package/dist/core/task/index.js +2 -1
- package/dist/core/task/index.js.map +1 -1
- package/dist/core/task/kernel-cli.d.ts +14 -1
- package/dist/core/task/kernel-cli.d.ts.map +1 -1
- package/dist/core/task/kernel-cli.js +128 -0
- package/dist/core/task/kernel-cli.js.map +1 -1
- package/dist/core/task/kernel-contract.d.ts +6 -3
- package/dist/core/task/kernel-contract.d.ts.map +1 -1
- package/dist/core/task/kernel-contract.js +71 -23
- package/dist/core/task/kernel-contract.js.map +1 -1
- package/dist/core/task/kernel-store.d.ts +6 -0
- package/dist/core/task/kernel-store.d.ts.map +1 -1
- package/dist/core/task/kernel-store.js +54 -2
- package/dist/core/task/kernel-store.js.map +1 -1
- package/dist/core/task/legacy-task-migration-reader.d.ts +137 -0
- package/dist/core/task/legacy-task-migration-reader.d.ts.map +1 -0
- package/dist/core/task/legacy-task-migration-reader.js +512 -0
- package/dist/core/task/legacy-task-migration-reader.js.map +1 -0
- package/dist/core/task/legacy-task-migration.d.ts +105 -0
- package/dist/core/task/legacy-task-migration.d.ts.map +1 -0
- package/dist/core/task/legacy-task-migration.js +562 -0
- package/dist/core/task/legacy-task-migration.js.map +1 -0
- package/dist/core/task/legacy-task-overlay-durable-io.d.ts +18 -0
- package/dist/core/task/legacy-task-overlay-durable-io.d.ts.map +1 -0
- package/dist/core/task/legacy-task-overlay-durable-io.js +66 -0
- package/dist/core/task/legacy-task-overlay-durable-io.js.map +1 -0
- package/dist/core/task/legacy-task-reconciliation-reader.d.ts +26 -0
- package/dist/core/task/legacy-task-reconciliation-reader.d.ts.map +1 -0
- package/dist/core/task/legacy-task-reconciliation-reader.js +324 -0
- package/dist/core/task/legacy-task-reconciliation-reader.js.map +1 -0
- package/dist/core/task/legacy-task-v2-import.d.ts +67 -0
- package/dist/core/task/legacy-task-v2-import.d.ts.map +1 -0
- package/dist/core/task/legacy-task-v2-import.js +1046 -0
- package/dist/core/task/legacy-task-v2-import.js.map +1 -0
- package/dist/core/task/project-file-observer.d.ts +46 -0
- package/dist/core/task/project-file-observer.d.ts.map +1 -0
- package/dist/core/task/project-file-observer.js +618 -0
- package/dist/core/task/project-file-observer.js.map +1 -0
- package/dist/core/task/start-authority.d.ts +14 -0
- package/dist/core/task/start-authority.d.ts.map +1 -0
- package/dist/core/task/start-authority.js +146 -0
- package/dist/core/task/start-authority.js.map +1 -0
- package/dist/core/task/strategy.d.ts +24 -0
- package/dist/core/task/strategy.d.ts.map +1 -0
- package/dist/core/task/strategy.js +136 -0
- package/dist/core/task/strategy.js.map +1 -0
- package/dist/core/task/task-candidate-observer.d.ts +111 -0
- package/dist/core/task/task-candidate-observer.d.ts.map +1 -0
- package/dist/core/task/task-candidate-observer.js +762 -0
- package/dist/core/task/task-candidate-observer.js.map +1 -0
- package/dist/core/task/task-kernel-close.d.ts +5 -0
- package/dist/core/task/task-kernel-close.d.ts.map +1 -0
- package/dist/core/task/task-kernel-close.js +367 -0
- package/dist/core/task/task-kernel-close.js.map +1 -0
- package/dist/core/task/task-kernel-dependencies.d.ts +3 -0
- package/dist/core/task/task-kernel-dependencies.d.ts.map +1 -0
- package/dist/core/task/task-kernel-dependencies.js +24 -0
- package/dist/core/task/task-kernel-dependencies.js.map +1 -0
- package/dist/core/task/task-kernel-host.d.ts +5 -0
- package/dist/core/task/task-kernel-host.d.ts.map +1 -0
- package/dist/core/task/task-kernel-host.js +136 -0
- package/dist/core/task/task-kernel-host.js.map +1 -0
- package/dist/core/task/task-kernel-paths.d.ts +19 -0
- package/dist/core/task/task-kernel-paths.d.ts.map +1 -0
- package/dist/core/task/task-kernel-paths.js +237 -0
- package/dist/core/task/task-kernel-paths.js.map +1 -0
- package/dist/core/task/task-kernel-reviews.d.ts +3 -0
- package/dist/core/task/task-kernel-reviews.d.ts.map +1 -0
- package/dist/core/task/task-kernel-reviews.js +100 -0
- package/dist/core/task/task-kernel-reviews.js.map +1 -0
- package/dist/core/task/task-kernel-runs.d.ts +5 -0
- package/dist/core/task/task-kernel-runs.d.ts.map +1 -0
- package/dist/core/task/task-kernel-runs.js +196 -0
- package/dist/core/task/task-kernel-runs.js.map +1 -0
- package/dist/core/task/task-kernel-schema.d.ts +29 -0
- package/dist/core/task/task-kernel-schema.d.ts.map +1 -0
- package/dist/core/task/task-kernel-schema.js +1169 -0
- package/dist/core/task/task-kernel-schema.js.map +1 -0
- package/dist/core/task/task-kernel-store-v2.d.ts +33 -0
- package/dist/core/task/task-kernel-store-v2.d.ts.map +1 -0
- package/dist/core/task/task-kernel-store-v2.js +574 -0
- package/dist/core/task/task-kernel-store-v2.js.map +1 -0
- package/dist/core/task/task-kernel-types.d.ts +585 -0
- package/dist/core/task/task-kernel-types.d.ts.map +1 -0
- package/dist/core/task/task-kernel-types.js +31 -0
- package/dist/core/task/task-kernel-types.js.map +1 -0
- package/dist/core/task/task-kernel-workspaces.d.ts +10 -0
- package/dist/core/task/task-kernel-workspaces.d.ts.map +1 -0
- package/dist/core/task/task-kernel-workspaces.js +250 -0
- package/dist/core/task/task-kernel-workspaces.js.map +1 -0
- package/dist/core/task/task-kernel-write-set.d.ts +3 -0
- package/dist/core/task/task-kernel-write-set.d.ts.map +1 -0
- package/dist/core/task/task-kernel-write-set.js +12 -0
- package/dist/core/task/task-kernel-write-set.js.map +1 -0
- package/dist/core/task/task-kernel.d.ts +19 -0
- package/dist/core/task/task-kernel.d.ts.map +1 -0
- package/dist/core/task/task-kernel.js +17 -0
- package/dist/core/task/task-kernel.js.map +1 -0
- package/dist/core/task/task-pull-request-observer.d.ts +25 -0
- package/dist/core/task/task-pull-request-observer.d.ts.map +1 -0
- package/dist/core/task/task-pull-request-observer.js +187 -0
- package/dist/core/task/task-pull-request-observer.js.map +1 -0
- package/dist/core/task/task-review-evidence.d.ts +27 -0
- package/dist/core/task/task-review-evidence.d.ts.map +1 -0
- package/dist/core/task/task-review-evidence.js +383 -0
- package/dist/core/task/task-review-evidence.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +5 -3
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/manifests/0.6.0-beta.3.json +9 -0
- package/dist/migrations/manifests/0.6.0-beta.4.json +9 -0
- package/dist/pactile/artifacts/documents.d.ts +72 -0
- package/dist/pactile/artifacts/documents.d.ts.map +1 -0
- package/dist/pactile/artifacts/documents.js +406 -0
- package/dist/pactile/artifacts/documents.js.map +1 -0
- package/dist/pactile/artifacts/index.d.ts +6 -0
- package/dist/pactile/artifacts/index.d.ts.map +1 -0
- package/dist/pactile/artifacts/index.js +6 -0
- package/dist/pactile/artifacts/index.js.map +1 -0
- package/dist/pactile/artifacts/projection.d.ts +50 -0
- package/dist/pactile/artifacts/projection.d.ts.map +1 -0
- package/dist/pactile/artifacts/projection.js +139 -0
- package/dist/pactile/artifacts/projection.js.map +1 -0
- package/dist/pactile/artifacts/reader.d.ts +20 -0
- package/dist/pactile/artifacts/reader.d.ts.map +1 -0
- package/dist/pactile/artifacts/reader.js +559 -0
- package/dist/pactile/artifacts/reader.js.map +1 -0
- package/dist/pactile/artifacts/schema.d.ts +4 -0
- package/dist/pactile/artifacts/schema.d.ts.map +1 -0
- package/dist/pactile/artifacts/schema.js +217 -0
- package/dist/pactile/artifacts/schema.js.map +1 -0
- package/dist/pactile/artifacts/types.d.ts +66 -0
- package/dist/pactile/artifacts/types.d.ts.map +1 -0
- package/dist/pactile/artifacts/types.js +45 -0
- package/dist/pactile/artifacts/types.js.map +1 -0
- package/dist/pactile/capabilities/claim.d.ts +3 -0
- package/dist/pactile/capabilities/claim.d.ts.map +1 -0
- package/dist/pactile/capabilities/claim.js +97 -0
- package/dist/pactile/capabilities/claim.js.map +1 -0
- package/dist/pactile/capabilities/command.d.ts +6 -0
- package/dist/pactile/capabilities/command.d.ts.map +1 -0
- package/dist/pactile/capabilities/command.js +253 -0
- package/dist/pactile/capabilities/command.js.map +1 -0
- package/dist/pactile/capabilities/discover.d.ts +6 -0
- package/dist/pactile/capabilities/discover.d.ts.map +1 -0
- package/dist/pactile/capabilities/discover.js +48 -0
- package/dist/pactile/capabilities/discover.js.map +1 -0
- package/dist/pactile/capabilities/node.d.ts +15 -0
- package/dist/pactile/capabilities/node.d.ts.map +1 -0
- package/dist/pactile/capabilities/node.js +292 -0
- package/dist/pactile/capabilities/node.js.map +1 -0
- package/dist/pactile/capabilities/read.d.ts +6 -0
- package/dist/pactile/capabilities/read.d.ts.map +1 -0
- package/dist/pactile/capabilities/read.js +100 -0
- package/dist/pactile/capabilities/read.js.map +1 -0
- package/dist/pactile/capabilities/receipts.d.ts +17 -0
- package/dist/pactile/capabilities/receipts.d.ts.map +1 -0
- package/dist/pactile/capabilities/receipts.js +90 -0
- package/dist/pactile/capabilities/receipts.js.map +1 -0
- package/dist/pactile/capabilities/search.d.ts +6 -0
- package/dist/pactile/capabilities/search.d.ts.map +1 -0
- package/dist/pactile/capabilities/search.js +181 -0
- package/dist/pactile/capabilities/search.js.map +1 -0
- package/dist/pactile/capabilities/shared.d.ts +29 -0
- package/dist/pactile/capabilities/shared.d.ts.map +1 -0
- package/dist/pactile/capabilities/shared.js +134 -0
- package/dist/pactile/capabilities/shared.js.map +1 -0
- package/dist/pactile/capabilities/workspace.d.ts +19 -0
- package/dist/pactile/capabilities/workspace.d.ts.map +1 -0
- package/dist/pactile/capabilities/workspace.js +273 -0
- package/dist/pactile/capabilities/workspace.js.map +1 -0
- package/dist/pactile/codex/bridge.d.ts +105 -2
- package/dist/pactile/codex/bridge.d.ts.map +1 -1
- package/dist/pactile/codex/bridge.js +1266 -92
- package/dist/pactile/codex/bridge.js.map +1 -1
- package/dist/pactile/codex/dispatch-stop-proof.d.ts +43 -0
- package/dist/pactile/codex/dispatch-stop-proof.d.ts.map +1 -0
- package/dist/pactile/codex/dispatch-stop-proof.js +177 -0
- package/dist/pactile/codex/dispatch-stop-proof.js.map +1 -0
- package/dist/pactile/codex/host-stop.d.ts +47 -0
- package/dist/pactile/codex/host-stop.d.ts.map +1 -0
- package/dist/pactile/codex/host-stop.js +344 -0
- package/dist/pactile/codex/host-stop.js.map +1 -0
- package/dist/pactile/coordination/index.d.ts +4 -0
- package/dist/pactile/coordination/index.d.ts.map +1 -0
- package/dist/pactile/coordination/index.js +4 -0
- package/dist/pactile/coordination/index.js.map +1 -0
- package/dist/pactile/coordination/journal.d.ts +10 -0
- package/dist/pactile/coordination/journal.d.ts.map +1 -0
- package/dist/pactile/coordination/journal.js +255 -0
- package/dist/pactile/coordination/journal.js.map +1 -0
- package/dist/pactile/coordination/kernel-resume.d.ts +8 -0
- package/dist/pactile/coordination/kernel-resume.d.ts.map +1 -0
- package/dist/pactile/coordination/kernel-resume.js +87 -0
- package/dist/pactile/coordination/kernel-resume.js.map +1 -0
- package/dist/pactile/coordination/model.d.ts +553 -0
- package/dist/pactile/coordination/model.d.ts.map +1 -0
- package/dist/pactile/coordination/model.js +239 -0
- package/dist/pactile/coordination/model.js.map +1 -0
- package/dist/pactile/coordination/state.d.ts +46 -0
- package/dist/pactile/coordination/state.d.ts.map +1 -0
- package/dist/pactile/coordination/state.js +301 -0
- package/dist/pactile/coordination/state.js.map +1 -0
- package/dist/pactile/coordination/store.d.ts +94 -0
- package/dist/pactile/coordination/store.d.ts.map +1 -0
- package/dist/pactile/coordination/store.js +396 -0
- package/dist/pactile/coordination/store.js.map +1 -0
- package/dist/pactile/index.d.ts +7 -1
- package/dist/pactile/index.d.ts.map +1 -1
- package/dist/pactile/index.js +7 -1
- package/dist/pactile/index.js.map +1 -1
- package/dist/pactile/jev/contracts.d.ts +104 -0
- package/dist/pactile/jev/contracts.d.ts.map +1 -0
- package/dist/pactile/jev/contracts.js +53 -0
- package/dist/pactile/jev/contracts.js.map +1 -0
- package/dist/pactile/jev/decision.d.ts +58 -0
- package/dist/pactile/jev/decision.d.ts.map +1 -0
- package/dist/pactile/jev/decision.js +149 -0
- package/dist/pactile/jev/decision.js.map +1 -0
- package/dist/pactile/jev/http.d.ts +25 -0
- package/dist/pactile/jev/http.d.ts.map +1 -0
- package/dist/pactile/jev/http.js +234 -0
- package/dist/pactile/jev/http.js.map +1 -0
- package/dist/pactile/jev/index.d.ts +8 -0
- package/dist/pactile/jev/index.d.ts.map +1 -0
- package/dist/pactile/jev/index.js +4 -0
- package/dist/pactile/jev/index.js.map +1 -0
- package/dist/pactile/jev/outbound.d.ts +15 -0
- package/dist/pactile/jev/outbound.d.ts.map +1 -0
- package/dist/pactile/jev/outbound.js +264 -0
- package/dist/pactile/jev/outbound.js.map +1 -0
- package/dist/pactile/jev/project-policy.d.ts +10 -0
- package/dist/pactile/jev/project-policy.d.ts.map +1 -0
- package/dist/pactile/jev/project-policy.js +53 -0
- package/dist/pactile/jev/project-policy.js.map +1 -0
- package/dist/pactile/jev/response.d.ts +17 -0
- package/dist/pactile/jev/response.d.ts.map +1 -0
- package/dist/pactile/jev/response.js +280 -0
- package/dist/pactile/jev/response.js.map +1 -0
- package/dist/pactile/jev/scheduler-advice.d.ts +92 -0
- package/dist/pactile/jev/scheduler-advice.d.ts.map +1 -0
- package/dist/pactile/jev/scheduler-advice.js +323 -0
- package/dist/pactile/jev/scheduler-advice.js.map +1 -0
- package/dist/pactile/jev/transport.d.ts +6 -0
- package/dist/pactile/jev/transport.d.ts.map +1 -0
- package/dist/pactile/jev/transport.js +87 -0
- package/dist/pactile/jev/transport.js.map +1 -0
- package/dist/pactile/lifecycle/deferred-live.d.ts +17 -0
- package/dist/pactile/lifecycle/deferred-live.d.ts.map +1 -0
- package/dist/pactile/lifecycle/deferred-live.js +173 -0
- package/dist/pactile/lifecycle/deferred-live.js.map +1 -0
- package/dist/pactile/lifecycle/legacy-import.d.ts +1 -1
- package/dist/pactile/lifecycle/legacy-import.js +3 -3
- package/dist/pactile/lifecycle/legacy-import.js.map +1 -1
- package/dist/pactile/lifecycle/project-files.d.ts.map +1 -1
- package/dist/pactile/lifecycle/project-files.js +1 -0
- package/dist/pactile/lifecycle/project-files.js.map +1 -1
- package/dist/pactile/migration/legacy-task-batch-generation.d.ts +23 -0
- package/dist/pactile/migration/legacy-task-batch-generation.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-generation.js +102 -0
- package/dist/pactile/migration/legacy-task-batch-generation.js.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-io.d.ts +9 -0
- package/dist/pactile/migration/legacy-task-batch-io.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-io.js +208 -0
- package/dist/pactile/migration/legacy-task-batch-io.js.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-journal.d.ts +6 -0
- package/dist/pactile/migration/legacy-task-batch-journal.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-journal.js +121 -0
- package/dist/pactile/migration/legacy-task-batch-journal.js.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-orchestrator.d.ts +18 -0
- package/dist/pactile/migration/legacy-task-batch-orchestrator.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-orchestrator.js +634 -0
- package/dist/pactile/migration/legacy-task-batch-orchestrator.js.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-source.d.ts +8 -0
- package/dist/pactile/migration/legacy-task-batch-source.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-source.js +158 -0
- package/dist/pactile/migration/legacy-task-batch-source.js.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-types.d.ts +127 -0
- package/dist/pactile/migration/legacy-task-batch-types.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch-types.js +127 -0
- package/dist/pactile/migration/legacy-task-batch-types.js.map +1 -0
- package/dist/pactile/migration/legacy-task-batch.d.ts +3 -0
- package/dist/pactile/migration/legacy-task-batch.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-batch.js +2 -0
- package/dist/pactile/migration/legacy-task-batch.js.map +1 -0
- package/dist/pactile/migration/legacy-task-held-source-reader.d.ts +27 -0
- package/dist/pactile/migration/legacy-task-held-source-reader.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-held-source-reader.js +261 -0
- package/dist/pactile/migration/legacy-task-held-source-reader.js.map +1 -0
- package/dist/pactile/migration/legacy-task-reconciliation.d.ts +46 -0
- package/dist/pactile/migration/legacy-task-reconciliation.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-reconciliation.js +589 -0
- package/dist/pactile/migration/legacy-task-reconciliation.js.map +1 -0
- package/dist/pactile/migration/legacy-task-update.d.ts +19 -0
- package/dist/pactile/migration/legacy-task-update.d.ts.map +1 -0
- package/dist/pactile/migration/legacy-task-update.js +164 -0
- package/dist/pactile/migration/legacy-task-update.js.map +1 -0
- package/dist/pactile/parallel/batch.d.ts +21 -2
- package/dist/pactile/parallel/batch.d.ts.map +1 -1
- package/dist/pactile/parallel/batch.js +271 -50
- package/dist/pactile/parallel/batch.js.map +1 -1
- package/dist/pactile/parallel/policy.d.ts +1 -1
- package/dist/pactile/parallel/policy.d.ts.map +1 -1
- package/dist/pactile/parallel/policy.js +130 -102
- package/dist/pactile/parallel/policy.js.map +1 -1
- package/dist/pactile/pi/bridge.d.ts +139 -2
- package/dist/pactile/pi/bridge.d.ts.map +1 -1
- package/dist/pactile/pi/bridge.js +1317 -106
- package/dist/pactile/pi/bridge.js.map +1 -1
- package/dist/pactile/pi/rpc.d.ts +23 -4
- package/dist/pactile/pi/rpc.d.ts.map +1 -1
- package/dist/pactile/pi/rpc.js +243 -42
- package/dist/pactile/pi/rpc.js.map +1 -1
- package/dist/pactile/pi/v2-dispatch.d.ts +113 -0
- package/dist/pactile/pi/v2-dispatch.d.ts.map +1 -0
- package/dist/pactile/pi/v2-dispatch.js +919 -0
- package/dist/pactile/pi/v2-dispatch.js.map +1 -0
- package/dist/pactile/projection/planner.js +1 -1
- package/dist/pactile/projection/planner.js.map +1 -1
- package/dist/pactile/registry.d.ts +63 -1
- package/dist/pactile/registry.d.ts.map +1 -1
- package/dist/pactile/registry.js +633 -4
- package/dist/pactile/registry.js.map +1 -1
- package/dist/pactile/retrieval/index.d.ts +1 -0
- package/dist/pactile/retrieval/index.d.ts.map +1 -1
- package/dist/pactile/retrieval/index.js +1 -0
- package/dist/pactile/retrieval/index.js.map +1 -1
- package/dist/pactile/retrieval/jev-planning.d.ts +28 -0
- package/dist/pactile/retrieval/jev-planning.d.ts.map +1 -0
- package/dist/pactile/retrieval/jev-planning.js +96 -0
- package/dist/pactile/retrieval/jev-planning.js.map +1 -0
- package/dist/pactile/review/contract.d.ts +232 -0
- package/dist/pactile/review/contract.d.ts.map +1 -0
- package/dist/pactile/review/contract.js +695 -0
- package/dist/pactile/review/contract.js.map +1 -0
- package/dist/pactile/review/escalation-artifacts.d.ts +41 -0
- package/dist/pactile/review/escalation-artifacts.d.ts.map +1 -0
- package/dist/pactile/review/escalation-artifacts.js +415 -0
- package/dist/pactile/review/escalation-artifacts.js.map +1 -0
- package/dist/pactile/review/escalation-contract.d.ts +115 -0
- package/dist/pactile/review/escalation-contract.d.ts.map +1 -0
- package/dist/pactile/review/escalation-contract.js +151 -0
- package/dist/pactile/review/escalation-contract.js.map +1 -0
- package/dist/pactile/review/escalation-finalize.d.ts +14 -0
- package/dist/pactile/review/escalation-finalize.d.ts.map +1 -0
- package/dist/pactile/review/escalation-finalize.js +319 -0
- package/dist/pactile/review/escalation-finalize.js.map +1 -0
- package/dist/pactile/review/escalation-reply.d.ts +10 -0
- package/dist/pactile/review/escalation-reply.d.ts.map +1 -0
- package/dist/pactile/review/escalation-reply.js +61 -0
- package/dist/pactile/review/escalation-reply.js.map +1 -0
- package/dist/pactile/review/escalation-transport.d.ts +32 -0
- package/dist/pactile/review/escalation-transport.d.ts.map +1 -0
- package/dist/pactile/review/escalation-transport.js +216 -0
- package/dist/pactile/review/escalation-transport.js.map +1 -0
- package/dist/pactile/review/escalation.d.ts +7 -0
- package/dist/pactile/review/escalation.d.ts.map +1 -0
- package/dist/pactile/review/escalation.js +6 -0
- package/dist/pactile/review/escalation.js.map +1 -0
- package/dist/pactile/review/evidence.d.ts +25 -0
- package/dist/pactile/review/evidence.d.ts.map +1 -0
- package/dist/pactile/review/evidence.js +58 -0
- package/dist/pactile/review/evidence.js.map +1 -0
- package/dist/pactile/review/jev-escalation-advice.d.ts +77 -0
- package/dist/pactile/review/jev-escalation-advice.d.ts.map +1 -0
- package/dist/pactile/review/jev-escalation-advice.js +358 -0
- package/dist/pactile/review/jev-escalation-advice.js.map +1 -0
- package/dist/pactile/scheduler/index.d.ts +6 -0
- package/dist/pactile/scheduler/index.d.ts.map +1 -0
- package/dist/pactile/scheduler/index.js +5 -0
- package/dist/pactile/scheduler/index.js.map +1 -0
- package/dist/pactile/scheduler/project-lease-store.d.ts +35 -0
- package/dist/pactile/scheduler/project-lease-store.d.ts.map +1 -0
- package/dist/pactile/scheduler/project-lease-store.js +189 -0
- package/dist/pactile/scheduler/project-lease-store.js.map +1 -0
- package/dist/pactile/scheduler/scheduler.d.ts +91 -0
- package/dist/pactile/scheduler/scheduler.d.ts.map +1 -0
- package/dist/pactile/scheduler/scheduler.js +589 -0
- package/dist/pactile/scheduler/scheduler.js.map +1 -0
- package/dist/pactile/scheduler/task-kernel-admission.d.ts +173 -0
- package/dist/pactile/scheduler/task-kernel-admission.d.ts.map +1 -0
- package/dist/pactile/scheduler/task-kernel-admission.js +1560 -0
- package/dist/pactile/scheduler/task-kernel-admission.js.map +1 -0
- package/dist/pactile/scheduler/task-kernel-wave-dispatch.d.ts +184 -0
- package/dist/pactile/scheduler/task-kernel-wave-dispatch.d.ts.map +1 -0
- package/dist/pactile/scheduler/task-kernel-wave-dispatch.js +952 -0
- package/dist/pactile/scheduler/task-kernel-wave-dispatch.js.map +1 -0
- package/dist/pactile/scheduler/task-map-scheduler.d.ts +116 -0
- package/dist/pactile/scheduler/task-map-scheduler.d.ts.map +1 -0
- package/dist/pactile/scheduler/task-map-scheduler.js +1448 -0
- package/dist/pactile/scheduler/task-map-scheduler.js.map +1 -0
- package/dist/pactile/scheduler/task-run-dispatch-state.d.ts +7 -0
- package/dist/pactile/scheduler/task-run-dispatch-state.d.ts.map +1 -0
- package/dist/pactile/scheduler/task-run-dispatch-state.js +69 -0
- package/dist/pactile/scheduler/task-run-dispatch-state.js.map +1 -0
- package/dist/pactile/task/authorization.d.ts +3 -0
- package/dist/pactile/task/authorization.d.ts.map +1 -0
- package/dist/pactile/task/authorization.js +43 -0
- package/dist/pactile/task/authorization.js.map +1 -0
- package/dist/pactile/task/creation.d.ts +22 -0
- package/dist/pactile/task/creation.d.ts.map +1 -0
- package/dist/pactile/task/creation.js +95 -0
- package/dist/pactile/task/creation.js.map +1 -0
- package/dist/pactile/task/guards.d.ts +1 -4
- package/dist/pactile/task/guards.d.ts.map +1 -1
- package/dist/pactile/task/guards.js +5 -57
- package/dist/pactile/task/guards.js.map +1 -1
- package/dist/pactile/task/session-jev-receipt.d.ts +58 -0
- package/dist/pactile/task/session-jev-receipt.d.ts.map +1 -0
- package/dist/pactile/task/session-jev-receipt.js +375 -0
- package/dist/pactile/task/session-jev-receipt.js.map +1 -0
- package/dist/pactile/task/session-jev.d.ts +7 -0
- package/dist/pactile/task/session-jev.d.ts.map +1 -0
- package/dist/pactile/task/session-jev.js +217 -0
- package/dist/pactile/task/session-jev.js.map +1 -0
- package/dist/pactile/task/session-pack.d.ts.map +1 -1
- package/dist/pactile/task/session-pack.js +155 -16
- package/dist/pactile/task/session-pack.js.map +1 -1
- package/dist/pactile/task/session-retrieval-jev-receipt.d.ts +49 -0
- package/dist/pactile/task/session-retrieval-jev-receipt.d.ts.map +1 -0
- package/dist/pactile/task/session-retrieval-jev-receipt.js +97 -0
- package/dist/pactile/task/session-retrieval-jev-receipt.js.map +1 -0
- package/dist/pactile/task/session-retrieval-jev.d.ts +8 -0
- package/dist/pactile/task/session-retrieval-jev.d.ts.map +1 -0
- package/dist/pactile/task/session-retrieval-jev.js +352 -0
- package/dist/pactile/task/session-retrieval-jev.js.map +1 -0
- package/dist/pactile/task/strategy.d.ts +1 -23
- package/dist/pactile/task/strategy.d.ts.map +1 -1
- package/dist/pactile/task/strategy.js +2 -135
- package/dist/pactile/task/strategy.js.map +1 -1
- package/dist/pactile/tiles/jev-selection.d.ts +44 -0
- package/dist/pactile/tiles/jev-selection.d.ts.map +1 -0
- package/dist/pactile/tiles/jev-selection.js +210 -0
- package/dist/pactile/tiles/jev-selection.js.map +1 -0
- package/dist/pactile/tiles/safe-yaml.d.ts +5 -1
- package/dist/pactile/tiles/safe-yaml.d.ts.map +1 -1
- package/dist/pactile/tiles/safe-yaml.js +8 -8
- package/dist/pactile/tiles/safe-yaml.js.map +1 -1
- package/dist/pactile/tiles/selection-receipts.d.ts +71 -0
- package/dist/pactile/tiles/selection-receipts.d.ts.map +1 -0
- package/dist/pactile/tiles/selection-receipts.js +319 -0
- package/dist/pactile/tiles/selection-receipts.js.map +1 -0
- package/dist/pactile/tiles/selection.d.ts +185 -0
- package/dist/pactile/tiles/selection.d.ts.map +1 -0
- package/dist/pactile/tiles/selection.js +985 -0
- package/dist/pactile/tiles/selection.js.map +1 -0
- package/dist/pactile/verification/git-observer.d.ts +3 -0
- package/dist/pactile/verification/git-observer.d.ts.map +1 -0
- package/dist/pactile/verification/git-observer.js +3 -0
- package/dist/pactile/verification/git-observer.js.map +1 -0
- package/dist/pactile/verification/index.d.ts +11 -0
- package/dist/pactile/verification/index.d.ts.map +1 -0
- package/dist/pactile/verification/index.js +6 -0
- package/dist/pactile/verification/index.js.map +1 -0
- package/dist/pactile/verification/jev-advice.d.ts +78 -0
- package/dist/pactile/verification/jev-advice.d.ts.map +1 -0
- package/dist/pactile/verification/jev-advice.js +397 -0
- package/dist/pactile/verification/jev-advice.js.map +1 -0
- package/dist/pactile/verification/planner.d.ts +15 -0
- package/dist/pactile/verification/planner.d.ts.map +1 -0
- package/dist/pactile/verification/planner.js +412 -0
- package/dist/pactile/verification/planner.js.map +1 -0
- package/dist/pactile/verification/receipt.d.ts +101 -0
- package/dist/pactile/verification/receipt.d.ts.map +1 -0
- package/dist/pactile/verification/receipt.js +400 -0
- package/dist/pactile/verification/receipt.js.map +1 -0
- package/dist/pactile/verification/types.d.ts +72 -0
- package/dist/pactile/verification/types.d.ts.map +1 -0
- package/dist/pactile/verification/types.js +21 -0
- package/dist/pactile/verification/types.js.map +1 -0
- package/dist/pactile/worktree/git-probe.d.ts +32 -0
- package/dist/pactile/worktree/git-probe.d.ts.map +1 -0
- package/dist/pactile/worktree/git-probe.js +336 -0
- package/dist/pactile/worktree/git-probe.js.map +1 -0
- package/dist/pactile/worktree/git-removal.d.ts +3 -0
- package/dist/pactile/worktree/git-removal.d.ts.map +1 -0
- package/dist/pactile/worktree/git-removal.js +11 -0
- package/dist/pactile/worktree/git-removal.js.map +1 -0
- package/dist/pactile/worktree/index.d.ts +2 -0
- package/dist/pactile/worktree/index.d.ts.map +1 -0
- package/dist/pactile/worktree/index.js +2 -0
- package/dist/pactile/worktree/index.js.map +1 -0
- package/dist/pactile/worktree/integration-evidence.d.ts +80 -0
- package/dist/pactile/worktree/integration-evidence.d.ts.map +1 -0
- package/dist/pactile/worktree/integration-evidence.js +166 -0
- package/dist/pactile/worktree/integration-evidence.js.map +1 -0
- package/dist/pactile/worktree/manager-core.d.ts +50 -0
- package/dist/pactile/worktree/manager-core.d.ts.map +1 -0
- package/dist/pactile/worktree/manager-core.js +359 -0
- package/dist/pactile/worktree/manager-core.js.map +1 -0
- package/dist/pactile/worktree/manager-provenance.d.ts +32 -0
- package/dist/pactile/worktree/manager-provenance.d.ts.map +1 -0
- package/dist/pactile/worktree/manager-provenance.js +409 -0
- package/dist/pactile/worktree/manager-provenance.js.map +1 -0
- package/dist/pactile/worktree/manager-types.d.ts +84 -0
- package/dist/pactile/worktree/manager-types.d.ts.map +1 -0
- package/dist/pactile/worktree/manager-types.js +11 -0
- package/dist/pactile/worktree/manager-types.js.map +1 -0
- package/dist/pactile/worktree/manager.d.ts +10 -0
- package/dist/pactile/worktree/manager.d.ts.map +1 -0
- package/dist/pactile/worktree/manager.js +6 -0
- package/dist/pactile/worktree/manager.js.map +1 -0
- package/dist/pactile/worktree/run-workspace-cleanup.d.ts +10 -0
- package/dist/pactile/worktree/run-workspace-cleanup.d.ts.map +1 -0
- package/dist/pactile/worktree/run-workspace-cleanup.js +695 -0
- package/dist/pactile/worktree/run-workspace-cleanup.js.map +1 -0
- package/dist/pactile/worktree/run-workspace-lifecycle.d.ts +65 -0
- package/dist/pactile/worktree/run-workspace-lifecycle.d.ts.map +1 -0
- package/dist/pactile/worktree/run-workspace-lifecycle.js +276 -0
- package/dist/pactile/worktree/run-workspace-lifecycle.js.map +1 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-hooks.md +1 -1
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/generated-files.md +1 -1
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/hooks-and-settings.md +1 -1
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/overview.md +1 -1
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/platform-map.md +1 -1
- package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +2 -0
- package/dist/templates/common/skills/brainstorm.md +19 -13
- package/dist/templates/markdown/agents.md +2 -2
- package/dist/templates/markdown/framework/execution-strategy.md.txt +1 -1
- package/dist/templates/markdown/framework/index.md.txt +1 -1
- package/dist/templates/markdown/framework/parallel-first-execution.md.txt +17 -105
- package/dist/templates/markdown/framework/prd-grill-frontier.md.txt +3 -3
- package/dist/templates/markdown/framework/release-boundary.md.txt +9 -10
- package/dist/templates/markdown/framework/retrieval-daily-guide.md.txt +1 -1
- package/dist/templates/pactile/CONTEXT.md +48 -36
- package/dist/templates/pactile/modules/approval-personal/contract.md +12 -24
- package/dist/templates/pactile/modules/close-basic/contract.md +15 -18
- package/dist/templates/pactile/modules/debug-recovery/contract.md +4 -4
- package/dist/templates/pactile/modules/define-basic/contract.md +15 -19
- package/dist/templates/pactile/modules/define-extended/contract.md +3 -3
- package/dist/templates/pactile/modules/execute-agent/contract.md +11 -19
- package/dist/templates/pactile/modules/intake-basic/contract.md +16 -13
- package/dist/templates/pactile/modules/verify-basic/contract.md +11 -20
- package/dist/templates/pactile/tasks/templates/release-execution/design.md +5 -5
- package/dist/templates/pactile/tasks/templates/release-readiness/design.md +6 -6
- package/dist/templates/pactile/tasks/templates/release-readiness/handoff-template.md +8 -2
- package/dist/templates/pactile/workflow.md +37 -41
- package/dist/templates/template-utils.d.ts +1 -2
- package/dist/templates/template-utils.d.ts.map +1 -1
- package/dist/templates/template-utils.js +2 -13
- package/dist/templates/template-utils.js.map +1 -1
- package/dist/types/ai-tools.d.ts +1 -1
- package/dist/types/ai-tools.js +1 -1
- package/dist/utils/manifest-prune.js +1 -1
- package/dist/utils/manifest-prune.js.map +1 -1
- package/dist/utils/p36-upgrade.d.ts +2 -2
- package/dist/utils/p36-upgrade.d.ts.map +1 -1
- package/dist/utils/p36-upgrade.js +2 -10
- package/dist/utils/p36-upgrade.js.map +1 -1
- package/dist/utils/post-update-smoke.js +1 -1
- package/dist/utils/post-update-smoke.js.map +1 -1
- package/dist/utils/readiness.d.ts +2 -2
- package/dist/utils/readiness.js +2 -2
- package/dist/utils/uninstall-scrubbers.js +1 -1
- package/dist/utils/workflow-dir.d.ts +1 -1
- package/dist/utils/workflow-dir.d.ts.map +1 -1
- package/dist/utils/workflow-dir.js +1 -1
- package/dist/utils/workflow-dir.js.map +1 -1
- package/package.json +42 -37
- package/CHANGELOG.md +0 -651
- package/bin/compat-warning.js +0 -11
- package/bin/pactile.js +0 -3
- package/bin/smart-search.js +0 -38
- package/dist/migrations/manifests/0.1.0.json +0 -9
- package/dist/migrations/manifests/0.1.1.json +0 -9
- package/dist/migrations/manifests/0.1.2.json +0 -9
- package/dist/migrations/manifests/0.1.3.json +0 -9
- package/dist/migrations/manifests/0.1.4.json +0 -9
- package/dist/migrations/manifests/0.2.1.json +0 -9
- package/dist/migrations/manifests/0.2.10.json +0 -374
- package/dist/migrations/manifests/0.2.2.json +0 -9
- package/dist/migrations/manifests/0.2.3.json +0 -9
- package/dist/migrations/manifests/0.2.4.json +0 -9
- package/dist/migrations/manifests/0.2.5.json +0 -9
- package/dist/migrations/manifests/0.2.6.json +0 -9
- package/dist/migrations/manifests/0.2.7.json +0 -9
- package/dist/migrations/manifests/0.2.8.json +0 -9
- package/dist/migrations/manifests/0.2.9.json +0 -9
- package/dist/migrations/manifests/0.3.0.json +0 -89
- package/dist/migrations/manifests/0.3.1.json +0 -32
- package/dist/migrations/manifests/0.3.2.json +0 -16
- package/dist/migrations/manifests/0.3.3.json +0 -9
- package/dist/migrations/manifests/0.3.4.json +0 -9
- package/dist/migrations/manifests/0.3.5.json +0 -9
- package/dist/migrations/manifests/0.3.6.json +0 -9
- package/dist/migrations/manifests/0.4.0.json +0 -9
- package/dist/migrations/manifests/0.4.1.json +0 -9
- package/dist/migrations/manifests/0.4.2.json +0 -9
- package/dist/migrations/manifests/0.4.3.json +0 -9
- package/dist/migrations/manifests/0.5.0-beta.0.json +0 -9
- package/dist/migrations/manifests/0.5.0-beta.1.json +0 -9
- package/dist/migrations/manifests/0.5.0-beta.2.json +0 -9
- package/dist/migrations/manifests/0.5.0-beta.3.json +0 -9
- package/dist/migrations/manifests/0.5.0-beta.4.json +0 -9
- package/dist/migrations/manifests/0.5.0-beta.5.json +0 -9
- package/dist/migrations/manifests/0.5.0.json +0 -9
- package/dist/pactile/compat/retired-alternate-client.d.ts +0 -42
- package/dist/pactile/compat/retired-alternate-client.d.ts.map +0 -1
- package/dist/pactile/compat/retired-alternate-client.js +0 -153
- package/dist/pactile/compat/retired-alternate-client.js.map +0 -1
- package/dist/pactile/compat/update-residue.d.ts +0 -4
- package/dist/pactile/compat/update-residue.d.ts.map +0 -1
- package/dist/pactile/compat/update-residue.js +0 -55
- package/dist/pactile/compat/update-residue.js.map +0 -1
- package/dist/utils/cursor-retrieval-env.d.ts +0 -17
- package/dist/utils/cursor-retrieval-env.d.ts.map +0 -1
- package/dist/utils/cursor-retrieval-env.js +0 -19
- package/dist/utils/cursor-retrieval-env.js.map +0 -1
- package/dist/utils/proxy.d.ts +0 -25
- package/dist/utils/proxy.d.ts.map +0 -1
- package/dist/utils/proxy.js +0 -60
- package/dist/utils/proxy.js.map +0 -1
- package/scripts/postinstall.js +0 -6
|
@@ -1,20 +1,58 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { fingerprintTaskValue, readTaskKernel, } from "../../core/task/index.js";
|
|
5
5
|
import { resolveTaskDir } from "../task/session.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { approvedExecuteTask } from "../task/authorization.js";
|
|
7
|
+
import { readStrategyContract } from "../task/strategy.js";
|
|
8
|
+
import { parallelChild, releaseParallelChild, reserveParallelChild, } from "../parallel/policy.js";
|
|
9
|
+
import { CoordinationStore, } from "../coordination/index.js";
|
|
10
|
+
import { assertCurrentPiReviewEscalationV1, assertCodexEscalationSendPromptV1, buildCodexEscalationPromptV1, readCodexEscalationSendV1, readPiReviewEscalationV1, } from "../review/escalation.js";
|
|
11
|
+
import { withProjectSchedulerMutex } from "../scheduler/project-lease-store.js";
|
|
12
|
+
export { readCodexHostStopReceipts, } from "./host-stop.js";
|
|
8
13
|
const idPattern = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
9
14
|
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15
|
+
const escalationIdPattern = /^pi-escalation:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16
|
+
const transportIdentifierPattern = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
17
|
+
const escalationSecretPattern = /\b(?:bearer\s+[a-z0-9._~+/-]{12,}|(?:sk[-_]|gh[pousr]_|glpat-|plane_api_)[a-z0-9_-]{12,}|(?:api[_-]?key|token|password|secret)\s*[:=]\s*\S+)/iu;
|
|
18
|
+
function taskContextFromDirectory(root, dir, archived) {
|
|
19
|
+
const read = readTaskKernel({ root, taskDir: dir, cwd: root });
|
|
20
|
+
if (read.kind === "task-kernel-v2") {
|
|
21
|
+
const kernel = read.kernel;
|
|
22
|
+
return {
|
|
23
|
+
dir,
|
|
24
|
+
task: path.relative(root, dir).replaceAll("\\", "/"),
|
|
25
|
+
taskId: kernel.identity.taskId,
|
|
26
|
+
phase: kernel.phase,
|
|
27
|
+
revision: kernel.revision,
|
|
28
|
+
kernelKind: read.kind,
|
|
29
|
+
contractFingerprint: fingerprintTaskValue(kernel.definition),
|
|
30
|
+
events: kernel.events,
|
|
31
|
+
runs: kernel.runs,
|
|
32
|
+
reviews: kernel.reviews,
|
|
33
|
+
archived,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const kernel = read.kernel.kernel;
|
|
37
|
+
return {
|
|
38
|
+
dir,
|
|
39
|
+
task: path.relative(root, dir).replaceAll("\\", "/"),
|
|
40
|
+
taskId: kernel.identity.taskId,
|
|
41
|
+
phase: kernel.phase,
|
|
42
|
+
revision: kernel.revision,
|
|
43
|
+
kernelKind: read.kind,
|
|
44
|
+
contractFingerprint: null,
|
|
45
|
+
events: [],
|
|
46
|
+
runs: [],
|
|
47
|
+
reviews: [],
|
|
48
|
+
archived,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
10
51
|
function taskContext(root, reference) {
|
|
11
52
|
const dir = resolveTaskDir(root, reference);
|
|
12
53
|
if (!fs.statSync(dir, { throwIfNoEntry: false })?.isDirectory())
|
|
13
54
|
throw new Error(`Task not found: ${reference}`);
|
|
14
|
-
|
|
15
|
-
if (!kernel.projection)
|
|
16
|
-
throw new Error("Task has no canonical Kernel projection");
|
|
17
|
-
return { dir, task: path.relative(root, dir).replaceAll("\\", "/"), phase: kernel.phase, revision: kernel.revision };
|
|
55
|
+
return taskContextFromDirectory(root, dir, false);
|
|
18
56
|
}
|
|
19
57
|
function archivedTaskContext(root, reference) {
|
|
20
58
|
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(reference))
|
|
@@ -22,28 +60,191 @@ function archivedTaskContext(root, reference) {
|
|
|
22
60
|
const archive = path.join(root, ".pactile", "tasks", "archive");
|
|
23
61
|
if (!fs.statSync(archive, { throwIfNoEntry: false })?.isDirectory())
|
|
24
62
|
throw new Error(`Task not found: ${reference}`);
|
|
25
|
-
const matches = fs
|
|
63
|
+
const matches = fs
|
|
64
|
+
.readdirSync(archive, { withFileTypes: true })
|
|
26
65
|
.filter((entry) => entry.isDirectory() && /^\d{4}-\d{2}$/.test(entry.name))
|
|
27
|
-
.flatMap((entry) => fs
|
|
28
|
-
.
|
|
66
|
+
.flatMap((entry) => fs
|
|
67
|
+
.readdirSync(path.join(archive, entry.name), { withFileTypes: true })
|
|
68
|
+
.filter((task) => task.isDirectory() &&
|
|
69
|
+
(task.name === reference || task.name.endsWith(`-${reference}`)))
|
|
29
70
|
.map((task) => path.join(archive, entry.name, task.name)));
|
|
30
71
|
if (matches.length !== 1)
|
|
31
|
-
throw new Error(matches.length
|
|
72
|
+
throw new Error(matches.length
|
|
73
|
+
? `Archived task reference is ambiguous: ${reference}`
|
|
74
|
+
: `Task not found: ${reference}`);
|
|
32
75
|
const dir = matches[0];
|
|
33
76
|
const realArchive = fs.realpathSync(archive);
|
|
34
77
|
const relative = path.relative(realArchive, fs.realpathSync(dir));
|
|
35
78
|
if (relative.startsWith("..") || path.isAbsolute(relative))
|
|
36
79
|
throw new Error("Archived task resolves outside the task archive");
|
|
37
|
-
|
|
38
|
-
|
|
80
|
+
return taskContextFromDirectory(root, dir, true);
|
|
81
|
+
}
|
|
82
|
+
function taskContextIncludingArchive(root, reference) {
|
|
83
|
+
try {
|
|
84
|
+
return taskContext(root, reference);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!(error instanceof Error) ||
|
|
88
|
+
!error.message.startsWith("Task not found:")) {
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
return archivedTaskContext(root, reference);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function selectRun(context, role, requestedRunId, requireRunning = false) {
|
|
95
|
+
if (context.kernelKind !== "task-kernel-v2") {
|
|
96
|
+
if (requestedRunId)
|
|
97
|
+
throw new Error("--run-id requires a Task Kernel v2 task");
|
|
98
|
+
return {
|
|
99
|
+
runId: null,
|
|
100
|
+
candidateSnapshotId: null,
|
|
101
|
+
candidateFingerprint: null,
|
|
102
|
+
run: null,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const run = requestedRunId
|
|
106
|
+
? context.runs.find((candidate) => candidate.id === requestedRunId)
|
|
107
|
+
: role === "review"
|
|
108
|
+
? [...context.runs]
|
|
109
|
+
.reverse()
|
|
110
|
+
.find((candidate) => candidate.candidateSnapshot)
|
|
111
|
+
: [...context.runs]
|
|
112
|
+
.reverse()
|
|
113
|
+
.find((candidate) => candidate.state === "running" || candidate.state === "waiting");
|
|
114
|
+
if (requestedRunId && !run)
|
|
115
|
+
throw new Error(`Run not found on Task ${context.taskId}: ${requestedRunId}`);
|
|
116
|
+
if (role === "execute" &&
|
|
117
|
+
requireRunning &&
|
|
118
|
+
run?.state !== "running" &&
|
|
119
|
+
run?.state !== "waiting") {
|
|
120
|
+
throw new Error("Codex Execute dispatch requires a running or waiting Task Kernel v2 Run");
|
|
121
|
+
}
|
|
122
|
+
if (role === "review" &&
|
|
123
|
+
context.phase === "verify" &&
|
|
124
|
+
!run?.candidateSnapshot) {
|
|
125
|
+
throw new Error("Codex Review requires the latest Run candidate snapshot");
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
runId: run?.id ?? null,
|
|
129
|
+
candidateSnapshotId: run?.candidateSnapshot?.id ?? null,
|
|
130
|
+
candidateFingerprint: run?.candidateSnapshot?.fingerprint ?? null,
|
|
131
|
+
run: run ?? null,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function bridgeDir(dir) {
|
|
135
|
+
return path.join(dir, "codex-bridge");
|
|
136
|
+
}
|
|
137
|
+
function requestFile(dir, id) {
|
|
138
|
+
return path.join(bridgeDir(dir), "requests", `${id}.json`);
|
|
139
|
+
}
|
|
140
|
+
function receiptFile(dir, id) {
|
|
141
|
+
return path.join(bridgeDir(dir), "receipts", `${id}.json`);
|
|
142
|
+
}
|
|
143
|
+
function queuedFile(dir, id) {
|
|
144
|
+
return path.join(bridgeDir(dir), "queued", `${id}.json`);
|
|
39
145
|
}
|
|
40
|
-
function bridgeDir(dir) { return path.join(dir, "codex-bridge"); }
|
|
41
|
-
function requestFile(dir, id) { return path.join(bridgeDir(dir), "requests", `${id}.json`); }
|
|
42
|
-
function receiptFile(dir, id) { return path.join(bridgeDir(dir), "receipts", `${id}.json`); }
|
|
43
|
-
function queuedFile(dir, id) { return path.join(bridgeDir(dir), "queued", `${id}.json`); }
|
|
44
146
|
function writeNew(file, value) {
|
|
45
147
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
46
|
-
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, {
|
|
148
|
+
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, {
|
|
149
|
+
encoding: "utf8",
|
|
150
|
+
flag: "wx",
|
|
151
|
+
mode: 0o600,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function codexRequestFingerprint(request) {
|
|
155
|
+
const { request_fingerprint: _stored, ...payload } = request;
|
|
156
|
+
return fingerprintTaskValue(payload);
|
|
157
|
+
}
|
|
158
|
+
function verifyFreshCoordinationMessage(root, entry, destinationContext, requireNative) {
|
|
159
|
+
const message = entry.message;
|
|
160
|
+
const requestId = message.request_id;
|
|
161
|
+
if (!requestId ||
|
|
162
|
+
!uuidPattern.test(requestId) ||
|
|
163
|
+
!new Set(["sent", "delivered", "acknowledged"]).has(entry.status)) {
|
|
164
|
+
throw new Error("Coordination message has no successful bound request");
|
|
165
|
+
}
|
|
166
|
+
const sourceContext = taskContext(root, message.from_task_id);
|
|
167
|
+
const request = readJson(requestFile(sourceContext.dir, requestId));
|
|
168
|
+
const receipt = readJson(receiptFile(sourceContext.dir, requestId));
|
|
169
|
+
const sendReceipt = entry.receipts.find((candidate) => candidate.receipt_id === requestId);
|
|
170
|
+
const evidenceLevel = receipt.evidence_level;
|
|
171
|
+
const requestFingerprint = codexRequestFingerprint(request);
|
|
172
|
+
const sourceBound = !sourceContext.archived &&
|
|
173
|
+
request.request_id === requestId &&
|
|
174
|
+
request.request_fingerprint === requestFingerprint &&
|
|
175
|
+
request.task === sourceContext.task &&
|
|
176
|
+
request.task_id === sourceContext.taskId &&
|
|
177
|
+
request.task_kernel_kind === sourceContext.kernelKind &&
|
|
178
|
+
request.kernel_revision === sourceContext.revision &&
|
|
179
|
+
(request.contract_fingerprint ?? null) ===
|
|
180
|
+
sourceContext.contractFingerprint &&
|
|
181
|
+
(request.run_id ?? null) === message.from_run_id &&
|
|
182
|
+
isRunBoundToContext(sourceContext, request.run_id, request.candidate_snapshot_id, request.candidate_fingerprint);
|
|
183
|
+
const destinationBound = !destinationContext.archived &&
|
|
184
|
+
request.to_task === path.basename(destinationContext.dir) &&
|
|
185
|
+
request.to_task_id === destinationContext.taskId &&
|
|
186
|
+
request.to_task_kernel_kind === destinationContext.kernelKind &&
|
|
187
|
+
request.to_kernel_revision === destinationContext.revision &&
|
|
188
|
+
(request.to_contract_fingerprint ?? null) ===
|
|
189
|
+
destinationContext.contractFingerprint &&
|
|
190
|
+
(request.to_run_id ?? null) === message.to_run_id &&
|
|
191
|
+
isRunBoundToContext(destinationContext, request.to_run_id, request.to_candidate_snapshot_id, request.to_candidate_fingerprint);
|
|
192
|
+
if (!sourceBound ||
|
|
193
|
+
!destinationBound ||
|
|
194
|
+
message.message_id !== request.coordination_message_id ||
|
|
195
|
+
message.message_id !== requestId ||
|
|
196
|
+
message.host_ref !== request.thread_id ||
|
|
197
|
+
request.tool !== "send_message_to_thread" ||
|
|
198
|
+
!request.thread_id ||
|
|
199
|
+
!request.host_id ||
|
|
200
|
+
receipt.schema_version !== 1 ||
|
|
201
|
+
receipt.request_id !== requestId ||
|
|
202
|
+
receipt.request_fingerprint !== requestFingerprint ||
|
|
203
|
+
receipt.task_id !== sourceContext.taskId ||
|
|
204
|
+
(receipt.run_id ?? null) !== (request.run_id ?? null) ||
|
|
205
|
+
(receipt.candidate_snapshot_id ?? null) !==
|
|
206
|
+
(request.candidate_snapshot_id ?? null) ||
|
|
207
|
+
(receipt.candidate_fingerprint ?? null) !==
|
|
208
|
+
(request.candidate_fingerprint ?? null) ||
|
|
209
|
+
(receipt.to_task_id ?? null) !== destinationContext.taskId ||
|
|
210
|
+
(receipt.to_run_id ?? null) !== (request.to_run_id ?? null) ||
|
|
211
|
+
(receipt.to_candidate_snapshot_id ?? null) !==
|
|
212
|
+
(request.to_candidate_snapshot_id ?? null) ||
|
|
213
|
+
(receipt.to_candidate_fingerprint ?? null) !==
|
|
214
|
+
(request.to_candidate_fingerprint ?? null) ||
|
|
215
|
+
receipt.destination_kernel_revision_at_receipt !==
|
|
216
|
+
request.to_kernel_revision ||
|
|
217
|
+
receipt.kernel_revision_at_receipt !== request.kernel_revision ||
|
|
218
|
+
receipt.thread_id !== request.thread_id ||
|
|
219
|
+
receipt.host_id !== request.host_id ||
|
|
220
|
+
receipt.tool !== request.tool ||
|
|
221
|
+
receipt.outcome !== "ok" ||
|
|
222
|
+
receipt.contract_stale !== false ||
|
|
223
|
+
!sendReceipt ||
|
|
224
|
+
!new Set(["sent", "delivered", "acknowledged"]).has(sendReceipt.status) ||
|
|
225
|
+
sendReceipt.evidence_level !== evidenceLevel ||
|
|
226
|
+
(evidenceLevel !== "simulated" && evidenceLevel !== "desktop-native") ||
|
|
227
|
+
(requireNative && evidenceLevel !== "desktop-native")) {
|
|
228
|
+
throw new Error("Coordination message request or receipt is stale, misbound, or not authoritative");
|
|
229
|
+
}
|
|
230
|
+
return { evidenceLevel, sourceContext };
|
|
231
|
+
}
|
|
232
|
+
function coordinationKernelBarrier(context) {
|
|
233
|
+
if (context.kernelKind !== "task-kernel-v2") {
|
|
234
|
+
return { runId: null, kernelRevision: null, kernelEventId: null };
|
|
235
|
+
}
|
|
236
|
+
const lastEvent = context.events.at(-1);
|
|
237
|
+
if (lastEvent?.revision !== context.revision) {
|
|
238
|
+
throw new Error("Cannot bind coordination unblock to the current Kernel event");
|
|
239
|
+
}
|
|
240
|
+
const activeRun = [...context.runs]
|
|
241
|
+
.reverse()
|
|
242
|
+
.find((run) => run.state === "running" || run.state === "waiting");
|
|
243
|
+
return {
|
|
244
|
+
runId: activeRun?.id ?? null,
|
|
245
|
+
kernelRevision: context.revision,
|
|
246
|
+
kernelEventId: lastEvent.id,
|
|
247
|
+
};
|
|
47
248
|
}
|
|
48
249
|
function readJson(file) {
|
|
49
250
|
const value = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
@@ -55,9 +256,12 @@ function requests(dir) {
|
|
|
55
256
|
const folder = path.join(bridgeDir(dir), "requests");
|
|
56
257
|
if (!fs.existsSync(folder))
|
|
57
258
|
return [];
|
|
58
|
-
return fs
|
|
259
|
+
return fs
|
|
260
|
+
.readdirSync(folder)
|
|
261
|
+
.filter((file) => uuidPattern.test(file.replace(/\.json$/, "")) && file.endsWith(".json"))
|
|
59
262
|
.map((file) => readJson(path.join(folder, file)))
|
|
60
|
-
.sort((left, right) => left.created_at.localeCompare(right.created_at) ||
|
|
263
|
+
.sort((left, right) => left.created_at.localeCompare(right.created_at) ||
|
|
264
|
+
left.request_id.localeCompare(right.request_id));
|
|
61
265
|
}
|
|
62
266
|
function boundThreads(dir) {
|
|
63
267
|
const bound = new Map();
|
|
@@ -68,12 +272,72 @@ function boundThreads(dir) {
|
|
|
68
272
|
if (!fs.existsSync(file))
|
|
69
273
|
continue;
|
|
70
274
|
const receipt = readJson(file);
|
|
71
|
-
if (receipt.outcome === "ok" &&
|
|
72
|
-
|
|
275
|
+
if (receipt.outcome === "ok" &&
|
|
276
|
+
receipt.contract_stale !== true &&
|
|
277
|
+
typeof receipt.thread_id === "string" &&
|
|
278
|
+
typeof receipt.host_id === "string") {
|
|
279
|
+
bound.set(receipt.thread_id, {
|
|
280
|
+
threadId: receipt.thread_id,
|
|
281
|
+
hostId: receipt.host_id,
|
|
282
|
+
role: request.role,
|
|
283
|
+
runId: request.run_id ?? null,
|
|
284
|
+
dispatchLeaseId: request.dispatch_lease_id ?? null,
|
|
285
|
+
});
|
|
73
286
|
}
|
|
74
287
|
}
|
|
75
288
|
return bound;
|
|
76
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* A Plan thread can outlive the Kernel revision that created it. Reuse that
|
|
292
|
+
* thread only for a coordination message, and only when its original request
|
|
293
|
+
* still matches this V2 Task's identity and contract. The outgoing message is
|
|
294
|
+
* separately bound to the current Kernel revision and active Run.
|
|
295
|
+
*/
|
|
296
|
+
function coordinationBoundThread(context, threadId) {
|
|
297
|
+
if (context.archived || context.kernelKind !== "task-kernel-v2")
|
|
298
|
+
return undefined;
|
|
299
|
+
for (const request of requests(context.dir).reverse()) {
|
|
300
|
+
if (request.tool !== "create_thread" ||
|
|
301
|
+
request.role !== "plan" ||
|
|
302
|
+
request.task !== context.task ||
|
|
303
|
+
request.task_id !== context.taskId ||
|
|
304
|
+
request.task_kernel_kind !== "task-kernel-v2" ||
|
|
305
|
+
(request.contract_fingerprint ?? null) !== context.contractFingerprint ||
|
|
306
|
+
!Number.isInteger(request.kernel_revision) ||
|
|
307
|
+
request.kernel_revision > context.revision) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const receiptPath = receiptFile(context.dir, request.request_id);
|
|
311
|
+
if (!fs.existsSync(receiptPath))
|
|
312
|
+
continue;
|
|
313
|
+
const receipt = readJson(receiptPath);
|
|
314
|
+
const requestFingerprint = codexRequestFingerprint(request);
|
|
315
|
+
if (request.request_fingerprint !== requestFingerprint ||
|
|
316
|
+
receipt.schema_version !== 1 ||
|
|
317
|
+
receipt.request_id !== request.request_id ||
|
|
318
|
+
receipt.request_fingerprint !== requestFingerprint ||
|
|
319
|
+
receipt.task_id !== context.taskId ||
|
|
320
|
+
receipt.run_id !== (request.run_id ?? null) ||
|
|
321
|
+
receipt.tool !== "create_thread" ||
|
|
322
|
+
receipt.outcome !== "ok" ||
|
|
323
|
+
(request.kernel_revision === context.revision &&
|
|
324
|
+
receipt.contract_stale === true) ||
|
|
325
|
+
receipt.kernel_revision_at_receipt !== request.kernel_revision ||
|
|
326
|
+
receipt.thread_id !== threadId ||
|
|
327
|
+
!receipt.host_id ||
|
|
328
|
+
!idPattern.test(receipt.host_id)) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
threadId,
|
|
333
|
+
hostId: receipt.host_id,
|
|
334
|
+
role: "plan",
|
|
335
|
+
runId: request.run_id ?? null,
|
|
336
|
+
dispatchLeaseId: request.dispatch_lease_id ?? null,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
77
341
|
function latestWaitCursor(dir, threadId) {
|
|
78
342
|
const waits = requests(dir).filter((request) => request.tool === "wait_threads" && request.thread_id === threadId);
|
|
79
343
|
for (const request of waits.reverse()) {
|
|
@@ -81,7 +345,9 @@ function latestWaitCursor(dir, threadId) {
|
|
|
81
345
|
if (!fs.existsSync(file))
|
|
82
346
|
continue;
|
|
83
347
|
const receipt = readJson(file);
|
|
84
|
-
if (receipt.outcome === "ok" &&
|
|
348
|
+
if (receipt.outcome === "ok" &&
|
|
349
|
+
receipt.contract_stale !== true &&
|
|
350
|
+
typeof receipt.cursor === "string")
|
|
85
351
|
return receipt.cursor;
|
|
86
352
|
}
|
|
87
353
|
return null;
|
|
@@ -107,28 +373,348 @@ function roleBoundary(role) {
|
|
|
107
373
|
return "Review is read-only: inspect the change set and evidence, report findings, and do not alter code or declare acceptance.";
|
|
108
374
|
return "Implement only the approved Execute contract and write set. Do not commit, integrate, archive, change Kernel approval, or declare acceptance.";
|
|
109
375
|
}
|
|
376
|
+
function recordRunBinding(store, context, selected) {
|
|
377
|
+
if (context.kernelKind !== "task-kernel-v2" || !selected.runId)
|
|
378
|
+
return;
|
|
379
|
+
store.startRun({
|
|
380
|
+
taskId: context.taskId,
|
|
381
|
+
runId: selected.runId,
|
|
382
|
+
role: null,
|
|
383
|
+
workspaceId: null,
|
|
384
|
+
providerRunId: null,
|
|
385
|
+
actor: { platform: "pactile", id: "codex-bridge" },
|
|
386
|
+
evidenceLevel: "local",
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
function runContextLine(context, selected, includeAuthorization = true) {
|
|
390
|
+
const parts = [
|
|
391
|
+
`Task ID: ${context.taskId}`,
|
|
392
|
+
`Task Kernel: ${context.kernelKind}`,
|
|
393
|
+
`Kernel revision: ${context.revision}`,
|
|
394
|
+
];
|
|
395
|
+
if (selected.runId)
|
|
396
|
+
parts.push(`Run ID: ${selected.runId}`);
|
|
397
|
+
if (selected.candidateSnapshotId && selected.candidateFingerprint) {
|
|
398
|
+
parts.push(`Candidate snapshot: ${selected.candidateSnapshotId} (${selected.candidateFingerprint})`);
|
|
399
|
+
}
|
|
400
|
+
if (includeAuthorization &&
|
|
401
|
+
selected.run &&
|
|
402
|
+
context.kernelKind === "task-kernel-v2") {
|
|
403
|
+
parts.push(`Run authorization: ${selected.run.authorization.scope}`);
|
|
404
|
+
if (selected.run.writeSetSnapshot.length) {
|
|
405
|
+
parts.push(`Run write set: ${selected.run.writeSetSnapshot.join(", ")}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return parts.join("\n");
|
|
409
|
+
}
|
|
410
|
+
function isRunBoundToContext(context, runId, candidateSnapshotId, candidateFingerprint) {
|
|
411
|
+
if (!runId) {
|
|
412
|
+
return candidateSnapshotId == null && candidateFingerprint == null;
|
|
413
|
+
}
|
|
414
|
+
if (context.kernelKind !== "task-kernel-v2")
|
|
415
|
+
return false;
|
|
416
|
+
const run = context.runs.find((candidate) => candidate.id === runId);
|
|
417
|
+
return Boolean(run &&
|
|
418
|
+
(run.candidateSnapshot?.id ?? null) === (candidateSnapshotId ?? null) &&
|
|
419
|
+
(run.candidateSnapshot?.fingerprint ?? null) ===
|
|
420
|
+
(candidateFingerprint ?? null));
|
|
421
|
+
}
|
|
422
|
+
function coordinationReceiptEvidence(value) {
|
|
423
|
+
if (value === undefined || value === "simulated")
|
|
424
|
+
return "simulated";
|
|
425
|
+
if (value === "desktop-native")
|
|
426
|
+
return value;
|
|
427
|
+
throw new Error("--evidence-level must be simulated or desktop-native");
|
|
428
|
+
}
|
|
429
|
+
function normalizeReplyEvidence(value, escalationId) {
|
|
430
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
431
|
+
throw new Error("Native read reply requires structured reply_evidence");
|
|
432
|
+
}
|
|
433
|
+
const evidence = value;
|
|
434
|
+
const body = evidence.body;
|
|
435
|
+
const responseTurnId = evidence.response_turn_id;
|
|
436
|
+
const bodySha256 = evidence.body_sha256;
|
|
437
|
+
if (evidence.reply_to_escalation_id !== escalationId ||
|
|
438
|
+
typeof responseTurnId !== "string" ||
|
|
439
|
+
!transportIdentifierPattern.test(responseTurnId) ||
|
|
440
|
+
typeof body !== "string" ||
|
|
441
|
+
body.trim() !== body ||
|
|
442
|
+
Buffer.byteLength(body, "utf8") < 1 ||
|
|
443
|
+
Buffer.byteLength(body, "utf8") > 8_192 ||
|
|
444
|
+
escalationSecretPattern.test(body) ||
|
|
445
|
+
typeof bodySha256 !== "string" ||
|
|
446
|
+
!/^[a-f0-9]{64}$/.test(bodySha256) ||
|
|
447
|
+
createHash("sha256").update(body, "utf8").digest("hex") !== bodySha256) {
|
|
448
|
+
throw new Error("Native read reply evidence must match the escalation and bounded body hash");
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
reply_to_escalation_id: escalationId,
|
|
452
|
+
response_turn_id: responseTurnId,
|
|
453
|
+
body,
|
|
454
|
+
body_sha256: bodySha256,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
110
457
|
export function prepareCodexRequest(input) {
|
|
111
458
|
const context = taskContext(input.root, input.task);
|
|
112
|
-
|
|
459
|
+
if (input.escalationId !== undefined &&
|
|
460
|
+
!escalationIdPattern.test(input.escalationId)) {
|
|
461
|
+
throw new Error("--escalation-id must be pi-escalation:<Pi Run UUID>");
|
|
462
|
+
}
|
|
463
|
+
if (input.replyToEscalationId !== undefined &&
|
|
464
|
+
!escalationIdPattern.test(input.replyToEscalationId)) {
|
|
465
|
+
throw new Error("--reply-to-escalation-id must be pi-escalation:<Pi Run UUID>");
|
|
466
|
+
}
|
|
467
|
+
if (input.escalationId && input.replyToEscalationId) {
|
|
468
|
+
throw new Error("A Codex request cannot send and reply to an escalation");
|
|
469
|
+
}
|
|
470
|
+
if (input.sourceTask && !input.replyToEscalationId) {
|
|
471
|
+
throw new Error("--source-task is only valid with --reply-to-escalation-id");
|
|
472
|
+
}
|
|
473
|
+
if (input.replyToEscalationId && !input.sourceTask) {
|
|
474
|
+
throw new Error("--reply-to-escalation-id requires --source-task");
|
|
475
|
+
}
|
|
476
|
+
if (input.replyToEscalationId && !input.sendRequestId) {
|
|
477
|
+
throw new Error("--reply-to-escalation-id requires --send-request-id");
|
|
478
|
+
}
|
|
479
|
+
if (input.sendRequestId && !input.replyToEscalationId) {
|
|
480
|
+
throw new Error("--send-request-id is only valid with --reply-to-escalation-id");
|
|
481
|
+
}
|
|
482
|
+
if (input.escalationId && input.promptFile) {
|
|
483
|
+
throw new Error("P40 Codex escalation uses its bound Review prompt; additional prompt files are not accepted");
|
|
484
|
+
}
|
|
485
|
+
if (input.escalationId && input.tool !== "send_message_to_thread") {
|
|
486
|
+
throw new Error("--escalation-id is only valid for a Codex message");
|
|
487
|
+
}
|
|
488
|
+
if (input.replyToEscalationId && input.tool !== "read_thread") {
|
|
489
|
+
throw new Error("--reply-to-escalation-id is only valid for a Codex read");
|
|
490
|
+
}
|
|
491
|
+
if (input.toTask && input.tool === "create_thread") {
|
|
492
|
+
throw new Error("--to-task is only valid for cross-task message");
|
|
493
|
+
}
|
|
494
|
+
if (input.toRunId && !input.toTask) {
|
|
495
|
+
throw new Error("--to-run-id requires --to-task");
|
|
496
|
+
}
|
|
497
|
+
if (input.toTask && !input.threadId) {
|
|
498
|
+
throw new Error("cross-task requests require --thread-id");
|
|
499
|
+
}
|
|
500
|
+
const targetContext = input.toTask
|
|
501
|
+
? taskContext(input.root, input.toTask)
|
|
502
|
+
: context;
|
|
503
|
+
const crossTask = targetContext.taskId !== context.taskId;
|
|
504
|
+
if (input.toTask && !crossTask) {
|
|
505
|
+
throw new Error("--to-task must identify a different Pactile Task");
|
|
506
|
+
}
|
|
507
|
+
if (crossTask && input.tool !== "send_message_to_thread") {
|
|
508
|
+
throw new Error("--to-task is currently supported only for cross-task messages");
|
|
509
|
+
}
|
|
510
|
+
if (input.resumeExecute &&
|
|
511
|
+
(!crossTask || input.tool !== "send_message_to_thread")) {
|
|
512
|
+
throw new Error("--resume-execute is only valid for a cross-task message");
|
|
513
|
+
}
|
|
514
|
+
if (input.resumeExecute && targetContext.kernelKind !== "task-kernel-v2") {
|
|
515
|
+
throw new Error("--resume-execute requires a Task Kernel v2 destination Run");
|
|
516
|
+
}
|
|
517
|
+
if (input.resumeExecute && targetContext.kernelKind === "task-kernel-v2") {
|
|
518
|
+
throw new Error("Task Kernel v2 --resume-execute dispatch is disabled until P37 admission, lease and Resume/block validation are connected");
|
|
519
|
+
}
|
|
520
|
+
const coordinationToExecutingV2Task = crossTask &&
|
|
521
|
+
input.tool === "send_message_to_thread" &&
|
|
522
|
+
targetContext.kernelKind === "task-kernel-v2" &&
|
|
523
|
+
targetContext.phase === "execute";
|
|
524
|
+
const bound = input.threadId
|
|
525
|
+
? coordinationToExecutingV2Task
|
|
526
|
+
? coordinationBoundThread(targetContext, input.threadId)
|
|
527
|
+
: boundThreads(targetContext.dir).get(input.threadId)
|
|
528
|
+
: undefined;
|
|
113
529
|
const role = input.tool === "create_thread" ? input.role : bound?.role;
|
|
114
530
|
if (!role)
|
|
115
|
-
throw new Error(input.tool === "create_thread"
|
|
531
|
+
throw new Error(input.tool === "create_thread"
|
|
532
|
+
? "--role plan|review|execute is required"
|
|
533
|
+
: "Thread is not bound to this Pactile task");
|
|
116
534
|
if (role !== "plan" && role !== "review" && role !== "execute")
|
|
117
535
|
throw new Error("Codex role must be plan, review or execute");
|
|
118
|
-
if (input.tool === "
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
536
|
+
if (input.tool === "send_message_to_thread" &&
|
|
537
|
+
input.role &&
|
|
538
|
+
input.role !== bound?.role) {
|
|
539
|
+
throw new Error("--role must match the bound Codex thread role");
|
|
540
|
+
}
|
|
541
|
+
if (!coordinationToExecutingV2Task &&
|
|
542
|
+
(input.tool === "create_thread" || input.tool === "send_message_to_thread")) {
|
|
543
|
+
checkPhase(role, crossTask ? targetContext.phase : context.phase);
|
|
544
|
+
}
|
|
545
|
+
if ((input.tool === "wait_threads" || input.tool === "read_thread") &&
|
|
546
|
+
input.promptFile) {
|
|
123
547
|
throw new Error("wait/read do not accept --prompt-file");
|
|
124
548
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
549
|
+
let prompt = input.promptFile ? textFile(input.promptFile) : null;
|
|
550
|
+
if (crossTask && prompt && Buffer.byteLength(prompt, "utf8") > 4_096) {
|
|
551
|
+
throw new Error("cross-task message body must be at most 4096 bytes for the coordination journal");
|
|
552
|
+
}
|
|
553
|
+
const executionDispatch = role === "execute" &&
|
|
554
|
+
(input.tool === "create_thread" ||
|
|
555
|
+
(input.tool === "send_message_to_thread" &&
|
|
556
|
+
(!crossTask || input.resumeExecute === true)));
|
|
557
|
+
const executionContext = crossTask ? targetContext : context;
|
|
558
|
+
if (executionDispatch &&
|
|
559
|
+
role === "execute" &&
|
|
560
|
+
executionContext.kernelKind === "task-kernel-v2") {
|
|
561
|
+
throw new Error("Task Kernel v2 Execute dispatch is disabled until P37 admission, lease and Resume/block validation are connected");
|
|
562
|
+
}
|
|
563
|
+
const selectedRun = selectRun(context, role, input.runId, executionDispatch && !crossTask);
|
|
564
|
+
const targetRun = crossTask
|
|
565
|
+
? selectRun(targetContext, role, input.toRunId, executionDispatch)
|
|
566
|
+
: selectedRun;
|
|
567
|
+
if (coordinationToExecutingV2Task &&
|
|
568
|
+
(!targetRun.runId ||
|
|
569
|
+
(targetRun.run?.state !== "running" &&
|
|
570
|
+
targetRun.run?.state !== "waiting") ||
|
|
571
|
+
(bound?.runId && bound.runId !== targetRun.runId))) {
|
|
572
|
+
throw new Error("Coordination to an executing Task requires its current active Run and a Plan thread bound to that Task");
|
|
573
|
+
}
|
|
574
|
+
if (input.escalationId) {
|
|
575
|
+
const prepared = readPiReviewEscalationV1(input.root, context.task, input.escalationId);
|
|
576
|
+
const current = assertCurrentPiReviewEscalationV1(input.root, context.task, prepared);
|
|
577
|
+
const sourceRun = context.runs.at(-1);
|
|
578
|
+
if (!crossTask ||
|
|
579
|
+
context.kernelKind !== "task-kernel-v2" ||
|
|
580
|
+
context.phase !== "verify" ||
|
|
581
|
+
role !== "review" ||
|
|
582
|
+
bound?.role !== "review" ||
|
|
583
|
+
targetContext.kernelKind !== "task-kernel-v2" ||
|
|
584
|
+
targetRun.run?.state !== "completed" ||
|
|
585
|
+
!targetRun.run.candidateSnapshot ||
|
|
586
|
+
!input.runId ||
|
|
587
|
+
sourceRun?.id !== input.runId ||
|
|
588
|
+
sourceRun.state !== "completed" ||
|
|
589
|
+
!sourceRun.candidateSnapshot ||
|
|
590
|
+
selectedRun.runId !== sourceRun.id ||
|
|
591
|
+
selectedRun.candidateSnapshotId !== sourceRun.candidateSnapshot.id ||
|
|
592
|
+
selectedRun.candidateFingerprint !==
|
|
593
|
+
sourceRun.candidateSnapshot.fingerprint ||
|
|
594
|
+
current.run.id !== sourceRun.id ||
|
|
595
|
+
current.kernel.reviews.at(-1)?.id !== prepared.request.reviewId ||
|
|
596
|
+
current.kernel.reviews.at(-1)?.decision === "pass") {
|
|
597
|
+
throw new Error("Codex escalation send requires its current prepared non-passing Pi Review, source candidate and bound Review thread");
|
|
598
|
+
}
|
|
599
|
+
prompt = buildCodexEscalationPromptV1({
|
|
600
|
+
prepared,
|
|
601
|
+
hostId: bound.hostId,
|
|
602
|
+
threadId: bound.threadId,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
let escalationBinding = null;
|
|
606
|
+
let escalationSendBinding = null;
|
|
607
|
+
if (input.escalationId) {
|
|
608
|
+
const prepared = readPiReviewEscalationV1(input.root, context.task, input.escalationId);
|
|
609
|
+
escalationBinding = {
|
|
610
|
+
sourceTask: context.task,
|
|
611
|
+
sourceTaskId: prepared.request.taskId,
|
|
612
|
+
preparedRequestRef: prepared.ref,
|
|
613
|
+
preparedFingerprint: prepared.request.preparedFingerprint,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
if (input.replyToEscalationId) {
|
|
617
|
+
if (role !== "review" || bound?.role !== "review") {
|
|
618
|
+
throw new Error("Pi escalation replies require a bound Codex Review thread");
|
|
619
|
+
}
|
|
620
|
+
const prepared = readPiReviewEscalationV1(input.root, input.sourceTask, input.replyToEscalationId);
|
|
621
|
+
assertCurrentPiReviewEscalationV1(input.root, input.sourceTask, prepared);
|
|
622
|
+
const send = readCodexEscalationSendV1({
|
|
623
|
+
root: input.root,
|
|
624
|
+
sourceTask: input.sourceTask,
|
|
625
|
+
escalationId: input.replyToEscalationId,
|
|
626
|
+
sendRequestId: input.sendRequestId,
|
|
627
|
+
});
|
|
628
|
+
if (send.request["to_task"] !== path.basename(context.dir) ||
|
|
629
|
+
send.request["to_task_id"] !== context.taskId ||
|
|
630
|
+
send.request["thread_id"] !== bound.threadId ||
|
|
631
|
+
send.request["host_id"] !== bound.hostId ||
|
|
632
|
+
send.request["to_run_id"] !== selectedRun.runId ||
|
|
633
|
+
send.request["to_candidate_snapshot_id"] !== selectedRun.candidateSnapshotId ||
|
|
634
|
+
send.request["to_candidate_fingerprint"] !== selectedRun.candidateFingerprint) {
|
|
635
|
+
throw new Error("Escalation reply read must follow the selected send to this exact Review Task and thread");
|
|
636
|
+
}
|
|
637
|
+
escalationSendBinding = {
|
|
638
|
+
requestId: input.sendRequestId,
|
|
639
|
+
requestFingerprint: send.requestFingerprint,
|
|
640
|
+
receiptSha256: send.receiptSha256,
|
|
641
|
+
receiptRecordedAt: send.receiptRecordedAt,
|
|
642
|
+
};
|
|
643
|
+
const sourceDir = prepared.taskDir;
|
|
644
|
+
escalationBinding = {
|
|
645
|
+
sourceTask: path.relative(input.root, sourceDir).replaceAll("\\", "/"),
|
|
646
|
+
sourceTaskId: prepared.request.taskId,
|
|
647
|
+
preparedRequestRef: prepared.ref,
|
|
648
|
+
preparedFingerprint: prepared.request.preparedFingerprint,
|
|
649
|
+
};
|
|
650
|
+
if (context.kernelKind !== "task-kernel-v2" ||
|
|
651
|
+
selectedRun.run?.state !== "completed" ||
|
|
652
|
+
!selectedRun.run.candidateSnapshot) {
|
|
653
|
+
throw new Error("Pi escalation reply read requires the current completed Review Task candidate");
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (executionDispatch &&
|
|
657
|
+
role === "execute" &&
|
|
658
|
+
input.tool !== "wait_threads" &&
|
|
659
|
+
(crossTask ? targetContext.kernelKind : context.kernelKind) ===
|
|
660
|
+
"task-kernel-v2" &&
|
|
661
|
+
!(crossTask ? input.toRunId : input.runId)) {
|
|
662
|
+
throw new Error(crossTask
|
|
663
|
+
? "Task Kernel v2 cross-task Execute dispatch requires an explicit --to-run-id"
|
|
664
|
+
: "Task Kernel v2 Execute dispatch requires an explicit --run-id");
|
|
665
|
+
}
|
|
666
|
+
if (executionDispatch &&
|
|
667
|
+
role === "execute" &&
|
|
668
|
+
(input.tool === "create_thread" || input.tool === "send_message_to_thread")) {
|
|
669
|
+
const dispatchContext = crossTask ? targetContext : context;
|
|
670
|
+
const dispatchRun = crossTask ? targetRun.run : selectedRun.run;
|
|
671
|
+
if (dispatchContext.kernelKind === "legacy-task-kernel-v1") {
|
|
672
|
+
const dir = approvedExecuteTask(input.root, dispatchContext.task);
|
|
673
|
+
if (fs.existsSync(path.join(dir, "implement.md"))) {
|
|
674
|
+
const parsed = readStrategyContract(dir);
|
|
675
|
+
if (parsed.errors.length)
|
|
676
|
+
throw new Error(`Invalid execution contract: ${parsed.errors.join("; ")}`);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
else if (!dispatchRun?.authorization.scope.trim() ||
|
|
680
|
+
!dispatchRun.writeSetSnapshot.length) {
|
|
681
|
+
throw new Error("Codex Execute dispatch requires a Task Kernel v2 Run with a scope and non-empty write set");
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
const executeScope = executionDispatch &&
|
|
685
|
+
role === "execute" &&
|
|
686
|
+
context.kernelKind === "legacy-task-kernel-v1" &&
|
|
687
|
+
(input.tool === "create_thread" || input.tool === "send_message_to_thread")
|
|
688
|
+
? parallelChild(input.root, context.dir)
|
|
689
|
+
: null;
|
|
690
|
+
const runScope = executionDispatch &&
|
|
691
|
+
role === "execute" &&
|
|
692
|
+
(crossTask ? targetContext.kernelKind : context.kernelKind) ===
|
|
693
|
+
"task-kernel-v2"
|
|
694
|
+
? crossTask
|
|
695
|
+
? targetRun.run
|
|
696
|
+
: selectedRun.run
|
|
697
|
+
: null;
|
|
698
|
+
const scopeLine = executeScope
|
|
699
|
+
? `Parent-approved write set: ${executeScope.touches.join(", ")}. Integration owner: Parent.`
|
|
700
|
+
: runScope
|
|
701
|
+
? `Task Run authorized scope: ${runScope.authorization.scope}. Approved write set: ${runScope.writeSetSnapshot.join(", ")}.`
|
|
702
|
+
: "";
|
|
703
|
+
let baseBranch = null;
|
|
704
|
+
if (input.tool === "create_thread" &&
|
|
705
|
+
context.kernelKind === "legacy-task-kernel-v1") {
|
|
706
|
+
const record = JSON.parse(fs.readFileSync(path.join(context.dir, "task.json"), "utf8"));
|
|
707
|
+
baseBranch =
|
|
708
|
+
record && typeof record === "object" && "base_branch" in record
|
|
709
|
+
? record.base_branch
|
|
710
|
+
: null;
|
|
711
|
+
}
|
|
712
|
+
if (executionDispatch &&
|
|
713
|
+
role === "execute" &&
|
|
714
|
+
baseBranch &&
|
|
715
|
+
(typeof baseBranch !== "string" ||
|
|
716
|
+
!/^[A-Za-z0-9][A-Za-z0-9._/-]{0,127}$/.test(baseBranch) ||
|
|
717
|
+
baseBranch.includes(".."))) {
|
|
132
718
|
throw new Error("Invalid approved base_branch for Codex Execute");
|
|
133
719
|
}
|
|
134
720
|
let args;
|
|
@@ -138,16 +724,34 @@ export function prepareCodexRequest(input) {
|
|
|
138
724
|
const targetType = input.targetType ?? "project";
|
|
139
725
|
if (targetType !== "project" && targetType !== "projectless")
|
|
140
726
|
throw new Error("--target must be project or projectless");
|
|
141
|
-
if (targetType === "project" &&
|
|
727
|
+
if (targetType === "project" &&
|
|
728
|
+
(!input.projectId ||
|
|
729
|
+
!idPattern.test(input.projectId) ||
|
|
730
|
+
!["local", "worktree"].includes(input.environment ?? ""))) {
|
|
142
731
|
throw new Error("project create requires --project-id and --environment local|worktree");
|
|
143
732
|
}
|
|
144
|
-
if (role === "execute" &&
|
|
733
|
+
if (role === "execute" &&
|
|
734
|
+
(targetType !== "project" || input.environment !== "worktree"))
|
|
145
735
|
throw new Error("Codex Execute requires a project worktree");
|
|
146
|
-
const target = targetType === "projectless"
|
|
147
|
-
{ type: "
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
736
|
+
const target = targetType === "projectless"
|
|
737
|
+
? { type: "projectless" }
|
|
738
|
+
: {
|
|
739
|
+
type: "project",
|
|
740
|
+
projectId: input.projectId,
|
|
741
|
+
environment: {
|
|
742
|
+
type: input.environment,
|
|
743
|
+
...(role === "execute" &&
|
|
744
|
+
typeof baseBranch === "string" &&
|
|
745
|
+
baseBranch
|
|
746
|
+
? { startingState: { type: "branch", branchName: baseBranch } }
|
|
747
|
+
: {}),
|
|
748
|
+
},
|
|
749
|
+
};
|
|
750
|
+
args = {
|
|
751
|
+
prompt: `Pactile task: ${context.task}\nCanonical Pactile task directory: ${context.dir}\nCodex role: ${role}\n${runContextLine(context, selectedRun)}\nUse Pactile as the task lifecycle and evidence source. ${roleBoundary(role)} ${scopeLine} Do not change Kernel approval or claim acceptance from a message alone. Do not dispatch Codex subagents.\n\n${prompt}`,
|
|
752
|
+
target,
|
|
753
|
+
...(input.title ? { title: input.title } : {}),
|
|
754
|
+
};
|
|
151
755
|
}
|
|
152
756
|
else {
|
|
153
757
|
if (!bound)
|
|
@@ -155,29 +759,110 @@ export function prepareCodexRequest(input) {
|
|
|
155
759
|
if (input.tool === "send_message_to_thread") {
|
|
156
760
|
if (!prompt)
|
|
157
761
|
throw new Error("message requires --prompt-file");
|
|
158
|
-
|
|
159
|
-
|
|
762
|
+
if (executionDispatch &&
|
|
763
|
+
role === "execute" &&
|
|
764
|
+
bound.runId &&
|
|
765
|
+
bound.runId !== (crossTask ? targetRun.runId : selectedRun.runId)) {
|
|
766
|
+
throw new Error("Codex Execute thread is bound to a different Task Run");
|
|
767
|
+
}
|
|
768
|
+
args = {
|
|
769
|
+
threadId: bound.threadId,
|
|
770
|
+
hostId: bound.hostId,
|
|
771
|
+
prompt: input.escalationId
|
|
772
|
+
? prompt
|
|
773
|
+
: crossTask
|
|
774
|
+
? input.resumeExecute
|
|
775
|
+
? `Pactile cross-task Execute dispatch from ${context.taskId} to ${targetContext.taskId}.\n${runContextLine(context, selectedRun, false)}\nRecipient ${runContextLine(targetContext, targetRun)}\n${roleBoundary(role)} ${scopeLine}\nDo not change Kernel approval or claim acceptance from this message. Do not dispatch Codex subagents.\n\n${prompt}`
|
|
776
|
+
: `Pactile coordination-only message from ${context.taskId} to ${targetContext.taskId}. This message and any send receipt do not resume a Run, change Task state, grant Execute permission, or authorize file writes. Preserve any blocked or waiting state. Do not edit files, change approval, or dispatch Codex subagents; wait for an explicit Kernel Resume and P37 dispatch admission before executing.\n${runContextLine(context, selectedRun, false)}\nRecipient ${runContextLine(targetContext, targetRun, false)}\n\n${prompt}`
|
|
777
|
+
: `Pactile task: ${context.task}\nCanonical Pactile task directory: ${context.dir}\n${runContextLine(context, selectedRun)}\n${roleBoundary(role)} ${scopeLine}\n\n${prompt}`,
|
|
778
|
+
};
|
|
160
779
|
}
|
|
161
780
|
else if (input.tool === "wait_threads") {
|
|
162
781
|
const timeoutMs = input.timeoutMs ?? 120_000;
|
|
163
782
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 0 || timeoutMs > 120_000)
|
|
164
783
|
throw new Error("wait timeout must be 0 to 120000 ms");
|
|
165
784
|
const afterCursor = latestWaitCursor(context.dir, bound.threadId);
|
|
166
|
-
args = {
|
|
167
|
-
|
|
785
|
+
args = {
|
|
786
|
+
targets: [
|
|
787
|
+
{
|
|
788
|
+
threadId: bound.threadId,
|
|
789
|
+
hostId: bound.hostId,
|
|
790
|
+
...(afterCursor ? { afterCursor } : {}),
|
|
791
|
+
},
|
|
792
|
+
],
|
|
793
|
+
timeoutMs,
|
|
794
|
+
};
|
|
168
795
|
}
|
|
169
796
|
else {
|
|
170
797
|
args = { threadId: bound.threadId, hostId: bound.hostId, turnLimit: 1 };
|
|
171
798
|
}
|
|
172
799
|
}
|
|
800
|
+
const requestId = randomUUID();
|
|
173
801
|
const request = {
|
|
174
|
-
schema_version: 1,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
802
|
+
schema_version: 1,
|
|
803
|
+
request_id: requestId,
|
|
804
|
+
task: context.task,
|
|
805
|
+
task_id: context.taskId,
|
|
806
|
+
task_kernel_kind: context.kernelKind,
|
|
807
|
+
kernel_revision: context.revision,
|
|
808
|
+
contract_fingerprint: context.contractFingerprint,
|
|
809
|
+
run_id: selectedRun.runId,
|
|
810
|
+
candidate_snapshot_id: selectedRun.candidateSnapshotId,
|
|
811
|
+
candidate_fingerprint: selectedRun.candidateFingerprint,
|
|
812
|
+
to_task: crossTask ? path.basename(targetContext.dir) : null,
|
|
813
|
+
to_task_id: crossTask ? targetContext.taskId : null,
|
|
814
|
+
to_kernel_revision: crossTask ? targetContext.revision : null,
|
|
815
|
+
to_task_kernel_kind: crossTask ? targetContext.kernelKind : null,
|
|
816
|
+
to_contract_fingerprint: crossTask
|
|
817
|
+
? targetContext.contractFingerprint
|
|
818
|
+
: null,
|
|
819
|
+
to_run_id: crossTask ? targetRun.runId : null,
|
|
820
|
+
to_candidate_snapshot_id: crossTask ? targetRun.candidateSnapshotId : null,
|
|
821
|
+
to_candidate_fingerprint: crossTask ? targetRun.candidateFingerprint : null,
|
|
822
|
+
coordination_message_id: crossTask && input.tool === "send_message_to_thread" ? requestId : null,
|
|
823
|
+
...(input.escalationId ? { escalation_id: input.escalationId } : {}),
|
|
824
|
+
...(input.replyToEscalationId
|
|
825
|
+
? { reply_to_escalation_id: input.replyToEscalationId }
|
|
826
|
+
: {}),
|
|
827
|
+
...(escalationBinding
|
|
828
|
+
? {
|
|
829
|
+
escalation_source_task: escalationBinding.sourceTask,
|
|
830
|
+
escalation_source_task_id: escalationBinding.sourceTaskId,
|
|
831
|
+
escalation_prepared_request_ref: escalationBinding.preparedRequestRef,
|
|
832
|
+
escalation_prepared_fingerprint: escalationBinding.preparedFingerprint,
|
|
833
|
+
}
|
|
834
|
+
: {}),
|
|
835
|
+
...(escalationSendBinding
|
|
836
|
+
? {
|
|
837
|
+
escalation_send_request_id: escalationSendBinding.requestId,
|
|
838
|
+
escalation_send_request_fingerprint: escalationSendBinding.requestFingerprint,
|
|
839
|
+
escalation_send_receipt_sha256: escalationSendBinding.receiptSha256,
|
|
840
|
+
escalation_send_receipt_recorded_at: escalationSendBinding.receiptRecordedAt,
|
|
841
|
+
}
|
|
842
|
+
: {}),
|
|
843
|
+
created_at: new Date().toISOString(),
|
|
844
|
+
tool: input.tool,
|
|
845
|
+
role,
|
|
846
|
+
thread_id: bound?.threadId ?? null,
|
|
847
|
+
host_id: bound?.hostId ?? null,
|
|
848
|
+
arguments: args,
|
|
849
|
+
prompt_sha256: prompt
|
|
850
|
+
? createHash("sha256").update(prompt).digest("hex")
|
|
851
|
+
: null,
|
|
178
852
|
};
|
|
179
|
-
|
|
180
|
-
|
|
853
|
+
request.request_fingerprint = codexRequestFingerprint(request);
|
|
854
|
+
const release = context.kernelKind === "legacy-task-kernel-v1" &&
|
|
855
|
+
role === "execute" &&
|
|
856
|
+
input.tool === "create_thread"
|
|
857
|
+
? reserveParallelChild(input.root, context.dir, {
|
|
858
|
+
id: request.request_id,
|
|
859
|
+
durable: true,
|
|
860
|
+
})
|
|
861
|
+
: null;
|
|
862
|
+
const coordination = new CoordinationStore(input.root);
|
|
863
|
+
recordRunBinding(coordination, context, selectedRun);
|
|
864
|
+
if (crossTask)
|
|
865
|
+
recordRunBinding(coordination, targetContext, targetRun);
|
|
181
866
|
try {
|
|
182
867
|
writeNew(requestFile(context.dir, request.request_id), request);
|
|
183
868
|
}
|
|
@@ -185,87 +870,576 @@ export function prepareCodexRequest(input) {
|
|
|
185
870
|
release?.();
|
|
186
871
|
throw error;
|
|
187
872
|
}
|
|
873
|
+
if (request.coordination_message_id && prompt) {
|
|
874
|
+
coordination.createMessage({
|
|
875
|
+
messageId: request.request_id,
|
|
876
|
+
fromTaskId: context.taskId,
|
|
877
|
+
toTaskId: targetContext.taskId,
|
|
878
|
+
fromRunId: selectedRun.runId,
|
|
879
|
+
toRunId: targetRun.runId,
|
|
880
|
+
sender: { platform: "codex", id: "node-bridge" },
|
|
881
|
+
evidenceLevel: "local",
|
|
882
|
+
body: prompt,
|
|
883
|
+
requestId: request.request_id,
|
|
884
|
+
hostRef: bound?.threadId ?? null,
|
|
885
|
+
});
|
|
886
|
+
}
|
|
188
887
|
return request;
|
|
189
888
|
}
|
|
190
|
-
export function recordCodexReceipt(root, task, requestId, resultFile) {
|
|
889
|
+
export function recordCodexReceipt(root, task, requestId, resultFile, evidenceLevelInput) {
|
|
191
890
|
if (!uuidPattern.test(requestId))
|
|
192
891
|
throw new Error("Invalid request id");
|
|
193
|
-
const
|
|
892
|
+
const initialContext = taskContextIncludingArchive(root, task);
|
|
893
|
+
if (initialContext.archived) {
|
|
894
|
+
throw new Error("Cannot record a new Codex receipt for an archived Task");
|
|
895
|
+
}
|
|
896
|
+
const initialRequest = readJson(requestFile(initialContext.dir, requestId));
|
|
897
|
+
const initialFingerprint = codexRequestFingerprint(initialRequest);
|
|
898
|
+
const record = () => recordCodexReceiptUnlocked(root, task, requestId, resultFile, evidenceLevelInput, initialRequest.tool, initialFingerprint);
|
|
899
|
+
if (initialRequest.tool !== "send_message_to_thread")
|
|
900
|
+
return record();
|
|
901
|
+
return withProjectSchedulerMutex(root, () => {
|
|
902
|
+
const lockedContext = taskContextIncludingArchive(root, task);
|
|
903
|
+
const lockedRequest = readJson(requestFile(lockedContext.dir, requestId));
|
|
904
|
+
if (codexRequestFingerprint(lockedRequest) !== initialFingerprint) {
|
|
905
|
+
throw new Error("Codex send request changed while acquiring the receipt lock");
|
|
906
|
+
}
|
|
907
|
+
return record();
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
function recordCodexReceiptUnlocked(root, task, requestId, resultFile, evidenceLevelInput, expectedTool, expectedFingerprint) {
|
|
911
|
+
if (!uuidPattern.test(requestId))
|
|
912
|
+
throw new Error("Invalid request id");
|
|
913
|
+
const context = taskContextIncludingArchive(root, task);
|
|
914
|
+
if (context.archived) {
|
|
915
|
+
throw new Error("Cannot record a new Codex receipt for an archived Task");
|
|
916
|
+
}
|
|
194
917
|
const request = readJson(requestFile(context.dir, requestId));
|
|
195
|
-
if (request.
|
|
918
|
+
if (request.tool !== expectedTool || codexRequestFingerprint(request) !== expectedFingerprint) {
|
|
919
|
+
throw new Error("Codex request changed before its receipt was recorded");
|
|
920
|
+
}
|
|
921
|
+
if (request.request_id !== requestId ||
|
|
922
|
+
(request.task_id && request.task_id !== context.taskId) ||
|
|
923
|
+
request.task !== context.task) {
|
|
196
924
|
throw new Error("Request belongs to another task");
|
|
925
|
+
}
|
|
926
|
+
const requestFingerprint = codexRequestFingerprint(request);
|
|
927
|
+
if (request.request_fingerprint !== undefined &&
|
|
928
|
+
request.request_fingerprint !== requestFingerprint) {
|
|
929
|
+
throw new Error("Request fingerprint does not match its persisted content");
|
|
930
|
+
}
|
|
197
931
|
const result = readJson(resultFile);
|
|
198
932
|
if (result.request_id !== requestId || result.tool !== request.tool)
|
|
199
933
|
throw new Error("Receipt does not match the request");
|
|
934
|
+
const evidenceLevel = coordinationReceiptEvidence(evidenceLevelInput);
|
|
200
935
|
if (!["ok", "failed", "queued"].includes(String(result.outcome)) ||
|
|
201
936
|
(result.outcome === "queued" && request.tool !== "create_thread")) {
|
|
202
937
|
throw new Error("Receipt outcome must be ok, failed or queued for create");
|
|
203
938
|
}
|
|
204
939
|
const successful = result.outcome === "ok";
|
|
205
|
-
const threadId = typeof result.thread_id === "string" && idPattern.test(result.thread_id)
|
|
206
|
-
|
|
207
|
-
|
|
940
|
+
const threadId = typeof result.thread_id === "string" && idPattern.test(result.thread_id)
|
|
941
|
+
? result.thread_id
|
|
942
|
+
: request.thread_id;
|
|
943
|
+
const hostId = typeof result.host_id === "string" && idPattern.test(result.host_id)
|
|
944
|
+
? result.host_id
|
|
945
|
+
: request.host_id;
|
|
946
|
+
const clientThreadId = typeof result.client_thread_id === "string" &&
|
|
947
|
+
idPattern.test(result.client_thread_id)
|
|
948
|
+
? result.client_thread_id
|
|
949
|
+
: null;
|
|
950
|
+
let threadCreationState;
|
|
951
|
+
if (request.tool === "create_thread") {
|
|
952
|
+
const suppliedState = result.thread_creation_state;
|
|
953
|
+
if (suppliedState !== undefined &&
|
|
954
|
+
suppliedState !== "created" &&
|
|
955
|
+
suppliedState !== "not_created" &&
|
|
956
|
+
suppliedState !== "unknown") {
|
|
957
|
+
throw new Error("thread_creation_state must be created, not_created or unknown");
|
|
958
|
+
}
|
|
959
|
+
if (successful) {
|
|
960
|
+
if (suppliedState === "not_created" || suppliedState === "unknown") {
|
|
961
|
+
throw new Error("Successful create receipt cannot report thread_creation_state as not created or unknown");
|
|
962
|
+
}
|
|
963
|
+
threadCreationState = "created";
|
|
964
|
+
}
|
|
965
|
+
else if (result.outcome === "queued") {
|
|
966
|
+
if (suppliedState === "created" || suppliedState === "not_created") {
|
|
967
|
+
throw new Error("Queued create cannot establish whether a thread was created");
|
|
968
|
+
}
|
|
969
|
+
threadCreationState = "unknown";
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
if (suppliedState === "created") {
|
|
973
|
+
throw new Error("Failed create receipt cannot report thread_creation_state as created");
|
|
974
|
+
}
|
|
975
|
+
threadCreationState = suppliedState ?? "unknown";
|
|
976
|
+
if (threadCreationState === "not_created" &&
|
|
977
|
+
(threadId !== null ||
|
|
978
|
+
clientThreadId !== null ||
|
|
979
|
+
result.thread_id != null ||
|
|
980
|
+
result.client_thread_id != null)) {
|
|
981
|
+
throw new Error("not_created requires no thread_id or client_thread_id");
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
208
985
|
if (successful && (!threadId || !hostId))
|
|
209
986
|
throw new Error("Successful receipt requires thread_id and host_id");
|
|
987
|
+
if (evidenceLevel === "desktop-native" &&
|
|
988
|
+
successful &&
|
|
989
|
+
(request.tool === "create_thread" || request.tool === "wait_threads") &&
|
|
990
|
+
(result.thread_id !== threadId || result.host_id !== hostId)) {
|
|
991
|
+
throw new Error("Desktop-native create/wait receipt must echo the native thread_id and host_id");
|
|
992
|
+
}
|
|
993
|
+
if (evidenceLevel === "desktop-native" &&
|
|
994
|
+
request.task_kernel_kind === "task-kernel-v2" &&
|
|
995
|
+
request.role === "execute" &&
|
|
996
|
+
request.tool === "wait_threads" &&
|
|
997
|
+
!request.run_id) {
|
|
998
|
+
throw new Error("Desktop-native Execute wait receipts require an explicit --run-id");
|
|
999
|
+
}
|
|
210
1000
|
if (result.outcome === "queued" && (!clientThreadId || threadId))
|
|
211
1001
|
throw new Error("Queued create requires client_thread_id without thread_id");
|
|
212
|
-
if (request.thread_id &&
|
|
1002
|
+
if (request.thread_id &&
|
|
1003
|
+
(threadId !== request.thread_id || hostId !== request.host_id))
|
|
213
1004
|
throw new Error("Receipt thread identity changed");
|
|
214
1005
|
const queuedPath = queuedFile(context.dir, requestId);
|
|
215
|
-
if (fs.existsSync(queuedPath) &&
|
|
1006
|
+
if (fs.existsSync(queuedPath) &&
|
|
1007
|
+
result.outcome !== "queued" &&
|
|
1008
|
+
readJson(queuedPath).client_thread_id !== clientThreadId) {
|
|
216
1009
|
throw new Error("Ready receipt must match the queued client_thread_id");
|
|
217
1010
|
}
|
|
218
|
-
const status = typeof result.status === "string" && result.status.length <= 80
|
|
219
|
-
|
|
1011
|
+
const status = typeof result.status === "string" && result.status.length <= 80
|
|
1012
|
+
? result.status
|
|
1013
|
+
: null;
|
|
1014
|
+
if (request.escalation_id) {
|
|
1015
|
+
const prepared = readPiReviewEscalationV1(root, context.task, request.escalation_id);
|
|
1016
|
+
const currentPiReview = assertCurrentPiReviewEscalationV1(root, context.task, prepared);
|
|
1017
|
+
assertCodexEscalationSendPromptV1(prepared, request);
|
|
1018
|
+
if (request.tool !== "send_message_to_thread" ||
|
|
1019
|
+
request.reply_to_escalation_id ||
|
|
1020
|
+
evidenceLevel !== "desktop-native" ||
|
|
1021
|
+
(successful && currentPiReview.kernel.reviews.at(-1)?.id !== prepared.request.reviewId) ||
|
|
1022
|
+
request.role !== "review" ||
|
|
1023
|
+
request.escalation_source_task !== context.task ||
|
|
1024
|
+
request.escalation_source_task_id !== prepared.request.taskId ||
|
|
1025
|
+
request.escalation_prepared_request_ref !== prepared.ref ||
|
|
1026
|
+
request.escalation_prepared_fingerprint !==
|
|
1027
|
+
prepared.request.preparedFingerprint ||
|
|
1028
|
+
request.escalation_id !== prepared.request.escalationId ||
|
|
1029
|
+
!request.to_task_id ||
|
|
1030
|
+
!request.thread_id ||
|
|
1031
|
+
!request.host_id ||
|
|
1032
|
+
(successful &&
|
|
1033
|
+
(result.thread_id !== request.thread_id ||
|
|
1034
|
+
result.host_id !== request.host_id))) {
|
|
1035
|
+
throw new Error("Pi escalation send requires a desktop-native cross-task message receipt bound to its Task and thread");
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
let replyEvidence;
|
|
1039
|
+
if (request.reply_to_escalation_id) {
|
|
1040
|
+
if (!request.escalation_source_task) {
|
|
1041
|
+
throw new Error("P40 reply read is missing its source Task binding");
|
|
1042
|
+
}
|
|
1043
|
+
const prepared = readPiReviewEscalationV1(root, request.escalation_source_task, request.reply_to_escalation_id);
|
|
1044
|
+
assertCurrentPiReviewEscalationV1(root, request.escalation_source_task, prepared);
|
|
1045
|
+
const send = readCodexEscalationSendV1({
|
|
1046
|
+
root,
|
|
1047
|
+
sourceTask: request.escalation_source_task,
|
|
1048
|
+
escalationId: request.reply_to_escalation_id,
|
|
1049
|
+
sendRequestId: request.escalation_send_request_id ?? "",
|
|
1050
|
+
});
|
|
1051
|
+
if (request.escalation_send_request_fingerprint !== send.requestFingerprint ||
|
|
1052
|
+
request.escalation_send_receipt_sha256 !== send.receiptSha256 ||
|
|
1053
|
+
request.escalation_send_receipt_recorded_at !== send.receiptRecordedAt ||
|
|
1054
|
+
Date.parse(request.created_at) < Date.parse(send.receiptRecordedAt)) {
|
|
1055
|
+
throw new Error("Escalation reply read request is not causally bound to the latest successful native send");
|
|
1056
|
+
}
|
|
1057
|
+
if (request.tool !== "read_thread" ||
|
|
1058
|
+
request.escalation_id ||
|
|
1059
|
+
evidenceLevel !== "desktop-native" ||
|
|
1060
|
+
request.role !== "review" ||
|
|
1061
|
+
request.escalation_source_task_id !== prepared.request.taskId ||
|
|
1062
|
+
request.escalation_prepared_request_ref !== prepared.ref ||
|
|
1063
|
+
request.escalation_prepared_fingerprint !==
|
|
1064
|
+
prepared.request.preparedFingerprint ||
|
|
1065
|
+
!request.escalation_send_request_id ||
|
|
1066
|
+
!request.escalation_send_request_fingerprint ||
|
|
1067
|
+
!request.escalation_send_receipt_sha256 ||
|
|
1068
|
+
!request.escalation_send_receipt_recorded_at ||
|
|
1069
|
+
!request.thread_id ||
|
|
1070
|
+
!request.host_id) {
|
|
1071
|
+
throw new Error("Escalation reply requires a desktop-native read_thread request bound to its Task and thread");
|
|
1072
|
+
}
|
|
1073
|
+
if (successful) {
|
|
1074
|
+
if (status !== "completed" ||
|
|
1075
|
+
result.reply_to_escalation_id !== request.reply_to_escalation_id ||
|
|
1076
|
+
result.thread_id !== request.thread_id ||
|
|
1077
|
+
result.host_id !== request.host_id) {
|
|
1078
|
+
throw new Error("Native escalation reply read must complete on the bound thread with exact escalation correlation");
|
|
1079
|
+
}
|
|
1080
|
+
replyEvidence = normalizeReplyEvidence(result.reply_evidence, request.reply_to_escalation_id);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
if (successful &&
|
|
1084
|
+
request.tool === "wait_threads" &&
|
|
1085
|
+
!["completed", "needs_attention", "timeout"].includes(status ?? "")) {
|
|
220
1086
|
throw new Error("Wait receipt requires completed, needs_attention or timeout status");
|
|
221
1087
|
}
|
|
222
|
-
const reason = typeof result.reason === "string" && result.reason.length <= 500
|
|
1088
|
+
const reason = typeof result.reason === "string" && result.reason.length <= 500
|
|
1089
|
+
? result.reason
|
|
1090
|
+
: null;
|
|
223
1091
|
if (result.outcome === "failed" && !reason)
|
|
224
1092
|
throw new Error("Failed receipt requires a short reason");
|
|
225
|
-
const cursor = typeof result.cursor === "string" && result.cursor.length <= 2048
|
|
1093
|
+
const cursor = typeof result.cursor === "string" && result.cursor.length <= 2048
|
|
1094
|
+
? result.cursor
|
|
1095
|
+
: null;
|
|
1096
|
+
let destinationContext = null;
|
|
1097
|
+
if (request.to_task) {
|
|
1098
|
+
try {
|
|
1099
|
+
destinationContext = taskContextIncludingArchive(root, request.to_task);
|
|
1100
|
+
}
|
|
1101
|
+
catch {
|
|
1102
|
+
destinationContext = null;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
const sourceStale = context.archived ||
|
|
1106
|
+
context.revision !== request.kernel_revision ||
|
|
1107
|
+
(request.task_id !== undefined && request.task_id !== context.taskId) ||
|
|
1108
|
+
(request.task_kernel_kind !== undefined &&
|
|
1109
|
+
request.task_kernel_kind !== context.kernelKind) ||
|
|
1110
|
+
(request.contract_fingerprint !== undefined &&
|
|
1111
|
+
request.contract_fingerprint !== context.contractFingerprint) ||
|
|
1112
|
+
!isRunBoundToContext(context, request.run_id, request.candidate_snapshot_id, request.candidate_fingerprint);
|
|
1113
|
+
const destinationStale = Boolean(request.to_task) &&
|
|
1114
|
+
(!destinationContext ||
|
|
1115
|
+
destinationContext.archived ||
|
|
1116
|
+
destinationContext.taskId !== request.to_task_id ||
|
|
1117
|
+
destinationContext.revision !== request.to_kernel_revision ||
|
|
1118
|
+
destinationContext.kernelKind !== request.to_task_kernel_kind ||
|
|
1119
|
+
destinationContext.contractFingerprint !==
|
|
1120
|
+
request.to_contract_fingerprint ||
|
|
1121
|
+
!isRunBoundToContext(destinationContext, request.to_run_id, request.to_candidate_snapshot_id, request.to_candidate_fingerprint));
|
|
1122
|
+
const contractStale = sourceStale || destinationStale;
|
|
226
1123
|
const receipt = {
|
|
227
|
-
schema_version: 1,
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
1124
|
+
schema_version: 1,
|
|
1125
|
+
request_id: requestId,
|
|
1126
|
+
task_id: context.taskId,
|
|
1127
|
+
run_id: request.run_id ?? null,
|
|
1128
|
+
candidate_snapshot_id: request.candidate_snapshot_id ?? null,
|
|
1129
|
+
candidate_fingerprint: request.candidate_fingerprint ?? null,
|
|
1130
|
+
to_task_id: request.to_task_id ?? null,
|
|
1131
|
+
to_run_id: request.to_run_id ?? null,
|
|
1132
|
+
to_candidate_snapshot_id: request.to_candidate_snapshot_id ?? null,
|
|
1133
|
+
to_candidate_fingerprint: request.to_candidate_fingerprint ?? null,
|
|
1134
|
+
destination_kernel_revision_at_receipt: destinationContext?.revision ?? null,
|
|
1135
|
+
request_fingerprint: requestFingerprint,
|
|
1136
|
+
evidence_level: evidenceLevel,
|
|
1137
|
+
...(request.escalation_id ? { escalation_id: request.escalation_id } : {}),
|
|
1138
|
+
...(request.reply_to_escalation_id
|
|
1139
|
+
? { reply_to_escalation_id: request.reply_to_escalation_id }
|
|
1140
|
+
: {}),
|
|
1141
|
+
...(request.escalation_source_task
|
|
1142
|
+
? { escalation_source_task: request.escalation_source_task }
|
|
1143
|
+
: {}),
|
|
1144
|
+
...(request.escalation_source_task_id
|
|
1145
|
+
? { escalation_source_task_id: request.escalation_source_task_id }
|
|
1146
|
+
: {}),
|
|
1147
|
+
...(request.escalation_prepared_request_ref
|
|
1148
|
+
? {
|
|
1149
|
+
escalation_prepared_request_ref: request.escalation_prepared_request_ref,
|
|
1150
|
+
}
|
|
1151
|
+
: {}),
|
|
1152
|
+
...(request.escalation_prepared_fingerprint
|
|
1153
|
+
? {
|
|
1154
|
+
escalation_prepared_fingerprint: request.escalation_prepared_fingerprint,
|
|
1155
|
+
}
|
|
1156
|
+
: {}),
|
|
1157
|
+
...(request.escalation_send_request_id
|
|
1158
|
+
? {
|
|
1159
|
+
escalation_send_request_id: request.escalation_send_request_id,
|
|
1160
|
+
escalation_send_request_fingerprint: request.escalation_send_request_fingerprint,
|
|
1161
|
+
escalation_send_receipt_sha256: request.escalation_send_receipt_sha256,
|
|
1162
|
+
escalation_send_receipt_recorded_at: request.escalation_send_receipt_recorded_at,
|
|
1163
|
+
}
|
|
1164
|
+
: {}),
|
|
1165
|
+
...(replyEvidence ? { reply_evidence: replyEvidence } : {}),
|
|
1166
|
+
...(threadCreationState
|
|
1167
|
+
? { thread_creation_state: threadCreationState }
|
|
1168
|
+
: {}),
|
|
1169
|
+
tool: request.tool,
|
|
1170
|
+
outcome: result.outcome,
|
|
1171
|
+
thread_id: threadId,
|
|
1172
|
+
client_thread_id: clientThreadId,
|
|
1173
|
+
host_id: hostId,
|
|
1174
|
+
status,
|
|
1175
|
+
cursor,
|
|
1176
|
+
reason,
|
|
1177
|
+
kernel_revision_at_receipt: context.revision,
|
|
1178
|
+
contract_stale: contractStale,
|
|
1179
|
+
recorded_at: new Date().toISOString(),
|
|
1180
|
+
assurance: "host-reported",
|
|
231
1181
|
};
|
|
232
|
-
writeNew(result.outcome === "queued"
|
|
233
|
-
|
|
1182
|
+
writeNew(result.outcome === "queued"
|
|
1183
|
+
? queuedPath
|
|
1184
|
+
: receiptFile(context.dir, requestId), receipt);
|
|
1185
|
+
if (request.task_kernel_kind !== "task-kernel-v2" &&
|
|
1186
|
+
request.role === "execute" &&
|
|
1187
|
+
request.tool === "create_thread" &&
|
|
1188
|
+
result.outcome === "failed") {
|
|
234
1189
|
releaseParallelChild(root, context.dir, requestId);
|
|
235
1190
|
}
|
|
236
|
-
if (request.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
1191
|
+
if (request.task_kernel_kind !== "task-kernel-v2" &&
|
|
1192
|
+
request.role === "execute" &&
|
|
1193
|
+
request.tool === "wait_threads" &&
|
|
1194
|
+
result.outcome === "ok" &&
|
|
1195
|
+
status === "completed") {
|
|
1196
|
+
const create = requests(context.dir).find((candidate) => candidate.tool === "create_thread" &&
|
|
1197
|
+
candidate.role === "execute" &&
|
|
1198
|
+
fs.existsSync(receiptFile(context.dir, candidate.request_id)) &&
|
|
1199
|
+
readJson(receiptFile(context.dir, candidate.request_id)).thread_id ===
|
|
1200
|
+
threadId);
|
|
240
1201
|
if (create)
|
|
241
1202
|
releaseParallelChild(root, context.dir, create.request_id);
|
|
242
1203
|
}
|
|
1204
|
+
if (!contractStale) {
|
|
1205
|
+
const coordination = new CoordinationStore(root);
|
|
1206
|
+
if (request.coordination_message_id &&
|
|
1207
|
+
request.tool === "send_message_to_thread") {
|
|
1208
|
+
coordination.recordMessageReceipt({
|
|
1209
|
+
messageId: request.coordination_message_id,
|
|
1210
|
+
receiptId: requestId,
|
|
1211
|
+
status: result.outcome === "ok" ? "sent" : "failed",
|
|
1212
|
+
actor: { platform: "codex", id: hostId ?? "desktop" },
|
|
1213
|
+
evidenceLevel,
|
|
1214
|
+
externalRef: threadId,
|
|
1215
|
+
note: result.outcome === "failed"
|
|
1216
|
+
? reason
|
|
1217
|
+
: "Host reported send accepted; recipient delivery is not confirmed.",
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
if (request.task_kernel_kind === "task-kernel-v2" && request.run_id) {
|
|
1221
|
+
const coordinatedRun = coordination
|
|
1222
|
+
.snapshot()
|
|
1223
|
+
.runs.find((run) => run.started.task_id === context.taskId &&
|
|
1224
|
+
run.started.run_id === request.run_id);
|
|
1225
|
+
if (coordinatedRun && !coordinatedRun.result) {
|
|
1226
|
+
const requestRef = path
|
|
1227
|
+
.relative(root, requestFile(context.dir, requestId))
|
|
1228
|
+
.replaceAll("\\", "/");
|
|
1229
|
+
const receiptRef = path
|
|
1230
|
+
.relative(root, receiptFile(context.dir, requestId))
|
|
1231
|
+
.replaceAll("\\", "/");
|
|
1232
|
+
const sequence = (coordinatedRun.progress.at(-1)?.sequence ?? -1) + 1;
|
|
1233
|
+
coordination.recordRunProgress({
|
|
1234
|
+
taskId: context.taskId,
|
|
1235
|
+
runId: request.run_id,
|
|
1236
|
+
sequence,
|
|
1237
|
+
name: `codex.${request.tool.replaceAll("_", ".")}.${receipt.outcome}`,
|
|
1238
|
+
summary: `Codex bridge host-reported ${request.tool} receipt: ${receipt.outcome}${status ? ` (${status})` : ""}${reason ? `: ${reason}` : ""}`,
|
|
1239
|
+
evidenceRefs: [requestRef, receiptRef],
|
|
1240
|
+
actor: { platform: "codex", id: hostId ?? "desktop" },
|
|
1241
|
+
evidenceLevel,
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
243
1246
|
return receipt;
|
|
244
1247
|
}
|
|
245
1248
|
export function codexBridgeStatus(root, task) {
|
|
246
|
-
|
|
247
|
-
let archived = false;
|
|
248
|
-
try {
|
|
249
|
-
context = taskContext(root, task);
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
if (!(error instanceof Error) || !error.message.startsWith("Task not found:"))
|
|
253
|
-
throw error;
|
|
254
|
-
context = archivedTaskContext(root, task);
|
|
255
|
-
archived = true;
|
|
256
|
-
}
|
|
1249
|
+
const context = taskContextIncludingArchive(root, task);
|
|
257
1250
|
const all = requests(context.dir);
|
|
258
1251
|
const receipts = all.flatMap((request) => {
|
|
259
1252
|
const file = receiptFile(context.dir, request.request_id);
|
|
260
|
-
return fs.existsSync(file)
|
|
1253
|
+
return fs.existsSync(file)
|
|
1254
|
+
? [readJson(file)]
|
|
1255
|
+
: [];
|
|
261
1256
|
});
|
|
262
1257
|
const completed = new Set(receipts.map((receipt) => receipt.request_id));
|
|
263
1258
|
const queued = all.flatMap((request) => {
|
|
264
1259
|
const file = queuedFile(context.dir, request.request_id);
|
|
265
|
-
return fs.existsSync(file) && !completed.has(request.request_id)
|
|
1260
|
+
return fs.existsSync(file) && !completed.has(request.request_id)
|
|
1261
|
+
? [readJson(file)]
|
|
1262
|
+
: [];
|
|
1263
|
+
});
|
|
1264
|
+
const coordinated = new CoordinationStore(root).snapshot();
|
|
1265
|
+
const taskEvents = coordinated.events.filter((event) => (event.type === "task.blocked" || event.type === "task.unblocked") &&
|
|
1266
|
+
event.task_id === context.taskId);
|
|
1267
|
+
return {
|
|
1268
|
+
task: context.task,
|
|
1269
|
+
task_id: context.taskId,
|
|
1270
|
+
task_kernel_kind: context.kernelKind,
|
|
1271
|
+
archived: context.archived,
|
|
1272
|
+
phase: context.phase,
|
|
1273
|
+
kernel_revision: context.revision,
|
|
1274
|
+
threads: [...boundThreads(context.dir).values()],
|
|
1275
|
+
pending: all
|
|
1276
|
+
.filter((request) => !completed.has(request.request_id))
|
|
1277
|
+
.map(({ request_id, tool, role, thread_id, kernel_revision, created_at, prompt_sha256, }) => ({
|
|
1278
|
+
request_id,
|
|
1279
|
+
tool,
|
|
1280
|
+
role,
|
|
1281
|
+
thread_id,
|
|
1282
|
+
kernel_revision,
|
|
1283
|
+
created_at,
|
|
1284
|
+
prompt_sha256,
|
|
1285
|
+
})),
|
|
1286
|
+
queued,
|
|
1287
|
+
receipts,
|
|
1288
|
+
coordination: {
|
|
1289
|
+
messages: coordinated.messages
|
|
1290
|
+
.filter(({ message }) => message.from_task_id === context.taskId ||
|
|
1291
|
+
message.to_task_id === context.taskId)
|
|
1292
|
+
.map(({ message, status, receipts: messageReceipts }) => ({
|
|
1293
|
+
message_id: message.message_id,
|
|
1294
|
+
from_task_id: message.from_task_id,
|
|
1295
|
+
to_task_id: message.to_task_id,
|
|
1296
|
+
from_run_id: message.from_run_id,
|
|
1297
|
+
to_run_id: message.to_run_id,
|
|
1298
|
+
status,
|
|
1299
|
+
request_id: message.request_id,
|
|
1300
|
+
host_ref: message.host_ref,
|
|
1301
|
+
evidence_level: messageReceipts.at(-1)?.evidence_level ?? message.evidence_level,
|
|
1302
|
+
recorded_at: message.recorded_at,
|
|
1303
|
+
})),
|
|
1304
|
+
blocked_tasks: coordinated.blocked_tasks.filter((event) => event.task_id === context.taskId),
|
|
1305
|
+
task_events: taskEvents,
|
|
1306
|
+
runs: coordinated.runs.filter(({ started }) => started.task_id === context.taskId),
|
|
1307
|
+
},
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
export function blockCodexTask(root, task, input) {
|
|
1311
|
+
const context = taskContext(root, task);
|
|
1312
|
+
const coordination = new CoordinationStore(root);
|
|
1313
|
+
let blockedByTaskId = input.blockedByTaskId ?? null;
|
|
1314
|
+
let evidenceLevel = "local";
|
|
1315
|
+
if (input.messageId) {
|
|
1316
|
+
const messageEntry = coordination
|
|
1317
|
+
.snapshot()
|
|
1318
|
+
.messages.find((candidate) => candidate.message.message_id === input.messageId);
|
|
1319
|
+
if (messageEntry?.message.to_task_id !== context.taskId) {
|
|
1320
|
+
throw new Error("block message must be addressed to this Task");
|
|
1321
|
+
}
|
|
1322
|
+
const sendReceipt = messageEntry.receipts.at(-1);
|
|
1323
|
+
if (!sendReceipt ||
|
|
1324
|
+
!new Set(["sent", "delivered", "acknowledged"]).has(sendReceipt.status)) {
|
|
1325
|
+
throw new Error("block message requires a non-stale successful send receipt");
|
|
1326
|
+
}
|
|
1327
|
+
const verified = verifyFreshCoordinationMessage(root, messageEntry, context, false);
|
|
1328
|
+
evidenceLevel = verified.evidenceLevel;
|
|
1329
|
+
if (messageEntry.message.to_run_id &&
|
|
1330
|
+
context.kernelKind === "task-kernel-v2") {
|
|
1331
|
+
const run = context.runs.find((candidate) => candidate.id === messageEntry.message.to_run_id);
|
|
1332
|
+
if (!run || (run.state !== "running" && run.state !== "waiting")) {
|
|
1333
|
+
throw new Error("block message Run is no longer active on this Task");
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
blockedByTaskId ??= messageEntry.message.from_task_id;
|
|
1337
|
+
}
|
|
1338
|
+
return coordination.blockTaskWithPrecondition({
|
|
1339
|
+
taskId: context.taskId,
|
|
1340
|
+
blockedByTaskId,
|
|
1341
|
+
messageId: input.messageId ?? null,
|
|
1342
|
+
reason: input.reason,
|
|
1343
|
+
actor: { platform: "user", id: input.actorId ?? null },
|
|
1344
|
+
evidenceLevel,
|
|
1345
|
+
}, (_event, snapshot) => {
|
|
1346
|
+
const currentContext = taskContext(root, task);
|
|
1347
|
+
if (currentContext.taskId !== context.taskId ||
|
|
1348
|
+
currentContext.revision !== context.revision) {
|
|
1349
|
+
throw new Error("Task changed while the coordination block was added");
|
|
1350
|
+
}
|
|
1351
|
+
if (!input.messageId)
|
|
1352
|
+
return;
|
|
1353
|
+
const messageEntry = snapshot.messages.find((candidate) => candidate.message.message_id === input.messageId);
|
|
1354
|
+
if (messageEntry?.message.to_task_id !== context.taskId) {
|
|
1355
|
+
throw new Error("block message must be addressed to this Task");
|
|
1356
|
+
}
|
|
1357
|
+
const verified = verifyFreshCoordinationMessage(root, messageEntry, currentContext, false);
|
|
1358
|
+
if (verified.evidenceLevel !== evidenceLevel) {
|
|
1359
|
+
throw new Error("block message receipt changed while adding the block");
|
|
1360
|
+
}
|
|
1361
|
+
if (messageEntry.message.from_task_id !== blockedByTaskId ||
|
|
1362
|
+
(messageEntry.message.to_run_id &&
|
|
1363
|
+
currentContext.kernelKind === "task-kernel-v2" &&
|
|
1364
|
+
!currentContext.runs.some((run) => run.id === messageEntry.message.to_run_id &&
|
|
1365
|
+
(run.state === "running" || run.state === "waiting")))) {
|
|
1366
|
+
throw new Error("block message Run is no longer active on this Task");
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
export function unblockCodexTask(root, task, input) {
|
|
1371
|
+
const context = taskContext(root, task);
|
|
1372
|
+
const coordination = new CoordinationStore(root);
|
|
1373
|
+
let unblockedByTaskId = input.unblockedByTaskId ?? null;
|
|
1374
|
+
let evidenceLevel = "local";
|
|
1375
|
+
let resolutionEntry;
|
|
1376
|
+
let resolutionSourceTaskId = null;
|
|
1377
|
+
if (input.resolutionMessageId) {
|
|
1378
|
+
resolutionEntry = coordination
|
|
1379
|
+
.snapshot()
|
|
1380
|
+
.messages.find((candidate) => candidate.message.message_id === input.resolutionMessageId);
|
|
1381
|
+
if (resolutionEntry?.message.to_task_id !== context.taskId) {
|
|
1382
|
+
throw new Error("resolution message must be addressed to this Task");
|
|
1383
|
+
}
|
|
1384
|
+
if (!resolutionEntry)
|
|
1385
|
+
throw new Error("Resolution message disappeared");
|
|
1386
|
+
const sendReceipt = resolutionEntry.receipts.at(-1);
|
|
1387
|
+
if (!sendReceipt ||
|
|
1388
|
+
!new Set(["sent", "delivered", "acknowledged"]).has(sendReceipt.status)) {
|
|
1389
|
+
throw new Error("unblock requires a non-stale successful resolution receipt");
|
|
1390
|
+
}
|
|
1391
|
+
if (sendReceipt.evidence_level !== "desktop-native") {
|
|
1392
|
+
throw new Error("unblock requires a successful desktop-native resolution receipt");
|
|
1393
|
+
}
|
|
1394
|
+
const verified = verifyFreshCoordinationMessage(root, resolutionEntry, context, true);
|
|
1395
|
+
evidenceLevel = verified.evidenceLevel;
|
|
1396
|
+
resolutionSourceTaskId = resolutionEntry.message.from_task_id;
|
|
1397
|
+
unblockedByTaskId ??= resolutionSourceTaskId;
|
|
1398
|
+
}
|
|
1399
|
+
const barrier = coordinationKernelBarrier(context);
|
|
1400
|
+
return coordination.unblockTaskWithPostcondition({
|
|
1401
|
+
taskId: context.taskId,
|
|
1402
|
+
blockId: input.blockId,
|
|
1403
|
+
unblockedByTaskId,
|
|
1404
|
+
resolutionMessageId: input.resolutionMessageId ?? null,
|
|
1405
|
+
runId: barrier.runId,
|
|
1406
|
+
kernelRevisionAtUnblock: barrier.kernelRevision,
|
|
1407
|
+
kernelEventIdAtUnblock: barrier.kernelEventId,
|
|
1408
|
+
reason: input.reason,
|
|
1409
|
+
actor: { platform: "user", id: input.actorId ?? null },
|
|
1410
|
+
evidenceLevel,
|
|
1411
|
+
}, () => {
|
|
1412
|
+
const afterContext = taskContext(root, task);
|
|
1413
|
+
if (afterContext.taskId !== context.taskId ||
|
|
1414
|
+
afterContext.revision !== context.revision) {
|
|
1415
|
+
throw new Error("Task Kernel changed while the coordination block was cleared");
|
|
1416
|
+
}
|
|
1417
|
+
if (input.resolutionMessageId) {
|
|
1418
|
+
const afterEntry = coordination
|
|
1419
|
+
.snapshot()
|
|
1420
|
+
.messages.find((candidate) => candidate.message.message_id === input.resolutionMessageId);
|
|
1421
|
+
if (!afterEntry)
|
|
1422
|
+
throw new Error("Resolution message disappeared");
|
|
1423
|
+
const beforeEntry = resolutionEntry;
|
|
1424
|
+
if (!beforeEntry)
|
|
1425
|
+
throw new Error("Resolution message disappeared");
|
|
1426
|
+
const afterVerified = verifyFreshCoordinationMessage(root, afterEntry, afterContext, true);
|
|
1427
|
+
const beforeVerified = verifyFreshCoordinationMessage(root, beforeEntry, context, true);
|
|
1428
|
+
if (afterVerified.sourceContext.revision !==
|
|
1429
|
+
beforeVerified.sourceContext.revision ||
|
|
1430
|
+
afterVerified.sourceContext.taskId !==
|
|
1431
|
+
beforeVerified.sourceContext.taskId) {
|
|
1432
|
+
throw new Error("Resolution source Task changed while the block was cleared");
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}, {
|
|
1436
|
+
taskId: context.taskId,
|
|
1437
|
+
blockId: randomUUID(),
|
|
1438
|
+
blockedByTaskId: resolutionSourceTaskId,
|
|
1439
|
+
messageId: null,
|
|
1440
|
+
reason: "Task or Run state changed while clearing the coordination block; obtain a fresh resolution.",
|
|
1441
|
+
actor: { platform: "user", id: input.actorId ?? null },
|
|
1442
|
+
evidenceLevel: "local",
|
|
266
1443
|
});
|
|
267
|
-
return { task: context.task, archived, phase: context.phase, kernel_revision: context.revision,
|
|
268
|
-
threads: [...boundThreads(context.dir).values()], pending: all.filter((request) => !completed.has(request.request_id))
|
|
269
|
-
.map(({ request_id, tool, role, thread_id, kernel_revision, created_at, prompt_sha256 }) => ({ request_id, tool, role, thread_id, kernel_revision, created_at, prompt_sha256 })), queued, receipts };
|
|
270
1444
|
}
|
|
271
1445
|
//# sourceMappingURL=bridge.js.map
|