@robota-sdk/agent-cli 3.0.0-beta.82 → 3.0.0-beta.84

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 (146) hide show
  1. package/CHANGELOG.md +2546 -0
  2. package/README.md +225 -1128
  3. package/dist/node/bin.js +33 -2
  4. package/dist/node/bounded-output-D3cgiOrh-C5ywb_Yg.js +2 -0
  5. package/dist/node/bounded-output-D3cgiOrh-C5ywb_Yg.js.map +1 -0
  6. package/dist/node/bounded-output-D3cgiOrh-kO7zrx1P.js +2 -0
  7. package/dist/node/cli-core-BloQpWhd.js +2891 -0
  8. package/dist/node/{command-executor-DV-H2oD6-BfKoGoFw.js → command-executor-BdE1zg3q-BGQmze1E.js} +1 -1
  9. package/dist/node/{command-executor-DV-H2oD6-OKy8pwYH.js → command-executor-BdE1zg3q-Br7z38P6.js} +2 -2
  10. package/dist/node/{command-executor-DV-H2oD6-OKy8pwYH.js.map → command-executor-BdE1zg3q-Br7z38P6.js.map} +1 -1
  11. package/dist/node/headless.js +2 -2
  12. package/dist/node/index.d.ts +358 -109
  13. package/dist/node/index.d.ts.map +1 -1
  14. package/dist/node/index.js +452 -328
  15. package/dist/node/index.js.map +1 -1
  16. package/dist/node/node-A7RJeEyA.js +14 -0
  17. package/dist/node/node-A7RJeEyA.js.map +1 -0
  18. package/dist/node/node-B_3rSS2i.js +67 -0
  19. package/dist/node/node-BhEYLQDQ.js +67 -0
  20. package/dist/node/node-BhEYLQDQ.js.map +1 -0
  21. package/dist/node/{node-bJ0lEuNF.js → node-C4_FOvnk.js} +2 -2
  22. package/dist/node/{node-bJ0lEuNF.js.map → node-C4_FOvnk.js.map} +1 -1
  23. package/dist/node/node-CCe6GM9V.js +14 -0
  24. package/dist/node/{node-2-nrieFn.js → node-DENLEmMT.js} +2 -2
  25. package/dist/node/{node-2-nrieFn.js.map → node-DENLEmMT.js.map} +1 -1
  26. package/dist/node/{node-cmTHiSYe.js → node-D_fk2mK2.js} +1 -1
  27. package/dist/web/assets/PretendardVariable.subset.0-BHUkWNFR.woff2 +0 -0
  28. package/dist/web/assets/PretendardVariable.subset.1-C-__qv6_.woff2 +0 -0
  29. package/dist/web/assets/PretendardVariable.subset.10-DzSWztS8.woff2 +0 -0
  30. package/dist/web/assets/PretendardVariable.subset.11-CqVmlKJn.woff2 +0 -0
  31. package/dist/web/assets/PretendardVariable.subset.12-BHuZSgT0.woff2 +0 -0
  32. package/dist/web/assets/PretendardVariable.subset.13-C42mj_j2.woff2 +0 -0
  33. package/dist/web/assets/PretendardVariable.subset.14-Bl512uUX.woff2 +0 -0
  34. package/dist/web/assets/PretendardVariable.subset.15-D04iXIE3.woff2 +0 -0
  35. package/dist/web/assets/PretendardVariable.subset.16-BQUnS2GX.woff2 +0 -0
  36. package/dist/web/assets/PretendardVariable.subset.17-BfZSA-Xc.woff2 +0 -0
  37. package/dist/web/assets/PretendardVariable.subset.18-CwAxMC3C.woff2 +0 -0
  38. package/dist/web/assets/PretendardVariable.subset.19-CJu4Zcdo.woff2 +0 -0
  39. package/dist/web/assets/PretendardVariable.subset.2-dCZkyKLw.woff2 +0 -0
  40. package/dist/web/assets/PretendardVariable.subset.20-Ig1-z3n5.woff2 +0 -0
  41. package/dist/web/assets/PretendardVariable.subset.21-yKPEdLXC.woff2 +0 -0
  42. package/dist/web/assets/PretendardVariable.subset.22-CSqxKoOs.woff2 +0 -0
  43. package/dist/web/assets/PretendardVariable.subset.23-DK80wi0t.woff2 +0 -0
  44. package/dist/web/assets/PretendardVariable.subset.24-CmkE8Q8D.woff2 +0 -0
  45. package/dist/web/assets/PretendardVariable.subset.25-CsoWBIZB.woff2 +0 -0
  46. package/dist/web/assets/PretendardVariable.subset.26-Sozl8dw8.woff2 +0 -0
  47. package/dist/web/assets/PretendardVariable.subset.27-CT6nuW9L.woff2 +0 -0
  48. package/dist/web/assets/PretendardVariable.subset.28-CpO0Y96p.woff2 +0 -0
  49. package/dist/web/assets/PretendardVariable.subset.29-D6hjrUWm.woff2 +0 -0
  50. package/dist/web/assets/PretendardVariable.subset.3-Dqw33sf4.woff2 +0 -0
  51. package/dist/web/assets/PretendardVariable.subset.30-CWDM1c0J.woff2 +0 -0
  52. package/dist/web/assets/PretendardVariable.subset.31-CdmyZ5mm.woff2 +0 -0
  53. package/dist/web/assets/PretendardVariable.subset.32-CGnFWD2i.woff2 +0 -0
  54. package/dist/web/assets/PretendardVariable.subset.33--0OT__YQ.woff2 +0 -0
  55. package/dist/web/assets/PretendardVariable.subset.34-CaCS33Md.woff2 +0 -0
  56. package/dist/web/assets/PretendardVariable.subset.35-DWFYRGLp.woff2 +0 -0
  57. package/dist/web/assets/PretendardVariable.subset.36-Dn5IBRQB.woff2 +0 -0
  58. package/dist/web/assets/PretendardVariable.subset.37-BD6FyOtY.woff2 +0 -0
  59. package/dist/web/assets/PretendardVariable.subset.38-D4hu443z.woff2 +0 -0
  60. package/dist/web/assets/PretendardVariable.subset.39-B_7wfth9.woff2 +0 -0
  61. package/dist/web/assets/PretendardVariable.subset.4-Bvh2YGoc.woff2 +0 -0
  62. package/dist/web/assets/PretendardVariable.subset.40-BDaOfdUe.woff2 +0 -0
  63. package/dist/web/assets/PretendardVariable.subset.41-BUACvzZC.woff2 +0 -0
  64. package/dist/web/assets/PretendardVariable.subset.42-Dp-5mnyL.woff2 +0 -0
  65. package/dist/web/assets/PretendardVariable.subset.43-DHdpry7N.woff2 +0 -0
  66. package/dist/web/assets/PretendardVariable.subset.44-qHopVhdd.woff2 +0 -0
  67. package/dist/web/assets/PretendardVariable.subset.45-BniyRFfm.woff2 +0 -0
  68. package/dist/web/assets/PretendardVariable.subset.46-BMRq7xC-.woff2 +0 -0
  69. package/dist/web/assets/PretendardVariable.subset.47-B-cWO2pw.woff2 +0 -0
  70. package/dist/web/assets/PretendardVariable.subset.48-Ct-fWrPO.woff2 +0 -0
  71. package/dist/web/assets/PretendardVariable.subset.49-BblQVys9.woff2 +0 -0
  72. package/dist/web/assets/PretendardVariable.subset.5-K_MNGNCe.woff2 +0 -0
  73. package/dist/web/assets/PretendardVariable.subset.50-C8IyFH7L.woff2 +0 -0
  74. package/dist/web/assets/PretendardVariable.subset.51-Bxd0gTAs.woff2 +0 -0
  75. package/dist/web/assets/PretendardVariable.subset.52-CNgqKOOJ.woff2 +0 -0
  76. package/dist/web/assets/PretendardVariable.subset.53-BSRnyb-u.woff2 +0 -0
  77. package/dist/web/assets/PretendardVariable.subset.54-Dt2-cQkx.woff2 +0 -0
  78. package/dist/web/assets/PretendardVariable.subset.55-jFgflYjX.woff2 +0 -0
  79. package/dist/web/assets/PretendardVariable.subset.56-BwZdvJZQ.woff2 +0 -0
  80. package/dist/web/assets/PretendardVariable.subset.57-BwFDg-Fs.woff2 +0 -0
  81. package/dist/web/assets/PretendardVariable.subset.58-DlucQts_.woff2 +0 -0
  82. package/dist/web/assets/PretendardVariable.subset.59-CMkWjhdo.woff2 +0 -0
  83. package/dist/web/assets/PretendardVariable.subset.6-Bxhohlcm.woff2 +0 -0
  84. package/dist/web/assets/PretendardVariable.subset.60-CeHezjjf.woff2 +0 -0
  85. package/dist/web/assets/PretendardVariable.subset.61-PUuTnod4.woff2 +0 -0
  86. package/dist/web/assets/PretendardVariable.subset.62-DGSAWCfb.woff2 +0 -0
  87. package/dist/web/assets/PretendardVariable.subset.63-B35xsm4O.woff2 +0 -0
  88. package/dist/web/assets/PretendardVariable.subset.64-CTbrgYF9.woff2 +0 -0
  89. package/dist/web/assets/PretendardVariable.subset.65-B66rjuyf.woff2 +0 -0
  90. package/dist/web/assets/PretendardVariable.subset.66-C3HqaDeY.woff2 +0 -0
  91. package/dist/web/assets/PretendardVariable.subset.67-BmuXdlDy.woff2 +0 -0
  92. package/dist/web/assets/PretendardVariable.subset.68-DS9B48d0.woff2 +0 -0
  93. package/dist/web/assets/PretendardVariable.subset.69-YT16ymcp.woff2 +0 -0
  94. package/dist/web/assets/PretendardVariable.subset.7-E2HaA55t.woff2 +0 -0
  95. package/dist/web/assets/PretendardVariable.subset.70-BUXiAGMT.woff2 +0 -0
  96. package/dist/web/assets/PretendardVariable.subset.71-DuPZj8us.woff2 +0 -0
  97. package/dist/web/assets/PretendardVariable.subset.72-pYYGrEQR.woff2 +0 -0
  98. package/dist/web/assets/PretendardVariable.subset.73-DMrK970F.woff2 +0 -0
  99. package/dist/web/assets/PretendardVariable.subset.74-D4tQnymK.woff2 +0 -0
  100. package/dist/web/assets/PretendardVariable.subset.75-CxKdrRNf.woff2 +0 -0
  101. package/dist/web/assets/PretendardVariable.subset.76-DhPm2b_q.woff2 +0 -0
  102. package/dist/web/assets/PretendardVariable.subset.77-DwaxqOC8.woff2 +0 -0
  103. package/dist/web/assets/PretendardVariable.subset.78-DhqRbBzT.woff2 +0 -0
  104. package/dist/web/assets/PretendardVariable.subset.79-XpoyPP38.woff2 +0 -0
  105. package/dist/web/assets/PretendardVariable.subset.8-CRbJhhyA.woff2 +0 -0
  106. package/dist/web/assets/PretendardVariable.subset.80-DsV9Qp_h.woff2 +0 -0
  107. package/dist/web/assets/PretendardVariable.subset.81-BZzF9Hb3.woff2 +0 -0
  108. package/dist/web/assets/PretendardVariable.subset.82-BgAHe30u.woff2 +0 -0
  109. package/dist/web/assets/PretendardVariable.subset.83-DF-zBLLe.woff2 +0 -0
  110. package/dist/web/assets/PretendardVariable.subset.84-Brb8EsYQ.woff2 +0 -0
  111. package/dist/web/assets/PretendardVariable.subset.85-Byo_x2hf.woff2 +0 -0
  112. package/dist/web/assets/PretendardVariable.subset.86-XG7lTN_6.woff2 +0 -0
  113. package/dist/web/assets/PretendardVariable.subset.87-Lzui2vbK.woff2 +0 -0
  114. package/dist/web/assets/PretendardVariable.subset.88-CqX6JSgh.woff2 +0 -0
  115. package/dist/web/assets/PretendardVariable.subset.89-DOzqWPpX.woff2 +0 -0
  116. package/dist/web/assets/PretendardVariable.subset.9-Btb3bmS6.woff2 +0 -0
  117. package/dist/web/assets/PretendardVariable.subset.90-BF7RiZjm.woff2 +0 -0
  118. package/dist/web/assets/PretendardVariable.subset.91-Csm0YNoH.woff2 +0 -0
  119. package/dist/web/assets/index-DSLs7oij.js +309 -0
  120. package/dist/web/assets/index-OqCBtMJ2.css +1 -0
  121. package/dist/web/index.html +6 -4
  122. package/package.json +43 -47
  123. package/dist/node/bounded-output-DpjpS98g-DFgAppgl.js +0 -2
  124. package/dist/node/bounded-output-DpjpS98g-DFgAppgl.js.map +0 -1
  125. package/dist/node/bounded-output-DpjpS98g-DoRuRGhV.js +0 -2
  126. package/dist/node/bounded-output-DpjpS98g-yPybHprY.cjs +0 -1
  127. package/dist/node/cli-core-DWG6gqoq.js +0 -2798
  128. package/dist/node/command-executor-DV-H2oD6-BAvcn7Tf.cjs +0 -1
  129. package/dist/node/http-executor-cWzI2svn-Nn7UFLl8.cjs +0 -1
  130. package/dist/node/index.cjs +0 -2796
  131. package/dist/node/index.d.cts +0 -3445
  132. package/dist/node/index.d.cts.map +0 -1
  133. package/dist/node/node-Bs1jlR4B.js +0 -67
  134. package/dist/node/node-CFTax5Wl.cjs +0 -1
  135. package/dist/node/node-CQqDd5KI.js +0 -14
  136. package/dist/node/node-CQqDd5KI.js.map +0 -1
  137. package/dist/node/node-D8uo8Kzf.cjs +0 -13
  138. package/dist/node/node-DE_LpiDk.cjs +0 -66
  139. package/dist/node/node-Du_7g6qW.js +0 -14
  140. package/dist/node/node-OBnZskvR.cjs +0 -1
  141. package/dist/node/node-hHzxDyjn.js +0 -67
  142. package/dist/node/node-hHzxDyjn.js.map +0 -1
  143. package/dist/node/rolldown-runtime-DK3Fl9T5-BIInC43l.cjs +0 -1
  144. package/dist/node/verdict-decoder-Dk_w2NG9-DNTeVdQ8.cjs +0 -1
  145. package/dist/web/assets/index-8_Slbxe7.css +0 -1
  146. package/dist/web/assets/index-Cgu5C1kn.js +0 -77
