@sema-agent/client-core 0.109.0 → 0.110.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 (123) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +46 -22
  3. package/dist/adapt/arms.js +20 -7
  4. package/dist/adapter/downstream/eventToSdkMessage.js +11 -6
  5. package/dist/declared/supportFloorDeclared.js +1 -1
  6. package/dist/displayUntrusted.js +132 -14
  7. package/dist/engineErrorCodes.d.ts +3 -0
  8. package/dist/engineErrorCodes.js +3 -0
  9. package/dist/engineHealthFacts.d.ts +9 -0
  10. package/dist/engineHealthFacts.js +21 -1
  11. package/dist/engineInlineTaskStats.d.ts +4 -3
  12. package/dist/engineInlineTaskStats.js +18 -2
  13. package/dist/engineNoticeCodes.d.ts +10 -0
  14. package/dist/engineNoticeCodes.js +33 -1
  15. package/dist/engineRepoint.d.ts +140 -0
  16. package/dist/engineRepoint.js +285 -0
  17. package/dist/engineRowRef.js +2 -0
  18. package/dist/engineSessionMessages.d.ts +2 -1
  19. package/dist/engineSessionMessages.js +5 -0
  20. package/dist/errorSupplementRoles.js +2 -1
  21. package/dist/fleet/fleetProjection.js +3 -2
  22. package/dist/generated/engineFactTables.d.ts +2 -0
  23. package/dist/generated/engineFactTables.js +12 -0
  24. package/dist/generated/sdkFactTables.d.ts +1 -0
  25. package/dist/generated/sdkFactTables.js +4 -0
  26. package/dist/hitl/approvalAskers.d.ts +6 -0
  27. package/dist/hitl/approvalAskers.js +30 -0
  28. package/dist/hitl/approvalCardReasons.js +6 -3
  29. package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
  30. package/dist/hitl/approvalRequestFrameReading.js +11 -0
  31. package/dist/hitl/approvalResolution.d.ts +8 -1
  32. package/dist/hitl/approvalResolution.js +4 -0
  33. package/dist/hitl/askGateWire.js +0 -2
  34. package/dist/hitl/automaticAnswerVerdict.js +2 -2
  35. package/dist/hitl/decisionConflict.js +6 -3
  36. package/dist/hitl/decisionRefusal.js +1 -0
  37. package/dist/hitl/decisionSend.d.ts +3 -0
  38. package/dist/hitl/decisionSend.js +29 -11
  39. package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
  40. package/dist/hitl/editedApprovalAcceptance.js +26 -0
  41. package/dist/hitl/frameRouter.js +4 -18
  42. package/dist/hitl/gateLedger.d.ts +0 -4
  43. package/dist/hitl/gateLedger.js +0 -19
  44. package/dist/hitl/hitlBridge.d.ts +1 -0
  45. package/dist/hitl/hitlBridge.js +4 -4
  46. package/dist/hitl/hitlHostSurface.d.ts +1 -0
  47. package/dist/hitl/hitlHostSurface.js +7 -2
  48. package/dist/hitl/hostWithdrawal.d.ts +15 -0
  49. package/dist/hitl/hostWithdrawal.js +38 -0
  50. package/dist/hitl/parkResolver.js +25 -9
  51. package/dist/hitl/persistedRulesWire.js +2 -2
  52. package/dist/hitl/planReviewWire.js +14 -4
  53. package/dist/hitl/sessionPolicyWire.js +6 -4
  54. package/dist/hitl/standingRows.d.ts +1 -0
  55. package/dist/hitl/standingRows.js +15 -1
  56. package/dist/hitl/toolApprovalWire.d.ts +35 -8
  57. package/dist/hitl/toolApprovalWire.js +235 -33
  58. package/dist/hooksWireCaps.js +31 -1
  59. package/dist/hostTurnSettings.d.ts +10 -4
  60. package/dist/hostTurnSettings.js +112 -5
  61. package/dist/i18n/messages.en.d.ts +83 -0
  62. package/dist/i18n/messages.en.js +86 -2
  63. package/dist/i18n/messages.zh.js +96 -2
  64. package/dist/index.d.ts +21 -7
  65. package/dist/index.js +14 -4
  66. package/dist/inheritEnvCapability.js +2 -0
  67. package/dist/inputAuthor.d.ts +16 -0
  68. package/dist/inputAuthor.js +44 -0
  69. package/dist/interruptRefusalNote.d.ts +2 -0
  70. package/dist/interruptRefusalNote.js +17 -0
  71. package/dist/liveModelCatalog.d.ts +2 -0
  72. package/dist/liveModelCatalog.js +21 -7
  73. package/dist/liveQuestionStore.d.ts +4 -1
  74. package/dist/liveQuestionStore.js +12 -3
  75. package/dist/mcpEngineLeg.d.ts +3 -0
  76. package/dist/mcpEngineLeg.js +38 -1
  77. package/dist/mcpPanel.js +2 -0
  78. package/dist/mcpReconnect.d.ts +9 -1
  79. package/dist/mcpReconnect.js +121 -16
  80. package/dist/modelCapabilityProbe.js +4 -3
  81. package/dist/modsFace.d.ts +8 -1
  82. package/dist/modsFace.js +27 -0
  83. package/dist/notifications.d.ts +17 -6
  84. package/dist/notifications.js +67 -19
  85. package/dist/ownKey.d.ts +0 -5
  86. package/dist/ownKey.js +0 -7
  87. package/dist/peerFrames.d.ts +40 -2
  88. package/dist/peerFrames.js +158 -3
  89. package/dist/pluginHooksWire.d.ts +2 -1
  90. package/dist/pluginHooksWire.js +56 -1
  91. package/dist/replayBody.js +10 -2
  92. package/dist/request/taskRequest.d.ts +5 -0
  93. package/dist/request/taskRequest.js +138 -21
  94. package/dist/resumeRefusalCopy.d.ts +1 -3
  95. package/dist/resumeRefusalCopy.js +2 -1
  96. package/dist/retryStatus.d.ts +2 -2
  97. package/dist/retryStatus.js +2 -0
  98. package/dist/seam.d.ts +12 -1
  99. package/dist/seam.js +7 -1
  100. package/dist/seatContract.d.ts +86 -9
  101. package/dist/seatContract.js +196 -7
  102. package/dist/sessionBackground.js +2 -1
  103. package/dist/sessionBackgroundHandoff.js +2 -1
  104. package/dist/sessionEngine.d.ts +2 -0
  105. package/dist/sessionEngine.js +111 -0
  106. package/dist/sessionMemoryStatus.d.ts +2 -1
  107. package/dist/sessionSyncFileHistory.d.ts +4 -0
  108. package/dist/sessionSyncFileHistory.js +28 -0
  109. package/dist/sseIdleTriage.d.ts +13 -1
  110. package/dist/sseIdleTriage.js +24 -6
  111. package/dist/subagent/engineSubagentTail.js +6 -0
  112. package/dist/terminalStatuses.d.ts +1 -0
  113. package/dist/terminalStatuses.js +4 -1
  114. package/dist/turnFailurePresentation.js +9 -2
  115. package/dist/typePins.d.ts +11 -0
  116. package/dist/usageAnalytics.d.ts +17 -0
  117. package/dist/usageAnalytics.js +44 -2
  118. package/dist/wireFailureShape.d.ts +2 -5
  119. package/dist/wireFailureShape.js +10 -20
  120. package/dist/wireRefusalCopy.d.ts +10 -0
  121. package/dist/wireRefusalCopy.js +76 -0
  122. package/docs/INTEGRATION-CLIENTS.md +2126 -20
  123. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
