@scotthuang/agent-knock-knock 0.13.2 → 0.13.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/CHANGELOG.md +36 -0
- package/README.md +27 -6
- package/dist/src/callback-outbox-policy.js +27 -6
- package/dist/src/callback-outbox-policy.js.map +1 -1
- package/dist/src/callback-outbox-service.d.ts +4 -30
- package/dist/src/callback-outbox-service.js +21 -154
- package/dist/src/callback-outbox-service.js.map +1 -1
- package/dist/src/callback-outbox-settlement.js +13 -8
- package/dist/src/callback-outbox-settlement.js.map +1 -1
- package/dist/src/callback-route-service.d.ts +46 -0
- package/dist/src/callback-route-service.js +155 -0
- package/dist/src/callback-route-service.js.map +1 -0
- package/dist/src/claude-terminal-agent-adapter.js +4 -0
- package/dist/src/claude-terminal-agent-adapter.js.map +1 -1
- package/dist/src/cli-core.js +9 -1
- package/dist/src/cli-core.js.map +1 -1
- package/dist/src/codex-process-incarnation.d.ts +8 -0
- package/dist/src/codex-process-incarnation.js +36 -0
- package/dist/src/codex-process-incarnation.js.map +1 -0
- package/dist/src/codex-terminal-agent-adapter.js +4 -0
- package/dist/src/codex-terminal-agent-adapter.js.map +1 -1
- package/dist/src/deferred-foreground-conflict-policy.d.ts +22 -0
- package/dist/src/deferred-foreground-conflict-policy.js +52 -0
- package/dist/src/deferred-foreground-conflict-policy.js.map +1 -0
- package/dist/src/durable-notification-kernel.d.ts +94 -0
- package/dist/src/durable-notification-kernel.js +68 -0
- package/dist/src/durable-notification-kernel.js.map +1 -0
- package/dist/src/herdr-socket-transport.d.ts +43 -0
- package/dist/src/herdr-socket-transport.js +170 -0
- package/dist/src/herdr-socket-transport.js.map +1 -0
- package/dist/src/herdr-terminal-control-provider.d.ts +2 -45
- package/dist/src/herdr-terminal-control-provider.js +8 -173
- package/dist/src/herdr-terminal-control-provider.js.map +1 -1
- package/dist/src/host-adapter-capabilities.d.ts +35 -0
- package/dist/src/host-adapter-capabilities.js +146 -0
- package/dist/src/host-adapter-capabilities.js.map +1 -0
- package/dist/src/host-adapter.d.ts +9 -3
- package/dist/src/host-adapter.js +33 -9
- package/dist/src/host-adapter.js.map +1 -1
- package/dist/src/host-bridge-tools.d.ts +3 -4
- package/dist/src/host-bridge-tools.js +49 -92
- package/dist/src/host-bridge-tools.js.map +1 -1
- package/dist/src/host-bridge.js +5 -5
- package/dist/src/host-bridge.js.map +1 -1
- package/dist/src/host-monitor-reconciliation.d.ts +6 -0
- package/dist/src/host-monitor-reconciliation.js +96 -0
- package/dist/src/host-monitor-reconciliation.js.map +1 -0
- package/dist/src/managed-session.js +2 -18
- package/dist/src/managed-session.js.map +1 -1
- package/dist/src/native-thread-lifecycle-cli-adapter.d.ts +13 -0
- package/dist/src/native-thread-lifecycle-cli-adapter.js +635 -3
- package/dist/src/native-thread-lifecycle-cli-adapter.js.map +1 -1
- package/dist/src/openclaw-list-projection.d.ts +2 -0
- package/dist/src/openclaw-list-projection.js +3 -0
- package/dist/src/openclaw-list-projection.js.map +1 -0
- package/dist/src/openclaw-model-facing-field-policy.d.ts +2 -0
- package/dist/src/openclaw-model-facing-field-policy.js +3 -0
- package/dist/src/openclaw-model-facing-field-policy.js.map +1 -0
- package/dist/src/openclaw-plugin-command-adapter.d.ts +6 -29
- package/dist/src/openclaw-plugin-command-adapter.js +7 -2370
- package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
- package/dist/src/openclaw-plugin-helpers.d.ts +2 -121
- package/dist/src/openclaw-plugin-helpers.js +2 -1164
- package/dist/src/openclaw-plugin-helpers.js.map +1 -1
- package/dist/src/openclaw-plugin-schemas.d.ts +2 -510
- package/dist/src/openclaw-plugin-schemas.js +2 -519
- package/dist/src/openclaw-plugin-schemas.js.map +1 -1
- package/dist/src/openclaw-plugin-supervisor.d.ts +4 -5
- package/dist/src/openclaw-plugin-supervisor.js +5 -94
- package/dist/src/openclaw-plugin-supervisor.js.map +1 -1
- package/dist/src/openclaw-plugin-value-helpers.d.ts +2 -0
- package/dist/src/openclaw-plugin-value-helpers.js +3 -0
- package/dist/src/openclaw-plugin-value-helpers.js.map +1 -0
- package/dist/src/openclaw-private-authority-offers.d.ts +4 -39
- package/dist/src/openclaw-private-authority-offers.js +3 -258
- package/dist/src/openclaw-private-authority-offers.js.map +1 -1
- package/dist/src/semantic-private-authority-offers.d.ts +41 -0
- package/dist/src/semantic-private-authority-offers.js +261 -0
- package/dist/src/semantic-private-authority-offers.js.map +1 -0
- package/dist/src/semantic-tool-arguments.d.ts +9 -0
- package/dist/src/semantic-tool-arguments.js +64 -0
- package/dist/src/semantic-tool-arguments.js.map +1 -0
- package/dist/src/semantic-tool-catalog.d.ts +48 -0
- package/dist/src/semantic-tool-catalog.js +105 -0
- package/dist/src/semantic-tool-catalog.js.map +1 -0
- package/dist/src/semantic-tool-command-helpers.d.ts +145 -0
- package/dist/src/semantic-tool-command-helpers.js +1272 -0
- package/dist/src/semantic-tool-command-helpers.js.map +1 -0
- package/dist/src/semantic-tool-list-projection.d.ts +10 -0
- package/dist/src/semantic-tool-list-projection.js +497 -0
- package/dist/src/semantic-tool-list-projection.js.map +1 -0
- package/dist/src/semantic-tool-model-facing-field-policy.d.ts +3 -0
- package/dist/src/semantic-tool-model-facing-field-policy.js +66 -0
- package/dist/src/semantic-tool-model-facing-field-policy.js.map +1 -0
- package/dist/src/semantic-tool-presentation.d.ts +37 -0
- package/dist/src/semantic-tool-presentation.js +680 -0
- package/dist/src/semantic-tool-presentation.js.map +1 -0
- package/dist/src/semantic-tool-private-authority.d.ts +39 -0
- package/dist/src/semantic-tool-private-authority.js +602 -0
- package/dist/src/semantic-tool-private-authority.js.map +1 -0
- package/dist/src/semantic-tool-relay.d.ts +16 -0
- package/dist/src/semantic-tool-relay.js +175 -0
- package/dist/src/semantic-tool-relay.js.map +1 -0
- package/dist/src/semantic-tool-runtime.d.ts +10 -0
- package/dist/src/semantic-tool-runtime.js +1157 -0
- package/dist/src/semantic-tool-runtime.js.map +1 -0
- package/dist/src/semantic-tool-schemas.d.ts +563 -0
- package/dist/src/semantic-tool-schemas.js +573 -0
- package/dist/src/semantic-tool-schemas.js.map +1 -0
- package/dist/src/semantic-tool-value-helpers.d.ts +5 -0
- package/dist/src/semantic-tool-value-helpers.js +27 -0
- package/dist/src/semantic-tool-value-helpers.js.map +1 -0
- package/dist/src/store-event-presentation.d.ts +17 -0
- package/dist/src/store-event-presentation.js +33 -0
- package/dist/src/store-event-presentation.js.map +1 -0
- package/dist/src/store.d.ts +3 -16
- package/dist/src/store.js +2 -30
- package/dist/src/store.js.map +1 -1
- package/dist/src/terminal-action-projection.d.ts +3 -17
- package/dist/src/terminal-action-projection.js +13 -41
- package/dist/src/terminal-action-projection.js.map +1 -1
- package/dist/src/terminal-agent-adapter.d.ts +7 -0
- package/dist/src/terminal-agent-adapter.js +8 -0
- package/dist/src/terminal-agent-adapter.js.map +1 -1
- package/dist/src/terminal-agent-bridge.d.ts +35 -332
- package/dist/src/terminal-agent-bridge.js +293 -2798
- package/dist/src/terminal-agent-bridge.js.map +1 -1
- package/dist/src/terminal-approval-cli-adapter.d.ts +17 -0
- package/dist/src/terminal-approval-cli-adapter.js +921 -0
- package/dist/src/terminal-approval-cli-adapter.js.map +1 -0
- package/dist/src/terminal-command-cli-adapter.d.ts +2 -429
- package/dist/src/terminal-command-cli-adapter.js +344 -6061
- package/dist/src/terminal-command-cli-adapter.js.map +1 -1
- package/dist/src/terminal-command-cli-ports.d.ts +443 -0
- package/dist/src/terminal-command-cli-ports.js +2 -0
- package/dist/src/terminal-command-cli-ports.js.map +1 -0
- package/dist/src/terminal-command-dispatch-preparation.d.ts +81 -0
- package/dist/src/terminal-command-dispatch-preparation.js +209 -0
- package/dist/src/terminal-command-dispatch-preparation.js.map +1 -0
- package/dist/src/terminal-command-dispatch-transport.d.ts +35 -0
- package/dist/src/terminal-command-dispatch-transport.js +859 -0
- package/dist/src/terminal-command-dispatch-transport.js.map +1 -0
- package/dist/src/terminal-command-foreground-proof.d.ts +32 -0
- package/dist/src/terminal-command-foreground-proof.js +72 -0
- package/dist/src/terminal-command-foreground-proof.js.map +1 -0
- package/dist/src/terminal-command-send-preflight.d.ts +41 -0
- package/dist/src/terminal-command-send-preflight.js +86 -0
- package/dist/src/terminal-command-send-preflight.js.map +1 -0
- package/dist/src/terminal-composer-classifier.d.ts +55 -0
- package/dist/src/terminal-composer-classifier.js +638 -0
- package/dist/src/terminal-composer-classifier.js.map +1 -0
- package/dist/src/terminal-control-ref.d.ts +23 -0
- package/dist/src/terminal-control-ref.js +32 -0
- package/dist/src/terminal-control-ref.js.map +1 -1
- package/dist/src/terminal-dispatch-recovery-authority.d.ts +56 -0
- package/dist/src/terminal-dispatch-recovery-authority.js +251 -0
- package/dist/src/terminal-dispatch-recovery-authority.js.map +1 -0
- package/dist/src/terminal-dispatch-recovery-cli-adapter.d.ts +1 -9
- package/dist/src/terminal-dispatch-recovery-cli-adapter.js +5 -240
- package/dist/src/terminal-dispatch-recovery-cli-adapter.js.map +1 -1
- package/dist/src/terminal-handoff-cli-adapter.d.ts +1 -11
- package/dist/src/terminal-handoff-cli-adapter.js +2 -39
- package/dist/src/terminal-handoff-cli-adapter.js.map +1 -1
- package/dist/src/terminal-human-explicit-send-cli-adapter.d.ts +25 -0
- package/dist/src/terminal-human-explicit-send-cli-adapter.js +903 -0
- package/dist/src/terminal-human-explicit-send-cli-adapter.js.map +1 -0
- package/dist/src/terminal-identity-authority-cli-adapter.d.ts +1 -6
- package/dist/src/terminal-identity-authority-cli-adapter.js +3 -33
- package/dist/src/terminal-identity-authority-cli-adapter.js.map +1 -1
- package/dist/src/terminal-interaction-cli-adapter.js +209 -210
- package/dist/src/terminal-interaction-cli-adapter.js.map +1 -1
- package/dist/src/terminal-interaction-core.d.ts +0 -2
- package/dist/src/terminal-interaction-core.js +4 -3
- package/dist/src/terminal-interaction-core.js.map +1 -1
- package/dist/src/terminal-interaction-protocol.d.ts +21 -0
- package/dist/src/terminal-interaction-protocol.js +74 -0
- package/dist/src/terminal-interaction-protocol.js.map +1 -1
- package/dist/src/terminal-interaction-response-bridge.d.ts +126 -0
- package/dist/src/terminal-interaction-response-bridge.js +579 -0
- package/dist/src/terminal-interaction-response-bridge.js.map +1 -0
- package/dist/src/terminal-interaction-response-transaction.d.ts +44 -0
- package/dist/src/terminal-interaction-response-transaction.js +56 -0
- package/dist/src/terminal-interaction-response-transaction.js.map +1 -0
- package/dist/src/terminal-list-action-policy.d.ts +43 -0
- package/dist/src/terminal-list-action-policy.js +164 -0
- package/dist/src/terminal-list-action-policy.js.map +1 -0
- package/dist/src/terminal-list-cli-adapter.d.ts +6 -36
- package/dist/src/terminal-list-cli-adapter.js +314 -1711
- package/dist/src/terminal-list-cli-adapter.js.map +1 -1
- package/dist/src/terminal-list-facts.d.ts +129 -0
- package/dist/src/terminal-list-facts.js +179 -0
- package/dist/src/terminal-list-facts.js.map +1 -0
- package/dist/src/terminal-list-inventory.d.ts +59 -0
- package/dist/src/terminal-list-inventory.js +194 -0
- package/dist/src/terminal-list-inventory.js.map +1 -0
- package/dist/src/terminal-list-ownership-service.d.ts +118 -0
- package/dist/src/terminal-list-ownership-service.js +1003 -0
- package/dist/src/terminal-list-ownership-service.js.map +1 -0
- package/dist/src/terminal-list-projection-service.d.ts +49 -0
- package/dist/src/terminal-list-projection-service.js +407 -0
- package/dist/src/terminal-list-projection-service.js.map +1 -0
- package/dist/src/terminal-list-renderer.d.ts +12 -11
- package/dist/src/terminal-list-renderer.js +237 -104
- package/dist/src/terminal-list-renderer.js.map +1 -1
- package/dist/src/terminal-managed-send-cli-adapter.d.ts +33 -0
- package/dist/src/terminal-managed-send-cli-adapter.js +994 -0
- package/dist/src/terminal-managed-send-cli-adapter.js.map +1 -0
- package/dist/src/terminal-managed-turn-list-action-policy.d.ts +47 -0
- package/dist/src/terminal-managed-turn-list-action-policy.js +64 -0
- package/dist/src/terminal-managed-turn-list-action-policy.js.map +1 -0
- package/dist/src/terminal-model-control-action-policy.d.ts +60 -0
- package/dist/src/terminal-model-control-action-policy.js +96 -0
- package/dist/src/terminal-model-control-action-policy.js.map +1 -0
- package/dist/src/terminal-model-control-availability.d.ts +68 -0
- package/dist/src/terminal-model-control-availability.js +157 -0
- package/dist/src/terminal-model-control-availability.js.map +1 -0
- package/dist/src/terminal-model-control-bridge.d.ts +48 -0
- package/dist/src/terminal-model-control-bridge.js +259 -0
- package/dist/src/terminal-model-control-bridge.js.map +1 -0
- package/dist/src/terminal-model-control-profile.d.ts +55 -0
- package/dist/src/terminal-model-control-profile.js +137 -0
- package/dist/src/terminal-model-control-profile.js.map +1 -0
- package/dist/src/terminal-model-control-subject.d.ts +34 -0
- package/dist/src/terminal-model-control-subject.js +58 -0
- package/dist/src/terminal-model-control-subject.js.map +1 -0
- package/dist/src/terminal-model-control-transaction.d.ts +19 -0
- package/dist/src/terminal-model-control-transaction.js +39 -0
- package/dist/src/terminal-model-control-transaction.js.map +1 -0
- package/dist/src/terminal-model-control.d.ts +331 -0
- package/dist/src/terminal-model-control.js +1686 -0
- package/dist/src/terminal-model-control.js.map +1 -0
- package/dist/src/terminal-monitor-application-service.js +50 -17
- package/dist/src/terminal-monitor-application-service.js.map +1 -1
- package/dist/src/terminal-native-inspection-bridge.d.ts +211 -0
- package/dist/src/terminal-native-inspection-bridge.js +1127 -0
- package/dist/src/terminal-native-inspection-bridge.js.map +1 -0
- package/dist/src/terminal-runtime-cli-adapter.d.ts +2 -0
- package/dist/src/terminal-runtime-cli-adapter.js +59 -17
- package/dist/src/terminal-runtime-cli-adapter.js.map +1 -1
- package/dist/src/terminal-submission-retry-application.d.ts +24 -0
- package/dist/src/terminal-submission-retry-application.js +402 -0
- package/dist/src/terminal-submission-retry-application.js.map +1 -0
- package/dist/src/terminal-submission-retry-ports.d.ts +30 -0
- package/dist/src/terminal-submission-retry-ports.js +2 -0
- package/dist/src/terminal-submission-retry-ports.js.map +1 -0
- package/dist/src/terminal-submission-retry-reconciliation.d.ts +236 -0
- package/dist/src/terminal-submission-retry-reconciliation.js +1130 -0
- package/dist/src/terminal-submission-retry-reconciliation.js.map +1 -0
- package/dist/src/terminal-submission-retry-transport.d.ts +58 -0
- package/dist/src/terminal-submission-retry-transport.js +675 -0
- package/dist/src/terminal-submission-retry-transport.js.map +1 -0
- package/dist/src/terminal-text-submission-bridge.d.ts +200 -0
- package/dist/src/terminal-text-submission-bridge.js +632 -0
- package/dist/src/terminal-text-submission-bridge.js.map +1 -0
- package/dist/src/terminal-user-explicit-send-policy.d.ts +29 -0
- package/dist/src/terminal-user-explicit-send-policy.js +46 -0
- package/dist/src/terminal-user-explicit-send-policy.js.map +1 -0
- package/dist/src/terminal-watch-cli-adapter.js +91 -143
- package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
- package/dist/src/terminal-watch-codec.d.ts +9 -0
- package/dist/src/terminal-watch-codec.js +1051 -0
- package/dist/src/terminal-watch-codec.js.map +1 -0
- package/dist/src/terminal-watch-interaction-response-store.d.ts +19 -0
- package/dist/src/terminal-watch-interaction-response-store.js +87 -0
- package/dist/src/terminal-watch-interaction-response-store.js.map +1 -0
- package/dist/src/terminal-watch-record.d.ts +319 -0
- package/dist/src/terminal-watch-record.js +742 -0
- package/dist/src/terminal-watch-record.js.map +1 -0
- package/dist/src/terminal-watch-service.js +48 -27
- package/dist/src/terminal-watch-service.js.map +1 -1
- package/dist/src/terminal-watch-store.d.ts +3 -279
- package/dist/src/terminal-watch-store.js +5 -1779
- package/dist/src/terminal-watch-store.js.map +1 -1
- package/docs/quickstart-herdr.md +1 -1
- package/docs/quickstart-tmux.md +27 -2
- package/openclaw.plugin.json +13 -1
- package/package.json +7 -2
- package/templates/openclaw-skills/agent-knock-knock/SKILL.md +54 -11
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { callbackDeliveryAttemptOutcome, supersedeUnacceptedCallbackDeliveries } from "./callback-outbox-policy.js";
|
|
4
|
+
import { captureCodexCandidateSetRolloutAcceptanceAnchor } from "./terminal-submission-acceptance.js";
|
|
5
|
+
import { fingerprint } from "./terminal-submission-facts.js";
|
|
6
|
+
import { listDeferredForegroundTransfers } from "./deferred-foreground-transfer.js";
|
|
7
|
+
import { isFinalDeferredForegroundTransferStatus } from "./deferred-foreground-transfer-policy.js";
|
|
8
|
+
import { humanExplicitCallbackDebtDisposition, humanExplicitCallbackDebtManagedTokenMatches, humanExplicitCallbackDebtRetirementDisposition } from "./deferred-foreground-authority-cli-adapter.js";
|
|
9
|
+
import { executorForConversation, sessionIdForConversation, turnIdForConversation } from "./protocol.js";
|
|
10
|
+
import { appendEvent, ensureDir, ensureStoreWritable, listConversations, loadState, pathsForConversation, saveState } from "./store.js";
|
|
11
|
+
import { createManagedSessionId, managedSessionBindingToken, managedSessionRevision } from "./managed-session.js";
|
|
12
|
+
import { listManagedSessions, listNativeThreadTransitions, loadManagedSession, saveManagedSession, tryLoadManagedSession } from "./session-store.js";
|
|
13
|
+
import { rolloutFileIdentityMatches } from "./terminal-binding-authority.js";
|
|
14
|
+
import { codexCompanionsPresentInOpenRootInventory, exactBoundCodexSendSource, isCompleteNativeRollout, nativeIdentityMatchesCodexPreMaterialization, terminalControlAliasMatches } from "./terminal-authority-policy.js";
|
|
15
|
+
import { decideTerminalSendAuthority } from "./terminal-action-projection.js";
|
|
16
|
+
import { withCanonicalMutationLocks } from "./mutation-transaction.js";
|
|
17
|
+
import { assertTerminalDispatchRouteMatches, withExactTerminalDispatchRoute } from "./terminal-dispatch-capability.js";
|
|
18
|
+
import { bindDeferredForegroundApplicationScope, bindDeferredForegroundWriterScope } from "./deferred-foreground-capability.js";
|
|
19
|
+
import { deferredForegroundBoundaryProjection } from "./deferred-foreground-preparation-cli-adapter.js";
|
|
20
|
+
import { assertFreshUserExplicitTerminalSendTargetWhileLocked, assertFreshUserExplicitTerminalSendToken } from "./terminal-human-explicit-send-cli-adapter.js";
|
|
21
|
+
import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
|
|
22
|
+
const managedSendContext = new AsyncLocalStorage();
|
|
23
|
+
function managedSendRuntime() {
|
|
24
|
+
const runtime = managedSendContext.getStore();
|
|
25
|
+
if (!runtime) {
|
|
26
|
+
throw new Error("Terminal managed Send runtime is unavailable");
|
|
27
|
+
}
|
|
28
|
+
return runtime;
|
|
29
|
+
}
|
|
30
|
+
function rawPort(name) {
|
|
31
|
+
return ((...arguments_) => {
|
|
32
|
+
const operation = managedSendRuntime().ports[name];
|
|
33
|
+
return operation(...arguments_);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const assertExpectedHandoffTokenUsesExactTerminalSelector = rawPort("assertExpectedHandoffTokenUsesExactTerminalSelector");
|
|
37
|
+
const assertManagedSessionCanStartTurn = rawPort("assertManagedSessionCanStartTurn");
|
|
38
|
+
const assertNativeThreadHasExclusiveOwnership = rawPort("assertNativeThreadHasExclusiveOwnership");
|
|
39
|
+
const bindingMatchesLiveTerminal = rawPort("bindingMatchesLiveTerminal");
|
|
40
|
+
const codexAllowedCompanionSetForManagedSession = rawPort("codexAllowedCompanionSetForManagedSession");
|
|
41
|
+
const codexPreMaterializationIdentityForManagedSession = rawPort("codexPreMaterializationIdentityForManagedSession");
|
|
42
|
+
const createBoundManagedSession = rawPort("createBoundManagedSession");
|
|
43
|
+
const createManagedTerminalTurn = rawPort("createManagedTerminalTurn");
|
|
44
|
+
const createTerminalAgentBridge = rawPort("createTerminalAgentBridge");
|
|
45
|
+
const deferredForegroundApplication = rawPort("deferredForegroundApplication");
|
|
46
|
+
const identifyCodexForegroundWhileLocked = rawPort("identifyCodexForegroundWhileLocked");
|
|
47
|
+
const inspectCodexOpenRootRolloutInventory = rawPort("inspectCodexOpenRootRolloutInventory");
|
|
48
|
+
const isDiscoverableTmuxConversation = rawPort("isDiscoverableTmuxConversation");
|
|
49
|
+
const logicalIdentityForManagedSession = rawPort("logicalIdentityForManagedSession");
|
|
50
|
+
const managedTurnsForSession = rawPort("managedTurnsForSession");
|
|
51
|
+
const materializeCurrentManagedSession = rawPort("materializeCurrentManagedSession");
|
|
52
|
+
const maybeAdoptObservedExternalThread = rawPort("maybeAdoptObservedExternalThread");
|
|
53
|
+
const maybeDetachVerifiedEmptyCodexSource = rawPort("maybeDetachVerifiedEmptyCodexSource");
|
|
54
|
+
const observeCurrentNativeAgentSessionIdentity = rawPort("observeCurrentNativeAgentSessionIdentity");
|
|
55
|
+
const prepareDeferredCodexForegroundBinding = rawPort("prepareDeferredCodexForegroundBinding");
|
|
56
|
+
const reattachManagedSessionForNativeIdentity = rawPort("reattachManagedSessionForNativeIdentity");
|
|
57
|
+
const refineManagedSessionNativeIdentity = rawPort("refineManagedSessionNativeIdentity");
|
|
58
|
+
const required = rawPort("required");
|
|
59
|
+
const resolveCurrentNativeAgentSessionIdentity = rawPort("resolveCurrentNativeAgentSessionIdentity");
|
|
60
|
+
const soleBoundManagedSessionClaimForTerminal = rawPort("soleBoundManagedSessionClaimForTerminal");
|
|
61
|
+
const storeDirFromOptions = rawPort("storeDirFromOptions");
|
|
62
|
+
const terminalBridgeRuntimeKey = rawPort("terminalBridgeRuntimeKey");
|
|
63
|
+
const terminalControlFromTakeover = rawPort("terminalControlFromTakeover");
|
|
64
|
+
const terminalWriterMutationLocks = rawPort("terminalWriterMutationLocks");
|
|
65
|
+
const verifyCodexPendingManagedSendStatus = rawPort("verifyCodexPendingManagedSendStatus");
|
|
66
|
+
const withTerminalDispatchStateScope = rawPort("withTerminalDispatchStateScope");
|
|
67
|
+
const mutationDispatchLedger = new Proxy({}, {
|
|
68
|
+
get: (_target, property) => managedSendRuntime().ports.mutationDispatchLedger[property]
|
|
69
|
+
});
|
|
70
|
+
const terminalListCliFacade = new Proxy({}, {
|
|
71
|
+
get: (_target, property) => managedSendRuntime().ports.terminalList[property]
|
|
72
|
+
});
|
|
73
|
+
const foregroundIdentificationAuthority = new Proxy({}, {
|
|
74
|
+
get: (_target, property) => managedSendRuntime().foregroundIdentificationAuthority[property]
|
|
75
|
+
});
|
|
76
|
+
const cliNow = () => managedSendRuntime().runtime.now();
|
|
77
|
+
const replayExactActiveTerminalSubmission = (input) => managedSendRuntime().replayExactActiveTerminalSubmission(input);
|
|
78
|
+
const runTerminalControlSend = (request) => managedSendRuntime().runTerminalControlSend(request);
|
|
79
|
+
const USER_EXPLICIT_MANAGED_LOCK_GRACE_MS = 1_000;
|
|
80
|
+
function captureDetachedCodexCandidateSessionClaims(input) {
|
|
81
|
+
const { inventory, terminal } = input;
|
|
82
|
+
const candidates = new Map(inventory.roots.map((root) => [
|
|
83
|
+
root.sessionId.toLowerCase(),
|
|
84
|
+
root
|
|
85
|
+
]));
|
|
86
|
+
const claims = listManagedSessions(input.storeDir).flatMap((session) => {
|
|
87
|
+
const binding = session.binding;
|
|
88
|
+
const nativeThreadId = binding?.native_thread_id?.toLowerCase();
|
|
89
|
+
const candidate = nativeThreadId ? candidates.get(nativeThreadId) : undefined;
|
|
90
|
+
if (session.status !== "detached" || session.agent !== "codex" ||
|
|
91
|
+
!binding || !nativeThreadId || !candidate ||
|
|
92
|
+
!isCompleteNativeRollout(binding.native_process.rollout) ||
|
|
93
|
+
path.resolve(session.workspace) !==
|
|
94
|
+
path.resolve(terminal.terminalControl.currentPath ?? "") ||
|
|
95
|
+
binding.native_process.pid !== inventory.pid ||
|
|
96
|
+
binding.native_process.process_uuid !== inventory.processUuid ||
|
|
97
|
+
binding.native_process.process_birth !== inventory.processBirth ||
|
|
98
|
+
candidate.processUuid !== inventory.processUuid ||
|
|
99
|
+
candidate.processBirth !== inventory.processBirth ||
|
|
100
|
+
!terminalControlAliasMatches(binding.terminal_id, binding.terminal_control, terminal.conversationId, terminal.terminalControl) ||
|
|
101
|
+
!rolloutFileIdentityMatches(binding.native_process.rollout, candidate.rollout)) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
return [{
|
|
105
|
+
session_id: session.session_id,
|
|
106
|
+
session_revision: managedSessionRevision(session),
|
|
107
|
+
session_binding_token: managedSessionBindingToken(session),
|
|
108
|
+
binding_id: binding.binding_id,
|
|
109
|
+
binding_generation: binding.generation,
|
|
110
|
+
native_thread_id: nativeThreadId,
|
|
111
|
+
process_uuid: inventory.processUuid,
|
|
112
|
+
process_birth: inventory.processBirth,
|
|
113
|
+
source_rollout: { ...binding.native_process.rollout },
|
|
114
|
+
candidate_rollout: { ...candidate.rollout }
|
|
115
|
+
}];
|
|
116
|
+
}).sort((left, right) => left.native_thread_id.localeCompare(right.native_thread_id) ||
|
|
117
|
+
left.session_id.localeCompare(right.session_id));
|
|
118
|
+
if (claims.length === 0)
|
|
119
|
+
return undefined;
|
|
120
|
+
const base = {
|
|
121
|
+
schema: "agent-knock-knock/codex-detached-candidate-session-claims",
|
|
122
|
+
version: 1,
|
|
123
|
+
anchor_fingerprint: input.anchor.anchor_fingerprint,
|
|
124
|
+
claims
|
|
125
|
+
};
|
|
126
|
+
return { ...base, claims_fingerprint: fingerprint(base) };
|
|
127
|
+
}
|
|
128
|
+
function rawTerminalInitialAuthority({ options, terminal, storeDir }) {
|
|
129
|
+
const claimedSession = soleBoundManagedSessionClaimForTerminal(storeDir, terminal);
|
|
130
|
+
const suppliedExpectedTerminalToken = stringValue(options.expectedTerminalToken);
|
|
131
|
+
const implicitCodexCandidateAuthority = Boolean(terminal.agent === "codex" &&
|
|
132
|
+
suppliedExpectedTerminalToken === undefined &&
|
|
133
|
+
claimedSession?.status === "bound" &&
|
|
134
|
+
isCompleteNativeRollout(claimedSession.binding?.native_process.rollout));
|
|
135
|
+
const knownCodexCompanions = claimedSession
|
|
136
|
+
? codexAllowedCompanionSetForManagedSession({
|
|
137
|
+
storeDir,
|
|
138
|
+
session: claimedSession
|
|
139
|
+
})
|
|
140
|
+
: { additional: [] };
|
|
141
|
+
return {
|
|
142
|
+
claimedSession,
|
|
143
|
+
suppliedExpectedTerminalToken,
|
|
144
|
+
implicitCodexCandidateAuthority,
|
|
145
|
+
knownCodexCompanions
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function assertRawTerminalCandidateAuthority({ terminal, nativeIdentityObservation, deferredCodexCandidateInventory, implicitCodexCandidateAuthority }) {
|
|
149
|
+
if (implicitCodexCandidateAuthority &&
|
|
150
|
+
!deferredCodexCandidateInventory) {
|
|
151
|
+
throw new Error("rollout-backed Codex terminal send requires a fresh complete " +
|
|
152
|
+
"nonempty open-root inventory; refresh AKK list before sending");
|
|
153
|
+
}
|
|
154
|
+
if (nativeIdentityObservation.status === "unavailable" &&
|
|
155
|
+
!deferredCodexCandidateInventory) {
|
|
156
|
+
throw new Error(`native ${terminal.agent} identity observation is ` +
|
|
157
|
+
`unavailable: ${nativeIdentityObservation.reason}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const USER_EXPLICIT_CALLBACK_SUPERSEDE_REASON = "superseded_by_user_explicit_send";
|
|
161
|
+
function sessionHasUnresolvedForegroundMutation(storeDir, sessionId) {
|
|
162
|
+
try {
|
|
163
|
+
if (listNativeThreadTransitions(storeDir).some((transition) => (transition.source_session_id === sessionId ||
|
|
164
|
+
transition.target_session_id === sessionId) &&
|
|
165
|
+
!["committed", "aborted"].includes(transition.status))) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
return listDeferredForegroundTransfers(storeDir).some((transfer) => (transfer.source_session_id === sessionId ||
|
|
169
|
+
transfer.target_session_id === sessionId) &&
|
|
170
|
+
!isFinalDeferredForegroundTransferStatus(transfer.status));
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Corrupt or unreadable lifecycle evidence must never be bypassed.
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function supersedeExactHumanExplicitCallbackDebt(input) {
|
|
178
|
+
const { options, terminal, session, candidateInventory, storeDir, scopes, resources } = input;
|
|
179
|
+
const expectedManagedToken = stringValue(options.expectedTerminalToken);
|
|
180
|
+
const binding = session?.binding;
|
|
181
|
+
if (terminal.agent !== "codex" ||
|
|
182
|
+
stringValue(options.expectedUserExplicitTerminalToken) === undefined ||
|
|
183
|
+
!session ||
|
|
184
|
+
session.status !== "bound" ||
|
|
185
|
+
!binding ||
|
|
186
|
+
!humanExplicitCallbackDebtManagedTokenMatches(expectedManagedToken, session) ||
|
|
187
|
+
!candidateInventory ||
|
|
188
|
+
!exactBoundCodexSendSource({
|
|
189
|
+
kind: "candidate",
|
|
190
|
+
sourceSession: session,
|
|
191
|
+
context: {
|
|
192
|
+
terminalId: terminal.conversationId,
|
|
193
|
+
terminalControl: terminal.terminalControl,
|
|
194
|
+
pid: terminal.pid,
|
|
195
|
+
workspace: terminal.terminalControl.currentPath,
|
|
196
|
+
liveProcessUuid: candidateInventory.processUuid,
|
|
197
|
+
liveProcessBirth: candidateInventory.processBirth
|
|
198
|
+
},
|
|
199
|
+
inventory: candidateInventory,
|
|
200
|
+
sourceRolloutAuthority: "present"
|
|
201
|
+
}) ||
|
|
202
|
+
sessionHasUnresolvedForegroundMutation(storeDir, session.session_id)) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
const bindingTurns = managedTurnsForSession(storeDir, session.session_id)
|
|
206
|
+
.filter((turn) => turn.terminal_binding_id === binding.binding_id &&
|
|
207
|
+
turn.terminal_binding_generation === binding.generation);
|
|
208
|
+
const dispositions = bindingTurns.map((turn) => ({
|
|
209
|
+
turn,
|
|
210
|
+
disposition: humanExplicitCallbackDebtRetirementDisposition(turn, session)
|
|
211
|
+
}));
|
|
212
|
+
const candidates = dispositions
|
|
213
|
+
.filter(({ disposition }) => disposition === "supersedable")
|
|
214
|
+
.map(({ turn }) => turn);
|
|
215
|
+
if (candidates.length === 0 ||
|
|
216
|
+
dispositions.some(({ disposition }) => disposition === undefined)) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
let superseded = 0;
|
|
220
|
+
for (const candidate of candidates) {
|
|
221
|
+
const paths = pathsForConversation(candidate.conversation_id, storeDir);
|
|
222
|
+
const expectedDelivery = JSON.stringify(candidate.callback_delivery);
|
|
223
|
+
await withTerminalDispatchStateScope(scopes, resources, paths.statePath, paths.logPath, async () => {
|
|
224
|
+
const current = loadState(paths.statePath);
|
|
225
|
+
if (JSON.stringify(current.callback_delivery) !== expectedDelivery ||
|
|
226
|
+
humanExplicitCallbackDebtDisposition(current, session) !==
|
|
227
|
+
"supersedable") {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const at = cliNow().toISOString();
|
|
231
|
+
const next = supersedeUnacceptedCallbackDeliveries(current, {
|
|
232
|
+
at,
|
|
233
|
+
reason: USER_EXPLICIT_CALLBACK_SUPERSEDE_REASON
|
|
234
|
+
});
|
|
235
|
+
if (next.callback_delivery === current.callback_delivery)
|
|
236
|
+
return;
|
|
237
|
+
saveState(paths.statePath, next);
|
|
238
|
+
appendEvent(paths.logPath, {
|
|
239
|
+
ts: at,
|
|
240
|
+
conversation_id: current.conversation_id,
|
|
241
|
+
event: "callback_delivery_superseded_by_user_explicit_send",
|
|
242
|
+
status: current.status,
|
|
243
|
+
reason: USER_EXPLICIT_CALLBACK_SUPERSEDE_REASON,
|
|
244
|
+
prior_callback_status: isRecord(current.callback_delivery)
|
|
245
|
+
? current.callback_delivery.status
|
|
246
|
+
: undefined,
|
|
247
|
+
prior_callback_attempt_disposition: callbackDeliveryAttemptOutcome(current.callback_delivery)
|
|
248
|
+
?.disposition,
|
|
249
|
+
// An uncertain transport may already have reached the controller.
|
|
250
|
+
// This records that the human-priority Send retired only future
|
|
251
|
+
// callback retries; it never asserts that delivery did not occur.
|
|
252
|
+
human_override_of_uncertain_callback: callbackDeliveryAttemptOutcome(current.callback_delivery)
|
|
253
|
+
?.disposition === "uncertain",
|
|
254
|
+
terminal_input_sent: false,
|
|
255
|
+
terminal_input_dispatched: false
|
|
256
|
+
});
|
|
257
|
+
superseded += 1;
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
return superseded === candidates.length;
|
|
261
|
+
}
|
|
262
|
+
function rawTerminalObservedIdentityForPreparation(input) {
|
|
263
|
+
if (input.atomicForegroundIdentification ||
|
|
264
|
+
input.sourceLessCandidateInventory !== undefined ||
|
|
265
|
+
input.observation.status !== "resolved") {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
return input.observation.identity;
|
|
269
|
+
}
|
|
270
|
+
async function maybePrepareVerifiedEmptyCodexHandoff(input) {
|
|
271
|
+
if (input.implicitCandidateAuthority ||
|
|
272
|
+
input.atomicForegroundIdentification) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
return maybeDetachVerifiedEmptyCodexSource({
|
|
276
|
+
options: input.options,
|
|
277
|
+
terminal: input.terminal,
|
|
278
|
+
sourceSession: input.sourceSession,
|
|
279
|
+
observation: input.observation
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function assertAtomicForegroundCandidateInventory(input) {
|
|
283
|
+
if (!input.enabled || input.claimedSession === undefined)
|
|
284
|
+
return;
|
|
285
|
+
if (input.inventory && input.inventory.roots.length > 0)
|
|
286
|
+
return;
|
|
287
|
+
throw new Error("atomic foreground identification requires a fresh nonempty " +
|
|
288
|
+
"candidate-set acceptance boundary; no task input was sent");
|
|
289
|
+
}
|
|
290
|
+
function assertAtomicForegroundAcceptanceBoundary(input) {
|
|
291
|
+
if (!input.enabled)
|
|
292
|
+
return;
|
|
293
|
+
if (input.deferred?.candidateAcceptanceAnchor || input.postSend)
|
|
294
|
+
return;
|
|
295
|
+
throw new Error("atomic foreground identification could not establish an exact " +
|
|
296
|
+
"task-acceptance boundary; no task input was sent");
|
|
297
|
+
}
|
|
298
|
+
async function prepareRawTerminalDispatchAuthority(input) {
|
|
299
|
+
const { options, messageBody, terminal, storeDir, scopes, resources } = input;
|
|
300
|
+
const atomicForegroundIdentification = options.identifyForeground === true;
|
|
301
|
+
const initialAuthority = rawTerminalInitialAuthority({
|
|
302
|
+
options,
|
|
303
|
+
terminal,
|
|
304
|
+
storeDir
|
|
305
|
+
});
|
|
306
|
+
let { claimedSession, knownCodexCompanions } = initialAuthority;
|
|
307
|
+
const { suppliedExpectedTerminalToken, implicitCodexCandidateAuthority } = initialAuthority;
|
|
308
|
+
const userExplicitTerminalToken = stringValue(options.expectedUserExplicitTerminalToken);
|
|
309
|
+
const nativeIdentityObservation = await observeCurrentNativeAgentSessionIdentity({
|
|
310
|
+
options,
|
|
311
|
+
agent: terminal.agent,
|
|
312
|
+
pid: terminal.pid,
|
|
313
|
+
cwd: terminal.terminalControl.currentPath,
|
|
314
|
+
preferredSessionId: knownCodexCompanions.primary
|
|
315
|
+
? claimedSession?.binding?.native_thread_id
|
|
316
|
+
: undefined,
|
|
317
|
+
allowedCompanionIdentity: knownCodexCompanions.primary,
|
|
318
|
+
allowedAdditionalIdentities: knownCodexCompanions.additional
|
|
319
|
+
});
|
|
320
|
+
let deferredCodexCandidateInventory;
|
|
321
|
+
if (terminal.agent === "codex" &&
|
|
322
|
+
(userExplicitTerminalToken ||
|
|
323
|
+
suppliedExpectedTerminalToken ||
|
|
324
|
+
implicitCodexCandidateAuthority)) {
|
|
325
|
+
try {
|
|
326
|
+
const inventory = await inspectCodexOpenRootRolloutInventory({
|
|
327
|
+
options,
|
|
328
|
+
pid: terminal.pid,
|
|
329
|
+
cwd: terminal.terminalControl.currentPath
|
|
330
|
+
});
|
|
331
|
+
// An empty set is meaningful only for a source-less human Send: it is
|
|
332
|
+
// the frozen proof that the first accepting rollout must appear after
|
|
333
|
+
// Enter. Preserve the older bound/deferred behavior otherwise.
|
|
334
|
+
if (inventory.roots.length > 0 ||
|
|
335
|
+
(userExplicitTerminalToken !== undefined && claimedSession === undefined)) {
|
|
336
|
+
deferredCodexCandidateInventory = inventory;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
if ((userExplicitTerminalToken !== undefined &&
|
|
341
|
+
claimedSession === undefined) ||
|
|
342
|
+
implicitCodexCandidateAuthority ||
|
|
343
|
+
nativeIdentityObservation.status === "unavailable") {
|
|
344
|
+
throw new Error(`native Codex foreground attribution requires a fresh complete ` +
|
|
345
|
+
`open-root inventory: ${error instanceof Error ? error.message : String(error)}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
assertRawTerminalCandidateAuthority({
|
|
350
|
+
terminal,
|
|
351
|
+
nativeIdentityObservation,
|
|
352
|
+
deferredCodexCandidateInventory,
|
|
353
|
+
implicitCodexCandidateAuthority
|
|
354
|
+
});
|
|
355
|
+
const sourceLessCodexCandidateInventory = terminal.agent === "codex" &&
|
|
356
|
+
userExplicitTerminalToken !== undefined &&
|
|
357
|
+
claimedSession === undefined
|
|
358
|
+
? deferredCodexCandidateInventory
|
|
359
|
+
: undefined;
|
|
360
|
+
let currentNativeIdentity = rawTerminalObservedIdentityForPreparation({
|
|
361
|
+
atomicForegroundIdentification,
|
|
362
|
+
sourceLessCandidateInventory: sourceLessCodexCandidateInventory,
|
|
363
|
+
observation: nativeIdentityObservation
|
|
364
|
+
});
|
|
365
|
+
// A fresh nonempty inventory is the stronger physical authority for an
|
|
366
|
+
// implicit candidate send. Do not let an earlier verified-absent
|
|
367
|
+
// observation divert this path into the token-only empty handoff.
|
|
368
|
+
const verifiedEmptyHandoff = await maybePrepareVerifiedEmptyCodexHandoff({
|
|
369
|
+
options,
|
|
370
|
+
terminal,
|
|
371
|
+
sourceSession: claimedSession,
|
|
372
|
+
observation: nativeIdentityObservation,
|
|
373
|
+
implicitCandidateAuthority: implicitCodexCandidateAuthority,
|
|
374
|
+
atomicForegroundIdentification
|
|
375
|
+
});
|
|
376
|
+
if (verifiedEmptyHandoff) {
|
|
377
|
+
// The old rollout is conclusively closed. Never carry it forward as a
|
|
378
|
+
// pre-materialization companion for the new virgin Session.
|
|
379
|
+
claimedSession = undefined;
|
|
380
|
+
knownCodexCompanions = { additional: [] };
|
|
381
|
+
currentNativeIdentity = undefined;
|
|
382
|
+
}
|
|
383
|
+
const physicalNativeIdentityBeforeHandoff = currentNativeIdentity;
|
|
384
|
+
// The status card emitted by identify_foreground is diagnostic evidence,
|
|
385
|
+
// never handoff authority. Let the existing candidate-set/deferred path
|
|
386
|
+
// bind only the rollout that later accepts the exact task request.
|
|
387
|
+
let handoff = atomicForegroundIdentification
|
|
388
|
+
? { identity: undefined, adopted: false }
|
|
389
|
+
: await maybeAdoptObservedExternalThread({
|
|
390
|
+
options,
|
|
391
|
+
terminal,
|
|
392
|
+
// A no-token raw send to an already managed rollout-backed Codex pane
|
|
393
|
+
// is an internal follow-current delegation, not a sole-root
|
|
394
|
+
// continuation.
|
|
395
|
+
sourceSession: implicitCodexCandidateAuthority
|
|
396
|
+
? undefined
|
|
397
|
+
: claimedSession,
|
|
398
|
+
resolvedIdentity: sourceLessCodexCandidateInventory
|
|
399
|
+
? undefined
|
|
400
|
+
: currentNativeIdentity,
|
|
401
|
+
storeDir
|
|
402
|
+
});
|
|
403
|
+
currentNativeIdentity =
|
|
404
|
+
handoff.adopted && terminal.agent === "codex" &&
|
|
405
|
+
!handoff.session?.binding?.native_process.rollout
|
|
406
|
+
? physicalNativeIdentityBeforeHandoff
|
|
407
|
+
: handoff.identity;
|
|
408
|
+
if (!handoff.adopted) {
|
|
409
|
+
await supersedeExactHumanExplicitCallbackDebt({
|
|
410
|
+
options,
|
|
411
|
+
terminal,
|
|
412
|
+
session: claimedSession,
|
|
413
|
+
candidateInventory: deferredCodexCandidateInventory,
|
|
414
|
+
storeDir,
|
|
415
|
+
scopes,
|
|
416
|
+
resources
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
assertAtomicForegroundCandidateInventory({
|
|
420
|
+
enabled: atomicForegroundIdentification,
|
|
421
|
+
claimedSession,
|
|
422
|
+
inventory: deferredCodexCandidateInventory
|
|
423
|
+
});
|
|
424
|
+
const deferredCodexForegroundBinding = !handoff.adopted
|
|
425
|
+
? await prepareDeferredCodexForegroundBinding({
|
|
426
|
+
options,
|
|
427
|
+
scope: bindDeferredForegroundWriterScope(scopes, resources),
|
|
428
|
+
terminal,
|
|
429
|
+
sourceSession: claimedSession,
|
|
430
|
+
observation: nativeIdentityObservation,
|
|
431
|
+
candidateInventory: deferredCodexCandidateInventory,
|
|
432
|
+
requestText: String(messageBody),
|
|
433
|
+
allowImplicitFreshAuthority: implicitCodexCandidateAuthority
|
|
434
|
+
})
|
|
435
|
+
: undefined;
|
|
436
|
+
const postSendCodexCandidateAnchor = terminal.agent === "codex" &&
|
|
437
|
+
userExplicitTerminalToken !== undefined &&
|
|
438
|
+
sourceLessCodexCandidateInventory !== undefined &&
|
|
439
|
+
verifiedEmptyHandoff === undefined &&
|
|
440
|
+
!handoff.adopted &&
|
|
441
|
+
deferredCodexForegroundBinding === undefined &&
|
|
442
|
+
claimedSession === undefined
|
|
443
|
+
? captureCodexCandidateSetRolloutAcceptanceAnchor({
|
|
444
|
+
inventory: sourceLessCodexCandidateInventory,
|
|
445
|
+
now: cliNow()
|
|
446
|
+
})
|
|
447
|
+
: undefined;
|
|
448
|
+
const postSendCodexDetachedSessionClaims = postSendCodexCandidateAnchor &&
|
|
449
|
+
sourceLessCodexCandidateInventory
|
|
450
|
+
? captureDetachedCodexCandidateSessionClaims({
|
|
451
|
+
storeDir,
|
|
452
|
+
terminal,
|
|
453
|
+
inventory: sourceLessCodexCandidateInventory,
|
|
454
|
+
anchor: postSendCodexCandidateAnchor
|
|
455
|
+
})
|
|
456
|
+
: undefined;
|
|
457
|
+
assertAtomicForegroundAcceptanceBoundary({
|
|
458
|
+
enabled: atomicForegroundIdentification,
|
|
459
|
+
deferred: deferredCodexForegroundBinding,
|
|
460
|
+
postSend: postSendCodexCandidateAnchor
|
|
461
|
+
});
|
|
462
|
+
const freshSendAuthority = decideTerminalSendAuthority({
|
|
463
|
+
ownership: "conflict",
|
|
464
|
+
verifiedEmpty: Boolean(verifiedEmptyHandoff),
|
|
465
|
+
externalHandoff: handoff.adopted,
|
|
466
|
+
deferred: Boolean(deferredCodexForegroundBinding)
|
|
467
|
+
});
|
|
468
|
+
if (freshSendAuthority.mode === "deferred" &&
|
|
469
|
+
deferredCodexForegroundBinding) {
|
|
470
|
+
claimedSession = undefined;
|
|
471
|
+
knownCodexCompanions = { additional: [] };
|
|
472
|
+
currentNativeIdentity = undefined;
|
|
473
|
+
handoff = { identity: undefined, adopted: false };
|
|
474
|
+
}
|
|
475
|
+
else if ((userExplicitTerminalToken ||
|
|
476
|
+
suppliedExpectedTerminalToken ||
|
|
477
|
+
implicitCodexCandidateAuthority) &&
|
|
478
|
+
!postSendCodexCandidateAnchor &&
|
|
479
|
+
freshSendAuthority.mode === "conflict") {
|
|
480
|
+
throw new Error("managed continuation authority is unavailable for the current " +
|
|
481
|
+
"terminal context" +
|
|
482
|
+
(userExplicitTerminalToken
|
|
483
|
+
? "; the physical terminal authority remains valid"
|
|
484
|
+
: "; refresh AKK list before retrying managed delivery"));
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
nativeIdentityObservation,
|
|
488
|
+
knownCodexCompanions,
|
|
489
|
+
currentNativeIdentity,
|
|
490
|
+
verifiedEmptyHandoff,
|
|
491
|
+
handoff,
|
|
492
|
+
deferredCodexForegroundBinding,
|
|
493
|
+
postSendCodexCandidateAnchor,
|
|
494
|
+
postSendCodexDetachedSessionClaims
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
async function runManagedRawTerminalSendAttemptInContext(options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt) {
|
|
498
|
+
// A token copied from list is authority for exactly the advertised full
|
|
499
|
+
// terminal selector. Reject aliases and implicit/no-selector resolution
|
|
500
|
+
// before taking locks or touching Store state.
|
|
501
|
+
assertExpectedHandoffTokenUsesExactTerminalSelector({
|
|
502
|
+
options,
|
|
503
|
+
terminal: terminalConversation
|
|
504
|
+
});
|
|
505
|
+
if (!options.background) {
|
|
506
|
+
throw new Error("raw terminal sends require --background so AKK can persist and monitor the submission safely");
|
|
507
|
+
}
|
|
508
|
+
const rawStoreDir = storeDirFromOptions(options);
|
|
509
|
+
let controlSendResult;
|
|
510
|
+
const atomicForegroundIdentification = options.identifyForeground === true;
|
|
511
|
+
foregroundIdentificationAuthority.clear(options);
|
|
512
|
+
const userExplicitLockOptions = deferZeroInputFailurePresentation
|
|
513
|
+
? {
|
|
514
|
+
terminalTimeoutMs: 0,
|
|
515
|
+
storeWriterTimeoutMs: USER_EXPLICIT_MANAGED_LOCK_GRACE_MS
|
|
516
|
+
}
|
|
517
|
+
: undefined;
|
|
518
|
+
const lockOptions = atomicForegroundIdentification
|
|
519
|
+
? {
|
|
520
|
+
...userExplicitLockOptions,
|
|
521
|
+
afterTerminalAcquired: async () => {
|
|
522
|
+
const expectedTerminalToken = required(stringValue(options.expectedUserExplicitTerminalToken), "atomic foreground identification requires fresh physical terminal authority");
|
|
523
|
+
const proof = await identifyCodexForegroundWhileLocked({
|
|
524
|
+
options,
|
|
525
|
+
terminal: terminalConversation,
|
|
526
|
+
expectedTerminalToken
|
|
527
|
+
});
|
|
528
|
+
if (proof.terminalId !== terminalConversation.conversationId ||
|
|
529
|
+
proof.pid !== terminalConversation.pid) {
|
|
530
|
+
throw new Error("foreground identification returned evidence for a different terminal");
|
|
531
|
+
}
|
|
532
|
+
foregroundIdentificationAuthority.remember(options, proof);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
: userExplicitLockOptions;
|
|
536
|
+
await withCanonicalMutationLocks(terminalWriterMutationLocks(rawStoreDir, terminalConversation.terminalControl, lockOptions), async (scopes, resources) => {
|
|
537
|
+
await assertFreshUserExplicitTerminalSendTargetWhileLocked(options, terminalConversation);
|
|
538
|
+
await mutationDispatchLedger.beforeMutation(scopes, resources, options, terminalConversation);
|
|
539
|
+
// Upgrade legacy Stores before resolving their Session authority. The
|
|
540
|
+
// protocol migration, rather than mutable Turn recency, is the only code
|
|
541
|
+
// allowed to materialize Session records from existing Turns.
|
|
542
|
+
ensureStoreWritable(rawStoreDir);
|
|
543
|
+
if (replayExactActiveTerminalSubmission({
|
|
544
|
+
options,
|
|
545
|
+
terminalControl: terminalConversation.terminalControl,
|
|
546
|
+
requestText: String(messageBody),
|
|
547
|
+
expectedStoreDir: rawStoreDir,
|
|
548
|
+
expectedMessageType: "task",
|
|
549
|
+
...(stringValue(options.expectedUserExplicitTerminalToken)
|
|
550
|
+
? { userExplicitTerminalId: terminalConversation.conversationId }
|
|
551
|
+
: {})
|
|
552
|
+
})) {
|
|
553
|
+
controlSendResult = { outcome: "replayed" };
|
|
554
|
+
attempt.result = controlSendResult;
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
terminalListCliFacade.assertTerminalIncarnationCanStartTurn(rawStoreDir, terminalConversation.terminalControl);
|
|
558
|
+
const { nativeIdentityObservation, knownCodexCompanions, currentNativeIdentity, verifiedEmptyHandoff, handoff, deferredCodexForegroundBinding, postSendCodexCandidateAnchor, postSendCodexDetachedSessionClaims } = await prepareRawTerminalDispatchAuthority({
|
|
559
|
+
options,
|
|
560
|
+
messageBody,
|
|
561
|
+
terminal: terminalConversation,
|
|
562
|
+
storeDir: rawStoreDir,
|
|
563
|
+
scopes,
|
|
564
|
+
resources
|
|
565
|
+
});
|
|
566
|
+
let managedSession = deferredCodexForegroundBinding
|
|
567
|
+
? undefined
|
|
568
|
+
: handoff.session ??
|
|
569
|
+
materializeCurrentManagedSession({
|
|
570
|
+
options,
|
|
571
|
+
terminal: terminalConversation,
|
|
572
|
+
identity: currentNativeIdentity
|
|
573
|
+
});
|
|
574
|
+
if (!managedSession && currentNativeIdentity) {
|
|
575
|
+
managedSession = await reattachManagedSessionForNativeIdentity({
|
|
576
|
+
options,
|
|
577
|
+
terminal: terminalConversation,
|
|
578
|
+
identity: currentNativeIdentity,
|
|
579
|
+
storeDir: rawStoreDir
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
let pendingRawAttachSessionCreate;
|
|
583
|
+
if (!managedSession) {
|
|
584
|
+
if (currentNativeIdentity) {
|
|
585
|
+
await assertNativeThreadHasExclusiveOwnership({
|
|
586
|
+
options,
|
|
587
|
+
agent: terminalConversation.agent,
|
|
588
|
+
currentPid: terminalConversation.pid,
|
|
589
|
+
nativeThreadId: currentNativeIdentity.sessionId,
|
|
590
|
+
storeDir: rawStoreDir,
|
|
591
|
+
terminalControl: terminalConversation.terminalControl
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
managedSession = createBoundManagedSession({
|
|
595
|
+
sessionId: deferredCodexForegroundBinding?.targetSessionId ??
|
|
596
|
+
createManagedSessionId(),
|
|
597
|
+
terminal: terminalConversation,
|
|
598
|
+
identity: currentNativeIdentity,
|
|
599
|
+
lineage: deferredCodexForegroundBinding
|
|
600
|
+
? {
|
|
601
|
+
created_by: "attach",
|
|
602
|
+
previous_session_id: deferredCodexForegroundBinding.sourceSessionId,
|
|
603
|
+
transition_id: deferredCodexForegroundBinding.transferId
|
|
604
|
+
}
|
|
605
|
+
: { created_by: "attach" }
|
|
606
|
+
});
|
|
607
|
+
if (terminalConversation.agent === "codex" &&
|
|
608
|
+
!currentNativeIdentity) {
|
|
609
|
+
if (deferredCodexForegroundBinding) {
|
|
610
|
+
managedSession = {
|
|
611
|
+
...managedSession,
|
|
612
|
+
// Both endpoints stay fenced from older writers until the
|
|
613
|
+
// dedicated transfer reaches its resolved receipt.
|
|
614
|
+
status: "transitioning",
|
|
615
|
+
last_transition_id: deferredCodexForegroundBinding.transferId
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
pendingRawAttachSessionCreate = managedSession;
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
managedSession = saveManagedSession(rawStoreDir, managedSession, { expectedRevision: null });
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
const logicalNativeIdentity = logicalIdentityForManagedSession({
|
|
625
|
+
storeDir: rawStoreDir,
|
|
626
|
+
session: managedSession,
|
|
627
|
+
observedIdentity: currentNativeIdentity
|
|
628
|
+
});
|
|
629
|
+
const allowedPreMaterializationIdentity = codexPreMaterializationIdentityForManagedSession({
|
|
630
|
+
storeDir: rawStoreDir,
|
|
631
|
+
session: managedSession,
|
|
632
|
+
observedIdentity: currentNativeIdentity
|
|
633
|
+
}) ?? (currentNativeIdentity === undefined ||
|
|
634
|
+
nativeIdentityMatchesCodexPreMaterialization(currentNativeIdentity, knownCodexCompanions.primary)
|
|
635
|
+
? knownCodexCompanions.primary
|
|
636
|
+
: undefined);
|
|
637
|
+
const allowedAdditionalIdentities = allowedPreMaterializationIdentity
|
|
638
|
+
? knownCodexCompanions.additional
|
|
639
|
+
: [];
|
|
640
|
+
const materializedNativeIdentity = currentNativeIdentity?.sessionId === logicalNativeIdentity?.sessionId
|
|
641
|
+
? currentNativeIdentity
|
|
642
|
+
: undefined;
|
|
643
|
+
if (options.identifyForeground !== true && !(handoff.adopted &&
|
|
644
|
+
terminalConversation.agent === "codex" &&
|
|
645
|
+
!managedSession.binding?.native_process.rollout)) {
|
|
646
|
+
await verifyCodexPendingManagedSendStatus({
|
|
647
|
+
options,
|
|
648
|
+
terminal: terminalConversation,
|
|
649
|
+
session: managedSession,
|
|
650
|
+
logicalIdentity: logicalNativeIdentity,
|
|
651
|
+
allowedPreMaterializationIdentity,
|
|
652
|
+
allowedAdditionalIdentities
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
const managedNativeThreadId = logicalNativeIdentity?.sessionId ??
|
|
656
|
+
managedSession.binding?.native_thread_id;
|
|
657
|
+
if (managedNativeThreadId) {
|
|
658
|
+
await assertNativeThreadHasExclusiveOwnership({
|
|
659
|
+
options,
|
|
660
|
+
agent: terminalConversation.agent,
|
|
661
|
+
currentPid: terminalConversation.pid,
|
|
662
|
+
nativeThreadId: managedNativeThreadId,
|
|
663
|
+
storeDir: rawStoreDir,
|
|
664
|
+
terminalControl: terminalConversation.terminalControl,
|
|
665
|
+
excludedManagedSessionId: managedSession.session_id
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
managedSession = refineManagedSessionNativeIdentity({
|
|
669
|
+
storeDir: rawStoreDir,
|
|
670
|
+
session: managedSession,
|
|
671
|
+
terminalControl: terminalConversation.terminalControl,
|
|
672
|
+
identity: logicalNativeIdentity
|
|
673
|
+
});
|
|
674
|
+
const sessionTurns = managedTurnsForSession(rawStoreDir, managedSession.session_id);
|
|
675
|
+
const reusableTurn = sessionTurns[0];
|
|
676
|
+
assertManagedSessionCanStartTurn(sessionTurns);
|
|
677
|
+
const managed = createManagedTerminalTurn({
|
|
678
|
+
options,
|
|
679
|
+
conversationId: terminalConversation.conversationId,
|
|
680
|
+
agent: terminalConversation.agent,
|
|
681
|
+
pid: terminalConversation.pid,
|
|
682
|
+
messageBody,
|
|
683
|
+
terminalControl: terminalConversation.terminalControl,
|
|
684
|
+
previousTurn: reusableTurn,
|
|
685
|
+
managedSession,
|
|
686
|
+
nativeAgentIdentity: materializedNativeIdentity,
|
|
687
|
+
deferredForegroundTransferId: deferredCodexForegroundBinding?.transferId
|
|
688
|
+
});
|
|
689
|
+
ensureStoreWritable(managed.conversation.store_dir);
|
|
690
|
+
ensureDir(path.dirname(managed.statePath));
|
|
691
|
+
await withTerminalDispatchStateScope(scopes, resources, managed.statePath, managed.logPath, async (dispatchScopes, dispatchResources) => {
|
|
692
|
+
attempt.terminalControlSendInvoked = true;
|
|
693
|
+
controlSendResult = await runTerminalControlSend({
|
|
694
|
+
transaction: {
|
|
695
|
+
scopes: dispatchScopes,
|
|
696
|
+
resources: dispatchResources
|
|
697
|
+
},
|
|
698
|
+
options,
|
|
699
|
+
conversation: managed.conversation,
|
|
700
|
+
nextConversation: managed.nextConversation,
|
|
701
|
+
executor: managed.executor,
|
|
702
|
+
message: managed.message,
|
|
703
|
+
recordMessageAfterSend: true,
|
|
704
|
+
recordRawAttachmentAfterSend: reusableTurn === undefined,
|
|
705
|
+
deferZeroInputFailurePresentation,
|
|
706
|
+
onTerminalPreflightVerified: async (route) => {
|
|
707
|
+
assertFreshUserExplicitTerminalSendToken(options, {
|
|
708
|
+
...terminalConversation,
|
|
709
|
+
terminalControl: route.terminalControl
|
|
710
|
+
});
|
|
711
|
+
if (!pendingRawAttachSessionCreate)
|
|
712
|
+
return;
|
|
713
|
+
const exactRoute = withExactTerminalDispatchRoute(route, {
|
|
714
|
+
terminalControl: terminalConversation.terminalControl,
|
|
715
|
+
terminalKey: terminalBridgeRuntimeKey(terminalConversation.terminalControl),
|
|
716
|
+
storeDir: rawStoreDir,
|
|
717
|
+
statePath: managed.statePath,
|
|
718
|
+
logPath: managed.logPath
|
|
719
|
+
}, (boundRoute) => boundRoute);
|
|
720
|
+
let createdSession;
|
|
721
|
+
if (deferredCodexForegroundBinding) {
|
|
722
|
+
const deferredScope = bindDeferredForegroundApplicationScope(dispatchScopes, dispatchResources);
|
|
723
|
+
const reserved = await deferredForegroundApplication(options, deferredCodexForegroundBinding.terminal).reserve({
|
|
724
|
+
scope: deferredScope,
|
|
725
|
+
boundary: deferredForegroundBoundaryProjection(deferredCodexForegroundBinding),
|
|
726
|
+
targetSession: pendingRawAttachSessionCreate,
|
|
727
|
+
messageId: managed.message.id,
|
|
728
|
+
turnId: turnIdForConversation(managed.conversation)
|
|
729
|
+
});
|
|
730
|
+
createdSession = reserved.createdSession;
|
|
731
|
+
managedSession = createdSession;
|
|
732
|
+
pendingRawAttachSessionCreate = undefined;
|
|
733
|
+
return (rollbackRoute) => {
|
|
734
|
+
assertTerminalDispatchRouteMatches(rollbackRoute, exactRoute);
|
|
735
|
+
reserved.rollback(deferredScope);
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
createdSession = saveManagedSession(exactRoute.storeDir, pendingRawAttachSessionCreate, {
|
|
739
|
+
expectedRevision: null
|
|
740
|
+
});
|
|
741
|
+
managedSession = createdSession;
|
|
742
|
+
pendingRawAttachSessionCreate = undefined;
|
|
743
|
+
return (rollbackRoute) => {
|
|
744
|
+
assertTerminalDispatchRouteMatches(rollbackRoute, route);
|
|
745
|
+
const current = loadManagedSession(rollbackRoute.storeDir, createdSession.session_id);
|
|
746
|
+
if (current.status !== "bound" ||
|
|
747
|
+
current.revision !== createdSession.revision ||
|
|
748
|
+
managedSessionBindingToken(current) !==
|
|
749
|
+
managedSessionBindingToken(createdSession)) {
|
|
750
|
+
throw new Error(`new raw-attach Session ${createdSession.session_id} changed before pre-transport rollback`);
|
|
751
|
+
}
|
|
752
|
+
const detachedAt = cliNow().toISOString();
|
|
753
|
+
managedSession = saveManagedSession(rollbackRoute.storeDir, {
|
|
754
|
+
...current,
|
|
755
|
+
status: "detached",
|
|
756
|
+
detached_at: detachedAt,
|
|
757
|
+
updated_at: detachedAt
|
|
758
|
+
}, {
|
|
759
|
+
expectedRevision: current.revision
|
|
760
|
+
});
|
|
761
|
+
};
|
|
762
|
+
},
|
|
763
|
+
allowedPreMaterializationIdentity,
|
|
764
|
+
allowedAdditionalIdentities,
|
|
765
|
+
observedHandoff: handoff.adopted && handoff.transition
|
|
766
|
+
? {
|
|
767
|
+
terminal: terminalConversation,
|
|
768
|
+
transition: handoff.transition
|
|
769
|
+
}
|
|
770
|
+
: undefined,
|
|
771
|
+
verifiedEmptyCodexHandoff: verifiedEmptyHandoff?.boundary,
|
|
772
|
+
postSendCodexCandidateAnchor,
|
|
773
|
+
postSendCodexDetachedSessionClaims,
|
|
774
|
+
deferredCodexForegroundBinding
|
|
775
|
+
});
|
|
776
|
+
attempt.result = controlSendResult;
|
|
777
|
+
}, deferZeroInputFailurePresentation
|
|
778
|
+
? { timeoutMs: USER_EXPLICIT_MANAGED_LOCK_GRACE_MS }
|
|
779
|
+
: undefined);
|
|
780
|
+
});
|
|
781
|
+
if (!controlSendResult) {
|
|
782
|
+
throw new Error("managed terminal Send completed without an outcome");
|
|
783
|
+
}
|
|
784
|
+
attempt.result = controlSendResult;
|
|
785
|
+
return controlSendResult;
|
|
786
|
+
}
|
|
787
|
+
async function runManagedSessionSendInContext(options, messageBody) {
|
|
788
|
+
if (stringValue(options.expectedTerminalToken)) {
|
|
789
|
+
throw new Error("--expected-terminal-token cannot be used with a managed Session; " +
|
|
790
|
+
"use the exact full terminal selector advertised by AKK list");
|
|
791
|
+
}
|
|
792
|
+
const sessionId = required(stringValue(options.session ?? options.conversation ?? options.conversationId), "--session is required for an ordinary managed send");
|
|
793
|
+
const storeDir = storeDirFromOptions(options);
|
|
794
|
+
// Read only enough legacy/Session authority to identify the physical
|
|
795
|
+
// terminal. Store migration is deliberately deferred until the terminal
|
|
796
|
+
// lock has reconciled any lifecycle fence.
|
|
797
|
+
let initialSession = tryLoadManagedSession(storeDir, sessionId);
|
|
798
|
+
let initialTurns = managedTurnsForSession(storeDir, sessionId);
|
|
799
|
+
if (!initialSession) {
|
|
800
|
+
const exactTurn = listConversations(storeDir)
|
|
801
|
+
.filter(isDiscoverableTmuxConversation)
|
|
802
|
+
.find((turn) => turnIdForConversation(turn) === sessionId ||
|
|
803
|
+
turn.conversation_id === sessionId);
|
|
804
|
+
if (exactTurn && sessionIdForConversation(exactTurn) !== sessionId) {
|
|
805
|
+
throw new Error(`turn ${sessionId} is an execution identity, not an ordinary send target; ` +
|
|
806
|
+
`send to session ${sessionIdForConversation(exactTurn)} instead`);
|
|
807
|
+
}
|
|
808
|
+
if (initialTurns.length === 0) {
|
|
809
|
+
throw new Error(`managed session ${sessionId} was not found`);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
const legacyBindingTurn = initialTurns[0];
|
|
813
|
+
const legacyTakeover = legacyBindingTurn && isRecord(legacyBindingTurn.native_session_takeover)
|
|
814
|
+
? legacyBindingTurn.native_session_takeover
|
|
815
|
+
: undefined;
|
|
816
|
+
const rawTerminalId = initialSession?.binding?.terminal_id ??
|
|
817
|
+
stringValue(legacyTakeover?.native_session_id);
|
|
818
|
+
if (!rawTerminalId) {
|
|
819
|
+
throw new Error(`managed Session ${sessionId} has no authoritative terminal binding`);
|
|
820
|
+
}
|
|
821
|
+
const storedTerminalControl = initialSession?.binding?.terminal_control ??
|
|
822
|
+
terminalControlFromTakeover(legacyTakeover);
|
|
823
|
+
const storedAgent = initialSession?.agent ??
|
|
824
|
+
(legacyBindingTurn
|
|
825
|
+
? executorForConversation(legacyBindingTurn).kind
|
|
826
|
+
: undefined);
|
|
827
|
+
const storedPid = initialSession?.binding?.native_process.pid ??
|
|
828
|
+
Number(legacyTakeover?.terminal_agent_pid);
|
|
829
|
+
const terminalBridge = createTerminalAgentBridge(options);
|
|
830
|
+
const resolvedTerminal = storedTerminalControl && storedAgent &&
|
|
831
|
+
Number.isSafeInteger(storedPid) && storedPid > 1
|
|
832
|
+
? await terminalBridge.resolveStoredTerminal(storedAgent, storedPid, storedTerminalControl, { pid: storedPid })
|
|
833
|
+
: await terminalBridge.resolveConversationId(rawTerminalId);
|
|
834
|
+
if (!resolvedTerminal) {
|
|
835
|
+
throw new Error(`session ${sessionId} is not attached to a live terminal`);
|
|
836
|
+
}
|
|
837
|
+
await withCanonicalMutationLocks(terminalWriterMutationLocks(storeDir, resolvedTerminal.terminalControl), async (scopes, resources) => {
|
|
838
|
+
const lockedStrictSession = tryLoadManagedSession(storeDir, sessionId);
|
|
839
|
+
if (lockedStrictSession?.agent === "codex" &&
|
|
840
|
+
lockedStrictSession.session_id === sessionId &&
|
|
841
|
+
lockedStrictSession.status === "bound" &&
|
|
842
|
+
isCompleteNativeRollout(lockedStrictSession.binding?.native_process.rollout)) {
|
|
843
|
+
throw new Error(`Codex rollout-backed managed Session ${sessionId} cannot use a ` +
|
|
844
|
+
"strict session_id send because an open rollout does not prove the " +
|
|
845
|
+
"current TUI foreground thread. Refresh AKK list and use its exact " +
|
|
846
|
+
"selector plus expected_terminal_token. No Turn was created and no " +
|
|
847
|
+
"terminal input was sent.");
|
|
848
|
+
}
|
|
849
|
+
await mutationDispatchLedger.beforeMutation(scopes, resources, options, resolvedTerminal);
|
|
850
|
+
// A protocol-1/2 Store materializes authoritative Session records as one
|
|
851
|
+
// atomic migration. Once protocol 3 is active, a missing Session is corrupt
|
|
852
|
+
// state and must not be reconstructed from whichever Turn looks newest.
|
|
853
|
+
ensureStoreWritable(storeDir);
|
|
854
|
+
if (replayExactActiveTerminalSubmission({
|
|
855
|
+
options,
|
|
856
|
+
terminalControl: resolvedTerminal.terminalControl,
|
|
857
|
+
requestText: String(messageBody),
|
|
858
|
+
expectedStoreDir: storeDir,
|
|
859
|
+
expectedSessionId: sessionId,
|
|
860
|
+
expectedMessageType: "task"
|
|
861
|
+
})) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
terminalListCliFacade.assertTerminalIncarnationCanStartTurn(storeDir, resolvedTerminal.terminalControl);
|
|
865
|
+
let currentSession = tryLoadManagedSession(storeDir, sessionId);
|
|
866
|
+
let knownCodexCompanions = currentSession
|
|
867
|
+
? codexAllowedCompanionSetForManagedSession({
|
|
868
|
+
storeDir,
|
|
869
|
+
session: currentSession
|
|
870
|
+
})
|
|
871
|
+
: { additional: [] };
|
|
872
|
+
if (currentSession?.agent === "codex" &&
|
|
873
|
+
knownCodexCompanions.primary) {
|
|
874
|
+
try {
|
|
875
|
+
const inventory = await inspectCodexOpenRootRolloutInventory({
|
|
876
|
+
options,
|
|
877
|
+
pid: resolvedTerminal.pid,
|
|
878
|
+
cwd: resolvedTerminal.terminalControl.currentPath
|
|
879
|
+
});
|
|
880
|
+
knownCodexCompanions = codexCompanionsPresentInOpenRootInventory(knownCodexCompanions, inventory);
|
|
881
|
+
}
|
|
882
|
+
catch {
|
|
883
|
+
// Inventory proof is an optimization only. Preserve the existing
|
|
884
|
+
// closed /status fence when exact open-root membership is unavailable.
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
const lockedNativeIdentity = await resolveCurrentNativeAgentSessionIdentity({
|
|
888
|
+
options,
|
|
889
|
+
agent: resolvedTerminal.agent,
|
|
890
|
+
pid: resolvedTerminal.pid,
|
|
891
|
+
cwd: resolvedTerminal.terminalControl.currentPath,
|
|
892
|
+
preferredSessionId: knownCodexCompanions.primary
|
|
893
|
+
? currentSession?.binding?.native_thread_id
|
|
894
|
+
: undefined,
|
|
895
|
+
allowedCompanionIdentity: knownCodexCompanions.primary,
|
|
896
|
+
allowedAdditionalIdentities: knownCodexCompanions.additional
|
|
897
|
+
});
|
|
898
|
+
if (!currentSession) {
|
|
899
|
+
currentSession = materializeCurrentManagedSession({
|
|
900
|
+
options,
|
|
901
|
+
terminal: resolvedTerminal,
|
|
902
|
+
identity: lockedNativeIdentity
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
if (!currentSession ||
|
|
906
|
+
currentSession.session_id !== sessionId ||
|
|
907
|
+
currentSession.status !== "bound" ||
|
|
908
|
+
!currentSession.binding) {
|
|
909
|
+
throw new Error(`managed Session ${sessionId} is no longer bound; refresh list and retry`);
|
|
910
|
+
}
|
|
911
|
+
const currentTurns = managedTurnsForSession(storeDir, sessionId);
|
|
912
|
+
assertManagedSessionCanStartTurn(currentTurns);
|
|
913
|
+
if (!bindingMatchesLiveTerminal(currentSession, resolvedTerminal, lockedNativeIdentity, storeDir)) {
|
|
914
|
+
throw new Error("managed session identity changed while waiting to send; refresh list and retry");
|
|
915
|
+
}
|
|
916
|
+
const logicalLockedNativeIdentity = logicalIdentityForManagedSession({
|
|
917
|
+
storeDir,
|
|
918
|
+
session: currentSession,
|
|
919
|
+
observedIdentity: lockedNativeIdentity
|
|
920
|
+
});
|
|
921
|
+
const allowedPreMaterializationIdentity = codexPreMaterializationIdentityForManagedSession({
|
|
922
|
+
storeDir,
|
|
923
|
+
session: currentSession,
|
|
924
|
+
observedIdentity: lockedNativeIdentity
|
|
925
|
+
}) ?? knownCodexCompanions.primary;
|
|
926
|
+
const allowedAdditionalIdentities = knownCodexCompanions.additional;
|
|
927
|
+
const materializedLockedNativeIdentity = lockedNativeIdentity?.sessionId === logicalLockedNativeIdentity?.sessionId
|
|
928
|
+
? lockedNativeIdentity
|
|
929
|
+
: undefined;
|
|
930
|
+
await verifyCodexPendingManagedSendStatus({
|
|
931
|
+
options,
|
|
932
|
+
terminal: resolvedTerminal,
|
|
933
|
+
session: currentSession,
|
|
934
|
+
logicalIdentity: logicalLockedNativeIdentity,
|
|
935
|
+
allowedPreMaterializationIdentity,
|
|
936
|
+
allowedAdditionalIdentities
|
|
937
|
+
});
|
|
938
|
+
const managedNativeThreadId = logicalLockedNativeIdentity?.sessionId ??
|
|
939
|
+
currentSession.binding.native_thread_id;
|
|
940
|
+
if (managedNativeThreadId) {
|
|
941
|
+
await assertNativeThreadHasExclusiveOwnership({
|
|
942
|
+
options,
|
|
943
|
+
agent: resolvedTerminal.agent,
|
|
944
|
+
currentPid: resolvedTerminal.pid,
|
|
945
|
+
nativeThreadId: managedNativeThreadId,
|
|
946
|
+
storeDir,
|
|
947
|
+
terminalControl: resolvedTerminal.terminalControl,
|
|
948
|
+
excludedManagedSessionId: currentSession.session_id
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
currentSession = refineManagedSessionNativeIdentity({
|
|
952
|
+
storeDir,
|
|
953
|
+
session: currentSession,
|
|
954
|
+
terminalControl: resolvedTerminal.terminalControl,
|
|
955
|
+
identity: logicalLockedNativeIdentity
|
|
956
|
+
});
|
|
957
|
+
const managed = createManagedTerminalTurn({
|
|
958
|
+
options,
|
|
959
|
+
conversationId: resolvedTerminal.conversationId,
|
|
960
|
+
agent: resolvedTerminal.agent,
|
|
961
|
+
pid: resolvedTerminal.pid,
|
|
962
|
+
messageBody,
|
|
963
|
+
terminalControl: resolvedTerminal.terminalControl,
|
|
964
|
+
previousTurn: currentTurns[0],
|
|
965
|
+
managedSession: currentSession,
|
|
966
|
+
nativeAgentIdentity: materializedLockedNativeIdentity
|
|
967
|
+
});
|
|
968
|
+
ensureStoreWritable(managed.conversation.store_dir);
|
|
969
|
+
ensureDir(path.dirname(managed.statePath));
|
|
970
|
+
await withTerminalDispatchStateScope(scopes, resources, managed.statePath, managed.logPath, async (dispatchScopes, dispatchResources) => {
|
|
971
|
+
await runTerminalControlSend({
|
|
972
|
+
transaction: {
|
|
973
|
+
scopes: dispatchScopes,
|
|
974
|
+
resources: dispatchResources
|
|
975
|
+
},
|
|
976
|
+
options,
|
|
977
|
+
conversation: managed.conversation,
|
|
978
|
+
nextConversation: managed.nextConversation,
|
|
979
|
+
executor: managed.executor,
|
|
980
|
+
message: managed.message,
|
|
981
|
+
recordMessageAfterSend: true,
|
|
982
|
+
allowedPreMaterializationIdentity,
|
|
983
|
+
allowedAdditionalIdentities
|
|
984
|
+
});
|
|
985
|
+
});
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
export async function runManagedRawTerminalSendAttempt(dependencies, options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt) {
|
|
989
|
+
return managedSendContext.run(dependencies, () => runManagedRawTerminalSendAttemptInContext(options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt));
|
|
990
|
+
}
|
|
991
|
+
export async function runManagedSessionSend(dependencies, options, messageBody) {
|
|
992
|
+
return managedSendContext.run(dependencies, () => runManagedSessionSendInContext(options, messageBody));
|
|
993
|
+
}
|
|
994
|
+
//# sourceMappingURL=terminal-managed-send-cli-adapter.js.map
|