@sema-agent/client-core 0.95.0 → 0.97.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 (233) hide show
  1. package/CHANGELOG.md +269 -0
  2. package/README.md +61 -31
  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 -2
  8. package/dist/adapter/activeRunSelfHeal.js +32 -6
  9. package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
  10. package/dist/adapter/downstream/terminalToSdkResult.js +14 -11
  11. package/dist/adapter/runStream.js +30 -47
  12. package/dist/agentSession/backgroundView.js +2 -15
  13. package/dist/agentSession/engineAgentRegistryRead.js +5 -4
  14. package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
  15. package/dist/agentsWireCaps.d.ts +1 -1
  16. package/dist/agentsWireCaps.js +29 -12
  17. package/dist/approvalDecidedByCapability.d.ts +2 -0
  18. package/dist/approvalDecidedByCapability.js +0 -1
  19. package/dist/approvalsStreamLiveCapability.d.ts +2 -0
  20. package/dist/approvalsStreamLiveCapability.js +3 -2
  21. package/dist/attachmentSeatCapability.d.ts +2 -0
  22. package/dist/attachmentSeatCapability.js +0 -1
  23. package/dist/callerCwdCapability.d.ts +2 -4
  24. package/dist/callerCwdCapability.js +0 -7
  25. package/dist/centerWiringCapability.d.ts +2 -4
  26. package/dist/centerWiringCapability.js +4 -9
  27. package/dist/classifierVerdictWire.js +4 -16
  28. package/dist/clientSlice.js +1 -1
  29. package/dist/cloudConfigWireCaps.d.ts +4 -4
  30. package/dist/cloudConfigWireCaps.js +241 -85
  31. package/dist/coreValuePorts.d.ts +11 -7
  32. package/dist/coreValuePorts.js +5 -8
  33. package/dist/credentialProvenance.d.ts +28 -0
  34. package/dist/credentialProvenance.js +76 -0
  35. package/dist/decideFailureNote.js +3 -1
  36. package/dist/decideReceipt.js +7 -10
  37. package/dist/declared/supportFloorDeclared.js +3 -3
  38. package/dist/deviceExecutorManagementCapability.d.ts +2 -0
  39. package/dist/deviceExecutorManagementCapability.js +3 -2
  40. package/dist/displayUntrusted.d.ts +10 -3
  41. package/dist/displayUntrusted.js +371 -60
  42. package/dist/engineCapReader.d.ts +8 -2
  43. package/dist/engineCapReader.js +15 -7
  44. package/dist/engineCapsCache.d.ts +17 -3
  45. package/dist/engineCapsCache.js +268 -43
  46. package/dist/engineDirectory.d.ts +79 -0
  47. package/dist/engineDirectory.js +186 -0
  48. package/dist/engineErrorCodes.d.ts +17 -1
  49. package/dist/engineErrorCodes.js +46 -16
  50. package/dist/engineNoticeCodes.d.ts +17 -0
  51. package/dist/engineNoticeCodes.js +54 -1
  52. package/dist/executionLaneCapability.d.ts +2 -0
  53. package/dist/executionLaneCapability.js +3 -2
  54. package/dist/fileHistoryCaptureCapability.d.ts +16 -0
  55. package/dist/fileHistoryCaptureCapability.js +98 -2
  56. package/dist/fileHistoryLegNotice.js +4 -0
  57. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  58. package/dist/fleet/bgSubagentRow.js +67 -0
  59. package/dist/fleet/fleetLedger.d.ts +1 -0
  60. package/dist/fleet/fleetLedger.js +164 -126
  61. package/dist/fleet/fleetProjection.d.ts +1 -0
  62. package/dist/fleet/fleetProjection.js +10 -3
  63. package/dist/fleetTaskDesc.js +4 -17
  64. package/dist/gateOutcome.d.ts +12 -1
  65. package/dist/gateOutcome.js +56 -1
  66. package/dist/gateVocabulary.d.ts +2 -2
  67. package/dist/gateVocabulary.js +4 -3
  68. package/dist/generated/engineAskFaceTables.js +1 -1
  69. package/dist/generated/engineFactTables.d.ts +5 -3
  70. package/dist/generated/engineFactTables.js +17 -4
  71. package/dist/generated/engineNoticeTables.js +12 -3
  72. package/dist/generated/sdkFactTables.d.ts +2 -0
  73. package/dist/generated/sdkFactTables.js +7 -0
  74. package/dist/generated/settingsSchemaFns.d.ts +3 -0
  75. package/dist/generated/settingsSchemaFns.js +53 -0
  76. package/dist/generated/toolNameTables.d.ts +1 -1
  77. package/dist/generated/toolNameTables.js +1 -42
  78. package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
  79. package/dist/hitl/approvalEndingCause.d.ts +2 -0
  80. package/dist/hitl/approvalEndingCause.js +26 -21
  81. package/dist/hitl/approvalHolds.d.ts +16 -1
  82. package/dist/hitl/approvalHolds.js +52 -12
  83. package/dist/hitl/askGateWire.js +1 -0
  84. package/dist/hitl/askParkRowRouting.js +1 -1
  85. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  86. package/dist/hitl/automaticAnswerVerdict.js +13 -10
  87. package/dist/hitl/decisionConflict.js +4 -5
  88. package/dist/hitl/decisionRefusal.d.ts +8 -0
  89. package/dist/hitl/decisionRefusal.js +55 -14
  90. package/dist/hitl/frameRouter.d.ts +3 -1
  91. package/dist/hitl/frameRouter.js +58 -39
  92. package/dist/hitl/gateLedger.d.ts +0 -5
  93. package/dist/hitl/gateLedger.js +0 -21
  94. package/dist/hitl/hitlBridge.d.ts +6 -2
  95. package/dist/hitl/hitlBridge.js +46 -11
  96. package/dist/hitl/localAllowRule.d.ts +1 -0
  97. package/dist/hitl/localAllowRule.js +2 -2
  98. package/dist/hitl/noAllowCause.d.ts +2 -1
  99. package/dist/hitl/noAllowCause.js +3 -2
  100. package/dist/hitl/parkResolver.d.ts +1 -0
  101. package/dist/hitl/parkResolver.js +14 -56
  102. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  103. package/dist/hitl/parkRowBirthWait.js +2 -2
  104. package/dist/hitl/planReviewWire.d.ts +1 -0
  105. package/dist/hitl/planReviewWire.js +98 -20
  106. package/dist/hitl/replayedApproval.d.ts +3 -3
  107. package/dist/hitl/replayedApproval.js +21 -16
  108. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  109. package/dist/hitl/sessionPolicyDeliverable.js +17 -17
  110. package/dist/hitl/sessionPolicyWire.d.ts +2 -0
  111. package/dist/hitl/sessionPolicyWire.js +15 -3
  112. package/dist/hitl/standingRows.d.ts +19 -0
  113. package/dist/hitl/standingRows.js +148 -0
  114. package/dist/hitl/suspendedReopen.js +2 -1
  115. package/dist/hitl/toolApprovalWire.d.ts +22 -10
  116. package/dist/hitl/toolApprovalWire.js +286 -47
  117. package/dist/hookMatcherVerdict.d.ts +1 -9
  118. package/dist/hookMatcherVerdict.js +21 -61
  119. package/dist/hooksWireCaps.js +2 -2
  120. package/dist/hostCallbackGuard.d.ts +1 -0
  121. package/dist/hostCallbackGuard.js +6 -0
  122. package/dist/index.d.ts +26 -12
  123. package/dist/index.js +20 -10
  124. package/dist/liveModelCatalog.d.ts +13 -0
  125. package/dist/liveModelCatalog.js +56 -0
  126. package/dist/mcpProbeCapability.d.ts +2 -4
  127. package/dist/mcpProbeCapability.js +3 -8
  128. package/dist/mcpWireCaps.d.ts +1 -0
  129. package/dist/mcpWireCaps.js +4 -1
  130. package/dist/memoryComplianceCapability.d.ts +2 -4
  131. package/dist/memoryComplianceCapability.js +3 -8
  132. package/dist/memoryOriginCapability.d.ts +2 -4
  133. package/dist/memoryOriginCapability.js +3 -8
  134. package/dist/memorySpecWire.js +2 -2
  135. package/dist/modelIdentityResolvability.d.ts +2 -2
  136. package/dist/modelIdentityResolvability.js +14 -5
  137. package/dist/noticePresentation.d.ts +68 -0
  138. package/dist/noticePresentation.js +247 -0
  139. package/dist/outputStyleSeatCapability.d.ts +2 -1
  140. package/dist/outputStyleSeatCapability.js +0 -4
  141. package/dist/ownKey.d.ts +2 -0
  142. package/dist/ownKey.js +18 -0
  143. package/dist/peerFrames.js +13 -9
  144. package/dist/peerLaneCapability.d.ts +2 -0
  145. package/dist/peerLaneCapability.js +3 -2
  146. package/dist/permissionModesCapability.d.ts +2 -4
  147. package/dist/permissionModesCapability.js +0 -7
  148. package/dist/permissionRuleIssue.js +0 -3
  149. package/dist/permissionRulesWriteCapability.d.ts +2 -0
  150. package/dist/permissionRulesWriteCapability.js +3 -2
  151. package/dist/permissionsAllowGrantCapability.d.ts +2 -0
  152. package/dist/permissionsAllowGrantCapability.js +4 -2
  153. package/dist/permissionsDeclaration.d.ts +2 -0
  154. package/dist/permissionsDeclaration.js +72 -59
  155. package/dist/printPermissionOutcome.d.ts +12 -0
  156. package/dist/printPermissionOutcome.js +50 -0
  157. package/dist/printToolResultFrame.d.ts +1 -0
  158. package/dist/printToolResultFrame.js +5 -9
  159. package/dist/promptBlockedCopy.d.ts +5 -0
  160. package/dist/promptBlockedCopy.js +35 -0
  161. package/dist/protocolSegment.d.ts +9 -6
  162. package/dist/protocolSegment.js +31 -21
  163. package/dist/providerRejection.d.ts +4 -0
  164. package/dist/providerRejection.js +75 -14
  165. package/dist/replayBody.d.ts +12 -0
  166. package/dist/replayBody.js +25 -0
  167. package/dist/request/taskRequest.d.ts +1 -4
  168. package/dist/request/taskRequest.js +74 -19
  169. package/dist/resumeRefusalCopy.js +9 -25
  170. package/dist/retryStatus.d.ts +9 -1
  171. package/dist/retryStatus.js +9 -2
  172. package/dist/rewindArchiveCapability.d.ts +3 -13
  173. package/dist/rewindArchiveCapability.js +12 -58
  174. package/dist/rewindArchiveReading.d.ts +17 -0
  175. package/dist/rewindArchiveReading.js +55 -0
  176. package/dist/ruleCompileVerdict.d.ts +9 -1
  177. package/dist/ruleCompileVerdict.js +29 -4
  178. package/dist/runTerminal.d.ts +48 -5
  179. package/dist/runTerminal.js +215 -12
  180. package/dist/sandboxWire.js +13 -0
  181. package/dist/sdkWireTransit.d.ts +2 -1
  182. package/dist/sdkWireTransit.js +1 -0
  183. package/dist/sealedKeyCapability.d.ts +2 -4
  184. package/dist/sealedKeyCapability.js +0 -7
  185. package/dist/seam.js +4 -2
  186. package/dist/seatContract.d.ts +76 -11
  187. package/dist/seatContract.js +222 -27
  188. package/dist/sessionPolicyCapability.d.ts +2 -0
  189. package/dist/sessionPolicyCapability.js +3 -2
  190. package/dist/sessionReadRedactionCapability.d.ts +2 -4
  191. package/dist/sessionReadRedactionCapability.js +0 -7
  192. package/dist/sessionSyncFileHistory.d.ts +4 -0
  193. package/dist/sessionSyncFileHistory.js +66 -0
  194. package/dist/sessionSyncFileHistoryCapability.d.ts +2 -1
  195. package/dist/sessionSyncFileHistoryCapability.js +3 -5
  196. package/dist/skillToolListsCapability.d.ts +2 -1
  197. package/dist/skillToolListsCapability.js +3 -5
  198. package/dist/sqlEngineCapability.d.ts +2 -0
  199. package/dist/sqlEngineCapability.js +4 -3
  200. package/dist/steerPriorityCapability.d.ts +2 -1
  201. package/dist/steerPriorityCapability.js +3 -5
  202. package/dist/storePostureCapability.d.ts +2 -4
  203. package/dist/storePostureCapability.js +4 -9
  204. package/dist/subagent/engineSubagentSteer.js +7 -5
  205. package/dist/subagentContentStore.js +4 -15
  206. package/dist/supportFloor.d.ts +1 -0
  207. package/dist/supportFloor.js +13 -9
  208. package/dist/systemReminderTag.d.ts +1 -0
  209. package/dist/systemReminderTag.js +8 -0
  210. package/dist/toolHistoryBadTurn.js +3 -2
  211. package/dist/toolHistoryMismatch.d.ts +0 -3
  212. package/dist/toolHistoryMismatch.js +3 -7
  213. package/dist/toolResult.d.ts +12 -1
  214. package/dist/toolResult.js +55 -1
  215. package/dist/toolResultContent.d.ts +2 -0
  216. package/dist/toolResultContent.js +63 -0
  217. package/dist/usageAnalytics.js +40 -16
  218. package/dist/userInvokedSkillsCapability.d.ts +2 -1
  219. package/dist/userInvokedSkillsCapability.js +3 -5
  220. package/dist/webSearchBackendCapability.d.ts +2 -0
  221. package/dist/webSearchBackendCapability.js +3 -2
  222. package/dist/wireErrorTriage.d.ts +2 -0
  223. package/dist/wireErrorTriage.js +91 -38
  224. package/dist/wireFailureShape.d.ts +20 -3
  225. package/dist/wireFailureShape.js +128 -72
  226. package/dist/workflowsJournalCapability.d.ts +2 -0
  227. package/dist/workflowsJournalCapability.js +3 -2
  228. package/dist/writeProtectionCapability.d.ts +2 -0
  229. package/dist/writeProtectionCapability.js +3 -2
  230. package/docs/INTEGRATION-CLIENTS.md +1784 -20
  231. package/package.json +5 -5
  232. package/dist/engineRefusedToolName.d.ts +0 -1
  233. package/dist/engineRefusedToolName.js +0 -8
