@scotthuang/agent-knock-knock 0.13.16 → 0.13.18

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.
Files changed (184) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +4 -4
  3. package/dist/src/claude-terminal-agent-adapter.js +1 -1
  4. package/dist/src/claude-terminal-agent-adapter.js.map +1 -1
  5. package/dist/src/codex-app-server-interaction-client.js +68 -26
  6. package/dist/src/codex-app-server-interaction-client.js.map +1 -1
  7. package/dist/src/codex-app-server-read-client.js +52 -20
  8. package/dist/src/codex-app-server-read-client.js.map +1 -1
  9. package/dist/src/codex-astra-composer-proof.js +1 -1
  10. package/dist/src/codex-astra-composer-proof.js.map +1 -1
  11. package/dist/src/codex-async-question-adapter.js +14 -4
  12. package/dist/src/codex-async-question-adapter.js.map +1 -1
  13. package/dist/src/codex-lifecycle-compatibility.d.ts +1 -1
  14. package/dist/src/codex-lifecycle-compatibility.js +9 -3
  15. package/dist/src/codex-lifecycle-compatibility.js.map +1 -1
  16. package/dist/src/codex-open-rollout-inventory.d.ts +51 -0
  17. package/dist/src/codex-open-rollout-inventory.js +365 -0
  18. package/dist/src/codex-open-rollout-inventory.js.map +1 -0
  19. package/dist/src/codex-paginated-thread-binding.js +1 -1
  20. package/dist/src/codex-paginated-thread-binding.js.map +1 -1
  21. package/dist/src/codex-permission-surface.d.ts +1 -1
  22. package/dist/src/codex-permission-surface.js +1 -1
  23. package/dist/src/codex-permission-surface.js.map +1 -1
  24. package/dist/src/codex-rollout-bound-completion.d.ts +44 -0
  25. package/dist/src/codex-rollout-bound-completion.js +357 -0
  26. package/dist/src/codex-rollout-bound-completion.js.map +1 -0
  27. package/dist/src/codex-rollout-file.d.ts +15 -0
  28. package/dist/src/codex-rollout-file.js +98 -0
  29. package/dist/src/codex-rollout-file.js.map +1 -0
  30. package/dist/src/codex-rollout-human-task.d.ts +61 -0
  31. package/dist/src/codex-rollout-human-task.js +555 -0
  32. package/dist/src/codex-rollout-human-task.js.map +1 -0
  33. package/dist/src/codex-rollout-interaction-evidence.d.ts +48 -0
  34. package/dist/src/codex-rollout-interaction-evidence.js +521 -0
  35. package/dist/src/codex-rollout-interaction-evidence.js.map +1 -0
  36. package/dist/src/codex-rollout-inventory.d.ts +5 -0
  37. package/dist/src/codex-rollout-inventory.js +81 -0
  38. package/dist/src/codex-rollout-inventory.js.map +1 -0
  39. package/dist/src/codex-rollout-records.d.ts +49 -0
  40. package/dist/src/codex-rollout-records.js +298 -0
  41. package/dist/src/codex-rollout-records.js.map +1 -0
  42. package/dist/src/codex-sqlite-thread-query.d.ts +85 -0
  43. package/dist/src/codex-sqlite-thread-query.js +440 -0
  44. package/dist/src/codex-sqlite-thread-query.js.map +1 -0
  45. package/dist/src/codex-status-history-navigation.d.ts +1 -1
  46. package/dist/src/codex-status-history-navigation.js +1 -1
  47. package/dist/src/codex-status-history-navigation.js.map +1 -1
  48. package/dist/src/codex-store-adapter.d.ts +3 -50
  49. package/dist/src/codex-store-adapter.js +5 -796
  50. package/dist/src/codex-store-adapter.js.map +1 -1
  51. package/dist/src/codex-terminal-agent-adapter.js +4 -2
  52. package/dist/src/codex-terminal-agent-adapter.js.map +1 -1
  53. package/dist/src/native-thread-lifecycle-cli-adapter.d.ts +4 -134
  54. package/dist/src/native-thread-lifecycle-cli-adapter.js +19 -633
  55. package/dist/src/native-thread-lifecycle-cli-adapter.js.map +1 -1
  56. package/dist/src/native-thread-lifecycle-cli-contract.d.ts +138 -0
  57. package/dist/src/native-thread-lifecycle-cli-contract.js +2 -0
  58. package/dist/src/native-thread-lifecycle-cli-contract.js.map +1 -0
  59. package/dist/src/semantic-permission-control.js +33 -6
  60. package/dist/src/semantic-permission-control.js.map +1 -1
  61. package/dist/src/semantic-tool-descriptions.d.ts +26 -0
  62. package/dist/src/semantic-tool-descriptions.js +259 -0
  63. package/dist/src/semantic-tool-descriptions.js.map +1 -0
  64. package/dist/src/semantic-tool-runtime.js +45 -37
  65. package/dist/src/semantic-tool-runtime.js.map +1 -1
  66. package/dist/src/semantic-tool-schemas.js +134 -33
  67. package/dist/src/semantic-tool-schemas.js.map +1 -1
  68. package/dist/src/terminal-action-contracts.d.ts +4 -0
  69. package/dist/src/terminal-action-contracts.js +695 -0
  70. package/dist/src/terminal-action-contracts.js.map +1 -0
  71. package/dist/src/terminal-composer-classifier.d.ts +1 -1
  72. package/dist/src/terminal-composer-classifier.js +2 -2
  73. package/dist/src/terminal-composer-classifier.js.map +1 -1
  74. package/dist/src/terminal-interaction-response-bridge.js +1 -1
  75. package/dist/src/terminal-interaction-response-bridge.js.map +1 -1
  76. package/dist/src/terminal-list-renderer.d.ts +1 -2
  77. package/dist/src/terminal-list-renderer.js +8 -424
  78. package/dist/src/terminal-list-renderer.js.map +1 -1
  79. package/dist/src/terminal-model-control-action-policy.d.ts +1 -1
  80. package/dist/src/terminal-model-control-availability.d.ts +1 -1
  81. package/dist/src/terminal-model-control-availability.js +1 -1
  82. package/dist/src/terminal-model-control-availability.js.map +1 -1
  83. package/dist/src/terminal-model-control-cli-adapter.d.ts +34 -0
  84. package/dist/src/terminal-model-control-cli-adapter.js +669 -0
  85. package/dist/src/terminal-model-control-cli-adapter.js.map +1 -0
  86. package/dist/src/terminal-model-control-contract.d.ts +198 -0
  87. package/dist/src/terminal-model-control-contract.js +15 -0
  88. package/dist/src/terminal-model-control-contract.js.map +1 -0
  89. package/dist/src/terminal-model-control-input.d.ts +29 -0
  90. package/dist/src/terminal-model-control-input.js +86 -0
  91. package/dist/src/terminal-model-control-input.js.map +1 -0
  92. package/dist/src/terminal-model-control-profile.d.ts +5 -1
  93. package/dist/src/terminal-model-control-profile.js +21 -7
  94. package/dist/src/terminal-model-control-profile.js.map +1 -1
  95. package/dist/src/terminal-model-control-subject.d.ts +52 -0
  96. package/dist/src/terminal-model-control-subject.js +73 -0
  97. package/dist/src/terminal-model-control-subject.js.map +1 -1
  98. package/dist/src/terminal-model-control-surface.d.ts +82 -0
  99. package/dist/src/terminal-model-control-surface.js +688 -0
  100. package/dist/src/terminal-model-control-surface.js.map +1 -0
  101. package/dist/src/terminal-model-control.d.ts +6 -270
  102. package/dist/src/terminal-model-control.js +11 -988
  103. package/dist/src/terminal-model-control.js.map +1 -1
  104. package/dist/src/terminal-model-selection.d.ts +33 -0
  105. package/dist/src/terminal-model-selection.js +143 -0
  106. package/dist/src/terminal-model-selection.js.map +1 -0
  107. package/dist/src/terminal-monitor-application-service.js +38 -59
  108. package/dist/src/terminal-monitor-application-service.js.map +1 -1
  109. package/dist/src/terminal-monitor-attention-store.d.ts +65 -0
  110. package/dist/src/terminal-monitor-attention-store.js +518 -0
  111. package/dist/src/terminal-monitor-attention-store.js.map +1 -0
  112. package/dist/src/terminal-monitor-collateral-recovery.d.ts +12 -0
  113. package/dist/src/terminal-monitor-collateral-recovery.js +415 -0
  114. package/dist/src/terminal-monitor-collateral-recovery.js.map +1 -0
  115. package/dist/src/terminal-monitor-interaction-projection.d.ts +19 -0
  116. package/dist/src/terminal-monitor-interaction-projection.js +48 -0
  117. package/dist/src/terminal-monitor-interaction-projection.js.map +1 -0
  118. package/dist/src/terminal-monitor-startup-recovery.d.ts +15 -0
  119. package/dist/src/terminal-monitor-startup-recovery.js +767 -0
  120. package/dist/src/terminal-monitor-startup-recovery.js.map +1 -0
  121. package/dist/src/terminal-monitor-state-cli-adapter.d.ts +2 -104
  122. package/dist/src/terminal-monitor-state-cli-adapter.js +28 -1640
  123. package/dist/src/terminal-monitor-state-cli-adapter.js.map +1 -1
  124. package/dist/src/terminal-monitor-state-contract.d.ts +108 -0
  125. package/dist/src/terminal-monitor-state-contract.js +8 -0
  126. package/dist/src/terminal-monitor-state-contract.js.map +1 -0
  127. package/dist/src/terminal-native-inspection-bridge.d.ts +4 -153
  128. package/dist/src/terminal-native-inspection-bridge.js +7 -646
  129. package/dist/src/terminal-native-inspection-bridge.js.map +1 -1
  130. package/dist/src/terminal-native-inspection-contract.d.ts +128 -0
  131. package/dist/src/terminal-native-inspection-contract.js +38 -0
  132. package/dist/src/terminal-native-inspection-contract.js.map +1 -0
  133. package/dist/src/terminal-native-inspection-profile.d.ts +15 -0
  134. package/dist/src/terminal-native-inspection-profile.js +189 -0
  135. package/dist/src/terminal-native-inspection-profile.js.map +1 -0
  136. package/dist/src/terminal-native-inspection-proof.d.ts +62 -0
  137. package/dist/src/terminal-native-inspection-proof.js +362 -0
  138. package/dist/src/terminal-native-inspection-proof.js.map +1 -0
  139. package/dist/src/terminal-permission-control-bridge.js +1 -1
  140. package/dist/src/terminal-permission-control-bridge.js.map +1 -1
  141. package/dist/src/terminal-permission-control.js +5 -1
  142. package/dist/src/terminal-permission-control.js.map +1 -1
  143. package/dist/src/terminal-questionnaire-adapter.js +5 -2
  144. package/dist/src/terminal-questionnaire-adapter.js.map +1 -1
  145. package/dist/src/terminal-runtime-cli-adapter.d.ts +2 -1
  146. package/dist/src/terminal-runtime-cli-adapter.js +1 -1
  147. package/dist/src/terminal-runtime-cli-adapter.js.map +1 -1
  148. package/dist/src/terminal-submission-acceptance.d.ts +5 -148
  149. package/dist/src/terminal-submission-acceptance.js +21 -1845
  150. package/dist/src/terminal-submission-acceptance.js.map +1 -1
  151. package/dist/src/terminal-watch-anchor-capture.d.ts +9 -0
  152. package/dist/src/terminal-watch-anchor-capture.js +139 -0
  153. package/dist/src/terminal-watch-anchor-capture.js.map +1 -0
  154. package/dist/src/terminal-watch-cli-adapter.d.ts +3 -117
  155. package/dist/src/terminal-watch-cli-adapter.js +10 -1992
  156. package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
  157. package/dist/src/terminal-watch-cli-contract.d.ts +117 -0
  158. package/dist/src/terminal-watch-cli-contract.js +2 -0
  159. package/dist/src/terminal-watch-cli-contract.js.map +1 -0
  160. package/dist/src/terminal-watch-fallback-observation.d.ts +15 -0
  161. package/dist/src/terminal-watch-fallback-observation.js +249 -0
  162. package/dist/src/terminal-watch-fallback-observation.js.map +1 -0
  163. package/dist/src/terminal-watch-interaction-observation.d.ts +26 -0
  164. package/dist/src/terminal-watch-interaction-observation.js +262 -0
  165. package/dist/src/terminal-watch-interaction-observation.js.map +1 -0
  166. package/dist/src/terminal-watch-observation-adapter.d.ts +4 -0
  167. package/dist/src/terminal-watch-observation-adapter.js +307 -0
  168. package/dist/src/terminal-watch-observation-adapter.js.map +1 -0
  169. package/dist/src/terminal-watch-observation-evidence.d.ts +25 -0
  170. package/dist/src/terminal-watch-observation-evidence.js +184 -0
  171. package/dist/src/terminal-watch-observation-evidence.js.map +1 -0
  172. package/dist/src/terminal-watch-response-authority.d.ts +6 -0
  173. package/dist/src/terminal-watch-response-authority.js +333 -0
  174. package/dist/src/terminal-watch-response-authority.js.map +1 -0
  175. package/dist/src/terminal-watch-response-cli-adapter.d.ts +3 -0
  176. package/dist/src/terminal-watch-response-cli-adapter.js +230 -0
  177. package/dist/src/terminal-watch-response-cli-adapter.js.map +1 -0
  178. package/dist/src/terminal-watch-terminal-identity.d.ts +39 -0
  179. package/dist/src/terminal-watch-terminal-identity.js +380 -0
  180. package/dist/src/terminal-watch-terminal-identity.js.map +1 -0
  181. package/docs/codex-0.160.0-compatibility.md +126 -0
  182. package/docs/codex-permissions.md +12 -1
  183. package/package.json +3 -2
  184. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +3 -3