@@ -3,7 +3,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
3
3
  import "@modelcontextprotocol/sdk/shared/auth.js";
4
4
  import "@modelcontextprotocol/sdk/types.js";
5
5
  import "@modelcontextprotocol/sdk/shared/transport.js";
6
- //#region ../agent-core/dist/node/types-gNrckgFE.d.ts
6
+ //#region ../agent-core/dist/node/types-BQ-sKCQS.d.ts
7
7
  //#region src/interfaces/universal-value.d.ts
8
8
  /**
9
9
  * Universal value type axis (recursive, JSON-like + Date).
@@ -91,7 +91,7 @@ interface IOutboundTraceContext {
91
91
  /** Claude Code compatible session end reasons. */
92
92
  type TSessionEndReason = 'clear' | 'resume' | 'logout' | 'prompt_input_exit' | 'bypass_permissions_disabled' | 'other';
93
93
  //#endregion
94
- //#region ../agent-core/dist/node/index-D2rky0wZ.d.ts
94
+ //#region ../agent-core/dist/node/index-DXZ-pyEr.d.ts
95
95
  /**
96
96
  * Context data type - for execution contexts
97
97
  */
@@ -105,81 +105,37 @@ type TLoggerData = Record<string, TUniversalValue | Date | Error>;
105
105
  */