@@ -0,0 +1,15 @@
1
+ import type { FleetTaskRow } from '@sema-agent/sdk';
2
+ export declare const DURABLE_AGENT_HANDLE_RE: RegExp;
3
+ export declare function isAgentHandle(rowId: string): boolean;
4
+ export type NonAgentHandleKind = 'background_bash' | 'monitor';
5
+ export declare function nonAgentHandleKind(rowId: string): NonAgentHandleKind | null;
6
+ export type BgSubagentRowFacts = Pick<FleetTaskRow, 'id' | 'parentId' | 'sourceLane'>;
7
+ export declare function isBackgroundSubagentRow(row: BgSubagentRowFacts): boolean;
8
+ export declare function isBackgroundWorkRow(row: BgSubagentRowFacts): boolean;
9
+ export interface BgRowOwnership {
10
+ readonly scoped: boolean;
11
+ readonly isOwnRun: (taskIdTail: string) => boolean;
12
+ }
13
+ export declare function liveBgRowOwnership(): BgRowOwnership;
14
+ export declare function liveBgRowOwnershipFor(sessionKey: string): BgRowOwnership;
15
+ export declare function isOwnBackgroundSubagentRow(row: BgSubagentRowFacts, own: BgRowOwnership): boolean;
@@ -0,0 +1,67 @@
1
+ import { CORE_DURABLE_AGENT_HANDLE_RE, CORE_TASK_HANDLE_PREFIXES } from '../generated/engineFactTables.js';
2
+ import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
3
+ import { isOwnEngineRun } from '../subagentContentStore.js';
4
+ import { isWorkflowAgentTaskId, rowIdTail } from '../workflow.js';
5
+ import { isFleetSessionScopedFor } from './fleetLedger.js';
6
+ import { wireParentId } from './fleetProjection.js';
7
+ const _taskTypePins = [true, true];
8
+ void _taskTypePins;
9
+ export const DURABLE_AGENT_HANDLE_RE = CORE_DURABLE_AGENT_HANDLE_RE;
10
+ export function isAgentHandle(rowId) {
11
+ if (typeof rowId !== 'string' || rowId.length === 0)
12
+ return false;
13
+ if (rowIdTail(rowId) !== rowId)
14
+ return false;
15
+ return DURABLE_AGENT_HANDLE_RE.test(rowId) || isWorkflowAgentTaskId(rowId);
16
+ }
17
+ const NON_AGENT_HANDLE_TYPES = ['background_bash', 'monitor'];
18
+ export function nonAgentHandleKind(rowId) {
19
+ if (typeof rowId !== 'string')
20
+ return null;
21
+ const prefix = /^([a-z])[0-9a-f]{16}$/.exec(rowIdTail(rowId))?.[1];
22
+ if (prefix === undefined)
23
+ return null;
24
+ for (const type of NON_AGENT_HANDLE_TYPES)
25
+ if (CORE_TASK_HANDLE_PREFIXES[type] === prefix)
26
+ return type;
27
+ return null;
28
+ }
29
+ const RUN_LEG_LANE = 'run-leg';
30
+ function isForegroundDelegationRow(row) {
31
+ return rowIdTail(row.id) !== row.id || row.sourceLane === RUN_LEG_LANE;
32
+ }
33
+ function hasRowId(row) {
34
+ return typeof row?.id === 'string' && row.id.length > 0;
35
+ }
36
+ export function isBackgroundSubagentRow(row) {
37
+ if (!hasRowId(row))
38
+ return false;
39
+ if (isForegroundDelegationRow(row))
40
+ return false;
41
+ if (nonAgentHandleKind(row.id) !== null)
42
+ return false;
43
+ if (wireParentId(row) !== undefined)
44
+ return true;
45
+ return isAgentHandle(row.id);
46
+ }
47
+ export function isBackgroundWorkRow(row) {
48
+ if (isBackgroundSubagentRow(row))
49
+ return true;
50
+ if (!hasRowId(row))
51
+ return false;
52
+ return !isForegroundDelegationRow(row) && nonAgentHandleKind(row.id) !== null;
53
+ }
54
+ export function liveBgRowOwnership() {
55
+ return liveBgRowOwnershipFor(DEFAULT_SESSION_KEY);
56
+ }
57
+ export function liveBgRowOwnershipFor(sessionKey) {
58
+ return { scoped: isFleetSessionScopedFor(sessionKey), isOwnRun: isOwnEngineRun };
59
+ }
60
+ export function isOwnBackgroundSubagentRow(row, own) {
61
+ if (!isBackgroundSubagentRow(row))
62
+ return false;
63
+ if (own.scoped)
64
+ return true;
65
+ const parentId = wireParentId(row);
66
+ return own.isOwnRun(rowIdTail(row.id)) || (parentId !== undefined && own.isOwnRun(rowIdTail(parentId)));
67
+ }
@@ -6,6 +6,7 @@ export interface EngineActiveBgTask {
6
6
  name?: string;
7
7
  status: string;
8
8
  parentId?: string;
9
+ sourceLane?: string;
9
10
  retiredByNotification?: boolean;
10
11
  }
