@sema-agent/client-core 0.95.0 → 0.96.0

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 (181) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/README.md +49 -25
  3. package/dist/adapt/arms.js +7 -1
  4. package/dist/adapt/toolCards.d.ts +1 -0
  5. package/dist/adapt/toolCards.js +16 -3
  6. package/dist/adapt/wireShapes.js +2 -16
  7. package/dist/adapter/activeRunSelfHeal.d.ts +4 -0
  8. package/dist/adapter/activeRunSelfHeal.js +30 -4
  9. package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
  10. package/dist/adapter/downstream/terminalToSdkResult.js +8 -9
  11. package/dist/adapter/runStream.js +30 -47
  12. package/dist/agentSession/engineAgentRegistryRead.js +5 -4
  13. package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
  14. package/dist/agentsWireCaps.js +13 -2
  15. package/dist/callerCwdCapability.d.ts +0 -4
  16. package/dist/callerCwdCapability.js +0 -6
  17. package/dist/centerWiringCapability.d.ts +0 -4
  18. package/dist/centerWiringCapability.js +0 -6
  19. package/dist/classifierVerdictWire.js +4 -16
  20. package/dist/clientSlice.js +1 -1
  21. package/dist/cloudConfigWireCaps.d.ts +3 -3
  22. package/dist/cloudConfigWireCaps.js +65 -45
  23. package/dist/coreValuePorts.d.ts +11 -7
  24. package/dist/coreValuePorts.js +5 -8
  25. package/dist/credentialProvenance.d.ts +28 -0
  26. package/dist/credentialProvenance.js +76 -0
  27. package/dist/decideFailureNote.js +3 -1
  28. package/dist/decideReceipt.js +7 -10
  29. package/dist/declared/supportFloorDeclared.js +3 -3
  30. package/dist/displayUntrusted.d.ts +7 -3
  31. package/dist/displayUntrusted.js +356 -60
  32. package/dist/engineCapsCache.d.ts +6 -0
  33. package/dist/engineCapsCache.js +226 -32
  34. package/dist/engineDirectory.d.ts +79 -0
  35. package/dist/engineDirectory.js +186 -0
  36. package/dist/engineErrorCodes.d.ts +14 -1
  37. package/dist/engineErrorCodes.js +37 -15
  38. package/dist/engineNoticeCodes.d.ts +17 -0
  39. package/dist/engineNoticeCodes.js +57 -3
  40. package/dist/engineWordRenames.d.ts +8 -0
  41. package/dist/engineWordRenames.js +13 -0
  42. package/dist/fileHistoryCaptureCapability.d.ts +14 -0
  43. package/dist/fileHistoryCaptureCapability.js +70 -0
  44. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  45. package/dist/fleet/bgSubagentRow.js +67 -0
  46. package/dist/fleet/fleetLedger.d.ts +1 -0
  47. package/dist/fleet/fleetLedger.js +103 -89
  48. package/dist/fleet/fleetProjection.d.ts +1 -0
  49. package/dist/fleet/fleetProjection.js +10 -3
  50. package/dist/fleetTaskDesc.js +4 -17
  51. package/dist/gateOutcome.d.ts +12 -1
  52. package/dist/gateOutcome.js +58 -1
  53. package/dist/gateVocabulary.d.ts +7 -2
  54. package/dist/gateVocabulary.js +5 -1
  55. package/dist/generated/engineAskFaceTables.js +1 -1
  56. package/dist/generated/engineFactTables.d.ts +5 -3
  57. package/dist/generated/engineFactTables.js +17 -4
  58. package/dist/generated/engineNoticeTables.js +12 -3
  59. package/dist/generated/settingsSchemaFns.d.ts +3 -0
  60. package/dist/generated/settingsSchemaFns.js +53 -0
  61. package/dist/generated/toolNameTables.d.ts +1 -0
  62. package/dist/generated/toolNameTables.js +1 -0
  63. package/dist/hitl/approvalEndingCause.d.ts +2 -0
  64. package/dist/hitl/approvalEndingCause.js +31 -21
  65. package/dist/hitl/askParkRowRouting.js +1 -1
  66. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  67. package/dist/hitl/automaticAnswerVerdict.js +13 -8
  68. package/dist/hitl/decisionConflict.js +0 -2
  69. package/dist/hitl/decisionRefusal.d.ts +8 -0
  70. package/dist/hitl/decisionRefusal.js +48 -14
  71. package/dist/hitl/frameRouter.d.ts +0 -1
  72. package/dist/hitl/frameRouter.js +6 -14
  73. package/dist/hitl/hitlBridge.d.ts +6 -2
  74. package/dist/hitl/hitlBridge.js +28 -7
  75. package/dist/hitl/localAllowRule.d.ts +1 -0
  76. package/dist/hitl/localAllowRule.js +2 -2
  77. package/dist/hitl/noAllowCause.d.ts +2 -1
  78. package/dist/hitl/noAllowCause.js +3 -2
  79. package/dist/hitl/parkResolver.d.ts +1 -0
  80. package/dist/hitl/parkResolver.js +8 -54
  81. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  82. package/dist/hitl/parkRowBirthWait.js +2 -2
  83. package/dist/hitl/planReviewWire.d.ts +1 -0
  84. package/dist/hitl/planReviewWire.js +98 -20
  85. package/dist/hitl/replayedApproval.d.ts +1 -0
  86. package/dist/hitl/replayedApproval.js +14 -0
  87. package/dist/hitl/sessionPolicyDeliverable.js +8 -6
  88. package/dist/hitl/standingRows.d.ts +18 -0
  89. package/dist/hitl/standingRows.js +127 -0
  90. package/dist/hitl/toolApprovalWire.d.ts +15 -3
  91. package/dist/hitl/toolApprovalWire.js +238 -25
  92. package/dist/hookMatcherVerdict.d.ts +1 -9
  93. package/dist/hookMatcherVerdict.js +21 -61
  94. package/dist/hooksWireCaps.js +2 -2
  95. package/dist/hostCallbackGuard.d.ts +1 -0
  96. package/dist/hostCallbackGuard.js +6 -0
  97. package/dist/index.d.ts +21 -9
  98. package/dist/index.js +17 -8
  99. package/dist/mcpProbeCapability.d.ts +0 -4
  100. package/dist/mcpProbeCapability.js +0 -6
  101. package/dist/memoryComplianceCapability.d.ts +0 -4
  102. package/dist/memoryComplianceCapability.js +0 -6
  103. package/dist/memoryOriginCapability.d.ts +0 -4
  104. package/dist/memoryOriginCapability.js +0 -6
  105. package/dist/memorySpecWire.js +2 -2
  106. package/dist/modelIdentityResolvability.d.ts +2 -2
  107. package/dist/modelIdentityResolvability.js +12 -3
  108. package/dist/noticePresentation.d.ts +68 -0
  109. package/dist/noticePresentation.js +247 -0
  110. package/dist/outputStyleSeatCapability.d.ts +0 -1
  111. package/dist/outputStyleSeatCapability.js +0 -3
  112. package/dist/ownKey.d.ts +2 -0
  113. package/dist/ownKey.js +18 -0
  114. package/dist/peerFrames.js +13 -9
  115. package/dist/permissionModesCapability.d.ts +0 -4
  116. package/dist/permissionModesCapability.js +0 -6
  117. package/dist/permissionRuleIssue.js +0 -3
  118. package/dist/permissionsDeclaration.d.ts +2 -0
  119. package/dist/permissionsDeclaration.js +56 -41
  120. package/dist/printPermissionOutcome.d.ts +12 -0
  121. package/dist/printPermissionOutcome.js +50 -0
  122. package/dist/printToolResultFrame.d.ts +1 -0
  123. package/dist/printToolResultFrame.js +5 -9
  124. package/dist/promptBlockedCopy.d.ts +5 -0
  125. package/dist/promptBlockedCopy.js +35 -0
  126. package/dist/protocolSegment.d.ts +9 -6
  127. package/dist/protocolSegment.js +31 -21
  128. package/dist/providerRejection.d.ts +4 -0
  129. package/dist/providerRejection.js +75 -14
  130. package/dist/replayBody.d.ts +12 -0
  131. package/dist/replayBody.js +25 -0
  132. package/dist/resumeRefusalCopy.js +5 -21
  133. package/dist/retryStatus.d.ts +9 -1
  134. package/dist/retryStatus.js +9 -2
  135. package/dist/rewindArchiveCapability.d.ts +3 -13
  136. package/dist/rewindArchiveCapability.js +7 -58
  137. package/dist/rewindArchiveReading.d.ts +15 -0
  138. package/dist/rewindArchiveReading.js +56 -0
  139. package/dist/ruleCompileVerdict.d.ts +9 -1
  140. package/dist/ruleCompileVerdict.js +29 -4
  141. package/dist/runTerminal.d.ts +15 -1
  142. package/dist/runTerminal.js +56 -8
  143. package/dist/sandboxWire.js +13 -0
  144. package/dist/sealedKeyCapability.d.ts +0 -4
  145. package/dist/sealedKeyCapability.js +0 -6
  146. package/dist/seam.js +4 -2
  147. package/dist/seatContract.d.ts +73 -11
  148. package/dist/seatContract.js +195 -14
  149. package/dist/sessionReadRedactionCapability.d.ts +0 -4
  150. package/dist/sessionReadRedactionCapability.js +0 -6
  151. package/dist/sessionSyncFileHistory.d.ts +4 -0
  152. package/dist/sessionSyncFileHistory.js +66 -0
  153. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
  154. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  155. package/dist/skillToolListsCapability.d.ts +0 -1
  156. package/dist/skillToolListsCapability.js +0 -3
  157. package/dist/steerPriorityCapability.d.ts +0 -1
  158. package/dist/steerPriorityCapability.js +0 -3
  159. package/dist/storePostureCapability.d.ts +0 -4
  160. package/dist/storePostureCapability.js +0 -6
  161. package/dist/subagent/engineSubagentSteer.js +7 -5
  162. package/dist/subagentContentStore.js +4 -15
  163. package/dist/supportFloor.d.ts +1 -0
  164. package/dist/supportFloor.js +13 -9
  165. package/dist/systemReminderTag.d.ts +1 -0
  166. package/dist/systemReminderTag.js +8 -0
  167. package/dist/toolHistoryMismatch.d.ts +0 -3
  168. package/dist/toolHistoryMismatch.js +3 -7
  169. package/dist/toolResult.d.ts +1 -1
  170. package/dist/toolResult.js +2 -1
  171. package/dist/toolResultContent.d.ts +2 -0
  172. package/dist/toolResultContent.js +63 -0
  173. package/dist/usageAnalytics.js +40 -16
  174. package/dist/userInvokedSkillsCapability.d.ts +0 -1
  175. package/dist/userInvokedSkillsCapability.js +0 -3
  176. package/dist/wireErrorTriage.d.ts +2 -0
  177. package/dist/wireErrorTriage.js +34 -5
  178. package/dist/wireFailureShape.d.ts +19 -2
  179. package/dist/wireFailureShape.js +55 -50
  180. package/docs/INTEGRATION-CLIENTS.md +1262 -17
  181. package/package.json +5 -5
