@sema-agent/client-core 0.104.0 → 0.105.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 (92) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/README.md +13 -5
  3. package/dist/adapt/arms.js +14 -6
  4. package/dist/adapter/activeRunSelfHeal.d.ts +1 -0
  5. package/dist/adapter/activeRunSelfHeal.js +10 -5
  6. package/dist/adapter/downstream/eventToSdkMessage.js +4 -4
  7. package/dist/adapter/downstream/wiringManifestView.d.ts +6 -0
  8. package/dist/adapter/downstream/wiringManifestView.js +25 -0
  9. package/dist/adapter/runStream.js +5 -1
  10. package/dist/cloudConfigWireCaps.js +3 -0
  11. package/dist/compensations.js +6 -6
  12. package/dist/coreValuePorts.d.ts +3 -1
  13. package/dist/coreValuePorts.js +4 -0
  14. package/dist/displayUntrusted.d.ts +4 -2
  15. package/dist/displayUntrusted.js +45 -22
  16. package/dist/engineGenerationPort.d.ts +11 -2
  17. package/dist/engineGenerationPort.js +63 -9
  18. package/dist/engineHealthFacts.d.ts +5 -0
  19. package/dist/engineHealthFacts.js +11 -0
  20. package/dist/eventLeg.d.ts +1 -1
  21. package/dist/eventLeg.js +23 -3
  22. package/dist/generated/engineFactTables.d.ts +1 -0
  23. package/dist/generated/engineFactTables.js +1 -0
  24. package/dist/generated/sdkFactTables.d.ts +2 -0
  25. package/dist/generated/sdkFactTables.js +9 -0
  26. package/dist/headlessReconnectWire.js +31 -4
  27. package/dist/hitl/askGateWire.js +26 -2
  28. package/dist/hitl/frameRouter.d.ts +4 -0
  29. package/dist/hitl/frameRouter.js +14 -0
  30. package/dist/hitl/gateIdentity.d.ts +1 -0
  31. package/dist/hitl/gateIdentity.js +3 -0
  32. package/dist/hitl/livePendingAsk.d.ts +2 -1
  33. package/dist/hitl/livePendingAsk.js +7 -1
  34. package/dist/hitl/planReviewCard.d.ts +21 -0
  35. package/dist/hitl/planReviewCard.js +229 -0
  36. package/dist/hitl/planReviewWire.d.ts +38 -13
  37. package/dist/hitl/planReviewWire.js +355 -133
  38. package/dist/hitl/toolApprovalWire.d.ts +2 -2
  39. package/dist/hitl/toolApprovalWire.js +53 -32
  40. package/dist/hostSettingsSource.d.ts +1 -1
  41. package/dist/hostSettingsSource.js +8 -4
  42. package/dist/hostTurnSettings.d.ts +1 -1
  43. package/dist/hostTurnSettings.js +29 -10
  44. package/dist/i18n/messages.en.d.ts +50 -0
  45. package/dist/i18n/messages.en.js +50 -0
  46. package/dist/i18n/messages.zh.js +51 -0
  47. package/dist/index.d.ts +15 -3
  48. package/dist/index.js +9 -1
  49. package/dist/mcpTransportKindsCapability.d.ts +18 -0
  50. package/dist/mcpTransportKindsCapability.js +75 -0
  51. package/dist/mcpWireCaps.d.ts +4 -1
  52. package/dist/mcpWireCaps.js +24 -13
  53. package/dist/notifications.d.ts +9 -0
  54. package/dist/notifications.js +11 -2
  55. package/dist/ownKey.d.ts +4 -0
  56. package/dist/ownKey.js +8 -0
  57. package/dist/permissionModeWriteCapability.d.ts +13 -0
  58. package/dist/permissionModeWriteCapability.js +35 -0
  59. package/dist/permissionsAllowGrantCapability.d.ts +3 -0
  60. package/dist/permissionsAllowGrantCapability.js +26 -3
  61. package/dist/permissionsDeclaration.d.ts +23 -1
  62. package/dist/permissionsDeclaration.js +60 -30
  63. package/dist/planReviewCardFacts.d.ts +116 -0
  64. package/dist/planReviewCardFacts.js +469 -0
  65. package/dist/reattachWindow.d.ts +8 -1
  66. package/dist/reattachWindow.js +44 -12
  67. package/dist/runFollow.d.ts +30 -0
  68. package/dist/runFollow.js +117 -0
  69. package/dist/runLedgerSnapshot.d.ts +20 -0
  70. package/dist/runLedgerSnapshot.js +272 -0
  71. package/dist/runPermissionModeSwitch.d.ts +57 -0
  72. package/dist/runPermissionModeSwitch.js +135 -0
  73. package/dist/runReattachPolicy.d.ts +13 -5
  74. package/dist/runReattachPolicy.js +58 -23
  75. package/dist/seam.d.ts +3 -0
  76. package/dist/seam.js +1 -1
  77. package/dist/seatContract.js +1 -0
  78. package/dist/sessionMemoryErase.d.ts +1 -1
  79. package/dist/sessionMemoryErase.js +5 -0
  80. package/dist/sessionMemoryStatus.d.ts +27 -1
  81. package/dist/sessionMemoryStatus.js +117 -0
  82. package/dist/sseIdleTriage.d.ts +3 -1
  83. package/dist/sseIdleTriage.js +19 -4
  84. package/dist/steering.d.ts +1 -0
  85. package/dist/steering.js +34 -26
  86. package/dist/subagent/engineSubagentTail.js +2 -0
  87. package/dist/subagentContentStore.d.ts +3 -0
  88. package/dist/subagentContentStore.js +10 -1
  89. package/dist/turnFailurePresentation.d.ts +5 -2
  90. package/dist/turnFailurePresentation.js +12 -4
  91. package/docs/INTEGRATION-CLIENTS.md +587 -10
  92. package/package.json +2 -2
