@sema-agent/client-core 0.93.0 → 0.94.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 (156) hide show
  1. package/CHANGELOG.md +261 -0
  2. package/README.md +31 -18
  3. package/dist/adapt/arms.js +8 -5
  4. package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
  5. package/dist/agentSession/engineSessionBackgroundStop.js +2 -1
  6. package/dist/agentsWireCaps.d.ts +15 -0
  7. package/dist/agentsWireCaps.js +111 -1
  8. package/dist/approvalReachWire.d.ts +18 -0
  9. package/dist/approvalReachWire.js +58 -0
  10. package/dist/approvalsStreamLiveCapability.js +16 -11
  11. package/dist/callerCwdCapability.d.ts +16 -0
  12. package/dist/callerCwdCapability.js +47 -0
  13. package/dist/controlRouter.js +3 -10
  14. package/dist/coreValuePorts.d.ts +64 -1
  15. package/dist/coreValuePorts.js +30 -0
  16. package/dist/detachWire.d.ts +1 -4
  17. package/dist/detachWire.js +1 -1
  18. package/dist/deviceExecutorManagementCapability.js +39 -34
  19. package/dist/deviceFlowPolling.d.ts +5 -0
  20. package/dist/deviceFlowPolling.js +28 -0
  21. package/dist/displayUntrusted.js +652 -21
  22. package/dist/engineErrorCodes.d.ts +5 -1
  23. package/dist/engineErrorCodes.js +9 -12
  24. package/dist/engineNoticeCodes.d.ts +22 -2
  25. package/dist/engineNoticeCodes.js +73 -6
  26. package/dist/engineRefusedToolName.d.ts +1 -0
  27. package/dist/engineRefusedToolName.js +8 -0
  28. package/dist/executionLaneCapability.js +14 -9
  29. package/dist/fileHistoryCaptureCapability.js +14 -9
  30. package/dist/fileHistoryLegNotice.d.ts +11 -0
  31. package/dist/fileHistoryLegNotice.js +50 -13
  32. package/dist/fleet/fleetLedger.js +5 -0
  33. package/dist/gateOutcome.d.ts +2 -1
  34. package/dist/gateOutcome.js +3 -0
  35. package/dist/gateVocabulary.js +1 -1
  36. package/dist/generated/engineAskFaceTables.d.ts +3 -0
  37. package/dist/generated/engineAskFaceTables.js +12 -0
  38. package/dist/generated/engineFactTables.d.ts +4 -2
  39. package/dist/generated/engineFactTables.js +13 -0
  40. package/dist/generated/engineNoticeTables.d.ts +5 -0
  41. package/dist/generated/engineNoticeTables.js +7 -0
  42. package/dist/generated/sdkFactTables.d.ts +3 -0
  43. package/dist/generated/sdkFactTables.js +17 -0
  44. package/dist/generated/settingsSchemaTables.d.ts +3 -0
  45. package/dist/generated/settingsSchemaTables.js +3 -0
  46. package/dist/headlessPermissionModeWire.d.ts +2 -2
  47. package/dist/headlessPermissionModeWire.js +11 -21
  48. package/dist/hitl/approvalHolds.d.ts +36 -0
  49. package/dist/hitl/approvalHolds.js +89 -0
  50. package/dist/hitl/approvalOutcomeNote.js +2 -1
  51. package/dist/hitl/approvalResolution.d.ts +3 -2
  52. package/dist/hitl/approvalResolution.js +21 -0
  53. package/dist/hitl/approvalsFeed.js +5 -0
  54. package/dist/hitl/askGateWire.js +3 -0
  55. package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
  56. package/dist/hitl/automaticAnswerVerdict.js +69 -21
  57. package/dist/hitl/decisionRefusal.d.ts +19 -0
  58. package/dist/hitl/decisionRefusal.js +63 -0
  59. package/dist/hitl/frameRouter.d.ts +10 -0
  60. package/dist/hitl/frameRouter.js +59 -3
  61. package/dist/hitl/gateLedger.d.ts +3 -0
  62. package/dist/hitl/gateLedger.js +17 -0
  63. package/dist/hitl/hitlBridge.d.ts +2 -2
  64. package/dist/hitl/hitlBridge.js +8 -10
  65. package/dist/hitl/hitlHostSurface.d.ts +6 -0
  66. package/dist/hitl/hitlHostSurface.js +25 -4
  67. package/dist/hitl/localAllowRule.js +2 -1
  68. package/dist/hitl/noAllowCause.d.ts +9 -0
  69. package/dist/hitl/noAllowCause.js +26 -0
  70. package/dist/hitl/parkResolver.js +6 -3
  71. package/dist/hitl/parkRowBirthWait.js +2 -1
  72. package/dist/hitl/persistedRulesWire.d.ts +6 -1
  73. package/dist/hitl/persistedRulesWire.js +12 -4
  74. package/dist/hitl/planReviewWire.d.ts +0 -1
  75. package/dist/hitl/planReviewWire.js +30 -9
  76. package/dist/hitl/sessionPolicyDeliverable.d.ts +1 -1
  77. package/dist/hitl/sessionPolicyDeliverable.js +3 -8
  78. package/dist/hitl/sessionPolicyWire.js +1 -1
  79. package/dist/hitl/toolApprovalWire.d.ts +37 -2
  80. package/dist/hitl/toolApprovalWire.js +392 -13
  81. package/dist/humanTurnRead.d.ts +15 -1
  82. package/dist/humanTurnRead.js +28 -2
  83. package/dist/index.d.ts +18 -6
  84. package/dist/index.js +14 -5
  85. package/dist/limitsWire.d.ts +0 -1
  86. package/dist/limitsWire.js +2 -10
  87. package/dist/liveModelCatalog.d.ts +14 -0
  88. package/dist/liveModelCatalog.js +61 -0
  89. package/dist/mcpProbeCapability.js +14 -9
  90. package/dist/mcpReconnect.js +13 -8
  91. package/dist/memoryComplianceCapability.js +15 -10
  92. package/dist/memoryOriginCapability.js +15 -10
  93. package/dist/modelIdentityResolvability.d.ts +4 -2
  94. package/dist/modelIdentityResolvability.js +31 -4
  95. package/dist/outputStyleSeatCapability.d.ts +16 -0
  96. package/dist/outputStyleSeatCapability.js +47 -0
  97. package/dist/ownKey.d.ts +1 -0
  98. package/dist/ownKey.js +10 -0
  99. package/dist/peerLaneCapability.js +16 -11
  100. package/dist/permissionRuleIssue.js +1 -1
  101. package/dist/permissionRulesWriteCapability.js +16 -11
  102. package/dist/permissionsAllowGrantCapability.d.ts +2 -0
  103. package/dist/permissionsAllowGrantCapability.js +38 -16
  104. package/dist/permissionsDeclaration.d.ts +10 -1
  105. package/dist/permissionsDeclaration.js +97 -15
  106. package/dist/protocolSegment.d.ts +1 -0
  107. package/dist/protocolSegment.js +13 -1
  108. package/dist/request/taskRequest.d.ts +11 -3
  109. package/dist/request/taskRequest.js +13 -1
  110. package/dist/resultFrameKeys.d.ts +4 -0
  111. package/dist/resultFrameKeys.js +13 -0
  112. package/dist/resumeRefusalCopy.js +6 -16
  113. package/dist/retryStatus.js +6 -4
  114. package/dist/rewindArchiveCapability.js +13 -8
  115. package/dist/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
  116. package/dist/runCancelContext.js +2 -1
  117. package/dist/sealedKeyCapability.js +19 -14
  118. package/dist/seatContract.d.ts +33 -5
  119. package/dist/seatContract.js +143 -2
  120. package/dist/sessionPolicyCapability.js +15 -10
  121. package/dist/sessionReadRedactionCapability.d.ts +16 -0
  122. package/dist/sessionReadRedactionCapability.js +47 -0
  123. package/dist/sessionSyncFileHistoryCapability.js +14 -9
  124. package/dist/skillToolListsCapability.js +14 -9
  125. package/dist/sqlEngineCapability.js +18 -13
  126. package/dist/steerPriorityCapability.js +21 -16
  127. package/dist/subagent/agentStateDetail.d.ts +1 -0
  128. package/dist/subagent/agentStateDetail.js +41 -0
  129. package/dist/subagent/engineCompactWire.d.ts +15 -0
  130. package/dist/subagent/engineCompactWire.js +75 -13
  131. package/dist/supportFloor.js +1 -1
  132. package/dist/taskRequestWords.d.ts +2 -4
  133. package/dist/taskRequestWords.js +3 -2
  134. package/dist/types/engineState.d.ts +1 -1
  135. package/dist/userAttachmentEnvelope.d.ts +22 -1
  136. package/dist/userAttachmentEnvelope.js +90 -2
  137. package/dist/userInvokedSkillsCapability.js +14 -9
  138. package/dist/webSearchBackendCapability.js +21 -16
  139. package/dist/wireErrorTriage.d.ts +11 -0
  140. package/dist/wireErrorTriage.js +35 -0
  141. package/dist/wireFailureShape.d.ts +6 -0
  142. package/dist/wireFailureShape.js +30 -3
  143. package/dist/wireRefusalCopy.d.ts +6 -1
  144. package/dist/wireRefusalCopy.js +22 -8
  145. package/dist/wiringInstructionsAttribution.d.ts +10 -0
  146. package/dist/wiringInstructionsAttribution.js +67 -0
  147. package/dist/workflowClient.js +22 -1
  148. package/dist/workflowsJournalCapability.js +14 -9
  149. package/dist/writeProtectionCapability.js +28 -23
  150. package/docs/INTEGRATION-CLIENTS.md +817 -45
  151. package/package.json +5 -5
  152. package/dist/askSurvivesStandingAnswer.d.ts +0 -13
  153. package/dist/askSurvivesStandingAnswer.js +0 -53
  154. package/dist/hitl/askSurvivesPosture.d.ts +0 -20
  155. package/dist/hitl/askSurvivesPosture.js +0 -48
  156. /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { readErrorNumber, readErrorString, readErrorStringList } from './wireFailureShape.js';