- import { applyDisplayFace, PEER_NAME_FACE } from './displayUntrusted.js';
1
+ import { applyDisplayFace, displayUntrusted, PEER_NAME_FACE } from './displayUntrusted.js';
2
+ import { msg, renderMessage } from './i18n/translate.js';
2
3
  import { ownSnapshotRecord } from './ownKey.js';
3
4
  import { CORE_ENGINE_AUTHORITY_ENVELOPE_TAGS, CORE_PERMISSION_MODE_CLASSES } from './generated/engineFactTables.js';
4
5
  const WIRE_KEY_FROM = 'from';
@@ -12,6 +13,20 @@ const WIRE_KEY_AGENT_TYPE = 'agentType';
12
13
  const WIRE_KEY_AGENT_MESSAGE = 'agentMessage';
13
14
  const WIRE_KEY_CROSS_SESSION_MESSAGE = 'crossSessionMessage';
14
15
  const WIRE_KEY_CROSS_SESSION_NOTICE = 'crossSessionNotice';
16
+ const WIRE_KEY_INBOX_NOTICE = 'inboxNotice';
17
+ const WIRE_KEY_PENDING = 'pending';
18
+ const WIRE_KEY_DELIVERED = 'delivered';
19
+ const WIRE_KEY_URGENT = 'urgent';
20
+ const WIRE_KEY_RESUPPLIED = 'resupplied';
21
+ const WIRE_KEY_PEER_META = 'peerMeta';
22
+ const WIRE_KEY_NOTICE = 'notice';
23
+ const WIRE_KEY_STATE = 'state';
24
+ const WIRE_KEY_REF_SEQ = 'refSeq';
25
+ const WIRE_KEY_RECIPIENT = 'recipient';
26
+ const WIRE_KEY_TARGET = 'target';
27
+ const WIRE_KEY_DETAIL = 'detail';
28
+ const WIRE_KEY_DROP_REASON = 'dropReason';
29
+ const WIRE_KEY_FINISHED_AT = 'finishedAt';
15
30
  const WIRE_KEY_PROVENANCE = '_sema_provenance';
16
31
  const WIRE_KEY_FROM_SESSION = 'fromSession';
17
32
  const WIRE_KEY_FROM_NAME = 'fromName';
@@ -20,7 +35,7 @@ const WIRE_KEY_FROM_SCOPE = 'fromScope';
20
35
  const FROM_ATTR = WIRE_KEY_FROM;
21
36
  export const AGENT_MESSAGE_TAG = 'agent-message';
22
37
  export const CROSS_SESSION_MESSAGE_TAG = 'cross-session-message';
23
- export const PEER_FRAME_LANES = Object.freeze(['agent_message', 'cross_session_message', 'cross_session_notice']);
38
+ export const PEER_FRAME_LANES = Object.freeze(['agent_message', 'cross_session_message', 'cross_session_notice', 'inbox_notice']);
24
39
  export const CROSS_SESSION_NOTICE_KINDS = Object.freeze(['delivery_notice', 'idle_notice']);
25
40
  export const PEER_MODE_CLASSES = CORE_PERMISSION_MODE_CLASSES;