11
12
  export interface EngineActiveBgReading {
@@ -13,6 +13,10 @@ import { projectTasks, projectWorkflows, wireCycleSeq, wireParentId, } from './f
13
13
  import { isInStreamDrainingEnd } from '../wireErrorTriage.js';
14
14
  import { cycleSeqOrder, cycleSeqValue } from '../cycleOrder.js';
15
15
  export const TERMINAL_RETAIN_MS = 60_000;
16
+ function hasRowId(row) {
17
+ const id = row?.id;
18
+ return typeof id === 'string' && id.length > 0;
19
+ }
16
20
  const liveBgViews = new Map();
17
21
  function viewsFor(sessionKey) {
18
22
  return liveBgViews.get(sessionKey) ?? new Set();
@@ -95,21 +99,48 @@ export function createFleetLedger(hooks = {}, opts = {}) {
95
99
  const wfMap = new Map();
96
100
  const rowMeta = new Map();
97
101
  const retained = new Map();
98
- const cycleWatermark = new Map();
99
- const CYCLE_WATERMARK_MAX = 512;
100
- function raiseCycleWatermark(tail, gen) {
102
+ const tails = new Map();
103
+ const TAIL_RECORD_MAX = 512;
104
+ function touchTail(tail) {
105
+ const prior = tails.get(tail);
106
+ tails.delete(tail);
107
+ if (prior === undefined && tails.size >= TAIL_RECORD_MAX) {
108
+ const held = new Set();
109
+ for (const id of taskMap.keys())
110
+ held.add(rowIdTail(id));
111
+ for (const id of retained.keys())
112
+ held.add(rowIdTail(id));
113
+ for (const candidate of tails.keys()) {
114
+ if (held.has(candidate))
115
+ continue;
116
+ tails.delete(candidate);
117
+ break;
118
+ }
119
+ }
120
+ const rec = prior ?? { gen: undefined, settled: undefined };
121
+ tails.set(tail, rec);
122
+ return rec;
123
+ }
124
+ function raiseTailGen(tail, gen) {
101
125
  if (gen === undefined || tail.length === 0)
102
126
  return;
103
- const prior = cycleWatermark.get(tail);
127
+ const prior = tails.get(tail)?.gen;
104
128
  if (prior !== undefined && cycleSeqOrder(prior, gen) !== 'before')
105
129
  return;
106
- cycleWatermark.delete(tail);
107
- if (cycleWatermark.size >= CYCLE_WATERMARK_MAX) {
108
- const oldest = cycleWatermark.keys().next().value;
109
- if (oldest !== undefined)
110
- cycleWatermark.delete(oldest);
111
- }
112
- cycleWatermark.set(tail, gen);
130
+ touchTail(tail).gen = gen;
131
+ }
132
+ function isFormerGeneration(tail, gen) {
133
+ return cycleSeqOrder(gen, tails.get(tail)?.gen) === 'before';
134
+ }
135
+ function noteSettledTerminal(tail, row) {
136
+ if (tail.length === 0 || typeof row.status !== 'string')
137
+ return;
138
+ touchTail(tail).settled = { status: row.status, cycleSeq: wireCycleSeq(row) };
139
+ }
140
+ function withdrawSettledTerminal(tail) {
141
+ const rec = tails.get(tail);
142
+ if (rec !== undefined)
143
+ rec.settled = undefined;
113
144
  }
114
145
  let droppedMalformed = 0;
115
146
  let droppedUnknownFrame = 0;
@@ -140,28 +171,67 @@ export function createFleetLedger(hooks = {}, opts = {}) {
140
171
  ...(typeof r.name === 'string' && r.name.length > 0 ? { name: r.name } : {}),
141
172
  status: r.status ?? 'unknown',
142
173
  ...(parentId !== undefined ? { parentId } : {}),
174
+ ...(typeof r.sourceLane === 'string' && r.sourceLane.length > 0 ? { sourceLane: r.sourceLane } : {}),
143
175
  ...(retired ? { retiredByNotification: true } : {}),
144
176
  };
145
177
  };
178
+ function settleTerminalRow(row, tail, receivedAtMs) {
179
+ taskMap.delete(row.id);
180
+ rowMeta.delete(row.id);
181
+ for (const id of taskMap.keys()) {
182
+ if (rowIdTail(id) === tail) {
183
+ debug(`[fleet-frame] terminal row not retained: tail still in flight on an alias(row=${row.id} alias=${id})`);
184
+ return;
185
+ }
186
+ }
187
+ retained.set(row.id, { row, expireAt: receivedAtMs + TERMINAL_RETAIN_MS });
188
+ for (const id of [...retained.keys()]) {
189
+ if (id !== row.id && rowIdTail(id) === tail)
190
+ retained.delete(id);
191
+ }
192
+ noteSettledTerminal(tail, row);
193
+ }
194
+ function admitRow(row, receivedAtMs) {
195
+ const tail = rowIdTail(row.id);
196
+ const gen = wireCycleSeq(row);
197
+ if (isFormerGeneration(tail, gen)) {
198
+ debug(`[fleet-frame] former-generation row ignored(row=${row.id} row-cycle=${gen} tail-cycle=${tails.get(tail)?.gen})`);
199
+ return;
200
+ }
201
+ raiseTailGen(tail, gen);
202
+ if (gen !== undefined) {
203
+ for (const [id, alias] of [...taskMap]) {
204
+ if (id !== row.id && rowIdTail(id) === tail && cycleSeqOrder(wireCycleSeq(alias), gen) === 'before') {
205
+ taskMap.delete(id);
206
+ rowMeta.delete(id);
207
+ }
208
+ }
209
+ }
210
+ if (isSdkFleetTaskTerminal(row.status)) {
211
+ settleTerminalRow(row, tail, receivedAtMs);
212
+ return;
213
+ }
214
+ taskMap.set(row.id, row);
215
+ rowMeta.set(row.id, { receivedAtMs });
216
+ for (const id of [...retained.keys()]) {
217
+ if (rowIdTail(id) === tail)
218
+ retained.delete(id);
219
+ }
220
+ withdrawSettledTerminal(tail);
221
+ clearBgTerminalFacts(tail);
222
+ }
146
223
  function forgetSettledTerminalRowOf(id) {
147
- const live = taskMap.get(id);
148
- if (live !== undefined && !isSdkFleetTaskTerminal(live.status))
224
+ if (taskMap.has(id))
149
225
  return false;
150
226
  const pooled = retained.get(id);
151
- if (pooled?.retiredByNotification === true)
227
+ if (pooled === undefined || pooled.retiredByNotification === true)
152
228
  return false;
153
- if (live === undefined && pooled === undefined)
154
- return false;
155
- taskMap.delete(id);
156
- rowMeta.delete(id);
157
229
  retained.delete(id);
158
230
  return true;
159
231
  }
160
232
  const bgView = {
161
233
  read: () => {
162
- const rows = [...taskMap.values()]
163
- .filter(r => !isSdkFleetTaskTerminal(r.status))
164
- .map(r => toBgTask(r, false));
234
+ const rows = [...taskMap.values()].map(r => toBgTask(r, false));
165
235
  const nowMs = nowFn();
166
236
  for (const [id, r] of retained) {
167
237
  if (r.retiredByNotification !== true)
@@ -200,37 +270,49 @@ export function createFleetLedger(hooks = {}, opts = {}) {
200
270
  break;
201
271
  }
202
272
  case 'snapshot': {
203
- taskMap.clear();
204
- wfMap.clear();
205
- rowMeta.clear();
206
273
  const receivedAtMs = nowFn();
274
+ const rows = [];
207
275
  for (const row of frame.tasks) {
208
- taskMap.set(row.id, row);
209
- rowMeta.set(row.id, { receivedAtMs });
210
- if (!isSdkFleetTaskTerminal(row.status)) {
211
- const tail = rowIdTail(row.id);
212
- for (const id of [...retained.keys()]) {
213
- if (rowIdTail(id) === tail)
214
- retained.delete(id);
215
- }
216
- clearBgTerminalFacts(tail);
276
+ if (!hasRowId(row)) {
277
+ droppedMalformed++;
278
+ debug('[fleet-frame] MALFORMED snapshot task row dropped(row 或 row.id 缺席 / 非串)');
279
+ continue;
217
280
  }
281
+ rows.push(row);
282
+ }
283
+ const keepTails = new Set();
284
+ const currentTails = new Set();
285
+ for (const row of rows) {
286
+ const tail = rowIdTail(row.id);
287
+ if (isFormerGeneration(tail, wireCycleSeq(row)))
288
+ keepTails.add(tail);
289
+ else
290
+ currentTails.add(tail);
291
+ }
292
+ for (const tail of currentTails)
293
+ keepTails.delete(tail);
294
+ for (const id of [...taskMap.keys()]) {
295
+ if (keepTails.has(rowIdTail(id)))
296
+ continue;
297
+ taskMap.delete(id);
298
+ rowMeta.delete(id);
218
299
  }
300
+ wfMap.clear();
301
+ for (const row of rows)
302
+ admitRow(row, receivedAtMs);
219
303
  for (const row of frame.workflows)
220
304
  wfMap.set(row.id, row);
221
305
  break;
222
306
  }
223
307
  case 'task': {
224
308
  const row = frame.row;
225
- if (!row?.id) {
309
+ if (!hasRowId(row)) {
226
310
  droppedMalformed++;
227
- debug('[fleet-frame] MALFORMED task frame dropped(row 或 row.id 缺席)');
311
+ debug('[fleet-frame] MALFORMED task frame dropped(row 或 row.id 缺席 / 非串)');
228
312
  break;
229
313
  }
230
314
  const receivedAtMs = nowFn();
231
- taskMap.set(row.id, row);
232
- raiseCycleWatermark(rowIdTail(row.id), wireCycleSeq(row));
233
- rowMeta.set(row.id, { receivedAtMs });
315
+ admitRow(row, receivedAtMs);
234
316
  debug(`[fleet-row] id=${row.id} parent=${row.parentId ?? '-'} agentType=${row.agentType ?? '-'}` +
235
317
  ` agentName=${row.agentName ?? '-'} name=${row.name ?? '-'} status=${row.status ?? '-'}` +
236
318
  ` tokens=${row.tokens ?? '-'} parentToolCallId=${row.parentToolCallId ?? '-'}`);
@@ -252,29 +334,13 @@ export function createFleetLedger(hooks = {}, opts = {}) {
252
334
  recordEngineTranscriptId(rowIdTail(row.id), row.transcriptId);
253
335
  }
254
336
  recordFleetRowAgentType(rowIdTail(row.id), row.agentType);
255
- if (isSdkFleetTaskTerminal(row.status)) {
256
- retained.set(row.id, { row, expireAt: receivedAtMs + TERMINAL_RETAIN_MS });
257
- const tailT = rowIdTail(row.id);
258
- for (const id of [...retained.keys()]) {
259
- if (id !== row.id && rowIdTail(id) === tailT)
260
- retained.delete(id);
261
- }
262
- }
263
- else {
264
- retained.delete(row.id);
265
- const tail = rowIdTail(row.id);
266
- for (const id of [...retained.keys()]) {
267
- if (id !== row.id && rowIdTail(id) === tail)
268
- retained.delete(id);
269
- }
270
- clearBgTerminalFacts(tail);
271
- }
272
337
  break;
273
338
  }
274
339
  case 'task_remove': {
275
340
  const fr = frame;
276
341
  const removedGen = cycleSeqValue(fr.cycleSeq);
277
- const held = taskMap.get(frame.id);
342
+ const pooledHeld = retained.get(frame.id);
343
+ const held = taskMap.get(frame.id) ?? (pooledHeld !== undefined && pooledHeld.retiredByNotification !== true ? pooledHeld.row : undefined);
278
344
  const heldGen = held !== undefined ? wireCycleSeq(held) : undefined;
279
345
  const stale = cycleSeqOrder(removedGen, heldGen) === 'before';
280
346
  const reason = typeof fr.removeReason === 'string' && fr.removeReason.length > 0 ? fr.removeReason : undefined;
@@ -391,41 +457,16 @@ export function createFleetLedger(hooks = {}, opts = {}) {
391
457
  const writtenIds = new Set();
392
458
  let applied = false;
393
459
  let washBlocked = false;
394
- let staleBlocked = false;
395
460
  const notifSeq = cycleSeqValue(n.seq);
396
- {
397
- const mark = cycleWatermark.get(n.taskId);
398
- if (cycleSeqOrder(notifSeq, mark) === 'before') {
399
- staleBlocked = true;
400
- debug(`[fleet-frame] bg_notification stale-cycle ignored(watermark=${mark} notif-seq=${notifSeq})`);
401
- }
461
+ const staleBlocked = isFormerGeneration(notifTail, notifSeq);
462
+ if (staleBlocked) {
463
+ debug(`[fleet-frame] bg_notification stale-cycle ignored(tail-cycle=${tails.get(notifTail)?.gen} notif-seq=${notifSeq})`);
402
464
  }
403
- for (const id of rowIds) {
404
- const known = taskMap.get(id);
405
- if (!known)
406
- continue;
407
- const heldGen = wireCycleSeq(known);
408
- if (cycleSeqOrder(notifSeq, heldGen) === 'before') {
409
- staleBlocked = true;
410
- debug(`[fleet-frame] bg_notification stale-cycle ignored(row=${id} row-cycle=${heldGen} notif-seq=${notifSeq})`);
411
- continue;
412
- }
413
- const rowStatus = known.status ?? '';
414
- if (isSdkFleetTaskTerminal(rowStatus)) {
415
- if (isWashGreen(rowStatus, n.status)) {
416
- washBlocked = true;
417
- debug(`[fleet-frame] bg_notification WASH-GREEN blocked(row=${id} row-status=${rowStatus} notif=${n.status})`);
465
+ if (!staleBlocked) {
466
+ for (const id of rowIds) {
467
+ const known = taskMap.get(id);
468
+ if (!known)
418
469
  continue;
419
- }
420
- if (rowStatus !== n.status) {
421
- const upgraded = { ...known, status: coerced };
422
- retained.set(id, { row: upgraded, expireAt: nowMs + TERMINAL_RETAIN_MS });
423
- taskMap.set(id, upgraded);
424
- }
425
- writtenIds.add(id);
426
- applied = true;
427
- }
428
- else {
429
470
  const started = known.startedAt;
430
471
  const meta = rowMeta.get(id);
431
472
  const frozenElapsed = typeof started === 'number' && started > 0 && started <= nowMs
@@ -447,51 +488,48 @@ export function createFleetLedger(hooks = {}, opts = {}) {
447
488
  writtenIds.add(id);
448
489
  applied = true;
449
490
  }
450
- }
451
- for (const [id, entry] of retained) {
452
- if (writtenIds.has(id))
453
- continue;
454
- if (rowIdTail(id) !== notifTail)
455
- continue;
456
- const retainedGen = wireCycleSeq(entry.row);
457
- if (cycleSeqOrder(notifSeq, retainedGen) === 'before') {
458
- staleBlocked = true;
459
- debug(`[fleet-frame] bg_notification stale-cycle ignored(retained=${id} row-cycle=${retainedGen} notif-seq=${notifSeq})`);
460
- continue;
461
- }
462
- const prior = entry.row.status ?? '';
463
- if (prior === n.status) {
491
+ for (const [id, entry] of retained) {
492
+ if (writtenIds.has(id))
493
+ continue;
494
+ if (rowIdTail(id) !== notifTail)
495
+ continue;
496
+ const prior = entry.row.status ?? '';
497
+ if (prior === n.status) {
498
+ applied = true;
499
+ continue;
500
+ }
501
+ if (isWashGreen(prior, n.status)) {
502
+ washBlocked = true;
503
+ debug(`[fleet-frame] bg_notification WASH-GREEN blocked(retained=${id} prior=${prior} notif=${n.status})`);
504
+ continue;
505
+ }
506
+ retained.set(id, {
507
+ row: { ...entry.row, status: coerced },
508
+ expireAt: nowMs + TERMINAL_RETAIN_MS,
509
+ ...(entry.retiredByNotification === true ? { retiredByNotification: true } : {}),
510
+ });
464
511
  applied = true;
465
- continue;
466
512
  }
467
- if (isWashGreen(prior, n.status)) {
468
- washBlocked = true;
469
- debug(`[fleet-frame] bg_notification WASH-GREEN blocked(retained=${id} prior=${prior} notif=${n.status})`);
470
- continue;
471
- }
472
- retained.set(id, {
473
- row: { ...entry.row, status: coerced },
474
- expireAt: nowMs + TERMINAL_RETAIN_MS,
475
- ...(entry.retiredByNotification === true ? { retiredByNotification: true } : {}),
476
- });
477
- applied = true;
478
513
  }
479
514
  const factsAccepted = !staleBlocked &&
480
515
  (applied ||
481
516
  (!washBlocked &&
482
517
  (() => {
483
- const prior = getBgTerminalFacts(n.taskId);
484
- if (prior === undefined)
485
- return true;
486
- const order = cycleSeqOrder(notifSeq, prior.cycleSeq);
487
- if (order === 'before')
488
- return false;
489
- if (order === 'after')
490
- return true;
491
- return !isWashGreen(prior.status, n.status);
518
+ for (const prior of [getBgTerminalFacts(n.taskId), tails.get(notifTail)?.settled]) {
519
+ if (prior === undefined)
520
+ continue;
521
+ const order = cycleSeqOrder(notifSeq, prior.cycleSeq);
522
+ if (order === 'before')
523
+ return false;
524
+ if (order === 'after')
525
+ continue;
526
+ if (isWashGreen(prior.status, n.status))
527
+ return false;
528
+ }
529
+ return true;
492
530
  })()));
493
531
  if (factsAccepted)
494
- raiseCycleWatermark(n.taskId, notifSeq);
532
+ raiseTailGen(notifTail, notifSeq);
495
533
  if (factsAccepted) {
496
534
  recordBgTerminalFacts(n.taskId, {
497
535
  status: n.status,
@@ -525,8 +563,6 @@ export function createFleetLedger(hooks = {}, opts = {}) {
525
563
  function project(nowMs, opts) {
526
564
  const viewingTaskId = opts.viewingTaskId;
527
565
  const liveRows = [...taskMap.values()].map(r => {
528
- if (isSdkFleetTaskTerminal(r.status))
529
- return r;
530
566
  const started = r.startedAt;
531
567
  if (typeof started === 'number' && started > 0 && started <= nowMs) {
532
568
  return { ...r, elapsedMs: nowMs - started };
@@ -620,6 +656,8 @@ export function createFleetLedger(hooks = {}, opts = {}) {
620
656
  wfMap.clear();
621
657
  rowMeta.clear();
622
658
  retained.clear();
659
+ for (const rec of tails.values())
660
+ rec.settled = undefined;
623
661
  contentAnchorSet = false;
624
662
  contentAnchor = undefined;
625
663
  debug(`[fleet-frame] 会话锚变更(${from ?? '-'} → ${to ?? '-'})⇒ 清上一会话的行/留存` +
@@ -30,6 +30,7 @@ export interface FleetTaskView {
30
30
  }>;
31
31
  cycleSeq?: number;
32
32
  retiredBy?: string;
33
+ workspaceSnapshot?: 'failed';
33
34
  }
34
35
  export interface FleetRowUsage {
35
36
  totalTokens?: number;
@@ -132,6 +132,9 @@ function wireRetiredBy(r) {
132
132
  const v = r.retiredBy;
133
133
  return typeof v === 'string' && v.length > 0 ? v : undefined;
134
134
  }
135
+ function wireWorkspaceSnapshot(r) {
136
+ return r.workspaceSnapshot === 'failed' ? 'failed' : undefined;
137
+ }
135
138
  export function wireResumable(r) {
136
139
  return typeof r.resumable === 'boolean' ? r.resumable : undefined;
137
140
  }
@@ -167,6 +170,7 @@ export function projectTasks(allRows, opts) {
167
170
  const editedFiles = wireEditedFiles(r);
168
171
  const cycleSeq = wireCycleSeq(r);
169
172
  const retiredBy = wireRetiredBy(r);
173
+ const workspaceSnapshot = wireWorkspaceSnapshot(r);
170
174
  const task = {
171
175
  id: r.id,
172
176
  name: deriveAgentLabel(r.agentType, r.agentName, r.name, r.id),
@@ -191,6 +195,7 @@ export function projectTasks(allRows, opts) {
191
195
  ...(editedFiles !== undefined ? { editedFiles } : {}),
192
196
  ...(cycleSeq !== undefined ? { cycleSeq } : {}),
193
197
  ...(retiredBy !== undefined ? { retiredBy } : {}),
198
+ ...(workspaceSnapshot !== undefined ? { workspaceSnapshot } : {}),
194
199
  };
195
200
  return task;
196
201
  });
@@ -245,6 +250,7 @@ const FLEET_TASK_VIEW_KEY_TUPLE = [
245
250
  'editedFiles',
246
251
  'cycleSeq',
247
252
  'retiredBy',
253
+ 'workspaceSnapshot',
248
254
  ];
249
255
  export const FLEET_TASK_VIEW_KEYS = FLEET_TASK_VIEW_KEY_TUPLE;
250
256
  const FLEET_WORKFLOW_VIEW_KEY_TUPLE = [
@@ -286,6 +292,7 @@ const FLEET_TASK_ROW_WIRE_KEY_TUPLE = [
286
292
  'editedFiles',
287
293
  'cycleSeq',
288
294
  'retiredBy',
295
+ 'workspaceSnapshot',
289
296
  ];
290
297
  export const FLEET_TASK_ROW_WIRE_KEYS = FLEET_TASK_ROW_WIRE_KEY_TUPLE;
291
298
  const FLEET_WORKFLOW_ROW_WIRE_KEY_TUPLE = [
@@ -305,9 +312,9 @@ export const FLEET_TASK_ROW_KEYS_NOT_PROJECTED = {
305
312
  sourceLane: {
306
313
  kind: 'by-design',
307
314
  owner: 'client-core 规范重构轮',
308
- reason: 'SDK 3.0.0 新键([2070]① 让位半场:前台 delegation 复合 id 行带 "run-leg" 标)。两仓现零消费面 ——' +
309
- '#95 纪律:没人读的键不盲投。已知潜在消费方=壳 wf-panel 的双生行过滤(现走 taskId 台账补偿),' +
310
- '若迁到本键判别则届时投影并删本条(那是行为改动,单独批)。',
315
+ reason: 'SDK 3.0.0 新键([2070]① 让位半场:前台 delegation 复合 id 行带 "run-leg" 标)。**渲染视图**(FleetTaskView)不投 —— 渲染面没有按车道分支的需求,' +
316
+ '#95 纪律:没人读的键不盲投。🆕 0.96.0 CC-643 起它有了消费者,但住在另一张读面:在飞 bg 读面行(EngineActiveBgTask)投了它,' +
317
+ '「这一行是不是后台子代」的单一判定口 isBackgroundSubagentRow 读它(见 fleet/bgSubagentRow.ts);视图不投的理由不变,不是第二份真源。',
311
318
  },
312
319
  agentType: {
313
320
  kind: 'by-design',
@@ -1,25 +1,12 @@
1
- import { applyDisplayFace, LEGACY_ESCAPE_FACE, LEGACY_LABEL_FACE } from './displayUntrusted.js';
1
+ import { applyDisplayFace, ESCAPE_FACE, LABEL_FACE, paintAndCap } from './displayUntrusted.js';
2
2
  export function escapeDisplayControlChars(s) {
3
- return applyDisplayFace(s, LEGACY_ESCAPE_FACE);
3
+ return applyDisplayFace(s, ESCAPE_FACE);
4
4
  }
5
5
  export function capForDisplay(raw, max) {
6
- const escaped = escapeDisplayControlChars(raw);
7
- if (escaped.length <= max)
8
- return escaped;
9
- let cut = max;
10
- const tokenStart = escaped.lastIndexOf('\\', cut - 1);
11
- if (tokenStart >= 0 && tokenStart + 6 > cut && /^\\u[0-9A-F]{4}$/.test(escaped.slice(tokenStart, tokenStart + 6))) {
12
- cut = tokenStart;
13
- }
14
- if (cut > 0) {
15
- const code = escaped.charCodeAt(cut - 1);
16
- if (code >= 0xd800 && code <= 0xdbff)
17
- cut -= 1;
18
- }
19
- return cut > 0 ? escaped.slice(0, cut) : '';
6
+ return paintAndCap(raw, ESCAPE_FACE, typeof max === 'number' && max > 0 ? max : 0);
20
7
  }
21
8
  export function collapseLabel(s) {
22
- return applyDisplayFace(s, LEGACY_LABEL_FACE);
9
+ return applyDisplayFace(s, LABEL_FACE);
23
10
  }
24
11
  export function taskDescFromName(name, agentType, agentName) {
25
12
  if (!name || !agentType)
@@ -32,9 +32,20 @@ export interface GateModeReleaseView {
32
32
  mandate?: string;
33
33
  reason?: string;
34
34
  }
35
- export declare const GATE_MODE_RELEASE_REASON_WORDS: readonly ["rule_unreadable", "write_protection_unresolved"];
35
+ export declare const GATE_MODE_RELEASE_REASON_WORDS: readonly ["rule_unreadable", "target_unresolved"];
36
36
  export type GateModeReleaseReasonWord = (typeof CORE_MODE_RELEASE_REASONS)[number];
37
37
  export declare function isGateModeReleaseReasonWord(v: unknown): v is GateModeReleaseReasonWord;
38
+ export declare function modeReleaseReasonSentence(reason: string | null | undefined): string | undefined;
39
+ export interface ReleaseDisclosureIdentity {
40
+ readonly toolCallId?: string;
41
+ readonly callKey?: string;
42
+ readonly epoch?: string | number;
43
+ }
44
+ export interface ReleaseDisclosureLedger {
45
+ readonly has: (identity: ReleaseDisclosureIdentity | null | undefined) => boolean;
46
+ readonly mark: (identity: ReleaseDisclosureIdentity | null | undefined) => void;
47
+ }
48
+ export declare function createReleaseDisclosureLedger(): ReleaseDisclosureLedger;
38
49
  export interface SettlementWhoView {
39
50
  party: string;
40
51
  approver?: string;