@@ -187,6 +187,8 @@ const ZH = {
187
187
  'config.mcp.nameReserved': 'MCP 服务器名 {name}{where} 不可用,所以没有启动:以 "remote-" 开头的名字留给已连接设备提供的 MCP 服务器。请给这台服务器换个名字。',
188
188
  'config.mcp.identityHeadersBothSet': 'MCP 服务器 {name}{where} 没有启动:它同时设置了 principalHeader 和 assertionHeader,而这两项指的是同一个身份头 —— 只保留其中一项。其他 MCP 服务器不受影响。',
189
189
  'config.mcp.transportUnreadable': '读不出(声明上的取值器或代理陷阱抛了错)',
190
+ 'config.mcp.transportNotAdvertised': 'MCP 服务器 {name}{where} 没有启动:它用的是 {kind} 传输,而这台引擎说它不支持这种传输(它支持:{supported})。其他 MCP 服务器不受影响。',
191
+ 'config.mcp.transportsNone': '无',
190
192
  'config.mcp.transportInvalid': 'MCP 服务器 {name}{where} 没有启动:它的传输设置不可用 —— {path} {problem}。请修正这台服务器的这项设置(或删掉这台服务器);其他 MCP 服务器不受影响。',
191
193
  'config.mcp.transportDegraded': 'MCP 服务器 {name}{where} 已启动,但它的部分传输设置不能照原样使用、被略去了:{lost}。其余设置照常生效;请修正上面点名的设置,让它们也生效。',
192
194
  'config.mcp.toolAxesInvalid': 'MCP 服务器 {name}{where} 没有启动:它的 toolAxes 设置不合法 —— {problem}。请修正这台服务器的 toolAxes(或删掉它);其他 MCP 服务器不受影响。',
@@ -547,6 +549,13 @@ const ZH = {
547
549
  'session.fileHistoryRefusal.notSaid': '没有发送:你的设置里已关闭文件检查点,但这台引擎没有报告它能否按会话停止记录文件历史,所以现在发送仍可能把它记录下来。只要这台引擎还是同样的报告,重试也不会改变这一点;要发送并让这一次的文件历史被记录,请在设置里把文件检查点重新打开。',
548
550
  'session.fileHistoryRefusal.unrecognized': '没有发送:你的设置里已关闭文件检查点,但这台引擎报告了一个本客户端不认识的文件历史捕获模式,所以不知道它能否按会话停止记录文件历史,现在发送仍可能把它记录下来。只要这台引擎还是同样的报告,重试也不会改变这一点;要发送并让这一次的文件历史被记录,请在设置里把文件检查点重新打开。',
549
551
  'session.fileHistoryRefusal.unreadable': '没有发送:你的设置里已关闭文件检查点,但这台引擎关于能否按会话停止记录文件历史的报告,本客户端读不出来,所以现在发送仍可能把它记录下来。只要这台引擎还是同样的报告,重试也不会改变这一点;要发送并让这一次的文件历史被记录,请在设置里把文件检查点重新打开。',
552
+ 'session.memoryErase.personalStoreUnjudged': '什么都没有抹除:这条会话的记忆有一部分存放在这台部署目前还抹除不了的个人记忆库里,所以抹除在任何改动之前就被拒绝了。',
553
+ 'session.memorySync.parked.one': '这台部署上「{scope}」这一层的记忆同步已暂停:它的同步游标用不了。{wayOut}',
554
+ 'session.memorySync.parked.other': '这台部署上 {count} 层的记忆同步已暂停({scopes}):它们的同步游标用不了。{wayOut}',
555
+ 'session.memorySync.parkedUnnamed.one': '这台部署上 1 层的记忆同步已暂停:它的同步游标用不了。{wayOut}',
556
+ 'session.memorySync.parkedUnnamed.other': '这台部署上 {count} 层的记忆同步已暂停:它们的同步游标用不了。{wayOut}',
557
+ 'session.memorySync.wayOut.deleteCursor': '运维在服务器上删掉每个暂停层的同步游标后,同步即恢复;自上次同步以来只在一侧删掉的条目会回来,需要再删一次。',
558
+ 'session.memorySync.wayOut.unrecognized': '部署给出的出路本客户端认不出,这里不给建议。',
550
559
  'session.hostSettings.memorySwitchMalformed': '设置文件里的记忆设置读不出,所以「关闭记忆」没有生效:这一次请求照常带着记忆发出。改好记忆那一段(memory.enabled 只能是 true 或 false)即可关闭。',
551
560
  'session.hostSettings.fileHistoryRestoreConflict': '没有发送:这次请求准备好之后,你在设置里关闭了文件检查点,但这次请求同时要从检查点还原文件,两者不能放在同一个请求里。要还原文件,请在设置里把文件检查点重新打开;否则请去掉文件还原再发送。',
552
561
  'session.hostSettings.projectionUnchecked': '这一次请求要带的设置在发出前没法核对,所以没有发送。请重新载入设置后再试。',
@@ -670,6 +679,18 @@ const ZH = {
670
679
  'session.steerRefusal.advice': '{happened} —— {nextStep}',
671
680
  'session.steerRefusal.hostQueue.queued': '它留在队列里,在这个 turn 结束时会原样提交',
672
681
  'session.steerRefusal.hostQueue.dropped': '它没有被保留;{nextStep}',
682
+ 'session.permissionModeSwitch.applied': '正在跑的这一轮现在用 {mode} 权限模式。',
683
+ 'session.permissionModeSwitch.folded': '正在跑的这一轮现在用 {mode} 权限模式,不是你选的那一档 —— {reason}。',
684
+ 'session.permissionModeSwitch.reason.entryFloor': '这台部署不允许比它的下限更宽松的模式',
685
+ 'session.permissionModeSwitch.reason.disableAutoMode': '这个任务的设置关掉了 auto 模式',
686
+ 'session.permissionModeSwitch.reason.engine': '引擎不允许这条 run 用你选的模式',
687
+ 'session.permissionModeSwitch.notPersisted': '{line}这次切档没有随 run 存下:run 停下后再续跑时会回到切档前的模式,续跑后请再切一次。',
688
+ 'session.permissionModeSwitch.notRunning': '这条 run 此刻没在跑一轮(停在等决断上、已经结束,或在别处跑),所以没有切它的模式。',
689
+ 'session.permissionModeSwitch.notFound': '你看不到这条 run,没有切任何模式。',
690
+ 'session.permissionModeSwitch.refused': '引擎拒绝切这条 run 的模式({status}),它保持原来的模式。',
691
+ 'session.permissionModeSwitch.refusedWithCode': '引擎拒绝切这条 run 的模式({status} {code}),它保持原来的模式。',
692
+ 'session.permissionModeSwitch.unconfirmed': '切档请求已发出,但没有收到读得懂的答复,不知道模式变没变 —— 请再切一次以确认。',
693
+ 'session.permissionModeSwitch.unavailable': '这里不能切正在跑的这一轮的模式,模式没有变。',
673
694
  'notice.capability.subject.userInvokedSkills': '用户点名的技能',
674
695
  'notice.capability.subject.skillToolLists': '技能工具清单',
675
696
  'notice.capability.subject.permissionRulesWrite': '权限规则写入口',
@@ -1053,10 +1074,40 @@ const ZH = {
1053
1074
  'config.mods.refusal.by': '被 {by} 拒绝',
1054
1075
  'config.mods.rewrite.resultInPlace': '由 {by} 代替工具作答',
1055
1076
  'config.mods.rewrite.inputBy': '参数在放行前被 {by} 改过',
1077
+ 'follow.notFollowed.headRun': '这块屏已不再跟着 run {taskId}{reason}{ending}{exit}',
1078
+ 'follow.notFollowed.headTurn': '这块屏已不再跟着这一轮的 run{reason}{ending}{exit}',
1079
+ 'follow.notFollowed.reason.exhaustedDraining': ':服务它的那台引擎实例在它最后一条事件流关闭时正在下线,而这个客户端的重新附着次数已经用完。',
1080
+ 'follow.notFollowed.reason.exhaustedConnectionLost': ':最后一次尝试时连接断了,而这个客户端的重新附着次数已经用完。',
1081
+ 'follow.notFollowed.reason.exhaustedStreamCap': ':最后一次尝试时它的事件流撞上了引擎的时长上限,而这个客户端的重新附着次数已经用完。',
1082
+ 'follow.notFollowed.reason.exhausted': ':这个客户端的重新附着次数已经用完。',
1083
+ 'follow.notFollowed.reason.badInput': ':这个客户端在重新附着时出了内部错误。',
1084
+ 'follow.notFollowed.reason.noRunId': ':这个客户端始终不知道它是哪一次 run,所以没有可以重新附着的对象。',
1085
+ 'follow.notFollowed.reason.runUnknown': ':引擎答复说它不认识那次 run —— 它可能已被清理,也可能是这个客户端用错了身份去问。',
1086
+ 'follow.notFollowed.reason.unspecified': '。',
1087
+ 'follow.notFollowed.endingUnknown': '引擎没有说那次 run 是怎么结束的 —— 它可能还在跑。',
1088
+ 'follow.notFollowed.exit.reattach': '它接下来的动作,只有在这个客户端重新附着到它之后才会显示在这里。',
1089
+ 'follow.notFollowed.exit.checkRuns': '再发一次这件工作之前,先查一下这个会话的 run。',
1090
+ 'follow.notFollowed.exit.runUnknown': '重新附着也不会把它带回这里;再发一次这件工作之前,先查一下这个会话的 run。',
1091
+ 'follow.notFollowed.idleTear': '这一轮的事件流静默了 {secs} 秒。{notice}{grace}',
1092
+ 'follow.notFollowed.idleGrace': '如果这次 run 本来就会安静这么久(比如一次长构建),下次可以调大空闲宽限:设置 {env}(settings 的 env 块,整数毫秒,{min}-{max};默认 {default})。',
1093
+ 'approval.planReview.note.empty': '计划为空。',
1094
+ 'approval.planReview.note.marked': '这份计划里有不能照原样显示的字符,不能在这张卡上批准。可以拒绝,或要模型重新呈一次计划。',
1095
+ 'approval.planReview.note.tooLarge': '这份计划太长,卡上显示不全({length} 个字符),不能在这张卡上批准。可以拒绝,或要一份更短的计划。',
1096
+ 'approval.planReview.note.notCarried': '引擎没有把这份计划的正文带到卡上(可能过长),不能在这张卡上批准。可以拒绝,或要模型重新呈一次计划。',
1097
+ 'approval.planReview.note.unknown': '这张卡给不出它要批的计划正文,不能在这张卡上批准。可以拒绝,或要模型重新呈一次计划。',
1098
+ 'approval.planReview.askAgain.shown': '用户要求重新呈上这份计划。',
1099
+ 'approval.planReview.askAgain.marked': '用户没法批准这份计划:里面有不能照原样显示的字符。请去掉这些字符后重新呈上计划。',
1100
+ 'approval.planReview.askAgain.tooLarge': '用户没法批准这份计划:它太长,显示不全。请呈上一份更短的计划。',
1101
+ 'approval.planReview.askAgain.notCarried': '用户没法批准这份计划:计划正文没有到达审批卡(可能过长)。请呈上一份更短的计划。',
1102
+ 'approval.planReview.askAgain.unknown': '用户没法批准这份计划:审批卡显示不了它。请重新呈上计划。',
1103
+ 'approval.planReview.askAgain.withNote': '{sentence} 用户补充:{note}',
1104
+ 'approval.planReview.option.askAgain.label': '不,要模型重新呈上计划',
1105
+ 'approval.planReview.option.askAgain.description': '不批准;要模型重新呈上计划',
1056
1106
  };
1057
1107
  export const ZH_MESSAGES = Object.freeze(ZH);
1058
1108
  export const TERM_SLOTS = Object.freeze({
1059
1109
  'session.background.refusal.envOff': ['SEMA_HEADLESS_DETACH'],
1110
+ 'session.permissionModeSwitch.reason.disableAutoMode': ['auto'],
1060
1111
  'session.thinking.offWithUltracodeOnBody': ['Ultracode'],
1061
1112
  'config.mcp.toolAxesInvalid': ['toolAxes'],
1062
1113
  'config.mcp.toolFacesInvalid': ['toolFaces'],
package/dist/index.d.ts CHANGED
@@ -77,6 +77,11 @@ export * from './steerPriorityCapability.js';
77
77
  export * from './permissionModesCapability.js';
78
78
  export * from './approvalDecidedByCapability.js';
79
79
  export * from './outputStyleSeatCapability.js';
80
+ export * from './permissionModeWriteCapability.js';
81
+ export { setRunPermissionMode, runPermissionModeSwitchLine } from './runPermissionModeSwitch.js';
82
+ export type { RunPermissionModeSwitchOutcome, RunPermissionModeSwitchRuns, RunPermissionModeSwitchOptions, PermissionModeAdmissionView, PermissionModeReceiptView, } from './runPermissionModeSwitch.js';
83
+ export { observedMcpTransportKinds, projectMcpTransportKindsCapability } from './mcpTransportKindsCapability.js';
84
+ export type { McpRequestTransportKind, McpTransportKindsReading } from './mcpTransportKindsCapability.js';
80
85
  export * from './mcpProbeWire.js';
81
86
  export * from './connectorStatus.js';
82
87
  export * from './effectiveFacts.js';
@@ -84,7 +89,7 @@ export * from './gateOutcome.js';
84
89
  export * from './postureKnob.js';
85
90
  export * from './engineIdentity.js';
86
91
  export { readEngineHealthFacts } from './engineHealthFacts.js';
87
- export type { EngineHealthFacts, EngineHealthCenterFacts, EngineHealthAuthFacts, EngineHealthDrainingFacts } from './engineHealthFacts.js';
92
+ export type { EngineHealthFacts, EngineHealthCenterFacts, EngineHealthAuthFacts, EngineHealthDrainingFacts, EngineHealthLeaseFacts } from './engineHealthFacts.js';
88
93
  export { transportFailureScene } from './engineWireFor.js';
89
94
  export type { EngineWireNoAnswerKind, TransportFailureChainEnd, TransportFailureLayer, TransportFailureScene, TransportFailureSocket } from './engineWireFor.js';
90
95
  export { engineUrlTransportVerdict, normalizeEngineBaseUrl } from './engineUrl.js';
@@ -105,6 +110,7 @@ export * from './engineToolLabelStore.js';
105
110
  export * from './fleetTaskDesc.js';
106
111
  export { displayUntrusted, displayUntrustedMarks, displayConfiguredUrl, queryCarriesCredential, cleanUntrustedScalar } from './displayUntrusted.js';
107
112
  export type { DisplayUntrustedOptions, DisplayMark, DisplayMarkSpan, DisplayUntrustedMarked } from './displayUntrusted.js';
113
+ export { DISPLAY_DECISION_BODY } from './displayUntrusted.js';
108
114
  export { isDiagnosticValueWord } from './displayUntrusted.js';
109
115
  export type * from './types/engineState.js';
110
116
  export * from './hostEnv.js';
@@ -222,7 +228,8 @@ export { guardedRead, readOwnDataFiniteNumber, readOwnDataNonEmptyString } from
222
228
  export { contextUsageReadingOf, type ContextUsageReading } from './ownKey.js';
223
229
  export { TURN_FAILURE_CATEGORIES, turnFailurePresentation, type TurnFailureCategory, type TurnFailurePresentation, type TurnFailureRetry } from './turnFailurePresentation.js';
224
230
  export { readSeatTurnFailure, seatTurnFailureOf, type SeatTurnFailure } from './turnFailurePresentation.js';
225
- export { REATTACH_BUDGET_FRESH, REATTACH_MAX_TRIES, runReattachPolicy, type ReattachBudget, type ReattachDecision, type ReattachEvent, type ReattachGiveUp, } from './runReattachPolicy.js';
231
+ export { REATTACH_BUDGET_FRESH, REATTACH_BUDGET_NONE, REATTACH_MAX_TRIES, runReattachPolicy, type ReattachBudget, type ReattachDecision, type ReattachDrainingEvent, type ReattachEvent, } from './runReattachPolicy.js';
232
+ export { runNotFollowedNotice, runNotFollowedOf, type ReattachBreak, type RunNotFollowed, type RunNotFollowedCause } from './runFollow.js';
226
233
  export * from './corruptSession.js';
227
234
  export * from './corruptSessionCopy.js';
228
235
  export { SEMA_TOOL_HISTORY_ACCEPTED_KEY, classifyToolHistoryMismatch, readToolHistoryAcceptedKey, readToolHistoryMismatchKey, resolveToolHistoryRewindTarget } from './toolHistoryMismatch.js';
@@ -260,7 +267,7 @@ export type { InterruptedRunRow, InterruptedRunSettleDeps, InterruptedRunSettleV
260
267
  export { ENGINE_GENERATION_WINDOW_MARGIN_MS, ENGINE_STOPPED_CALL_PHASES, approvalWindowLeftMs, convergeEndedEngineGeneration } from './engineGenerationConvergence.js';
261
268
  export type { ApprovalWindowAnchor, EndedGenerationCard, EndedGenerationFacts, EndedGenerationOpenedCall, EndedGenerationPhaseChange, EndedGenerationPhaseHold, EngineGenerationConvergence, EngineStoppedCallPhase, } from './engineGenerationConvergence.js';
262
269
  export { AWAIT_ENGINE_INSTALL_POLL_MS, REATTACH_AWAIT_NEXT_ENGINE_MS, REATTACH_RUN_STATES, approvalFrameGenerationVerdict, awaitNextEngineInstalled, endedGenerationSettleStep, engineGenerationEnded, engineGenerationOfPort, engineGenerationReadingOf, unreachableForSettle, } from './engineGenerationPort.js';
263
- export type { ApprovalFrameGenerationFacts, AwaitNextEngineDeps, EndedGenerationMaterials, EndedGenerationSettleFacts, EndedGenerationSettleStep, EngineGenerationEndedFacts, EngineGenerationPort, EngineGenerationReading, ReattachLivenessReading, ReattachOutageStopLine, ReattachOutageStopLineParts, ReattachRunState, } from './engineGenerationPort.js';
270
+ export type { ApprovalFrameGenerationFacts, AwaitNextEngineDeps, EndedGenerationMaterials, EndedGenerationSettleFacts, EndedGenerationSettleStep, EndedGenerationWaitReading, EngineGenerationEndFact, EngineGenerationEndedFacts, EngineGenerationPort, EngineGenerationReading, ReattachLivenessReading, ReattachOutageStopLine, ReattachOutageStopLineParts, ReattachRunState, } from './engineGenerationPort.js';
264
271
  export { POISON_FRAME_RAW_MAX, REATTACH_BACKOFF_CAP_MS, REATTACH_BACKOFF_START_MS, REATTACH_NOT_FOUND_CONFIRM, REATTACH_NOT_FOUND_MIN_ELAPSED_MS, REATTACH_WINDOW_MS, malformedFrameErrorOf, poisonFrameInitial, poisonFrameStep, reattachBackoffMs, reattachWindowOpen, reattachWindowStep, } from './reattachWindow.js';
265
272
  export type { PoisonFrameDecision, PoisonFrameEvent, PoisonFrameState, PoisonFrameStep, ReattachProbeResult, ReattachWindowDecision, ReattachWindowEvent, ReattachWindowState, ReattachWindowStep, ReattachWindowTuning, } from './reattachWindow.js';
266
273
  export * from './inheritEnvWire.js';
@@ -310,6 +317,11 @@ export { ruleToolNameVerdictOf } from './protocolSegment.js';
310
317
  export type { RuleToolNameReading } from './protocolSegment.js';
311
318
  export * from './hitl/askGateWire.js';
312
319
  export * from './hitl/planReviewWire.js';
320
+ export type { PlanReviewCardFacts, PlanReviewBody, PlanBodyUnknownCause } from './planReviewCardFacts.js';
321
+ export { planReviewBodyOf } from './planReviewCardFacts.js';
322
+ export { planReviewCardNote } from './hitl/planReviewCard.js';
323
+ export { readRunLedgerSnapshot } from './runLedgerSnapshot.js';
324
+ export type { RunLedgerSnapshot, RunLedgerFold, RunLedgerSnapshotDeps } from './runLedgerSnapshot.js';
313
325
  export { decisionInFlightOf, decisionReadMark } from './hitl/decisionLedger.js';
314
326
  export { ASK_PARK_AUTO_REOPEN_BLOCKS, askParkAutoReopenBlockedContent, askParkAutoReopenBlockOf, askParkRefusalBlockOf, claimAskParkAutoReopenBlockNotice, clearAskParkAutoReopenBlocks, } from './hitl/askParkAutoReopenBlock.js';
315
327
  export type { AskParkAutoReopenBlock, AskParkAutoReopenBlockNotice, AskParkGate } from './hitl/askParkAutoReopenBlock.js';
package/dist/index.js CHANGED
@@ -66,6 +66,9 @@ export * from './steerPriorityCapability.js';
66
66
  export * from './permissionModesCapability.js';
67
67
  export * from './approvalDecidedByCapability.js';
68
68
  export * from './outputStyleSeatCapability.js';
69
+ export * from './permissionModeWriteCapability.js';
70
+ export { setRunPermissionMode, runPermissionModeSwitchLine } from './runPermissionModeSwitch.js';
71
+ export { observedMcpTransportKinds, projectMcpTransportKindsCapability } from './mcpTransportKindsCapability.js';
69
72
  export * from './mcpProbeWire.js';
70
73
  export * from './connectorStatus.js';
71
74
  export * from './effectiveFacts.js';
@@ -88,6 +91,7 @@ export * from './classifierStatus.js';
88
91
  export * from './engineToolLabelStore.js';
89
92
  export * from './fleetTaskDesc.js';
90
93
  export { displayUntrusted, displayUntrustedMarks, displayConfiguredUrl, queryCarriesCredential, cleanUntrustedScalar } from './displayUntrusted.js';
94
+ export { DISPLAY_DECISION_BODY } from './displayUntrusted.js';
91
95
  export { isDiagnosticValueWord } from './displayUntrusted.js';
92
96
  export * from './hostEnv.js';
93
97
  export * from './unrefTimer.js';
@@ -191,7 +195,8 @@ export { guardedRead, readOwnDataFiniteNumber, readOwnDataNonEmptyString } from
191
195
  export { contextUsageReadingOf } from './ownKey.js';
192
196
  export { TURN_FAILURE_CATEGORIES, turnFailurePresentation } from './turnFailurePresentation.js';
193
197
  export { readSeatTurnFailure, seatTurnFailureOf } from './turnFailurePresentation.js';
194
- export { REATTACH_BUDGET_FRESH, REATTACH_MAX_TRIES, runReattachPolicy, } from './runReattachPolicy.js';
198
+ export { REATTACH_BUDGET_FRESH, REATTACH_BUDGET_NONE, REATTACH_MAX_TRIES, runReattachPolicy, } from './runReattachPolicy.js';
199
+ export { runNotFollowedNotice, runNotFollowedOf } from './runFollow.js';
195
200
  export * from './corruptSession.js';
196
201
  export * from './corruptSessionCopy.js';
197
202
  export { SEMA_TOOL_HISTORY_ACCEPTED_KEY, classifyToolHistoryMismatch, readToolHistoryAcceptedKey, readToolHistoryMismatchKey, resolveToolHistoryRewindTarget } from './toolHistoryMismatch.js';
@@ -254,6 +259,9 @@ export * from './coreValuePorts.js';
254
259
  export { ruleToolNameVerdictOf } from './protocolSegment.js';
255
260
  export * from './hitl/askGateWire.js';
256
261
  export * from './hitl/planReviewWire.js';
262
+ export { planReviewBodyOf } from './planReviewCardFacts.js';
263
+ export { planReviewCardNote } from './hitl/planReviewCard.js';
264
+ export { readRunLedgerSnapshot } from './runLedgerSnapshot.js';
257
265
  export { decisionInFlightOf, decisionReadMark } from './hitl/decisionLedger.js';
258
266
  export { ASK_PARK_AUTO_REOPEN_BLOCKS, askParkAutoReopenBlockedContent, askParkAutoReopenBlockOf, askParkRefusalBlockOf, claimAskParkAutoReopenBlockNotice, clearAskParkAutoReopenBlocks, } from './hitl/askParkAutoReopenBlock.js';
259
267
  export { HITL_DECISION_FAMILIES, HITL_DECISION_NOT_APPLIED_CAUSES, HITL_DECISION_NOT_SENT_CAUSES, HITL_DECISION_UNCONFIRMED_CAUSES, sendHitlDecision, hitlDecisionOutcomeContent, } from './hitl/decisionSend.js';
@@ -0,0 +1,18 @@
1
+ import type { McpServerSpec } from '@sema-agent/sdk';
2
+ export type McpRequestTransportKind = McpServerSpec['transport']['kind'];
3
+ export declare const MCP_TRANSPORT_KINDS_WHEN_NOT_STATED: readonly ["stdio", "http"];
4
+ export type McpTransportKindsReading = {
5
+ readonly kind: 'stated';
6
+ readonly kinds: readonly McpRequestTransportKind[];
7
+ readonly unrecognized: readonly string[];
8
+ } | {
9
+ readonly kind: 'not_stated';
10
+ readonly kinds: readonly McpRequestTransportKind[];
11
+ } | {
12
+ readonly kind: 'unreadable';
13
+ } | {
14
+ readonly kind: 'unobserved';
15
+ };
16
+ export declare function projectMcpTransportKindsCapability(caps: unknown): McpTransportKindsReading | undefined;
17
+ export declare function observedMcpTransportKinds(baseUrl?: string | undefined): McpTransportKindsReading;
18
+ export declare function mcpTransportNotAdvertised(reading: McpTransportKindsReading | undefined, transportKind: string): readonly McpRequestTransportKind[] | undefined;
@@ -0,0 +1,75 @@
1
+ import { engineWireTargetBaseUrl } from './engineWireTarget.js';
2
+ import { createEngineCapReader } from './engineCapReader.js';
3
+ import { appendOwnElement, ownDataField } from './ownKey.js';
4
+ export const MCP_TRANSPORT_KINDS_WHEN_NOT_STATED = Object.freeze(['stdio', 'http']);
5
+ const _kindsEqRequestFace = true;
6
+ void _kindsEqRequestFace;
7
+ const KNOWN = new Set(MCP_TRANSPORT_KINDS_WHEN_NOT_STATED);
8
+ export function projectMcpTransportKindsCapability(caps) {
9
+ try {
10
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
11
+ return undefined;
12
+ const v = ownDataField(caps, 'mcpTransportKinds');
13
+ if (v === undefined)
14
+ return { kind: 'not_stated', kinds: MCP_TRANSPORT_KINDS_WHEN_NOT_STATED };
15
+ if (!Array.isArray(v))
16
+ return undefined;
17
+ const len = ownDataField(v, 'length');
18
+ if (typeof len !== 'number' || !Number.isSafeInteger(len) || len < 0 || len > 1000)
19
+ return undefined;
20
+ const kinds = [];
21
+ const unrecognized = [];
22
+ for (let i = 0; i < len; i++) {
23
+ if (!Object.hasOwn(v, i))
24
+ return undefined;
25
+ const w = ownDataField(v, String(i));
26
+ if (typeof w !== 'string')
27
+ return undefined;
28
+ if (KNOWN.has(w)) {
29
+ if (!kinds.includes(w))
30
+ appendOwnElement(kinds, w);
31
+ }
32
+ else if (!unrecognized.includes(w))
33
+ appendOwnElement(unrecognized, w);
34
+ }
35
+ return { kind: 'stated', kinds, unrecognized };
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ }
41
+ const reader = createEngineCapReader({
42
+ name: 'mcpTransportKinds',
43
+ project: projectMcpTransportKindsCapability,
44
+ });
45
+ export function observedMcpTransportKinds(baseUrl = engineWireTargetBaseUrl()) {
46
+ return reader.observed(baseUrl);
47
+ }
48
+ export function mcpTransportNotAdvertised(reading, transportKind) {
49
+ try {
50
+ if (reading === null || reading === undefined || typeof reading !== 'object' || Array.isArray(reading))
51
+ return undefined;
52
+ if (ownDataField(reading, 'kind') !== 'stated')
53
+ return undefined;
54
+ const kinds = ownDataField(reading, 'kinds');
55
+ if (!Array.isArray(kinds))
56
+ return undefined;
57
+ const len = ownDataField(kinds, 'length');
58
+ if (typeof len !== 'number' || !Number.isSafeInteger(len) || len < 0 || len > MCP_TRANSPORT_KINDS_WHEN_NOT_STATED.length)
59
+ return undefined;
60
+ const list = [];
61
+ for (let i = 0; i < len; i++) {
62
+ if (!Object.hasOwn(kinds, i))
63
+ return undefined;
64
+ const k = ownDataField(kinds, String(i));
65
+ if (typeof k !== 'string' || !KNOWN.has(k))
66
+ return undefined;
67
+ if (!list.includes(k))
68
+ appendOwnElement(list, k);
69
+ }
70
+ return list.includes(transportKind) ? undefined : Object.freeze([...list]);
71
+ }
72
+ catch {
73
+ return undefined;
74
+ }
75
+ }
@@ -1,5 +1,6 @@
1
1
  import type { McpServerSpec } from '@sema-agent/sdk';
2
2
  import type { McpEntryKeyIssue } from './generated/settingsSchemaTypes.js';
3
+ import { type McpTransportKindsReading } from './mcpTransportKindsCapability.js';
3
4
  import type { UiLanguage } from './env/uiLanguage.js';
4
5
  export type { McpServerSpec };
5
6
  export interface McpConfigLike {
@@ -16,6 +17,7 @@ export interface McpConfigLike {
16
17
  toolFaces?: unknown;
17
18
  toolAxes?: unknown;
18
19
  startupTimeoutMs?: number;
20
+ sessionMetaKey?: string;
19
21
  }
20
22
  export type McpTransportEntryLike = Pick<McpConfigLike, 'type' | 'command' | 'args' | 'env' | 'url' | 'headers' | 'principalHeader' | 'assertionHeader'>;
21
23
  export type McpTransportVerdict = {
@@ -72,7 +74,7 @@ export type McpAllowToolsVerdict = {
72
74
  readonly problem: string;
73
75
  };
74
76
  export declare function mcpAllowToolsVerdict(read: () => {} | null | undefined, keyPrefix?: string): McpAllowToolsVerdict;
75
- export type McpConfigDropReason = 'name_blank' | 'name_edge_whitespace' | 'name_collides_after_trim' | 'name_too_long' | 'name_reserved' | 'transport_invalid' | 'identity_headers_both_set' | 'tool_axes_invalid' | 'tool_faces_invalid' | 'elicitation_invalid' | 'allow_tools_invalid' | 'entry_not_object' | 'entry_unreadable';
77
+ export type McpConfigDropReason = 'name_blank' | 'name_edge_whitespace' | 'name_collides_after_trim' | 'name_too_long' | 'name_reserved' | 'transport_invalid' | 'identity_headers_both_set' | 'tool_axes_invalid' | 'tool_faces_invalid' | 'elicitation_invalid' | 'allow_tools_invalid' | 'entry_not_object' | 'entry_unreadable' | 'transport_not_advertised';
76
78
  export type McpServerNameUnusableReason = 'name_blank' | 'name_edge_whitespace' | 'name_collides_after_trim' | 'name_too_long' | 'name_reserved';
77
79
  export type McpServerNameVerdict = {
78
80
  readonly usable: true;
@@ -100,6 +102,7 @@ export interface McpConfigProjection {
100
102
  }
101
103
  export interface ProjectMcpConfigsOptions {
102
104
  readonly sourceLabel?: (serverName: string) => string | undefined;
105
+ readonly transportKinds?: McpTransportKindsReading;
103
106
  readonly lang?: UiLanguage;
104
107
  }
105
108
  export declare function projectMcpConfigs(servers: Record<string, McpConfigLike> | undefined, opts?: ProjectMcpConfigsOptions): McpConfigProjection;
@@ -4,14 +4,16 @@ import { appendOwnElement, guardedRead } from './ownKey.js';
4
4
  import { readMcpToolAxes, readToolFaces } from './coreValuePorts.js';
5
5
  import { capForDisplay } from './fleetTaskDesc.js';
6
6
  import { msg, renderMessage } from './i18n/translate.js';
7
+ import { mcpTransportNotAdvertised } from './mcpTransportKindsCapability.js';
7
8
  const _mcpServerSpecPin = true;
8
9
  void _mcpServerSpecPin;
9
- function transparentKeys(startupTimeoutMs, axes, faces, elicitation) {
10
+ function transparentKeys(startupTimeoutMs, axes, faces, elicitation, sessionMetaKey) {
10
11
  return {
11
12
  ...(faces !== undefined ? { toolFaces: faces } : {}),
12
13
  ...(axes !== undefined ? { toolAxes: axes } : {}),
13
14
  ...(elicitation !== undefined ? { elicitation } : {}),
14
15
  ...(startupTimeoutMs !== undefined ? { startupTimeoutMs } : {}),
16
+ ...(sessionMetaKey !== undefined ? { sessionMetaKey } : {}),
15
17
  };
16
18
  }
17
19
  export function readMcpHttpIdentityHeaders(transport) {
@@ -36,7 +38,7 @@ function entryShapeOf(c) {
36
38
  function readEntryOwnKeys(c) {
37
39
  try {
38
40
  const allowTools = c.allowTools;
39
- return { toolAxes: c.toolAxes, elicitation: c.elicitation, allowTools, startupTimeoutMs: c.startupTimeoutMs };
41
+ return { toolAxes: c.toolAxes, elicitation: c.elicitation, allowTools, startupTimeoutMs: c.startupTimeoutMs, sessionMetaKey: c.sessionMetaKey };
40
42
  }
41
43
  catch {
42
44
  return undefined;
@@ -153,7 +155,7 @@ function specOf(name, c, own, axes, faces, elicitation, allowTools) {
153
155
  name,
154
156
  transport: t.transport,
155
157
  ...(allowTools !== undefined ? { allowTools } : {}),
156
- ...transparentKeys(own.startupTimeoutMs, axes, faces, elicitation),
158
+ ...transparentKeys(own.startupTimeoutMs, axes, faces, elicitation, own.sessionMetaKey),
157
159
  };
158
160
  return { kind: 'ok', spec, lost: t.lost };
159
161
  }
@@ -305,7 +307,7 @@ const DROP_LABEL_SHOWN = 140;
305
307
  const DROP_PROBLEM_SHOWN = 300;
306
308
  const DROP_BAD_NAME_SHOWN = 160;
307
309
  const DEGRADED_LOST_SHOWN = 400;
308
- function dropNotice(name, reason, problem, opts, path) {
310
+ function dropNotice(name, reason, problem, opts, path, transportKind) {
309
311
  let label;
310
312
  try {
311
313
  label = opts?.sourceLabel?.(name);
@@ -332,15 +334,17 @@ function dropNotice(name, reason, problem, opts, path) {
332
334
  ? msg('config.mcp.identityHeadersBothSet', { name: quoted, where })
333
335
  : reason === 'transport_invalid'
334
336
  ? msg('config.mcp.transportInvalid', { name: quoted, where, path: capForDisplay(path ?? 'transport', DROP_NAME_SHOWN), problem: capForDisplay(problem ?? '', DROP_PROBLEM_SHOWN) })
335
- : reason === 'name_blank'
336
- ? msg('config.mcp.nameBlank', { name: badName(), where })
337
- : reason === 'name_collides_after_trim'
338
- ? msg('config.mcp.nameCollides', { name: badName(), where })
339
- : reason === 'name_too_long'
340
- ? msg('config.mcp.nameTooLong', { name: badName(), where })
341
- : reason === 'name_reserved'
342
- ? msg('config.mcp.nameReserved', { name: badName(), where })
343
- : msg('config.mcp.nameEdgeWhitespace', { name: badName(), where });
337
+ : reason === 'transport_not_advertised'
338
+ ? msg('config.mcp.transportNotAdvertised', { name: quoted, where, kind: capForDisplay(transportKind ?? '', DROP_NAME_SHOWN), supported: problem !== undefined && problem.length > 0 ? problem : renderMessage(msg('config.mcp.transportsNone'), opts?.lang) })
339
+ : reason === 'name_blank'
340
+ ? msg('config.mcp.nameBlank', { name: badName(), where })
341
+ : reason === 'name_collides_after_trim'
342
+ ? msg('config.mcp.nameCollides', { name: badName(), where })
343
+ : reason === 'name_too_long'
344
+ ? msg('config.mcp.nameTooLong', { name: badName(), where })
345
+ : reason === 'name_reserved'
346
+ ? msg('config.mcp.nameReserved', { name: badName(), where })
347
+ : msg('config.mcp.nameEdgeWhitespace', { name: badName(), where });
344
348
  return renderMessage(ref, opts?.lang);
345
349
  }
346
350
  function degradedNotice(name, lost, opts) {
@@ -381,6 +385,13 @@ export function projectMcpConfigs(servers, opts) {
381
385
  }
382
386
  const out = slotUnreadable ? { spec: null, entryUnreadable: true } : mcpConfigEntry(name, c);
383
387
  if (out.spec !== null) {
388
+ const kind = out.spec.transport.kind;
389
+ const supported = opts?.transportKinds === undefined ? undefined : mcpTransportNotAdvertised(opts.transportKinds, kind);
390
+ if (supported !== undefined) {
391
+ const listed = supported.join(', ');
392
+ dropped.push({ name, reason: 'transport_not_advertised', path: 'transport.kind', problem: listed, notice: dropNotice(name, 'transport_not_advertised', listed, opts, 'transport.kind', kind) });
393
+ continue;
394
+ }
384
395
  specs.push(out.spec);
385
396
  if (out.transportLost !== undefined)
386
397
  degraded.push({ name, lost: Object.freeze([...out.transportLost]), notice: degradedNotice(name, out.transportLost, opts) });
@@ -42,6 +42,14 @@ export declare function taskNotificationDedupKey(n: {
42
42
  seq?: number | string;
43
43
  taskType?: string;
44
44
  }): string;
45
+ export interface TaskNotificationRenderKeyInput {
46
+ taskId: string;
47
+ status: string;
48
+ seq?: number | string;
49
+ taskType?: string;
50
+ completionId?: string;
51
+ }
52
+ export declare function taskNotificationRenderKeys(n: TaskNotificationRenderKeyInput): readonly [selfKey: string, ...completionKey: string[]];
45
53
  export declare function taskNotificationDedupKeyFromWire(raw: Record<string, unknown>): string;
46
54
  export interface TranscriptNotificationSeeds {
47
55
  renderedKeys: string[];
@@ -120,6 +128,7 @@ export interface EngineWorkflowCompletion {
120
128
  runId: string;
121
129
  status: 'completed' | 'failed';
122
130
  summary: string;
131
+ completionId?: string;
123
132
  }
124
133
  export declare function enqueueBgChildNotification(raw: {
125
134
  taskId: string;
@@ -5,7 +5,7 @@ import { panelEndFact } from './panelReduce.js';
5
5
  import { isCoreTaskNotificationTerminal, isCoreTaskNotificationTerminalNotSuccess } from './terminalStatuses.js';
6
6
  import { cycleSeqValue } from './cycleOrder.js';
7
7
  import { CORE_ENGINE_AUTHORITY_ENVELOPE_TAGS } from './generated/engineFactTables.js';
8
- import { guardedRead, ownSnapshot, ownSnapshotRecord, ownSnapshotTyped, readOwnDataValue } from './ownKey.js';
8
+ import { guardedRead, ownSnapshot, ownSnapshotRecord, ownSnapshotTyped, readOwnDataValue, workflowCompletionExtrasOf } from './ownKey.js';
9
9
  function escapeXml(v) {
10
10
  return v.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
11
11
  }
@@ -244,6 +244,14 @@ export function taskNotificationDedupKey(n) {
244
244
  const lane = n.taskType === 'external' ? 'external:' : '';
245
245
  return `${lane}${n.taskId}:${n.status}${seq ? `:${seq}` : ''}`;
246
246
  }
247
+ const COMPLETION_KEY_PREFIX = 'completion:';
248
+ export function taskNotificationRenderKeys(n) {
249
+ const own = taskNotificationDedupKey(n);
250
+ const id = n.completionId;
251
+ if (n.taskType === 'external' || !isCoreTaskNotificationTerminal(n.status) || typeof id !== 'string' || id.length === 0)
252
+ return [own];
253
+ return [own, `${COMPLETION_KEY_PREFIX}${id}`];
254
+ }
247
255
  export function taskNotificationDedupKeyFromWire(raw) {
248
256
  const n = ownSnapshotRecord(raw) ?? {};
249
257
  return taskNotificationDedupKey({
@@ -830,6 +838,7 @@ function enqueueBgChild(n, identity) {
830
838
  ...identity,
831
839
  }));
832
840
  }
841
+ const completionIdOnly = (x) => (x.completionId !== undefined ? { completionId: x.completionId } : {});
833
842
  export function enqueueEngineWorkflowNotification(raw) {
834
843
  const c = ownSnapshotRecord(raw);
835
844
  if (c === undefined) {
@@ -843,7 +852,7 @@ export function enqueueEngineWorkflowNotification(raw) {
843
852
  }
844
853
  markRunNotified(c.runId);
845
854
  cardEnqueuedRunIds.add(c.runId);
846
- port()?.enqueuePendingNotification(taskNotificationQueueCommand({ taskId: c.runId, taskType: 'workflow', status: c.status, summary: c.summary }));
855
+ port()?.enqueuePendingNotification(taskNotificationQueueCommand({ taskId: c.runId, taskType: 'workflow', status: c.status, summary: c.summary, ...completionIdOnly(workflowCompletionExtrasOf(c)) }));
847
856
  }
848
857
  export function _resetEngineTaskNotificationForTest() {
849
858
  notifiedRunIds.clear();
package/dist/ownKey.d.ts CHANGED
@@ -71,3 +71,7 @@ export interface SampledRecord {
71
71
  export declare function ownSnapshotWhenTyped<V>(value: V, word: string): SampledJson;
72
72
  export declare function ownSnapshotTyped<T extends object>(value: T): T | undefined;
73
73
  export declare function ownSnapshotRecord<V>(value: V): SampledRecord | undefined;
74
+ export declare function workflowCompletionExtrasOf(c: object): {
75
+ completionId?: string;
76
+ diagnostics?: string;
77
+ };
package/dist/ownKey.js CHANGED
@@ -440,3 +440,11 @@ function sampleObject(src, depth, run) {
440
440
  run.path.delete(src);
441
441
  }
442
442
  }
443
+ export function workflowCompletionExtrasOf(c) {
444
+ const completionId = guardedRead(() => readOwnDataNonEmptyString(c, 'completionId'));
445
+ const diagnostics = guardedRead(() => readOwnDataNonEmptyString(c, 'diagnostics'));
446
+ return {
447
+ ...(completionId !== undefined ? { completionId } : {}),
448
+ ...(diagnostics !== undefined ? { diagnostics } : {}),
449
+ };
450
+ }
@@ -0,0 +1,13 @@
1
+ export type PermissionModeWriteReading = {
2
+ kind: 'unobserved';
3
+ } | {
4
+ kind: 'unreadable';
5
+ } | {
6
+ kind: 'not_reported';
7
+ } | {
8
+ kind: 'present';
9
+ value: boolean;
10
+ };
11
+ export declare function projectPermissionModeWriteCapability(caps: unknown): PermissionModeWriteReading | undefined;
12
+ export declare function observedPermissionModeWrite(baseUrl?: string | undefined): PermissionModeWriteReading;
13
+ export declare function permissionModeWriteAvailable(reading: PermissionModeWriteReading | undefined): boolean;
@@ -0,0 +1,35 @@
1
+ import { engineWireTargetBaseUrl } from './engineWireTarget.js';
2
+ import { createEngineCapReader } from './engineCapReader.js';
3
+ import { ownDataField, readOwnDataValue } from './ownKey.js';
4
+ export function projectPermissionModeWriteCapability(caps) {
5
+ try {
6
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
7
+ return undefined;
8
+ const v = ownDataField(caps, 'permissionModeWrite');
9
+ if (v === undefined)
10
+ return { kind: 'not_reported' };
11
+ return typeof v === 'boolean' ? { kind: 'present', value: v } : undefined;
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ }
17
+ const reader = createEngineCapReader({
18
+ name: 'permissionModeWrite',
19
+ project: projectPermissionModeWriteCapability,
20
+ });
21
+ export function observedPermissionModeWrite(baseUrl = engineWireTargetBaseUrl()) {
22
+ return reader.observed(baseUrl);
23
+ }
24
+ export function permissionModeWriteAvailable(reading) {
25
+ try {
26
+ if (reading === null || reading === undefined || typeof reading !== 'object' || Array.isArray(reading))
27
+ return false;
28
+ if (readOwnDataValue(reading, 'kind') !== 'present')
29
+ return false;
30
+ return readOwnDataValue(reading, 'value') === true;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
@@ -1,3 +1,4 @@
1
+ export declare const RULE_LAYERS_CAP_LEAF: "layers";
1
2
  export type PermissionsAllowGrantReading = {
2
3
  kind: 'unobserved';
3
4
  } | {
@@ -8,10 +9,12 @@ export type PermissionsAllowGrantReading = {
8
9
  kind: 'present';
9
10
  grants: boolean;
10
11
  layer?: boolean;
12
+ layers?: boolean;
11
13
  };
12
14
  export declare function projectPermissionsAllowGrantCapability(caps: unknown): PermissionsAllowGrantReading | undefined;
13
15
  export declare function observedPermissionsAllowGrant(baseUrl?: string | undefined): PermissionsAllowGrantReading;
14
16
  export declare function permissionsAllowGrantAvailable(reading: PermissionsAllowGrantReading): boolean;
15
17
  export declare function allowWireForm(reading: PermissionsAllowGrantReading): 'layer' | 'grant' | 'off';
16
18
  export declare function allowRulesGate(reading: PermissionsAllowGrantReading, settingsRead: 'clean' | 'partial' | 'unreadable' | undefined): 'open' | 'capability_off' | 'settings_read_not_clean';
19
+ export declare function permissionRuleLayersOn(reading: PermissionsAllowGrantReading | undefined): boolean;
17
20
  export declare function permissionsAllowGrantDoctorDetail(reading: PermissionsAllowGrantReading, settingsRead?: 'clean' | 'partial' | 'unreadable'): string;
@@ -4,6 +4,7 @@ import { ownDataField } from './ownKey.js';
4
4
  import { hasCoreValuePort } from './coreValuePorts.js';
5
5
  const ALLOW_GRANT_CAP_PATH = ['settings', 'permissions', 'allowGrant'];
6
6
  const ALLOW_LAYER_CAP_LEAF = 'allowLayer';
7
+ export const RULE_LAYERS_CAP_LEAF = 'layers';
7
8
  export function projectPermissionsAllowGrantCapability(caps) {
8
9
  try {
9
10
  if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
@@ -18,9 +19,21 @@ export function projectPermissionsAllowGrantCapability(caps) {
18
19
  if (typeof v !== 'boolean')
19
20
  return undefined;
20
21
  const layer = ownDataField(node, ALLOW_LAYER_CAP_LEAF);
21
- if (layer === undefined)
22
- return { kind: 'present', grants: v };
23
- return typeof layer === 'boolean' ? { kind: 'present', grants: v, layer } : undefined;
22
+ if (layer !== undefined && typeof layer !== 'boolean')
23
+ return undefined;
24
+ let layers;
25
+ try {
26
+ layers = ownDataField(node, RULE_LAYERS_CAP_LEAF);
27
+ }
28
+ catch {
29
+ layers = undefined;
30
+ }
31
+ return {
32
+ kind: 'present',
33
+ grants: v,
34
+ ...(layer !== undefined ? { layer } : {}),
35
+ ...(typeof layers === 'boolean' ? { layers } : {}),
36
+ };
24
37
  }
25
38
  if (v === null || typeof v !== 'object' || Array.isArray(v))
26
39
  return undefined;
@@ -61,6 +74,16 @@ export function allowRulesGate(reading, settingsRead) {
61
74
  return 'capability_off';
62
75
  return settingsRead === 'clean' ? 'open' : 'settings_read_not_clean';
63
76
  }
77
+ export function permissionRuleLayersOn(reading) {
78
+ try {
79
+ if (reading === null || typeof reading !== 'object' || Array.isArray(reading))
80
+ return false;
81
+ return ownDataField(reading, 'kind') === 'present' && ownDataField(reading, RULE_LAYERS_CAP_LEAF) === true;
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ }
64
87
  function ownReadingField(reading, key) {
65
88
  try {
66
89
  if (reading === null || typeof reading !== 'object' || Array.isArray(reading))