26
41
  function dataProp(o, key) {
@@ -43,6 +58,40 @@ function nonEmptyString(v) {
43
58
  function finiteNumber(v) {
44
59
  return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
45
60
  }
61
+ function countOf(v) {
62
+ return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : undefined;
63
+ }
64
+ function shownLabel(v, max) {
65
+ if (typeof v !== 'string')
66
+ return undefined;
67
+ const s = displayUntrusted(v, { blanks: true, max });
68
+ return s.length > 0 ? s : undefined;
69
+ }
70
+ const NOTICE_LABEL_MAX = 64;
71
+ const NOTICE_TEXT_MAX = 200;
72
+ function peerNoticeOf(n) {
73
+ const notice = dataProp(dataProp(dataProp(n, WIRE_KEY_PROVENANCE), WIRE_KEY_PEER_META), WIRE_KEY_NOTICE);
74
+ if (notice === null || typeof notice !== 'object')
75
+ return undefined;
76
+ const state = nonEmptyString(dataProp(notice, WIRE_KEY_STATE));
77
+ if (state === undefined)
78
+ return undefined;
79
+ const recipient = shownLabel(dataProp(notice, WIRE_KEY_RECIPIENT), NOTICE_LABEL_MAX);
80
+ const target = shownLabel(dataProp(notice, WIRE_KEY_TARGET), NOTICE_LABEL_MAX);
81
+ const detail = shownLabel(dataProp(notice, WIRE_KEY_DETAIL), NOTICE_TEXT_MAX);
82
+ const dropReason = shownLabel(dataProp(notice, WIRE_KEY_DROP_REASON), NOTICE_TEXT_MAX);
83
+ const refSeq = countOf(dataProp(notice, WIRE_KEY_REF_SEQ));
84
+ const finishedAt = countOf(dataProp(notice, WIRE_KEY_FINISHED_AT));
85
+ return {
86
+ state,
87
+ ...(recipient !== undefined ? { recipient } : {}),
88
+ ...(target !== undefined ? { target } : {}),
89
+ ...(detail !== undefined ? { detail } : {}),
90
+ ...(dropReason !== undefined ? { dropReason } : {}),
91
+ ...(refSeq !== undefined ? { refSeq } : {}),
92
+ ...(finishedAt !== undefined ? { finishedAt } : {}),
93
+ };
94
+ }
46
95
  function provenanceAgrees(n, lane, carrierFromRaw) {
47
96
  const prov = dataProp(n, WIRE_KEY_PROVENANCE);
48
97
  if (prov === null || typeof prov !== 'object')
@@ -112,7 +161,24 @@ export function classifyPeerNotification(raw) {
112
161
  const text = nonEmptyString(dataProp(crossSessionNotice, WIRE_KEY_TEXT));
113
162
  if (kind === undefined || text === undefined || !provenanceAgrees(n, 'cross_session_notice'))
114
163
  return null;
115
- return { lane: 'cross_session_notice', kind, text };
164
+ const notice = peerNoticeOf(n);
165
+ return { lane: 'cross_session_notice', kind, text, ...(notice !== undefined ? { notice } : {}) };
166
+ }
167
+ const inboxNotice = dataProp(n, WIRE_KEY_INBOX_NOTICE);
168
+ if (inboxNotice !== undefined) {
169
+ const pending = countOf(dataProp(inboxNotice, WIRE_KEY_PENDING));
170
+ const delivered = countOf(dataProp(inboxNotice, WIRE_KEY_DELIVERED));
171
+ if (pending === undefined || delivered === undefined || !provenanceAgrees(n, 'inbox_notice'))
172
+ return null;
173
+ const urgent = countOf(dataProp(inboxNotice, WIRE_KEY_URGENT));
174
+ const resupplied = countOf(dataProp(inboxNotice, WIRE_KEY_RESUPPLIED));
175
+ return {
176
+ lane: 'inbox_notice',
177
+ pending,
178
+ delivered,
179
+ ...(urgent !== undefined ? { urgent } : {}),
180
+ ...(resupplied !== undefined ? { resupplied } : {}),
181
+ };
116
182
  }
117
183
  return null;
118
184
  }
@@ -140,9 +206,98 @@ function attr(v) {
140
206
  function unattr(v) {
141
207
  return v.replace(/&quot;/g, '"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
142
208
  }
209
+ const DELIVERY_SENTENCE_KEYS = Object.freeze({
210
+ delivered: 'notice.sessionBox.delivery.delivered',
211
+ held: 'notice.sessionBox.delivery.held',
212
+ held_by_policy: 'notice.sessionBox.delivery.heldByPolicy',
213
+ denied: 'notice.sessionBox.delivery.denied',
214
+ refused: 'notice.sessionBox.delivery.refused',
215
+ expired: 'notice.sessionBox.delivery.expired',
216
+ });
217
+ const IDLE_SENTENCE_KEYS = Object.freeze({
218
+ exited: 'notice.sessionBox.idle.exited',
219
+ unavailable: 'notice.sessionBox.idle.unavailable',
220
+ expired: 'notice.sessionBox.idle.expired',
221
+ });
222
+ function sentenceKeyOf(table, word) {
223
+ return Object.hasOwn(table, word) ? table[word] : undefined;
224
+ }
225
+ function joinParts(parts, lang) {
226
+ return parts.join(lang === 'zh' ? '' : ' ');
227
+ }
228
+ function inboxLine(pending, urgent, resupplied, lang) {
229
+ const parts = [renderMessage(pending === 1 ? msg('notice.sessionBox.inbox.one') : msg('notice.sessionBox.inbox.many', { pending }), lang)];
230
+ if (urgent !== undefined)
231
+ parts.push(renderMessage(msg('notice.sessionBox.inbox.urgent', { urgent }), lang));
232
+ if (resupplied !== undefined)
233
+ parts.push(renderMessage(msg('notice.sessionBox.inbox.resupplied', { resupplied }), lang));
234
+ return joinParts(parts, lang);
235
+ }
236
+ export function sessionBoxNoticeSentence(facts, lang) {
237
+ try {
238
+ const noticeKind = dataProp(facts, 'noticeKind');
239
+ if (noticeKind === 'inbox') {
240
+ const pending = countOf(dataProp(facts, WIRE_KEY_PENDING));
241
+ if (pending === undefined)
242
+ return undefined;
243
+ return inboxLine(pending, countOf(dataProp(facts, WIRE_KEY_URGENT)), countOf(dataProp(facts, WIRE_KEY_RESUPPLIED)), lang);
244
+ }
245
+ if (noticeKind !== 'delivery' && noticeKind !== 'idle')
246
+ return undefined;
247
+ const state = nonEmptyString(dataProp(facts, WIRE_KEY_STATE));
248
+ if (state === undefined)
249
+ return undefined;
250
+ const label = shownLabel(dataProp(facts, 'peerLabel'), NOTICE_LABEL_MAX);
251
+ const detail = shownLabel(dataProp(facts, WIRE_KEY_DETAIL), NOTICE_TEXT_MAX);
252
+ const dropReason = shownLabel(dataProp(facts, WIRE_KEY_DROP_REASON), NOTICE_TEXT_MAX);
253
+ if (noticeKind === 'delivery') {
254
+ const peer = label ?? renderMessage(msg('notice.sessionBox.peer.another'), lang);
255
+ if (state === 'dropped')
256
+ return renderMessage(dropReason !== undefined ? msg('notice.sessionBox.delivery.dropped', { peer, reason: dropReason }) : msg('notice.sessionBox.delivery.droppedPlain', { peer }), lang);
257
+ return renderMessage(msg(sentenceKeyOf(DELIVERY_SENTENCE_KEYS, state) ?? 'notice.sessionBox.delivery.other', { peer }), lang);
258
+ }
259
+ const peer = label ?? renderMessage(msg('notice.sessionBox.peer.anotherStart'), lang);
260
+ if (state === 'idle')
261
+ return renderMessage(detail !== undefined ? msg('notice.sessionBox.idle.finishedDetail', { peer, detail }) : msg('notice.sessionBox.idle.finished', { peer }), lang);
262
+ return renderMessage(msg(sentenceKeyOf(IDLE_SENTENCE_KEYS, state) ?? 'notice.sessionBox.idle.other', { peer }), lang);
263
+ }
264
+ catch {
265
+ return undefined;
266
+ }
267
+ }
268
+ export function sessionBoxNoticeOf(p) {
269
+ if (p.lane === 'inbox_notice') {
270
+ const facts = {
271
+ noticeKind: 'inbox',
272
+ pending: p.pending,
273
+ delivered: p.delivered,
274
+ ...(p.urgent !== undefined ? { urgent: p.urgent } : {}),
275
+ ...(p.resupplied !== undefined ? { resupplied: p.resupplied } : {}),
276
+ };
277
+ const text = sessionBoxNoticeSentence(facts);
278
+ return text === undefined ? undefined : { ...facts, text };
279
+ }
280
+ if (p.lane !== 'cross_session_notice' || p.notice === undefined)
281
+ return undefined;
282
+ const delivery = p.kind === 'delivery_notice';
283
+ const peerLabel = delivery ? (p.notice.recipient ?? p.notice.target) : (p.notice.target ?? p.notice.recipient);
284
+ const facts = {
285
+ noticeKind: delivery ? 'delivery' : 'idle',
286
+ state: p.notice.state,
287
+ ...(peerLabel !== undefined ? { peerLabel } : {}),
288
+ ...(p.notice.detail !== undefined ? { detail: p.notice.detail } : {}),
289
+ ...(p.notice.dropReason !== undefined ? { dropReason: p.notice.dropReason } : {}),
290
+ ...(p.notice.refSeq !== undefined ? { refSeq: p.notice.refSeq } : {}),
291
+ ...(p.notice.finishedAt !== undefined ? { finishedAt: p.notice.finishedAt } : {}),
292
+ };
293
+ const text = sessionBoxNoticeSentence(facts);
294
+ return text === undefined ? undefined : { ...facts, text };
295
+ }
143
296
  export function renderPeerFrameTranscriptText(p) {
144
297
  if (p.lane === 'cross_session_notice')
145
298
  return escapeEnvelopeTag(CROSS_SESSION_MESSAGE_TAG, escapeEnvelopeTag(AGENT_MESSAGE_TAG, neutralizeAuthorityTags(p.text)));
299
+ if (p.lane === 'inbox_notice')
300
+ return inboxLine(p.pending, p.urgent, p.resupplied, undefined);
146
301
  if (p.lane === 'agent_message') {
147
302
  const body = escapeEnvelopeTag(AGENT_MESSAGE_TAG, neutralizeAuthorityTags(p.body));
148
303
  return `<${AGENT_MESSAGE_TAG} ${FROM_ATTR}="${attr(p.from)}">\n${body}\n</${AGENT_MESSAGE_TAG}>`;
@@ -12,7 +12,7 @@ export declare const PLUGIN_HOOK_REASONS: readonly ["projected", "shell_event",
12
12
  export type PluginHookReason = (typeof PLUGIN_HOOK_REASONS)[number];
13
13
  export declare const PLUGIN_HOOK_EXCLUSION_REASONS: readonly ["workspace_untrusted", "governance_unreadable", "policy_disable_all", "startup_mode", "managed_plugins_only", "prompt_not_user_authored"];
14
14
  export type PluginHookExclusionReason = (typeof PLUGIN_HOOK_EXCLUSION_REASONS)[number];
15
- export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported", "key_not_read", "source_not_authored"];
15
+ export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported", "key_not_read", "source_not_authored", "workspace_untrusted", "governance_unreadable", "policy_disable_all"];
16
16
  export type SettingsHookDropReason = (typeof SETTINGS_HOOK_DROP_REASONS)[number];
17
17
  export type HookSettingsSource = 'policySettings' | 'userSettings' | 'projectSettings' | 'localSettings' | 'flagSettings';
18
18
  export interface PluginHookKey {
@@ -196,6 +196,7 @@ export interface SettingsHooksLocalGroup<T> {
196
196
  export declare function settingsHooksKeptLocally<T>(plan: HooksWirePlan, event: string, group: SettingsHooksLocalGroup<T>, opts?: {
197
197
  readonly engineCompaction?: 'performed' | 'not_performed';
198
198
  }): readonly T[];
199
+ export declare function pluginHooksKeptLocally<T>(plan: HooksWirePlan, pluginId: string, event: string, groupIndex: number, hooks: readonly T[]): readonly T[];
199
200
  export declare function pluginHookReasonText(reason: PluginHookReason): string;
200
201
  export declare function settingsHookDropText(reason: SettingsHookDropReason): string;
201
202
  export declare function pluginHookExecutorLabel(v: PluginHookVerdict): string;
@@ -1,5 +1,6 @@
1
1
  import { displayUntrusted } from './displayUntrusted.js';
2
2
  import { appendOwnElement, readOwnDataValue } from './ownKey.js';
3
+ import { inSlotReadOf } from './wireFailureShape.js';
3
4
  import { msg, renderMessage } from './i18n/translate.js';
4
5
  import { SETTINGS_ENGINE_OWNED_HOOK_EVENTS } from './generated/settingsSchemaTables.js';
5
6
  import { HOOK_SETTINGS_SOURCE_TEXT, hooksEntryUnreadKeys, hooksGroupAuthoredSource, hooksGroupUnreadKeys, hooksKeyCoordinateText, hooksSalvageMaskOf, salvageSettingsHooksEntries, } from './settingsHooksSalvage.js';
@@ -40,7 +41,15 @@ export const PLUGIN_HOOK_EXCLUSION_REASONS = [
40
41
  'managed_plugins_only',
41
42
  'prompt_not_user_authored',
42
43
  ];
43
- export const SETTINGS_HOOK_DROP_REASONS = ['exec_form_unsupported', 'mcp_tool_unsupported', 'key_not_read', 'source_not_authored'];
44
+ export const SETTINGS_HOOK_DROP_REASONS = [
45
+ 'exec_form_unsupported',
46
+ 'mcp_tool_unsupported',
47
+ 'key_not_read',
48
+ 'source_not_authored',
49
+ 'workspace_untrusted',
50
+ 'governance_unreadable',
51
+ 'policy_disable_all',
52
+ ];
44
53
  export function hooksWirePlanShapeOf(v) {
45
54
  try {
46
55
  if (typeof v !== 'object' || v === null || Array.isArray(v))
@@ -729,6 +738,8 @@ function skipMatcherKey(matcher) {
729
738
  return matcher === undefined || matcher === null || matcher === '' || matcher === '*' ? 'null' : JSON.stringify(matcher);
730
739
  }
731
740
  export function settingsHooksKeptLocally(plan, event, group, opts) {
741
+ if (planClosedLocally(plan))
742
+ return [];
732
743
  let raw;
733
744
  try {
734
745
  raw = group?.hooks;
@@ -802,6 +813,42 @@ export function settingsHooksKeptLocally(plan, event, group, opts) {
802
813
  return hooks;
803
814
  }
804
815
  }
816
+ function planClosedLocally(plan) {
817
+ if (typeof plan !== 'object' || plan === null)
818
+ return false;
819
+ let slot;
820
+ try {
821
+ slot = inSlotReadOf(plan, 'closedBy');
822
+ }
823
+ catch {
824
+ return true;
825
+ }
826
+ if (slot.state === 'absent')
827
+ return false;
828
+ if (slot.state !== 'present')
829
+ return true;
830
+ return slot.value !== null && slot.value !== undefined;
831
+ }
832
+ export function pluginHooksKeptLocally(plan, pluginId, event, groupIndex, hooks) {
833
+ if (planClosedLocally(plan))
834
+ return [];
835
+ if (!Array.isArray(hooks))
836
+ return hooks;
837
+ try {
838
+ let kept = null;
839
+ hooks.forEach((h, i) => {
840
+ const engineRuns = pluginHookVerdictOf(plan, pluginId, event, groupIndex, i)?.disposition === 'engine';
841
+ if (engineRuns)
842
+ kept ??= hooks.slice(0, i);
843
+ else if (kept !== null)
844
+ appendOwnElement(kept, h);
845
+ });
846
+ return kept ?? hooks;
847
+ }
848
+ catch {
849
+ return hooks;
850
+ }
851
+ }
805
852
  function settingsRowBaseOf(v) {
806
853
  if (!isRecord(v))
807
854
  return undefined;
@@ -881,6 +928,9 @@ const DROP_TEXT = {
881
928
  mcp_tool_unsupported: 'MCP tool hooks are not supported by the engine',
882
929
  key_not_read: REASON_TEXT.key_not_read,
883
930
  source_not_authored: REASON_TEXT.source_not_authored,
931
+ workspace_untrusted: renderMessage(msg('config.hooks.plan.reason.closedUntrusted')),
932
+ governance_unreadable: renderMessage(msg('config.hooks.plan.reason.closedGovernanceUnreadable')),
933
+ policy_disable_all: renderMessage(msg('config.hooks.plan.reason.closedDisableAll')),
884
934
  };
885
935
  const SOURCE_TEXT = HOOK_SETTINGS_SOURCE_TEXT;
886
936
  export function pluginHookReasonText(reason) {
@@ -958,6 +1008,9 @@ function namedPathsOfRow(d) {
958
1008
  return typeof d.event === 'string' && Number.isInteger(d.groupIndex) && d.groupIndex >= 0 ? [['hooks', d.event, d.groupIndex, 'source']] : [];
959
1009
  case 'exec_form_unsupported':
960
1010
  case 'mcp_tool_unsupported':
1011
+ case 'workspace_untrusted':
1012
+ case 'governance_unreadable':
1013
+ case 'policy_disable_all':
961
1014
  return [];
962
1015
  }
963
1016
  }
@@ -1009,6 +1062,8 @@ export function hooksNotRunNotice(plan) {
1009
1062
  for (const d of plan.settingsDropped) {
1010
1063
  if (!d.notRun)
1011
1064
  continue;
1065
+ if (d.reason === 'workspace_untrusted' || d.reason === 'policy_disable_all')
1066
+ continue;
1012
1067
  const named = d.reason === 'key_not_read' || d.reason === 'source_not_authored' ? namedPathsOfRow(d) : [];
1013
1068
  if (named.length > 0 && (d.reason === 'key_not_read' || d.reason === 'source_not_authored')) {
1014
1069
  const nk = `${d.source}\u0000${d.reason}`;
@@ -62,8 +62,16 @@ export function runRowSentenceOf(carrier) {
62
62
  return undefined;
63
63
  }
64
64
  }
65
+ function isPlainObjectLike(v) {
66
+ try {
67
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
65
73
  export function doneResultView(result) {
66
- if (typeof result !== 'object' || result === null || Array.isArray(result))
74
+ if (!isPlainObjectLike(result))
67
75
  return { replay: false, receipt: false, body: result };
68
76
  const replay = guarded(result, 'replay') === true;
69
77
  const engine = engineResultLayerOf(result);
@@ -80,7 +88,7 @@ export function doneResultView(result) {
80
88
  return { replay, receipt: true, body: Object.freeze(view) };
81
89
  }
82
90
  export function isReplayedTerminal(frame) {
83
- if (frame === null || typeof frame !== 'object' || Array.isArray(frame))
91
+ if (!isPlainObjectLike(frame))
84
92
  return false;
85
93
  if (guarded(frame, 'type') !== 'done')
86
94
  return false;
@@ -179,5 +179,10 @@ export interface LiveDefaultsInput {
179
179
  mockScenarioKeys?: ReadonlySet<string>;
180
180
  }
181
181
  export declare function applyLiveRequestDefaults(req: TaskRequestLike, host: LiveDefaultsInput): TaskRequestLike;
182
+ export interface LiveRequestDefaultsResult {
183
+ readonly request: TaskRequestLike;
184
+ readonly notices: readonly HostSettingNotice[];
185
+ }
186
+ export declare function applyLiveRequestDefaultsWithNotices(req: TaskRequestLike, host: LiveDefaultsInput): LiveRequestDefaultsResult;
182
187
  export type BuiltTaskRequest = TaskRequest;
183
188
  export declare function unregisteredRequestKeys(req: TaskRequestLike, lane: RequestLane): string[];
@@ -8,9 +8,9 @@ import { PROJECT_MEMORY_DISABLED } from '../projectMemory.js';
8
8
  import { frameFamiliesJudgementOf } from '../approvalFrameFamilies.js';
9
9
  import { outputStyleSeatAdmitted } from '../outputStyleSeatCapability.js';
10
10
  import { refuseBadApprovalReach } from '../approvalReachWire.js';
11
- import { HOST_SUPPLIED_KEYS, UNWIRED_HOST_TURN_SETTINGS, buildHostTurnSettings, hostIntakeSnapshotOf, hostFileHistoryRestoreNotice, hostProjectionNotice, hostTurnSettingsOf, intersectHostHooks, rethrowHostResolvedDeferred, hostSettingsRefusedError, } from '../hostTurnSettings.js';
11
+ import { HOST_SUPPLIED_KEYS, UNWIRED_HOST_TURN_SETTINGS, buildHostTurnSettings, hostIntakeSnapshotOf, hostFileHistoryRestoreNotice, hostProjectionNotice, hostStyleNotAppliedNotice, hostTurnSettingsOf, hookEnvNamesOf, intersectHostHooks, rethrowHostResolvedDeferred, hostSettingsRefusedError, } from '../hostTurnSettings.js';
12
12
  import { SUBMISSION_ORIGINS, SUBMISSION_SURFACES, SUBMISSION_TOOLS, submissionAxesOf, } from './submissionIdentity.js';
13
- import { withAssemblyRefusal } from '../wireFailureShape.js';
13
+ import { slotReadOf, withAssemblyRefusal } from '../wireFailureShape.js';
14
14
  import { isPlainRecord, materializeJsonFaithful, shapeTag } from '../jsonFaithful.js';
15
15
  export const REQUEST_FIELD_MATRIX = [
16
16
  { field: 'objective', lanes: ['interactive', 'print', 'utility'], live: false, why: '本 turn 的真实输入,每条车道都必需', whyUtilityLane: '恒座:三条车道都必须带上本次提交的模型面输入' },
@@ -29,6 +29,7 @@ export const REQUEST_FIELD_MATRIX = [
29
29
  { field: 'mcpServers', lanes: ['interactive', 'print'], live: true, why: '本地 .mcp.json 投影;service 单用户门决定是否兑现', whyUtilityLane: '无座:MCP 服务挂的是工具,与零工具面矛盾' },
30
30
  { field: 'settings.webSearch', lanes: ['interactive', 'print'], live: true, why: 'SEMA_WEBSEARCH_* / settings.json;per-request 配置赢过部署 env', whyUtilityLane: '无座:联网检索是一只工具,与零工具面矛盾' },
31
31
  { field: 'settings.hooks', lanes: ['interactive', 'print'], live: true, why: '[495]① 用户 settings 文件 hooks 逐字上 wire', whyUtilityLane: '无座:hook 挂在工具门上(零工具面没有门),而且 side-channel 是壳自己的提交,不该继承用户那份 hook 表' },
32
+ { field: 'settings.env', lanes: ['interactive', 'print'], live: true, why: '交引擎执行的 http hook 头 `$NAME` 插值的那一层环境(服务端 `settings.env`:引擎 hook 环境 = 十二名基础名单 + 本键;同一份也进引擎命令 hook 与单用户宿主车道的会话 shell 环境 —— 服务端的设计)。两条用户车道都把 hooks 交给引擎执行 ⇒ 都有座,与 settings.hooks 同座。值只由宿主自供项入口按 hooks 那一行算出:名集 = 这一发请求体 hooks 里引擎点亮的事件下 http 条目 allowedEnvVars 之并 ∩ 宿主环境在场,值 = 环境原值,名集空 ⇒ 键缺席;不按凭据名预筛(凭据判官只在服务端:400 request.env_credential_refused)', whyUtilityLane: '无座:与 settings.hooks 同理由 —— side-channel 不带用户的 hook 表,就没有要插值的 http 头;带上它只会把宿主环境里的值交给一条零工具面的提交' },
32
33
  { field: 'settings.approvalFrameFamilies', lanes: ['interactive', 'print'], live: true, why: '这条运行的客户端渲得了哪些审批开卡帧族的**逐运行声明**(服务端提交体 `settings.approvalFrameFamilies`:词数组,值族闭集 tool_approval / approval_request;一条运行只在声明含服务端呈的那一族时才开审批卡,不含 ⇒ 问当场交无人值守政策口、不出卡)。两条用户车道都有审批腿(交互面出卡答人;`-p` 面交宿主的审批口),都得声明;🔴 只在能力读数 confirmed(受理位 `taskSettings.approvalFrameFamilies` 恒真 ∧ 值族位合格)时由装配口自己铸,老服务端(受理位缺席)对表外 settings 子键整条 400', whyUtilityLane: '无座:side-channel 强制零工具面(`excludeAllTools`),没有门控调用、不会问审批 ⇒ 声明没有对象;带上它只会在不认识这一键的老服务端上给这条提交多一种 400' },
33
34
  { field: 'settings.<resolved>', lanes: ['interactive', 'print'], live: true, why: 'settings resolver 的 effective 快照(hooks/env/model + 已解析权限投影)。两条车道同源:交互面 replEntry / print 面 printModeEngine 各跑一遍同一个 resolver,产物经同一个 buildWireSettingsStamp 投影。开放集(子键不可枚举)⇒ unregisteredRequestKeys 放行本车道 settings 的**表外**子键,但表内异车道子键仍点名', whyUtilityLane: '无座:这一位是**开放集 spread**(子键原样即 wire 键),摊开的是用户 settings 的已解析面(权限 / env / 模型)。side-channel 是壳自己的提交:摊上去既无用(零工具面没有工具门求值权限)又把用户的配置面带进了一条他没参与的提交。🔴 无座 ⇒ 本车道整只快照不产。🔴 **本行无座的前提由构造期校验兜住**:剥掉的是用户显式的 deny / ask,所以 `refuseUtilityWithoutToolUnload` 强制这条车道必须带字面 `excludeAllTools: true` —— 否则产出会是一条「既没卸工具、又没带用户 deny」的请求(比无人值守车道同一份输入更宽)' },
34
35
  { field: 'repo', lanes: ['interactive', 'print'], live: true, why: 'scan/code-review 场景的仓库坐标(passthrough;server 是权威校验方,本层不铸第二判官)', whyUtilityLane: '无座:场景键;side-channel 不走场景' },
@@ -217,6 +218,7 @@ const SETTINGS_KEY_ROUTES = {
217
218
  webSearch: row('settings.webSearch'),
218
219
  ultracode: row('settings.ultracode'),
219
220
  hooks: row('settings.hooks'),
221
+ env: row('settings.env'),
220
222
  approvalFrameFamilies: row('settings.approvalFrameFamilies'),
221
223
  outputStyle: { via: 'always' },
222
224
  };
@@ -520,27 +522,59 @@ export function refilterHostSettings(request, fresh, lane) {
520
522
  const base = tight.request;
521
523
  const tightened = tight.tightened;
522
524
  const settings = base.settings;
523
- if (!isPlainRecord(settings) || !Object.hasOwn(settings, 'hooks'))
525
+ if (!isPlainRecord(settings))
524
526
  return Object.freeze({ kind: 'send', request: base, hooksDropped: 0, tightened });
525
- const disposition = intake.dispositions['settings.hooks'];
526
- if (disposition === 'unwired')
527
- return Object.freeze({ kind: 'send', request: base, hooksDropped: 0, tightened });
528
- const now = intake.carried.hooks;
529
- const sentHooks = settings.hooks;
530
- if (!isPlainRecord(sentHooks))
531
- return Object.freeze({ kind: 'refuse', notice: refuseNotice() });
532
- const cut = intersectHostHooks(sentHooks, now);
533
- if (!cut.judged)
534
- return Object.freeze({ kind: 'refuse', notice: refuseNotice() });
535
- if (cut.dropped === 0)
527
+ const unjudged = () => Object.freeze({ kind: 'refuse', notice: refuseNotice() });
528
+ let nextSettings = settings;
529
+ let hooksDropped = 0;
530
+ let finalHooks;
531
+ if (Object.hasOwn(settings, 'hooks')) {
532
+ const sentHooks = settings.hooks;
533
+ if (intake.dispositions['settings.hooks'] === 'unwired')
534
+ finalHooks = sentHooks;
535
+ else {
536
+ const now = intake.carried.hooks;
537
+ if (!isPlainRecord(sentHooks))
538
+ return unjudged();
539
+ const cut = intersectHostHooks(sentHooks, now);
540
+ if (!cut.judged)
541
+ return unjudged();
542
+ finalHooks = cut.hooks;
543
+ if (cut.dropped > 0) {
544
+ const { hooks: _sentHooks, ...restSettings } = settings;
545
+ void _sentHooks;
546
+ nextSettings = cut.hooks === undefined ? restSettings : { ...restSettings, hooks: cut.hooks };
547
+ hooksDropped = cut.dropped;
548
+ }
549
+ }
550
+ }
551
+ if (Object.hasOwn(nextSettings, 'env')) {
552
+ const sentEnv = nextSettings.env;
553
+ if (!isPlainRecord(sentEnv))
554
+ return unjudged();
555
+ let names;
556
+ try {
557
+ names = hookEnvNamesOf(finalHooks);
558
+ }
559
+ catch {
560
+ return unjudged();
561
+ }
562
+ const nowEnv = intake.carried.env;
563
+ const envUnwired = intake.dispositions['settings.env'] === 'unwired';
564
+ const sentKeys = Object.keys(sentEnv);
565
+ const kept = sentKeys.filter((k) => names.includes(k) && (envUnwired || (nowEnv !== undefined && Object.hasOwn(nowEnv, k))));
566
+ if (kept.length !== sentKeys.length) {
567
+ const { env: _sentEnv, ...restSettings } = nextSettings;
568
+ void _sentEnv;
569
+ nextSettings = kept.length === 0 ? restSettings : { ...restSettings, env: Object.fromEntries(kept.map((k) => [k, sentEnv[k]])) };
570
+ }
571
+ }
572
+ if (nextSettings === settings)
536
573
  return Object.freeze({ kind: 'send', request: base, hooksDropped: 0, tightened });
537
- const { hooks: _sentHooks, ...restSettings } = settings;
538
- void _sentHooks;
539
- const nextSettings = cut.hooks === undefined ? restSettings : { ...restSettings, hooks: cut.hooks };
540
574
  const { settings: _sentSettings, ...restRequest } = base;
541
575
  void _sentSettings;
542
576
  const next = Object.keys(nextSettings).length > 0 ? { ...restRequest, settings: nextSettings } : restRequest;
543
- return Object.freeze({ kind: 'send', request: next, hooksDropped: cut.dropped, tightened });
577
+ return Object.freeze({ kind: 'send', request: next, hooksDropped, tightened });
544
578
  }
545
579
  export const MEMORY_CAPTURE_OFF = 'off';
546
580
  export function memoryCaptureDeclarationField(declared) {
@@ -924,6 +958,7 @@ export function assembleTaskRequest(input, laneOrIdentity) {
924
958
  hooks: intake.carried.hooks,
925
959
  outputStyle: intake.carried.outputStyle,
926
960
  approvalFrameFamilies: approvalFamilies,
961
+ env: intake.carried.env,
927
962
  };
928
963
  refuseBadMemoryCapture(memoryCaptureIn);
929
964
  refuseBadMaxCostUsd(maxCostUsdIn);
@@ -1080,6 +1115,7 @@ export function assembleTaskRequest(input, laneOrIdentity) {
1080
1115
  ...(onSetting('webSearch') ? { webSearch: s.webSearch } : {}),
1081
1116
  ...(onSetting('ultracode') ? { ultracode: s.ultracode } : {}),
1082
1117
  ...(onSetting('hooks') ? { hooks: s.hooks } : {}),
1118
+ ...(onSetting('env') ? { env: { ...s.env } } : {}),
1083
1119
  ...(s.outputStyle !== undefined ? { outputStyle: s.outputStyle } : {}),
1084
1120
  ...(onSetting('approvalFrameFamilies') ? { approvalFrameFamilies: [...(s.approvalFrameFamilies ?? [])] } : {}),
1085
1121
  };
@@ -1228,6 +1264,74 @@ export function thinkingTurnProjection(input) {
1228
1264
  return projectThinkingCore({ lane, latch, strength, floor, ultracodeStamped: seated && inPlay('settings.ultracode', ultracode) && ultracode === true });
1229
1265
  }
1230
1266
  export function applyLiveRequestDefaults(req, host) {
1267
+ return liveRequestDefaultsOf(req, host).request;
1268
+ }
1269
+ export function applyLiveRequestDefaultsWithNotices(req, host) {
1270
+ return liveRequestDefaultsOf(req, host);
1271
+ }
1272
+ const SELF_KNOWLEDGE_JOIN = '\n\n';
1273
+ const OUTPUT_STYLE_MAX_CHARS = 16384;
1274
+ function selfKnowledgeSeatOf(block, readBody) {
1275
+ if (typeof block !== 'string')
1276
+ return { kind: 'set', value: block };
1277
+ let body;
1278
+ const read = readBody();
1279
+ if (read !== undefined) {
1280
+ if (read.presence === 'unreadable')
1281
+ return { kind: 'set', value: block, notice: hostStyleNotAppliedNotice('unreadable', OUTPUT_STYLE_MAX_CHARS) };
1282
+ if (read.presence === 'present' && read.value !== undefined && read.value !== null) {
1283
+ if (typeof read.value !== 'string')
1284
+ return { kind: 'set', value: block, notice: hostStyleNotAppliedNotice('unreadable', OUTPUT_STYLE_MAX_CHARS) };
1285
+ if (read.value.trim() !== '')
1286
+ body = read.value;
1287
+ }
1288
+ }
1289
+ if (body === undefined)
1290
+ return { kind: 'set', value: block };
1291
+ let merged;
1292
+ let separable = false;
1293
+ if (block.trim() === '' || body === block || body.startsWith(block + SELF_KNOWLEDGE_JOIN)) {
1294
+ merged = body;
1295
+ }
1296
+ else if (block.endsWith(SELF_KNOWLEDGE_JOIN + body)) {
1297
+ merged = block;
1298
+ }
1299
+ else {
1300
+ merged = block + SELF_KNOWLEDGE_JOIN + body;
1301
+ separable = true;
1302
+ }
1303
+ if (merged.length <= OUTPUT_STYLE_MAX_CHARS)
1304
+ return { kind: 'set', value: merged };
1305
+ const notice = hostStyleNotAppliedNotice('oversize', OUTPUT_STYLE_MAX_CHARS);
1306
+ return separable && block.length <= OUTPUT_STYLE_MAX_CHARS ? { kind: 'set', value: block, notice } : { kind: 'omit', notice };
1307
+ }
1308
+ const styleBodyReadOf = (settings) => () => typeof settings === 'object' && settings !== null ? slotReadOf(settings, 'outputStyle') : undefined;
1309
+ const appendBodyReadOf = (req) => () => typeof req === 'object' && req !== null ? slotReadOf(req, 'appendSystemPrompt') : undefined;
1310
+ function settingsWithStyleSeat(settings, seat) {
1311
+ const next = {};
1312
+ const put = (key, value) => {
1313
+ Object.defineProperty(next, key, { value, writable: true, enumerable: true, configurable: true });
1314
+ };
1315
+ const src = Object(settings);
1316
+ let placed = false;
1317
+ for (const key of Reflect.ownKeys(src)) {
1318
+ const d = Object.getOwnPropertyDescriptor(src, key);
1319
+ if (d === undefined || d.enumerable !== true)
1320
+ continue;
1321
+ if (key === 'outputStyle') {
1322
+ if (seat.kind === 'set')
1323
+ put(key, seat.value);
1324
+ placed = true;
1325
+ continue;
1326
+ }
1327
+ put(key, src[key]);
1328
+ }
1329
+ if (!placed && seat.kind === 'set')
1330
+ put('outputStyle', seat.value);
1331
+ return Reflect.ownKeys(next).length > 0 ? next : undefined;
1332
+ }
1333
+ function liveRequestDefaultsOf(req, host) {
1334
+ const notices = [];
1231
1335
  const out = { ...req };
1232
1336
  if (out.cwd == null && host.cwd !== undefined)
1233
1337
  out.cwd = host.cwd;
@@ -1249,11 +1353,24 @@ export function applyLiveRequestDefaults(req, host) {
1249
1353
  }
1250
1354
  if (host.selfKnowledge !== undefined) {
1251
1355
  if (host.appendSystemPromptCapable) {
1252
- out.appendSystemPrompt = host.selfKnowledge.forAppend;
1356
+ const seat = selfKnowledgeSeatOf(host.selfKnowledge.forAppend, appendBodyReadOf(req));
1357
+ if (seat.notice !== undefined)
1358
+ appendOwnElement(notices, seat.notice);
1359
+ if (seat.kind === 'set')
1360
+ out.appendSystemPrompt = seat.value;
1361
+ else
1362
+ delete out.appendSystemPrompt;
1253
1363
  }
1254
1364
  else {
1255
1365
  const settings = (out.settings ?? {});
1256
- out.settings = { ...settings, outputStyle: host.selfKnowledge.forOutputStyle };
1366
+ const seat = selfKnowledgeSeatOf(host.selfKnowledge.forOutputStyle, styleBodyReadOf(settings));
1367
+ if (seat.notice !== undefined)
1368
+ appendOwnElement(notices, seat.notice);
1369
+ const next = settingsWithStyleSeat(settings, seat);
1370
+ if (next !== undefined)
1371
+ out.settings = next;
1372
+ else
1373
+ delete out.settings;
1257
1374
  }
1258
1375
  }
1259
1376
  if (out.outputStyle === undefined && host.outputStyleSeat !== undefined && outputStyleSeatAdmitted(host.outputStyleSeatReading)) {
@@ -1276,7 +1393,7 @@ export function applyLiveRequestDefaults(req, host) {
1276
1393
  delete out.sessionId;
1277
1394
  }
1278
1395
  refuseRequireExistingWithoutSession(out.requireExistingSession, out.sessionId, 'applyLiveRequestDefaults');
1279
- return out;
1396
+ return Object.freeze({ request: out, notices: Object.freeze(notices) });
1280
1397
  }
1281
1398
  export function unregisteredRequestKeys(req, lane) {
1282
1399
  const liveDefaults = liveDefaultKeyNames();
@@ -43,12 +43,10 @@ export interface ParkedResumeStartupDetail {
43
43
  code: string;
44
44
  cause: ParkedResumeStartupCause;
45
45
  taskId?: string;
46
- startupCause?: ResumeStartupCause | ResumeCauseCoreAhead;
46
+ startupCause?: ResumeStartupCause;
47
47
  resendable: false;
48
48
  denyStaysOpen: true;
49
49
  }
50
- declare const RESUME_CAUSE_CORE_AHEAD: readonly ["transcript_corrupt"];
51
- type ResumeCauseCoreAhead = Exclude<(typeof RESUME_CAUSE_CORE_AHEAD)[number], ResumeStartupCause>;
52
50
  export declare function parkedResumeStartupFromError(err: unknown, decision?: ParkedResumeStartupDecision): ParkedResumeStartupDetail | null;
53
51
  export declare function parkedResumeStartupContent(detail: ParkedResumeStartupDetail, lang?: UiLanguage): string;
54
52
  export interface CheckpointUnsupportedVersionDetail {
@@ -132,7 +132,6 @@ function parkedResumeStartupCauseWord(err) {
132
132
  function isResumeStartupCause(v) {
133
133
  return typeof v === 'string' && CORE_RESUME_STARTUP_CAUSES.includes(v);
134
134
  }
135
- const RESUME_CAUSE_CORE_AHEAD = Object.freeze(['transcript_corrupt']);
136
135
  const _startupCausePin = true;
137
136
  void _startupCausePin;
138
137
  export function parkedResumeStartupFromError(err, decision) {
@@ -349,3 +348,5 @@ export function refusedParkBlockedContent(taskId, lane = 'interactive', lang) {
349
348
  return renderMessage(msg('resume.refusal.park.blockedPrint', { run, cancel: `POST /v1/runs/${runId ?? '<run id>'}/cancel` }), lang);
350
349
  return renderMessage(msg('resume.refusal.park.blockedInteractive', { run }), lang);
351
350
  }
351
+ const _pinRefusedPark = [true, true, true];
352
+ void _pinRefusedPark;
@@ -1,3 +1,4 @@
1
+ import type { BrainStatusPhase } from '@sema-agent/sdk';
1
2
  import type { UiLanguage } from './env/uiLanguage.js';
2
3
  export type RetryStatus = {
3
4
  kind: 'stalled';
@@ -62,7 +63,7 @@ interface RetryStatusErrorPayload {
62
63
  } | null;
63
64
  }
64
65
  export declare const BRAIN_STATUS_PHASES: readonly ["rate_limited", "retrying", "reconnecting", "circuit_open", "recovered", "gave_up", "waiting_first_token"];
65
- export type BrainStatusPhase = (typeof BRAIN_STATUS_PHASES)[number];
66
+ export type { BrainStatusPhase };
66
67
  export type BrainRetryErrClass = 'connect_refused' | 'transport' | 'stall' | 'rate_limit' | 'server' | 'http' | 'output_cap';
67
68
  export interface BrainStatusPayload {
68
69
  phase: BrainStatusPhase | (string & {});
@@ -161,4 +162,3 @@ export interface ResultWayOut {
161
162
  }
162
163
  export declare function resultWayOutOf(frame: object | null | undefined): ResultWayOut | undefined;
163
164
  export declare function wayOutSentence(wayOut: ResultWayOut | null | undefined, lang?: UiLanguage): string | undefined;
164
- export {};
@@ -11,6 +11,8 @@ export const BRAIN_STATUS_PHASES = [
11
11
  'gave_up',
12
12
  'waiting_first_token',
13
13
  ];
14
+ const _brainStatusPhasePin = [true, true];
15
+ void _brainStatusPhasePin;
14
16
  export const BRAIN_STATUS_WAIT_SEGMENTS = Object.freeze(['response_headers', 'first_token']);
15
17
  void true;
16
18
  void true;