2
2
  import { capForDisplay } from './fleetTaskDesc.js';
3
+ import { readOwnDataValue } from './ownKey.js';
3
4
  import { fleetLeaseUnavailableFromError } from './wireRefusalCopy.js';
4
5
  import { DRAINING_ERROR_CODE, isCorruptSessionCode, RESUME_AT_ERROR_CODE_PREFIX, RESUME_POLICY_FOLD_CODE, RESUME_RETRY_LATER_CODES, RESUME_USAGE_WINDOW_EXHAUSTED, SCENARIO_NOT_ALLOWED_ERROR_CODE, } from './engineErrorCodes.js';
5
6
  export const WIRE_NETWORK_ERROR_PATTERN = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EHOSTUNREACH|ENETUNREACH|EPIPE|socket hang up|UND_ERR|terminated|other side closed/i;
@@ -87,6 +88,40 @@ export function drainingRetryDelayMs(err, attempt, opts) {
87
88
  const ladder = opts?.ladder && opts.ladder.length > 0 ? opts.ladder : [1_000, 2_000, 4_000];
88
89
  return ladder[Math.min(attempt, ladder.length - 1)] ?? 1_000;
89
90
  }
91
+ export function isInStreamDrainingEnd(frame) {
92
+ try {
93
+ if (typeof frame !== 'object' || frame === null)
94
+ return false;
95
+ if (typeof readOwnDataValue(frame, 'status') === 'number')
96
+ return false;
97
+ const typeSlot = Object.getOwnPropertyDescriptor(frame, 'type');
98
+ const outerType = typeSlot !== undefined && Object.hasOwn(typeSlot, 'value') ? typeSlot.value : undefined;
99
+ if (outerType === 'error')
100
+ return readOwnDataValue(frame, 'errorCode') === DRAINING_ERROR_CODE;
101
+ if (typeSlot !== undefined && outerType !== 'unknown')
102
+ return false;
103
+ if (readOwnDataValue(frame, 'event') !== 'error')
104
+ return false;
105
+ const data = readOwnDataValue(frame, 'data');
106
+ if (typeof data !== 'object' || data === null)
107
+ return false;
108
+ const dataType = readOwnDataValue(data, 'type');
109
+ if (dataType !== undefined && dataType !== 'error')
110
+ return false;
111
+ return readOwnDataValue(data, 'errorCode') === DRAINING_ERROR_CODE;
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ }
117
+ export const STREAM_DRAINING_RECONNECT_MAX = 3;
118
+ export function streamDrainingDecision(frame, attempt, opts) {
119
+ if (!isInStreamDrainingEnd(frame))
120
+ return { giveUp: 'not_draining_end' };
121
+ if (!Number.isSafeInteger(attempt) || attempt < 0 || attempt >= STREAM_DRAINING_RECONNECT_MAX)
122
+ return { giveUp: 'attempts_exhausted' };
123
+ return { reconnectAfterMs: drainingRetryDelayMs(null, attempt, opts?.ladder !== undefined ? { ladder: opts.ladder } : undefined) };
124
+ }
90
125
  export function scenarioDenyFromError(err) {
91
126
  if (typeof err !== 'object' || err === null)
92
127
  return null;
@@ -8,6 +8,7 @@ interface WireFailureShape {
8
8
  bodyVerdict?: string;
9
9
  bodyCurrentName?: string;
10
10
  message: string;
11
+ ownMessage?: string;
11
12
  }
12
13
  export declare function readErrorNumber(o: object, key: string): number | undefined;
13
14
  export declare function readErrorRecord(o: object, key: string): object | undefined;
@@ -15,4 +16,9 @@ export declare function readErrorString(o: object, key: string): string | undefi
15
16
  export declare function readErrorStringList(o: object, key: string): readonly string[] | undefined;
16
17
  export declare function readErrorStrictStringList(o: object, key: string): readonly string[] | undefined;
17
18
  export declare function wireFailureShapeOf(e: unknown): WireFailureShape;
19
+ export declare const WIRE_FAILURE_UNRENDERABLE_TEXT = "the call failed with an error this client could not render";
20
+ export declare function wireFailureTextsOf(e: unknown): {
21
+ reason: string;
22
+ log: string;
23
+ };
18
24
  export {};
@@ -97,7 +97,14 @@ export function wireFailureShapeOf(e) {
97
97
  catch {
98
98
  extraUnreadable = true;
99
99
  }
100
- const extraObj = typeof extra === 'object' && extra !== null && !Array.isArray(extra) ? extra : undefined;
100
+ let extraObj;
101
+ try {
102
+ extraObj = typeof extra === 'object' && extra !== null && !Array.isArray(extra) ? extra : undefined;
103
+ }
104
+ catch {
105
+ extraObj = undefined;
106
+ extraUnreadable = true;
107
+ }
101
108
  let committedPresent = false;
102
109
  let committedRaw;
103
110
  if (extraObj !== undefined) {
@@ -133,12 +140,13 @@ export function wireFailureShapeOf(e) {
133
140
  const bodyName = ownString('name');
134
141
  const bodyVerdict = ownString('verdict');
135
142
  const bodyCurrentName = ownString('currentName');
143
+ const ownMessage = typeof rawMessage === 'string' && rawMessage !== '' ? rawMessage : undefined;
136
144
  let message;
137
145
  try {
138
- message = typeof rawMessage === 'string' && rawMessage !== '' ? rawMessage : String(e);
146
+ message = ownMessage !== undefined ? ownMessage : String(e);
139
147
  }
140
148
  catch {
141
- message = 'the call failed with an error this client could not render';
149
+ message = WIRE_FAILURE_UNRENDERABLE_TEXT;
142
150
  }
143
151
  const sec = typeof retryAfterMs === 'number' && Number.isFinite(retryAfterMs) && retryAfterMs >= 0
144
152
  ? Math.ceil(retryAfterMs / 1000)
@@ -160,5 +168,24 @@ export function wireFailureShapeOf(e) {
160
168
  ...(bodyVerdict !== undefined ? { bodyVerdict } : {}),
161
169
  ...(bodyCurrentName !== undefined ? { bodyCurrentName } : {}),
162
170
  message,
171
+ ...(ownMessage !== undefined ? { ownMessage } : {}),
163
172
  };
164
173
  }
174
+ export const WIRE_FAILURE_UNRENDERABLE_TEXT = 'the call failed with an error this client could not render';
175
+ export function wireFailureTextsOf(e) {
176
+ const { ownMessage } = wireFailureShapeOf(e);
177
+ let log;
178
+ try {
179
+ log = String(e).slice(0, 300);
180
+ }
181
+ catch {
182
+ log = '<unprintable thrown value>';
183
+ }
184
+ if (ownMessage !== undefined)
185
+ return { reason: ownMessage, log };
186
+ if (typeof e === 'string')
187
+ return { reason: e !== '' ? e : WIRE_FAILURE_UNRENDERABLE_TEXT, log };
188
+ if (typeof e === 'number' || typeof e === 'boolean' || typeof e === 'bigint')
189
+ return { reason: String(e), log };
190
+ return { reason: WIRE_FAILURE_UNRENDERABLE_TEXT, log };
191
+ }
@@ -1,4 +1,4 @@
1
- import { FLEET_LEASE_UNAVAILABLE, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE, USAGE_WINDOW_EXHAUSTED } from './engineErrorCodes.js';
1
+ import { FLEET_LEASE_UNAVAILABLE, REQUEST_AUTONOMY_LANE_REFUSED, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE, USAGE_WINDOW_EXHAUSTED } from './engineErrorCodes.js';
2
2
  import type { TaskRequestLike } from './request/taskRequest.js';
3
3
  export declare const CONFLICT_APPROVAL_SETTLED = "conflict.approval_settled";
4
4
  export declare const CONFLICT_RUN_NOT_RUNNING = "conflict.run_not_running";
@@ -83,3 +83,8 @@ export interface HookMatcherRefusal {
83
83
  readonly canonical: string;
84
84
  }
85
85
  export declare function hookMatcherRefusalFromError(err: unknown): HookMatcherRefusal | undefined;
86
+ export interface AutonomyLaneRefusalDetail {
87
+ readonly code: typeof REQUEST_AUTONOMY_LANE_REFUSED;
88
+ }
89
+ export declare function autonomyLaneRefusalFromError(err: unknown): AutonomyLaneRefusalDetail | null;
90
+ export declare function autonomyLaneRefusalContent(): string;
@@ -1,6 +1,6 @@
1
1
  import { readErrorNumber, readErrorRecord, readErrorStrictStringList, readErrorString, readErrorStringList } from './wireFailureShape.js';
2
2
  import { readOwnNonEmptyString } from './ownKey.js';
3
- import { ACTIVE_RUN_BUSY_ERROR_CODE, FLEET_LEASE_UNAVAILABLE, REQUEST_FIELD_CONFLICT, RESUME_POLICY_FOLD_CODE, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE, USAGE_WINDOW_EXHAUSTED } from './engineErrorCodes.js';
3
+ import { ACTIVE_RUN_BUSY_ERROR_CODE, FLEET_LEASE_UNAVAILABLE, REQUEST_AUTONOMY_LANE_REFUSED, REQUEST_FIELD_CONFLICT, RESUME_POLICY_FOLD_CODE, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE, USAGE_WINDOW_EXHAUSTED } from './engineErrorCodes.js';
4
4
  import { capForDisplay } from './fleetTaskDesc.js';
5
5
  import { effectiveWireErrorCode } from './wireErrorTriage.js';
6
6
  import { CORE_TOOL_DECLARATION_CODES } from './generated/engineFactTables.js';
@@ -11,24 +11,31 @@ function readStringField(o, key) {
11
11
  return typeof v === 'string' && v !== '' ? v : undefined;
12
12
  }
13
13
  export function cancelConflictFromError(err) {
14
+ let o;
14
15
  try {
15
16
  if (err === null || typeof err !== 'object')
16
17
  return null;
17
- const o = err;
18
+ o = err;
18
19
  const rawStatus = o.status ?? o.statusCode;
19
20
  const is409 = rawStatus === 409 || (rawStatus === undefined && o.name === 'ConflictError');
20
21
  if (!is409)
21
22
  return null;
22
- const code = readStringField(o, 'errorCode');
23
- if (code === CONFLICT_APPROVAL_SETTLED)
24
- return { kind: 'approval_settled', code };
25
- if (code === CONFLICT_RUN_NOT_RUNNING)
26
- return { kind: 'run_not_running', code };
27
- return { kind: 'unrecognized', ...(code !== undefined ? { code } : {}) };
28
23
  }
29
24
  catch {
30
25
  return null;
31
26
  }
27
+ let code;
28
+ try {
29
+ code = readStringField(o, 'errorCode');
30
+ }
31
+ catch {
32
+ code = undefined;
33
+ }
34
+ if (code === CONFLICT_APPROVAL_SETTLED)
35
+ return { kind: 'approval_settled', code };
36
+ if (code === CONFLICT_RUN_NOT_RUNNING)
37
+ return { kind: 'run_not_running', code };
38
+ return { kind: 'unrecognized', ...(code !== undefined ? { code } : {}) };
32
39
  }
33
40
  export function cancelConflictContent(detail) {
34
41
  switch (detail.kind) {
@@ -619,3 +626,10 @@ export function hookMatcherRefusalFromError(err) {
619
626
  return undefined;
620
627
  }
621
628
  }
629
+ export function autonomyLaneRefusalFromError(err) {
630
+ return effectiveWireErrorCode(err) === REQUEST_AUTONOMY_LANE_REFUSED ? { code: REQUEST_AUTONOMY_LANE_REFUSED } : null;
631
+ }
632
+ export function autonomyLaneRefusalContent() {
633
+ return ('The engine did not start this leader run: this deployment runs in plan-only autonomy, and a leader run has no way to have its plan reviewed, ' +
634
+ 'so nothing was started · Submit the work as a regular run instead, or ask whoever operates the engine to change its autonomy setting');
635
+ }
@@ -0,0 +1,10 @@
1
+ import { type CallerCwdReading } from './callerCwdCapability.js';
2
+ export declare function legCwdOfBody(body: object | null | undefined, callerCwd: CallerCwdReading | undefined): string | undefined;
3
+ export interface InstructionsAttributionInput {
4
+ legCwd: string | undefined;
5
+ currentCwd: string;
6
+ realPathOf: (path: string) => string;
7
+ }
8
+ export declare function engineSelectedInstructionsFile(view: {
9
+ readonly selected: readonly string[];
10
+ } | null | undefined, input: InstructionsAttributionInput): string | undefined;
@@ -0,0 +1,67 @@
1
+ import { callerCwdAdmitted } from './callerCwdCapability.js';
2
+ import { displayUntrusted } from './displayUntrusted.js';
3
+ import { readOutboundBodyField } from './fileHistoryLegNotice.js';
4
+ export function legCwdOfBody(body, callerCwd) {
5
+ if (!callerCwdAdmitted(callerCwd))
6
+ return undefined;
7
+ const r = readOutboundBodyField(body, 'cwd');
8
+ return r.kind === 'value' && typeof r.value === 'string' && r.value.length > 0 ? r.value : undefined;
9
+ }
10
+ function realOf(realPathOf, path) {
11
+ try {
12
+ if (typeof realPathOf !== 'function')
13
+ return undefined;
14
+ const r = realPathOf(path);
15
+ return typeof r === 'string' && r.length > 0 ? r : undefined;
16
+ }
17
+ catch {
18
+ return undefined;
19
+ }
20
+ }
21
+ function safeRelativeMember(member) {
22
+ if (typeof member !== 'string' || member.length === 0)
23
+ return false;
24
+ if (displayUntrusted(member) !== member)
25
+ return false;
26
+ if (member.includes('\\') || member.startsWith('/') || /^[A-Za-z]:/.test(member))
27
+ return false;
28
+ return member.split('/').every((seg) => seg !== '' && seg !== '..');
29
+ }
30
+ function isSep(path, c) {
31
+ return c === '/' || (!path.startsWith('/') && c === '\\');
32
+ }
33
+ function trimSeps(path) {
34
+ let end = path.length;
35
+ while (end > 0 && isSep(path, path.charAt(end - 1)))
36
+ end--;
37
+ return path.slice(0, end);
38
+ }
39
+ function strictlyWithin(child, dir) {
40
+ const trimmed = trimSeps(dir);
41
+ if (!child.startsWith(trimmed) || child.length <= trimmed.length)
42
+ return false;
43
+ return isSep(dir, child.charAt(trimmed.length));
44
+ }
45
+ export function engineSelectedInstructionsFile(view, input) {
46
+ try {
47
+ if (view === null || typeof view !== 'object' || input === null || typeof input !== 'object')
48
+ return undefined;
49
+ const { legCwd, currentCwd, realPathOf } = input;
50
+ if (typeof legCwd !== 'string' || legCwd.length === 0 || legCwd !== currentCwd)
51
+ return undefined;
52
+ const selected = view.selected;
53
+ if (!Array.isArray(selected) || selected.length === 0)
54
+ return undefined;
55
+ const member = selected[0];
56
+ if (!safeRelativeMember(member))
57
+ return undefined;
58
+ const realDir = realOf(realPathOf, currentCwd);
59
+ const realFile = realOf(realPathOf, `${trimSeps(currentCwd)}/${member}`);
60
+ if (realDir === undefined || realFile === undefined || !strictlyWithin(realFile, realDir))
61
+ return undefined;
62
+ return member;
63
+ }
64
+ catch {
65
+ return undefined;
66
+ }
67
+ }
@@ -5,6 +5,7 @@ import { makeEngineWireClient } from './engineWireSdk.js';
5
5
  import { engineWireDebugEnabled } from './engineWireTarget.js';
6
6
  import { hostLog } from './host.js';
7
7
  import { isReadCredentialRefusal } from './readCredentialRefusal.js';
8
+ import { isInStreamDrainingEnd, streamDrainingDecision } from './wireErrorTriage.js';
8
9
  function coerceRunStatus(s) {
9
10
  switch (s) {
10
11
  case 'completed':
@@ -584,9 +585,11 @@ async function consumeWorkflowActivity(l, cfg) {
584
585
  emitActivityTick(l);
585
586
  return;
586
587
  }
588
+ let drainEnds = 0;
587
589
  while (!l.closed && !l.abort.signal.aborted) {
588
590
  let sawFrame = false;
589
591
  let threw = false;
592
+ let lastDrainEnd;
590
593
  try {
591
594
  const stream = client.workflows.stream(l.workflowId, {
592
595
  signal: l.abort.signal,
@@ -597,6 +600,12 @@ async function consumeWorkflowActivity(l, cfg) {
597
600
  return;
598
601
  sawFrame = true;
599
602
  l.connected = true;
603
+ if (isInStreamDrainingEnd(frame)) {
604
+ lastDrainEnd = frame;
605
+ continue;
606
+ }
607
+ lastDrainEnd = undefined;
608
+ drainEnds = 0;
600
609
  try {
601
610
  foldWorkflowActivityFrame(l, frame);
602
611
  }
@@ -632,9 +641,21 @@ async function consumeWorkflowActivity(l, cfg) {
632
641
  return;
633
642
  }
634
643
  }
644
+ let waitMs = WORKFLOW_ACTIVITY_RECONNECT_MS;
645
+ if (lastDrainEnd !== undefined) {
646
+ const decision = streamDrainingDecision(lastDrainEnd, drainEnds++);
647
+ if ('giveUp' in decision) {
648
+ l.closed = true;
649
+ l.closedReason = 'error';
650
+ l.lastError = 'the engine kept ending this stream because it is going down (drain end frames)';
651
+ emitActivityTick(l);
652
+ return;
653
+ }
654
+ waitMs = decision.reconnectAfterMs;
655
+ }
635
656
  emitActivityTick(l);
636
657
  if (!l.closed && !l.abort.signal.aborted) {
637
- await abortableSleep(WORKFLOW_ACTIVITY_RECONNECT_MS, l.abort.signal);
658
+ await abortableSleep(waitMs, l.abort.signal);
638
659
  }
639
660
  }
640
661
  emitActivityTick(l);
@@ -1,16 +1,21 @@
1
1
  import { engineWireTarget } from './engineWireTarget.js';
2
2
  import { createEngineCapReader } from './engineCapReader.js';
3
3
  export function projectWorkflowsJournalCapability(caps) {
4
- if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
5
- return undefined;
6
- if (!Object.hasOwn(caps, 'workflowsJournal'))
7
- return { kind: 'not_reported' };
8
- const v = caps.workflowsJournal;
9
- if (v === undefined)
10
- return { kind: 'not_reported' };
11
- if (typeof v !== 'boolean')
4
+ try {
5
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
6
+ return undefined;
7
+ if (!Object.hasOwn(caps, 'workflowsJournal'))
8
+ return { kind: 'not_reported' };
9
+ const v = caps.workflowsJournal;
10
+ if (v === undefined)
11
+ return { kind: 'not_reported' };
12
+ if (typeof v !== 'boolean')
13
+ return undefined;
14
+ return v ? { kind: 'present' } : { kind: 'absent' };
15
+ }
16
+ catch {
12
17
  return undefined;
13
- return v ? { kind: 'present' } : { kind: 'absent' };
18
+ }
14
19
  }
15
20
  const reader = createEngineCapReader({
16
21
  name: 'workflowsJournal',
@@ -2,30 +2,35 @@ import { capForDisplay } from './fleetTaskDesc.js';
2
2
  import { engineWireTarget } from './engineWireTarget.js';
3
3
  import { createEngineCapReader } from './engineCapReader.js';
4
4
  export function projectWriteProtectionCapability(caps) {
5
- if (caps === null || typeof caps !== 'object')
6
- return undefined;
7
- if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
8
- return undefined;
9
- if (!Object.hasOwn(caps, 'writeProtection'))
10
- return { kind: 'not_reported' };
11
- const wp = caps.writeProtection;
12
- if (wp === null)
13
- return { kind: 'none' };
14
- if (wp === undefined)
15
- return { kind: 'not_reported' };
16
- if (typeof wp !== 'object' || Array.isArray(wp))
17
- return undefined;
18
- const w = wp;
19
- const armed = w.armed;
20
- const replaced = w.replaced;
21
- const rows = w.rows;
22
- if (typeof armed !== 'boolean')
23
- return undefined;
24
- if (typeof replaced !== 'boolean')
25
- return undefined;
26
- if (typeof rows !== 'number' || !Number.isInteger(rows) || rows < 0)
5
+ try {
6
+ if (caps === null || typeof caps !== 'object')
7
+ return undefined;
8
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
9
+ return undefined;
10
+ if (!Object.hasOwn(caps, 'writeProtection'))
11
+ return { kind: 'not_reported' };
12
+ const wp = caps.writeProtection;
13
+ if (wp === null)
14
+ return { kind: 'none' };
15
+ if (wp === undefined)
16
+ return { kind: 'not_reported' };
17
+ if (typeof wp !== 'object' || Array.isArray(wp))
18
+ return undefined;
19
+ const w = wp;
20
+ const armed = w.armed;
21
+ const replaced = w.replaced;
22
+ const rows = w.rows;
23
+ if (typeof armed !== 'boolean')
24
+ return undefined;
25
+ if (typeof replaced !== 'boolean')
26
+ return undefined;
27
+ if (typeof rows !== 'number' || !Number.isInteger(rows) || rows < 0)
28
+ return undefined;
29
+ return { kind: 'present', view: { armed, rows, replaced } };
30
+ }
31
+ catch {
27
32
  return undefined;
28
- return { kind: 'present', view: { armed, rows, replaced } };
33
+ }
29
34
  }
30
35
  export function projectWriteProtectionPosture(wiring) {
31
36
  if (wiring === null || typeof wiring !== 'object')