@@ -0,0 +1,669 @@
1
+ import { isExactNativeThreadId } from "./managed-session.js";
2
+ import { turnIdForConversation } from "./protocol.js";
3
+ import { decideModelControlAvailability } from "./terminal-model-control-availability.js";
4
+ import { isCodexModelControlAgentVersion, isTerminalModelControlPlanForAgent, isTerminalModelReasoningEffort, terminalModelControlPlanConforms, terminalModelControlProfileForPlan, terminalUserExplicitModelControlBindingToken } from "./terminal-model-control.js";
5
+ import { nonBlankString } from "./value-guards.js";
6
+ export function createTerminalModelControlCliAdapter(ports) {
7
+ const app = new TerminalModelControlCliApplication(ports);
8
+ return Object.freeze({
9
+ runModelOptions: (options) => app.runModelOptions(options),
10
+ runSetModel: (options) => app.runSetModel(options),
11
+ runRepairModelControl: (options) => app.runRepairModelControl(options)
12
+ });
13
+ }
14
+ /** Ordinary selection, residual continuation, and repair retain separate authority paths. */
15
+ class TerminalModelControlCliApplication {
16
+ ports;
17
+ constructor(ports) {
18
+ this.ports = ports;
19
+ }
20
+ /**
21
+ * Model control on Codex is an explicit physical-pane operation. A freshly
22
+ * started TUI may legitimately have no rollout-backed Session yet. Keep the
23
+ * physical token separate from native lifecycle binding while retaining the
24
+ * resolver's fail-closed behavior for genuinely ambiguous live rollouts.
25
+ */
26
+ async modelControlSnapshot(options, terminal) {
27
+ if (terminal.agent !== "codex") {
28
+ return this.ports.lifecycle.currentSnapshot(options, terminal);
29
+ }
30
+ const snapshot = await this.ports.lifecycle.currentSnapshot(options, terminal);
31
+ const nativeThreadId = snapshot.identity?.sessionId ??
32
+ snapshot.session?.binding?.native_thread_id;
33
+ if (isExactNativeThreadId(nativeThreadId) ||
34
+ snapshot.identity || snapshot.session) {
35
+ return snapshot;
36
+ }
37
+ const adapter = this.ports.lifecycle.agentAdapter(options, terminal.agent);
38
+ const { capability, plan, profile } = modelControlProfileObservation(adapter, snapshot.version);
39
+ if (!plan || profile?.agent !== "codex" ||
40
+ !profile.supportsZeroRolloutPhysicalAuthority) {
41
+ throw new Error(capability?.reason ?? "Codex has no verified physical model-control profile");
42
+ }
43
+ const bindingToken = this.physicalModelControlBindingToken(terminal, snapshot.version, plan.behaviorProfile);
44
+ return Object.freeze({
45
+ ...snapshot,
46
+ bindingToken,
47
+ bindingTokens: Object.freeze([bindingToken])
48
+ });
49
+ }
50
+ physicalModelControlBindingToken(terminal, agentVersion, behaviorProfile) {
51
+ const version = required(nonBlankString(agentVersion), "Codex physical model control requires an exact running version");
52
+ const incarnation = this.ports.identity.physicalProcessIncarnation(terminal.pid);
53
+ return terminalUserExplicitModelControlBindingToken({
54
+ terminalId: terminal.conversationId,
55
+ terminalControl: terminal.terminalControl,
56
+ pid: terminal.pid,
57
+ workspace: terminal.terminalControl.currentPath ?? this.ports.output.cwd(),
58
+ processUuid: incarnation.processUuid,
59
+ processBirth: incarnation.processBirth,
60
+ agentVersion: version,
61
+ behaviorProfile
62
+ });
63
+ }
64
+ validateModelOptions(options) {
65
+ if (options.command !== undefined || options.message !== undefined ||
66
+ options.model !== undefined || options.reasoningEffort !== undefined ||
67
+ options.expectedCatalogFingerprint !== undefined) {
68
+ throw new Error("model-options accepts only an exact terminal and current binding authority");
69
+ }
70
+ return required(nonBlankString(options.expectedBindingToken), "--expected-binding-token is required");
71
+ }
72
+ validateSetModel(options) {
73
+ if (options.command !== undefined || options.message !== undefined ||
74
+ options.scope !== undefined || options.keys !== undefined ||
75
+ options.index !== undefined) {
76
+ throw new Error("set-model accepts no command, key, menu index, or caller-selected scope");
77
+ }
78
+ const expectedBindingToken = required(nonBlankString(options.expectedBindingToken), "--expected-binding-token is required");
79
+ const expectedCatalogFingerprint = required(nonBlankString(options.expectedCatalogFingerprint), "--expected-catalog-fingerprint is required");
80
+ if (!/^[0-9a-f]{64}$/u.test(expectedCatalogFingerprint)) {
81
+ throw new Error("--expected-catalog-fingerprint must be the exact sha256 from model-options");
82
+ }
83
+ const model = required(nonBlankString(options.model), "--model is required");
84
+ const reasoningEffort = options.reasoningEffort;
85
+ if (!isTerminalModelReasoningEffort(reasoningEffort)) {
86
+ throw new Error("--reasoning-effort must be one exact semantic value advertised by model-options");
87
+ }
88
+ return {
89
+ expectedBindingToken,
90
+ expectedCatalogFingerprint,
91
+ request: { model, reasoningEffort }
92
+ };
93
+ }
94
+ validateRepairModelControl(options) {
95
+ if (options.command !== undefined ||
96
+ options.message !== undefined ||
97
+ options.model !== undefined ||
98
+ options.reasoningEffort !== undefined ||
99
+ options.expectedCatalogFingerprint !== undefined ||
100
+ options.scope !== undefined ||
101
+ options.keys !== undefined ||
102
+ options.index !== undefined) {
103
+ throw new Error("repair-model-control accepts only an exact terminal and current private repair authority");
104
+ }
105
+ return required(nonBlankString(options.expectedBindingToken), "--expected-binding-token is required");
106
+ }
107
+ async runModelOptions(options) {
108
+ const expectedBindingToken = this.validateModelOptions(options);
109
+ const context = await this.withPreparedModelControl(options, expectedBindingToken, async (prepared) => {
110
+ const result = await prepared.bridge.modelOptions(prepared.terminal.agent, prepared.terminal.terminalControl, prepared.agentVersion, prepared.plan, {
111
+ runtime: prepared.runtime,
112
+ beforeInput: () => prepared.initialResidual
113
+ ? this.assertFreshModelControlResidualBoundary(prepared)
114
+ : this.assertFreshModelControlBoundary(prepared),
115
+ loadCodexCatalog: prepared.loadCodexCatalog,
116
+ initialResidual: prepared.initialResidual
117
+ });
118
+ if (prepared.initialResidual) {
119
+ await this.assertFreshModelControlBoundary({
120
+ ...prepared,
121
+ expectedBindingToken: prepared.ordinaryBindingToken,
122
+ initialResidual: undefined
123
+ });
124
+ }
125
+ return { prepared, catalog: result.catalog };
126
+ }, { allowResidualEntry: true });
127
+ this.ports.output.print(this.modelOptionsResult(context.prepared, context.catalog));
128
+ }
129
+ async runSetModel(options) {
130
+ const validated = this.validateSetModel(options);
131
+ const output = await this.withPreparedModelControl(options, validated.expectedBindingToken, async (prepared) => {
132
+ const result = await prepared.bridge.setModel(prepared.terminal.agent, prepared.terminal.terminalControl, prepared.agentVersion, prepared.plan, validated.expectedCatalogFingerprint, validated.request, {
133
+ runtime: prepared.runtime,
134
+ beforeInput: () => this.assertFreshModelControlBoundary(prepared),
135
+ loadCodexCatalog: prepared.loadCodexCatalog
136
+ });
137
+ return { prepared, result };
138
+ });
139
+ const { result, prepared } = output;
140
+ this.ports.output.print({
141
+ terminal_id: prepared.terminal.conversationId,
142
+ agent: prepared.terminal.agent,
143
+ agent_version: prepared.agentVersion,
144
+ behavior_profile: prepared.plan.behaviorProfile,
145
+ outcome: result.outcome,
146
+ requested: modelValueOutput(result.requested),
147
+ ...(result.effective
148
+ ? { effective: modelValueOutput(result.effective) }
149
+ : {}),
150
+ ...(result.newSessionDefaults
151
+ ? { new_session_defaults: modelValueOutput(result.newSessionDefaults) }
152
+ : {}),
153
+ scope: result.scope,
154
+ defaults_changed: result.defaultsChanged,
155
+ do_not_retry: result.doNotRetry,
156
+ ...(result.reason ? { reason: result.reason } : {})
157
+ });
158
+ }
159
+ async runRepairModelControl(options) {
160
+ const expectedBindingToken = this.validateRepairModelControl(options);
161
+ const output = await this.withPreparedModelControlRepair(options, expectedBindingToken, async (prepared) => {
162
+ const result = await prepared.bridge.repairModelControlResidual(prepared.terminal.agent, prepared.terminal.terminalControl, prepared.agentVersion, prepared.plan, prepared.residual.fingerprint, {
163
+ runtime: prepared.runtime,
164
+ beforeInput: () => this.assertFreshModelControlResidualBoundary(prepared)
165
+ });
166
+ return { prepared, result };
167
+ });
168
+ this.ports.output.print({
169
+ terminal_id: output.prepared.terminal.conversationId,
170
+ agent: output.prepared.terminal.agent,
171
+ agent_version: output.prepared.agentVersion,
172
+ behavior_profile: output.prepared.plan.behaviorProfile,
173
+ outcome: output.result.outcome,
174
+ terminal_input_attempted: output.result.terminalInputAttempted,
175
+ composer_postcondition: output.result.composerPostcondition,
176
+ do_not_retry: output.result.doNotRetry,
177
+ ...(output.result.reason ? { reason: output.result.reason } : {}),
178
+ ...(output.result.outcome === "repaired"
179
+ ? { next: "refresh_list_then_model_options" }
180
+ : {})
181
+ });
182
+ }
183
+ async withPreparedModelControlRepair(options, expectedBindingToken, operation) {
184
+ const storeDir = this.ports.state.storeDir(options);
185
+ if (this.ports.state.inspectStore(storeDir).writable !== true) {
186
+ throw new Error("model-control repair requires a compatible AKK Store for current-snapshot authority");
187
+ }
188
+ const initiallyResolved = await this.ports.lifecycle.resolveLifecycleTerminal(options);
189
+ const release = this.ports.state.acquireTerminal(storeDir, initiallyResolved.terminalControl, { timeoutMs: 30_000 });
190
+ try {
191
+ const runtimeFacade = this.ports.runtime.forOptions(options);
192
+ const bridge = runtimeFacade.createBridge();
193
+ const terminal = await bridge.resolveStoredTerminal(initiallyResolved.agent, initiallyResolved.pid, initiallyResolved.terminalControl, { pid: initiallyResolved.pid });
194
+ this.ports.lifecycle.assertSameInspectionTerminal(initiallyResolved, terminal, "while waiting for model-control repair ownership");
195
+ if (terminal.agent !== "codex") {
196
+ throw new Error("model-control residual repair currently supports only verified Codex profiles");
197
+ }
198
+ const snapshot = await this.modelControlSnapshot(options, terminal);
199
+ const agentVersion = required(nonBlankString(snapshot.version), "model-control repair requires an exact running agent version");
200
+ const adapter = runtimeFacade.createAgentRegistry().require(terminal.agent);
201
+ const { capability, plan, profile } = modelControlProfileObservation(adapter, agentVersion);
202
+ if (!plan || profile?.agent !== "codex" ||
203
+ !profile.supportsResidualRepair) {
204
+ throw new Error(capability?.reason ??
205
+ "the running Codex version has no verified model-control repair profile");
206
+ }
207
+ await this.assertModelControlExclusive({ options, terminal, snapshot });
208
+ const runtime = this.ports.lifecycle.inspectionRuntime(terminal, snapshot);
209
+ const status = await this.assertModelControlRepairReady({
210
+ options,
211
+ terminal,
212
+ snapshot,
213
+ bridge,
214
+ runtime
215
+ });
216
+ const residual = await bridge.inspectModelControlResidual(terminal.agent, terminal.terminalControl, agentVersion, plan, { runtime, beforeInput: () => undefined });
217
+ if (residual.state !== "recoverable") {
218
+ throw new Error(residual.reason);
219
+ }
220
+ const availability = this.modelControlAvailability({
221
+ options,
222
+ terminal,
223
+ snapshot,
224
+ agentVersion,
225
+ plan,
226
+ status,
227
+ surface: {
228
+ kind: "residual",
229
+ residualKind: residual.kind,
230
+ residualFingerprint: residual.fingerprint,
231
+ activityState: status.activity_state
232
+ }
233
+ });
234
+ const repairBindingToken = availability.availability === "residual_continuation"
235
+ ? availability.repairBindingToken
236
+ : availability.availability === "repair_only"
237
+ ? availability.expectedBindingToken
238
+ : undefined;
239
+ if (repairBindingToken !== expectedBindingToken) {
240
+ throw new Error("the exact model-control residual changed after it was listed; refresh AKK list");
241
+ }
242
+ return await operation({
243
+ options,
244
+ terminal,
245
+ snapshot,
246
+ bridge,
247
+ runtime,
248
+ adapter,
249
+ agentVersion,
250
+ plan,
251
+ expectedBindingToken,
252
+ residual
253
+ });
254
+ }
255
+ finally {
256
+ release();
257
+ }
258
+ }
259
+ async assertFreshModelControlResidualBoundary(context) {
260
+ const terminal = await this.resolveModelControlBoundaryTerminal(context);
261
+ this.ports.lifecycle.assertSameInspectionTerminal(context.terminal, terminal, "immediately before model-control repair input");
262
+ const snapshot = await this.modelControlSnapshot(context.options, terminal);
263
+ if (snapshot.version !== context.agentVersion) {
264
+ throw new Error("terminal binding or coding-agent version changed during model-control repair");
265
+ }
266
+ const expectedNativeThreadId = context.snapshot.identity?.sessionId ??
267
+ context.snapshot.session?.binding?.native_thread_id;
268
+ const actualNativeThreadId = snapshot.identity?.sessionId ??
269
+ snapshot.session?.binding?.native_thread_id;
270
+ if (expectedNativeThreadId !== actualNativeThreadId) {
271
+ throw new Error("the current native Session changed during model-control repair");
272
+ }
273
+ const { plan } = modelControlProfileObservation(context.adapter, snapshot.version);
274
+ if (!plan || JSON.stringify(plan) !== JSON.stringify(context.plan)) {
275
+ throw new Error("the exact model-control repair profile changed during the operation");
276
+ }
277
+ await this.assertModelControlExclusive({
278
+ options: context.options,
279
+ terminal,
280
+ snapshot
281
+ });
282
+ await this.assertModelControlRepairReady({
283
+ options: context.options,
284
+ terminal,
285
+ snapshot,
286
+ bridge: context.bridge,
287
+ runtime: context.runtime
288
+ });
289
+ }
290
+ async assertModelControlRepairReady(input) {
291
+ const status = await input.bridge.status(input.terminal.agent, input.terminal.terminalControl, { runtime: input.runtime });
292
+ if (status.reachable !== true ||
293
+ status.approval_state.scanned !== true ||
294
+ status.approval_state.blocked === true ||
295
+ status.interaction_state !== undefined) {
296
+ throw new Error("model-control repair requires a reachable prompt with no approval or questionnaire");
297
+ }
298
+ const storeDir = this.ports.state.storeDir(input.options);
299
+ const blocker = this.ports.state.terminalBlockingTurns(storeDir, input.terminal.terminalControl)[0];
300
+ if (blocker) {
301
+ throw new Error(`terminal ${input.terminal.terminalControl.target} still has unresolved Turn ` +
302
+ `${turnIdForConversation(blocker)} (${blocker.status})`);
303
+ }
304
+ if (input.snapshot.session &&
305
+ this.ports.state.hasUnresolvedTransition(storeDir, input.snapshot.session)) {
306
+ throw new Error(`managed Session ${input.snapshot.session.session_id} has an unresolved native-thread transition`);
307
+ }
308
+ if (this.ports.state.dispatchOwnership(input.terminal.terminalControl).state !==
309
+ "none") {
310
+ throw new Error("the terminal has unresolved dispatch ownership during model-control repair");
311
+ }
312
+ if (this.ports.state.orphanedForRecovery(input.terminal.terminalControl)) {
313
+ throw new Error("the terminal has unresolved input ownership during model-control repair");
314
+ }
315
+ return status;
316
+ }
317
+ modelControlAvailability(input) {
318
+ const nativeThreadId = input.snapshot.identity?.sessionId ??
319
+ input.snapshot.session?.binding?.native_thread_id;
320
+ const zeroRolloutVerified = input.terminal.agent === "codex" &&
321
+ !input.snapshot.identity && !input.snapshot.session;
322
+ const incarnation = this.ports.identity.physicalProcessIncarnation(input.terminal.pid);
323
+ const storeDir = this.ports.state.storeDir(input.options);
324
+ return decideModelControlAvailability({
325
+ exactTerminalRow: true,
326
+ terminalId: input.terminal.conversationId,
327
+ processState: "active",
328
+ terminalControl: input.terminal.terminalControl,
329
+ agent: input.terminal.agent,
330
+ pid: input.terminal.pid,
331
+ processUuid: incarnation.processUuid,
332
+ processBirth: incarnation.processBirth,
333
+ agentVersion: input.agentVersion,
334
+ behaviorProfile: input.plan.behaviorProfile,
335
+ nativeAuthority: isExactNativeThreadId(nativeThreadId)
336
+ ? {
337
+ kind: "exact_session",
338
+ ordinaryBindingToken: input.snapshot.bindingToken
339
+ }
340
+ : zeroRolloutVerified
341
+ ? { kind: "verified_zero_rollout" }
342
+ : { kind: "unavailable" },
343
+ modelControlSupported: true,
344
+ approvalScanned: input.status.approval_state.scanned === true,
345
+ approvalBlocked: input.status.approval_state.blocked === true,
346
+ terminalHasInteraction: input.status.interaction_state !== undefined,
347
+ terminalHasBlockingTurn: this.ports.state.terminalBlockingTurns(storeDir, input.terminal.terminalControl).length > 0,
348
+ hasOrphanedDispatch: this.ports.state.dispatchOwnership(input.terminal.terminalControl)
349
+ .state !== "none" ||
350
+ this.ports.state.orphanedForRecovery(input.terminal.terminalControl) !== undefined,
351
+ surface: input.surface
352
+ });
353
+ }
354
+ async prepareModelControlBinding(input) {
355
+ const { options, terminal, expectedBindingToken, runtimeFacade } = input;
356
+ const behavior = input;
357
+ const snapshot = await this.modelControlSnapshot(options, terminal);
358
+ const ordinaryBindingToken = required(nonBlankString(snapshot.bindingToken), "terminal model control requires current ordinary binding authority");
359
+ const hasOrdinaryAuthority = snapshot.bindingTokens.includes(expectedBindingToken);
360
+ if (!hasOrdinaryAuthority && !behavior.allowResidualEntry) {
361
+ throw new Error("terminal binding changed after it was listed; refresh AKK list and retry");
362
+ }
363
+ const agentVersion = required(nonBlankString(snapshot.version), "model control requires an exact running agent version");
364
+ const adapter = runtimeFacade.createAgentRegistry().require(terminal.agent);
365
+ const { capability, plan, profile } = modelControlProfileObservation(adapter, agentVersion);
366
+ if (capability?.status !== "supported" ||
367
+ capability.modelSelection !== true ||
368
+ capability.reasoningEffortSelection !== true) {
369
+ throw new Error(capability?.reason ??
370
+ `${adapter.displayName} has no verified model-control profile`);
371
+ }
372
+ if (!plan || !profile) {
373
+ throw new Error("the agent adapter did not produce a model-control plan");
374
+ }
375
+ await this.assertModelControlExclusive({ options, terminal, snapshot });
376
+ return { snapshot, ordinaryBindingToken, hasOrdinaryAuthority, agentVersion, adapter, plan, profile };
377
+ }
378
+ async observeOrdinaryModelControlEntry(input) {
379
+ const { options, terminal, snapshot, bridge, agentVersion, plan, ordinaryBindingToken } = input;
380
+ const ready = await this.ports.lifecycle.observeInitialInspectionReady(options, terminal, snapshot, bridge);
381
+ if (ready.status.approval_state.scanned !== true ||
382
+ ready.status.approval_state.blocked === true ||
383
+ ready.status.interaction_state !== undefined) {
384
+ throw new Error("model control requires a freshly scanned terminal with no approval or questionnaire");
385
+ }
386
+ const availability = this.modelControlAvailability({
387
+ options,
388
+ terminal,
389
+ snapshot,
390
+ agentVersion,
391
+ plan,
392
+ status: ready.status,
393
+ surface: {
394
+ kind: "idle_empty",
395
+ screenState: ready.status.screen_state
396
+ }
397
+ });
398
+ if (availability.availability !== "open_from_empty" ||
399
+ availability.expectedBindingToken !== ordinaryBindingToken) {
400
+ throw new Error("model control requires an exact verified idle pane with an empty composer and no blocking interaction");
401
+ }
402
+ return ready.runtime;
403
+ }
404
+ async observeResidualModelControlEntry(input) {
405
+ const { options, terminal, snapshot, bridge, agentVersion, plan, expectedBindingToken } = input;
406
+ if (terminal.agent !== "codex" ||
407
+ terminalModelControlProfileForPlan(plan)
408
+ ?.supportsResidualContinuation !== true) {
409
+ throw new Error("terminal binding changed after it was listed; refresh AKK list and retry");
410
+ }
411
+ const runtime = this.ports.lifecycle.inspectionRuntime(terminal, snapshot);
412
+ const status = await this.assertModelControlRepairReady({
413
+ options,
414
+ terminal,
415
+ snapshot,
416
+ bridge,
417
+ runtime
418
+ });
419
+ const observed = await bridge.inspectModelControlResidual(terminal.agent, terminal.terminalControl, agentVersion, plan, { runtime, beforeInput: () => undefined });
420
+ if (observed.state !== "recoverable") {
421
+ throw new Error(observed.reason);
422
+ }
423
+ const availability = this.modelControlAvailability({
424
+ options,
425
+ terminal,
426
+ snapshot,
427
+ agentVersion,
428
+ plan,
429
+ status,
430
+ surface: {
431
+ kind: "residual",
432
+ residualKind: observed.kind,
433
+ residualFingerprint: observed.fingerprint,
434
+ activityState: status.activity_state
435
+ }
436
+ });
437
+ if (availability.availability !== "residual_continuation" ||
438
+ availability.expectedBindingToken !== expectedBindingToken) {
439
+ throw new Error("the exact model-control residual changed after it was listed; refresh AKK list");
440
+ }
441
+ return { runtime, initialResidual: observed };
442
+ }
443
+ async withPreparedModelControl(options, expectedBindingToken, operation, behavior = {}) {
444
+ const storeDir = this.ports.state.storeDir(options);
445
+ if (this.ports.state.inspectStore(storeDir).writable !== true) {
446
+ throw new Error("terminal model control requires a compatible AKK Store for current-snapshot authority");
447
+ }
448
+ const initiallyResolved = await this.ports.lifecycle.resolveLifecycleTerminal(options);
449
+ const release = this.ports.state.acquireTerminal(storeDir, initiallyResolved.terminalControl, { timeoutMs: 30_000 });
450
+ try {
451
+ const runtimeFacade = this.ports.runtime.forOptions(options);
452
+ const bridge = runtimeFacade.createBridge();
453
+ const terminal = await bridge.resolveStoredTerminal(initiallyResolved.agent, initiallyResolved.pid, initiallyResolved.terminalControl, { pid: initiallyResolved.pid });
454
+ this.ports.lifecycle.assertSameInspectionTerminal(initiallyResolved, terminal, "while waiting for model-control ownership");
455
+ const { snapshot, ordinaryBindingToken, hasOrdinaryAuthority, agentVersion, adapter, plan, profile } = await this.prepareModelControlBinding({
456
+ options, terminal, expectedBindingToken, runtimeFacade,
457
+ allowResidualEntry: behavior.allowResidualEntry
458
+ });
459
+ const entry = { options, terminal, snapshot, bridge, agentVersion, plan };
460
+ const { runtime, initialResidual } = hasOrdinaryAuthority
461
+ ? { runtime: await this.observeOrdinaryModelControlEntry({
462
+ ...entry, ordinaryBindingToken
463
+ }), initialResidual: undefined }
464
+ : await this.observeResidualModelControlEntry({ ...entry, expectedBindingToken });
465
+ const codexCatalogVersion = profile.agent === "codex" &&
466
+ isCodexModelControlAgentVersion(profile.agentVersion)
467
+ ? profile.agentVersion
468
+ : undefined;
469
+ return await operation({
470
+ options,
471
+ terminal,
472
+ snapshot,
473
+ bridge,
474
+ runtime,
475
+ adapter,
476
+ agentVersion,
477
+ plan,
478
+ expectedBindingToken,
479
+ ordinaryBindingToken,
480
+ initialResidual,
481
+ ...(terminal.agent === "codex" &&
482
+ isTerminalModelControlPlanForAgent(plan, "codex") &&
483
+ codexCatalogVersion !== undefined
484
+ ? {
485
+ loadCodexCatalog: async () => runtimeFacade.codexModelCatalogForRunningProcess(terminal.pid, codexCatalogVersion, terminal.terminalControl.currentPath)
486
+ }
487
+ : {})
488
+ });
489
+ }
490
+ finally {
491
+ release();
492
+ }
493
+ }
494
+ async assertFreshModelControlBoundary(context) {
495
+ const terminal = await this.resolveModelControlBoundaryTerminal(context);
496
+ this.ports.lifecycle.assertSameInspectionTerminal(context.terminal, terminal, "immediately before model-control input");
497
+ const snapshot = await this.modelControlSnapshot(context.options, terminal);
498
+ if (!snapshot.bindingTokens.includes(context.expectedBindingToken) ||
499
+ snapshot.version !== context.agentVersion) {
500
+ throw new Error("terminal binding or coding-agent version changed during model control; refresh AKK list");
501
+ }
502
+ const expectedNativeThreadId = context.snapshot.identity?.sessionId ??
503
+ context.snapshot.session?.binding?.native_thread_id;
504
+ const actualNativeThreadId = snapshot.identity?.sessionId ??
505
+ snapshot.session?.binding?.native_thread_id;
506
+ if (expectedNativeThreadId !== actualNativeThreadId) {
507
+ throw new Error("the current native Session changed during model control; inspect the pane before retrying");
508
+ }
509
+ const { plan } = modelControlProfileObservation(context.adapter, snapshot.version);
510
+ if (!plan || JSON.stringify(plan) !== JSON.stringify(context.plan)) {
511
+ throw new Error("the exact model-control profile changed during the operation");
512
+ }
513
+ await this.assertModelControlExclusive({
514
+ options: context.options,
515
+ terminal,
516
+ snapshot
517
+ });
518
+ this.ports.lifecycle.assertInspectionReady({
519
+ options: context.options,
520
+ terminal,
521
+ session: snapshot.session
522
+ });
523
+ this.assertModelControlAgentIdentity({
524
+ options: context.options,
525
+ terminal,
526
+ snapshot
527
+ });
528
+ }
529
+ async resolveModelControlBoundaryTerminal(context) {
530
+ try {
531
+ return await context.bridge.resolveStoredTerminal(context.terminal.agent, context.terminal.pid, context.terminal.terminalControl, context.runtime);
532
+ }
533
+ catch (idleError) {
534
+ if (context.terminal.agent !== "claude" ||
535
+ !terminalModelControlPlanConforms({
536
+ agent: context.terminal.agent,
537
+ agentVersion: context.agentVersion,
538
+ plan: context.plan
539
+ }) ||
540
+ context.runtime.requireExactClaudeAgentRow !== true ||
541
+ context.runtime.exactClaudeAgentState !== "idle") {
542
+ throw idleError;
543
+ }
544
+ try {
545
+ return await context.bridge.resolveStoredTerminal(context.terminal.agent, context.terminal.pid, context.terminal.terminalControl, { ...context.runtime, exactClaudeAgentState: "status_dialog" });
546
+ }
547
+ catch {
548
+ // All immutable process, native Session, cwd, and terminal fences are
549
+ // identical in both attempts. Only the exact Claude agents UI state
550
+ // differs, and the bridge must still prove a fresh profiled model
551
+ // surface after this read-only boundary before any key is dispatched.
552
+ throw idleError;
553
+ }
554
+ }
555
+ }
556
+ assertModelControlAgentIdentity(input) {
557
+ if (input.terminal.agent !== "claude")
558
+ return;
559
+ try {
560
+ this.ports.lifecycle.assertInspectionAgentIdentity({
561
+ ...input,
562
+ stage: "during model control",
563
+ expectedClaudeState: "idle"
564
+ });
565
+ }
566
+ catch (idleError) {
567
+ try {
568
+ this.ports.lifecycle.assertInspectionAgentIdentity({
569
+ ...input,
570
+ stage: "during model control",
571
+ expectedClaudeState: "status_dialog"
572
+ });
573
+ }
574
+ catch {
575
+ throw idleError;
576
+ }
577
+ }
578
+ }
579
+ async assertModelControlExclusive(input) {
580
+ if (input.terminal.agent === "codex") {
581
+ const nativeThreadId = input.snapshot.identity?.sessionId ??
582
+ input.snapshot.session?.binding?.native_thread_id;
583
+ if (!nativeThreadId && !input.snapshot.identity && !input.snapshot.session) {
584
+ // A fresh, verified-empty Codex process has no durable native Session
585
+ // to own yet. The physical pane/process/cwd fence remains exact.
586
+ this.ports.lifecycle.assertForegroundHasNoLifecycleTransition(input.options, input.terminal);
587
+ return;
588
+ }
589
+ if (!isExactNativeThreadId(nativeThreadId)) {
590
+ throw new Error("Codex model control requires either a fresh zero-rollout pane or one exact current native Session identity");
591
+ }
592
+ await this.ports.lifecycle.assertExclusive({
593
+ options: input.options,
594
+ agent: input.terminal.agent,
595
+ currentPid: input.terminal.pid,
596
+ nativeThreadId,
597
+ storeDir: this.ports.state.storeDir(input.options),
598
+ terminalControl: input.terminal.terminalControl,
599
+ excludedManagedSessionId: input.snapshot.session?.session_id
600
+ });
601
+ return;
602
+ }
603
+ const nativeThreadId = input.snapshot.identity?.sessionId ??
604
+ input.snapshot.session?.binding?.native_thread_id;
605
+ if (!isExactNativeThreadId(nativeThreadId)) {
606
+ throw new Error("model control requires one exact current native Session identity");
607
+ }
608
+ await this.ports.lifecycle.assertExclusive({
609
+ options: input.options,
610
+ agent: input.terminal.agent,
611
+ currentPid: input.terminal.pid,
612
+ nativeThreadId,
613
+ storeDir: this.ports.state.storeDir(input.options),
614
+ terminalControl: input.terminal.terminalControl,
615
+ excludedManagedSessionId: input.snapshot.session?.session_id
616
+ });
617
+ }
618
+ modelOptionsResult(context, catalog) {
619
+ return {
620
+ terminal_id: context.terminal.conversationId,
621
+ agent: context.terminal.agent,
622
+ agent_version: context.agentVersion,
623
+ behavior_profile: catalog.behaviorProfile,
624
+ scope: catalog.scope,
625
+ current: modelValueOutput(catalog.current),
626
+ models: catalog.models.map((model) => ({
627
+ id: model.id,
628
+ label: model.label,
629
+ reasoning_efforts: [...model.reasoningEfforts]
630
+ })),
631
+ catalog_fingerprint: catalog.catalogFingerprint,
632
+ available_actions: {
633
+ set_model: {
634
+ tool: "agent_knock_knock_set_model",
635
+ arguments: {
636
+ terminal_id: context.terminal.conversationId,
637
+ expected_binding_token: context.ordinaryBindingToken,
638
+ expected_catalog_fingerprint: catalog.catalogFingerprint
639
+ }
640
+ }
641
+ }
642
+ };
643
+ }
644
+ }
645
+ function modelValueOutput(value) {
646
+ return {
647
+ model: value.model,
648
+ ...(value.reasoningEffort
649
+ ? { reasoning_effort: value.reasoningEffort }
650
+ : {})
651
+ };
652
+ }
653
+ function modelControlProfileObservation(adapter, agentVersion) {
654
+ const capability = adapter.probeModelControl?.(agentVersion);
655
+ const plan = capability?.status === "supported"
656
+ ? adapter.planModelControl?.(capability)
657
+ : undefined;
658
+ return {
659
+ capability,
660
+ plan,
661
+ profile: plan ? terminalModelControlProfileForPlan(plan) : undefined
662
+ };
663
+ }
664
+ function required(value, message) {
665
+ if (value === undefined || value === "")
666
+ throw new Error(message);
667
+ return value;
668
+ }
669
+ //# sourceMappingURL=terminal-model-control-cli-adapter.js.map