@scotthuang/agent-knock-knock 0.13.3 → 0.13.5
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 +25 -0
- package/README.md +13 -5
- 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/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.d.ts +1 -1
- package/dist/src/codex-terminal-agent-adapter.js +56 -4
- 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 +2 -172
- 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/native-thread-lifecycle-cli-adapter.js +116 -60
- 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 -2660
- package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
- package/dist/src/openclaw-plugin-helpers.d.ts +2 -148
- package/dist/src/openclaw-plugin-helpers.js +2 -1844
- package/dist/src/openclaw-plugin-helpers.js.map +1 -1
- package/dist/src/openclaw-plugin-schemas.d.ts +2 -563
- package/dist/src/openclaw-plugin-schemas.js +2 -572
- 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 +2 -98
- package/dist/src/terminal-action-projection.js +13 -215
- package/dist/src/terminal-action-projection.js.map +1 -1
- package/dist/src/terminal-agent-bridge.d.ts +14 -340
- package/dist/src/terminal-agent-bridge.js +155 -3226
- 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-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 +165 -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 +241 -1946
- 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 +11 -11
- package/dist/src/terminal-list-renderer.js +168 -119
- 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 +37 -18
- package/dist/src/terminal-model-control.js +285 -194
- package/dist/src/terminal-model-control.js.map +1 -1
- 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 -2
- 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/package.json +7 -2
- package/templates/openclaw-skills/agent-knock-knock/SKILL.md +1 -1
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
// Infrastructure composition for terminal list discovery and selector projection.
|
|
2
2
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
-
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import { listDeferredForegroundTransfers } from "./deferred-foreground-transfer.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { executorForConversation, isSessionSendBlockingStatus, isTerminalDispatchOwnerReleasedStatus, resolveExecutor, sessionIdForConversation, turnIdForConversation } from "./protocol.js";
|
|
5
|
+
import { isExactNativeThreadId, unmanagedTerminalBindingToken } from "./managed-session.js";
|
|
6
|
+
import { executorForConversation, resolveExecutor, sessionIdForConversation } from "./protocol.js";
|
|
9
7
|
import { resolveSessionSelector, sessionShortRef } from "./session-selector.js";
|
|
10
8
|
import { projectSessionSelectorCandidate } from "./terminal-selector-projection-service.js";
|
|
11
|
-
import { listManagedSessions,
|
|
9
|
+
import { listManagedSessions, tryLoadManagedSession } from "./session-store.js";
|
|
12
10
|
import { defaultStoreDir, ensureStoreWritable, inspectStoreCompatibility, listConversations, storeManifestPath, STORE_SESSION_AUTHORITY_PROTOCOL } from "./store.js";
|
|
13
|
-
import { parseTerminalConversationId } from "./terminal-agent-adapter.js";
|
|
14
11
|
import { exactCodexReadyStyledComposerCapture } from "./terminal-agent-bridge.js";
|
|
15
12
|
import { captureCodexHumanStartedActiveTaskAnchor } from "./terminal-submission-acceptance.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
13
|
+
import { decideTerminalUserExplicitSendAuthority } from "./terminal-action-projection.js";
|
|
14
|
+
import { materializeModelControlAvailability } from "./terminal-model-control-availability.js";
|
|
15
|
+
import { terminalModelControlPlanConforms } from "./terminal-model-control.js";
|
|
16
|
+
import { childProcessIdsForRoot, terminalControlsShareIncarnation } from "./terminal-authority-policy.js";
|
|
17
|
+
import { terminalScopedCodexApprovalPromptSnapshot } from "./terminal-scoped-approval-authority.js";
|
|
18
|
+
import { listActionContracts, renderAvailableListActions, renderTerminalModelControlActions } from "./terminal-list-renderer.js";
|
|
19
|
+
import { collectTerminalListInventory } from "./terminal-list-inventory.js";
|
|
20
|
+
import { collectTerminalListTerminalFacts } from "./terminal-list-facts.js";
|
|
21
|
+
import { decideTerminalListActions, modelControlPolicyFacts } from "./terminal-list-action-policy.js";
|
|
22
|
+
import { createTerminalListOwnershipService } from "./terminal-list-ownership-service.js";
|
|
23
|
+
import { createTerminalListProjectionService } from "./terminal-list-projection-service.js";
|
|
25
24
|
import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
|
|
26
25
|
import { expandHome, writeCliJson as printJson } from "./cli-command-runtime.js";
|
|
27
26
|
import { cliCwd, cliNowMs, cliRuntimeLog as runtimeLog } from "./cli-runtime-context.js";
|
|
@@ -33,16 +32,43 @@ function terminalListRuntime() {
|
|
|
33
32
|
}
|
|
34
33
|
return runtime;
|
|
35
34
|
}
|
|
35
|
+
function terminalListOwnershipService() {
|
|
36
|
+
return terminalListRuntime().ownershipService;
|
|
37
|
+
}
|
|
38
|
+
function terminalListProjectionService() {
|
|
39
|
+
return terminalListRuntime().projectionService;
|
|
40
|
+
}
|
|
36
41
|
function withTerminalListRuntime(runtime, operation) {
|
|
37
42
|
return terminalListRuntimeContext.run(runtime, operation);
|
|
38
43
|
}
|
|
39
44
|
export function createTerminalListCliFacade(dependencies) {
|
|
45
|
+
const ownershipService = createTerminalListOwnershipService({
|
|
46
|
+
...dependencies.store,
|
|
47
|
+
...dependencies.authority,
|
|
48
|
+
codexProcessIncarnationForPid: dependencies.discovery.codexProcessIncarnationForPid,
|
|
49
|
+
currentWorkingDirectory: cliCwd,
|
|
50
|
+
runtimeLog
|
|
51
|
+
});
|
|
52
|
+
const projectionService = createTerminalListProjectionService({
|
|
53
|
+
approvalTtlMs: dependencies.policy.approvalTtlMs,
|
|
54
|
+
callbackRetryDisposition: dependencies.store.callbackRetryDisposition,
|
|
55
|
+
isVerifiedDeadTerminalAgentProcess: dependencies.store.isVerifiedDeadTerminalAgentProcess,
|
|
56
|
+
listDeferredForegroundTransfers,
|
|
57
|
+
nowMs: cliNowMs,
|
|
58
|
+
ownershipService,
|
|
59
|
+
summarizeConversation: dependencies.store.summarizeConversation,
|
|
60
|
+
terminalBridgeEnabled: dependencies.store.terminalBridgeEnabled,
|
|
61
|
+
terminalBridgeSubmission: dependencies.store.terminalBridgeSubmission,
|
|
62
|
+
terminalControlFromTakeover: dependencies.store.terminalControlFromTakeover
|
|
63
|
+
});
|
|
40
64
|
const runtime = {
|
|
41
65
|
...dependencies.reconciliation,
|
|
42
66
|
...dependencies.discovery,
|
|
43
67
|
...dependencies.store,
|
|
44
68
|
...dependencies.authority,
|
|
45
|
-
...dependencies.policy
|
|
69
|
+
...dependencies.policy,
|
|
70
|
+
ownershipService,
|
|
71
|
+
projectionService
|
|
46
72
|
};
|
|
47
73
|
const call = (operation) => withTerminalListRuntime(runtime, operation);
|
|
48
74
|
return {
|
|
@@ -203,7 +229,7 @@ function projectTerminalListScan(input) {
|
|
|
203
229
|
let projection;
|
|
204
230
|
if (managementErrors.length === 0) {
|
|
205
231
|
try {
|
|
206
|
-
projection =
|
|
232
|
+
projection = terminalListProjectionService().projectTerminalFirstList({
|
|
207
233
|
storeDir,
|
|
208
234
|
terminals: physicalTerminals,
|
|
209
235
|
managedSessions,
|
|
@@ -350,298 +376,36 @@ async function reconcileStoreForList(storeDir, options) {
|
|
|
350
376
|
idle_timeout_minutes: idle.idle_timeout_minutes
|
|
351
377
|
};
|
|
352
378
|
}
|
|
353
|
-
async function buildTerminalListGroup({ options, agentFilter, statusFilter, terminalId }) {
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const adapters = agentFilter
|
|
367
|
-
? [registry.get(agentFilter)].filter((adapter) => adapter !== undefined)
|
|
368
|
-
: registry.list();
|
|
369
|
-
if (agentFilter && adapters.length === 0) {
|
|
370
|
-
return {
|
|
371
|
-
...empty,
|
|
372
|
-
summary: {
|
|
373
|
-
enabled: true,
|
|
374
|
-
agents: [],
|
|
375
|
-
skipped: `terminal agent adapter is not registered for ${agentFilter}`
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
const terminalProvider = terminalListRuntime().createTerminalControlProvider(options);
|
|
380
|
-
const bridge = terminalListRuntime().createTerminalAgentBridge(options, terminalProvider, registry);
|
|
381
|
-
const terminalDiagnostics = options.terminalDebug
|
|
382
|
-
? await terminalControlDiagnostics(terminalProvider)
|
|
383
|
-
: undefined;
|
|
384
|
-
const exactTarget = terminalId
|
|
385
|
-
? exactTerminalTargetDiagnostic(terminalId)
|
|
386
|
-
: undefined;
|
|
387
|
-
if (terminalId) {
|
|
388
|
-
runtimeLog("info", "terminal_exact_scan", {
|
|
389
|
-
stage: "started",
|
|
390
|
-
terminal_id: terminalId,
|
|
391
|
-
target: exactTarget
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
const terminalControlled = [];
|
|
395
|
-
let activeCount = 0;
|
|
396
|
-
const errors = [];
|
|
397
|
-
try {
|
|
398
|
-
const processSource = terminalListRuntime().createTerminalProcessSource(options);
|
|
399
|
-
const snapshots = await processSource.listProcessSnapshots((snapshot) => adapters.some((adapter) => adapter.capabilities.processDiscovery && adapter.classifyProcess(snapshot) !== undefined), { includeAncestors: true });
|
|
400
|
-
if (terminalId) {
|
|
401
|
-
const targetPid = exactTarget?.pid;
|
|
402
|
-
runtimeLog("info", "terminal_exact_scan", {
|
|
403
|
-
stage: "process_inventory",
|
|
404
|
-
terminal_id: terminalId,
|
|
405
|
-
target_pid: targetPid,
|
|
406
|
-
snapshot_count: snapshots.length,
|
|
407
|
-
target_process_found: targetPid === undefined
|
|
408
|
-
? undefined
|
|
409
|
-
: snapshots.some((snapshot) => snapshot.pid === targetPid),
|
|
410
|
-
target_process_snapshots: targetPid === undefined
|
|
411
|
-
? []
|
|
412
|
-
: snapshots
|
|
413
|
-
.filter((snapshot) => snapshot.pid === targetPid)
|
|
414
|
-
.map((snapshot) => ({ pid: snapshot.pid, ppid: snapshot.ppid }))
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
const activeSessions = await bridge.listProcesses(snapshots, adapters.map((adapter) => adapter.agent));
|
|
418
|
-
const rootSessions = selectRootTerminalProcesses(activeSessions, snapshots);
|
|
419
|
-
const controlledSessions = rootSessions.filter((session) => session.terminalControl !== undefined);
|
|
420
|
-
if (terminalId) {
|
|
421
|
-
const targetPid = exactTarget?.pid;
|
|
422
|
-
const targetSessions = targetPid === undefined
|
|
423
|
-
? []
|
|
424
|
-
: activeSessions.filter((session) => session.pid === targetPid);
|
|
425
|
-
runtimeLog("info", "terminal_exact_scan", {
|
|
426
|
-
stage: "process_classification_and_association",
|
|
427
|
-
terminal_id: terminalId,
|
|
428
|
-
target_pid: targetPid,
|
|
429
|
-
classified_process_count: activeSessions.length,
|
|
430
|
-
root_process_count: rootSessions.length,
|
|
431
|
-
controlled_process_count: controlledSessions.length,
|
|
432
|
-
target_classified_count: targetSessions.length,
|
|
433
|
-
target_controlled_count: targetSessions.filter((session) => session.terminalControl !== undefined).length,
|
|
434
|
-
target_sessions: targetSessions.map((session) => ({
|
|
435
|
-
agent: session.agent,
|
|
436
|
-
pid: session.pid,
|
|
437
|
-
ppid: session.ppid,
|
|
438
|
-
kind: session.kind,
|
|
439
|
-
confidence: session.confidence,
|
|
440
|
-
selected_as_root: rootSessions.includes(session),
|
|
441
|
-
terminal_conversation_id: session.terminalControl
|
|
442
|
-
? bridge.terminalConversationId(session)
|
|
443
|
-
: undefined,
|
|
444
|
-
terminal_control: terminalControlScanDiagnostic(session.terminalControl)
|
|
445
|
-
}))
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
activeCount = controlledSessions.length;
|
|
449
|
-
const selectedSessions = terminalId
|
|
450
|
-
? activeSessions.filter((session) => session.terminalControl !== undefined &&
|
|
451
|
-
bridge.terminalConversationId(session) === terminalId)
|
|
452
|
-
: controlledSessions;
|
|
453
|
-
for (const session of selectedSessions) {
|
|
454
|
-
try {
|
|
455
|
-
terminalControlled.push(await terminalControlledListEntry(session, activeSessions, options, bridge));
|
|
456
|
-
}
|
|
457
|
-
catch (error) {
|
|
458
|
-
errors.push(`terminal process ${session.pid}: ` +
|
|
459
|
-
(error instanceof Error ? error.message : String(error)));
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
catch (error) {
|
|
464
|
-
errors.push(error instanceof Error ? error.message : String(error));
|
|
465
|
-
}
|
|
466
|
-
if (terminalId) {
|
|
467
|
-
runtimeLog("info", "terminal_exact_scan", {
|
|
468
|
-
stage: "complete",
|
|
469
|
-
terminal_id: terminalId,
|
|
470
|
-
controlled_process_count: activeCount,
|
|
471
|
-
terminal_row_count: terminalControlled.length,
|
|
472
|
-
terminal_row_ids: terminalControlled.map((terminal) => terminal.id),
|
|
473
|
-
errors
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
return {
|
|
477
|
-
terminalControlled,
|
|
478
|
-
summary: {
|
|
479
|
-
enabled: true,
|
|
480
|
-
agents: adapters.map((adapter) => adapter.agent),
|
|
481
|
-
active_count: activeCount,
|
|
482
|
-
terminal_count: terminalControlled.length,
|
|
483
|
-
approval_scan: options.noApprovalScan ? "disabled" : "enabled",
|
|
484
|
-
diagnostics: terminalDiagnostics,
|
|
485
|
-
error: errors.length > 0 ? errors.join("; ") : undefined
|
|
379
|
+
async function buildTerminalListGroup({ options, agentFilter, statusFilter: _statusFilter, terminalId }) {
|
|
380
|
+
const runtime = terminalListRuntime();
|
|
381
|
+
return collectTerminalListInventory({
|
|
382
|
+
options,
|
|
383
|
+
agentFilter,
|
|
384
|
+
terminalId,
|
|
385
|
+
ports: {
|
|
386
|
+
createRegistry: (currentOptions) => runtime.createRuntimeTerminalAgentRegistry(currentOptions),
|
|
387
|
+
createBridge: (currentOptions, provider, registry) => runtime.createTerminalAgentBridge(currentOptions, provider, registry),
|
|
388
|
+
createProvider: (currentOptions) => runtime.createTerminalControlProvider(currentOptions),
|
|
389
|
+
createProcessSource: (currentOptions) => runtime.createTerminalProcessSource(currentOptions),
|
|
390
|
+
projectTerminal: ({ session, activeSessions, options: currentOptions, bridge }) => terminalControlledListEntry(session, activeSessions, currentOptions, bridge),
|
|
391
|
+
log: runtimeLog
|
|
486
392
|
}
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
function exactTerminalTargetDiagnostic(terminalId) {
|
|
490
|
-
try {
|
|
491
|
-
const parsed = parseTerminalConversationId(terminalId);
|
|
492
|
-
return parsed ? {
|
|
493
|
-
provider: parsed.kind,
|
|
494
|
-
agent: parsed.agent,
|
|
495
|
-
route: parsed.target,
|
|
496
|
-
pid: parsed.pid
|
|
497
|
-
} : undefined;
|
|
498
|
-
}
|
|
499
|
-
catch (error) {
|
|
500
|
-
return {
|
|
501
|
-
parse_error: error instanceof Error ? error.message : String(error)
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
function terminalControlScanDiagnostic(terminalControl) {
|
|
506
|
-
if (!terminalControl) {
|
|
507
|
-
return undefined;
|
|
508
|
-
}
|
|
509
|
-
const control = terminalControl;
|
|
510
|
-
return {
|
|
511
|
-
kind: terminalControl.kind,
|
|
512
|
-
target: terminalControl.target,
|
|
513
|
-
pane_pid: control.panePid,
|
|
514
|
-
process_anchor_pid: control.processAnchorPid,
|
|
515
|
-
endpoint_key: control.endpointKey,
|
|
516
|
-
resource_key: control.resourceKey,
|
|
517
|
-
terminal_id: control.terminalId
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
async function terminalControlDiagnostics(provider) {
|
|
521
|
-
return provider.diagnostics();
|
|
522
|
-
}
|
|
523
|
-
function managedTurnListEntry(task, { terminalBridge = false, approvalState, conversation } = {}) {
|
|
524
|
-
return renderManagedTurnListEntry(task, {
|
|
525
|
-
terminalBridge,
|
|
526
|
-
approvalState,
|
|
527
|
-
actionFacts: managedTurnListActionFacts(task, conversation)
|
|
528
393
|
});
|
|
529
394
|
}
|
|
530
|
-
function managedTurnListActionFacts(task, conversation) {
|
|
531
|
-
const nativeTakeover = isRecord(conversation?.native_session_takeover)
|
|
532
|
-
? conversation.native_session_takeover
|
|
533
|
-
: undefined;
|
|
534
|
-
const managedApprovalPending = isRecord(nativeTakeover?.terminal_bridge_approval);
|
|
535
|
-
const terminalBridgeReady = Boolean(conversation &&
|
|
536
|
-
terminalListRuntime().terminalBridgeEnabled(conversation) &&
|
|
537
|
-
terminalListRuntime().terminalControlFromTakeover(nativeTakeover) !== undefined);
|
|
538
|
-
const submission = terminalListRuntime().terminalBridgeSubmission(conversation);
|
|
539
|
-
const renewEligible = Boolean(terminalBridgeReady &&
|
|
540
|
-
task.status === "stalled" &&
|
|
541
|
-
submission?.status !== "uncertain" &&
|
|
542
|
-
!terminalListRuntime().isVerifiedDeadTerminalAgentProcess(conversation ?? {}));
|
|
543
|
-
const callbackDelivery = isRecord(conversation?.callback_delivery)
|
|
544
|
-
? conversation.callback_delivery
|
|
545
|
-
: undefined;
|
|
546
|
-
const retryCallbackEligible = Boolean(conversation &&
|
|
547
|
-
conversation.legacy_callback_status_error === undefined &&
|
|
548
|
-
terminalListRuntime().callbackRetryDisposition(callbackDelivery).state ===
|
|
549
|
-
"retryable");
|
|
550
|
-
const retrySubmissionCandidate = Boolean(conversation &&
|
|
551
|
-
executorForConversation(conversation).kind === "codex" &&
|
|
552
|
-
terminalBridgeReady &&
|
|
553
|
-
task.status === "stalled" &&
|
|
554
|
-
submission?.status === "uncertain" &&
|
|
555
|
-
stringValue(submission.last_proven_stage) === "text_injected");
|
|
556
|
-
return {
|
|
557
|
-
terminalBridgeReady,
|
|
558
|
-
managedApprovalPending,
|
|
559
|
-
renewEligible,
|
|
560
|
-
retryCallbackEligible,
|
|
561
|
-
retrySubmissionCandidate
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
395
|
async function terminalControlledListEntry(session, activeSessions, options, bridge = terminalListRuntime().createTerminalAgentBridge(options)) {
|
|
565
396
|
const terminalControl = session.terminalControl;
|
|
566
397
|
if (!terminalControl) {
|
|
567
398
|
throw new Error(`process ${session.pid} is not terminal-controlled`);
|
|
568
399
|
}
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
...(session.agent === "codex"
|
|
577
|
-
? { conversationId: bridge.terminalConversationId(session) }
|
|
578
|
-
: { sessionId: session.sessionId }),
|
|
579
|
-
terminalTarget: terminalControl.target
|
|
580
|
-
});
|
|
581
|
-
const { orphanedDispatch, nativeIdentityObservation, nativeAgentIdentity, authorityNativeIdentityObservation, authorityNativeAgentIdentity, codexOpenRootRolloutInventory, nativeProcessUuid, nativeProcessBirth, nativeProcessEvidence } = await observeTerminalNativeListIdentity(session, terminalControl, options, bridge);
|
|
582
|
-
const effectiveTerminalState = effectiveTerminalListState({
|
|
583
|
-
session,
|
|
584
|
-
terminalState,
|
|
585
|
-
nativeIdentityObservation,
|
|
586
|
-
nativeAgentIdentity,
|
|
587
|
-
nativeIdentityAuthorityObservation: authorityNativeIdentityObservation,
|
|
588
|
-
codexOpenRootRolloutInventory,
|
|
589
|
-
nativeProcessUuid,
|
|
590
|
-
nativeProcessBirth
|
|
591
|
-
});
|
|
592
|
-
const terminalStatusSnapshot = effectiveTerminalState._terminal_status_snapshot
|
|
593
|
-
? terminalBridgeStatusWithProjection(effectiveTerminalState._terminal_status_snapshot, effectiveTerminalState)
|
|
594
|
-
: undefined;
|
|
595
|
-
const statusCardObservation = session.agent === "codex" &&
|
|
596
|
-
typeof effectiveTerminalState.screen_excerpt === "string"
|
|
597
|
-
? bridge.registry.require("codex").observeThreadLifecycle?.({
|
|
598
|
-
operation: { kind: "new_thread" },
|
|
599
|
-
phase: "before",
|
|
600
|
-
screen: effectiveTerminalState.screen_excerpt
|
|
601
|
-
})
|
|
602
|
-
: undefined;
|
|
603
|
-
const statusCardNativeThreadId = statusCardObservation?.status === "observed" &&
|
|
604
|
-
effectiveTerminalState.activity_state === "idle" &&
|
|
605
|
-
effectiveTerminalState.approval_state.blocked !== true &&
|
|
606
|
-
isExactNativeThreadId(statusCardObservation.nativeThreadId)
|
|
607
|
-
? statusCardObservation.nativeThreadId
|
|
608
|
-
: undefined;
|
|
609
|
-
const agentVersion = terminalListRuntime().agentVersionForRunningProcess(session.agent, session.pid, options);
|
|
610
|
-
const lifecycleCapability = bridge.registry.require(session.agent)
|
|
611
|
-
.probeThreadLifecycle?.(agentVersion) ?? {
|
|
612
|
-
status: "unsupported",
|
|
613
|
-
agentVersion,
|
|
614
|
-
newThread: false,
|
|
615
|
-
resumeExact: false,
|
|
616
|
-
reason: "native thread lifecycle is unavailable"
|
|
617
|
-
};
|
|
618
|
-
const nativeInspectionCapability = bridge.registry.require(session.agent)
|
|
619
|
-
.probeNativeInspection?.(agentVersion) ?? {
|
|
620
|
-
status: "unsupported",
|
|
621
|
-
agentVersion,
|
|
622
|
-
statusInspection: false,
|
|
623
|
-
reason: "native inspection is unavailable"
|
|
624
|
-
};
|
|
625
|
-
const modelControlCapability = bridge.registry.require(session.agent)
|
|
626
|
-
.probeModelControl?.(agentVersion) ?? {
|
|
627
|
-
status: "unsupported",
|
|
628
|
-
agentVersion,
|
|
629
|
-
modelSelection: false,
|
|
630
|
-
reasoningEffortSelection: false,
|
|
631
|
-
reason: "terminal model control is unavailable"
|
|
632
|
-
};
|
|
633
|
-
const compatibilityWarnings = [...new Set([
|
|
634
|
-
lifecycleCapability.compatibilityWarning,
|
|
635
|
-
nativeInspectionCapability.compatibilityWarning
|
|
636
|
-
].filter((warning) => typeof warning === "string" && warning.trim().length > 0))];
|
|
637
|
-
const codexLatentClearResumeObservationValue = session.agent === "codex"
|
|
638
|
-
? terminalListRuntime().codexLatentClearResumeObservation({
|
|
639
|
-
screen: effectiveTerminalState.screen_excerpt,
|
|
640
|
-
agentVersion
|
|
641
|
-
})
|
|
642
|
-
: undefined;
|
|
400
|
+
const facts = await collectTerminalFactsForList(session, activeSessions, options, bridge, terminalControl);
|
|
401
|
+
const { orphanedDispatch, nativeIdentityObservation, nativeAgentIdentity, authorityNativeIdentityObservation, authorityNativeAgentIdentity, codexOpenRootRolloutInventory, nativeProcessUuid, nativeProcessBirth, nativeProcessEvidence } = facts.native;
|
|
402
|
+
const { observed: _observedTerminalState, effective: effectiveTerminalState, projected: projectedTerminalState, snapshot: terminalStatusSnapshot, statusCardNativeThreadId } = facts.status;
|
|
403
|
+
const { agentVersion, lifecycleCapability, nativeInspectionCapability, modelControlCapability, compatibilityWarnings } = facts.runtime;
|
|
404
|
+
const { automatedInputComposerReady, userExplicitComposerReady } = facts.composer;
|
|
405
|
+
const { terminalId, childPids, processIncarnation: physicalProcessIncarnation } = facts.physical;
|
|
406
|
+
const { latentClearResume: codexLatentClearResumeObservationValue } = facts.codex;
|
|
643
407
|
const lifecycleBindingToken = unmanagedTerminalBindingToken({
|
|
644
|
-
terminalId
|
|
408
|
+
terminalId,
|
|
645
409
|
terminalControl,
|
|
646
410
|
agent: session.agent,
|
|
647
411
|
pid: session.pid,
|
|
@@ -652,7 +416,7 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
652
416
|
rollout: nativeAgentIdentity?.rollout
|
|
653
417
|
});
|
|
654
418
|
const authorityLifecycleBindingToken = unmanagedTerminalBindingToken({
|
|
655
|
-
terminalId
|
|
419
|
+
terminalId,
|
|
656
420
|
terminalControl,
|
|
657
421
|
agent: session.agent,
|
|
658
422
|
pid: session.pid,
|
|
@@ -662,92 +426,26 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
662
426
|
processBirth: nativeProcessBirth,
|
|
663
427
|
rollout: authorityNativeAgentIdentity?.rollout
|
|
664
428
|
});
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
try {
|
|
669
|
-
terminalHasBlockingTurn = terminalIncarnationBlockingTurns(terminalListRuntime().storeDirFromOptions(options), terminalControl).length > 0;
|
|
670
|
-
}
|
|
671
|
-
catch (error) {
|
|
672
|
-
runtimeLog("warn", "terminal_managed_turn_inventory_unavailable", {
|
|
673
|
-
terminal_target: terminalControl.target,
|
|
674
|
-
error: error instanceof Error ? error.message : String(error)
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
const composerAuthority = await observeAutomatedInputComposerReady({
|
|
678
|
-
session,
|
|
679
|
-
terminalControl,
|
|
680
|
-
terminalState: effectiveTerminalState,
|
|
681
|
-
options
|
|
682
|
-
});
|
|
683
|
-
const automatedInputComposerReady = composerAuthority.automatedInputComposerReady;
|
|
684
|
-
const userExplicitComposerReady = composerAuthority.userExplicitComposerReady;
|
|
685
|
-
let physicalProcessIncarnation;
|
|
686
|
-
try {
|
|
687
|
-
physicalProcessIncarnation =
|
|
688
|
-
terminalListRuntime().processIncarnationForPid(session.pid);
|
|
689
|
-
}
|
|
690
|
-
catch (error) {
|
|
691
|
-
runtimeLog("warn", "terminal_physical_process_incarnation_unavailable", {
|
|
692
|
-
agent: session.agent,
|
|
693
|
-
terminal_target: terminalControl.target,
|
|
694
|
-
pid: session.pid,
|
|
695
|
-
error: error instanceof Error ? error.message : String(error)
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
const zeroRolloutModelControlVerified = session.agent === "codex" &&
|
|
699
|
-
nativeIdentityObservation.status === "verified_absent" &&
|
|
700
|
-
authorityNativeIdentityObservation.status === "verified_absent" &&
|
|
701
|
-
codexOpenRootRolloutInventory?.status === "verified_absent" &&
|
|
702
|
-
codexOpenRootRolloutInventory.pid === session.pid &&
|
|
703
|
-
codexOpenRootRolloutInventory.roots.length === 0 &&
|
|
704
|
-
codexOpenRootRolloutInventory.processBirth ===
|
|
705
|
-
physicalProcessIncarnation?.processBirth;
|
|
706
|
-
const exactModelControlNativeIdentity = session.agent === "codex" &&
|
|
707
|
-
isExactNativeThreadId(nativeAgentIdentity?.sessionId);
|
|
708
|
-
const modelControlResidual = await observeModelControlResidualForList({
|
|
709
|
-
bridge,
|
|
710
|
-
session,
|
|
711
|
-
terminalControl,
|
|
712
|
-
agentVersion,
|
|
713
|
-
modelControlCapability,
|
|
714
|
-
nativeAgentIdentity,
|
|
715
|
-
zeroRolloutVerified: zeroRolloutModelControlVerified,
|
|
716
|
-
nativeIdentityEligible: exactModelControlNativeIdentity || zeroRolloutModelControlVerified,
|
|
717
|
-
effectiveTerminalState,
|
|
718
|
-
terminalHasInteraction: terminalStatusSnapshot?.interaction_state !== undefined,
|
|
719
|
-
terminalHasBlockingTurn,
|
|
720
|
-
hasOrphanedDispatch: orphanedDispatch !== undefined
|
|
721
|
-
});
|
|
722
|
-
const modelControlSurfaceOpen = modelControlResidual?.state === "recoverable" &&
|
|
723
|
-
modelControlResidual.kind === "model_surface";
|
|
724
|
-
const projectedTerminalState = modelControlSurfaceOpen
|
|
725
|
-
? terminalListStateWithOpenModelControlSurface(effectiveTerminalState)
|
|
726
|
-
: effectiveTerminalState;
|
|
727
|
-
const commands = terminalListCommands({
|
|
429
|
+
const actionSubject = {
|
|
430
|
+
exactTerminalRow: true,
|
|
431
|
+
processState: "active",
|
|
728
432
|
agent: session.agent,
|
|
729
433
|
terminalControl,
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
nativeProcessUuid,
|
|
736
|
-
nativeProcessBirth,
|
|
737
|
-
codexLifecycleIncarnationAvailable,
|
|
738
|
-
automatedInputComposerReady,
|
|
739
|
-
hasOrphanedDispatch: orphanedDispatch !== undefined,
|
|
740
|
-
terminalHasBlockingTurn,
|
|
741
|
-
terminalHasInteraction: terminalStatusSnapshot?.interaction_state !== undefined
|
|
434
|
+
pid: session.pid
|
|
435
|
+
};
|
|
436
|
+
const actionDecisions = decideTerminalListActions({
|
|
437
|
+
subject: actionSubject,
|
|
438
|
+
facts
|
|
742
439
|
});
|
|
440
|
+
const commands = actionDecisions.commands;
|
|
743
441
|
const entry = {
|
|
744
|
-
id:
|
|
745
|
-
short_ref: sessionShortRef(
|
|
442
|
+
id: terminalId,
|
|
443
|
+
short_ref: sessionShortRef(terminalId),
|
|
746
444
|
source: "terminal",
|
|
747
445
|
agent: session.agent,
|
|
748
446
|
process_state: "active",
|
|
749
447
|
pid: session.pid,
|
|
750
|
-
child_pids:
|
|
448
|
+
child_pids: childPids,
|
|
751
449
|
command: session.command,
|
|
752
450
|
cwd: session.cwd,
|
|
753
451
|
workspace: session.cwd,
|
|
@@ -791,9 +489,9 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
791
489
|
...(terminalStatusSnapshot
|
|
792
490
|
? { _terminal_status_snapshot: terminalStatusSnapshot }
|
|
793
491
|
: {}),
|
|
794
|
-
// Internal action-projection evidence.
|
|
795
|
-
// this field after gating every automated-input action that
|
|
796
|
-
// human native-thread switch.
|
|
492
|
+
// Internal action-projection evidence. The terminal-first projection
|
|
493
|
+
// service strips this field after gating every automated-input action that
|
|
494
|
+
// can follow a human native-thread switch.
|
|
797
495
|
_automated_input_composer_ready: automatedInputComposerReady,
|
|
798
496
|
_user_explicit_composer_ready: userExplicitComposerReady,
|
|
799
497
|
_native_identity_authority: {
|
|
@@ -822,7 +520,7 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
822
520
|
owner_conversation_id: stringValue(orphanedDispatch.conversation_id),
|
|
823
521
|
message_id: stringValue(orphanedDispatch.message_id),
|
|
824
522
|
transition_id: stringValue(orphanedDispatch.transition_id),
|
|
825
|
-
recovery: `/akk close ${
|
|
523
|
+
recovery: `/akk close ${terminalId} ` +
|
|
826
524
|
(orphanedDispatch.kind === "lifecycle"
|
|
827
525
|
? `--expected-transition-id ${String(orphanedDispatch.transition_id)}`
|
|
828
526
|
: `--expected-message-id ${String(orphanedDispatch.message_id)}`)
|
|
@@ -832,23 +530,25 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
832
530
|
commands
|
|
833
531
|
};
|
|
834
532
|
const renderedActions = renderAvailableListActions(entry);
|
|
835
|
-
const terminalUserExplicitSendAuthority =
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
533
|
+
const terminalUserExplicitSendAuthority = actionDecisions.terminalUserExplicitSend.eligible
|
|
534
|
+
? decideTerminalUserExplicitSendAuthority({
|
|
535
|
+
exactTerminalRow: true,
|
|
536
|
+
terminalId: entry.id,
|
|
537
|
+
processState: entry.process_state,
|
|
538
|
+
terminalControl,
|
|
539
|
+
agent: session.agent,
|
|
540
|
+
pid: session.pid,
|
|
541
|
+
processUuid: physicalProcessIncarnation?.processUuid,
|
|
542
|
+
processBirth: physicalProcessIncarnation?.processBirth,
|
|
543
|
+
approvalScanned: projectedTerminalState.approval_state.scanned === true,
|
|
544
|
+
approvalBlocked: projectedTerminalState.approval_state.blocked === true,
|
|
545
|
+
// Codex user-explicit Send treats this observation as advisory: an
|
|
546
|
+
// off-screen or truncated composer must not hide the physical action.
|
|
547
|
+
// Claude Code still consumes the exact-composer result in the shared
|
|
548
|
+
// authority decision below.
|
|
549
|
+
userExplicitComposerReady
|
|
550
|
+
})
|
|
551
|
+
: { eligible: false };
|
|
852
552
|
const terminalUserExplicitSendAction = terminalUserExplicitSendAuthority.eligible
|
|
853
553
|
? {
|
|
854
554
|
tool: "agent_knock_knock_send",
|
|
@@ -865,25 +565,26 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
865
565
|
: {})
|
|
866
566
|
}
|
|
867
567
|
: undefined;
|
|
868
|
-
const
|
|
568
|
+
const modelControlFacts = modelControlPolicyFacts({
|
|
569
|
+
subject: actionSubject,
|
|
570
|
+
facts
|
|
571
|
+
});
|
|
572
|
+
const modelControlAvailability = materializeModelControlAvailability({
|
|
573
|
+
...modelControlFacts,
|
|
574
|
+
nativeAuthority: modelControlFacts.nativeAuthority.kind ===
|
|
575
|
+
"exact_session" && lifecycleBindingToken
|
|
576
|
+
? {
|
|
577
|
+
kind: "exact_session",
|
|
578
|
+
ordinaryBindingToken: lifecycleBindingToken
|
|
579
|
+
}
|
|
580
|
+
: modelControlFacts.nativeAuthority.kind === "verified_zero_rollout"
|
|
581
|
+
? { kind: "verified_zero_rollout" }
|
|
582
|
+
: { kind: "unavailable" }
|
|
583
|
+
}, actionDecisions.modelControl);
|
|
584
|
+
const modelControlActions = renderTerminalModelControlActions({
|
|
869
585
|
renderedActions,
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
terminalControl,
|
|
873
|
-
session,
|
|
874
|
-
physicalProcessIncarnation,
|
|
875
|
-
agentVersion,
|
|
876
|
-
modelControlCapability,
|
|
877
|
-
nativeIdentityObservation,
|
|
878
|
-
authorityNativeIdentityObservation,
|
|
879
|
-
nativeAgentIdentity,
|
|
880
|
-
codexOpenRootRolloutInventory,
|
|
881
|
-
modelControlResidual,
|
|
882
|
-
effectiveTerminalState: projectedTerminalState,
|
|
883
|
-
automatedInputComposerReady,
|
|
884
|
-
terminalHasInteraction: terminalStatusSnapshot?.interaction_state !== undefined,
|
|
885
|
-
terminalHasBlockingTurn,
|
|
886
|
-
hasOrphanedDispatch: orphanedDispatch !== undefined
|
|
586
|
+
availability: modelControlAvailability,
|
|
587
|
+
mutationScope: modelControlCapability.scope
|
|
887
588
|
});
|
|
888
589
|
const foregroundIdentificationActions = terminalUserExplicitSendAuthority.eligible &&
|
|
889
590
|
commands.identify_foreground === true
|
|
@@ -922,172 +623,112 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
|
|
|
922
623
|
}
|
|
923
624
|
};
|
|
924
625
|
}
|
|
925
|
-
function
|
|
926
|
-
const
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
zeroRolloutVerified: input.session.agent === "codex" &&
|
|
942
|
-
input.nativeIdentityObservation.status === "verified_absent" &&
|
|
943
|
-
input.authorityNativeIdentityObservation.status === "verified_absent" &&
|
|
944
|
-
input.codexOpenRootRolloutInventory?.status === "verified_absent" &&
|
|
945
|
-
input.codexOpenRootRolloutInventory.pid === input.session.pid &&
|
|
946
|
-
input.codexOpenRootRolloutInventory.roots.length === 0 &&
|
|
947
|
-
input.codexOpenRootRolloutInventory.processBirth ===
|
|
948
|
-
input.physicalProcessIncarnation?.processBirth,
|
|
949
|
-
modelControlSupported: input.modelControlCapability.status === "supported" &&
|
|
950
|
-
input.modelControlCapability.modelSelection === true &&
|
|
951
|
-
input.modelControlCapability.reasoningEffortSelection === true,
|
|
952
|
-
activityState: input.effectiveTerminalState.activity_state,
|
|
953
|
-
screenState: input.effectiveTerminalState.screen_state,
|
|
954
|
-
approvalScanned: input.effectiveTerminalState.approval_state.scanned === true,
|
|
955
|
-
approvalBlocked: input.effectiveTerminalState.approval_state.blocked === true,
|
|
956
|
-
automatedInputComposerReady: input.automatedInputComposerReady,
|
|
957
|
-
terminalHasInteraction: input.terminalHasInteraction,
|
|
958
|
-
terminalHasBlockingTurn: input.terminalHasBlockingTurn,
|
|
959
|
-
hasOrphanedDispatch: input.hasOrphanedDispatch
|
|
960
|
-
});
|
|
961
|
-
const hasExactCodexIdentity = input.session.agent === "codex" &&
|
|
962
|
-
isExactNativeThreadId(input.nativeAgentIdentity?.sessionId);
|
|
963
|
-
if (input.session.agent === "codex" && !hasExactCodexIdentity) {
|
|
964
|
-
delete actions.model_options;
|
|
965
|
-
}
|
|
966
|
-
if (authority.eligible) {
|
|
967
|
-
actions.model_options = {
|
|
968
|
-
tool: "agent_knock_knock_model_options",
|
|
969
|
-
arguments: {
|
|
970
|
-
terminal_id: authority.terminalId,
|
|
971
|
-
expected_binding_token: authority.expectedBindingToken
|
|
972
|
-
},
|
|
973
|
-
authority_scope: "terminal_user_explicit_model_control",
|
|
974
|
-
mutation_scope: input.modelControlCapability.scope,
|
|
975
|
-
requires_user_intent: true
|
|
976
|
-
};
|
|
977
|
-
}
|
|
978
|
-
const residual = input.modelControlResidual?.state === "recoverable"
|
|
979
|
-
? input.modelControlResidual
|
|
980
|
-
: undefined;
|
|
981
|
-
const repairAuthority = decideTerminalUserExplicitModelControlRepairAuthority({
|
|
982
|
-
exactTerminalRow: true,
|
|
983
|
-
terminalId: input.terminalId,
|
|
984
|
-
processState: input.processState,
|
|
985
|
-
terminalControl: input.terminalControl,
|
|
986
|
-
agent: input.session.agent,
|
|
987
|
-
pid: input.session.pid,
|
|
988
|
-
processUuid: input.physicalProcessIncarnation?.processUuid,
|
|
989
|
-
processBirth: input.physicalProcessIncarnation?.processBirth,
|
|
990
|
-
agentVersion: input.agentVersion,
|
|
991
|
-
behaviorProfile: input.modelControlCapability.behaviorProfile ===
|
|
992
|
-
"codex-model-control-0.154.0"
|
|
993
|
-
? input.modelControlCapability.behaviorProfile
|
|
994
|
-
: undefined,
|
|
995
|
-
nativeIdentityEligible: hasExactCodexIdentity || authority.eligible ||
|
|
996
|
-
(input.session.agent === "codex" &&
|
|
997
|
-
input.nativeIdentityObservation.status === "verified_absent" &&
|
|
998
|
-
input.authorityNativeIdentityObservation.status === "verified_absent" &&
|
|
999
|
-
input.codexOpenRootRolloutInventory?.status === "verified_absent" &&
|
|
1000
|
-
input.codexOpenRootRolloutInventory.pid === input.session.pid &&
|
|
1001
|
-
input.codexOpenRootRolloutInventory.roots.length === 0 &&
|
|
1002
|
-
input.codexOpenRootRolloutInventory.processBirth ===
|
|
1003
|
-
input.physicalProcessIncarnation?.processBirth),
|
|
1004
|
-
modelControlSupported: input.modelControlCapability.status === "supported" &&
|
|
1005
|
-
input.modelControlCapability.modelSelection === true &&
|
|
1006
|
-
input.modelControlCapability.reasoningEffortSelection === true,
|
|
1007
|
-
activityState: input.effectiveTerminalState.activity_state,
|
|
1008
|
-
approvalScanned: input.effectiveTerminalState.approval_state.scanned === true,
|
|
1009
|
-
approvalBlocked: input.effectiveTerminalState.approval_state.blocked === true,
|
|
1010
|
-
terminalHasInteraction: input.terminalHasInteraction,
|
|
1011
|
-
terminalHasBlockingTurn: input.terminalHasBlockingTurn,
|
|
1012
|
-
hasOrphanedDispatch: input.hasOrphanedDispatch,
|
|
1013
|
-
residualKind: residual?.kind,
|
|
1014
|
-
residualFingerprint: residual?.fingerprint
|
|
1015
|
-
});
|
|
1016
|
-
const residualEntryAuthority = decideTerminalUserExplicitModelControlResidualEntryAuthority({
|
|
1017
|
-
exactTerminalRow: true,
|
|
1018
|
-
terminalId: input.terminalId,
|
|
1019
|
-
processState: input.processState,
|
|
1020
|
-
terminalControl: input.terminalControl,
|
|
1021
|
-
agent: input.session.agent,
|
|
1022
|
-
pid: input.session.pid,
|
|
1023
|
-
processUuid: input.physicalProcessIncarnation?.processUuid,
|
|
1024
|
-
processBirth: input.physicalProcessIncarnation?.processBirth,
|
|
1025
|
-
agentVersion: input.agentVersion,
|
|
1026
|
-
behaviorProfile: input.modelControlCapability.behaviorProfile ===
|
|
1027
|
-
"codex-model-control-0.154.0"
|
|
1028
|
-
? input.modelControlCapability.behaviorProfile
|
|
1029
|
-
: undefined,
|
|
1030
|
-
nativeIdentityEligible: hasExactCodexIdentity || authority.eligible ||
|
|
1031
|
-
(input.session.agent === "codex" &&
|
|
1032
|
-
input.nativeIdentityObservation.status === "verified_absent" &&
|
|
1033
|
-
input.authorityNativeIdentityObservation.status === "verified_absent" &&
|
|
1034
|
-
input.codexOpenRootRolloutInventory?.status === "verified_absent" &&
|
|
1035
|
-
input.codexOpenRootRolloutInventory.pid === input.session.pid &&
|
|
1036
|
-
input.codexOpenRootRolloutInventory.roots.length === 0 &&
|
|
1037
|
-
input.codexOpenRootRolloutInventory.processBirth ===
|
|
1038
|
-
input.physicalProcessIncarnation?.processBirth),
|
|
1039
|
-
modelControlSupported: input.modelControlCapability.status === "supported" &&
|
|
1040
|
-
input.modelControlCapability.modelSelection === true &&
|
|
1041
|
-
input.modelControlCapability.reasoningEffortSelection === true,
|
|
1042
|
-
activityState: input.effectiveTerminalState.activity_state,
|
|
1043
|
-
approvalScanned: input.effectiveTerminalState.approval_state.scanned === true,
|
|
1044
|
-
approvalBlocked: input.effectiveTerminalState.approval_state.blocked === true,
|
|
1045
|
-
terminalHasInteraction: input.terminalHasInteraction,
|
|
1046
|
-
terminalHasBlockingTurn: input.terminalHasBlockingTurn,
|
|
1047
|
-
hasOrphanedDispatch: input.hasOrphanedDispatch,
|
|
1048
|
-
residualKind: residual?.kind,
|
|
1049
|
-
residualFingerprint: residual?.fingerprint
|
|
626
|
+
async function collectTerminalFactsForList(session, activeSessions, options, bridge, terminalControl) {
|
|
627
|
+
const terminalId = bridge.terminalConversationId(session);
|
|
628
|
+
const adapter = bridge.registry.require(session.agent);
|
|
629
|
+
return collectTerminalListTerminalFacts({
|
|
630
|
+
session,
|
|
631
|
+
terminalControl,
|
|
632
|
+
terminalId,
|
|
633
|
+
childPids: childProcessIdsForRoot(session, activeSessions),
|
|
634
|
+
adapter,
|
|
635
|
+
ports: terminalListFactPortsFor({
|
|
636
|
+
session,
|
|
637
|
+
terminalControl,
|
|
638
|
+
terminalId,
|
|
639
|
+
options,
|
|
640
|
+
bridge
|
|
641
|
+
})
|
|
1050
642
|
});
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
643
|
+
}
|
|
644
|
+
function terminalListFactPortsFor(input) {
|
|
645
|
+
const { session, terminalControl, terminalId, options, bridge } = input;
|
|
646
|
+
return {
|
|
647
|
+
observeStatus: (agentVersion) => listStateForTerminal(session.agent, terminalControl, options, bridge, {
|
|
648
|
+
pid: session.pid, agentVersion,
|
|
649
|
+
cwd: session.cwd,
|
|
650
|
+
// Status and approval share this exact full terminal identity.
|
|
651
|
+
...(session.agent === "codex"
|
|
652
|
+
? { conversationId: terminalId }
|
|
653
|
+
: { sessionId: session.sessionId }),
|
|
654
|
+
terminalTarget: terminalControl.target
|
|
655
|
+
}),
|
|
656
|
+
observeNativeIdentity: (observedTerminalId) => observeTerminalNativeListIdentity(session, terminalControl, options, bridge, observedTerminalId),
|
|
657
|
+
projectEffectiveState: ({ terminalState, native }) => effectiveTerminalListState({
|
|
658
|
+
session,
|
|
659
|
+
terminalState,
|
|
660
|
+
nativeIdentityObservation: native.nativeIdentityObservation,
|
|
661
|
+
nativeAgentIdentity: native.nativeAgentIdentity,
|
|
662
|
+
nativeIdentityAuthorityObservation: native.authorityNativeIdentityObservation,
|
|
663
|
+
codexOpenRootRolloutInventory: native.codexOpenRootRolloutInventory,
|
|
664
|
+
nativeProcessUuid: native.nativeProcessUuid,
|
|
665
|
+
nativeProcessBirth: native.nativeProcessBirth
|
|
666
|
+
}),
|
|
667
|
+
observeAgentVersion: () => terminalListRuntime().agentVersionForRunningProcess(session.agent, session.pid, options),
|
|
668
|
+
observeTerminalHasBlockingTurn: () => observeTerminalHasBlockingTurnForList(options, terminalControl),
|
|
669
|
+
observeComposer: (terminalState) => observeAutomatedInputComposerReady({
|
|
670
|
+
session,
|
|
671
|
+
terminalControl,
|
|
672
|
+
terminalState,
|
|
673
|
+
options
|
|
674
|
+
}),
|
|
675
|
+
observePhysicalProcessIncarnation: () => observePhysicalProcessIncarnationForList(session, terminalControl),
|
|
676
|
+
observeLatentClearResume: (request) => terminalListRuntime().codexLatentClearResumeObservation(request),
|
|
677
|
+
observeModelControlResidual: ({ agentVersion, modelControlCapability, modelControlProfile, native, zeroRolloutVerified, effectiveTerminalState, terminalHasInteraction, terminalHasBlockingTurn, hasOrphanedDispatch }) => observeModelControlResidualForList({
|
|
678
|
+
bridge,
|
|
679
|
+
session,
|
|
680
|
+
terminalControl,
|
|
681
|
+
agentVersion,
|
|
682
|
+
modelControlCapability,
|
|
683
|
+
modelControlProfile,
|
|
684
|
+
nativeAgentIdentity: native.nativeAgentIdentity,
|
|
685
|
+
zeroRolloutVerified,
|
|
686
|
+
nativeIdentityEligible: (session.agent === "codex" &&
|
|
687
|
+
isExactNativeThreadId(native.nativeAgentIdentity?.sessionId)) ||
|
|
688
|
+
zeroRolloutVerified,
|
|
689
|
+
effectiveTerminalState,
|
|
690
|
+
terminalHasInteraction,
|
|
691
|
+
terminalHasBlockingTurn,
|
|
692
|
+
hasOrphanedDispatch
|
|
693
|
+
}),
|
|
694
|
+
projectStatusSnapshot: terminalBridgeStatusWithProjection
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
function observeTerminalHasBlockingTurnForList(options, terminalControl) {
|
|
698
|
+
try {
|
|
699
|
+
return terminalIncarnationBlockingTurns(terminalListRuntime().storeDirFromOptions(options), terminalControl).length > 0;
|
|
1062
700
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
701
|
+
catch (error) {
|
|
702
|
+
runtimeLog("warn", "terminal_managed_turn_inventory_unavailable", {
|
|
703
|
+
terminal_target: terminalControl.target,
|
|
704
|
+
error: error instanceof Error ? error.message : String(error)
|
|
705
|
+
});
|
|
706
|
+
return true;
|
|
1065
707
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
terminal_id: repairAuthority.terminalId,
|
|
1071
|
-
expected_binding_token: repairAuthority.expectedBindingToken
|
|
1072
|
-
},
|
|
1073
|
-
authority_scope: "terminal_user_explicit_model_control_repair",
|
|
1074
|
-
mutation_scope: "exact_model_control_residual_only",
|
|
1075
|
-
requires_user_intent: true
|
|
1076
|
-
};
|
|
708
|
+
}
|
|
709
|
+
function observePhysicalProcessIncarnationForList(session, terminalControl) {
|
|
710
|
+
try {
|
|
711
|
+
return terminalListRuntime().processIncarnationForPid(session.pid);
|
|
1077
712
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
713
|
+
catch (error) {
|
|
714
|
+
runtimeLog("warn", "terminal_physical_process_incarnation_unavailable", {
|
|
715
|
+
agent: session.agent,
|
|
716
|
+
terminal_target: terminalControl.target,
|
|
717
|
+
pid: session.pid,
|
|
718
|
+
error: error instanceof Error ? error.message : String(error)
|
|
719
|
+
});
|
|
720
|
+
return undefined;
|
|
1080
721
|
}
|
|
1081
|
-
return actions;
|
|
1082
722
|
}
|
|
1083
723
|
async function observeModelControlResidualForList(input) {
|
|
1084
724
|
const inspect = input.bridge.inspectModelControlResidual;
|
|
725
|
+
const profile = input.modelControlProfile;
|
|
1085
726
|
if (typeof inspect !== "function" ||
|
|
1086
727
|
input.session.agent !== "codex" ||
|
|
1087
|
-
|
|
728
|
+
!profile?.supportsResidualRepair ||
|
|
1088
729
|
input.modelControlCapability.status !== "supported" ||
|
|
1089
730
|
input.modelControlCapability.behaviorProfile !==
|
|
1090
|
-
|
|
731
|
+
profile.behaviorProfile ||
|
|
1091
732
|
!input.nativeIdentityEligible ||
|
|
1092
733
|
input.effectiveTerminalState.activity_state === "working" ||
|
|
1093
734
|
input.effectiveTerminalState.activity_state === "awaiting_approval" ||
|
|
@@ -1099,11 +740,14 @@ async function observeModelControlResidualForList(input) {
|
|
|
1099
740
|
return undefined;
|
|
1100
741
|
}
|
|
1101
742
|
const adapter = input.bridge.registry.require("codex");
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
? adapter.planModelControl?.(capability)
|
|
743
|
+
const plan = input.modelControlCapability.status === "supported"
|
|
744
|
+
? adapter.planModelControl?.(input.modelControlCapability)
|
|
1105
745
|
: undefined;
|
|
1106
|
-
if (!plan ||
|
|
746
|
+
if (!plan || !terminalModelControlPlanConforms({
|
|
747
|
+
agent: input.session.agent,
|
|
748
|
+
agentVersion: input.agentVersion,
|
|
749
|
+
plan
|
|
750
|
+
})) {
|
|
1107
751
|
return undefined;
|
|
1108
752
|
}
|
|
1109
753
|
const identity = input.nativeAgentIdentity;
|
|
@@ -1135,7 +779,7 @@ async function observeModelControlResidualForList(input) {
|
|
|
1135
779
|
: {})
|
|
1136
780
|
};
|
|
1137
781
|
try {
|
|
1138
|
-
return await inspect.call(input.bridge, "codex", input.terminalControl,
|
|
782
|
+
return await inspect.call(input.bridge, "codex", input.terminalControl, profile.agentVersion, plan, { runtime, beforeInput: () => undefined });
|
|
1139
783
|
}
|
|
1140
784
|
catch (error) {
|
|
1141
785
|
runtimeLog("warn", "terminal_model_control_residual_probe_unavailable", {
|
|
@@ -1145,81 +789,6 @@ async function observeModelControlResidualForList(input) {
|
|
|
1145
789
|
return undefined;
|
|
1146
790
|
}
|
|
1147
791
|
}
|
|
1148
|
-
function terminalListCommands(input) {
|
|
1149
|
-
const { agent, terminalControl, terminalState, lifecycleCapability, nativeInspectionCapability, modelControlCapability, nativeAgentIdentity, nativeProcessUuid, nativeProcessBirth, codexLifecycleIncarnationAvailable, automatedInputComposerReady, hasOrphanedDispatch, terminalHasBlockingTurn, terminalHasInteraction } = input;
|
|
1150
|
-
const foregroundIdentificationEligible = agent === "codex" &&
|
|
1151
|
-
nativeInspectionCapability.status === "supported" &&
|
|
1152
|
-
nativeInspectionCapability.statusInspection === true &&
|
|
1153
|
-
terminalState.screen_state === "idle" &&
|
|
1154
|
-
terminalState.native_identity_state !== "resolved" &&
|
|
1155
|
-
terminalState.approval_state.scanned === true &&
|
|
1156
|
-
terminalState.approval_state.blocked !== true &&
|
|
1157
|
-
automatedInputComposerReady &&
|
|
1158
|
-
codexLifecycleIncarnationAvailable &&
|
|
1159
|
-
terminalControl.capabilities.includes("send_keys") &&
|
|
1160
|
-
terminalControl.capabilities.includes("screen_status") &&
|
|
1161
|
-
!terminalHasInteraction &&
|
|
1162
|
-
!hasOrphanedDispatch &&
|
|
1163
|
-
!terminalHasBlockingTurn;
|
|
1164
|
-
return {
|
|
1165
|
-
send: !terminalHasBlockingTurn,
|
|
1166
|
-
approve: terminalControl.capabilities.includes("terminal_approval") &&
|
|
1167
|
-
terminalState.approval_state.approvable === true,
|
|
1168
|
-
status: true,
|
|
1169
|
-
cancel: terminalControl.capabilities.includes("terminal_cancel"),
|
|
1170
|
-
close: hasOrphanedDispatch,
|
|
1171
|
-
new_thread: lifecycleCapability.status === "supported" &&
|
|
1172
|
-
lifecycleCapability.newThread === true &&
|
|
1173
|
-
codexLifecycleIncarnationAvailable &&
|
|
1174
|
-
!terminalHasBlockingTurn,
|
|
1175
|
-
list_resumable_threads: lifecycleCapability.status === "supported" &&
|
|
1176
|
-
lifecycleCapability.resumeExact === true &&
|
|
1177
|
-
codexLifecycleIncarnationAvailable,
|
|
1178
|
-
native_inspect: nativeInspectionCapability.status === "supported" &&
|
|
1179
|
-
nativeInspectionCapability.statusInspection === true &&
|
|
1180
|
-
terminalState.activity_state === "idle" &&
|
|
1181
|
-
automatedInputComposerReady &&
|
|
1182
|
-
terminalControl.capabilities.includes("send_keys") &&
|
|
1183
|
-
terminalControl.capabilities.includes("screen_status") &&
|
|
1184
|
-
(agent === "codex"
|
|
1185
|
-
? codexLifecycleIncarnationAvailable
|
|
1186
|
-
: Boolean(nativeAgentIdentity?.sessionId &&
|
|
1187
|
-
nativeAgentIdentity.processUuid)) &&
|
|
1188
|
-
!hasOrphanedDispatch &&
|
|
1189
|
-
!terminalHasBlockingTurn,
|
|
1190
|
-
model_options: modelControlCapability.status === "supported" &&
|
|
1191
|
-
modelControlCapability.modelSelection === true &&
|
|
1192
|
-
modelControlCapability.reasoningEffortSelection === true &&
|
|
1193
|
-
terminalState.activity_state === "idle" &&
|
|
1194
|
-
terminalState.approval_state.scanned === true &&
|
|
1195
|
-
terminalState.approval_state.blocked !== true &&
|
|
1196
|
-
automatedInputComposerReady &&
|
|
1197
|
-
terminalControl.capabilities.includes("send_keys") &&
|
|
1198
|
-
terminalControl.capabilities.includes("screen_status") &&
|
|
1199
|
-
(agent === "codex"
|
|
1200
|
-
? codexLifecycleIncarnationAvailable
|
|
1201
|
-
: Boolean(nativeAgentIdentity?.sessionId &&
|
|
1202
|
-
nativeAgentIdentity.processUuid)) &&
|
|
1203
|
-
!terminalHasInteraction &&
|
|
1204
|
-
!hasOrphanedDispatch &&
|
|
1205
|
-
!terminalHasBlockingTurn,
|
|
1206
|
-
identify_foreground: foregroundIdentificationEligible,
|
|
1207
|
-
identify_and_send: foregroundIdentificationEligible,
|
|
1208
|
-
watch: terminalControl.capabilities.includes("screen_status") ||
|
|
1209
|
-
Boolean(nativeAgentIdentity?.sessionId &&
|
|
1210
|
-
(agent !== "codex" || nativeAgentIdentity.rollout))
|
|
1211
|
-
};
|
|
1212
|
-
}
|
|
1213
|
-
function terminalListStateWithOpenModelControlSurface(state) {
|
|
1214
|
-
const reason = "an exact native model-control surface is open";
|
|
1215
|
-
return {
|
|
1216
|
-
...state,
|
|
1217
|
-
activity_state: "unknown",
|
|
1218
|
-
activity_reason: reason,
|
|
1219
|
-
screen_state: "unknown",
|
|
1220
|
-
screen_reason: reason
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
792
|
function effectiveTerminalListState(input) {
|
|
1224
793
|
const { session, terminalState, nativeIdentityObservation, nativeAgentIdentity, nativeIdentityAuthorityObservation, codexOpenRootRolloutInventory, nativeProcessUuid, nativeProcessBirth } = input;
|
|
1225
794
|
const nativeIdentityState = terminalNativeIdentityState({
|
|
@@ -1381,7 +950,7 @@ function terminalBridgeStatusWithProjection(status, projection) {
|
|
|
1381
950
|
}
|
|
1382
951
|
return Object.create(Object.getPrototypeOf(status), descriptors);
|
|
1383
952
|
}
|
|
1384
|
-
async function observeTerminalNativeListIdentity(session, terminalControl, options, bridge) {
|
|
953
|
+
async function observeTerminalNativeListIdentity(session, terminalControl, options, bridge, terminalId) {
|
|
1385
954
|
let orphanedDispatch;
|
|
1386
955
|
try {
|
|
1387
956
|
orphanedDispatch =
|
|
@@ -1399,7 +968,7 @@ async function observeTerminalNativeListIdentity(session, terminalControl, optio
|
|
|
1399
968
|
codexIdentityContext = terminalListRuntime().codexManagedIdentityResolutionContext({
|
|
1400
969
|
storeDir: terminalListRuntime().storeDirFromOptions(options),
|
|
1401
970
|
terminal: {
|
|
1402
|
-
conversationId:
|
|
971
|
+
conversationId: terminalId,
|
|
1403
972
|
agent: session.agent,
|
|
1404
973
|
pid: session.pid,
|
|
1405
974
|
terminalControl
|
|
@@ -1570,1197 +1139,41 @@ async function observeAutomatedInputComposerReady({ session, terminalControl, te
|
|
|
1570
1139
|
userExplicitComposerReady: userExplicitReady
|
|
1571
1140
|
};
|
|
1572
1141
|
}
|
|
1573
|
-
function observeTerminalListBindingAuthority(listedTerminal, context) {
|
|
1574
|
-
const { storeDir, managedSessions, allConversations, displayedConversations, mutationsAllowed, nonterminalDeferredTransfers } = context;
|
|
1575
|
-
const { _automated_input_composer_ready: automatedInputComposerReady, _user_explicit_composer_ready: _userExplicitComposerReady, _codex_open_root_rollout_inventory: codexOpenRootRolloutInventoryValue, _codex_latent_clear_resume: codexLatentClearResumeValue, _terminal_user_explicit_send_action: terminalUserExplicitSendAction, _terminal_status_snapshot: _terminalStatusSnapshot, _native_identity_authority: nativeIdentityAuthorityValue, ...publicTerminal } = listedTerminal;
|
|
1576
|
-
const terminal = terminalIdentityAuthorityView(listedTerminal, nativeIdentityAuthorityValue);
|
|
1577
|
-
const codexOpenRootRolloutInventory = isRecord(codexOpenRootRolloutInventoryValue)
|
|
1578
|
-
? codexOpenRootRolloutInventoryValue
|
|
1579
|
-
: undefined;
|
|
1580
|
-
const terminalControl = isRecord(terminal.terminal_control)
|
|
1581
|
-
? terminal.terminal_control
|
|
1582
|
-
: undefined;
|
|
1583
|
-
const terminalHasNonterminalDeferredTransfer = Boolean(terminalControl && nonterminalDeferredTransfers.some((transfer) => transfer.terminal_id === String(terminal.id) &&
|
|
1584
|
-
transfer.process_pid === Number(terminal.pid) &&
|
|
1585
|
-
terminalControlEvidenceMatches(transfer.terminal_endpoint, terminalControl)));
|
|
1586
|
-
const allRelated = terminalControl
|
|
1587
|
-
? allConversations.filter((conversation) => terminalControlsShareIncarnation(terminalControlForManagedConversation(conversation), terminalControl))
|
|
1588
|
-
: [];
|
|
1589
|
-
const displayedRelated = terminalControl
|
|
1590
|
-
? displayedConversations.filter((conversation) => terminalControlsShareIncarnation(terminalControlForManagedConversation(conversation), terminalControl))
|
|
1591
|
-
: [];
|
|
1592
|
-
const relatedSessions = terminalControl
|
|
1593
|
-
? managedSessions.filter((session) => terminalControlsShareIncarnation(session.binding?.terminal_control, terminalControl))
|
|
1594
|
-
: [];
|
|
1595
|
-
const matchingSessions = relatedSessions.filter((session) => managedSessionMatchesLiveTerminalEntry(session, terminal, storeDir));
|
|
1596
|
-
const conflictingBoundSessionClaims = relatedSessions.flatMap((session) => {
|
|
1597
|
-
const kind = managedBindingConflictKindForLiveTerminalEntry({
|
|
1598
|
-
storeDir,
|
|
1599
|
-
session,
|
|
1600
|
-
terminal
|
|
1601
|
-
});
|
|
1602
|
-
return kind && kind !== "stale_process_incarnation"
|
|
1603
|
-
? [{ session, kind }]
|
|
1604
|
-
: [];
|
|
1605
|
-
});
|
|
1606
|
-
const unresolvedSessionClaims = relatedSessions.filter((session) => ["transitioning", "quarantined"].includes(session.status) &&
|
|
1607
|
-
managedSessionClaimsLiveTerminalEntry(session, terminal));
|
|
1608
|
-
const sessionAuthorityConflict = decideTerminalSessionAuthorityConflict({
|
|
1609
|
-
unresolvedSessionClaims,
|
|
1610
|
-
conflictingBoundSessionClaims,
|
|
1611
|
-
matchingSessions
|
|
1612
|
-
});
|
|
1613
|
-
const authoritativeSession = matchingSessions[0];
|
|
1614
|
-
const discoveredOwnership = terminalControl
|
|
1615
|
-
? terminalDispatchOwnership(terminalControl)
|
|
1616
|
-
: { state: "none" };
|
|
1617
|
-
const localOwnership = discoveredOwnership.state === "current"
|
|
1618
|
-
? localTerminalDispatchOwnership(discoveredOwnership.conversation, allRelated, terminal)
|
|
1619
|
-
: discoveredOwnership;
|
|
1620
|
-
const dispatchOwnerMismatch = !sessionAuthorityConflict &&
|
|
1621
|
-
localOwnership.state === "current" &&
|
|
1622
|
-
authoritativeSession &&
|
|
1623
|
-
sessionIdForConversation(localOwnership.conversation) !==
|
|
1624
|
-
authoritativeSession.session_id
|
|
1625
|
-
? {
|
|
1626
|
-
ownerSessionId: sessionIdForConversation(discoveredOwnership.state === "current"
|
|
1627
|
-
? discoveredOwnership.conversation
|
|
1628
|
-
: localOwnership.conversation)
|
|
1629
|
-
}
|
|
1630
|
-
: undefined;
|
|
1631
|
-
const ownership = applySessionAuthorityToDispatch({
|
|
1632
|
-
localOwnership,
|
|
1633
|
-
sessionAuthorityConflict,
|
|
1634
|
-
authoritativeSession,
|
|
1635
|
-
dispatchOwnerMismatch
|
|
1636
|
-
});
|
|
1637
|
-
const discoveredRawActions = isRecord(terminal.available_actions)
|
|
1638
|
-
? terminal.available_actions
|
|
1639
|
-
: {};
|
|
1640
|
-
const rawActions = mutationsAllowed
|
|
1641
|
-
? discoveredRawActions
|
|
1642
|
-
: readOnlyListActions(discoveredRawActions);
|
|
1643
|
-
const rawSendAction = isRecord(rawActions.send)
|
|
1644
|
-
? rawActions.send
|
|
1645
|
-
: {};
|
|
1646
|
-
const bindingAwareRawActions = authoritativeSession
|
|
1647
|
-
? actionsForManagedSessionBinding(rawActions, authoritativeSession)
|
|
1648
|
-
: rawActions;
|
|
1649
|
-
const sessionAwareRawActionsBase = authoritativeSession &&
|
|
1650
|
-
managedSessionHasUnresolvedNativeTransition(storeDir, authoritativeSession)
|
|
1651
|
-
? withoutInspectionActionsDuringNativeTransition(bindingAwareRawActions)
|
|
1652
|
-
: bindingAwareRawActions;
|
|
1653
|
-
const sessionAwareRawActions = terminalHasNonterminalDeferredTransfer
|
|
1654
|
-
? readOnlyListActions(sessionAwareRawActionsBase)
|
|
1655
|
-
: sessionAwareRawActionsBase;
|
|
1656
|
-
const soleBindingConflict = conflictingBoundSessionClaims.length === 1
|
|
1657
|
-
? conflictingBoundSessionClaims[0]
|
|
1658
|
-
: undefined;
|
|
1659
|
-
const externalHandoffDetected = conflictingBoundSessionClaims.some(({ kind }) => kind === "live_external_thread_change");
|
|
1660
|
-
const conflictingSessionRevision = Number(soleBindingConflict?.session.revision);
|
|
1661
|
-
const conflictingSessionTurns = soleBindingConflict
|
|
1662
|
-
? terminalListRuntime().managedTurnsForSession(storeDir, soleBindingConflict.session.session_id)
|
|
1663
|
-
: [];
|
|
1664
|
-
const expectedTerminalToken = stringValue(terminal.lifecycle_binding_token);
|
|
1665
|
-
const externalHandoffNativeThreadId = stringValue(terminal.native_agent_status_card_session_id) ?? stringValue(terminal.native_agent_session_id);
|
|
1666
|
-
const resolvedNativeThreadId = stringValue(terminal.native_agent_session_id);
|
|
1667
|
-
const externalHandoffTerminalToken = terminalControl &&
|
|
1668
|
-
externalHandoffNativeThreadId &&
|
|
1669
|
-
isExactNativeThreadId(externalHandoffNativeThreadId)
|
|
1670
|
-
? unmanagedTerminalBindingToken({
|
|
1671
|
-
terminalId: stringValue(terminal.id),
|
|
1672
|
-
terminalControl,
|
|
1673
|
-
agent: terminal.agent,
|
|
1674
|
-
pid: Number(terminal.pid),
|
|
1675
|
-
workspace: terminal.workspace ?? terminal.cwd ?? cliCwd(),
|
|
1676
|
-
nativeThreadId: externalHandoffNativeThreadId,
|
|
1677
|
-
processUuid: stringValue(terminal.native_agent_process_uuid),
|
|
1678
|
-
processBirth: stringValue(terminal.native_agent_process_birth),
|
|
1679
|
-
rollout: resolvedNativeThreadId === externalHandoffNativeThreadId &&
|
|
1680
|
-
isRecord(terminal.native_agent_rollout)
|
|
1681
|
-
? terminal.native_agent_rollout
|
|
1682
|
-
: undefined
|
|
1683
|
-
})
|
|
1684
|
-
: undefined;
|
|
1685
|
-
const externalHandoffTarget = soleBindingConflict?.kind === "live_external_thread_change" &&
|
|
1686
|
-
externalHandoffNativeThreadId &&
|
|
1687
|
-
isExactNativeThreadId(externalHandoffNativeThreadId)
|
|
1688
|
-
? terminalListRuntime().observedHandoffTargetResolution({
|
|
1689
|
-
storeDir,
|
|
1690
|
-
agent: terminal.agent,
|
|
1691
|
-
workspace: terminal.workspace ?? terminal.cwd ?? cliCwd(),
|
|
1692
|
-
nativeThreadId: externalHandoffNativeThreadId.toLowerCase(),
|
|
1693
|
-
sourceSessionId: soleBindingConflict.session.session_id
|
|
1694
|
-
})
|
|
1695
|
-
: undefined;
|
|
1696
|
-
const externalHandoffSnapshotToken = externalHandoffTerminalToken &&
|
|
1697
|
-
soleBindingConflict?.kind === "live_external_thread_change" &&
|
|
1698
|
-
externalHandoffTarget?.status === "eligible"
|
|
1699
|
-
? humanObservedHandoffBindingToken({
|
|
1700
|
-
terminal_token: externalHandoffTerminalToken,
|
|
1701
|
-
source_session_id: soleBindingConflict.session.session_id,
|
|
1702
|
-
source_revision: managedSessionRevision(soleBindingConflict.session),
|
|
1703
|
-
source_binding_token: managedSessionBindingToken(soleBindingConflict.session),
|
|
1704
|
-
target: externalHandoffTarget.snapshot
|
|
1705
|
-
})
|
|
1706
|
-
: undefined;
|
|
1707
|
-
const blockingHandoffTurns = conflictingSessionTurns.filter((turn) => isSessionSendBlockingStatus(turn.status));
|
|
1708
|
-
const terminalBlockingTurns = terminalControl
|
|
1709
|
-
? terminalIncarnationBlockingTurns(storeDir, terminalControl, allRelated)
|
|
1710
|
-
: [];
|
|
1711
|
-
const externalHandoffSourceSessionIds = new Set(conflictingBoundSessionClaims
|
|
1712
|
-
.filter(({ kind }) => kind === "live_external_thread_change")
|
|
1713
|
-
.map(({ session }) => session.session_id));
|
|
1714
|
-
const handoffSourceBlockingTurns = terminalBlockingTurns.filter((turn) => externalHandoffSourceSessionIds.has(sessionIdForConversation(turn)));
|
|
1715
|
-
const nativeIdentityObservation = isRecord(terminal.native_agent_identity_observation)
|
|
1716
|
-
? terminal.native_agent_identity_observation
|
|
1717
|
-
: undefined;
|
|
1718
|
-
const codexProcessUuid = stringValue(terminal.native_agent_process_uuid);
|
|
1719
|
-
const codexProcessBirth = stringValue(terminal.native_agent_process_birth);
|
|
1720
|
-
const codexWorkspace = stringValue(terminal.workspace ?? terminal.cwd);
|
|
1721
|
-
const codexSendAuthorityContext = terminalControl
|
|
1722
|
-
? {
|
|
1723
|
-
terminalId: String(terminal.id),
|
|
1724
|
-
terminalControl,
|
|
1725
|
-
pid: Number(terminal.pid),
|
|
1726
|
-
workspace: codexWorkspace,
|
|
1727
|
-
liveProcessUuid: codexProcessUuid,
|
|
1728
|
-
liveProcessBirth: codexProcessBirth
|
|
1729
|
-
}
|
|
1730
|
-
: undefined;
|
|
1731
|
-
return {
|
|
1732
|
-
authorityTerminal: terminal,
|
|
1733
|
-
automatedInputComposerReady,
|
|
1734
|
-
codexOpenRootRolloutInventory,
|
|
1735
|
-
codexLatentClearResumeValue,
|
|
1736
|
-
terminalUserExplicitSendAction,
|
|
1737
|
-
publicTerminal,
|
|
1738
|
-
terminalControl,
|
|
1739
|
-
terminalHasNonterminalDeferredTransfer,
|
|
1740
|
-
allRelated,
|
|
1741
|
-
displayedRelated,
|
|
1742
|
-
relatedSessions,
|
|
1743
|
-
matchingSessions,
|
|
1744
|
-
conflictingBoundSessionClaims,
|
|
1745
|
-
unresolvedSessionClaims,
|
|
1746
|
-
sessionAuthorityConflict,
|
|
1747
|
-
authoritativeSession,
|
|
1748
|
-
discoveredOwnership,
|
|
1749
|
-
ownership,
|
|
1750
|
-
rawActions,
|
|
1751
|
-
rawSendAction,
|
|
1752
|
-
sessionAwareRawActions,
|
|
1753
|
-
soleBindingConflict,
|
|
1754
|
-
externalHandoffDetected,
|
|
1755
|
-
conflictingSessionRevision,
|
|
1756
|
-
conflictingSessionTurns,
|
|
1757
|
-
expectedTerminalToken,
|
|
1758
|
-
externalHandoffNativeThreadId,
|
|
1759
|
-
externalHandoffTarget,
|
|
1760
|
-
externalHandoffSnapshotToken,
|
|
1761
|
-
blockingHandoffTurns,
|
|
1762
|
-
terminalBlockingTurns,
|
|
1763
|
-
handoffSourceBlockingTurns,
|
|
1764
|
-
nativeIdentityObservation,
|
|
1765
|
-
codexProcessUuid,
|
|
1766
|
-
codexProcessBirth,
|
|
1767
|
-
codexWorkspace,
|
|
1768
|
-
codexSendAuthorityContext
|
|
1769
|
-
};
|
|
1770
|
-
}
|
|
1771
|
-
function terminalIdentityAuthorityView(terminal, authorityValue) {
|
|
1772
|
-
if (!isRecord(authorityValue)) {
|
|
1773
|
-
return terminal;
|
|
1774
|
-
}
|
|
1775
|
-
const observation = isRecord(authorityValue.observation)
|
|
1776
|
-
? authorityValue.observation
|
|
1777
|
-
: { status: "not_observed" };
|
|
1778
|
-
const identity = isRecord(authorityValue.identity)
|
|
1779
|
-
? authorityValue.identity
|
|
1780
|
-
: undefined;
|
|
1781
|
-
return {
|
|
1782
|
-
...terminal,
|
|
1783
|
-
native_agent_session_id: stringValue(identity?.sessionId),
|
|
1784
|
-
native_agent_rollout: isRecord(identity?.rollout)
|
|
1785
|
-
? identity.rollout
|
|
1786
|
-
: undefined,
|
|
1787
|
-
native_agent_identity_observation: observation,
|
|
1788
|
-
lifecycle_binding_token: stringValue(authorityValue.lifecycle_binding_token) ??
|
|
1789
|
-
terminal.lifecycle_binding_token
|
|
1790
|
-
};
|
|
1791
|
-
}
|
|
1792
|
-
function observeVerifiedEmptyTerminalAuthority(terminal, context, binding) {
|
|
1793
|
-
const { storeDir, terminals, mutationsAllowed } = context;
|
|
1794
|
-
const { automatedInputComposerReady, terminalControl, matchingSessions, unresolvedSessionClaims, discoveredOwnership, rawActions, soleBindingConflict, blockingHandoffTurns, terminalBlockingTurns, nativeIdentityObservation, codexProcessUuid, codexProcessBirth, codexWorkspace, codexSendAuthorityContext } = binding;
|
|
1795
|
-
const verifiedEmptySourceNativeThreadId = stringValue(soleBindingConflict?.session.binding?.native_thread_id)?.toLowerCase();
|
|
1796
|
-
const verifiedEmptySourceActiveElsewhere = Boolean(verifiedEmptySourceNativeThreadId &&
|
|
1797
|
-
terminals.some((candidate) => stringValue(candidate.id) !== stringValue(terminal.id) &&
|
|
1798
|
-
candidate.agent === "codex" &&
|
|
1799
|
-
stringValue(candidate.native_agent_session_id)?.toLowerCase() ===
|
|
1800
|
-
verifiedEmptySourceNativeThreadId));
|
|
1801
|
-
const verifiedEmptyRawSendAction = isRecord(rawActions.send)
|
|
1802
|
-
? rawActions.send
|
|
1803
|
-
: {
|
|
1804
|
-
tool: "agent_knock_knock_send",
|
|
1805
|
-
arguments: { selector: stringValue(terminal.id) },
|
|
1806
|
-
missing_required: ["request"]
|
|
1807
|
-
};
|
|
1808
|
-
const verifiedEmptyCodexHandoffEligible = Boolean(mutationsAllowed &&
|
|
1809
|
-
terminal.agent === "codex" &&
|
|
1810
|
-
terminalControl &&
|
|
1811
|
-
discoveredOwnership.state === "none" &&
|
|
1812
|
-
unresolvedSessionClaims.length === 0 &&
|
|
1813
|
-
matchingSessions.length === 0 &&
|
|
1814
|
-
soleBindingConflict?.kind === "unverifiable" &&
|
|
1815
|
-
nativeIdentityObservation?.status === "verified_absent" &&
|
|
1816
|
-
codexSendAuthorityContext &&
|
|
1817
|
-
codexProcessUuid &&
|
|
1818
|
-
codexProcessBirth &&
|
|
1819
|
-
codexWorkspace &&
|
|
1820
|
-
exactBoundCodexSendSource({
|
|
1821
|
-
kind: "verified_empty",
|
|
1822
|
-
sourceSession: soleBindingConflict.session,
|
|
1823
|
-
context: codexSendAuthorityContext
|
|
1824
|
-
}) &&
|
|
1825
|
-
["idle", "unknown"].includes(String(terminal.activity_state)) &&
|
|
1826
|
-
automatedInputComposerReady === true &&
|
|
1827
|
-
!(isRecord(terminal.approval_state) &&
|
|
1828
|
-
terminal.approval_state.blocked === true) &&
|
|
1829
|
-
blockingHandoffTurns.length === 0 &&
|
|
1830
|
-
terminalBlockingTurns.length === 0 &&
|
|
1831
|
-
!managedSessionHasUnresolvedNativeTransition(storeDir, soleBindingConflict.session) &&
|
|
1832
|
-
!verifiedEmptySourceActiveElsewhere &&
|
|
1833
|
-
terminal.orphaned_terminal_dispatch === undefined &&
|
|
1834
|
-
terminalControl?.capabilities.includes("send_keys") &&
|
|
1835
|
-
terminalControl.capabilities.includes("screen_status"));
|
|
1836
|
-
const verifiedEmptyCodexSnapshotToken = verifiedEmptyCodexHandoffEligible &&
|
|
1837
|
-
codexSendAuthorityContext &&
|
|
1838
|
-
soleBindingConflict &&
|
|
1839
|
-
codexProcessUuid &&
|
|
1840
|
-
codexProcessBirth &&
|
|
1841
|
-
codexWorkspace
|
|
1842
|
-
? verifiedEmptyCodexHandoffToken({
|
|
1843
|
-
terminalId: String(terminal.id),
|
|
1844
|
-
terminalControl: codexSendAuthorityContext.terminalControl,
|
|
1845
|
-
pid: Number(terminal.pid),
|
|
1846
|
-
workspace: codexWorkspace,
|
|
1847
|
-
processUuid: codexProcessUuid,
|
|
1848
|
-
processBirth: codexProcessBirth,
|
|
1849
|
-
sourceSession: soleBindingConflict.session
|
|
1850
|
-
})
|
|
1851
|
-
: undefined;
|
|
1852
|
-
return {
|
|
1853
|
-
...binding,
|
|
1854
|
-
verifiedEmptyRawSendAction,
|
|
1855
|
-
verifiedEmptyCodexSnapshotToken
|
|
1856
|
-
};
|
|
1857
|
-
}
|
|
1858
|
-
function observeDeferredSourceAuthority(terminal, context, observation) {
|
|
1859
|
-
const { terminals } = context;
|
|
1860
|
-
const { codexLatentClearResumeValue, codexOpenRootRolloutInventory, authoritativeSession, matchingSessions, conflictingBoundSessionClaims, unresolvedSessionClaims, soleBindingConflict, nativeIdentityObservation } = observation;
|
|
1861
|
-
const deferredCodexCandidateInventory = codexOpenRootRolloutInventory &&
|
|
1862
|
-
codexOpenRootRolloutInventory.roots.length > 0
|
|
1863
|
-
? codexOpenRootRolloutInventory
|
|
1864
|
-
: undefined;
|
|
1865
|
-
const abandonedConflictSource = !authoritativeSession &&
|
|
1866
|
-
soleBindingConflict?.kind === "unverifiable" &&
|
|
1867
|
-
matchingSessions.length === 0 &&
|
|
1868
|
-
conflictingBoundSessionClaims.length === 1 &&
|
|
1869
|
-
unresolvedSessionClaims.length === 0 &&
|
|
1870
|
-
terminal.agent === "codex"
|
|
1871
|
-
? soleBindingConflict.session
|
|
1872
|
-
: undefined;
|
|
1873
|
-
const deferredCodexSource = (authoritativeSession ??
|
|
1874
|
-
abandonedConflictSource) &&
|
|
1875
|
-
terminal.agent === "codex" &&
|
|
1876
|
-
(nativeIdentityObservation?.status === "verified_absent" ||
|
|
1877
|
-
deferredCodexCandidateInventory !== undefined)
|
|
1878
|
-
? authoritativeSession ?? abandonedConflictSource
|
|
1879
|
-
: undefined;
|
|
1880
|
-
const deferredCodexSourceNativeThreadId = stringValue(deferredCodexSource?.binding?.native_thread_id)?.toLowerCase();
|
|
1881
|
-
const deferredCodexLatentClearResumeFingerprint = isRecord(codexLatentClearResumeValue) &&
|
|
1882
|
-
stringValue(codexLatentClearResumeValue.source_native_thread_id)?.toLowerCase() === deferredCodexSourceNativeThreadId
|
|
1883
|
-
? stringValue(codexLatentClearResumeValue.fingerprint)
|
|
1884
|
-
: undefined;
|
|
1885
|
-
if (deferredCodexLatentClearResumeFingerprint) {
|
|
1886
|
-
// The resume hint is useful operational context, but it is not durable
|
|
1887
|
-
// foreground authority: it can scroll away while the latent thread is
|
|
1888
|
-
// still current. Candidate routing and its token rely on the complete
|
|
1889
|
-
// rollout inventory and Store authority below instead.
|
|
1890
|
-
runtimeLog("info", "terminal_codex_latent_clear_hint_observed", {
|
|
1891
|
-
terminal_id: String(terminal.id),
|
|
1892
|
-
source_session_id: deferredCodexSource?.session_id,
|
|
1893
|
-
source_native_thread_id: deferredCodexSourceNativeThreadId
|
|
1894
|
-
});
|
|
1895
|
-
}
|
|
1896
|
-
const deferredCodexSourceActiveElsewhere = Boolean(deferredCodexSourceNativeThreadId &&
|
|
1897
|
-
terminals.some((candidate) => stringValue(candidate.id) !== stringValue(terminal.id) &&
|
|
1898
|
-
candidate.agent === "codex" &&
|
|
1899
|
-
stringValue(candidate.native_agent_session_id)?.toLowerCase() ===
|
|
1900
|
-
deferredCodexSourceNativeThreadId));
|
|
1901
|
-
return {
|
|
1902
|
-
...observation,
|
|
1903
|
-
deferredCodexCandidateInventory,
|
|
1904
|
-
abandonedConflictSource,
|
|
1905
|
-
deferredCodexSource,
|
|
1906
|
-
deferredCodexSourceActiveElsewhere
|
|
1907
|
-
};
|
|
1908
|
-
}
|
|
1909
|
-
function observeDeferredTerminalAuthority(terminal, context, observation) {
|
|
1910
|
-
const { storeDir, mutationsAllowed } = context;
|
|
1911
|
-
const { automatedInputComposerReady, terminalControl, terminalHasNonterminalDeferredTransfer, matchingSessions, conflictingBoundSessionClaims, unresolvedSessionClaims, discoveredOwnership, terminalBlockingTurns, codexProcessUuid, codexProcessBirth, codexWorkspace, codexSendAuthorityContext, deferredCodexCandidateInventory, abandonedConflictSource, deferredCodexSource, deferredCodexSourceActiveElsewhere } = observation;
|
|
1912
|
-
const deferredCodexAuthority = codexSendAuthorityContext
|
|
1913
|
-
? terminalListRuntime().observeDeferredCodexAuthority({
|
|
1914
|
-
mode: "list",
|
|
1915
|
-
storeDir,
|
|
1916
|
-
context: codexSendAuthorityContext,
|
|
1917
|
-
sourceSession: deferredCodexSource,
|
|
1918
|
-
candidateInventory: deferredCodexCandidateInventory,
|
|
1919
|
-
abandonment: abandonedConflictSource
|
|
1920
|
-
? "missing_rollout"
|
|
1921
|
-
: "never",
|
|
1922
|
-
requireUnclaimedCandidate: true
|
|
1923
|
-
})
|
|
1924
|
-
: undefined;
|
|
1925
|
-
const deferredCodexSourceRolloutAuthority = deferredCodexAuthority?.sourceRolloutAuthority ?? "present";
|
|
1926
|
-
const deferredCodexDispatchSnapshot = deferredCodexAuthority?.dispatchSnapshot;
|
|
1927
|
-
const deferredCodexForegroundEligible = Boolean(mutationsAllowed &&
|
|
1928
|
-
!terminalHasNonterminalDeferredTransfer &&
|
|
1929
|
-
deferredCodexSource &&
|
|
1930
|
-
terminalControl &&
|
|
1931
|
-
hasCanonicalTerminalEndpoint(terminalControl) &&
|
|
1932
|
-
discoveredOwnership.state === "none" &&
|
|
1933
|
-
unresolvedSessionClaims.length === 0 &&
|
|
1934
|
-
((matchingSessions.length === 1 &&
|
|
1935
|
-
conflictingBoundSessionClaims.length === 0) ||
|
|
1936
|
-
(deferredCodexSourceRolloutAuthority ===
|
|
1937
|
-
"explicitly_abandoned_predecessor" &&
|
|
1938
|
-
matchingSessions.length === 0 &&
|
|
1939
|
-
conflictingBoundSessionClaims.length === 1)) &&
|
|
1940
|
-
codexProcessUuid &&
|
|
1941
|
-
codexProcessBirth &&
|
|
1942
|
-
codexWorkspace &&
|
|
1943
|
-
deferredCodexAuthority?.exactSource &&
|
|
1944
|
-
terminalBlockingTurns.length === 0 &&
|
|
1945
|
-
terminal.orphaned_terminal_dispatch === undefined &&
|
|
1946
|
-
deferredCodexDispatchSnapshot &&
|
|
1947
|
-
["idle", "unknown"].includes(String(terminal.activity_state)) &&
|
|
1948
|
-
automatedInputComposerReady === true &&
|
|
1949
|
-
!(isRecord(terminal.approval_state) &&
|
|
1950
|
-
terminal.approval_state.blocked === true) &&
|
|
1951
|
-
!deferredCodexSourceActiveElsewhere &&
|
|
1952
|
-
terminalControl.capabilities.includes("send_keys") &&
|
|
1953
|
-
terminalControl.capabilities.includes("screen_status"));
|
|
1954
|
-
const deferredCodexForegroundToken = deferredCodexForegroundEligible &&
|
|
1955
|
-
deferredCodexSource &&
|
|
1956
|
-
terminalControl &&
|
|
1957
|
-
codexProcessUuid &&
|
|
1958
|
-
codexProcessBirth &&
|
|
1959
|
-
codexWorkspace &&
|
|
1960
|
-
deferredCodexDispatchSnapshot
|
|
1961
|
-
? deferredCodexForegroundBindingToken({
|
|
1962
|
-
terminalId: String(terminal.id),
|
|
1963
|
-
terminalControl,
|
|
1964
|
-
pid: Number(terminal.pid),
|
|
1965
|
-
workspace: codexWorkspace,
|
|
1966
|
-
processUuid: codexProcessUuid,
|
|
1967
|
-
processBirth: codexProcessBirth,
|
|
1968
|
-
sourceSession: deferredCodexSource,
|
|
1969
|
-
dispatchSnapshot: deferredCodexDispatchSnapshot,
|
|
1970
|
-
sourceTurnHistory: deferredCodexAuthority?.sourceTurnHistory,
|
|
1971
|
-
sourceRolloutAuthority: deferredCodexSourceRolloutAuthority,
|
|
1972
|
-
sourceAbandonmentFingerprint: deferredCodexAuthority?.sourceAbandonmentFingerprint,
|
|
1973
|
-
...(deferredCodexCandidateInventory
|
|
1974
|
-
? { candidateInventory: deferredCodexCandidateInventory }
|
|
1975
|
-
: {})
|
|
1976
|
-
})
|
|
1977
|
-
: undefined;
|
|
1978
|
-
return {
|
|
1979
|
-
...observation,
|
|
1980
|
-
deferredCodexSourceRolloutAuthority,
|
|
1981
|
-
deferredCodexForegroundToken
|
|
1982
|
-
};
|
|
1983
|
-
}
|
|
1984
|
-
function observeTerminalHandoffAuthority(terminal, context, observation) {
|
|
1985
|
-
const { storeDir, mutationsAllowed, conversationHasNonterminalDeferredTransfer } = context;
|
|
1986
|
-
const { automatedInputComposerReady, terminalControl, matchingSessions, unresolvedSessionClaims, discoveredOwnership, rawActions, soleBindingConflict, conflictingSessionRevision, conflictingSessionTurns, expectedTerminalToken, externalHandoffNativeThreadId, externalHandoffTarget, externalHandoffSnapshotToken, blockingHandoffTurns, terminalBlockingTurns, handoffSourceBlockingTurns } = observation;
|
|
1987
|
-
const reconcileBindingAction = mutationsAllowed &&
|
|
1988
|
-
discoveredOwnership.state === "none" &&
|
|
1989
|
-
unresolvedSessionClaims.length === 0 &&
|
|
1990
|
-
matchingSessions.length === 0 &&
|
|
1991
|
-
soleBindingConflict &&
|
|
1992
|
-
soleBindingConflict.kind !== "unverifiable" &&
|
|
1993
|
-
Number.isSafeInteger(conflictingSessionRevision) &&
|
|
1994
|
-
conflictingSessionRevision > 0 &&
|
|
1995
|
-
expectedTerminalToken &&
|
|
1996
|
-
terminal.activity_state === "idle" &&
|
|
1997
|
-
!(isRecord(terminal.approval_state) &&
|
|
1998
|
-
terminal.approval_state.blocked === true) &&
|
|
1999
|
-
!conflictingSessionTurns.some((turn) => isSessionSendBlockingStatus(turn.status)) &&
|
|
2000
|
-
terminalBlockingTurns.length === 0 &&
|
|
2001
|
-
!managedSessionHasUnresolvedNativeTransition(storeDir, soleBindingConflict.session)
|
|
2002
|
-
? projectReconcileBindingAction({
|
|
2003
|
-
terminalId: stringValue(terminal.id),
|
|
2004
|
-
conflictingSession: soleBindingConflict.session,
|
|
2005
|
-
conflictingSessionRevision,
|
|
2006
|
-
expectedTerminalToken
|
|
2007
|
-
})
|
|
2008
|
-
: undefined;
|
|
2009
|
-
const externalHandoffAdoptable = Boolean(mutationsAllowed &&
|
|
2010
|
-
discoveredOwnership.state === "none" &&
|
|
2011
|
-
unresolvedSessionClaims.length === 0 &&
|
|
2012
|
-
soleBindingConflict?.kind === "live_external_thread_change" &&
|
|
2013
|
-
terminal.activity_state === "idle" &&
|
|
2014
|
-
automatedInputComposerReady === true &&
|
|
2015
|
-
!(isRecord(terminal.approval_state) &&
|
|
2016
|
-
terminal.approval_state.blocked === true) &&
|
|
2017
|
-
!conflictingSessionTurns.some((turn) => isSessionSendBlockingStatus(turn.status)) &&
|
|
2018
|
-
terminalBlockingTurns.length === 0 &&
|
|
2019
|
-
!managedSessionHasUnresolvedNativeTransition(storeDir, soleBindingConflict.session) &&
|
|
2020
|
-
externalHandoffTarget?.status === "eligible" &&
|
|
2021
|
-
isRecord(rawActions.send) &&
|
|
2022
|
-
Boolean(externalHandoffSnapshotToken));
|
|
2023
|
-
const handoffDecisionTurn = mutationsAllowed &&
|
|
2024
|
-
soleBindingConflict?.kind === "live_external_thread_change" &&
|
|
2025
|
-
externalHandoffTarget?.status === "eligible" &&
|
|
2026
|
-
terminal.activity_state === "idle" &&
|
|
2027
|
-
!(isRecord(terminal.approval_state) &&
|
|
2028
|
-
terminal.approval_state.blocked === true) &&
|
|
2029
|
-
!managedSessionHasUnresolvedNativeTransition(storeDir, soleBindingConflict.session) &&
|
|
2030
|
-
blockingHandoffTurns.length === 1 &&
|
|
2031
|
-
terminalBlockingTurns.every((turn) => turn.conversation_id === blockingHandoffTurns[0].conversation_id)
|
|
2032
|
-
? blockingHandoffTurns[0]
|
|
2033
|
-
: undefined;
|
|
2034
|
-
const handoffDecisionToken = handoffDecisionTurn &&
|
|
2035
|
-
externalHandoffSnapshotToken &&
|
|
2036
|
-
terminalControl
|
|
2037
|
-
? terminalListRuntime().activeTurnHandoffDecisionToken({
|
|
2038
|
-
handoffToken: externalHandoffSnapshotToken,
|
|
2039
|
-
turn: handoffDecisionTurn,
|
|
2040
|
-
ledger: terminalListRuntime().loadTerminalBridgeDispatchLedger(terminalControl)
|
|
2041
|
-
})
|
|
2042
|
-
: undefined;
|
|
2043
|
-
const handoffDecision = handoffDecisionTurn &&
|
|
2044
|
-
handoffDecisionToken &&
|
|
2045
|
-
externalHandoffNativeThreadId
|
|
2046
|
-
? projectHandoffDecision({
|
|
2047
|
-
sourceSessionId: soleBindingConflict?.session.session_id,
|
|
2048
|
-
sourceTurnId: turnIdForConversation(handoffDecisionTurn),
|
|
2049
|
-
liveNativeThreadId: externalHandoffNativeThreadId,
|
|
2050
|
-
handoffDecisionToken,
|
|
2051
|
-
actionTurnId: turnIdForConversation(handoffDecisionTurn)
|
|
2052
|
-
})
|
|
2053
|
-
: undefined;
|
|
2054
|
-
const blockingHandoffTurnIds = new Set(handoffSourceBlockingTurns.map((turn) => turn.conversation_id));
|
|
2055
|
-
// A blocking managed Turn always remains explicitly closable. Close releases
|
|
2056
|
-
// AKK management only; it does not send input or stop the coding agent.
|
|
2057
|
-
const terminalRecoveryBlockingTurns = terminalBlockingTurns;
|
|
2058
|
-
return {
|
|
2059
|
-
...observation,
|
|
2060
|
-
reconcileBindingAction,
|
|
2061
|
-
externalHandoffAdoptable,
|
|
2062
|
-
handoffDecision,
|
|
2063
|
-
blockingHandoffTurnIds,
|
|
2064
|
-
terminalRecoveryBlockingTurns
|
|
2065
|
-
};
|
|
2066
|
-
}
|
|
2067
|
-
function observeTerminalScopedApprovalAuthority(terminal, context, observation) {
|
|
2068
|
-
const { storeDir, mutationsAllowed } = context;
|
|
2069
|
-
const { terminalControl, terminalHasNonterminalDeferredTransfer, conflictingBoundSessionClaims, unresolvedSessionClaims, sessionAuthorityConflict, authoritativeSession, discoveredOwnership, ownership, rawActions } = observation;
|
|
2070
|
-
let terminalScopedCodexApprovalAction;
|
|
2071
|
-
const terminalScopedCodexApprovalPrompt = terminalScopedCodexApprovalPromptSnapshot(terminal.approval_state);
|
|
2072
|
-
if (mutationsAllowed &&
|
|
2073
|
-
terminal.agent === "codex" &&
|
|
2074
|
-
terminalControl &&
|
|
2075
|
-
hasCanonicalTerminalEndpoint(terminalControl) &&
|
|
2076
|
-
authoritativeSession &&
|
|
2077
|
-
!sessionAuthorityConflict &&
|
|
2078
|
-
!terminalHasNonterminalDeferredTransfer &&
|
|
2079
|
-
unresolvedSessionClaims.length === 0 &&
|
|
2080
|
-
conflictingBoundSessionClaims.length === 0 &&
|
|
2081
|
-
terminalScopedCodexApprovalPrompt &&
|
|
2082
|
-
isRecord(rawActions.approve)) {
|
|
2083
|
-
try {
|
|
2084
|
-
const ledger = terminalListRuntime().loadTerminalBridgeDispatchLedger(terminalControl);
|
|
2085
|
-
const boundary = ownership.state === "conflict" &&
|
|
2086
|
-
discoveredOwnership.state === "current" &&
|
|
2087
|
-
ledger
|
|
2088
|
-
? terminalScopedCodexApprovalBoundary({
|
|
2089
|
-
storeDir,
|
|
2090
|
-
terminal,
|
|
2091
|
-
owner: discoveredOwnership.conversation,
|
|
2092
|
-
session: authoritativeSession,
|
|
2093
|
-
ledger,
|
|
2094
|
-
approval: terminalScopedCodexApprovalPrompt
|
|
2095
|
-
})
|
|
2096
|
-
: ownership.state === "none" &&
|
|
2097
|
-
discoveredOwnership.state === "none"
|
|
2098
|
-
? terminalScopedCodexApprovalBoundary({
|
|
2099
|
-
storeDir,
|
|
2100
|
-
terminal,
|
|
2101
|
-
session: authoritativeSession,
|
|
2102
|
-
ledger,
|
|
2103
|
-
approval: terminalScopedCodexApprovalPrompt
|
|
2104
|
-
})
|
|
2105
|
-
: undefined;
|
|
2106
|
-
if (!boundary) {
|
|
2107
|
-
throw new Error("terminal-scoped Codex approval has no eligible managed authority");
|
|
2108
|
-
}
|
|
2109
|
-
terminalScopedCodexApprovalAction = {
|
|
2110
|
-
...rawActions.approve,
|
|
2111
|
-
arguments: {
|
|
2112
|
-
conversation_id: String(terminal.id),
|
|
2113
|
-
expected_terminal_token: boundary.token
|
|
2114
|
-
},
|
|
2115
|
-
scope: "terminal_current_prompt",
|
|
2116
|
-
authority: boundary.authority.kind,
|
|
2117
|
-
managed_state_unchanged: true,
|
|
2118
|
-
automatic_approval_eligible: false,
|
|
2119
|
-
durable_dispatch_receipt: false,
|
|
2120
|
-
uncertain_outcome_recovery: "refresh status and inspect the live prompt; do not retry blindly"
|
|
2121
|
-
};
|
|
2122
|
-
}
|
|
2123
|
-
catch (error) {
|
|
2124
|
-
runtimeLog("info", "terminal_scoped_codex_approval_not_advertised", {
|
|
2125
|
-
terminal_id: String(terminal.id),
|
|
2126
|
-
terminal_target: terminalControl.target,
|
|
2127
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
2128
|
-
});
|
|
2129
|
-
}
|
|
2130
|
-
}
|
|
2131
|
-
const rolloutBackedCodexSession = Boolean(authoritativeSession?.agent === "codex" &&
|
|
2132
|
-
isCompleteNativeRollout(authoritativeSession.binding?.native_process.rollout));
|
|
2133
|
-
return {
|
|
2134
|
-
...observation,
|
|
2135
|
-
terminalScopedCodexApprovalAction,
|
|
2136
|
-
rolloutBackedCodexSession
|
|
2137
|
-
};
|
|
2138
|
-
}
|
|
2139
|
-
function observeTerminalListActionAuthority(terminal, context, binding) {
|
|
2140
|
-
return observeTerminalScopedApprovalAuthority(terminal, context, observeTerminalHandoffAuthority(terminal, context, observeDeferredTerminalAuthority(terminal, context, observeDeferredSourceAuthority(terminal, context, observeVerifiedEmptyTerminalAuthority(terminal, context, binding)))));
|
|
2141
|
-
}
|
|
2142
|
-
function renderTerminalFirstListEntry(terminal, context, observation) {
|
|
2143
|
-
const { sessionAuthorityRequired, includeAll, mutationsAllowed, conversationHasNonterminalDeferredTransfer } = context;
|
|
2144
|
-
const { automatedInputComposerReady, terminalUserExplicitSendAction, publicTerminal, terminalControl, allRelated, displayedRelated, relatedSessions, authoritativeSession, ownership, rawSendAction, sessionAwareRawActions, externalHandoffDetected, externalHandoffSnapshotToken, handoffSourceBlockingTurns, verifiedEmptyRawSendAction, verifiedEmptyCodexSnapshotToken, deferredCodexSourceRolloutAuthority, deferredCodexForegroundToken, reconcileBindingAction, externalHandoffAdoptable, handoffDecision, blockingHandoffTurnIds, terminalRecoveryBlockingTurns, terminalScopedCodexApprovalAction, rolloutBackedCodexSession } = observation;
|
|
2145
|
-
const association = decideManagedTerminalAssociation({
|
|
2146
|
-
allRelated,
|
|
2147
|
-
displayedRelated,
|
|
2148
|
-
authoritativeSession,
|
|
2149
|
-
sessionAuthorityRequired,
|
|
2150
|
-
currentOwner: ownership.state === "current"
|
|
2151
|
-
? ownership.conversation
|
|
2152
|
-
: undefined
|
|
2153
|
-
});
|
|
2154
|
-
const { managedSessionId, sessionIds, sessionAllRelated, sessionDisplayedRelated } = association;
|
|
2155
|
-
// History remains useful when a pane has restarted and therefore no
|
|
2156
|
-
// first-class Session is authoritative for the new process incarnation.
|
|
2157
|
-
// Keep that display-only association separate from the send target: under
|
|
2158
|
-
// protocol 3, only authoritativeSession may populate managedSessionId.
|
|
2159
|
-
const sessionBindingMatchesLiveTerminal = authoritativeSession
|
|
2160
|
-
? true
|
|
2161
|
-
: Boolean(!sessionAuthorityRequired &&
|
|
2162
|
-
sessionAllRelated.some((turn) => managedTurnMatchesLiveTerminal(turn, terminal)));
|
|
2163
|
-
const currentTurnValue = ownership.state === "current"
|
|
2164
|
-
? currentManagedTurnForTerminal(ownership.conversation, terminal, sessionAwareRawActions)
|
|
2165
|
-
: undefined;
|
|
2166
|
-
const currentTurnProjection = currentTurnValue
|
|
2167
|
-
? !mutationsAllowed
|
|
2168
|
-
? readOnlyManagedTurn(currentTurnValue)
|
|
2169
|
-
: ownership.state === "current" &&
|
|
2170
|
-
conversationHasNonterminalDeferredTransfer(ownership.conversation)
|
|
2171
|
-
? userReleasableManagedTurn(currentTurnValue)
|
|
2172
|
-
: currentTurnValue
|
|
2173
|
-
: undefined;
|
|
2174
|
-
const currentTurn = currentTurnProjection
|
|
2175
|
-
? withoutGenericHandoffSourceClose(currentTurnProjection, blockingHandoffTurnIds)
|
|
2176
|
-
: undefined;
|
|
2177
|
-
const nonOwnerRawActions = nonOwnerTerminalActions(sessionAwareRawActions, {
|
|
2178
|
-
hasAuthoritativeSession: Boolean(authoritativeSession),
|
|
2179
|
-
rolloutBackedCodexSession
|
|
2180
|
-
});
|
|
2181
|
-
const { recentConversation, historyConversations } = selectManagedTerminalHistory({
|
|
2182
|
-
displayedRelated: sessionDisplayedRelated,
|
|
2183
|
-
currentConversationId: stringValue(currentTurn?.conversation_id),
|
|
2184
|
-
hasCurrentTurn: Boolean(currentTurn),
|
|
2185
|
-
includeAll
|
|
2186
|
-
});
|
|
2187
|
-
const recentTurnValue = recentConversation
|
|
2188
|
-
? historicalManagedTurnForTerminal(recentConversation)
|
|
2189
|
-
: undefined;
|
|
2190
|
-
const recentTurnProjection = recentTurnValue
|
|
2191
|
-
? !mutationsAllowed
|
|
2192
|
-
? readOnlyManagedTurn(recentTurnValue)
|
|
2193
|
-
: recentConversation &&
|
|
2194
|
-
conversationHasNonterminalDeferredTransfer(recentConversation)
|
|
2195
|
-
? userReleasableManagedTurn(recentTurnValue)
|
|
2196
|
-
: recentTurnValue
|
|
2197
|
-
: undefined;
|
|
2198
|
-
const recentTurn = recentTurnProjection
|
|
2199
|
-
? withoutGenericHandoffSourceClose(recentTurnProjection, blockingHandoffTurnIds)
|
|
2200
|
-
: undefined;
|
|
2201
|
-
const history = historyConversations.map((conversation) => {
|
|
2202
|
-
const turn = historicalManagedTurnForTerminal(conversation);
|
|
2203
|
-
return withoutGenericHandoffSourceClose(!mutationsAllowed
|
|
2204
|
-
? readOnlyManagedTurn(turn)
|
|
2205
|
-
: conversationHasNonterminalDeferredTransfer(conversation)
|
|
2206
|
-
? userReleasableManagedTurn(turn)
|
|
2207
|
-
: turn, blockingHandoffTurnIds);
|
|
2208
|
-
});
|
|
2209
|
-
const visibleTurnIds = new Set([currentTurn, recentTurn, ...history]
|
|
2210
|
-
.map((turn) => stringValue(turn?.conversation_id))
|
|
2211
|
-
.filter((id) => id !== undefined));
|
|
2212
|
-
const managedSessionShortReference = managedSessionId
|
|
2213
|
-
? sessionShortRef(managedSessionId)
|
|
2214
|
-
: null;
|
|
2215
|
-
const management = projectTerminalManagement({
|
|
2216
|
-
managedSessionId,
|
|
2217
|
-
managedSessionShortRef: managedSessionShortReference,
|
|
2218
|
-
currentTurn,
|
|
2219
|
-
recentTurn,
|
|
2220
|
-
sessionAllRelatedCount: sessionAllRelated.length,
|
|
2221
|
-
hiddenTurnCount: sessionAllRelated.filter((conversation) => !visibleTurnIds.has(conversation.conversation_id)).length,
|
|
2222
|
-
sessionCount: new Set([
|
|
2223
|
-
...sessionIds,
|
|
2224
|
-
...relatedSessions.map((session) => session.session_id)
|
|
2225
|
-
]).size,
|
|
2226
|
-
authoritativeSession,
|
|
2227
|
-
history: includeAll ? history : undefined
|
|
2228
|
-
});
|
|
2229
|
-
const sendAuthority = decideTerminalSendAuthority({
|
|
2230
|
-
ownership: ownership.state,
|
|
2231
|
-
verifiedEmptyToken: verifiedEmptyCodexSnapshotToken,
|
|
2232
|
-
externalToken: externalHandoffAdoptable
|
|
2233
|
-
? externalHandoffSnapshotToken
|
|
2234
|
-
: undefined,
|
|
2235
|
-
deferredToken: ownership.state !== "conflict" ||
|
|
2236
|
-
deferredCodexSourceRolloutAuthority ===
|
|
2237
|
-
"explicitly_abandoned_predecessor"
|
|
2238
|
-
? deferredCodexForegroundToken
|
|
2239
|
-
: undefined,
|
|
2240
|
-
managedSendSessionId: managedSessionId &&
|
|
2241
|
-
!rolloutBackedCodexSession &&
|
|
2242
|
-
sessionBindingMatchesLiveTerminal &&
|
|
2243
|
-
isRecord(sessionAwareRawActions.send)
|
|
2244
|
-
? managedSessionId
|
|
2245
|
-
: undefined
|
|
2246
|
-
});
|
|
2247
|
-
const tokenSendAction = sendAuthority.mode === "external_handoff"
|
|
2248
|
-
? rawSendAction
|
|
2249
|
-
: sendAuthority.mode === "verified_empty" ||
|
|
2250
|
-
sendAuthority.mode === "deferred"
|
|
2251
|
-
? verifiedEmptyRawSendAction
|
|
2252
|
-
: undefined;
|
|
2253
|
-
const authoritativeSendAction = sendAuthority.mode === "managed" && isRecord(sessionAwareRawActions.send)
|
|
2254
|
-
? sendActionForManagedSession(sessionAwareRawActions.send, sendAuthority.sessionId)
|
|
2255
|
-
: tokenSendAction &&
|
|
2256
|
-
"token" in sendAuthority &&
|
|
2257
|
-
sendAuthority.token
|
|
2258
|
-
? {
|
|
2259
|
-
...tokenSendAction,
|
|
2260
|
-
arguments: {
|
|
2261
|
-
...(isRecord(tokenSendAction.arguments)
|
|
2262
|
-
? tokenSendAction.arguments
|
|
2263
|
-
: {}),
|
|
2264
|
-
expected_terminal_token: sendAuthority.token
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
: undefined;
|
|
2268
|
-
const managedFastPathToken = "token" in sendAuthority
|
|
2269
|
-
? sendAuthority.token
|
|
2270
|
-
: undefined;
|
|
2271
|
-
const prioritizedTerminalUserExplicitSendAction = terminalUserExplicitSendAction && managedFastPathToken
|
|
2272
|
-
? {
|
|
2273
|
-
...terminalUserExplicitSendAction,
|
|
2274
|
-
arguments: {
|
|
2275
|
-
...(isRecord(terminalUserExplicitSendAction.arguments)
|
|
2276
|
-
? terminalUserExplicitSendAction.arguments
|
|
2277
|
-
: {}),
|
|
2278
|
-
expected_managed_terminal_token: managedFastPathToken
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
: terminalUserExplicitSendAction;
|
|
2282
|
-
const availableActions = selectTerminalAvailableActions({
|
|
2283
|
-
ownership: ownership.state,
|
|
2284
|
-
currentActions: ownership.state === "current"
|
|
2285
|
-
? currentTerminalActions(currentTurn)
|
|
2286
|
-
: {},
|
|
2287
|
-
sessionAwareRawActions: sessionAwareRawActions,
|
|
2288
|
-
nonOwnerRawActions,
|
|
2289
|
-
authoritativeSendAction,
|
|
2290
|
-
terminalUserExplicitSendAction: prioritizedTerminalUserExplicitSendAction,
|
|
2291
|
-
reconcileBindingAction,
|
|
2292
|
-
terminalScopedApprovalAction: terminalScopedCodexApprovalAction,
|
|
2293
|
-
isAction: isRecord
|
|
2294
|
-
});
|
|
2295
|
-
// An explicit undefined rollout prevents a lingering resolver rollout from
|
|
2296
|
-
// being presented as the authoritative status-card thread.
|
|
2297
|
-
const authoritativeIdentity = authoritativeTerminalIdentity(authoritativeSession);
|
|
2298
|
-
const publicManagementConflict = ownership.state === "conflict"
|
|
2299
|
-
? projectPublicManagementConflict({
|
|
2300
|
-
conflict: ownership.conflict,
|
|
2301
|
-
verifiedEmptyToken: verifiedEmptyCodexSnapshotToken,
|
|
2302
|
-
deferredToken: deferredCodexForegroundToken,
|
|
2303
|
-
explicitlyAbandonedPredecessor: deferredCodexSourceRolloutAuthority ===
|
|
2304
|
-
"explicitly_abandoned_predecessor"
|
|
2305
|
-
})
|
|
2306
|
-
: undefined;
|
|
2307
|
-
const handoffPresentation = projectHandoffPresentation({
|
|
2308
|
-
externalHandoffDetected,
|
|
2309
|
-
externalHandoffAdoptable,
|
|
2310
|
-
recoveryBlockingTurnCount: terminalRecoveryBlockingTurns.length,
|
|
2311
|
-
hasHandoffDecision: Boolean(handoffDecision),
|
|
2312
|
-
sourceBlockingTurnCount: handoffSourceBlockingTurns.length,
|
|
2313
|
-
automatedInputComposerReady: automatedInputComposerReady === true,
|
|
2314
|
-
verifiedEmptyToken: verifiedEmptyCodexSnapshotToken
|
|
2315
|
-
});
|
|
2316
|
-
return {
|
|
2317
|
-
...publicTerminal,
|
|
2318
|
-
...authoritativeIdentity,
|
|
2319
|
-
management_state: ownership.state === "conflict"
|
|
2320
|
-
? "conflict"
|
|
2321
|
-
: ownership.state === "current" || Boolean(authoritativeSession)
|
|
2322
|
-
? "managed"
|
|
2323
|
-
: "unmanaged",
|
|
2324
|
-
...(ownership.state === "conflict"
|
|
2325
|
-
? { management_conflict: publicManagementConflict }
|
|
2326
|
-
: {}),
|
|
2327
|
-
...handoffPresentation,
|
|
2328
|
-
...(handoffDecision ? { handoff_decision: handoffDecision } : {}),
|
|
2329
|
-
...(terminalRecoveryBlockingTurns.length > 0
|
|
2330
|
-
? {
|
|
2331
|
-
blocking_turns: terminalRecoveryBlockingTurns.map((turn) => projectBlockingTurn({
|
|
2332
|
-
sessionId: sessionIdForConversation(turn),
|
|
2333
|
-
turnId: turnIdForConversation(turn),
|
|
2334
|
-
status: turn.status,
|
|
2335
|
-
recoveryTurnId: turnIdForConversation(turn)
|
|
2336
|
-
}))
|
|
2337
|
-
}
|
|
2338
|
-
: {}),
|
|
2339
|
-
managed: management,
|
|
2340
|
-
available_actions: availableActions
|
|
2341
|
-
};
|
|
2342
|
-
}
|
|
2343
|
-
function terminalFirstListProjection({ storeDir, terminals, managedSessions, sessionAuthorityRequired, allConversations, displayedConversations, includeAll, managedOnly, statusFilter, mutationsAllowed }) {
|
|
2344
|
-
const nonterminalDeferredTransfers = listDeferredForegroundTransfers(storeDir).filter((transfer) => !isFinalDeferredForegroundTransferStatus(transfer.status));
|
|
2345
|
-
const nonterminalDeferredTransferIds = new Set(nonterminalDeferredTransfers.map((transfer) => transfer.transfer_id));
|
|
2346
|
-
const nonterminalDeferredSourceTurnIds = new Set(nonterminalDeferredTransfers.flatMap((transfer) => transfer.version === 2 &&
|
|
2347
|
-
transfer.source_kind === "candidate_rollout_quiescent"
|
|
2348
|
-
? (transfer.source_turn_history ?? []).map((turn) => turn.turn_id)
|
|
2349
|
-
: []));
|
|
2350
|
-
const conversationHasNonterminalDeferredTransfer = (conversation) => {
|
|
2351
|
-
if (nonterminalDeferredSourceTurnIds.has(turnIdForConversation(conversation))) {
|
|
2352
|
-
return true;
|
|
2353
|
-
}
|
|
2354
|
-
const takeover = isRecord(conversation.native_session_takeover)
|
|
2355
|
-
? conversation.native_session_takeover
|
|
2356
|
-
: undefined;
|
|
2357
|
-
const transferId = stringValue(takeover?.deferred_foreground_transfer_id);
|
|
2358
|
-
return Boolean(transferId && nonterminalDeferredTransferIds.has(transferId));
|
|
2359
|
-
};
|
|
2360
|
-
const discoveredTerminalControls = terminals.flatMap((terminal) => {
|
|
2361
|
-
const control = isRecord(terminal.terminal_control)
|
|
2362
|
-
? terminal.terminal_control
|
|
2363
|
-
: undefined;
|
|
2364
|
-
return control ? [control] : [];
|
|
2365
|
-
});
|
|
2366
|
-
const projectionContext = {
|
|
2367
|
-
storeDir,
|
|
2368
|
-
terminals,
|
|
2369
|
-
managedSessions,
|
|
2370
|
-
sessionAuthorityRequired,
|
|
2371
|
-
allConversations,
|
|
2372
|
-
displayedConversations,
|
|
2373
|
-
includeAll,
|
|
2374
|
-
mutationsAllowed,
|
|
2375
|
-
nonterminalDeferredTransfers,
|
|
2376
|
-
conversationHasNonterminalDeferredTransfer
|
|
2377
|
-
};
|
|
2378
|
-
const projectedTerminals = terminals.map((terminal) => {
|
|
2379
|
-
const binding = observeTerminalListBindingAuthority(terminal, projectionContext);
|
|
2380
|
-
return renderTerminalFirstListEntry(binding.authorityTerminal, projectionContext, observeTerminalListActionAuthority(binding.authorityTerminal, projectionContext, binding));
|
|
2381
|
-
});
|
|
2382
|
-
const unavailableManagedTurns = displayedConversations
|
|
2383
|
-
.filter((conversation) => {
|
|
2384
|
-
const managedControl = terminalControlForManagedConversation(conversation);
|
|
2385
|
-
if (discoveredTerminalControls.some((control) => terminalControlsShareIncarnation(managedControl, control))) {
|
|
2386
|
-
return false;
|
|
2387
|
-
}
|
|
2388
|
-
return (includeAll ||
|
|
2389
|
-
managedOnly ||
|
|
2390
|
-
statusFilter !== undefined ||
|
|
2391
|
-
managedTurnNeedsAttention(conversation));
|
|
2392
|
-
})
|
|
2393
|
-
.sort(compareManagedConversationRecency)
|
|
2394
|
-
.map((conversation) => {
|
|
2395
|
-
const managedTurn = managedTurnListEntry(terminalListRuntime().summarizeConversation(conversation), {
|
|
2396
|
-
terminalBridge: terminalListRuntime().terminalBridgeEnabled(conversation),
|
|
2397
|
-
approvalState: managedListApprovalState(conversation),
|
|
2398
|
-
conversation
|
|
2399
|
-
});
|
|
2400
|
-
return {
|
|
2401
|
-
...managedTurn,
|
|
2402
|
-
available_actions: !mutationsAllowed
|
|
2403
|
-
? readOnlyListActions(isRecord(managedTurn.available_actions)
|
|
2404
|
-
? managedTurn.available_actions
|
|
2405
|
-
: {})
|
|
2406
|
-
: conversationHasNonterminalDeferredTransfer(conversation)
|
|
2407
|
-
? userReleaseListActions(isRecord(managedTurn.available_actions)
|
|
2408
|
-
? managedTurn.available_actions
|
|
2409
|
-
: {}, turnIdForConversation(conversation))
|
|
2410
|
-
: safeUnavailableManagedTurnActions(isRecord(managedTurn.available_actions)
|
|
2411
|
-
? managedTurn.available_actions
|
|
2412
|
-
: {}),
|
|
2413
|
-
terminal_availability: {
|
|
2414
|
-
available: false,
|
|
2415
|
-
reason: managedOnly
|
|
2416
|
-
? "terminal discovery was disabled by --managed-only"
|
|
2417
|
-
: "the referenced terminal pane is not currently available"
|
|
2418
|
-
}
|
|
2419
|
-
};
|
|
2420
|
-
});
|
|
2421
|
-
return {
|
|
2422
|
-
terminals: projectedTerminals,
|
|
2423
|
-
unavailableManagedTurns
|
|
2424
|
-
};
|
|
2425
|
-
}
|
|
2426
1142
|
function managedSessionMatchesLiveTerminalEntry(session, terminal, storeDir) {
|
|
2427
|
-
|
|
2428
|
-
const liveControl = isRecord(terminal.terminal_control)
|
|
2429
|
-
? terminal.terminal_control
|
|
2430
|
-
: undefined;
|
|
2431
|
-
if (session.status !== "bound" ||
|
|
2432
|
-
!binding ||
|
|
2433
|
-
session.agent !== terminal.agent ||
|
|
2434
|
-
binding.native_process.pid !== Number(terminal.pid)) {
|
|
2435
|
-
return false;
|
|
2436
|
-
}
|
|
2437
|
-
const terminalAliasMatches = terminalControlAliasMatches(binding.terminal_id, binding.terminal_control, terminal.id, liveControl);
|
|
2438
|
-
if (!terminalAliasMatches) {
|
|
2439
|
-
return false;
|
|
2440
|
-
}
|
|
2441
|
-
const workspaceMatches = terminalListRuntime().matchesConfiguredWorkspace(session.workspace, terminal.workspace ?? terminal.cwd);
|
|
2442
|
-
if (!workspaceMatches) {
|
|
2443
|
-
return false;
|
|
2444
|
-
}
|
|
2445
|
-
const observation = terminalObservationFromListEntry(terminal, session.agent);
|
|
2446
|
-
const evidence = {
|
|
2447
|
-
terminalAliasMatches,
|
|
2448
|
-
workspaceMatches
|
|
2449
|
-
};
|
|
2450
|
-
let decision = decideTerminalBindingMatch(session, observation, evidence);
|
|
2451
|
-
if (decision.state === "not_exact" &&
|
|
2452
|
-
decision.reason === "native_identity_mismatch" &&
|
|
2453
|
-
session.agent === "codex" &&
|
|
2454
|
-
observation.nativeIdentity.status === "resolved") {
|
|
2455
|
-
decision = decideTerminalBindingMatch(session, observation, {
|
|
2456
|
-
...evidence,
|
|
2457
|
-
codexLingeringBeforeMatches: terminalListRuntime().codexLingeringBeforeIdentityMatchesSession({
|
|
2458
|
-
storeDir,
|
|
2459
|
-
session,
|
|
2460
|
-
identity: observation.nativeIdentity.identity
|
|
2461
|
-
})
|
|
2462
|
-
});
|
|
2463
|
-
}
|
|
2464
|
-
return decision.state === "exact";
|
|
2465
|
-
}
|
|
2466
|
-
function managedSessionClaimsLiveTerminalEntry(session, terminal) {
|
|
2467
|
-
const binding = session.binding;
|
|
2468
|
-
const liveControl = isRecord(terminal.terminal_control)
|
|
2469
|
-
? terminal.terminal_control
|
|
2470
|
-
: undefined;
|
|
2471
|
-
return Boolean(binding &&
|
|
2472
|
-
session.agent === terminal.agent &&
|
|
2473
|
-
binding.native_process.pid === Number(terminal.pid) &&
|
|
2474
|
-
terminalControlsShareIncarnation(binding.terminal_control, liveControl));
|
|
2475
|
-
}
|
|
2476
|
-
function listedTerminalProcessIncarnation(terminal) {
|
|
2477
|
-
const processUuid = stringValue(terminal.native_agent_process_uuid);
|
|
2478
|
-
const processBirth = stringValue(terminal.native_agent_process_birth);
|
|
2479
|
-
if (terminal.agent !== "codex" ||
|
|
2480
|
-
(processUuid && processBirth)) {
|
|
2481
|
-
return { processUuid, processBirth };
|
|
2482
|
-
}
|
|
2483
|
-
const pid = Number(terminal.pid);
|
|
2484
|
-
if (!Number.isSafeInteger(pid) || pid <= 1) {
|
|
2485
|
-
return { processUuid, processBirth };
|
|
2486
|
-
}
|
|
2487
|
-
try {
|
|
2488
|
-
const incarnation = terminalListRuntime().codexProcessIncarnationForPid(pid);
|
|
2489
|
-
return {
|
|
2490
|
-
processUuid: processUuid ?? incarnation.processUuid,
|
|
2491
|
-
processBirth: processBirth ?? incarnation.processBirth
|
|
2492
|
-
};
|
|
2493
|
-
}
|
|
2494
|
-
catch {
|
|
2495
|
-
return { processUuid, processBirth };
|
|
2496
|
-
}
|
|
2497
|
-
}
|
|
2498
|
-
function managedBindingConflictKindForLiveTerminalEntry({ storeDir, session, terminal }) {
|
|
2499
|
-
const binding = session.binding;
|
|
2500
|
-
if (session.status !== "bound" ||
|
|
2501
|
-
!binding ||
|
|
2502
|
-
!managedSessionClaimsLiveTerminalEntry(session, terminal) ||
|
|
2503
|
-
managedSessionMatchesLiveTerminalEntry(session, terminal, storeDir)) {
|
|
2504
|
-
return undefined;
|
|
2505
|
-
}
|
|
2506
|
-
const livePid = Number(terminal.pid);
|
|
2507
|
-
const incarnation = listedTerminalProcessIncarnation(terminal);
|
|
2508
|
-
const relationship = processIncarnationRelationship({
|
|
2509
|
-
binding,
|
|
2510
|
-
livePid,
|
|
2511
|
-
liveProcessUuid: incarnation.processUuid,
|
|
2512
|
-
liveProcessBirth: incarnation.processBirth
|
|
2513
|
-
});
|
|
2514
|
-
if (relationship === "different") {
|
|
2515
|
-
return "stale_process_incarnation";
|
|
2516
|
-
}
|
|
2517
|
-
if (!terminalControlAliasMatches(binding.terminal_id, binding.terminal_control, terminal.id, isRecord(terminal.terminal_control)
|
|
2518
|
-
? terminal.terminal_control
|
|
2519
|
-
: undefined) ||
|
|
2520
|
-
!terminalListRuntime().matchesConfiguredWorkspace(session.workspace, terminal.workspace ?? terminal.cwd)) {
|
|
2521
|
-
return "unverifiable";
|
|
2522
|
-
}
|
|
2523
|
-
return decideManagedBindingConflict({
|
|
2524
|
-
session,
|
|
2525
|
-
claimsTerminal: true,
|
|
2526
|
-
exactBinding: false,
|
|
2527
|
-
ownerConclusivelyInactive: false,
|
|
2528
|
-
processRelationship: relationship,
|
|
2529
|
-
liveNativeThreadId: stringValue(terminal.native_agent_session_id),
|
|
2530
|
-
statusCardNativeThreadId: stringValue(terminal.native_agent_status_card_session_id),
|
|
2531
|
-
managedTurnCount: provisionalManagedBindingTurnCount(storeDir, session)
|
|
2532
|
-
});
|
|
1143
|
+
return terminalListOwnershipService().managedSessionMatchesLiveTerminalEntry(session, terminal, storeDir);
|
|
2533
1144
|
}
|
|
2534
1145
|
function provisionalManagedBindingTurnCount(storeDir, session) {
|
|
2535
|
-
|
|
2536
|
-
return binding && session.lineage.created_by === "attach" &&
|
|
2537
|
-
!session.last_transition_id &&
|
|
2538
|
-
!binding.native_thread_id &&
|
|
2539
|
-
!binding.native_process.rollout
|
|
2540
|
-
? terminalListRuntime().managedTurnsForSession(storeDir, session.session_id).length
|
|
2541
|
-
: undefined;
|
|
1146
|
+
return terminalListOwnershipService().provisionalManagedBindingTurnCount(storeDir, session);
|
|
2542
1147
|
}
|
|
2543
1148
|
function managedSessionHasUnresolvedNativeTransition(storeDir, session) {
|
|
2544
|
-
|
|
2545
|
-
if (!fs.existsSync(root)) {
|
|
2546
|
-
return false;
|
|
2547
|
-
}
|
|
2548
|
-
let entries;
|
|
2549
|
-
try {
|
|
2550
|
-
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
2551
|
-
}
|
|
2552
|
-
catch {
|
|
2553
|
-
return true;
|
|
2554
|
-
}
|
|
2555
|
-
for (const entry of entries) {
|
|
2556
|
-
if (!entry.isDirectory()) {
|
|
2557
|
-
continue;
|
|
2558
|
-
}
|
|
2559
|
-
let transition;
|
|
2560
|
-
try {
|
|
2561
|
-
transition = loadNativeThreadTransition(storeDir, entry.name);
|
|
2562
|
-
}
|
|
2563
|
-
catch {
|
|
2564
|
-
return true;
|
|
2565
|
-
}
|
|
2566
|
-
if (transition.source_session_id !== session.session_id &&
|
|
2567
|
-
transition.target_session_id !== session.session_id) {
|
|
2568
|
-
continue;
|
|
2569
|
-
}
|
|
2570
|
-
if (!["committed", "aborted"].includes(transition.status)) {
|
|
2571
|
-
return true;
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
return false;
|
|
1149
|
+
return terminalListOwnershipService().managedSessionHasUnresolvedNativeTransition(storeDir, session);
|
|
2575
1150
|
}
|
|
2576
1151
|
function managedSessionHasAnyNativeTransition(storeDir, session) {
|
|
2577
|
-
|
|
2578
|
-
if (!fs.existsSync(root)) {
|
|
2579
|
-
return false;
|
|
2580
|
-
}
|
|
2581
|
-
let entries;
|
|
2582
|
-
try {
|
|
2583
|
-
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
2584
|
-
}
|
|
2585
|
-
catch {
|
|
2586
|
-
return true;
|
|
2587
|
-
}
|
|
2588
|
-
for (const entry of entries) {
|
|
2589
|
-
if (!entry.isDirectory()) {
|
|
2590
|
-
continue;
|
|
2591
|
-
}
|
|
2592
|
-
let transition;
|
|
2593
|
-
try {
|
|
2594
|
-
transition = loadNativeThreadTransition(storeDir, entry.name);
|
|
2595
|
-
}
|
|
2596
|
-
catch {
|
|
2597
|
-
return true;
|
|
2598
|
-
}
|
|
2599
|
-
if (transition.source_session_id === session.session_id ||
|
|
2600
|
-
transition.target_session_id === session.session_id) {
|
|
2601
|
-
return true;
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
|
-
return false;
|
|
1152
|
+
return terminalListOwnershipService().managedSessionHasAnyNativeTransition(storeDir, session);
|
|
2605
1153
|
}
|
|
2606
1154
|
function terminalControlForManagedConversation(conversation) {
|
|
2607
|
-
return
|
|
2608
|
-
? conversation.native_session_takeover
|
|
2609
|
-
: undefined);
|
|
1155
|
+
return terminalListOwnershipService().terminalControlForManagedConversation(conversation);
|
|
2610
1156
|
}
|
|
2611
1157
|
function terminalIncarnationBlockingTurns(storeDir, terminalControl, conversations = listConversations(storeDir)) {
|
|
2612
|
-
return conversations
|
|
2613
|
-
.filter(terminalListRuntime().isDiscoverableTmuxConversation)
|
|
2614
|
-
.filter((turn) => terminalControlsShareIncarnation(terminalControlForManagedConversation(turn), terminalControl) &&
|
|
2615
|
-
isSessionSendBlockingStatus(turn.status))
|
|
2616
|
-
.sort(compareManagedConversationRecency);
|
|
1158
|
+
return terminalListOwnershipService().terminalIncarnationBlockingTurns(storeDir, terminalControl, conversations);
|
|
2617
1159
|
}
|
|
2618
1160
|
function managedTurnNeedsAttention(conversation) {
|
|
2619
|
-
return
|
|
2620
|
-
status: conversation.status,
|
|
2621
|
-
get callbackDeliveryStatus() {
|
|
2622
|
-
const delivery = isRecord(conversation.callback_delivery)
|
|
2623
|
-
? conversation.callback_delivery
|
|
2624
|
-
: undefined;
|
|
2625
|
-
return String(delivery?.status ?? "");
|
|
2626
|
-
}
|
|
2627
|
-
});
|
|
1161
|
+
return terminalListOwnershipService().managedTurnNeedsAttention(conversation);
|
|
2628
1162
|
}
|
|
2629
1163
|
function assertTerminalIncarnationCanStartTurn(storeDir, terminalControl) {
|
|
2630
|
-
|
|
2631
|
-
if (!blocker) {
|
|
2632
|
-
return;
|
|
2633
|
-
}
|
|
2634
|
-
throw new Error(`terminal ${terminalControl.target} still has unresolved Turn ` +
|
|
2635
|
-
`${turnIdForConversation(blocker)} (${blocker.status})`);
|
|
1164
|
+
return terminalListOwnershipService().assertTerminalIncarnationCanStartTurn(storeDir, terminalControl);
|
|
2636
1165
|
}
|
|
2637
1166
|
function terminalDispatchOwnership(terminalControl) {
|
|
2638
|
-
|
|
2639
|
-
try {
|
|
2640
|
-
ledger = terminalListRuntime().loadTerminalBridgeDispatchLedger(terminalControl);
|
|
2641
|
-
}
|
|
2642
|
-
catch (error) {
|
|
2643
|
-
const decision = dispatch.decideTerminalDispatchOwnership("unreadable");
|
|
2644
|
-
return {
|
|
2645
|
-
state: "conflict",
|
|
2646
|
-
conflict: {
|
|
2647
|
-
reason: decision.code === "ledger_unreadable"
|
|
2648
|
-
? error instanceof Error ? error.message : String(error)
|
|
2649
|
-
: "terminal dispatch ledger is unreadable",
|
|
2650
|
-
recovery: "inspect the shared terminal pane before performing a side effect"
|
|
2651
|
-
}
|
|
2652
|
-
};
|
|
2653
|
-
}
|
|
2654
|
-
const ledgerAuthority = !ledger
|
|
2655
|
-
? "absent"
|
|
2656
|
-
: ledger.status === "resolved"
|
|
2657
|
-
? "resolved"
|
|
2658
|
-
: terminalListRuntime().terminalDispatchRecordMatchesControl(ledger, terminalControl, {
|
|
2659
|
-
requireProcessAnchor: false
|
|
2660
|
-
}) && !terminalListRuntime().terminalDispatchRecordMatchesControl(ledger, terminalControl)
|
|
2661
|
-
? "stale_process_incarnation"
|
|
2662
|
-
: dispatch.isActiveTerminalDispatchStatus(String(ledger.status))
|
|
2663
|
-
? "active"
|
|
2664
|
-
: "inactive_status";
|
|
2665
|
-
let decision = dispatch.decideTerminalDispatchOwnership(ledgerAuthority);
|
|
2666
|
-
if (decision.state === "none" || !ledger)
|
|
2667
|
-
return { state: "none" };
|
|
2668
|
-
const owner = terminalListRuntime().loadTerminalDispatchLedgerOwner(ledger);
|
|
2669
|
-
const ledgerMessageId = stringValue(ledger.message_id);
|
|
2670
|
-
const ownerAuthority = !owner
|
|
2671
|
-
? "unavailable"
|
|
2672
|
-
: isTerminalDispatchOwnerReleasedStatus(owner.status)
|
|
2673
|
-
? "released"
|
|
2674
|
-
: !terminalControlsShareIncarnation(terminalControlForManagedConversation(owner), terminalControl)
|
|
2675
|
-
? "terminal_mismatch"
|
|
2676
|
-
: ledgerMessageId && stringValue(isRecord(owner.native_session_takeover)
|
|
2677
|
-
? owner.native_session_takeover.terminal_bridge_message_id
|
|
2678
|
-
: undefined) !== ledgerMessageId
|
|
2679
|
-
? "generation_mismatch"
|
|
2680
|
-
: "current";
|
|
2681
|
-
decision = dispatch.decideTerminalDispatchOwnership(ledgerAuthority, ownerAuthority);
|
|
2682
|
-
if (decision.state === "none")
|
|
2683
|
-
return { state: "none" };
|
|
2684
|
-
if (decision.state === "current" && owner) {
|
|
2685
|
-
return { state: "current", conversation: owner };
|
|
2686
|
-
}
|
|
2687
|
-
const reason = decision.state === "conflict" &&
|
|
2688
|
-
decision.code === "owner_terminal_mismatch"
|
|
2689
|
-
? "dispatch owner does not reference this terminal pane incarnation"
|
|
2690
|
-
: decision.state === "conflict" &&
|
|
2691
|
-
decision.code === "owner_generation_mismatch"
|
|
2692
|
-
? "dispatch generation does not match the owner state"
|
|
2693
|
-
: "dispatch owner state is unavailable";
|
|
2694
|
-
return {
|
|
2695
|
-
state: "conflict",
|
|
2696
|
-
conflict: projectTerminalDispatchConflict({
|
|
2697
|
-
reason,
|
|
2698
|
-
dispatchStatus: stringValue(ledger.status),
|
|
2699
|
-
ownerConversationId: stringValue(ledger.conversation_id),
|
|
2700
|
-
messageId: stringValue(ledger.message_id)
|
|
2701
|
-
})
|
|
2702
|
-
};
|
|
2703
|
-
}
|
|
2704
|
-
function localTerminalDispatchOwnership(ledgerOwner, localConversations, terminal) {
|
|
2705
|
-
const localOwner = localConversations.find((conversation) => conversation.conversation_id === ledgerOwner.conversation_id &&
|
|
2706
|
-
sameCanonicalStatePath(conversation.state_path, ledgerOwner.state_path));
|
|
2707
|
-
return decideLocalTerminalDispatchOwnership({
|
|
2708
|
-
ledgerOwnerId: ledgerOwner.conversation_id,
|
|
2709
|
-
localOwner,
|
|
2710
|
-
localOwnerMatchesLiveTerminal: localOwner
|
|
2711
|
-
? managedTurnMatchesLiveTerminal(localOwner, terminal)
|
|
2712
|
-
: false
|
|
2713
|
-
});
|
|
1167
|
+
return terminalListOwnershipService().terminalDispatchOwnership(terminalControl);
|
|
2714
1168
|
}
|
|
2715
1169
|
function terminalScopedCodexApprovalBoundary({ storeDir, terminal, session, ledger, approval, owner }) {
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
.filter((candidate) => candidate.status === "bound" &&
|
|
2724
|
-
candidate.agent === "codex" &&
|
|
2725
|
-
candidate.binding?.native_process.pid === Number(terminalRecord.pid) &&
|
|
2726
|
-
terminalControlsShareIncarnation(candidate.binding?.terminal_control, terminalControl))
|
|
2727
|
-
.map((candidate) => candidate.session_id);
|
|
2728
|
-
const blockingTurnIds = () => terminalIncarnationBlockingTurns(storeDir, control)
|
|
2729
|
-
.map((turn) => turnIdForConversation(turn));
|
|
2730
|
-
const hasDeferredRecovery = () => listDeferredForegroundTransfers(storeDir).some((transfer) => !isFinalDeferredForegroundTransferStatus(transfer.status) &&
|
|
2731
|
-
(transfer.source_session_id === session.session_id ||
|
|
2732
|
-
transfer.target_session_id === session.session_id ||
|
|
2733
|
-
(transfer.terminal_id === terminalId &&
|
|
2734
|
-
terminalControlEvidenceMatches(transfer.terminal_endpoint, control))));
|
|
2735
|
-
const commonChecks = {
|
|
2736
|
-
relatedBoundSessionIds, blockingTurnIds,
|
|
2737
|
-
hasNativeTransition: () => managedSessionHasAnyNativeTransition(storeDir, session),
|
|
2738
|
-
hasDeferredRecovery,
|
|
2739
|
-
ledgerMatchesTerminal: () => terminalListRuntime().terminalDispatchRecordMatchesControl(ledger, control)
|
|
2740
|
-
};
|
|
2741
|
-
if (owner && ledger) {
|
|
2742
|
-
return decideTerminalScopedCodexApprovalAuthority({
|
|
2743
|
-
kind: "current_dispatch_owner", storeDir, terminal, owner, session,
|
|
2744
|
-
ledger, approval,
|
|
2745
|
-
checks: {
|
|
2746
|
-
...commonChecks,
|
|
2747
|
-
assertDispatchOwner: () => terminalListRuntime().assertManagedTerminalDispatchOwner({
|
|
2748
|
-
storeDir, conversation: owner, terminalControl: control, action: "approve"
|
|
2749
|
-
}),
|
|
2750
|
-
ownerMatchesNativeIdentity: (identity) => nativeAgentIdentityMatchesTurn(owner, identity
|
|
2751
|
-
? { ...identity, evidence: "terminal_scoped_approval" }
|
|
2752
|
-
: undefined)
|
|
2753
|
-
}
|
|
2754
|
-
});
|
|
2755
|
-
}
|
|
2756
|
-
return decideTerminalScopedCodexApprovalAuthority({
|
|
2757
|
-
kind: "managed_session_no_dispatch_owner", storeDir, terminal, session,
|
|
2758
|
-
ledger, approval,
|
|
2759
|
-
checks: {
|
|
2760
|
-
...commonChecks,
|
|
2761
|
-
dispatchOwnershipIsNone: () => terminalDispatchOwnership(control).state === "none",
|
|
2762
|
-
hasOrphanedDispatch: () => Boolean(terminalListRuntime().orphanedTerminalDispatchForRecovery(control))
|
|
2763
|
-
}
|
|
1170
|
+
return terminalListOwnershipService().terminalScopedCodexApprovalBoundary({
|
|
1171
|
+
storeDir,
|
|
1172
|
+
terminal,
|
|
1173
|
+
session,
|
|
1174
|
+
ledger,
|
|
1175
|
+
approval,
|
|
1176
|
+
owner
|
|
2764
1177
|
});
|
|
2765
1178
|
}
|
|
2766
1179
|
async function resolveTerminalScopedCodexApproval({ options, terminal, approvalSnapshot }) {
|
|
@@ -2942,90 +1355,6 @@ async function resolveTerminalScopedCodexApproval({ options, terminal, approvalS
|
|
|
2942
1355
|
};
|
|
2943
1356
|
}
|
|
2944
1357
|
}
|
|
2945
|
-
function historicalManagedTurnForTerminal(conversation) {
|
|
2946
|
-
return renderHistoricalManagedTurn(managedTurnListEntry(terminalListRuntime().summarizeConversation(conversation), {
|
|
2947
|
-
terminalBridge: terminalListRuntime().terminalBridgeEnabled(conversation),
|
|
2948
|
-
approvalState: managedListApprovalState(conversation),
|
|
2949
|
-
conversation
|
|
2950
|
-
}));
|
|
2951
|
-
}
|
|
2952
|
-
function managedTurnMatchesLiveTerminal(conversation, terminal) {
|
|
2953
|
-
const takeover = isRecord(conversation.native_session_takeover)
|
|
2954
|
-
? conversation.native_session_takeover
|
|
2955
|
-
: undefined;
|
|
2956
|
-
const liveControl = isRecord(terminal.terminal_control)
|
|
2957
|
-
? terminal.terminal_control
|
|
2958
|
-
: undefined;
|
|
2959
|
-
const storedControl = terminalListRuntime().terminalControlFromTakeover(takeover);
|
|
2960
|
-
const livePid = Number(terminal.pid);
|
|
2961
|
-
const storedPid = Number(takeover?.terminal_agent_pid);
|
|
2962
|
-
if (executorForConversation(conversation).kind !== terminal.agent ||
|
|
2963
|
-
!Number.isSafeInteger(livePid) ||
|
|
2964
|
-
livePid <= 1 ||
|
|
2965
|
-
storedPid !== livePid ||
|
|
2966
|
-
!terminalControlAliasMatches(stringValue(takeover?.native_session_id), storedControl, stringValue(terminal.id), liveControl) ||
|
|
2967
|
-
!terminalControlsShareIncarnation(storedControl, liveControl)) {
|
|
2968
|
-
return false;
|
|
2969
|
-
}
|
|
2970
|
-
const liveSessionId = stringValue(terminal.native_agent_session_id);
|
|
2971
|
-
const liveProcessUuid = stringValue(terminal.native_agent_process_uuid);
|
|
2972
|
-
const liveProcessBirth = stringValue(terminal.native_agent_process_birth);
|
|
2973
|
-
const liveRollout = isRecord(terminal.native_agent_rollout)
|
|
2974
|
-
? terminal.native_agent_rollout
|
|
2975
|
-
: undefined;
|
|
2976
|
-
const liveNativeIdentity = liveSessionId
|
|
2977
|
-
? {
|
|
2978
|
-
sessionId: liveSessionId,
|
|
2979
|
-
...(liveProcessUuid ? { processUuid: liveProcessUuid } : {}),
|
|
2980
|
-
...(liveProcessBirth ? { processBirth: liveProcessBirth } : {}),
|
|
2981
|
-
...(liveRollout
|
|
2982
|
-
? {
|
|
2983
|
-
rollout: {
|
|
2984
|
-
fd: String(liveRollout.fd ?? ""),
|
|
2985
|
-
device: String(liveRollout.device ?? ""),
|
|
2986
|
-
inode: String(liveRollout.inode ?? ""),
|
|
2987
|
-
path: String(liveRollout.path ?? "")
|
|
2988
|
-
}
|
|
2989
|
-
}
|
|
2990
|
-
: {}),
|
|
2991
|
-
evidence: "live_terminal"
|
|
2992
|
-
}
|
|
2993
|
-
: undefined;
|
|
2994
|
-
if (!nativeAgentIdentityMatchesTurn(conversation, liveNativeIdentity)) {
|
|
2995
|
-
return false;
|
|
2996
|
-
}
|
|
2997
|
-
const liveWorkspace = terminal.workspace ?? terminal.cwd;
|
|
2998
|
-
if (!terminalListRuntime().matchesConfiguredWorkspace(conversation.workspace, liveWorkspace)) {
|
|
2999
|
-
return false;
|
|
3000
|
-
}
|
|
3001
|
-
const livePanePath = liveControl?.currentPath;
|
|
3002
|
-
if (livePanePath !== undefined &&
|
|
3003
|
-
!terminalListRuntime().matchesConfiguredWorkspace(conversation.workspace, livePanePath)) {
|
|
3004
|
-
return false;
|
|
3005
|
-
}
|
|
3006
|
-
return true;
|
|
3007
|
-
}
|
|
3008
|
-
function currentManagedTurnForTerminal(conversation, terminal, rawTerminalActions) {
|
|
3009
|
-
const managedTurn = managedTurnListEntry(terminalListRuntime().summarizeConversation(conversation), {
|
|
3010
|
-
terminalBridge: terminalListRuntime().terminalBridgeEnabled(conversation),
|
|
3011
|
-
approvalState: managedListApprovalState(conversation),
|
|
3012
|
-
conversation
|
|
3013
|
-
});
|
|
3014
|
-
const rawApproval = isRecord(rawTerminalActions.approve)
|
|
3015
|
-
? rawTerminalActions.approve
|
|
3016
|
-
: undefined;
|
|
3017
|
-
if (!rawApproval || executorForConversation(conversation).kind !== "codex") {
|
|
3018
|
-
return managedTurn;
|
|
3019
|
-
}
|
|
3020
|
-
return renderCurrentManagedTurn(managedTurn, {
|
|
3021
|
-
isCodex: true,
|
|
3022
|
-
ownerId: conversation.conversation_id,
|
|
3023
|
-
rawApproval,
|
|
3024
|
-
terminalApprovalState: () => isRecord(terminal.approval_state)
|
|
3025
|
-
? terminal.approval_state
|
|
3026
|
-
: undefined
|
|
3027
|
-
});
|
|
3028
|
-
}
|
|
3029
1358
|
async function listStateForTerminal(agent, terminalControl, options, bridge = terminalListRuntime().createTerminalAgentBridge(options), runtime) {
|
|
3030
1359
|
if (options.noApprovalScan) {
|
|
3031
1360
|
return {
|
|
@@ -3077,39 +1406,6 @@ async function listStateForTerminal(agent, terminalControl, options, bridge = te
|
|
|
3077
1406
|
};
|
|
3078
1407
|
}
|
|
3079
1408
|
}
|
|
3080
|
-
function managedListApprovalState(conversation) {
|
|
3081
|
-
if (!terminalListRuntime().terminalBridgeEnabled(conversation) ||
|
|
3082
|
-
!["waiting_for_agent", "waiting_for_openclaw"].includes(String(conversation.status))) {
|
|
3083
|
-
return undefined;
|
|
3084
|
-
}
|
|
3085
|
-
const nativeTakeover = isRecord(conversation.native_session_takeover)
|
|
3086
|
-
? conversation.native_session_takeover
|
|
3087
|
-
: undefined;
|
|
3088
|
-
if (!terminalListRuntime().terminalControlFromTakeover(nativeTakeover) ||
|
|
3089
|
-
!stringValue(nativeTakeover?.terminal_bridge_message_id)) {
|
|
3090
|
-
return undefined;
|
|
3091
|
-
}
|
|
3092
|
-
const approval = isRecord(nativeTakeover?.terminal_bridge_approval)
|
|
3093
|
-
? nativeTakeover.terminal_bridge_approval
|
|
3094
|
-
: undefined;
|
|
3095
|
-
const approvalState = isRecord(approval?.approval_state)
|
|
3096
|
-
? approval.approval_state
|
|
3097
|
-
: undefined;
|
|
3098
|
-
const fingerprint = stringValue(approval?.fingerprint);
|
|
3099
|
-
const notifiedAt = stringValue(approval?.notified_at);
|
|
3100
|
-
const notifiedAtMs = validTimestampMs(notifiedAt);
|
|
3101
|
-
if (!approvalState ||
|
|
3102
|
-
!fingerprint ||
|
|
3103
|
-
notifiedAtMs === undefined ||
|
|
3104
|
-
cliNowMs() - notifiedAtMs > terminalListRuntime().approvalTtlMs) {
|
|
3105
|
-
return undefined;
|
|
3106
|
-
}
|
|
3107
|
-
return {
|
|
3108
|
-
...approvalState,
|
|
3109
|
-
fingerprint,
|
|
3110
|
-
notified_at: notifiedAt
|
|
3111
|
-
};
|
|
3112
|
-
}
|
|
3113
1409
|
async function resolveConversationSelectorOption(commandName, options) {
|
|
3114
1410
|
const sendOperation = commandName === "send";
|
|
3115
1411
|
// Submission retry is already bound to one authoritative managed Turn.
|
|
@@ -3280,12 +1576,11 @@ async function sessionSelectorCandidates(commandName, options) {
|
|
|
3280
1576
|
.filter((conversation) => terminalListRuntime().matchesConfiguredWorkspace(options.workspace, conversation.workspace));
|
|
3281
1577
|
const discoverableWorkspaceConversations = workspaceConversations
|
|
3282
1578
|
.filter(terminalListRuntime().isDiscoverableTmuxConversation);
|
|
3283
|
-
const managed = discoverableWorkspaceConversations.map((conversation) => managedTurnListEntry(terminalListRuntime().summarizeConversation(conversation), {
|
|
1579
|
+
const managed = discoverableWorkspaceConversations.map((conversation) => terminalListProjectionService().managedTurnListEntry(terminalListRuntime().summarizeConversation(conversation), {
|
|
3284
1580
|
terminalBridge: terminalListRuntime().terminalBridgeEnabled(conversation),
|
|
3285
|
-
approvalState: managedListApprovalState(conversation),
|
|
3286
1581
|
conversation
|
|
3287
1582
|
}));
|
|
3288
|
-
const terminalProjection =
|
|
1583
|
+
const terminalProjection = terminalListProjectionService().projectTerminalFirstList({
|
|
3289
1584
|
storeDir,
|
|
3290
1585
|
terminals: terminalScan.terminalControlled.filter((entry) => terminalListRuntime().matchesConfiguredWorkspace(options.workspace, entry.workspace ?? entry.cwd)),
|
|
3291
1586
|
managedSessions: selectorStore.readable
|