@@ -88,9 +88,6 @@ const reader = createEngineCapReader({
88
88
  project: projectCenterWiringCapability,
89
89
  makeUnobserved: () => ({ kind: 'unobserved' }),
90
90
  });
91
- export function noteEngineCapsForCenterWiring(baseUrl, caps, opts) {
92
- reader.note(baseUrl, caps, opts);
93
- }
94
91
  export function observedCenterWiring(baseUrl = engineWireTarget()?.baseUrl) {
95
92
  return reader.observed(baseUrl);
96
93
  }
@@ -194,6 +191,3 @@ export function centerWiringDoctorDetail(reading) {
194
191
  return unobserved;
195
192
  }
196
193
  }
197
- export function __resetCenterWiringReadingsForTests() {
198
- reader.__resetForTests();
199
- }
@@ -1,21 +1,7 @@
1
1
  import { unwrapSystemReminder } from './systemReminderTag.js';
2
+ import { toolEndOutputText } from './toolResultContent.js';
2
3
  export const CLASSIFIER_DENY_SIGNATURE = 'auto-mode classifier blocked this call';
3
4
  const NOTICE_REASON_MAX = 80;
4
- function textFromWireOutput(output) {
5
- if (typeof output === 'string')
6
- return output;
7
- const blocks = Array.isArray(output)
8
- ? output
9
- : output !== null && typeof output === 'object' && Array.isArray(output.content)
10
- ? (output.content)
11
- : undefined;
12
- if (!blocks)
13
- return undefined;
14
- const texts = blocks
15
- .map(b => (b !== null && typeof b === 'object' && typeof b.text === 'string' ? b.text : undefined))
16
- .filter((t) => t !== undefined);
17
- return texts.length > 0 ? texts.join('\n') : undefined;
18
- }
19
5
  const CLASSIFIER_DENY_FORMS = [
20
6
  'auto-mode classifier blocked the approved edit at an inherited ancestor layer',
21
7
  'auto-mode classifier blocked this call at an inherited ancestor layer',
@@ -24,7 +10,9 @@ const CLASSIFIER_DENY_FORMS = [
24
10
  export function classifierDenyFromToolEnd(ev) {
25
11
  if (!ev || ev.type !== 'tool_end' || ev.isError !== true)
26
12
  return undefined;
27
- const raw = textFromWireOutput(ev.output);
13
+ if (Array.isArray(ev.output) && ev.output.length !== 1)
14
+ return undefined;
15
+ const raw = toolEndOutputText(ev.output);
28
16
  if (raw === undefined)
29
17
  return undefined;
30
18
  const message = unwrapSystemReminder(raw).trim();
@@ -14,4 +14,4 @@ export const CLIENT_VERBS = [
14
14
  { verb: 'probeHealth', required: false, duty: '健康探测' },
15
15
  ];
16
16
  export const PROBE_HEALTH_DIVERGENCE = 'probeHealth: SDK 要求 status==="ok",壳侧 limitsWire:225 / detachWire:82 手拼只要 res.ok。' +
17
- 'B4 保旧行为(res.ok),差异候裁 —— 换成 SDK 语义会让"自报 degraded 但可用"的引擎少发 detach 头。';
17
+ 'B4 保旧行为(res.ok),差异待定 —— 换成 SDK 语义会让"自报 degraded 但可用"的引擎少发 detach 头。';
@@ -4,7 +4,7 @@ import type { EnvLike } from './hostEnv.js';
4
4
  export type { McpServerSpec };
5
5
  type Rec = Record<string, unknown>;
6
6
  export type { EnvLike };
7
- export type CloudMcpDropReason = 'disabled' | 'missing-field' | 'unknown-transport' | 'capped';
7
+ export type CloudMcpDropReason = 'disabled' | 'missing-field' | 'unknown-transport' | 'capped' | 'principal-and-assertion-header';
8
8
  export interface CloudMcpDroppedServer {
9
9
  name?: string;
10
10
  reason: CloudMcpDropReason;
@@ -17,10 +17,10 @@ export interface CloudMcpProjection {
17
17
  export declare function cloudMcpToSpecs(servers: unknown, env: EnvLike): CloudMcpProjection;
18
18
  export declare function cloudSkillsToSpecs(manifestSkills: unknown, resolveBody: (contentHash: string) => string | null): SkillSpec[];
19
19
  export interface CloudModelRefIssue {
20
- readonly key: 'models' | 'default' | 'roles' | 'atModelAllowlist' | 'tierGroups' | 'activeTierGroup';
20
+ readonly key: 'models' | 'roles' | 'atMention' | 'tierGroups' | 'activeTierGroup';
21
21
  readonly at?: string;
22
22
  readonly target?: string;
23
- readonly reason: 'dangling' | 'rejected' | 'unreadable' | 'unsupported' | 'duplicate';
23
+ readonly reason: 'dangling' | 'rejected' | 'unreadable' | 'unsupported' | 'duplicate' | 'shadowed';
24
24
  readonly outcome: 'dropped' | 'kept';
25
25
  }
26
26
  export interface CloudModelsDocOptions {
@@ -62,6 +62,10 @@ export function cloudMcpToSpecs(servers, env) {
62
62
  drop(name, 'missing-field');
63
63
  continue;
64
64
  }
65
+ if (asStr(t.principalHeader) && asStr(t.assertionHeader)) {
66
+ drop(name, 'principal-and-assertion-header');
67
+ continue;
68
+ }
65
69
  const headers = {};
66
70
  for (const [headerName, ref] of Object.entries(asRec(t.headerRefs) ?? {})) {
67
71
  const refName = asStr(ref);
@@ -166,8 +170,10 @@ function modelsDocOf(models, opts) {
166
170
  const refOf = (v) => (typeof v === 'string' && v !== '' ? { target: v } : {});
167
171
  const reasonOf = (v) => typeof v === 'string' && v !== '' ? (rawNames.has(v) ? 'rejected' : 'dangling') : 'unreadable';
168
172
  let written = stripped;
173
+ let catalogKept = false;
169
174
  if (acceptedFlags && stripped.length > 0) {
170
175
  const anyAccepted = acceptedFlags.some((f) => f);
176
+ catalogKept = !anyAccepted;
171
177
  stripped.forEach((e, i) => {
172
178
  if (!acceptedFlags[i])
173
179
  issues.push({ key: 'models', target: e.name, reason: 'rejected', outcome: anyAccepted ? 'dropped' : 'kept' });
@@ -178,59 +184,80 @@ function modelsDocOf(models, opts) {
178
184
  const doc = { models: written };
179
185
  const policy = modelsPolicyOf(m);
180
186
  if (policy.unreadable) {
181
- drop({ key: 'default', reason: 'unreadable' });
182
- drop({ key: 'atModelAllowlist', at: 'models', reason: 'unreadable' });
187
+ drop({ key: 'roles', at: 'default', reason: 'unreadable' });
188
+ drop({ key: 'atMention', at: 'models', reason: 'unreadable' });
183
189
  }
184
190
  if (policy.defaultUnreadable)
185
- drop({ key: 'default', reason: 'unreadable' });
191
+ drop({ key: 'roles', at: 'default', reason: 'unreadable' });
186
192
  const dm = policy.defaultModel;
187
- if (accept && dm !== undefined) {
193
+ let defaultRole;
194
+ if (accept && dm !== undefined && dm.from === 'default') {
188
195
  if (names.has(dm.name))
189
- doc.default = dm.name;
196
+ defaultRole = { model: dm.name };
190
197
  else
191
- drop({ key: 'default', target: dm.name, reason: reasonOf(dm.name) });
198
+ drop({ key: 'roles', at: 'default', target: dm.name, reason: reasonOf(dm.name) });
192
199
  }
193
200
  const roles = asRec(m.roles);
194
- if (roles) {
195
- const kept = {};
196
- for (const [role, t] of Object.entries(roles)) {
197
- if (role === 'default' && accept && dm?.from === 'roles.default')
198
- continue;
199
- const tr = asRec(t);
200
- const model = tr && Object.hasOwn(tr, 'model') ? tr.model : undefined;
201
- if (typeof model === 'string' && !names.has(model)) {
202
- drop({ key: 'roles', at: role, ...refOf(model), reason: reasonOf(model) });
203
- continue;
201
+ const keptRoles = {};
202
+ for (const [role, t] of Object.entries(roles ?? {})) {
203
+ if (role === 'default' && defaultRole !== undefined) {
204
+ let same = false;
205
+ try {
206
+ same = JSON.stringify(t) === JSON.stringify(defaultRole);
204
207
  }
205
- setOwn(kept, role, t);
208
+ catch {
209
+ same = false;
210
+ }
211
+ if (!same) {
212
+ const tr = asRec(t);
213
+ const model = tr && Object.hasOwn(tr, 'model') ? tr.model : undefined;
214
+ drop({ key: 'roles', at: 'default', ...refOf(model), reason: 'shadowed' });
215
+ }
216
+ continue;
217
+ }
218
+ const tr = asRec(t);
219
+ const model = tr && Object.hasOwn(tr, 'model') ? tr.model : undefined;
220
+ if (typeof model === 'string' && !names.has(model)) {
221
+ drop({ key: 'roles', at: role, ...refOf(model), reason: reasonOf(model) });
222
+ continue;
206
223
  }
207
- doc.roles = kept;
224
+ setOwn(keptRoles, role, t);
208
225
  }
226
+ const rolesOut = {};
227
+ if (defaultRole !== undefined)
228
+ setOwn(rolesOut, 'default', defaultRole);
229
+ else if (Object.hasOwn(keptRoles, 'default'))
230
+ setOwn(rolesOut, 'default', keptRoles.default);
231
+ for (const [k, v] of Object.entries(keptRoles))
232
+ if (k !== 'default')
233
+ setOwn(rolesOut, k, v);
234
+ if (Object.keys(rolesOut).length > 0)
235
+ doc.roles = rolesOut;
209
236
  const am = policy.atMention;
210
237
  if (am?.kind === 'unreadable') {
211
- drop({ key: 'atModelAllowlist', at: am.from, reason: 'unreadable' });
238
+ drop({ key: 'atMention', at: am.from, reason: 'unreadable' });
212
239
  }
213
240
  else if (am !== undefined) {
214
241
  for (let i = 0; i < am.unreadableEntries; i += 1)
215
- drop({ key: 'atModelAllowlist', reason: 'unreadable' });
242
+ drop({ key: 'atMention', reason: 'unreadable' });
216
243
  const v = am.value;
217
- if (v.mode === 'none') {
218
- drop({ key: 'atModelAllowlist', at: 'atMention', reason: 'unsupported' });
219
- }
220
- else if (v.mode === 'only') {
244
+ if (v.mode === 'only') {
245
+ for (const n of v.models)
246
+ if (!names.has(n))
247
+ drop({ key: 'atMention', target: n, reason: reasonOf(n) });
221
248
  const narrowed = SETTINGS_NARROW_AT_MENTION(v, names);
222
249
  if (narrowed.mode === 'only') {
223
- for (const n of v.models)
224
- if (!names.has(n))
225
- drop({ key: 'atModelAllowlist', target: n, reason: reasonOf(n) });
226
- doc.atModelAllowlist = [...narrowed.models];
250
+ doc.atMention = { mode: 'only', models: [...narrowed.models] };
227
251
  }
228
252
  else {
229
- doc.atModelAllowlist = [...v.models];
230
- for (const n of v.models)
231
- issues.push({ key: 'atModelAllowlist', target: n, reason: reasonOf(n), outcome: 'kept' });
253
+ doc.atMention = { mode: narrowed.mode };
254
+ if (narrowed.mode === 'none' && !catalogKept)
255
+ drop({ key: 'atMention', at: 'atMention', reason: 'dangling' });
232
256
  }
233
257
  }
258
+ else if (v.mode === 'none') {
259
+ doc.atMention = { mode: 'none' };
260
+ }
234
261
  }
235
262
  let groupNames;
236
263
  const rawGroupNames = new Set((Array.isArray(m.tierGroups) ? m.tierGroups : []).map((g) => asStr(asRec(g)?.name)).filter((n) => !!n));
@@ -536,13 +563,15 @@ function droppedRefNotice(d) {
536
563
  switch (d.key) {
537
564
  case 'models':
538
565
  return { level: 'warn', text: `cloud config: ${t === undefined ? 'a model entry' : `model "${t}"`} ${ENTRY_REJECTED} — it was left out of the local catalog` };
539
- case 'default':
540
- return { level: 'warn', text: `cloud config: ${t === undefined ? 'the default model setting could not be read' : `the default model "${t}" ${notServed}`}, so it was left out — the local engine picks its default from roles and tiers instead` };
541
566
  case 'roles':
567
+ if (d.at === 'default' && d.reason === 'unreadable')
568
+ return { level: 'warn', text: 'cloud config: the default model setting could not be read, so it was left out — the local engine picks its default from roles and tiers instead' };
569
+ if (d.reason === 'shadowed')
570
+ return { level: 'warn', text: `cloud config: the "${d.at ?? ''}" role${t === undefined ? '' : ` ("${t}")`} is overridden by the default model setting served to you — only one default model can be set, so that role entry was left out` };
542
571
  return { level: 'warn', text: `cloud config: role "${d.at ?? ''}" ${t === undefined ? 'names no readable model' : `points at model "${t}", which ${notServed}`} — the role was left out and falls back along the engine's role chain` };
543
- case 'atModelAllowlist':
544
- if (d.reason === 'unsupported')
545
- return { level: 'warn', text: 'cloud config: the @-mention setting served to you allows no model to be @-mentioned, which the local engine\'s settings format cannot express — it was left out, so @-mentions are not restricted on the local engine' };
572
+ case 'atMention':
573
+ if (d.at === 'atMention' && d.reason === 'dangling')
574
+ return { level: 'warn', text: 'cloud config: none of the models in the @-mention allowlist served to you can be used on the local engine, so @-mentions are turned off there' };
546
575
  if (d.at !== undefined)
547
576
  return { level: 'warn', text: 'cloud config: the @-mention setting served to you could not be read by this client — it was left out, so @-mentions are not restricted on the local engine' };
548
577
  return { level: 'warn', text: `cloud config: ${t === undefined ? 'an unreadable @-mention allowlist entry' : `@-mention allowlist entry "${t}" ${notServed} and`} was left out` };
@@ -625,15 +654,6 @@ export function cloudEffectiveNotices(p) {
625
654
  'the catalog is kept as sent, and a locally started engine rejects the cloud model settings: at startup it uses its own environment catalog instead, and on a later refresh it keeps the previous configuration',
626
655
  });
627
656
  }
628
- const keptAllowlist = p.modelRefIssues.filter((d) => d.outcome === 'kept' && d.key === 'atModelAllowlist');
629
- if (keptAllowlist.length > 0) {
630
- const names = keptAllowlist.flatMap((d) => (d.target === undefined ? [] : [`"${d.target}"`]));
631
- out.push({
632
- level: 'warn',
633
- text: `cloud config: no @-mention allowlist entry${names.length > 0 ? ` (${names.join(', ')})` : ''} names a usable model in the catalog served to you — ` +
634
- 'the list is kept as sent, because an empty list would let every model be mentioned; with it, a locally started engine rejects the cloud model settings — at startup it uses its own environment catalog instead, and on a later refresh it keeps the previous configuration',
635
- });
636
- }
637
657
  out.push(budgetNotice(p.budget));
638
658
  out.push(runtimeCapsNotice(p.runtimeCaps));
639
659
  return out;
@@ -91,17 +91,21 @@ export interface PerModelAuthView {
91
91
  apiKey?: string;
92
92
  headers?: Record<string, string>;
93
93
  }
94
+ export type RuleGrammarView = 'command' | 'domain' | 'name' | 'path';
95
+ export interface RuleToolNameVerdictView {
96
+ readonly kind: 'current' | 'retired' | 'unprefixed_namespace' | 'unmintable_segment' | (string & {});
97
+ readonly guidance?: string;
98
+ readonly currentName?: string;
99
+ }
94
100
  export interface CoreValuePorts {
95
101
  resolveAutonomousLoopPrompt: (prompt: string, opts?: AutonomousLoopPromptOptionsView) => string | null;
96
102
  loosenReasons: (prior: SessionPermissionRules, next: SessionPermissionRules) => string[];
97
103
  combinePolicies: (...policies: CoreToolPolicyHandle[]) => CoreToolPolicyHandle;
98
104
  createAllowDenyPolicy: (opts: AllowDenyPolicyOptionsView) => CoreToolPolicyHandle;
99
105
  MCP_NAMESPACE: CoreProtocolNamespaceView;
100
- RETIRED_TOOL_NAMES: ReadonlyMap<string, string>;
101
106
  protocolOf: (name: string) => CoreProtocolNamespaceView | undefined;
102
- ruleToolGrammarOf: (toolName: string) => 'command' | 'path' | undefined;
107
+ ruleToolGrammarOf: (toolName: string) => RuleGrammarView | undefined;
103
108
  validatePermissionRules: (rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView) => PermissionRuleIssueView[];
104
- DISCUSSION_WORKFLOW_NAME: string;
105
109
  mintNamespacePrefix(ns: CoreProtocolNamespaceView, peer: string): string;
106
110
  compileAllowList(entries: readonly string[], behavior: 'allow' | 'deny', roster?: ReadonlySet<string>): AllowListReadingView;
107
111
  routeKeyOf(url: string | undefined): string;
@@ -113,8 +117,9 @@ export interface CoreValuePorts {
113
117
  routePairingStatus(brain: {
114
118
  adjudicateRoute?(model: RouteModelView, perModelAuth?: PerModelAuthView): RouteAdjudicationView | undefined;
115
119
  }, model: RouteModelView, perModelAuth?: PerModelAuthView): RoutePairingStatusView;
120
+ judgeRuleToolName(name: string, roster: ReadonlySet<string>): RuleToolNameVerdictView;
116
121
  }
117
- export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "RETIRED_TOOL_NAMES", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "DISCUSSION_WORKFLOW_NAME", "mintNamespacePrefix", "compileAllowList", "routeKeyOf", "joinRequestUrl", "resolveRouteCredential", "adjudicateModelRoute", "routePairingStatus"];
122
+ export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "mintNamespacePrefix", "compileAllowList", "routeKeyOf", "joinRequestUrl", "resolveRouteCredential", "adjudicateModelRoute", "routePairingStatus", "judgeRuleToolName"];
118
123
  export type CoreValuePortName = (typeof CORE_VALUE_PORT_NAMES)[number];
119
124
  export declare function installCoreValuePorts(ports: Partial<CoreValuePorts> | null): () => void;
120
125
  export declare function hasCoreValuePorts(): boolean;
@@ -125,13 +130,12 @@ export declare function loosenReasons(prior: SessionPermissionRules, next: Sessi
125
130
  export declare function combinePolicies(...policies: CoreToolPolicyHandle[]): CoreToolPolicyHandle | undefined;
126
131
  export declare function createAllowDenyPolicy(opts: AllowDenyPolicyOptionsView): CoreToolPolicyHandle | undefined;
127
132
  export declare function mcpNamespace(): CoreProtocolNamespaceView | undefined;
128
- export declare function retiredToolNames(): ReadonlyMap<string, string> | undefined;
129
133
  export declare function protocolOf(name: string): CoreProtocolNamespaceView | undefined;
130
- export declare function ruleToolGrammarOf(toolName: string): 'command' | 'path' | undefined;
134
+ export declare function ruleToolGrammarOf(toolName: string): RuleGrammarView | undefined;
131
135
  export declare function validatePermissionRules(rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView): PermissionRuleIssueView[] | undefined;
132
- export declare function discussionWorkflowName(): string | undefined;
133
136
  export declare function mintNamespacePrefix(ns: CoreProtocolNamespaceView, peer: string): string | undefined;
134
137
  export declare function compileAllowList(entries: readonly string[], behavior: 'allow' | 'deny', roster?: ReadonlySet<string>): AllowListReadingView | undefined;
138
+ export declare function ruleToolNameJudgement(name: string, roster: ReadonlySet<string>): RuleToolNameVerdictView | undefined;
135
139
  export declare function routeKeyOf(url: string | undefined): string | undefined;
136
140
  export declare function joinRequestUrl(root: string | undefined, suffix: string): string | undefined;
137
141
  export declare function resolveRouteCredential(input: RouteCredentialInputView): RouteCredentialView | undefined;
@@ -4,11 +4,9 @@ export const CORE_VALUE_PORT_NAMES = Object.freeze([
4
4
  'combinePolicies',
5
5
  'createAllowDenyPolicy',
6
6
  'MCP_NAMESPACE',
7
- 'RETIRED_TOOL_NAMES',
8
7
  'protocolOf',
9
8
  'ruleToolGrammarOf',
10
9
  'validatePermissionRules',
11
- 'DISCUSSION_WORKFLOW_NAME',
12
10
  'mintNamespacePrefix',
13
11
  'compileAllowList',
14
12
  'routeKeyOf',
@@ -16,6 +14,7 @@ export const CORE_VALUE_PORT_NAMES = Object.freeze([
16
14
  'resolveRouteCredential',
17
15
  'adjudicateModelRoute',
18
16
  'routePairingStatus',
17
+ 'judgeRuleToolName',
19
18
  ]);
20
19
  let installed = null;
21
20
  export function installCoreValuePorts(ports) {
@@ -56,9 +55,6 @@ export function createAllowDenyPolicy(opts) {
56
55
  export function mcpNamespace() {
57
56
  return port('MCP_NAMESPACE');
58
57
  }
59
- export function retiredToolNames() {
60
- return port('RETIRED_TOOL_NAMES');
61
- }
62
58
  export function protocolOf(name) {
63
59
  const fn = port('protocolOf');
64
60
  return fn === undefined ? undefined : fn(name);
@@ -71,9 +67,6 @@ export function validatePermissionRules(rules, opts) {
71
67
  const fn = port('validatePermissionRules');
72
68
  return fn === undefined ? undefined : fn(rules, opts);
73
69
  }
74
- export function discussionWorkflowName() {
75
- return port('DISCUSSION_WORKFLOW_NAME');
76
- }
77
70
  export function mintNamespacePrefix(ns, peer) {
78
71
  const fn = port('mintNamespacePrefix');
79
72
  return fn === undefined ? undefined : fn(ns, peer);
@@ -82,6 +75,10 @@ export function compileAllowList(entries, behavior, roster) {
82
75
  const fn = port('compileAllowList');
83
76
  return fn === undefined ? undefined : fn(entries, behavior, roster);
84
77
  }
78
+ export function ruleToolNameJudgement(name, roster) {
79
+ const fn = port('judgeRuleToolName');
80
+ return fn === undefined ? undefined : fn(name, roster);
81
+ }
85
82
  export function routeKeyOf(url) {
86
83
  const fn = port('routeKeyOf');
87
84
  return fn === undefined ? undefined : fn(url);
@@ -0,0 +1,28 @@
1
+ export declare const CREDENTIAL_ATTACH_WORDS: readonly ["local-sidecar", "service-token", "registry", "none"];
2
+ export type CredentialAttachWord = (typeof CREDENTIAL_ATTACH_WORDS)[number];
3
+ declare const TARGET_KIND_WORDS: readonly ["local-managed", "loopback-pin", "remote", "unresolved"];
4
+ declare const TARGET_PROVENANCE_WORDS: readonly ["managed", "connect-pin", "manual", "none"];
5
+ declare const CONSENT_WORDS: readonly ["granted", "absent", "n/a"];
6
+ declare const SIDECAR_OWNERSHIP_WORDS: readonly ["verified", "mismatch"];
7
+ export type CredentialTargetKind = (typeof TARGET_KIND_WORDS)[number];
8
+ export type CredentialTargetProvenance = (typeof TARGET_PROVENANCE_WORDS)[number];
9
+ export type CredentialConsent = (typeof CONSENT_WORDS)[number];
10
+ export type CredentialSidecarOwnership = (typeof SIDECAR_OWNERSHIP_WORDS)[number];
11
+ export interface CredentialFacts {
12
+ readonly kind: CredentialTargetKind;
13
+ readonly provenance?: CredentialTargetProvenance;
14
+ readonly sidecarOwnership?: CredentialSidecarOwnership;
15
+ readonly serviceTokenAtFirstWrite?: boolean;
16
+ readonly loggedIn?: boolean;
17
+ readonly consent?: CredentialConsent;
18
+ }
19
+ export type CredentialFactName = 'facts' | 'kind' | 'sidecarOwnership' | 'serviceTokenAtFirstWrite' | 'loggedIn' | 'provenance' | 'consent';
20
+ export type CredentialProvenance = {
21
+ readonly kind: 'word';
22
+ readonly word: CredentialAttachWord;
23
+ } | {
24
+ readonly kind: 'unreadable';
25
+ readonly reason: CredentialFactName;
26
+ };
27
+ export declare function credentialProvenance(facts: CredentialFacts): CredentialProvenance;
28
+ export {};
@@ -0,0 +1,76 @@
1
+ export const CREDENTIAL_ATTACH_WORDS = Object.freeze(['local-sidecar', 'service-token', 'registry', 'none']);
2
+ const TARGET_KIND_WORDS = ['local-managed', 'loopback-pin', 'remote', 'unresolved'];
3
+ const TARGET_PROVENANCE_WORDS = ['managed', 'connect-pin', 'manual', 'none'];
4
+ const CONSENT_WORDS = ['granted', 'absent', 'n/a'];
5
+ const SIDECAR_OWNERSHIP_WORDS = ['verified', 'mismatch'];
6
+ function said(word) {
7
+ const r = { kind: 'word', word };
8
+ return Object.freeze(r);
9
+ }
10
+ function unreadable(reason) {
11
+ const r = { kind: 'unreadable', reason };
12
+ return Object.freeze(r);
13
+ }
14
+ function ownData(holder, key) {
15
+ try {
16
+ if (typeof holder !== 'object' || holder === null)
17
+ return undefined;
18
+ const d = Object.getOwnPropertyDescriptor(holder, key);
19
+ return d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
20
+ }
21
+ catch {
22
+ return undefined;
23
+ }
24
+ }
25
+ function ownBool(holder, key) {
26
+ const v = ownData(holder, key);
27
+ return typeof v === 'boolean' ? v : undefined;
28
+ }
29
+ function ownWord(holder, key, closed) {
30
+ const v = ownData(holder, key);
31
+ return typeof v === 'string' ? closed.find((w) => w === v) : undefined;
32
+ }
33
+ function decide(facts) {
34
+ if (typeof facts !== 'object' || facts === null || Array.isArray(facts))
35
+ return unreadable('facts');
36
+ const kind = ownWord(facts, 'kind', TARGET_KIND_WORDS);
37
+ if (kind === undefined)
38
+ return unreadable('kind');
39
+ if (kind === 'unresolved')
40
+ return said('none');
41
+ if (kind === 'local-managed') {
42
+ const owned = ownWord(facts, 'sidecarOwnership', SIDECAR_OWNERSHIP_WORDS);
43
+ if (owned === undefined)
44
+ return unreadable('sidecarOwnership');
45
+ return said(owned === 'verified' ? 'local-sidecar' : 'none');
46
+ }
47
+ const tokenAtFirstWrite = ownBool(facts, 'serviceTokenAtFirstWrite');
48
+ if (tokenAtFirstWrite === undefined)
49
+ return unreadable('serviceTokenAtFirstWrite');
50
+ if (tokenAtFirstWrite)
51
+ return said('service-token');
52
+ const loggedIn = ownBool(facts, 'loggedIn');
53
+ if (loggedIn === undefined)
54
+ return unreadable('loggedIn');
55
+ if (!loggedIn)
56
+ return said('none');
57
+ const provenance = ownWord(facts, 'provenance', TARGET_PROVENANCE_WORDS);
58
+ if (provenance === undefined)
59
+ return unreadable('provenance');
60
+ if (provenance !== 'connect-pin')
61
+ return said('none');
62
+ if (kind === 'remote')
63
+ return said('registry');
64
+ const consent = ownWord(facts, 'consent', CONSENT_WORDS);
65
+ if (consent === undefined || consent === 'n/a')
66
+ return unreadable('consent');
67
+ return said(consent === 'granted' ? 'registry' : 'none');
68
+ }
69
+ export function credentialProvenance(facts) {
70
+ try {
71
+ return decide(facts);
72
+ }
73
+ catch {
74
+ return unreadable('facts');
75
+ }
76
+ }
@@ -1,4 +1,4 @@
1
- import { corruptStoredRowContent, corruptStoredRowWhere } from './wireErrorTriage.js';
1
+ import { corruptStoredRowContent, corruptStoredRowWhere, scenarioDenyFromError, scenarioNotAllowedContent } from './wireErrorTriage.js';
2
2
  import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, parkedResumeStartupContent, parkedResumeStartupFromError, resumePolicyBlockContent, resumePolicyBlockFromError, } from './resumeRefusalCopy.js';
3
3
  import { askGoneContent, askGoneFromError, decideParkMovedContent, decideParkMovedFromError } from './decideReceipt.js';
4
4
  import { settingsPermissionBucketRefusalContent, settingsPermissionBucketRefusalFromError } from './wireRefusalCopy.js';
@@ -9,12 +9,14 @@ export function decideFailureNote(err, decision) {
9
9
  const startup = parkedResumeStartupFromError(err, decision);
10
10
  const moved = decideParkMovedFromError(err);
11
11
  const bucket = settingsPermissionBucketRefusalFromError(err);
12
+ const scenario = scenarioDenyFromError(err);
12
13
  const unsupported = checkpointUnsupportedVersionFromError(err);
13
14
  const gone = askGoneFromError(err);
14
15
  const answerInvalid = decisionConflictOf(err) === 'answer_invalid';
15
16
  return ((where === undefined ? '' : ` — ${corruptStoredRowContent(where)}`) +
16
17
  (fold === null ? '' : ` — ${resumePolicyBlockContent(fold)}`) +
17
18
  (bucket === null ? '' : ` — ${settingsPermissionBucketRefusalContent(bucket)}`) +
19
+ (scenario === null ? '' : ` — ${scenarioNotAllowedContent(scenario, undefined, 'resumed_work')}`) +
18
20
  (startup === null ? '' : ` — ${parkedResumeStartupContent(startup)}`) +
19
21
  (moved === null ? '' : ` — ${decideParkMovedContent(moved)}`) +
20
22
  (unsupported === null ? '' : ` — ${checkpointUnsupportedVersionContent(unsupported)}`) +
@@ -2,7 +2,7 @@ import { gateOutcomeOf } from './gateOutcome.js';
2
2
  import { resumeReopenFromError } from './hitl/suspendedReopen.js';
3
3
  import { ASK_GONE, DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_PARK_FORKED, DECIDE_WORKFLOW_PARKS_UNREADABLE, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
4
4
  import { effectiveWireErrorCode } from './wireErrorTriage.js';
5
- import { readErrorString, readErrorStrictStringList } from './wireFailureShape.js';
5
+ import { readErrorString, readErrorStrictStringList, readThrownExtra } from './wireFailureShape.js';
6
6
  import { isCrashConvergedCause } from './hitl/crashConverged.js';
7
7
  import { askRowEndingCauseFor } from './hitl/approvalEndingCause.js';
8
8
  const STATUS_RESUMING = 'resuming';
@@ -143,14 +143,11 @@ function askGoneRawCause(e) {
143
143
  }
144
144
  if (typeof top === 'string')
145
145
  return top;
146
- let extra;
147
- try {
148
- extra = e.extra;
149
- }
150
- catch {
151
- extra = undefined;
152
- }
153
- if (typeof extra === 'object' && extra !== null && !Array.isArray(extra)) {
146
+ const reading = readThrownExtra(e);
147
+ if (reading.state === 'unreadable')
148
+ return undefined;
149
+ if (reading.state === 'object') {
150
+ const extra = reading.value;
154
151
  let hasCause = false;
155
152
  let word;
156
153
  try {
@@ -163,7 +160,7 @@ function askGoneRawCause(e) {
163
160
  if (hasCause)
164
161
  return word;
165
162
  }
166
- return readErrorString(e, 'deniedReason');
163
+ return undefined;
167
164
  }
168
165
  export function askGoneFromError(e) {
169
166
  if (typeof e !== 'object' || e === null)
@@ -1,5 +1,5 @@
1
1
  export const DECLARED_SUPPORT_FLOOR = Object.freeze({
2
- server: "7.115.0",
3
- core: "7.40.1",
4
- sdk: "19.0.0",
2
+ server: "7.125.0",
3
+ core: "7.48.0",
4
+ sdk: "20.0.0",
5
5
  });
@@ -8,9 +8,6 @@ export interface DisplayFace {
8
8
  readonly mark: DisplayMark;
9
9
  readonly keepBlanks?: boolean;
10
10
  }
11
- export declare const LEGACY_ESCAPE_FACE: DisplayFace;
12
- export declare const LEGACY_LABEL_FACE: DisplayFace;
13
- export declare const LEGACY_NAME_FACE: DisplayFace;
14
11
  export declare function applyDisplayFace(text: string, face: DisplayFace): string;
15
12
  export interface DisplayUntrustedOptions {
16
13
  readonly credentialUrls?: boolean;
@@ -33,10 +30,17 @@ export interface DisplayUntrustedMarked {
33
30
  readonly text: string;
34
31
  readonly marks: readonly DisplayMarkSpan[];
35
32
  }
33
+ export declare const ESCAPE_FACE: DisplayFace;
34
+ export declare const LABEL_FACE: DisplayFace;
35
+ export declare const PEER_NAME_FACE: DisplayFace;
36
+ export declare function capDisplay(text: string, max: number | undefined, mark: DisplayMark): string;
37
+ export declare function paintAndCap(text: string, face: DisplayFace, max?: number): string;
36
38
  export declare function credentialWashPasses(text: string, opts?: DisplayUntrustedOptions | null): {
37
39
  passes: number;
38
40
  capped: boolean;
39
41
  };
40
42
  export declare function displayUntrusted(text: string, opts?: DisplayUntrustedOptions): string;
43
+ export declare function queryCarriesCredential(query: string): boolean;
44
+ export declare function displayConfiguredUrl(url: string, opts?: DisplayUntrustedOptions): string;
41
45
  export declare function quoteUntrustedForSentence(text: string, max: number): string | undefined;
42
46
  export declare function displayUntrustedMarks(text: string, opts?: DisplayUntrustedOptions): DisplayUntrustedMarked;