@astrosheep/keiyaku 4.5.29 → 4.6.2
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/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +0 -13
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +47 -78
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +54 -41
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +10 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +27 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +68 -71
- package/build/src/akuma/akuma-call.d.ts +53 -0
- package/build/src/akuma/akuma-call.js +113 -0
- package/build/src/akuma/akuma-instance.d.ts +20 -18
- package/build/src/akuma/akuma-instance.js +65 -175
- package/build/src/akuma/akuma-observe.d.ts +3 -21
- package/build/src/akuma/akuma-observe.js +7 -24
- package/build/src/akuma/{akuma-handle.d.ts → akuma-owner.d.ts} +55 -27
- package/build/src/akuma/{akuma-handle.js → akuma-owner.js} +24 -23
- package/build/src/akuma/akuma-selection-execution.d.ts +51 -0
- package/build/src/akuma/akuma-selection-execution.js +134 -0
- package/build/src/akuma/{fleet-execution.d.ts → akuma-wait.d.ts} +24 -44
- package/build/src/akuma/akuma-wait.js +113 -0
- package/build/src/akuma/akuma.d.ts +35 -89
- package/build/src/akuma/akuma.js +148 -30
- package/build/src/akuma/archetype.d.ts +12 -0
- package/build/src/akuma/archetype.js +47 -19
- package/build/src/akuma/body.d.ts +76 -36
- package/build/src/akuma/body.js +84 -49
- package/build/src/akuma/call-initial-tell.d.ts +131 -22
- package/build/src/akuma/call-initial-tell.js +31 -1
- package/build/src/akuma/call-request.d.ts +237 -31
- package/build/src/akuma/call-request.js +67 -94
- package/build/src/akuma/coordinate.d.ts +15 -5
- package/build/src/akuma/coordinate.js +12 -22
- package/build/src/akuma/dispatch-association.d.ts +1 -1
- package/build/src/akuma/dispatch-association.js +1 -10
- package/build/src/akuma/heart/activity-schema.d.ts +325 -0
- package/build/src/akuma/heart/activity-schema.js +53 -0
- package/build/src/akuma/heart/facts.d.ts +1 -6
- package/build/src/akuma/heart/index.d.ts +3 -1
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/rows.d.ts +49 -2
- package/build/src/akuma/heart/rows.js +16 -2
- package/build/src/akuma/heart/soul.d.ts +1 -0
- package/build/src/akuma/heart/soul.js +6 -4
- package/build/src/akuma/heart/tells.d.ts +1 -0
- package/build/src/akuma/heart/tells.js +18 -0
- package/build/src/akuma/identity.d.ts +10 -7
- package/build/src/akuma/identity.js +23 -0
- package/build/src/akuma/index.d.ts +10 -8
- package/build/src/akuma/index.js +2 -2
- package/build/src/akuma/nuke.d.ts +3 -0
- package/build/src/akuma/nuke.js +13 -7
- package/build/src/akuma/projection.d.ts +0 -5
- package/build/src/akuma/projection.js +22 -43
- package/build/src/akuma/provider-recipe.d.ts +58 -13
- package/build/src/akuma/provider-recipe.js +62 -80
- package/build/src/akuma/provider.d.ts +6 -76
- package/build/src/akuma/provider.js +11 -219
- package/build/src/akuma/providers/acp/config.d.ts +2 -0
- package/build/src/akuma/providers/acp/config.js +26 -1
- package/build/src/akuma/providers/acp/core.d.ts +7 -0
- package/build/src/akuma/providers/acp/core.js +49 -18
- package/build/src/akuma/providers/acp/index.js +14 -6
- package/build/src/akuma/providers/grok-build/index.js +44 -13
- package/build/src/akuma/providers/index.d.ts +3 -3
- package/build/src/akuma/providers/index.js +2 -13
- package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +28 -0
- package/build/src/akuma/providers/opencode-sdk/event-stream.js +92 -0
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +0 -1
- package/build/src/akuma/providers/opencode-sdk/index.js +200 -64
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +41 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +69 -2
- package/build/src/akuma/providers/pi/events.js +5 -2
- package/build/src/akuma/providers/pi/index.d.ts +3 -4
- package/build/src/akuma/providers/pi/index.js +99 -45
- package/build/src/akuma/publication.d.ts +84 -3
- package/build/src/akuma/publication.js +145 -2
- package/build/src/akuma/read-pool.d.ts +2 -0
- package/build/src/akuma/read-pool.js +15 -0
- package/build/src/akuma/request-rendezvous.js +10 -0
- package/build/src/akuma/request-serve.js +7 -0
- package/build/src/akuma/request-wire.d.ts +14 -26
- package/build/src/akuma/request-wire.js +4 -0
- package/build/src/akuma/requests.d.ts +0 -2
- package/build/src/akuma/requests.js +0 -17
- package/build/src/akuma/{fleet-observation.d.ts → selection-observation.d.ts} +37 -36
- package/build/src/akuma/selection-observation.js +65 -0
- package/build/src/akuma/{fleet-owner-port.d.ts → selection-owner-port.d.ts} +3 -3
- package/build/src/akuma/{fleet-owner-port.js → selection-owner-port.js} +11 -17
- package/build/src/akuma/{fleet-request.d.ts → selection-request.d.ts} +42 -82
- package/build/src/akuma/{fleet-request.js → selection-request.js} +92 -136
- package/build/src/akuma/turn-drive.js +73 -14
- package/build/src/akuma-body.js +91 -56
- package/build/src/body/amend.d.ts +5 -0
- package/build/src/body/amend.js +26 -50
- package/build/src/body/arc.d.ts +4 -2
- package/build/src/body/arc.js +19 -26
- package/build/src/body/criteria.d.ts +6 -0
- package/build/src/body/criteria.js +37 -0
- package/build/src/body/decode.js +5 -42
- package/build/src/body/region.d.ts +5 -0
- package/build/src/body/region.js +45 -2
- package/build/src/body/render.js +2 -4
- package/build/src/cli/activity.d.ts +26 -0
- package/build/src/cli/activity.js +75 -0
- package/build/src/cli/actor.d.ts +3 -1
- package/build/src/cli/actor.js +15 -2
- package/build/src/cli/commands/akuma-grammar.d.ts +75 -0
- package/build/src/cli/commands/akuma-grammar.js +414 -0
- package/build/src/cli/commands/akuma.d.ts +5 -69
- package/build/src/cli/commands/akuma.js +352 -319
- package/build/src/cli/commands/amend.d.ts +4 -5
- package/build/src/cli/commands/amend.js +1 -2
- package/build/src/cli/commands/bind.d.ts +4 -5
- package/build/src/cli/commands/bind.js +7 -10
- package/build/src/cli/commands/contract-grammar.d.ts +112 -0
- package/build/src/cli/commands/contract-grammar.js +282 -0
- package/build/src/cli/commands/contract-help.d.ts +17 -22
- package/build/src/cli/commands/contract-help.js +37 -24
- package/build/src/cli/commands/contract.d.ts +18 -97
- package/build/src/cli/commands/contract.js +621 -233
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +2 -2
- package/build/src/cli/commands/task-grammar.d.ts +19 -0
- package/build/src/cli/commands/task-grammar.js +438 -0
- package/build/src/cli/commands/task-query.js +23 -104
- package/build/src/cli/commands/task.d.ts +5 -20
- package/build/src/cli/commands/task.js +414 -364
- package/build/src/cli/coordinates.d.ts +10 -0
- package/build/src/cli/coordinates.js +20 -0
- package/build/src/cli/draft.d.ts +7 -1
- package/build/src/cli/main.js +10 -1
- package/build/src/cli/parse.d.ts +8 -9
- package/build/src/cli/parse.js +62 -62
- package/build/src/cli/render/akuma-activity.d.ts +54 -36
- package/build/src/cli/render/akuma-activity.js +262 -242
- package/build/src/cli/render/akuma-tool.d.ts +8 -4
- package/build/src/cli/render/akuma-tool.js +6 -5
- package/build/src/cli/render/akuma.d.ts +36 -16
- package/build/src/cli/render/akuma.js +65 -132
- package/build/src/cli/render/audit.d.ts +6 -2
- package/build/src/cli/render/audit.js +59 -28
- package/build/src/cli/render/catalog.d.ts +11 -2
- package/build/src/cli/render/catalog.js +75 -95
- package/build/src/cli/render/contract-history.d.ts +3 -1
- package/build/src/cli/render/contract-history.js +215 -22
- package/build/src/cli/render/contract-observation.d.ts +10 -5
- package/build/src/cli/render/contract-observation.js +29 -46
- package/build/src/cli/render/contract.d.ts +10 -3
- package/build/src/cli/render/contract.js +252 -103
- package/build/src/cli/render/effects.d.ts +26 -0
- package/build/src/cli/render/effects.js +41 -0
- package/build/src/cli/render/execution-progress.d.ts +18 -6
- package/build/src/cli/render/execution-progress.js +34 -31
- package/build/src/cli/render/kanshi-akuma.d.ts +1 -2
- package/build/src/cli/render/kanshi-akuma.js +5 -26
- package/build/src/cli/render/kanshi.js +107 -128
- package/build/src/cli/render/marks.d.ts +13 -0
- package/build/src/cli/render/marks.js +74 -0
- package/build/src/cli/render/nuke.js +18 -7
- package/build/src/cli/render/receipt.d.ts +10 -4
- package/build/src/cli/render/receipt.js +124 -44
- package/build/src/cli/render/reconcile.d.ts +5 -0
- package/build/src/cli/render/reconcile.js +152 -0
- package/build/src/cli/render/refusal.d.ts +21 -4
- package/build/src/cli/render/refusal.js +60 -33
- package/build/src/cli/render/region.js +3 -2
- package/build/src/cli/render/settings.js +2 -12
- package/build/src/cli/render/task.d.ts +37 -6
- package/build/src/cli/render/task.js +161 -157
- package/build/src/cli/render/terminal.d.ts +20 -1
- package/build/src/cli/render/terminal.js +92 -18
- package/build/src/cli/runtime.d.ts +32 -8
- package/build/src/cli/runtime.js +157 -165
- package/build/src/cli/selectors.d.ts +5 -2
- package/build/src/cli/selectors.js +11 -3
- package/build/src/cli/streams.d.ts +11 -0
- package/build/src/cli/streams.js +32 -0
- package/build/src/cli/usage.d.ts +2 -0
- package/build/src/cli/usage.js +12 -8
- package/build/src/contract-guidance.js +3 -7
- package/build/src/contract-worktree.d.ts +20 -28
- package/build/src/contract-worktree.js +18 -70
- package/build/src/coordination/durable-file.d.ts +2 -2
- package/build/src/coordination/durable-file.js +0 -27
- package/build/src/core/facts/codec.d.ts +1 -2
- package/build/src/core/facts/codec.js +6 -7
- package/build/src/core/facts/gate.d.ts +0 -1
- package/build/src/core/facts/gate.js +0 -82
- package/build/src/core/facts/types.d.ts +1 -2
- package/build/src/core/verbs/abandon.d.ts +2 -6
- package/build/src/core/verbs/abandon.js +0 -16
- package/build/src/core/verbs/amend.d.ts +0 -1
- package/build/src/core/verbs/amend.js +0 -20
- package/build/src/core/verbs/arc.d.ts +7 -8
- package/build/src/core/verbs/arc.js +2 -19
- package/build/src/core/verbs/attestation.d.ts +2 -6
- package/build/src/core/verbs/attestation.js +0 -16
- package/build/src/core/verbs/bind.d.ts +0 -1
- package/build/src/core/verbs/bind.js +0 -16
- package/build/src/core/verbs/deliver.d.ts +0 -1
- package/build/src/core/verbs/deliver.js +0 -16
- package/build/src/core/verbs/placement.d.ts +2 -1
- package/build/src/core/verbs/placement.js +10 -59
- package/build/src/git/admission.d.ts +6 -4
- package/build/src/git/admission.js +4 -0
- package/build/src/git/hooks.d.ts +55 -30
- package/build/src/git/hooks.js +30 -3
- package/build/src/git/identity.d.ts +6 -0
- package/build/src/git/identity.js +47 -0
- package/build/src/git/integration.d.ts +31 -13
- package/build/src/git/integration.js +32 -1
- package/build/src/git/nuke.d.ts +10 -1
- package/build/src/git/nuke.js +31 -11
- package/build/src/git/observe.js +2 -15
- package/build/src/git/private-state-seat.d.ts +6 -7
- package/build/src/git/private-state-seat.js +8 -6
- package/build/src/git/read-observation.d.ts +6 -1
- package/build/src/git/read-observation.js +81 -46
- package/build/src/git/reconcile.d.ts +117 -40
- package/build/src/git/reconcile.js +169 -40
- package/build/src/git/scratch.d.ts +7 -4
- package/build/src/git/scratch.js +28 -6
- package/build/src/git/target-placement.d.ts +53 -38
- package/build/src/git/target-placement.js +69 -54
- package/build/src/git/tender.d.ts +37 -28
- package/build/src/git/tender.js +39 -0
- package/build/src/git/terminal-reconcile.js +21 -23
- package/build/src/git/terminal-seal.d.ts +8 -6
- package/build/src/git/terminal-seal.js +10 -0
- package/build/src/git/workspace.d.ts +29 -15
- package/build/src/git/workspace.js +28 -2
- package/build/src/identity/normalize.js +19 -6
- package/build/src/index.d.ts +78 -7
- package/build/src/index.js +52 -4
- package/build/src/kanshi/read.d.ts +3 -3
- package/build/src/kanshi/read.js +21 -21
- package/build/src/kanshi/report.d.ts +9 -8
- package/build/src/kanshi/roster.d.ts +2 -0
- package/build/src/kanshi/roster.js +2 -0
- package/build/src/kanshi/select.js +7 -3
- package/build/src/library/address.d.ts +3 -7
- package/build/src/library/address.js +7 -7
- package/build/src/library/akuma-creation.d.ts +21 -32
- package/build/src/library/akuma-creation.js +148 -165
- package/build/src/library/akumas.d.ts +20 -22
- package/build/src/library/akumas.js +43 -20
- package/build/src/library/bind.d.ts +107 -13
- package/build/src/library/bind.js +29 -23
- package/build/src/library/continuation.d.ts +556 -28
- package/build/src/library/continuation.js +29 -54
- package/build/src/library/contract-composition.d.ts +40 -0
- package/build/src/library/contract-composition.js +105 -0
- package/build/src/library/contract-creation.d.ts +7 -0
- package/build/src/library/contract-creation.js +192 -0
- package/build/src/library/contract-execution.d.ts +29 -40
- package/build/src/library/contract-execution.js +503 -128
- package/build/src/library/contract-operations.d.ts +275 -134
- package/build/src/library/contract-operations.js +83 -92
- package/build/src/library/contract-outcomes.d.ts +71 -0
- package/build/src/library/contract-outcomes.js +32 -0
- package/build/src/library/contract-settings.d.ts +25 -0
- package/build/src/library/contract-settings.js +135 -0
- package/build/src/library/contract-types.d.ts +17 -38
- package/build/src/library/delivery.d.ts +530 -10
- package/build/src/library/delivery.js +20 -45
- package/build/src/library/input.d.ts +3 -1
- package/build/src/library/input.js +11 -16
- package/build/src/library/invocation.d.ts +87 -0
- package/build/src/library/invocation.js +290 -0
- package/build/src/library/keiyaku.d.ts +45 -22
- package/build/src/library/keiyaku.js +134 -8
- package/build/src/library/nuke.d.ts +2 -11
- package/build/src/library/nuke.js +70 -57
- package/build/src/library/outcome.d.ts +13196 -0
- package/build/src/library/outcome.js +487 -0
- package/build/src/library/reconcile.d.ts +96 -24
- package/build/src/library/reconcile.js +102 -42
- package/build/src/library/refusal.d.ts +470 -42
- package/build/src/library/refusal.js +55 -143
- package/build/src/library/region.d.ts +15 -7
- package/build/src/library/region.js +23 -3
- package/build/src/library/repo.d.ts +2 -12
- package/build/src/library/repo.js +1 -22
- package/build/src/library/selection.d.ts +121 -0
- package/build/src/library/{fleet.js → selection.js} +169 -152
- package/build/src/plugin/public.d.ts +2 -0
- package/build/src/protocol/abandon.d.ts +2 -2
- package/build/src/protocol/abandon.js +1 -0
- package/build/src/protocol/amend.js +1 -0
- package/build/src/protocol/arc.d.ts +6 -4
- package/build/src/protocol/attempt.d.ts +4 -2
- package/build/src/protocol/attempt.js +10 -0
- package/build/src/protocol/audit.d.ts +255 -52
- package/build/src/protocol/audit.js +63 -5
- package/build/src/protocol/bind.d.ts +18 -17
- package/build/src/protocol/bind.js +9 -28
- package/build/src/protocol/completion.d.ts +256 -22
- package/build/src/protocol/completion.js +100 -12
- package/build/src/protocol/deliver.d.ts +34 -23
- package/build/src/protocol/deliver.js +39 -25
- package/build/src/protocol/execution-observation.d.ts +36 -37
- package/build/src/protocol/execution-observation.js +7 -9
- package/build/src/protocol/intent.d.ts +101 -30
- package/build/src/protocol/intent.js +74 -1
- package/build/src/protocol/operations.d.ts +570 -64
- package/build/src/protocol/operations.js +189 -9
- package/build/src/protocol/outcome.d.ts +2 -1
- package/build/src/protocol/placement.d.ts +2 -2
- package/build/src/protocol/placement.js +3 -1
- package/build/src/protocol/progress.d.ts +108 -65
- package/build/src/protocol/progress.js +82 -132
- package/build/src/protocol/read/status.d.ts +4 -3
- package/build/src/protocol/read/status.js +6 -5
- package/build/src/protocol/reconcile.d.ts +3 -3
- package/build/src/protocol/reconcile.js +4 -0
- package/build/src/protocol/reintegrate.d.ts +2 -2
- package/build/src/protocol/review.d.ts +30 -12
- package/build/src/protocol/review.js +15 -24
- package/build/src/protocol/run.d.ts +34 -5
- package/build/src/protocol/run.js +24 -12
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settings.d.ts +0 -10
- package/build/src/settings.js +0 -76
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +25 -16
- package/build/src/settlement/settle.js +80 -20
- package/build/src/task/board.d.ts +3 -1
- package/build/src/task/board.js +13 -17
- package/build/src/task/catalog.d.ts +0 -4
- package/build/src/task/catalog.js +0 -15
- package/build/src/task/compose-language.d.ts +19 -9
- package/build/src/task/compose-language.js +30 -20
- package/build/src/task/compose.d.ts +7 -37
- package/build/src/task/compose.js +20 -2
- package/build/src/task/created-observation.d.ts +0 -1
- package/build/src/task/created-observation.js +1 -4
- package/build/src/task/document.d.ts +12 -2
- package/build/src/task/document.js +4 -0
- package/build/src/task/identity.d.ts +4 -1
- package/build/src/task/identity.js +21 -17
- package/build/src/task/index.d.ts +36 -16
- package/build/src/task/index.js +103 -96
- package/build/src/task/lifecycle-operations.d.ts +1 -1
- package/build/src/task/mutation-result.d.ts +647 -586
- package/build/src/task/mutation-result.js +79 -46
- package/build/src/task/mutation.d.ts +298 -270
- package/build/src/task/mutation.js +93 -110
- package/build/src/task/operation-types.d.ts +6 -49
- package/build/src/task/operations.d.ts +2 -1
- package/build/src/task/operations.js +35 -12
- package/build/src/task/query.d.ts +9 -3
- package/build/src/task/query.js +42 -16
- package/build/src/task/store.d.ts +2 -1
- package/build/src/task/store.js +10 -14
- package/build/src/verification/declaration.d.ts +0 -1
- package/build/src/verification/declaration.js +1 -18
- package/build/src/verification/execution.d.ts +6 -2
- package/build/src/verification/observation.d.ts +1 -1
- package/package.json +2 -18
- package/build/src/akuma/akuma-product.d.ts +0 -58
- package/build/src/akuma/akuma-product.js +0 -276
- package/build/src/akuma/fleet-execution.js +0 -234
- package/build/src/akuma/fleet-observation.js +0 -97
- package/build/src/cli/accepted.d.ts +0 -24
- package/build/src/cli/accepted.js +0 -167
- package/build/src/cli/catalog.d.ts +0 -45
- package/build/src/cli/catalog.js +0 -1
- package/build/src/cli/commands/akuma-invoke.d.ts +0 -114
- package/build/src/cli/commands/akuma-invoke.js +0 -375
- package/build/src/cli/commands/contract-invoke.d.ts +0 -34
- package/build/src/cli/commands/contract-invoke.js +0 -259
- package/build/src/cli/commands/nuke.d.ts +0 -10
- package/build/src/cli/commands/nuke.js +0 -20
- package/build/src/cli/commands/status-set.d.ts +0 -4
- package/build/src/cli/commands/status-set.js +0 -52
- package/build/src/cli/commands/task-invoke.d.ts +0 -49
- package/build/src/cli/commands/task-invoke.js +0 -306
- package/build/src/cli/invoke.d.ts +0 -27
- package/build/src/cli/invoke.js +0 -521
- package/build/src/cli/render/board.d.ts +0 -3
- package/build/src/cli/render/board.js +0 -25
- package/build/src/cli/render/status-set.d.ts +0 -5
- package/build/src/cli/render/status-set.js +0 -19
- package/build/src/cli/render/text.d.ts +0 -3
- package/build/src/cli/render/text.js +0 -33
- package/build/src/cli/result.d.ts +0 -240
- package/build/src/cli/result.js +0 -1
- package/build/src/git/result-codec.d.ts +0 -29
- package/build/src/git/result-codec.js +0 -309
- package/build/src/kanshi/fleet.d.ts +0 -6
- package/build/src/kanshi/fleet.js +0 -27
- package/build/src/library/audit.d.ts +0 -29
- package/build/src/library/audit.js +0 -41
- package/build/src/library/composition.d.ts +0 -15
- package/build/src/library/composition.js +0 -28
- package/build/src/library/configuration.d.ts +0 -4
- package/build/src/library/configuration.js +0 -2
- package/build/src/library/contract-bind.d.ts +0 -31
- package/build/src/library/contract-bind.js +0 -140
- package/build/src/library/contract-forwarding.d.ts +0 -55
- package/build/src/library/contract-forwarding.js +0 -67
- package/build/src/library/contract-handle.d.ts +0 -50
- package/build/src/library/contract-handle.js +0 -385
- package/build/src/library/contract.d.ts +0 -46
- package/build/src/library/contract.js +0 -73
- package/build/src/library/execution-result.d.ts +0 -243
- package/build/src/library/execution-result.js +0 -101
- package/build/src/library/execution.d.ts +0 -8
- package/build/src/library/execution.js +0 -102
- package/build/src/library/fleet.d.ts +0 -83
- package/build/src/library/mutation.d.ts +0 -501
- package/build/src/library/mutation.js +0 -248
- package/build/src/library/result-codec.d.ts +0 -2
- package/build/src/library/result-codec.js +0 -12
- package/build/src/protocol/result-codec.d.ts +0 -23
- package/build/src/protocol/result-codec.js +0 -488
- package/build/src/settlement/result-codec.d.ts +0 -2
- package/build/src/settlement/result-codec.js +0 -56
- package/build/src/task/public.d.ts +0 -2
- package/build/src/task/public.js +0 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A backoff sleep that resolves when the owned signal aborts and always clears
|
|
3
|
+
* its timer. Cancellation before the sleep starts completes immediately, and a
|
|
4
|
+
* simultaneous timeout and abort still settles once and drops the listener.
|
|
5
|
+
*/
|
|
6
|
+
function cancellableSleep(signal) {
|
|
7
|
+
return (milliseconds) => new Promise((resolve) => {
|
|
8
|
+
if (signal.aborted) {
|
|
9
|
+
resolve();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
let timer;
|
|
13
|
+
const finish = () => {
|
|
14
|
+
if (timer !== undefined)
|
|
15
|
+
clearTimeout(timer);
|
|
16
|
+
signal.removeEventListener("abort", finish);
|
|
17
|
+
resolve();
|
|
18
|
+
};
|
|
19
|
+
timer = setTimeout(finish, milliseconds);
|
|
20
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function ownEventStream(input) {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const follow = () => {
|
|
26
|
+
if (!controller.signal.aborted)
|
|
27
|
+
controller.abort(input.signal.reason);
|
|
28
|
+
};
|
|
29
|
+
input.signal.addEventListener("abort", follow, { once: true });
|
|
30
|
+
if (input.signal.aborted)
|
|
31
|
+
follow();
|
|
32
|
+
let iterator;
|
|
33
|
+
let pending;
|
|
34
|
+
let settling;
|
|
35
|
+
let ready;
|
|
36
|
+
let subscribed;
|
|
37
|
+
// Retirement may be requested the moment custody owns this stream, so it
|
|
38
|
+
// waits for the one subscription call rather than reaching an unset value.
|
|
39
|
+
const subscribing = new Promise((resolve) => {
|
|
40
|
+
subscribed = resolve;
|
|
41
|
+
});
|
|
42
|
+
let settleClosed;
|
|
43
|
+
let rejectClosed;
|
|
44
|
+
const closed = new Promise((resolve, reject) => {
|
|
45
|
+
settleClosed = resolve;
|
|
46
|
+
rejectClosed = reject;
|
|
47
|
+
});
|
|
48
|
+
const retire = () => {
|
|
49
|
+
if (settling !== undefined)
|
|
50
|
+
return settling;
|
|
51
|
+
settling = (async () => {
|
|
52
|
+
// Abort first: it interrupts the SDK's fetch, reader, and backoff and
|
|
53
|
+
// settles a pending read, before iterator return can be waited on.
|
|
54
|
+
if (!controller.signal.aborted)
|
|
55
|
+
controller.abort(new Error("OpenCode event stream retired"));
|
|
56
|
+
input.signal.removeEventListener("abort", follow);
|
|
57
|
+
await subscribing;
|
|
58
|
+
await ready.catch(() => undefined);
|
|
59
|
+
const reading = pending;
|
|
60
|
+
if (reading !== undefined)
|
|
61
|
+
await reading.catch(() => undefined);
|
|
62
|
+
if (iterator?.return !== undefined)
|
|
63
|
+
await iterator.return(undefined);
|
|
64
|
+
})();
|
|
65
|
+
settling.then(settleClosed, rejectClosed);
|
|
66
|
+
return settling;
|
|
67
|
+
};
|
|
68
|
+
// The owner is registered before native subscription setup begins, so
|
|
69
|
+
// resources arriving after cancellation are still owned and retired.
|
|
70
|
+
input.custody?.own({ closed, abort: retire, forceDispose: retire });
|
|
71
|
+
ready = (async () => {
|
|
72
|
+
const subscription = await input.subscribe({
|
|
73
|
+
directory: input.directory,
|
|
74
|
+
signal: controller.signal,
|
|
75
|
+
sleep: cancellableSleep(controller.signal),
|
|
76
|
+
});
|
|
77
|
+
iterator = subscription.stream[Symbol.asyncIterator]();
|
|
78
|
+
})();
|
|
79
|
+
subscribed();
|
|
80
|
+
void ready.catch(() => undefined);
|
|
81
|
+
return {
|
|
82
|
+
ready,
|
|
83
|
+
next: () => {
|
|
84
|
+
const reading = ready.then(() => iterator.next());
|
|
85
|
+
pending = reading;
|
|
86
|
+
void reading.catch(() => undefined);
|
|
87
|
+
return reading;
|
|
88
|
+
},
|
|
89
|
+
retire,
|
|
90
|
+
closed,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -49,6 +49,5 @@ export declare const OPENCODE_EVENT_DISPOSITIONS: {
|
|
|
49
49
|
readonly "server.connected": "dropped";
|
|
50
50
|
};
|
|
51
51
|
export declare function mapEvent(value: unknown, events: Emitter, state: State): void;
|
|
52
|
-
export type EventState = State;
|
|
53
52
|
export declare function createEventState(sessionId?: string): State;
|
|
54
53
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
|
|
2
|
+
import { ownEventStream } from "./event-stream.js";
|
|
3
3
|
import { createEventState, mapEvent } from "./events.js";
|
|
4
|
-
import { coordinate, loadOpencode, OPENCODE_SDK_PROVIDER, parseModel } from "./session.js";
|
|
4
|
+
import { coordinate, loadOpencode, messageId, OPENCODE_SDK_PROVIDER, parseModel, } from "./session.js";
|
|
5
5
|
function object(value) {
|
|
6
6
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
7
7
|
? value
|
|
@@ -70,7 +70,7 @@ function newest(rows) {
|
|
|
70
70
|
return row;
|
|
71
71
|
const at = Number(object(row.info.time)?.created ?? 0);
|
|
72
72
|
const latestAt = Number(object(latest.info.time)?.created ?? 0);
|
|
73
|
-
return at
|
|
73
|
+
return at > latestAt || (at === latestAt && String(row.info.id) > String(latest.info.id)) ? row : latest;
|
|
74
74
|
}, undefined);
|
|
75
75
|
}
|
|
76
76
|
async function readTurnResult(input) {
|
|
@@ -83,9 +83,9 @@ async function readTurnResult(input) {
|
|
|
83
83
|
const rows = messageRows(response, input.sessionId);
|
|
84
84
|
const user = rows.find((row) => row.info.role === "user" && row.info.id === input.messageID);
|
|
85
85
|
if (user === undefined)
|
|
86
|
-
return
|
|
87
|
-
const userId = text(user
|
|
88
|
-
const assistant = newest(rows.filter((row) => row.info.role === "assistant" && row.info.parentID === userId));
|
|
86
|
+
return { kind: "failed", diagnostic: "OpenCode completed without the admitted user message" };
|
|
87
|
+
const userId = text(user.info.id);
|
|
88
|
+
const assistant = newest(rows.filter((row) => row.info.role === "assistant" && row.info.parentID === userId && row.info.summary !== true));
|
|
89
89
|
const historyId = text(assistant?.info.id);
|
|
90
90
|
if (input.state.failure !== undefined)
|
|
91
91
|
return { kind: "failed", diagnostic: input.state.failure };
|
|
@@ -119,10 +119,6 @@ function scopedProperties(value, sessionId) {
|
|
|
119
119
|
const properties = object(object(value)?.properties);
|
|
120
120
|
return nativeSessionId(value) === sessionId ? properties : undefined;
|
|
121
121
|
}
|
|
122
|
-
function stopIterator(iterator) {
|
|
123
|
-
const stopped = iterator?.return?.(undefined);
|
|
124
|
-
void stopped?.catch(() => undefined);
|
|
125
|
-
}
|
|
126
122
|
function nativeProgress(type, properties, busy) {
|
|
127
123
|
if (type === "session.idle")
|
|
128
124
|
return { busy, terminal: busy };
|
|
@@ -137,48 +133,122 @@ function startsTurn(value, sessionId, messageID) {
|
|
|
137
133
|
const info = object(object(event?.properties)?.info);
|
|
138
134
|
return (event?.type === "message.updated" && info?.sessionID === sessionId && info.role === "user" && info.id === messageID);
|
|
139
135
|
}
|
|
136
|
+
function recognizeAdmission(value, sessionId, admission) {
|
|
137
|
+
const event = object(value);
|
|
138
|
+
const properties = object(event?.properties);
|
|
139
|
+
const info = object(properties?.info);
|
|
140
|
+
if (event?.type === "message.updated" &&
|
|
141
|
+
info?.sessionID === sessionId &&
|
|
142
|
+
info.role === "user" &&
|
|
143
|
+
typeof info.id === "string") {
|
|
144
|
+
admission.admit(info.id);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function observeEvent(input) {
|
|
148
|
+
const observedSessionId = nativeSessionId(input.value);
|
|
149
|
+
if (observedSessionId !== undefined && observedSessionId !== input.sessionId) {
|
|
150
|
+
return { active: input.active, busy: input.busy, terminal: false };
|
|
151
|
+
}
|
|
152
|
+
const event = object(input.value);
|
|
153
|
+
const properties = scopedProperties(input.value, input.sessionId);
|
|
154
|
+
if (properties === undefined) {
|
|
155
|
+
if (input.active)
|
|
156
|
+
mapEvent(input.value, input.events, input.state);
|
|
157
|
+
return { active: input.active, busy: input.busy, terminal: false };
|
|
158
|
+
}
|
|
159
|
+
const starts = !input.active && startsTurn(input.value, input.sessionId, input.messageID);
|
|
160
|
+
const active = input.active || starts;
|
|
161
|
+
const busy = starts ? false : input.busy;
|
|
162
|
+
recognizeAdmission(input.value, input.sessionId, input.admission);
|
|
163
|
+
const submittedError = event?.type === "session.error" && input.submissionState.started;
|
|
164
|
+
if (!active && !submittedError)
|
|
165
|
+
return { active, busy, terminal: false };
|
|
166
|
+
mapEvent(input.value, input.events, input.state);
|
|
167
|
+
if (event?.type === "session.error") {
|
|
168
|
+
input.admission.end();
|
|
169
|
+
return {
|
|
170
|
+
active,
|
|
171
|
+
busy,
|
|
172
|
+
terminal: true,
|
|
173
|
+
result: { kind: "failed", diagnostic: input.state.failure ?? diagnostic(properties.error) },
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const progress = nativeProgress(event?.type, properties, busy);
|
|
177
|
+
return { active, busy: progress.busy, terminal: progress.terminal };
|
|
178
|
+
}
|
|
140
179
|
async function observeTurn(input) {
|
|
141
180
|
let active = false;
|
|
142
181
|
let busy = false;
|
|
143
182
|
try {
|
|
144
183
|
for (;;) {
|
|
145
|
-
const next = await input.
|
|
184
|
+
const next = await input.stream.next();
|
|
146
185
|
if (next.done)
|
|
147
186
|
return { kind: "failed", diagnostic: "OpenCode event stream ended before Turn completion" };
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (!active && !submittedError)
|
|
165
|
-
continue;
|
|
166
|
-
mapEvent(value, input.events, input.state);
|
|
167
|
-
if (event?.type === "session.error") {
|
|
168
|
-
return { kind: "failed", diagnostic: input.state.failure ?? diagnostic(properties.error) };
|
|
169
|
-
}
|
|
170
|
-
const progress = nativeProgress(event?.type, properties, busy);
|
|
171
|
-
busy = progress.busy;
|
|
172
|
-
if (!progress.terminal)
|
|
187
|
+
const observed = observeEvent({
|
|
188
|
+
value: eventValue(next.value),
|
|
189
|
+
sessionId: input.sessionId,
|
|
190
|
+
messageID: input.messageID,
|
|
191
|
+
active,
|
|
192
|
+
busy,
|
|
193
|
+
admission: input.admission,
|
|
194
|
+
events: input.events,
|
|
195
|
+
state: input.state,
|
|
196
|
+
submissionState: input.submissionState,
|
|
197
|
+
});
|
|
198
|
+
active = observed.active;
|
|
199
|
+
busy = observed.busy;
|
|
200
|
+
if (observed.result !== undefined)
|
|
201
|
+
return observed.result;
|
|
202
|
+
if (!observed.terminal)
|
|
173
203
|
continue;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return result;
|
|
204
|
+
input.admission.end();
|
|
205
|
+
return await readTurnResult({ ...input, messageID: input.admission.latest() });
|
|
177
206
|
}
|
|
178
207
|
}
|
|
179
208
|
catch (error) {
|
|
180
209
|
return { kind: "failed", diagnostic: `OpenCode event stream failed: ${diagnostic(error)}` };
|
|
181
210
|
}
|
|
211
|
+
finally {
|
|
212
|
+
input.admission.end();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function liveAdmission(initial) {
|
|
216
|
+
let latest = initial;
|
|
217
|
+
let ended = false;
|
|
218
|
+
const pending = new Map();
|
|
219
|
+
const wait = (id) => {
|
|
220
|
+
if (ended)
|
|
221
|
+
return Promise.resolve({ kind: "turn-ended" });
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
pending.set(id, { resolve, reject });
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
return {
|
|
227
|
+
initial: wait(initial),
|
|
228
|
+
latest: () => latest,
|
|
229
|
+
open: () => !ended,
|
|
230
|
+
wait,
|
|
231
|
+
admit(id) {
|
|
232
|
+
const waiter = pending.get(id);
|
|
233
|
+
if (waiter === undefined || ended)
|
|
234
|
+
return;
|
|
235
|
+
pending.delete(id);
|
|
236
|
+
latest = id;
|
|
237
|
+
waiter.resolve({ kind: "accepted", fence: id });
|
|
238
|
+
},
|
|
239
|
+
fail(id, error) {
|
|
240
|
+
pending.get(id)?.reject(error);
|
|
241
|
+
pending.delete(id);
|
|
242
|
+
},
|
|
243
|
+
end() {
|
|
244
|
+
if (ended)
|
|
245
|
+
return;
|
|
246
|
+
ended = true;
|
|
247
|
+
for (const waiter of pending.values())
|
|
248
|
+
waiter.resolve({ kind: "turn-ended" });
|
|
249
|
+
pending.clear();
|
|
250
|
+
},
|
|
251
|
+
};
|
|
182
252
|
}
|
|
183
253
|
function terminalSettlement(events, close) {
|
|
184
254
|
let finish;
|
|
@@ -186,8 +256,14 @@ function terminalSettlement(events, close) {
|
|
|
186
256
|
let settlement;
|
|
187
257
|
finish = (result) => {
|
|
188
258
|
settlement ??= (async () => {
|
|
189
|
-
|
|
259
|
+
// Whole closure is proved before narration ends. The driver therefore
|
|
260
|
+
// stays inside its Heart/control observation race while retirement is
|
|
261
|
+
// outstanding, so a rejected or unprovable closure still reaches attempt
|
|
262
|
+
// custody's bounded hung handling instead of parking on a pending
|
|
263
|
+
// completion. Ending narration first would move that await outside the
|
|
264
|
+
// driver's race and make the Body unresponsive to stop or Heart loss.
|
|
190
265
|
await close();
|
|
266
|
+
events.end();
|
|
191
267
|
resolve(result);
|
|
192
268
|
})();
|
|
193
269
|
return settlement;
|
|
@@ -195,6 +271,18 @@ function terminalSettlement(events, close) {
|
|
|
195
271
|
});
|
|
196
272
|
return { completion, finish };
|
|
197
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* One memoized whole-close: stream retirement and existing server retirement
|
|
276
|
+
* start together on every terminal path, so a live socket can never outwait the
|
|
277
|
+
* server's death.
|
|
278
|
+
*/
|
|
279
|
+
function wholeClosure(retireStream, closeServer) {
|
|
280
|
+
let closing;
|
|
281
|
+
return () => {
|
|
282
|
+
closing ??= Promise.all([retireStream(), closeServer()]).then(() => undefined);
|
|
283
|
+
return closing;
|
|
284
|
+
};
|
|
285
|
+
}
|
|
198
286
|
async function forceDisposeOpencode(abortController, close, finish) {
|
|
199
287
|
abortController.abort();
|
|
200
288
|
await close();
|
|
@@ -245,6 +333,46 @@ async function openDriveSession(runtime, input, resumeSessionId, signal) {
|
|
|
245
333
|
throw new Error("OpenCode did not return a session id");
|
|
246
334
|
return { session, sessionId };
|
|
247
335
|
}
|
|
336
|
+
function createLiveSession(input) {
|
|
337
|
+
let submissions = input.admission.initial.then(() => undefined);
|
|
338
|
+
const submit = (tell) => {
|
|
339
|
+
const submission = async () => {
|
|
340
|
+
if (!input.admission.open())
|
|
341
|
+
return { kind: "turn-ended" };
|
|
342
|
+
const receipt = input.admission.wait(tell.id);
|
|
343
|
+
void input.session
|
|
344
|
+
.promptAsync({
|
|
345
|
+
path: { id: input.sessionId },
|
|
346
|
+
query: { directory: input.cwd },
|
|
347
|
+
body: input.promptBody(tell.id, tell.text),
|
|
348
|
+
throwOnError: true,
|
|
349
|
+
})
|
|
350
|
+
.catch((error) => input.admission.fail(tell.id, error));
|
|
351
|
+
return await receipt;
|
|
352
|
+
};
|
|
353
|
+
const next = submissions.then(submission);
|
|
354
|
+
submissions = next.then(() => undefined, () => undefined);
|
|
355
|
+
return next;
|
|
356
|
+
};
|
|
357
|
+
return {
|
|
358
|
+
admission: { fence: input.sessionId },
|
|
359
|
+
events: input.events,
|
|
360
|
+
completion: input.completion,
|
|
361
|
+
tell: (tell) => submit({ ...tell, id: input.nextMessageId() }),
|
|
362
|
+
abort: async () => {
|
|
363
|
+
input.admission.end();
|
|
364
|
+
input.abortController.abort();
|
|
365
|
+
void input.session
|
|
366
|
+
.abort({ path: { id: input.sessionId }, query: { directory: input.cwd }, throwOnError: true })
|
|
367
|
+
.catch(() => undefined);
|
|
368
|
+
await input.finish({ kind: "failed", diagnostic: "OpenCode session interrupted" });
|
|
369
|
+
},
|
|
370
|
+
forceDispose: () => {
|
|
371
|
+
input.admission.end();
|
|
372
|
+
return forceDisposeOpencode(input.abortController, input.close, input.finish);
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
}
|
|
248
376
|
async function drive(execution, input, loader, custody) {
|
|
249
377
|
admit(input.options);
|
|
250
378
|
const signal = input.signal ?? new AbortController().signal;
|
|
@@ -257,27 +385,34 @@ async function drive(execution, input, loader, custody) {
|
|
|
257
385
|
const runtime = await loadDriveRuntime(execution, input, abortController.signal, loader, (ready) => {
|
|
258
386
|
closeOnce = ownRuntime(custody, ready);
|
|
259
387
|
});
|
|
260
|
-
|
|
388
|
+
const stream = ownEventStream({
|
|
389
|
+
directory: input.cwd,
|
|
390
|
+
signal: abortController.signal,
|
|
391
|
+
...(custody === undefined ? {} : { custody }),
|
|
392
|
+
subscribe: (request) => runtime.client.event.subscribe(request),
|
|
393
|
+
});
|
|
394
|
+
const wholeClose = wholeClosure(() => stream.retire(), () => closeOnce());
|
|
261
395
|
try {
|
|
262
396
|
const { session, sessionId } = await openDriveSession(runtime, input, resumeSessionId, abortController.signal);
|
|
263
397
|
const events = new AgentEventChannel();
|
|
264
398
|
const state = createEventState(sessionId);
|
|
265
|
-
const
|
|
399
|
+
const messageSequence = { value: 0 };
|
|
400
|
+
const nextMessageId = () => messageId(messageSequence.value++);
|
|
401
|
+
const messageID = nextMessageId();
|
|
402
|
+
const admission = liveAdmission(messageID);
|
|
266
403
|
const submissionState = { started: false };
|
|
267
404
|
events.emit({ type: "session", coordinate: coordinate(sessionId) });
|
|
268
|
-
|
|
269
|
-
if (abortController.signal.aborted)
|
|
270
|
-
await streamResult.stream[Symbol.asyncIterator]().return?.(undefined);
|
|
405
|
+
await stream.ready;
|
|
406
|
+
if (abortController.signal.aborted)
|
|
271
407
|
abortController.signal.throwIfAborted();
|
|
272
|
-
}
|
|
273
|
-
iterator = streamResult.stream[Symbol.asyncIterator]();
|
|
274
|
-
const { completion, finish } = terminalSettlement(events, closeOnce);
|
|
408
|
+
const { completion, finish } = terminalSettlement(events, wholeClose);
|
|
275
409
|
const observation = observeTurn({
|
|
276
|
-
|
|
410
|
+
stream,
|
|
277
411
|
session,
|
|
278
412
|
sessionId,
|
|
279
413
|
cwd: input.cwd,
|
|
280
414
|
messageID,
|
|
415
|
+
admission,
|
|
281
416
|
events,
|
|
282
417
|
state,
|
|
283
418
|
submissionState,
|
|
@@ -290,26 +425,27 @@ async function drive(execution, input, loader, custody) {
|
|
|
290
425
|
throwOnError: true,
|
|
291
426
|
});
|
|
292
427
|
abortController.signal.throwIfAborted();
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
428
|
+
// The observer never awaits its own completion: finishing retires the whole
|
|
429
|
+
// stream, but the observer that invoked finish stays outside that wait. Its
|
|
430
|
+
// rejection is owned by attempt custody, not by an unobserved promise.
|
|
431
|
+
void observation.then(finish).catch(() => undefined);
|
|
432
|
+
return createLiveSession({
|
|
433
|
+
session,
|
|
434
|
+
sessionId,
|
|
435
|
+
cwd: input.cwd,
|
|
436
|
+
promptBody: (messageID, text) => promptBody({ ...input, body: text, launchTells: [] }, messageID),
|
|
437
|
+
admission,
|
|
438
|
+
nextMessageId,
|
|
297
439
|
events,
|
|
298
440
|
completion,
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
.catch(() => undefined);
|
|
304
|
-
await finish({ kind: "failed", diagnostic: "OpenCode session interrupted" });
|
|
305
|
-
},
|
|
306
|
-
forceDispose: () => forceDisposeOpencode(abortController, closeOnce, finish),
|
|
307
|
-
};
|
|
441
|
+
abortController,
|
|
442
|
+
close: wholeClose,
|
|
443
|
+
finish,
|
|
444
|
+
});
|
|
308
445
|
}
|
|
309
446
|
catch (error) {
|
|
310
447
|
signal.removeEventListener("abort", abortSetup);
|
|
311
|
-
|
|
312
|
-
await closeOnce();
|
|
448
|
+
await wholeClose();
|
|
313
449
|
throw error;
|
|
314
450
|
}
|
|
315
451
|
}
|
|
@@ -2,7 +2,24 @@ import type { OpencodeClient } from "@opencode-ai/sdk";
|
|
|
2
2
|
import type { ResumeCoordinate } from "../../heart/index.js";
|
|
3
3
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
4
4
|
export type OpencodeSdkSession = Pick<OpencodeClient["session"], "create" | "get" | "fork" | "abort" | "promptAsync" | "messages">;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The adapter's own event subscription port. It carries the cancellation signal
|
|
7
|
+
* and the cancellable retry backoff the installed client honors at runtime,
|
|
8
|
+
* without naming the SDK's generated request type at the call site.
|
|
9
|
+
*/
|
|
10
|
+
export type OpencodeEventSubscriptionRequest = Readonly<{
|
|
11
|
+
directory: string;
|
|
12
|
+
/** Cancels the subscription's fetch, reader, and retry waiting. */
|
|
13
|
+
signal: AbortSignal;
|
|
14
|
+
/** Resolves without rejecting when `signal` aborts, and always clears its timer. */
|
|
15
|
+
sleep(milliseconds: number): Promise<void>;
|
|
16
|
+
}>;
|
|
17
|
+
type OpencodeEventSubscription = Readonly<{
|
|
18
|
+
stream: AsyncIterable<unknown>;
|
|
19
|
+
}>;
|
|
20
|
+
export type OpencodeSdkEvent = Readonly<{
|
|
21
|
+
subscribe(request: OpencodeEventSubscriptionRequest): Promise<OpencodeEventSubscription>;
|
|
22
|
+
}>;
|
|
6
23
|
export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution, signal: AbortSignal) => Promise<Readonly<{
|
|
7
24
|
client: {
|
|
8
25
|
session: OpencodeSdkSession;
|
|
@@ -12,10 +29,32 @@ export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution, sign
|
|
|
12
29
|
ready?: Promise<void>;
|
|
13
30
|
}>>;
|
|
14
31
|
export declare const OPENCODE_SDK_PROVIDER: "opencode-sdk";
|
|
32
|
+
/**
|
|
33
|
+
* Adapt the installed client's generated event endpoint to the adapter's
|
|
34
|
+
* subscription port.
|
|
35
|
+
*
|
|
36
|
+
* The generated per-endpoint `Options` type omits the SDK's runtime
|
|
37
|
+
* `sseSleepFn` option even though the client forwards every per-request key
|
|
38
|
+
* into `createSseClient`, so a caller cannot express a cancellable backoff
|
|
39
|
+
* through the published type. Declaring the port here keeps that one typing gap
|
|
40
|
+
* and its single adaptation at the SDK seam: no other module repeats a cast,
|
|
41
|
+
* the SDK's own parser and retry policy stay untouched, and an injected loader
|
|
42
|
+
* supplies the same port shape.
|
|
43
|
+
*/
|
|
44
|
+
export declare function opencodeEventPort(event: OpencodeClient["event"]): OpencodeSdkEvent;
|
|
45
|
+
export declare function messageId(sequence?: number): string;
|
|
15
46
|
export declare function parseModel(model: string): Readonly<{
|
|
16
47
|
providerID: string;
|
|
17
48
|
modelID: string;
|
|
18
49
|
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Compose the config handed to a headless opencode server. The permission base
|
|
52
|
+
* layer fills only the classes the caller leaves unspecified: an explicit caller
|
|
53
|
+
* permission key wins per key and every non-permission key passes through
|
|
54
|
+
* untouched. A caller that supplies a non-object `permission` shorthand states
|
|
55
|
+
* the whole policy and keeps it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function composeHeadlessPermissionConfig(config?: Readonly<Record<string, unknown>>): Record<string, unknown>;
|
|
19
58
|
export type OpencodeRuntime = Readonly<{
|
|
20
59
|
client: {
|
|
21
60
|
session: OpencodeSdkSession;
|
|
@@ -32,3 +71,4 @@ export declare function loadOpencode(input: Readonly<{
|
|
|
32
71
|
requests?: string;
|
|
33
72
|
}>): Promise<OpencodeRuntime>;
|
|
34
73
|
export declare function coordinate(sessionId: string): ResumeCoordinate;
|
|
74
|
+
export {};
|
|
@@ -1,14 +1,81 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
2
3
|
import { abortable } from "../../abort.js";
|
|
3
4
|
import { akumaExecutionEnvironment } from "../execution-environment.js";
|
|
4
5
|
import { spawnDetachedProcess } from "../../../runtime/proc/run.js";
|
|
5
6
|
export const OPENCODE_SDK_PROVIDER = "opencode-sdk";
|
|
7
|
+
/**
|
|
8
|
+
* Adapt the installed client's generated event endpoint to the adapter's
|
|
9
|
+
* subscription port.
|
|
10
|
+
*
|
|
11
|
+
* The generated per-endpoint `Options` type omits the SDK's runtime
|
|
12
|
+
* `sseSleepFn` option even though the client forwards every per-request key
|
|
13
|
+
* into `createSseClient`, so a caller cannot express a cancellable backoff
|
|
14
|
+
* through the published type. Declaring the port here keeps that one typing gap
|
|
15
|
+
* and its single adaptation at the SDK seam: no other module repeats a cast,
|
|
16
|
+
* the SDK's own parser and retry policy stay untouched, and an injected loader
|
|
17
|
+
* supplies the same port shape.
|
|
18
|
+
*/
|
|
19
|
+
export function opencodeEventPort(event) {
|
|
20
|
+
return {
|
|
21
|
+
subscribe: (request) => {
|
|
22
|
+
const adapted = {
|
|
23
|
+
query: { directory: request.directory },
|
|
24
|
+
signal: request.signal,
|
|
25
|
+
};
|
|
26
|
+
// Runtime-only key omitted from the generated Options type; the installed
|
|
27
|
+
// client forwards it to createSseClient unchanged.
|
|
28
|
+
adapted.sseSleepFn = request.sleep;
|
|
29
|
+
return event.subscribe(adapted);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function messageId(sequence = 0) {
|
|
34
|
+
const timestamp = BigInt(new Date().getTime()) * 0x1000n + BigInt(sequence);
|
|
35
|
+
const bytes = Buffer.alloc(6);
|
|
36
|
+
bytes.writeUIntBE(Number(timestamp & 0xffffffffffffn), 0, 6);
|
|
37
|
+
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
38
|
+
const suffix = [...randomBytes(14)].map((byte) => alphabet[byte % alphabet.length]).join("");
|
|
39
|
+
return `msg_${bytes.toString("hex")}${suffix}`;
|
|
40
|
+
}
|
|
6
41
|
export function parseModel(model) {
|
|
7
42
|
const slash = model.indexOf("/");
|
|
8
43
|
if (slash <= 0 || slash === model.length - 1)
|
|
9
44
|
throw new Error("OpenCode model must be <provider>/<model>");
|
|
10
45
|
return { providerID: model.slice(0, slash), modelID: model.slice(slash + 1) };
|
|
11
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Permission classes whose upstream defaults can await a human reply. A headless
|
|
49
|
+
* server has no reply channel, so such a pending ask never settles.
|
|
50
|
+
*
|
|
51
|
+
* Verified against the installed opencode 1.18.33 agent permission ruleset: the
|
|
52
|
+
* primary agents start from `{"*":"allow"}` with `external_directory` and
|
|
53
|
+
* `doom_loop` set to ask, `read` set to ask for `.env` files, and `question`
|
|
54
|
+
* allowed (the question tool awaits an answer by semantics). Every other class
|
|
55
|
+
* matches the allow-all rule and cannot await.
|
|
56
|
+
*/
|
|
57
|
+
const HEADLESS_PERMISSION_BASE = Object.freeze({
|
|
58
|
+
external_directory: "allow",
|
|
59
|
+
doom_loop: "allow",
|
|
60
|
+
read: "allow",
|
|
61
|
+
question: "deny",
|
|
62
|
+
});
|
|
63
|
+
function isRecord(value) {
|
|
64
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Compose the config handed to a headless opencode server. The permission base
|
|
68
|
+
* layer fills only the classes the caller leaves unspecified: an explicit caller
|
|
69
|
+
* permission key wins per key and every non-permission key passes through
|
|
70
|
+
* untouched. A caller that supplies a non-object `permission` shorthand states
|
|
71
|
+
* the whole policy and keeps it.
|
|
72
|
+
*/
|
|
73
|
+
export function composeHeadlessPermissionConfig(config) {
|
|
74
|
+
const permission = config?.permission;
|
|
75
|
+
if (permission !== undefined && !isRecord(permission))
|
|
76
|
+
return { ...config };
|
|
77
|
+
return { ...config, permission: { ...HEADLESS_PERMISSION_BASE, ...permission } };
|
|
78
|
+
}
|
|
12
79
|
async function waitReady(client, cwd, signal) {
|
|
13
80
|
for (let attempt = 0; attempt < 100; attempt += 1) {
|
|
14
81
|
if (signal.aborted)
|
|
@@ -67,7 +134,7 @@ export async function loadOpencode(input) {
|
|
|
67
134
|
argv: [execution.executable ?? "opencode", "serve", "--hostname", "127.0.0.1", "--port", String(port)],
|
|
68
135
|
cwd,
|
|
69
136
|
env: akumaExecutionEnvironment(process.env, {
|
|
70
|
-
|
|
137
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify(composeHeadlessPermissionConfig(execution.config)),
|
|
71
138
|
...execution.env,
|
|
72
139
|
}, requests),
|
|
73
140
|
log: `${cwd}/.opencode.log`,
|
|
@@ -76,7 +143,7 @@ export async function loadOpencode(input) {
|
|
|
76
143
|
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}`, directory: cwd });
|
|
77
144
|
let closing;
|
|
78
145
|
const runtime = {
|
|
79
|
-
client,
|
|
146
|
+
client: { session: client.session, event: opencodeEventPort(client.event) },
|
|
80
147
|
close: async () => {
|
|
81
148
|
closing ??= owned.terminate();
|
|
82
149
|
await closing;
|
|
@@ -146,7 +146,6 @@ function translateMessage(event, state) {
|
|
|
146
146
|
const message = record(event.message);
|
|
147
147
|
if (message?.role !== "assistant")
|
|
148
148
|
return [];
|
|
149
|
-
state.assistantSeen = true;
|
|
150
149
|
const translated = [];
|
|
151
150
|
if (Array.isArray(message.content)) {
|
|
152
151
|
for (const block of message.content) {
|
|
@@ -160,7 +159,11 @@ function translateMessage(event, state) {
|
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
161
|
const text = textContent(message.content);
|
|
163
|
-
|
|
162
|
+
const terminal = message.stopReason !== "toolUse";
|
|
163
|
+
if (terminal) {
|
|
164
|
+
state.assistantSeen = true;
|
|
165
|
+
state.answer = text;
|
|
166
|
+
}
|
|
164
167
|
// Gemini emits an empty text block alongside every tool-use message. It is
|
|
165
168
|
// transport scaffolding, not narration; an ordinary terminal empty answer
|
|
166
169
|
// remains public evidence.
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { createAgentSessionFromServices, createAgentSessionServices, createBashToolDefinition, getAgentDir, SessionManager } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
3
3
|
import { type ProviderAdapter } from "../../provider.js";
|
|
4
4
|
export type PiSdk = Readonly<{
|
|
5
|
-
|
|
5
|
+
createAgentSessionFromServices: typeof createAgentSessionFromServices;
|
|
6
|
+
createAgentSessionServices: typeof createAgentSessionServices;
|
|
6
7
|
createBashToolDefinition: typeof createBashToolDefinition;
|
|
7
|
-
DefaultResourceLoader: typeof DefaultResourceLoader;
|
|
8
8
|
getAgentDir: typeof getAgentDir;
|
|
9
|
-
ModelRuntime: typeof ModelRuntime;
|
|
10
9
|
SessionManager: typeof SessionManager;
|
|
11
10
|
}>;
|
|
12
11
|
export declare function createPiProvider(execution?: ProviderExecution, load?: () => Promise<PiSdk>): ProviderAdapter;
|