@sema-agent/client-core 0.112.1 → 0.113.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 (178) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +36 -23
  3. package/dist/adapt/arms.js +7 -1
  4. package/dist/adapt/textStream.d.ts +2 -0
  5. package/dist/adapt/textStream.js +27 -1
  6. package/dist/adapter/activeRunSelfHeal.d.ts +7 -5
  7. package/dist/adapter/activeRunSelfHeal.js +38 -66
  8. package/dist/adapter/downstream/eventToSdkMessage.js +4 -0
  9. package/dist/adapter/downstream/terminalToSdkResult.d.ts +8 -0
  10. package/dist/adapter/downstream/terminalToSdkResult.js +36 -1
  11. package/dist/adapter/runStream.d.ts +2 -12
  12. package/dist/adapter/runStream.js +46 -19
  13. package/dist/agentSession/engineAgentRegistryRead.js +2 -1
  14. package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
  15. package/dist/attachmentOutcome.d.ts +35 -0
  16. package/dist/attachmentOutcome.js +192 -0
  17. package/dist/attachmentPathPlan.d.ts +67 -0
  18. package/dist/attachmentPathPlan.js +203 -0
  19. package/dist/attachmentRoute.d.ts +9 -1
  20. package/dist/attachmentRoute.js +23 -2
  21. package/dist/declared/supportFloorDeclared.d.ts +1 -1
  22. package/dist/declared/supportFloorDeclared.js +1 -0
  23. package/dist/deviceRebind.js +2 -3
  24. package/dist/displayUntrusted.js +126 -19
  25. package/dist/engineAddress.d.ts +1 -1
  26. package/dist/engineAddress.js +9 -6
  27. package/dist/engineErrorCodes.d.ts +3 -0
  28. package/dist/engineErrorCodes.js +4 -0
  29. package/dist/engineNoticeCodes.d.ts +34 -4
  30. package/dist/engineNoticeCodes.js +133 -6
  31. package/dist/engineUnavailable.d.ts +4 -2
  32. package/dist/engineUnavailable.js +99 -17
  33. package/dist/fleet/fleetLedger.d.ts +9 -3
  34. package/dist/fleet/fleetLedger.js +112 -16
  35. package/dist/fleet/fleetProjection.d.ts +5 -0
  36. package/dist/fleet/fleetProjection.js +9 -1
  37. package/dist/gateVocabulary.d.ts +7 -0
  38. package/dist/gateVocabulary.js +40 -14
  39. package/dist/generated/engineFactTables.d.ts +4 -2
  40. package/dist/generated/engineFactTables.js +198 -2
  41. package/dist/generated/engineNoticeTables.js +56 -8
  42. package/dist/generated/settingsSchemaFns.d.ts +7 -0
  43. package/dist/generated/settingsSchemaFns.js +11 -0
  44. package/dist/generated/settingsSchemaHash.d.ts +1 -0
  45. package/dist/generated/settingsSchemaHash.js +58 -0
  46. package/dist/generated/settingsSchemaOwnKeyRead.js +6 -1
  47. package/dist/generated/settingsSchemaTables.d.ts +3 -2
  48. package/dist/generated/settingsSchemaTables.js +14 -0
  49. package/dist/generated/settingsSchemaTightenVerdict.d.ts +1 -0
  50. package/dist/generated/settingsSchemaTightenVerdict.js +125 -0
  51. package/dist/headlessPermissionModeWire.d.ts +7 -2
  52. package/dist/headlessPermissionModeWire.js +77 -8
  53. package/dist/hitl/approvalDecisionDoor.d.ts +24 -0
  54. package/dist/hitl/approvalDecisionDoor.js +77 -0
  55. package/dist/hitl/approvalDelivery.d.ts +6 -0
  56. package/dist/hitl/approvalDelivery.js +57 -7
  57. package/dist/hitl/approvalResolution.d.ts +6 -3
  58. package/dist/hitl/approvalResolution.js +24 -2
  59. package/dist/hitl/approvalsFeed.js +1 -1
  60. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  61. package/dist/hitl/decisionSend.d.ts +7 -4
  62. package/dist/hitl/decisionSend.js +90 -41
  63. package/dist/hitl/frameRouter.d.ts +3 -3
  64. package/dist/hitl/frameRouter.js +5 -0
  65. package/dist/hitl/hitlHostSurface.d.ts +3 -2
  66. package/dist/hitl/hitlHostSurface.js +5 -3
  67. package/dist/hitl/legacyApprovalShapes.d.ts +142 -0
  68. package/dist/hitl/legacyApprovalShapes.js +1 -0
  69. package/dist/hitl/livePendingAsk.d.ts +4 -4
  70. package/dist/hitl/livePendingAsk.js +5 -3
  71. package/dist/hitl/parkResolver.js +1 -1
  72. package/dist/hitl/persistedRulesWire.js +2 -2
  73. package/dist/hitl/planReviewCard.d.ts +2 -1
  74. package/dist/hitl/planReviewCard.js +64 -1
  75. package/dist/hitl/planReviewWire.d.ts +30 -0
  76. package/dist/hitl/planReviewWire.js +204 -65
  77. package/dist/hitl/sessionPolicyWire.js +16 -7
  78. package/dist/hitl/subagentSource.d.ts +1 -0
  79. package/dist/hitl/subagentSource.js +11 -0
  80. package/dist/hitl/toolApprovalWire.d.ts +34 -10
  81. package/dist/hitl/toolApprovalWire.js +182 -33
  82. package/dist/hookMatcherVerdict.d.ts +2 -1
  83. package/dist/hookMatcherVerdict.js +3 -2
  84. package/dist/hooksReaderGenerations.d.ts +8 -0
  85. package/dist/hooksReaderGenerations.js +49 -0
  86. package/dist/hooksWireCaps.js +43 -18
  87. package/dist/hostSettingsSource.d.ts +1 -1
  88. package/dist/hostSettingsSource.js +2 -2
  89. package/dist/hostTurnSettings.d.ts +2 -2
  90. package/dist/hostTurnSettings.js +87 -47
  91. package/dist/humanTurn.d.ts +2 -1
  92. package/dist/humanTurn.js +44 -13
  93. package/dist/humanTurnRead.d.ts +7 -0
  94. package/dist/humanTurnRead.js +23 -14
  95. package/dist/humanTurnSentences.js +3 -0
  96. package/dist/i18n/messages.en.d.ts +91 -5
  97. package/dist/i18n/messages.en.js +98 -12
  98. package/dist/i18n/messages.zh.js +108 -15
  99. package/dist/index.d.ts +29 -15
  100. package/dist/index.js +17 -9
  101. package/dist/liveModelCatalog.js +1 -0
  102. package/dist/liveQuestionStore.d.ts +2 -0
  103. package/dist/liveQuestionStore.js +7 -2
  104. package/dist/localConfig/kernel.d.ts +2 -1
  105. package/dist/localConfig/kernel.js +12 -18
  106. package/dist/localConfig/mcp/edit.js +25 -27
  107. package/dist/localConfig/mcp/servers.js +5 -8
  108. package/dist/localConfig/modelPool.d.ts +6 -1
  109. package/dist/localConfig/modelPool.js +104 -27
  110. package/dist/localConfig/modelPoolWords.d.ts +2 -0
  111. package/dist/localConfig/modelPoolWords.js +1 -0
  112. package/dist/localConfig/settingsWrite.js +1 -14
  113. package/dist/localConfig/skills.js +9 -16
  114. package/dist/localEngineSpawn.d.ts +29 -1
  115. package/dist/localEngineSpawn.js +62 -1
  116. package/dist/mcpLiveness.d.ts +1 -1
  117. package/dist/mcpProbeWire.js +2 -2
  118. package/dist/mcpReconnect.js +2 -2
  119. package/dist/model/catalogLoader.js +3 -17
  120. package/dist/model/onboardJudgement.d.ts +8 -0
  121. package/dist/model/onboardJudgement.js +8 -3
  122. package/dist/model/onboardSteps.d.ts +19 -0
  123. package/dist/model/onboardSteps.js +76 -0
  124. package/dist/notifications.js +6 -0
  125. package/dist/ownKey.d.ts +4 -0
  126. package/dist/ownKey.js +61 -0
  127. package/dist/pathShape.d.ts +14 -0
  128. package/dist/pathShape.js +44 -0
  129. package/dist/planReviewCardFacts.d.ts +3 -0
  130. package/dist/planReviewCardFacts.js +20 -3
  131. package/dist/pluginHooksWire.d.ts +20 -8
  132. package/dist/pluginHooksWire.js +204 -86
  133. package/dist/prepareRefusal.d.ts +2 -0
  134. package/dist/prepareRefusal.js +11 -1
  135. package/dist/request/taskRequest.js +3 -1
  136. package/dist/resultFrameKeys.d.ts +1 -0
  137. package/dist/resultFrameKeys.js +3 -0
  138. package/dist/resumeRefusalCopy.js +3 -1
  139. package/dist/retryStatus.d.ts +11 -1
  140. package/dist/retryStatus.js +15 -4
  141. package/dist/runTerminal.d.ts +1 -0
  142. package/dist/runTerminal.js +15 -1
  143. package/dist/sdkWireTransit.d.ts +1 -1
  144. package/dist/seatContract.d.ts +12 -3
  145. package/dist/seatContract.js +24 -13
  146. package/dist/sessionEngine.js +1 -1
  147. package/dist/sessionHooksRoster.js +8 -6
  148. package/dist/sessionIdSegment.d.ts +0 -1
  149. package/dist/sessionIdSegment.js +1 -3
  150. package/dist/sessionMemoryErase.js +2 -2
  151. package/dist/sessionMemoryStatus.js +2 -1
  152. package/dist/sessionOccupant.d.ts +29 -0
  153. package/dist/sessionOccupant.js +78 -0
  154. package/dist/settingsHooksSalvage.d.ts +4 -1
  155. package/dist/settingsHooksSalvage.js +22 -9
  156. package/dist/skillOverrideChain.d.ts +3 -0
  157. package/dist/skillOverrideChain.js +31 -4
  158. package/dist/skillsWireCaps.d.ts +16 -2
  159. package/dist/skillsWireCaps.js +47 -20
  160. package/dist/subagent/agentStateDetail.js +32 -8
  161. package/dist/subagent/engineCompactWire.js +48 -36
  162. package/dist/subagent/engineDelegatedPrompt.d.ts +3 -2
  163. package/dist/subagent/engineDelegatedPrompt.js +65 -28
  164. package/dist/subagentEditOutcomes.d.ts +9 -0
  165. package/dist/subagentEditOutcomes.js +43 -0
  166. package/dist/supportFloor.d.ts +2 -1
  167. package/dist/supportFloor.js +1 -1
  168. package/dist/toolResult.js +4 -2
  169. package/dist/toolRoster.d.ts +1 -0
  170. package/dist/toolRoster.js +1 -0
  171. package/dist/usageAnalytics.js +2 -1
  172. package/dist/userAttachmentEnvelope.d.ts +11 -0
  173. package/dist/userAttachmentEnvelope.js +7 -2
  174. package/dist/userAttachmentSeat.d.ts +7 -1
  175. package/dist/userAttachmentSeat.js +44 -7
  176. package/dist/wiringInstructionsAttribution.js +8 -2
  177. package/docs/INTEGRATION-CLIENTS.md +1588 -16
  178. package/package.json +5 -5