106
106
  type TToolParameters = Record<string, TUniversalValue>;
107
107
  //#endregion
108
- //#region src/interfaces/interaction.d.ts
109
- /**
110
- * UI-agnostic "ask the user" contract (CMD-004).
111
- *
112
- * The SSOT for the interaction action lives in agent-core so every interaction *source* can reach it:
113
- * command execution (`ICommandHostContext`, agent-framework) AND tool execution
114
- * (`IToolExecutionContext`, agent-core, for model-issued questions — CMD-005). These are pure types
115
- * with no runtime dependency, so the contract crosses a serialization/transport boundary unchanged
116
- * (no function-valued fields).
117
- *
118
- * A single shape covers every interaction kind, parameterised by fields rather than split into
119
- * variants:
120
- * - confirm → two options, `maxSelect` 1
121
- * - single → options, `maxSelect` 1
122
- * - multi → options, `maxSelect` > 1
123
- * - free text → no options, `allowFreeText` true
124
- * - secret → free text with `masked` true
125
- */
126
- /** One predefined option the user can choose. */
127
- interface IActionOption {
128
- value: string;
129
- label: string;
130
- description?: string;
108
+ //#region src/interfaces/tool-continuation.d.ts
109
+ /** Core-owned identity, independent of a provider's reusable tool-call identifier. */
110
+ interface IToolActionIdentity {
111
+ executionId: string;
112
+ actionId: string;
113
+ parentCallId: string;
114
+ toolCallId: string;
115
+ toolName: string;
131
116
  }
132
- /** Pre-selected option values and/or prefilled free text for an action request. */
133
- interface IActionDefault {
134
- values?: readonly string[];
135
- text?: string;
117
+ interface IToolContinuationPrompt {
118
+ kind: string;
119
+ data: TToolParameters;
136
120
  }
137
- /** One request for the user to answer. See the module doc for how the fields encode each kind. */
138
- interface IActionRequest {
139
- /** Correlation key; the ask port resolves a given id exactly once (idempotent, first-answer wins). */
140
- id: string;
141
- title: string;
142
- description?: string;
143
- /** Predefined options. Empty/omitted ⇒ pure free-text entry. */
144
- options?: readonly IActionOption[];
145
- /** Minimum selections required (default 1). */
146
- minSelect?: number;
147
- /** Maximum selections allowed (default 1 ⇒ single; > 1 ⇒ multi). */
148
- maxSelect?: number;
149
- /** Allow a typed custom answer in addition to / instead of the options. */
150
- allowFreeText?: boolean;
151
- /** Free-text entry is masked (secret entry such as an API key); the renderer hides input. */
152
- masked?: boolean;
153
- /** Allow submitting empty free text. */
154
- allowEmpty?: boolean;
155
- /** Placeholder shown in the free-text field. */
156
- placeholder?: string;
157
- /** Maximum options shown before scrolling (renderer hint). */
158
- maxVisible?: number;
159
- /** Pre-selected option values and/or prefilled free text. */
160
- default?: IActionDefault;
121
+ interface IToolWaitRequest extends IToolActionIdentity, IToolContinuationPrompt {
122
+ requestId: string;
161
123
  }
162
- /**
163
- * The user's answer to an {@link IActionRequest}. `answer` carries the selected option values and/or
164
- * the typed text; `cancelled` means the user dismissed the request, or no interactive renderer was
165
- * available to answer it.
166
- */
167
- type TActionResponse = {
168
- type: 'answer';
169
- values: readonly string[];
170
- text?: string;
171
- } | {
172
- type: 'cancelled';
173
- };
174
- /**
175
- * The injected "ask the user" port — a single seam reachable by every interaction source (command
176
- * execution now; tool execution for model-issued questions later) and rendered per-environment by each
177
- * transport. The concurrency model (broadcast to attached interactive channels, first answer wins,
178
- * later answers for an already-resolved `id` ignored) is owned by the port implementation, not the
179
- * contract.
180
- */
181
- interface IUserInteraction {
182
- ask(request: IActionRequest): Promise<TActionResponse>;
124
+ interface IToolWaitResponse {
125
+ requestId: string;
126
+ responseId: string;
127
+ response: TToolParameters;
128
+ }
129
+ interface IToolWaitState {
130
+ request: IToolWaitRequest;
131
+ response?: IToolWaitResponse;
132
+ }
133
+ /** Available before effect admission. The runtime owns interpretation and authorization. */
134
+ interface IToolContinuation {
135
+ readonly action: IToolActionIdentity;
136
+ readonly waits: readonly IToolWaitState[];
137
+ /** Return a saved response or persist a request and suspend this execution. */
138
+ request(prompt: IToolContinuationPrompt): Promise<TToolParameters>;
183
139
  }
184
140
  /**
185
141
  * Message metadata used across conversation history and provider adapters.
@@ -361,8 +317,6 @@ interface IModelRef {
361
317
  provider: string;
362
318
  model: string;
363
319
  }
364
- //#endregion
365
- //#region src/utils/provider-failure.d.ts
366
320
  /** Why a provider call failed, as far as switching models is concerned. */
367
321
  type TProviderFailureReason = 'overloaded' | 'service-unavailable' | 'server-error' | 'model-unavailable' | 'authentication' | 'billing' | 'rate-limit' | 'invalid-request' | 'network' | 'aborted' | 'unknown';
368
322
  //#endregion
@@ -804,24 +758,6 @@ interface IAIProvider {
804
758
  */
805
759
  close?(): Promise<void>;
806
760
  }
807
- /**
808
- * The catalog a search tool loads through — the port `IToolExecutionContext.deferredTools` carries.
809
- *
810
- * Narrow on purpose: a tool that can list and load must not be able to register, remove or execute.
811
- */
812
- interface IDeferredToolCatalog {
813
- /**
814
- * Deferred tools not yet loaded — the population a search can still discover. Empty while
815
- * deferral is not engaged, because nothing is withheld then.
816
- */
817
- listDeferredTools(): IToolSchema[];
818
- /**
819
- * Mark the named deferred tools loaded for the rest of the session and return their schemas. A
820
- * resident name is returned as it is (it was never withheld); an unknown name throws, naming the
821
- * entry, and then nothing is loaded — the check runs over every name before the first load.
822
- */
823
- loadDeferredTools(names: readonly string[]): IToolSchema[];
824
- }
825
761
  //#endregion
826
762
  //#region src/event-service/interfaces.d.ts
827
763
  /**
@@ -896,7 +832,104 @@ interface IEventService {
896
832
  unsubscribe(listener: TEventListener): void;
897
833
  }
898
834
  //#endregion
835
+ //#region src/interfaces/interaction.d.ts
836
+ /**
837
+ * UI-agnostic "ask the user" contract (CMD-004).
838
+ *
839
+ * The SSOT for the interaction action lives in agent-core so every interaction *source* can reach it:
840
+ * command execution (`ICommandHostContext`, agent-framework) AND tool execution
841
+ * (`IToolExecutionContext`, agent-core, for model-issued questions — CMD-005). These are pure types
842
+ * with no runtime dependency, so the contract crosses a serialization/transport boundary unchanged
843
+ * (no function-valued fields).
844
+ *
845
+ * A single shape covers every interaction kind, parameterised by fields rather than split into
846
+ * variants:
847
+ * - confirm → two options, `maxSelect` 1
848
+ * - single → options, `maxSelect` 1
849
+ * - multi → options, `maxSelect` > 1
850
+ * - free text → no options, `allowFreeText` true
851
+ * - secret → free text with `masked` true
852
+ */
853
+ /** One predefined option the user can choose. */
854
+ interface IActionOption {
855
+ value: string;
856
+ label: string;
857
+ description?: string;
858
+ }
859
+ /** Pre-selected option values and/or prefilled free text for an action request. */
860
+ interface IActionDefault {
861
+ values?: readonly string[];
862
+ text?: string;
863
+ }
864
+ /** One request for the user to answer. See the module doc for how the fields encode each kind. */
865
+ interface IActionRequest {
866
+ /** Correlation key; the ask port resolves a given id exactly once (idempotent, first-answer wins). */
867
+ id: string;
868
+ title: string;
869
+ description?: string;
870
+ /** Predefined options. Empty/omitted ⇒ pure free-text entry. */
871
+ options?: readonly IActionOption[];
872
+ /** Minimum selections required (default 1). */
873
+ minSelect?: number;
874
+ /** Maximum selections allowed (default 1 ⇒ single; > 1 ⇒ multi). */
875
+ maxSelect?: number;
876
+ /** Allow a typed custom answer in addition to / instead of the options. */
877
+ allowFreeText?: boolean;
878
+ /** Free-text entry is masked (secret entry such as an API key); the renderer hides input. */
879
+ masked?: boolean;
880
+ /** Allow submitting empty free text. */
881
+ allowEmpty?: boolean;
882
+ /** Placeholder shown in the free-text field. */
883
+ placeholder?: string;
884
+ /** Maximum options shown before scrolling (renderer hint). */
885
+ maxVisible?: number;
886
+ /** Pre-selected option values and/or prefilled free text. */
887
+ default?: IActionDefault;
888
+ }
889
+ /**
890
+ * The user's answer to an {@link IActionRequest}. `answer` carries the selected option values and/or
891
+ * the typed text; `cancelled` means the user dismissed the request, or no interactive renderer was
892
+ * available to answer it.
893
+ */
894
+ type TActionResponse = {
895
+ type: 'answer';
896
+ values: readonly string[];
897
+ text?: string;
898
+ } | {
899
+ type: 'cancelled';
900
+ };
901
+ /**
902
+ * The injected "ask the user" port — a single seam reachable by every interaction source (command
903
+ * execution now; tool execution for model-issued questions later) and rendered per-environment by each
904
+ * transport. The concurrency model (broadcast to attached interactive channels, first answer wins,
905
+ * later answers for an already-resolved `id` ignored) is owned by the port implementation, not the
906
+ * contract.
907
+ */
908
+ interface IUserInteraction {
909
+ ask(request: IActionRequest): Promise<TActionResponse>;
910
+ }
911
+ /**
912
+ * The catalog a search tool loads through — the port `IToolExecutionContext.deferredTools` carries.
913
+ *
914
+ * Narrow on purpose: a tool that can list and load must not be able to register, remove or execute.
915
+ */
916
+ interface IDeferredToolCatalog {
917
+ /**
918
+ * Deferred tools not yet loaded — the population a search can still discover. Empty while
919
+ * deferral is not engaged, because nothing is withheld then.
920
+ */
921
+ listDeferredTools(): IToolSchema[];
922
+ /**
923
+ * Mark the named deferred tools loaded for the rest of the session and return their schemas. A
924
+ * resident name is returned as it is (it was never withheld); an unknown name throws, naming the
925
+ * entry, and then nothing is loaded — the check runs over every name before the first load.
926
+ */
927
+ loadDeferredTools(names: readonly string[]): IToolSchema[];
928
+ }
929
+ //#endregion
899
930
  //#region src/interfaces/tool.d.ts
931
+ /** Awaited host admission for effective parameters, immediately before a tool body. */
932
+ type TToolEffectAdmission<TParameters = TToolParameters> = (parameters: TParameters) => Promise<void>;
900
933
  type TToolContextExtensionValue = TUniversalValue | Date | Error | TLoggerData | TContextData | TToolParameters | TToolMetadata;
901
934
  /**
902
935
  * Tool metadata structure - specific type definition
@@ -926,6 +959,10 @@ interface IToolResult {
926
959
  interface IToolExecutionContext {
927
960
  toolName: string;
928
961
  parameters: TToolParameters;
962
+ /** Runtime-owned barrier, consumed after permission and before entering the tool. */
963
+ beforeToolEffect?: TToolEffectAdmission;
964
+ /** Journaled pre-effect request/response port for admission-aware runtime wrappers. */
965
+ continuation?: IToolContinuation;
929
966
  /**
930
967
  * Run-scoped cancellation signal (CORE-018). Long-running tools MUST honor it: terminate
931
968
  * the underlying work (kill the child process, abort the network request) and return an
@@ -984,6 +1021,14 @@ interface IToolExecutionContext {
984
1021
  * Owner-bound instances must not be layered across different owners.
985
1022
  */
986
1023
  baseEventService?: IEventService;
1024
+ /**
1025
+ * The service this call's caller would give the tool with `setEventService`, carried with the
1026
+ * call instead. One tool instance can serve several agents, and the service set on it is
1027
+ * whichever agent set one last; a tool that emits events of its own (the `FunctionTool` span)
1028
+ * emits them here when present, so they reach the agent that made the call. The no-op default
1029
+ * service means that caller wants none.
1030
+ */
1031
+ instanceEventService?: IEventService;
987
1032
  /**
988
1033
  * Injected "ask the user" port (CMD-004). Present when an interactive renderer is attached, letting
989
1034
  * a tool solicit a structured answer from the user (the model-issued question seam consumed by
@@ -1038,6 +1083,11 @@ interface IParameterValidationResult {
1038
1083
  interface IToolContract<TParameters = TToolParameters, TResult = IToolResult> {
1039
1084
  readonly schema: IToolSchema;
1040
1085
  execute(parameters: TParameters, context: IToolExecutionContext): Promise<TResult>;
1086
+ /**
1087
+ * Wrappers await admission exactly once with final canonical arguments after preconditions and before
1088
+ * the body. Denial returns without admission. Admission failures propagate unchanged.
1089
+ */
1090
+ executeWithAdmission?(parameters: TParameters, context: IToolExecutionContext, admit: TToolEffectAdmission<TParameters>): Promise<TResult>;
1041
1091
  validate(parameters: TParameters): boolean;
1042
1092
  validateParameters(parameters: TParameters): IParameterValidationResult;
1043
1093
  getDescription(): string;
@@ -1309,6 +1359,27 @@ interface ICapabilityDescriptor {
1309
1359
  * re-exports it. A transport-origin command runs as a local one by default; an optional policy may restrict (REMOTE-006).
1310
1360
  */
1311
1361
  type TCommandInvocationSource = 'user' | 'model' | 'remote';
1362
+ /**
1363
+ * Whether a `'remote'`-sourced invocation is provably on this machine. The loopback-bound WS carrier
1364
+ * (the desktop app and a locally served browser page) is `'local'`; the device-mesh/WebRTC carrier
1365
+ * proves no locality ("a browser device proves no locality, so it is treated as another machine" —
1366
+ * the same rule `ConnectionAuthority` already applies to pairing), so it is always `'remote'`. Absent
1367
+ * (an in-process caller, an older host, or a test double) defaults to `'local'` — the allow-by-default
1368
+ * posture the rest of the command layer already uses. A command that runs code from outside the
1369
+ * session (installing a plugin) reads this to refuse a remote device even though `'remote'`-sourced
1370
+ * commands otherwise run like a local one (REMOTE-006).
1371
+ */
1372
+ type TCommandSurfaceLocality = 'local' | 'remote';
1373
+ /**
1374
+ * Who runs a command. `'runtime'`: the process that owns the session runs it, whichever surface
1375
+ * sent it. `'client'`: the surface the user is typing into runs it itself, because what it does
1376
+ * belongs to that surface (its terminal, its appearance), not to the session. A client that is
1377
+ * attached to a runtime in another process runs such a command locally instead of sending it; the
1378
+ * runtime keeps it in its catalog so help stays complete and a surface that cannot run it refuses it.
1379
+ */
1380
+ type TCommandRunner = 'runtime' | 'client';
1381
+ /** A kind of client surface. Names the surfaces a `'client'` command can run on. */
1382
+ type TCommandSurface = 'terminal' | 'gui';
1312
1383
  /** A command entry */
1313
1384
  interface ICommand {
1314
1385
  /** Command name without slash (e.g., "mode") — used for invocation */
@@ -1368,6 +1439,15 @@ interface ICommand {
1368
1439
  agent?: string;
1369
1440
  /** Plugin installation directory (plugin skills/commands only) */
1370
1441
  pluginDir?: string;
1442
+ /**
1443
+ * Who runs this command. Absent → `'runtime'`; the listing resolves it, see
1444
+ * `ICommandListEntry.runner`.
1445
+ */
1446
+ runner?: TCommandRunner;
1447
+ /**
1448
+ * The surfaces a `'client'` command can run on. Absent → the command does not restrict them.
1449
+ */
1450
+ surfaces?: readonly TCommandSurface[];
1371
1451
  }
1372
1452
  /** A source that provides commands */
1373
1453
  interface ICommandSource {
@@ -1494,6 +1574,40 @@ interface ICommandListEntry {
1494
1574
  * list does not say". Those need different handling and the first must not be reached by accident.
1495
1575
  */
1496
1576
  modelInvocable: boolean;
1577
+ /**
1578
+ * Who runs this command — what a surface reads to mark a command another surface owns. A client
1579
+ * does not route by it: it runs locally only the commands it implements itself, so an older
1580
+ * runtime or a catalog that arrives late cannot misroute a command.
1581
+ *
1582
+ * REQUIRED for the same reason as `modelInvocable`: the producer resolves a command that declares
1583
+ * no runner to `'runtime'` in one place, so "runs on the runtime" is never confused with "the
1584
+ * producer of this list does not say".
1585
+ */
1586
+ runner: TCommandRunner;
1587
+ /** The surfaces a `'client'` command can run on. Absent when the command does not restrict them. */
1588
+ surfaces?: readonly TCommandSurface[];
1589
+ /** The argument grammar a client shows after the name while the user types (e.g. `<name> [args]`). */
1590
+ argumentHint?: string;
1591
+ /** The subcommands a client completes after `/<name> `. Absent when the command declares none. */
1592
+ subcommands?: readonly ICommandSubcommandEntry[];
1593
+ }
1594
+ /** A subcommand as a client offers it after its command's name. */
1595
+ interface ICommandSubcommandEntry {
1596
+ readonly name: string;
1597
+ readonly description: string;
1598
+ readonly displayName?: string;
1599
+ readonly argumentHint?: string;
1600
+ }
1601
+ /** A skill as a client offers it beside the commands; `/<name>` activates it. */
1602
+ interface ICommandSkillListEntry {
1603
+ readonly name: string;
1604
+ readonly description: string;
1605
+ readonly source: string;
1606
+ readonly modelInvocable: boolean;
1607
+ readonly userInvocable: boolean;
1608
+ readonly argumentHint?: string;
1609
+ readonly context?: string;
1610
+ readonly agent?: string;
1497
1611
  }
1498
1612
  type TPluginInstallScope = 'user' | 'project';
1499
1613
  interface ICommandInstalledPlugin {
@@ -1546,6 +1660,26 @@ interface IBackgroundTaskError {
1546
1660
  * TYPE-003: alias of the `agent-core` usage-triple SSOT (`ITokenUsage`) — derived, not re-declared.
1547
1661
  */
1548
1662
  type IBackgroundTaskUsage = ITokenUsage;
1663
+ /**
1664
+ * Issue #3288 §1: why a tool call inside a task was refused — the same distinction the session-layer
1665
+ * enforcer already records for its own denials (`hasApprover ? 'user' : 'no-approver'`), named here for
1666
+ * a task's result rather than a live session's denial log: `'no-approver'` when no approver was
1667
+ * attached at all (print mode, a truly headless run); `'denied-by-person'` when one was attached and
1668
+ * answered no; `'approver-error'` when it threw or rejected instead of answering — a broken approver
1669
+ * still fails the call closed rather than hanging it; `'cancelled'` when the task ended (finished,
1670
+ * failed, or was stopped) before an attached approver's answer arrived — a `false` produced by that
1671
+ * cutoff is not the same fact as a person's own denial, so it is never counted as one.
1672
+ */
1673
+ type TBackgroundTaskPermissionDenialReason = 'denied-by-person' | 'no-approver' | 'approver-error' | 'cancelled';
1674
+ /**
1675
+ * How many of a task's tool calls were refused, and why. Additive: a caller only reads this when at
1676
+ * least one call was refused, so a task with none carries no new field — the result of a task that
1677
+ * finished exactly as it always did is unchanged.
1678
+ */
1679
+ interface IBackgroundTaskDeniedToolCalls {
1680
+ readonly total: number;
1681
+ readonly byReason: Readonly<Record<TBackgroundTaskPermissionDenialReason, number>>;
1682
+ }
1549
1683
  interface IBaseBackgroundTaskResult {
1550
1684
  taskId: string;
1551
1685
  output: string;
@@ -1555,6 +1689,8 @@ interface IAgentBackgroundTaskResult extends IBaseBackgroundTaskResult {
1555
1689
  kind: 'agent';
1556
1690
  /** ANALYTICS-001 (Phase 2): total token usage of an agent task, attributed to it in the parent log. */
1557
1691
  usage?: IBackgroundTaskUsage;
1692
+ /** Issue #3288 §1: present only when the task had at least one tool call refused. */
1693
+ deniedToolCalls?: IBackgroundTaskDeniedToolCalls;
1558
1694
  }
1559
1695
  interface IProcessBackgroundTaskResult extends IBaseBackgroundTaskResult {
1560
1696
  kind: 'process';
@@ -1800,7 +1936,7 @@ interface ISubagentJobState extends Pick<IBackgroundTaskState<'agent'>, 'id' | '
1800
1936
  error?: string;
1801
1937
  }
1802
1938
  //#endregion
1803
- //#region ../agent-interface-session/dist/node/session-contracts-BVCzd3uY.d.ts
1939
+ //#region ../agent-interface-session/dist/node/session-contracts-C4R5bYiU.d.ts
1804
1940
  //#endregion
1805
1941
  //#region src/session-loop-contracts.d.ts
1806
1942
  /** A self-paced loop's durable lifecycle, independent of its disposable wake timer. */
@@ -2044,7 +2180,7 @@ interface ISessionReplayValidationResult {
2044
2180
  */
2045
2181
  type TWorkspaceRelation = 'same-worktree' | 'same-repo' | 'different-repo' | 'unknown';
2046
2182
  //#endregion
2047
- //#region ../agent-framework/dist/node/createInteractiveRuntime-Bmh2KYP6.d.ts
2183
+ //#region ../agent-framework/dist/node/createInteractiveRuntime-3MZpPTdw.d.ts
2048
2184
  //#region src/effort/effort-resolution.d.ts
2049
2185
  type TEffortSelection = TModelEffort | 'auto';
2050
2186
  type TEffortSource = 'command' | 'flag' | 'environment' | 'settings' | 'preset' | 'model-default';
@@ -2092,16 +2228,6 @@ interface IEditCheckpointRestoreResult {
2092
2228
  }
2093
2229
  //#endregion
2094
2230
  //#region src/command-api/host-context-types.d.ts
2095
- interface ICommandSkillListEntry {
2096
- readonly name: string;
2097
- readonly description: string;
2098
- readonly source: string;
2099
- readonly modelInvocable: boolean;
2100
- readonly userInvocable: boolean;
2101
- readonly argumentHint?: string;
2102
- readonly context?: string;
2103
- readonly agent?: string;
2104
- }
2105
2231
  interface ICommandSkillActivationRequest {
2106
2232
  readonly invocationSource: TCommandInvocationSource;
2107
2233
  readonly displayInput?: string;
@@ -2249,10 +2375,25 @@ interface ISessionUsageRecord {
2249
2375
  //#region src/command-api/agent-job-roles.d.ts
2250
2376
  /** Starting, steering and ending subagent jobs. */
2251
2377
  interface IAgentJobDispatch {
2378
+ /**
2379
+ * #3282 §4: the agent switcher's roster — `definedIn` is a plain-words location (a discovered
2380
+ * file's path, or "Built-in") a person picking an agent can read.
2381
+ */
2252
2382
  listAgentDefinitions(): Array<{
2253
2383
  name: string;
2254
2384
  description: string;
2385
+ definedIn: string;
2255
2386
  }>;
2387
+ /**
2388
+ * #3282 §4: the agent type `/agent <name>` (no prompt) currently selects — the agent switcher
2389
+ * shows it checked. Never throws; a host without the agent runtime just has the fallback default.
2390
+ */
2391
+ getDefaultAgentType(): string;
2392
+ /**
2393
+ * #3282 §4: `/agent <name>` (bare, no prompt) sets this — the agent type used as the default
2394
+ * `agentType` whenever one is not otherwise named. Throws if the agent runtime is unavailable.
2395
+ */
2396
+ setDefaultAgentType(agentType: string): void;
2256
2397
  listAgentJobs(): ISubagentJobState[];
2257
2398
  spawnAgentJob(input: {
2258
2399
  agentType: string;
@@ -2328,7 +2469,7 @@ interface IAgentJobMonitors {
2328
2469
  interface IAgentJobLogs {
2329
2470
  readBackgroundTaskLog(taskId: string, cursor?: IBackgroundTaskLogCursor): Promise<IBackgroundTaskLogPage>;
2330
2471
  }
2331
- /** Aggregate: all 15 members remain source-compatible. Declare a role port instead of this. */
2472
+ /** Aggregate of the five role interfaces above, kept source-compatible. Declare a role port instead of this. */
2332
2473
  interface IAgentJobHostContext extends IAgentJobDispatch, IAgentJobGroups, IAgentJobSchedules, IAgentJobMonitors, IAgentJobLogs {}
2333
2474
  //#endregion
2334
2475
  //#region src/command-api/preset/preset-application-types.d.ts
@@ -2512,9 +2653,22 @@ interface IPermissionRuleLayer {
2512
2653
  readonly deny: readonly string[];
2513
2654
  readonly ask: readonly string[];
2514
2655
  }
2656
+ /** One rule to remove from the settings layer it was declared in (#3282 §4a). */
2657
+ interface IPermissionRuleRemoval {
2658
+ /** The `scope` of the {@link IPermissionRuleLayer} the rule was read from. */
2659
+ readonly scope: string;
2660
+ readonly kind: 'allow' | 'deny' | 'ask';
2661
+ readonly pattern: string;
2662
+ }
2515
2663
  /** Where each configured permission rule comes from, read fresh on every call. */
2516
2664
  interface ICommandPermissionRulesAdapter {
2517
2665
  readLayers(): readonly IPermissionRuleLayer[];
2666
+ /**
2667
+ * #3282 §4a: remove one declared rule from its settings layer. Optional — a host with no write
2668
+ * target for any layer (read-only rule discovery) makes rule removal fail EXPLICITLY wherever it
2669
+ * is offered, never a silent no-op. Returns `false` when no writable layer matched the removal.
2670
+ */
2671
+ removeRule?(removal: IPermissionRuleRemoval): boolean;
2518
2672
  }
2519
2673
  /** How shell commands are confined: not at all, confined without prompts, or confined and asked. */
2520
2674
  type TSandboxCommandMode = 'off' | 'auto-allow' | 'regular';
@@ -2527,6 +2681,22 @@ interface ICommandSandboxStatus {
2527
2681
  readonly network: boolean;
2528
2682
  readonly excludedCommands: readonly string[];
2529
2683
  }
2684
+ /** One external-event grant as the owner sees it: never the principal, a token or any content. */
2685
+ interface ICommandExternalEventGrant {
2686
+ readonly grantId: string;
2687
+ readonly principal: 'subject' | 'client';
2688
+ readonly state: 'open' | 'revoked';
2689
+ readonly counters: {
2690
+ readonly accepted: number;
2691
+ readonly refused: Readonly<Partial<Record<string, number>>>;
2692
+ readonly settled: Readonly<Partial<Record<string, number>>>;
2693
+ };
2694
+ }
2695
+ /** The session's external-event grants: `/events` lists them and withdraws one. */
2696
+ interface ICommandExternalEventsAdapter {
2697
+ list(): readonly ICommandExternalEventGrant[];
2698
+ revoke(grantId: string): 'revoked' | 'unknown-grant';
2699
+ }
2530
2700
  /** The OS sandbox, live: `/sandbox` reads it and changes the mode for the next command. */
2531
2701
  interface ICommandSandboxAdapter {
2532
2702
  status(): ICommandSandboxStatus;
@@ -2594,6 +2764,15 @@ interface ICommandMCPActivationSummary {
2594
2764
  readonly provenanceId: string;
2595
2765
  readonly definitionFingerprint: string;
2596
2766
  readonly securityIdentity: string;
2767
+ /**
2768
+ * #3282 §4 part b-2: this process's live connection outcome for an `allowed` server — absent for
2769
+ * one that is not `allowed`, or has not been attempted yet. `'failed'`'s reason is
2770
+ * {@link connectionFailureReason}; a connected server's tool names are {@link toolNames}.
2771
+ */
2772
+ readonly connection?: 'connected' | 'failed';
2773
+ readonly connectionFailureReason?: string;
2774
+ /** The names of the tools this server currently contributes; empty when not connected. */
2775
+ readonly toolNames?: readonly string[];
2597
2776
  }
2598
2777
  /**
2599
2778
  * A definition-source-level problem — issue #2794: a configuration root that is not an object, no
@@ -2714,6 +2893,33 @@ interface ICommandMCPActivationAdapter {
2714
2893
  * a name it already had. Called once per sign-in that returned tools.
2715
2894
  */
2716
2895
  oauthToolsAdded?(serverId: string, added: readonly string[]): void;
2896
+ /**
2897
+ * #3282 §4 part b-2: `/mcp reload` and the Settings screen's "Reload servers" button. Retries
2898
+ * every allowed server that is not currently connected; a server already connected is left
2899
+ * running. Never rejects: a server that still cannot connect keeps its `list()` failure reason.
2900
+ * Absent: the host offers no reload (the button/command then say so).
2901
+ */
2902
+ reload?(): Promise<{
2903
+ readonly tools: readonly IToolWithEventService[];
2904
+ readonly connectedServerIds: readonly string[];
2905
+ readonly failedServerIds: readonly string[];
2906
+ /**
2907
+ * Identifies this call's staged tool provenance for `reloadToolsAdded`; absent when there is
2908
+ * nothing to acknowledge (no server newly connected). Two `reload()` calls outstanding at once
2909
+ * — `/mcp reload` runs inline, unblocked by the mid-turn gate, and an `update-settings` write
2910
+ * is fire-and-forget, so this is reachable, not hypothetical — join the same connection pass
2911
+ * and get the same token back; a fresh call started only after the last one's token was
2912
+ * acknowledged gets a new one.
2913
+ */
2914
+ readonly reloadToken?: string;
2915
+ }>;
2916
+ /**
2917
+ * Which of `reload`'s tools the session actually took, keyed to the `reloadToken` it returned;
2918
+ * any other was left out for a name it already had. `token` not matching the currently staged
2919
+ * reload — already committed, or superseded by a later call — makes this a no-op, so a late or
2920
+ * duplicate acknowledgement can never clear or corrupt a different reload's provenance.
2921
+ */
2922
+ reloadToolsAdded?(token: string, added: readonly string[]): void;
2717
2923
  }
2718
2924
  /**
2719
2925
  * PEER-004 (#1863): a live session this one can address, as the operator sees it.
@@ -2734,6 +2940,16 @@ interface ILocalPeerSummary {
2734
2940
  /** `mismatched` when the peer's claim disagreed with what this session read; it is not believed. */
2735
2941
  readonly workspaceClaim?: 'verified' | 'mismatched' | 'absent';
2736
2942
  }
2943
+ /**
2944
+ * Another of the user's devices with an admitted device-mesh link to this session, as the operator
2945
+ * sees it. `deviceId` names it for a later `send`; `locality` is where the carrier established it
2946
+ * runs, shown and never an authority input.
2947
+ */
2948
+ interface ILinkedDeviceSummary {
2949
+ readonly deviceId: string;
2950
+ readonly name?: string;
2951
+ readonly locality: 'same-host' | 'another-host';
2952
+ }
2737
2953
  /**
2738
2954
  * PEER-004: what `/peers` reads. The registry, the guarded directory and the liveness rule all live
2739
2955
  * in the composition root — a command never touches the filesystem, for the same reason it never
@@ -2749,6 +2965,16 @@ interface ICommandLocalPeersAdapter {
2749
2965
  listWithWorkspace?(): Promise<readonly ILocalPeerSummary[]>;
2750
2966
  /** This session's own id, so the command can mark which row is the reader. */
2751
2967
  ownSessionId(): string;
2968
+ /**
2969
+ * The user's other devices linked to this session over the device mesh, addressed by device id
2970
+ * wherever a session id is taken. Absent on a host with no device mesh.
2971
+ */
2972
+ listDevices?(): readonly ILinkedDeviceSummary[];
2973
+ /**
2974
+ * Why sessions on this host cannot be listed, when local discovery is off for this session; the
2975
+ * linked devices still are. Absent when discovery is on.
2976
+ */
2977
+ readonly localDiscoveryOff?: string;
2752
2978
  /**
2753
2979
  * PEER-006: hand `text` to another announced session, and report what came back.
2754
2980
  *
@@ -2970,6 +3196,8 @@ interface ICommandHostAdapters {
2970
3196
  workspace?: ICommandWorkspaceAdapter;
2971
3197
  /** Absent on a host with no OS sandbox — `/sandbox` then says so. */
2972
3198
  sandbox?: ICommandSandboxAdapter;
3199
+ /** Absent when the session holds no external-event grant — `/events` then says so. */
3200
+ externalEvents?: ICommandExternalEventsAdapter;
2973
3201
  }
2974
3202
  interface IContextReferenceAddResult {
2975
3203
  reference?: IContextReferenceItem;
@@ -3130,6 +3358,17 @@ interface ICommandHostUserInteraction {
3130
3358
  */
3131
3359
  getUserInteraction(): IUserInteraction | undefined;
3132
3360
  }
3361
+ /**
3362
+ * Whether THIS session is running with no provider configured yet (issue #3282 §3 setup mode).
3363
+ *
3364
+ * Exists for exactly one command (`/provider add`, deciding hot-swap vs. restart) — never inferred
3365
+ * from settings, because an ordinary session started from an env-default provider also has none
3366
+ * persisted. The member is optional so a host with no concept of setup mode costs nothing and is
3367
+ * correctly read as "not in it" (`?.() === true`), never mistaken for a required capability.
3368
+ */
3369
+ interface ICommandHostSetupState {
3370
+ isSetupRequired?(): boolean;
3371
+ }
3133
3372
  /** Re-applying preset-owned configuration to the live session. */
3134
3373
  interface ICommandHostPresetApplication {
3135
3374
  /** Apply an additive response style to the live system prompt. */
@@ -3168,6 +3407,12 @@ interface ICommandHostContextReferences {
3168
3407
  interface ICommandHostWorkspace {
3169
3408
  getCwd(): string;
3170
3409
  getCommandInvocationSource(): TCommandInvocationSource;
3410
+ /**
3411
+ * #3282 §4 part b-2: whether THIS invocation is provably on this machine. Optional so an older or
3412
+ * narrower host still satisfies this interface; a caller that needs it treats a missing method the
3413
+ * same as `'local'` (allow-by-default, matching the rest of the command layer).
3414
+ */
3415
+ getCommandSurfaceLocality?(): TCommandSurfaceLocality;
3171
3416
  }
3172
3417
  /** What commands and skills this host can dispatch. */
3173
3418
  interface ICommandHostCatalog {
@@ -3249,8 +3494,8 @@ interface ICommandHostTerminalHandoff {
3249
3494
  interface ICommandHostAdapterAccess {
3250
3495
  getCommandHostAdapters?(): ICommandHostAdapters;
3251
3496
  }
3252
- /** Aggregate: all 47 members remain source-compatible. Declare a role port instead of this. */
3253
- interface ICommandHostContext extends ICommandHostSessionAccess, ICommandHostAgentJobs, ICommandHostUserInteraction, ICommandHostPresetApplication, ICommandHostContextWindow, ICommandHostContextReferences, ICommandHostWorkspace, ICommandHostCatalog, ICommandHostCheckpoints, ICommandHostMemory, ICommandHostBackgroundTasks, ICommandHostGoal, ICommandHostPlan, ICommandHostTerminalHandoff, ICommandHostAdapterAccess {}
3497
+ /** Aggregate: all 48 members remain source-compatible. Declare a role port instead of this. */
3498
+ interface ICommandHostContext extends ICommandHostSessionAccess, ICommandHostAgentJobs, ICommandHostUserInteraction, ICommandHostSetupState, ICommandHostPresetApplication, ICommandHostContextWindow, ICommandHostContextReferences, ICommandHostWorkspace, ICommandHostCatalog, ICommandHostCheckpoints, ICommandHostMemory, ICommandHostBackgroundTasks, ICommandHostGoal, ICommandHostPlan, ICommandHostTerminalHandoff, ICommandHostAdapterAccess {}
3254
3499
  //#endregion
3255
3500
  //#region src/command-api/contracts.d.ts
3256
3501
  type TSystemCommandLifecycle = 'inline' | 'blocking' | 'background';
@@ -3272,6 +3517,10 @@ interface ISystemCommand {
3272
3517
  argumentHint?: string;
3273
3518
  safety?: TCapabilitySafety;
3274
3519
  subcommands?: readonly ICommand[];
3520
+ /** Who runs this command; absent → `'runtime'`. See `ICommand.runner`. */
3521
+ runner?: TCommandRunner;
3522
+ /** The surfaces a `'client'` command can run on. See `ICommand.surfaces`. */
3523
+ surfaces?: readonly TCommandSurface[];
3275
3524
  lifecycle?: TSystemCommandLifecycle;
3276
3525
  /**
3277
3526
  * Whether executing this command requires explicit user permission/confirmation.