@@ -0,0 +1,43 @@
1
+ import { msg, renderMessage } from './i18n/translate.js';
2
+ import { readOwnDataValue } from './ownKey.js';
3
+ const isPlainRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
4
+ function countOf(v, key) {
5
+ const x = readOwnDataValue(v, key);
6
+ return typeof x === 'number' && Number.isSafeInteger(x) && x >= 0 ? x : undefined;
7
+ }
8
+ function checkedOutcomes(attempted, succeeded, refused, failed) {
9
+ if (attempted === undefined || succeeded === undefined || refused === undefined || failed === undefined)
10
+ return undefined;
11
+ if (succeeded + refused + failed > attempted)
12
+ return undefined;
13
+ return Object.freeze({ attempted, succeeded, refused, failed });
14
+ }
15
+ export function subagentEditOutcomesOf(toolStats) {
16
+ try {
17
+ if (!isPlainRecord(toolStats))
18
+ return undefined;
19
+ const outcomes = readOwnDataValue(toolStats, 'editFileOutcomes');
20
+ if (!isPlainRecord(outcomes))
21
+ return undefined;
22
+ return checkedOutcomes(countOf(toolStats, 'editFileCount'), countOf(outcomes, 'landed'), countOf(outcomes, 'refused'), countOf(outcomes, 'failed'));
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ export function subagentEditOutcomesSentence(outcomes, lang) {
29
+ try {
30
+ if (!isPlainRecord(outcomes))
31
+ return undefined;
32
+ const v = checkedOutcomes(countOf(outcomes, 'attempted'), countOf(outcomes, 'succeeded'), countOf(outcomes, 'refused'), countOf(outcomes, 'failed'));
33
+ if (v === undefined || v.attempted === 0)
34
+ return undefined;
35
+ if (v.succeeded === v.attempted) {
36
+ return renderMessage(msg(v.attempted === 1 ? 'session.subagent.editOutcomes.allApplied.one' : 'session.subagent.editOutcomes.allApplied.other', { count: v.attempted }), lang);
37
+ }
38
+ return renderMessage(msg('session.subagent.editOutcomes.mixed', { attempted: v.attempted, succeeded: v.succeeded, refused: v.refused, failed: v.failed }), lang);
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
43
+ }
@@ -1,8 +1,9 @@
1
- export type SupportFloorComponent = 'server' | 'core' | 'sdk';
1
+ export type SupportFloorComponent = 'server' | 'core' | 'sdk' | 'settingsContract';
2
2
  export interface SupportFloor {
3
3
  readonly server: string;
4
4
  readonly core: string;
5
5
  readonly sdk: string;
6
+ readonly settingsContract: string;
6
7
  }
7
8
  export declare const SUPPORT_FLOOR: Readonly<SupportFloor>;
8
9
  export declare function supportFloorOf(component: unknown): string | undefined;
@@ -1,7 +1,7 @@
1
1
  import { DECLARED_SUPPORT_FLOOR } from './declared/supportFloorDeclared.js';
2
2
  export const SUPPORT_FLOOR = DECLARED_SUPPORT_FLOOR;
3
3
  export function supportFloorOf(component) {
4
- if (component === 'server' || component === 'core' || component === 'sdk')
4
+ if (component === 'server' || component === 'core' || component === 'sdk' || component === 'settingsContract')
5
5
  return SUPPORT_FLOOR[component];
6
6
  return undefined;
7
7
  }
@@ -11,11 +11,12 @@ import { CORE_ENGINE_CARD_TYPES } from './generated/engineFactTables.js';
11
11
  import { SEMA_REFUSAL_NOTED_KEY } from './engineRowRef.js';
12
12
  export const STRUCTURED_DETAIL_TYPES = frozenSet(CORE_ENGINE_CARD_TYPES);
13
13
  const LEGACY_STRUCTURED_DETAIL_TYPE = 'task-output';
14
+ const LEGACY_FILE_UNCHANGED_DETAIL_TYPE = 'file_unchanged';
14
15
  export function structuredDetailType(structured) {
15
16
  if (typeof structured !== 'object' || structured === null)
16
17
  return undefined;
17
18
  const t = structured.type;
18
- return typeof t === 'string' && (STRUCTURED_DETAIL_TYPES.has(t) || t === LEGACY_STRUCTURED_DETAIL_TYPE) ? t : undefined;
19
+ return typeof t === 'string' && (STRUCTURED_DETAIL_TYPES.has(t) || t === LEGACY_STRUCTURED_DETAIL_TYPE || t === LEGACY_FILE_UNCHANGED_DETAIL_TYPE) ? t : undefined;
19
20
  }
20
21
  const MAX_STRUCTURED_FIELD_CHARS = 1_000_000;
21
22
  export const PROTOCOL_MARKERS = {
@@ -1072,6 +1073,7 @@ export function readCompletedAgentCard(structured) {
1072
1073
  return null;
1073
1074
  const str = (v) => (typeof v === 'string' && v.length > 0 ? v : undefined);
1074
1075
  const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
1076
+ const failureCode = Object.hasOwn(s, 'code') ? str(s.code) : str(s.errorCode);
1075
1077
  return {
1076
1078
  status,
1077
1079
  taskId,
@@ -1082,7 +1084,7 @@ export function readCompletedAgentCard(structured) {
1082
1084
  ...(s.structuredOutput !== undefined ? { structuredOutput: s.structuredOutput } : {}),
1083
1085
  ...(str(s.blockedReason) !== undefined ? { blockedReason: str(s.blockedReason) } : {}),
1084
1086
  ...(str(s.errorMessage) !== undefined ? { errorMessage: str(s.errorMessage) } : {}),
1085
- ...(str(s.errorCode) !== undefined ? { errorCode: str(s.errorCode) } : {}),
1087
+ ...(failureCode !== undefined ? { errorCode: failureCode } : {}),
1086
1088
  ...(num(s.retryAfterMs) !== undefined ? { retryAfterMs: num(s.retryAfterMs) } : {}),
1087
1089
  ...(typeof s.degraded === 'object' && s.degraded !== null
1088
1090
  ? { degraded: s.degraded }
@@ -22,6 +22,7 @@ export interface ToolRosterEntryView {
22
22
  peer: string;
23
23
  declaredBy?: string;
24
24
  };
25
+ remoteName?: string;
25
26
  contract?: {
26
27
  contractId: string;
27
28
  implementationRevision?: string;
@@ -50,6 +50,7 @@ function readEntry(raw) {
50
50
  ...(peer !== undefined
51
51
  ? { origin: { peer, ...(declaredBy !== undefined ? { declaredBy } : {}) } }
52
52
  : {}),
53
+ ...(str(o.remoteName) !== undefined ? { remoteName: str(o.remoteName) } : {}),
53
54
  ...(contractId !== undefined
54
55
  ? { contract: { contractId, ...(implementationRevision !== undefined ? { implementationRevision } : {}) } }
55
56
  : {}),
@@ -1,4 +1,5 @@
1
1
  import { readThrownSlot, slotReadOf, THROWN_SLOT_UNREADABLE } from './wireFailureShape.js';
2
+ import { ROUTE_NOT_FOUND } from './engineErrorCodes.js';
2
3
  export const USAGE_SENTENCES = Object.freeze({
3
4
  analyticsUnavailable: 'Usage analytics aren’t available on this backend.',
4
5
  analyticsUnread: 'Usage analytics couldn’t be read just now.',
@@ -22,7 +23,7 @@ export function classifyUsageFailure(e) {
22
23
  return { kind: 'unavailable', why: 'capability' };
23
24
  if (code.startsWith('feature.'))
24
25
  return { kind: 'unavailable', why: 'feature' };
25
- if (code === 'not_found.route')
26
+ if (code === ROUTE_NOT_FOUND)
26
27
  return { kind: 'unavailable', why: 'route' };
27
28
  return { kind: 'failed', error: e };
28
29
  }
@@ -75,10 +75,21 @@ export type UserAttachmentDescriptor = {
75
75
  readonly name: string;
76
76
  readonly parts: readonly UserAttachmentMcpResourcePart[];
77
77
  readonly truncated: boolean;
78
+ } | {
79
+ readonly kind: 'path';
80
+ readonly name: string;
81
+ readonly path: string;
82
+ readonly lines?: {
83
+ readonly start: number;
84
+ readonly end?: number;
85
+ };
78
86
  };
79
87
  export declare function showAttachmentName(s: string): string;
80
88
  export declare function showAttachmentNameCc(s: string): string;
81
89
  export declare function mintEnvelopeOf(d: DescriptorView, imageDelivery: 'attached' | 'not-attached'): string;
82
90
  export declare function seatTextOf(d: DescriptorView): string | undefined;
91
+ export declare function mintPathPointerOf(d: Extract<DescriptorView, {
92
+ kind: 'path';
93
+ }>): string;
83
94
  export declare function mintReferenceOf(d: DescriptorView): string;
84
95
  export declare function mintUserAttachmentEnvelope(descriptor: UserAttachmentDescriptor): string;
@@ -280,6 +280,8 @@ function envelopeInner(d, imageDelivery) {
280
280
  }
281
281
  }
282
282
  export function mintEnvelopeOf(d, imageDelivery) {
283
+ if (d.kind === 'path')
284
+ return mintReferenceOf(d);
283
285
  return `${TAG_OPEN}${tagAttributes(d)}>\n${envelopeInner(d, imageDelivery)}\n${TAG_CLOSE}`;
284
286
  }
285
287
  function referenceSentence(d) {
@@ -288,8 +290,8 @@ function referenceSentence(d) {
288
290
  return `The user mentioned the MCP resource ${name} (${showAttachmentName(d.uri)} on the server ${showAttachmentName(d.server)}) in this message; its contents are not included here.`;
289
291
  }
290
292
  const path = showAttachmentName(d.path);
291
- const what = d.kind === 'directory' ? 'directory' : d.kind === 'not-included' ? targetWhat(d.target).replace(/^an? /, '') : 'file';
292
- if (d.kind !== 'directory' && d.kind !== 'not-included' && d.source === 'compact-restore') {
293
+ const what = d.kind === 'directory' ? 'directory' : d.kind === 'not-included' ? targetWhat(d.target).replace(/^an? /, '') : d.kind === 'path' ? targetWhat('path').replace(/^an? /, '') : 'file';
294
+ if (d.kind !== 'directory' && d.kind !== 'not-included' && d.kind !== 'path' && d.source === 'compact-restore') {
293
295
  return `The client re-attached the ${what} ${name} (${path}), read earlier in this conversation; its contents are not included here.`;
294
296
  }
295
297
  return `The user mentioned the ${what} ${name} (${path}) in this message; its contents are not included here.`;
@@ -321,6 +323,9 @@ export function seatTextOf(d) {
321
323
  }
322
324
  return text.length > 0 ? text : undefined;
323
325
  }
326
+ export function mintPathPointerOf(d) {
327
+ return renderMessage(msg('attachments.pathPointer.model', { path: showAttachmentName(d.path) }));
328
+ }
324
329
  export function mintReferenceOf(d) {
325
330
  return `${TAG_OPEN}${tagAttributes(d)} />\n${referenceSentence(d)}`;
326
331
  }
@@ -18,4 +18,10 @@ export type UserAttachmentSeatReading = {
18
18
  } | UserAttachmentSeatPresent;
19
19
  export declare function projectUserAttachmentSeatCapability(caps: {} | null | undefined): UserAttachmentSeatReading | undefined;
20
20
  export declare function observedUserAttachmentSeat(baseUrl?: string | undefined): UserAttachmentSeatReading;
21
- export declare function userAttachmentSeatAdmits(reading: UserAttachmentSeatReading | undefined): 'yes' | 'no' | 'unknown';
21
+ interface UserAttachmentSeatUse {
22
+ readonly supply?: 'content_text' | 'path';
23
+ readonly scenario?: {} | null;
24
+ readonly lane?: 'objective' | 'steer';
25
+ }
26
+ export declare function userAttachmentSeatAdmits(reading: UserAttachmentSeatReading | undefined, use?: UserAttachmentSeatUse): 'yes' | 'no' | 'unknown';
27
+ export {};
@@ -49,7 +49,35 @@ const reader = createEngineCapReader({ name: 'userAttachments', project: project
49
49
  export function observedUserAttachmentSeat(baseUrl = engineWireTargetBaseUrl()) {
50
50
  return reader.observed(baseUrl);
51
51
  }
52
- export function userAttachmentSeatAdmits(reading) {
52
+ function scenarioSupplyReadingOf(card) {
53
+ if (card === undefined || card === null)
54
+ return 'not_handed';
55
+ try {
56
+ if (!isPlainRecord(card))
57
+ return 'unreadable';
58
+ const raw = ownDataField(card, 'attachmentSupplies');
59
+ if (raw === undefined)
60
+ return 'not_on_card';
61
+ return stringList(raw) ?? 'unreadable';
62
+ }
63
+ catch {
64
+ return 'unreadable';
65
+ }
66
+ }
67
+ function seatQuestionOf(use) {
68
+ if (use === undefined)
69
+ return { supply: 'content_text', lane: 'objective', card: 'not_handed' };
70
+ if (!isPlainRecord(use))
71
+ return undefined;
72
+ const supply = ownDataField(use, 'supply');
73
+ const lane = ownDataField(use, 'lane');
74
+ return {
75
+ supply: supply === undefined ? 'content_text' : supply === 'content_text' || supply === 'path' ? supply : undefined,
76
+ lane: lane === 'objective' || lane === 'steer' ? lane : undefined,
77
+ card: scenarioSupplyReadingOf(ownDataField(use, 'scenario')),
78
+ };
79
+ }
80
+ export function userAttachmentSeatAdmits(reading, use) {
53
81
  try {
54
82
  if (!isPlainRecord(reading))
55
83
  return 'unknown';
@@ -58,16 +86,25 @@ export function userAttachmentSeatAdmits(reading) {
58
86
  return 'no';
59
87
  if (kind !== 'present')
60
88
  return 'unknown';
89
+ const q = seatQuestionOf(use);
90
+ if (q === undefined)
91
+ return 'unknown';
61
92
  const has = (key, word) => {
62
93
  const list = stringList(readOwnDataValue(reading, key));
63
- return list === undefined ? undefined : list.includes(word);
94
+ return list === undefined ? undefined : word !== undefined && list.includes(word);
64
95
  };
65
- const objective = has('entries', 'objective');
66
- const text = has('supplies', 'content_text');
67
- const client = has('kinds', 'client_text');
68
- if (objective === undefined || text === undefined || client === undefined)
96
+ const lane = has('entries', q.lane);
97
+ const supply = has('supplies', q.supply);
98
+ const client = q.supply === 'path' ? true : has('kinds', 'client_text');
99
+ if (lane === undefined || supply === undefined || client === undefined)
100
+ return 'unknown';
101
+ if (!(lane && supply && client))
102
+ return 'no';
103
+ if (q.card === 'unreadable')
69
104
  return 'unknown';
70
- return objective && text && client ? 'yes' : 'no';
105
+ if (q.card === 'not_handed' || q.card === 'not_on_card')
106
+ return q.supply === 'path' ? 'unknown' : 'yes';
107
+ return q.supply !== undefined && q.card.includes(q.supply) ? 'yes' : 'no';
71
108
  }
72
109
  catch {
73
110
  return 'unknown';
@@ -1,6 +1,7 @@
1
1
  import { callerCwdAdmitted } from './callerCwdCapability.js';
2
2
  import { displayUntrusted } from './displayUntrusted.js';
3
3
  import { readOutboundBodyField } from './fileHistoryLegNotice.js';
4
+ import { pathShapeOf } from './pathShape.js';
4
5
  export function legCwdOfBody(body, callerCwd) {
5
6
  if (!callerCwdAdmitted(callerCwd))
6
7
  return undefined;
@@ -23,9 +24,10 @@ function safeRelativeMember(member) {
23
24
  return false;
24
25
  if (displayUntrusted(member) !== member)
25
26
  return false;
26
- if (member.includes('\\') || member.startsWith('/') || /^[A-Za-z]:/.test(member))
27
+ if (member.includes('\\') || /^[A-Za-z]:/.test(member))
27
28
  return false;
28
- return member.split('/').every((seg) => seg !== '' && seg !== '..');
29
+ const shape = pathShapeOf(member);
30
+ return shape !== undefined && shape.kind === 'relative' && !shape.hasEmptySegment && !shape.hasTrailingSeparator && !shape.hasParentSegment;
29
31
  }
30
32
  function isSep(path, c) {
31
33
  return c === '/' || (!path.startsWith('/') && c === '\\');
@@ -37,6 +39,10 @@ function trimSeps(path) {
37
39
  return path.slice(0, end);
38
40
  }
39
41
  function strictlyWithin(child, dir) {
42
+ const c = pathShapeOf(child);
43
+ const d = pathShapeOf(dir);
44
+ if (c === undefined || d === undefined || c.hasDotSegment || d.hasDotSegment)
45
+ return false;
40
46
  const trimmed = trimSeps(dir);
41
47
  if (!child.startsWith(trimmed) || child.length <= trimmed.length)
42
48
  return false;