@sema-agent/client-core 0.110.0 → 0.112.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 (243) hide show
  1. package/CHANGELOG.md +244 -0
  2. package/README.md +59 -18
  3. package/dist/abortableSleep.d.ts +7 -0
  4. package/dist/abortableSleep.js +37 -0
  5. package/dist/adapt/arms.js +25 -4
  6. package/dist/adapt/toolCards.d.ts +3 -1
  7. package/dist/adapt/toolCards.js +4 -2
  8. package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
  9. package/dist/adapter/activeRunSelfHeal.js +171 -3
  10. package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
  11. package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
  12. package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
  13. package/dist/adapter/runStream.d.ts +5 -0
  14. package/dist/adapter/runStream.js +15 -3
  15. package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
  16. package/dist/attachmentRoute.d.ts +20 -0
  17. package/dist/attachmentRoute.js +39 -0
  18. package/dist/attachmentsWireCaps.js +1 -1
  19. package/dist/builtinOutputStyles.d.ts +12 -0
  20. package/dist/builtinOutputStyles.js +147 -0
  21. package/dist/checkpointRowVerdict.d.ts +3 -0
  22. package/dist/checkpointRowVerdict.js +14 -1
  23. package/dist/compactionStatus.d.ts +9 -0
  24. package/dist/compactionStatus.js +29 -5
  25. package/dist/consoleCaPin.d.ts +136 -0
  26. package/dist/consoleCaPin.js +827 -0
  27. package/dist/controlRouter.js +2 -1
  28. package/dist/coreValuePorts.d.ts +39 -1
  29. package/dist/coreValuePorts.js +10 -0
  30. package/dist/decideReceipt.d.ts +2 -1
  31. package/dist/deviceRebind.js +3 -3
  32. package/dist/displayUntrusted.d.ts +1 -0
  33. package/dist/displayUntrusted.js +6 -0
  34. package/dist/effectiveFacts.d.ts +9 -0
  35. package/dist/effectiveFacts.js +33 -0
  36. package/dist/engineAddress.d.ts +1 -0
  37. package/dist/engineAddress.js +4 -1
  38. package/dist/engineCredentialRelease.d.ts +54 -0
  39. package/dist/engineCredentialRelease.js +146 -0
  40. package/dist/engineErrorCodes.d.ts +1 -0
  41. package/dist/engineErrorCodes.js +1 -0
  42. package/dist/engineHealthProbeVerdict.d.ts +24 -0
  43. package/dist/engineHealthProbeVerdict.js +123 -0
  44. package/dist/engineNoticeCodes.js +5 -7
  45. package/dist/engineRepoint.d.ts +12 -5
  46. package/dist/engineRepoint.js +44 -19
  47. package/dist/engineRowRef.d.ts +3 -0
  48. package/dist/engineRowRef.js +11 -1
  49. package/dist/engineSwapCrossing.d.ts +57 -0
  50. package/dist/engineSwapCrossing.js +297 -0
  51. package/dist/engineUnavailable.d.ts +45 -0
  52. package/dist/engineUnavailable.js +496 -0
  53. package/dist/engineUrl.js +4 -2
  54. package/dist/eventLeg.js +3 -3
  55. package/dist/gateFailureCodes.js +2 -2
  56. package/dist/generated/sdkFactTables.d.ts +2 -1
  57. package/dist/generated/sdkFactTables.js +14 -0
  58. package/dist/generated/settingsSchemaFns.d.ts +1 -0
  59. package/dist/generated/settingsSchemaFns.js +3 -0
  60. package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
  61. package/dist/generated/settingsSchemaTables.d.ts +56 -0
  62. package/dist/generated/settingsSchemaTables.js +19 -0
  63. package/dist/generated/settingsSchemaTypes.d.ts +23 -13
  64. package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
  65. package/dist/generated/settingsSchemaUrlShape.js +17 -0
  66. package/dist/hitl/approvalDelivery.d.ts +1 -0
  67. package/dist/hitl/approvalDelivery.js +1 -1
  68. package/dist/hitl/approvalResolution.d.ts +1 -1
  69. package/dist/hitl/approvalResolution.js +2 -1
  70. package/dist/hitl/askGateWire.js +5 -6
  71. package/dist/hitl/decisionRefusal.d.ts +6 -0
  72. package/dist/hitl/decisionRefusal.js +19 -10
  73. package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
  74. package/dist/hitl/decisionRefusalCarrier.js +348 -0
  75. package/dist/hitl/decisionSend.d.ts +7 -0
  76. package/dist/hitl/decisionSend.js +34 -12
  77. package/dist/hitl/editedApprovalAcceptance.js +1 -1
  78. package/dist/hitl/elicitationRefusal.d.ts +4 -0
  79. package/dist/hitl/elicitationRefusal.js +23 -0
  80. package/dist/hitl/frameRouter.d.ts +2 -2
  81. package/dist/hitl/frameRouter.js +8 -15
  82. package/dist/hitl/gateIdentity.d.ts +5 -0
  83. package/dist/hitl/gateIdentity.js +23 -0
  84. package/dist/hitl/hitlBridge.d.ts +6 -0
  85. package/dist/hitl/hitlBridge.js +10 -4
  86. package/dist/hitl/hitlHostSurface.d.ts +2 -1
  87. package/dist/hitl/hitlHostSurface.js +7 -2
  88. package/dist/hitl/localAllowRedemption.d.ts +70 -0
  89. package/dist/hitl/localAllowRedemption.js +276 -0
  90. package/dist/hitl/parkOwnership.js +2 -1
  91. package/dist/hitl/parkResolver.js +14 -4
  92. package/dist/hitl/persistedRulesWire.d.ts +16 -0
  93. package/dist/hitl/persistedRulesWire.js +70 -0
  94. package/dist/hitl/planReviewWire.d.ts +3 -0
  95. package/dist/hitl/planReviewWire.js +23 -6
  96. package/dist/hitl/policyDenyCause.d.ts +1 -1
  97. package/dist/hitl/policyDenyCause.js +1 -1
  98. package/dist/hitl/resumeRunningCard.d.ts +1 -0
  99. package/dist/hitl/resumeRunningCard.js +1 -0
  100. package/dist/hitl/screenCardCarriers.d.ts +15 -0
  101. package/dist/hitl/screenCardCarriers.js +41 -0
  102. package/dist/hitl/screenDecisionCards.d.ts +98 -0
  103. package/dist/hitl/screenDecisionCards.js +363 -0
  104. package/dist/hitl/sessionPolicyWire.js +2 -2
  105. package/dist/hitl/standingRows.d.ts +6 -2
  106. package/dist/hitl/standingRows.js +27 -2
  107. package/dist/hitl/toolApprovalWire.d.ts +30 -8
  108. package/dist/hitl/toolApprovalWire.js +264 -121
  109. package/dist/hooksReaderGenerations.js +1 -1
  110. package/dist/hooksWireCaps.js +3 -3
  111. package/dist/hostSettingNoticeArm.d.ts +3 -0
  112. package/dist/hostSettingNoticeArm.js +12 -0
  113. package/dist/hostTurnSettings.d.ts +3 -0
  114. package/dist/hostTurnSettings.js +38 -5
  115. package/dist/humanTurnRead.js +11 -1
  116. package/dist/i18n/messages.en.d.ts +292 -0
  117. package/dist/i18n/messages.en.js +298 -7
  118. package/dist/i18n/messages.zh.js +316 -6
  119. package/dist/i18n/translate.d.ts +3 -0
  120. package/dist/i18n/translate.js +78 -10
  121. package/dist/i18n/zh.d.ts +1 -0
  122. package/dist/i18n/zh.js +1 -0
  123. package/dist/index.d.ts +71 -20
  124. package/dist/index.js +44 -13
  125. package/dist/interactiveHalt.js +2 -1
  126. package/dist/interactiveInterrupt.js +20 -2
  127. package/dist/liveModelCatalog.d.ts +4 -0
  128. package/dist/liveModelCatalog.js +12 -3
  129. package/dist/localConfig/documents.d.ts +61 -0
  130. package/dist/localConfig/documents.js +51 -0
  131. package/dist/localConfig/kernel.d.ts +149 -0
  132. package/dist/localConfig/kernel.js +597 -0
  133. package/dist/localConfig/mcp/edit.d.ts +161 -0
  134. package/dist/localConfig/mcp/edit.js +846 -0
  135. package/dist/localConfig/mcp/servers.d.ts +165 -0
  136. package/dist/localConfig/mcp/servers.js +776 -0
  137. package/dist/localConfig/mcp/views.d.ts +170 -0
  138. package/dist/localConfig/mcp/views.js +429 -0
  139. package/dist/localConfig/modelPool.d.ts +262 -0
  140. package/dist/localConfig/modelPool.js +1489 -0
  141. package/dist/localConfig/modelPoolWords.d.ts +13 -0
  142. package/dist/localConfig/modelPoolWords.js +20 -0
  143. package/dist/localConfig/receiptShape.d.ts +7 -0
  144. package/dist/localConfig/receiptShape.js +135 -0
  145. package/dist/localConfig/settingsWrite.d.ts +127 -0
  146. package/dist/localConfig/settingsWrite.js +237 -0
  147. package/dist/localConfig/skills.d.ts +124 -0
  148. package/dist/localConfig/skills.js +397 -0
  149. package/dist/localConfig/skillsWords.d.ts +10 -0
  150. package/dist/localConfig/skillsWords.js +5 -0
  151. package/dist/localEngineSeatReading.d.ts +2 -2
  152. package/dist/localEngineSeatReading.js +5 -3
  153. package/dist/localEngineSpawn.d.ts +0 -7
  154. package/dist/localEngineSpawn.js +0 -92
  155. package/dist/localEngineStep.d.ts +2 -2
  156. package/dist/localEngineStep.js +2 -0
  157. package/dist/mcpProbeWire.js +2 -1
  158. package/dist/mcpReconnect.js +3 -3
  159. package/dist/mcpWireCaps.js +1 -1
  160. package/dist/memoryVerbsWire.js +3 -2
  161. package/dist/model/engineModelWords.d.ts +3 -0
  162. package/dist/model/engineModelWords.js +13 -0
  163. package/dist/model/onboardJudgement.d.ts +14 -4
  164. package/dist/model/onboardJudgement.js +91 -139
  165. package/dist/model/subagentModelWord.d.ts +21 -2
  166. package/dist/model/subagentModelWord.js +100 -29
  167. package/dist/modelCapabilityProbe.js +3 -40
  168. package/dist/modelConfigGapNotice.d.ts +20 -0
  169. package/dist/modelConfigGapNotice.js +102 -0
  170. package/dist/modsKernelIdentity.js +2 -47
  171. package/dist/notifications.d.ts +19 -0
  172. package/dist/notifications.js +114 -12
  173. package/dist/ownKey.d.ts +7 -0
  174. package/dist/ownKey.js +71 -8
  175. package/dist/pendingUserRow.d.ts +4 -0
  176. package/dist/pendingUserRow.js +16 -0
  177. package/dist/permissionsDeclaration.d.ts +3 -1
  178. package/dist/permissionsDeclaration.js +33 -9
  179. package/dist/planReviewCardFacts.d.ts +3 -0
  180. package/dist/planReviewCardFacts.js +52 -2
  181. package/dist/pluginHooksWire.d.ts +9 -1
  182. package/dist/pluginHooksWire.js +40 -6
  183. package/dist/printToolResultFrame.js +4 -2
  184. package/dist/promptBlockedCopy.js +12 -7
  185. package/dist/promptSuggestionBatch.d.ts +7 -0
  186. package/dist/promptSuggestionBatch.js +9 -0
  187. package/dist/promptSuggestionsTail.d.ts +39 -0
  188. package/dist/promptSuggestionsTail.js +116 -0
  189. package/dist/request/taskRequest.js +10 -6
  190. package/dist/requestCoordinate.d.ts +1 -0
  191. package/dist/requestCoordinate.js +13 -0
  192. package/dist/resumeRefusalCopy.d.ts +3 -1
  193. package/dist/resumeRefusalCopy.js +12 -4
  194. package/dist/rewindArchiveReading.js +4 -4
  195. package/dist/runCancelContext.d.ts +2 -1
  196. package/dist/runCancelContext.js +1 -0
  197. package/dist/runLedgerSnapshot.js +3 -3
  198. package/dist/runPermissionModeSwitch.js +3 -4
  199. package/dist/scenarioRefusal.js +11 -13
  200. package/dist/scenarioSkills.js +11 -6
  201. package/dist/seam.d.ts +16 -2
  202. package/dist/seam.js +10 -0
  203. package/dist/seatContract.d.ts +259 -9
  204. package/dist/seatContract.js +444 -15
  205. package/dist/sessionCostReading.d.ts +70 -0
  206. package/dist/sessionCostReading.js +150 -0
  207. package/dist/sessionHooksRoster.d.ts +4 -0
  208. package/dist/sessionHooksRoster.js +158 -0
  209. package/dist/sessionIdSegment.d.ts +1 -0
  210. package/dist/sessionIdSegment.js +4 -1
  211. package/dist/sessionMemoryErase.js +2 -1
  212. package/dist/sessionMemoryStatus.js +2 -2
  213. package/dist/sessionReadRedaction.d.ts +7 -0
  214. package/dist/sessionReadRedaction.js +26 -0
  215. package/dist/sessionSyncFileHistory.js +8 -9
  216. package/dist/settingsHooksSalvage.js +2 -1
  217. package/dist/sha256Bytes.d.ts +1 -0
  218. package/dist/sha256Bytes.js +46 -0
  219. package/dist/skillOverrideChain.d.ts +83 -0
  220. package/dist/skillOverrideChain.js +378 -0
  221. package/dist/skillsWireCaps.d.ts +3 -0
  222. package/dist/skillsWireCaps.js +16 -1
  223. package/dist/sseIdleTriage.js +2 -1
  224. package/dist/storeDurabilityWord.d.ts +15 -0
  225. package/dist/storeDurabilityWord.js +18 -0
  226. package/dist/storePostureCapability.d.ts +7 -3
  227. package/dist/storePostureCapability.js +69 -39
  228. package/dist/subagent/engineSubagentResume.js +2 -2
  229. package/dist/subagent/engineSubagentTail.js +2 -1
  230. package/dist/subagentContentStore.d.ts +11 -0
  231. package/dist/subagentContentStore.js +28 -2
  232. package/dist/toolResult.d.ts +1 -0
  233. package/dist/toolResult.js +2 -0
  234. package/dist/turnFailurePresentation.js +4 -10
  235. package/dist/userAttachmentEnvelope.d.ts +2 -1
  236. package/dist/userAttachmentEnvelope.js +10 -0
  237. package/dist/wireErrorTriage.js +2 -1
  238. package/dist/wireFailureShape.d.ts +4 -0
  239. package/dist/wireFailureShape.js +141 -19
  240. package/dist/wireRefusalCopy.d.ts +6 -5
  241. package/dist/wireRefusalCopy.js +49 -92
  242. package/docs/INTEGRATION-CLIENTS.md +2718 -17
  243. package/package.json +7 -3
@@ -115,6 +115,13 @@ const EN = {
115
115
  'model.subagent.chainUnbound': "Subagent model {word} is not bound on this engine (neither it nor any tier below it has a model) — the subagent will run on its parent's model.",
116
116
  'model.subagent.bindingNotInCatalog': "Subagent model {word} is bound to a model that is not in this engine's model catalog — the subagent will run on its parent's model.",
117
117
  'model.subagent.ambiguous': "Subagent model {word} matches more than one model name that differ only in case — spell it exactly; the subagent will run on its parent's model.",
118
+ 'model.subagent.call.ambiguous': "Subagent model {word} can't be used for this call: it matches more than one model name that differ only in case — spell it exactly.",
119
+ 'model.subagent.call.tiersInert': "Subagent model {word} can't be used for this call: it is a tier word, but this engine has no model tiers configured.",
120
+ 'model.subagent.call.chainUnbound': "Subagent model {word} can't be used for this call: it maps to tier {tier}, which has no model bound on this engine (nor does any tier below it).",
121
+ 'model.subagent.call.bindingNotInCatalog': "Subagent model {word} can't be used for this call: its tier {tier} is bound to a model that is not in this engine's model catalog.",
122
+ 'model.subagent.refused.notListed': "Subagent model {word} is not a model name, tier word or model id on this engine, so this agent is left out of the request (the engine refuses any request that carries it) — change the agent's model, or set it to `inherit`.",
123
+ 'model.subagent.refused.notServed': "Subagent model {word} has no model behind it on this engine, so this agent is left out of the request (the engine refuses any request that carries it) — change the agent's model, or set it to `inherit`.",
124
+ 'model.subagent.refused.disabled': "Subagent model {word} is disabled on this engine, so this agent is left out of the request (the engine refuses any request that carries it) — change the agent's model, or set it to `inherit`.",
118
125
  'model.catalogDefault.refused.named': 'A task that names no model would be refused: the engine cannot resolve a default model from its model configuration (the settings default is {name}) · Set a default model the engine can run, or add or fix one',
119
126
  'model.catalogDefault.refused.select': 'A task that names no model would be refused: the engine cannot resolve a default model from its model configuration (the settings default is a selection) · Change the selection, or add or fix a model the engine can run',
120
127
  'session.sync.pushRowBitsWriterSide': 'The session was pushed · At the destination it is a read-only mirror, so its title and pin stay with the side that writes it and were not changed there',
@@ -147,8 +154,11 @@ const EN = {
147
154
  'session.mcpReconnect.undeclared': 'This run declared no MCP servers, so there is nothing to re-dial ({server} is not part of this run){why}',
148
155
  'session.mcpReconnect.unsettled': "The MCP re-dial did not settle within the time this request waits, so there is no result yet: the re-dial was not cancelled and may still be running. Check the server's state before re-dialing it again — a second request that arrives after the dial has settled closes the connection and dials once more.",
149
156
  'session.mcpReconnect.reasonTail': ' — {reason}',
157
+ 'session.mcpReconnect.transaction': 'Reconnecting closes the current connection before dialing again. On a healthy server this is a transaction, not a refresh: a failed re-dial leaves the server down and withdraws its tools from the model until a later re-dial succeeds.',
150
158
  'session.mcpFailure.reauthorizeSuffix': ' (re-authorize)',
151
159
  'session.mcpFailure.serverDownSuffix': ' (the server is down)',
160
+ 'mcp.elicitation.refused.named': 'MCP server {server} asked for input through a form that cannot be shown here, so the request was declined.',
161
+ 'mcp.elicitation.refused.unnamed': 'An MCP server asked for input through a form that cannot be shown here, so the request was declined.',
152
162
  'config.cloudLogin.accessDenied': 'Sign-in was declined.',
153
163
  'config.cloudLogin.expiredToken': 'The sign-in code expired before it was approved — start again.',
154
164
  'config.cloudLogin.invalidGrant': 'The Cloud sign-in can no longer be renewed — sign in again.',
@@ -201,6 +211,20 @@ const EN = {
201
211
  'onboard.plan.envNotObject': 'The settings file has an "env" that is not an object — not rewriting it.',
202
212
  'onboard.plan.envCatalogPresent': 'The engine is serving "{model}" from environment settings and the catalog has no enabled model; a first catalog model would replace the environment models. Add them to the catalog first.',
203
213
  'onboard.input.keyInFields': 'The model ID / base URL contains the API key — check the fields.',
214
+ 'model.pool.add.duplicate': '"{model}" is listed twice in this batch with the same address — add it once.',
215
+ 'model.pool.add.probeFailed': 'The provider rejected "{model}" (key, model name or reply format) — fix it and check again.',
216
+ 'model.pool.add.probeUnverified': '"{model}" hasn\'t been checked against its provider (or the check couldn\'t finish) — check it again, or save it as unverified.',
217
+ 'model.pool.add.pinMoved': 'The model list changed while "{name}" was being saved (its name or stored key moved) — nothing was added. Try again.',
218
+ 'model.pool.notFound': 'There is no model named "{name}" in the model list.',
219
+ 'model.pool.importEnv.notYet': 'The engine is serving "{model}" from its environment settings. This app can\'t copy environment models into the model list yet — add them by hand (address and key) first, then add more.',
220
+ 'model.pool.tier.badGroup': 'A tier group name must start with a letter or digit and use only letters, digits, ".", "_" or "-".',
221
+ 'model.pool.tier.noGroup': 'There is no tier group named "{group}".',
222
+ 'model.pool.tier.groupExists': 'A tier group named "{group}" already exists.',
223
+ 'model.pool.channel.badPick': 'The picked profile or models were not found in what this app read from that source.',
224
+ 'model.pool.discover.status': 'The model list request answered HTTP {status}.',
225
+ 'model.pool.discover.notList': 'The endpoint did not answer with a model list.',
226
+ 'model.pool.discover.timeout': 'The model list request timed out.',
227
+ 'model.pool.discover.unreachable': 'The endpoint could not be reached: {cause}',
204
228
  'onboard.refusal.input': 'The model setup is incomplete or not in the expected shape — nothing was saved.',
205
229
  'onboard.refusal.probeFailed': 'The provider did not accept this setup — nothing was saved.',
206
230
  'onboard.refusal.probeUnverified': "The provider couldn't be checked, so nothing was saved — try again, or save it as unverified.",
@@ -221,9 +245,9 @@ const EN = {
221
245
  'config.mcp.transportsNone': 'none',
222
246
  'config.mcp.transportInvalid': 'MCP server {name}{where} was not started: its transport setting cannot be used — {path} {problem}. Fix that setting for this server (or remove the server); the other MCP servers are unaffected.',
223
247
  'config.mcp.transportDegraded': 'MCP server {name}{where} was started without part of its transport settings, which cannot be used as written: {lost}. The rest of its settings are applied; fix the settings named above to get them applied too.',
224
- 'config.mcp.toolAxesInvalid': 'MCP server {name}{where} was not started: its toolAxes setting is not valid — {problem}. Fix the toolAxes entry for this server (or remove it); the other MCP servers are unaffected.',
248
+ 'config.mcp.toolAxesInvalid': 'MCP server {name}{where} was started to read its tool list and then dropped: its toolAxes setting is not valid — {problem}. Fix the toolAxes entry for this server (or remove it); the other MCP servers are unaffected.',
225
249
  'config.mcp.toolAxesFallbackProblem': 'the declaration is not a valid set of per-tool safety settings',
226
- 'config.mcp.toolFacesInvalid': 'MCP server {name}{where} was not started: its toolFaces setting is not valid — {problem}. Fix the toolFaces entry for this server (or remove it); the other MCP servers are unaffected.',
250
+ 'config.mcp.toolFacesInvalid': 'MCP server {name}{where} was started to read its tool list and then dropped: its toolFaces setting is not valid — {problem}. Fix the toolFaces entry for this server (or remove it); the other MCP servers are unaffected.',
227
251
  'config.mcp.toolFacesFallbackProblem': 'the declaration is not a valid set of per-tool display and approval settings',
228
252
  'config.mcp.toolFacesUnreadable': 'the setting could not be read (a getter or proxy trap on it threw)',
229
253
  'config.mcp.elicitationInvalid': 'MCP server {name}{where} was not started: its elicitation setting must be true or false. Fix the elicitation entry for this server (or remove it); the other MCP servers are unaffected.',
@@ -232,7 +256,7 @@ const EN = {
232
256
  'config.mcp.entryNotObjectProblem': 'the entry is not an object (an object with a command or a url is expected)',
233
257
  'config.mcp.transportTypeUnsupported': 'this transport type cannot be carried on the request (only stdio and http are supported)',
234
258
  'config.mcp.transportIdentityBothSetProblem': 'both principalHeader and assertionHeader are set, and they name the same identity header — keep only one of the two',
235
- 'config.mcp.allowToolsInvalid': 'MCP server {name}{where} was not started: its allowTools setting cannot be used — {problem}. Fix the allowTools entry for this server (a list of tool-name strings); the other MCP servers are unaffected.',
259
+ 'config.mcp.allowToolsInvalid': 'MCP server {name}{where} was started to read its tool list and then dropped: its allowTools setting cannot be used — {problem}. Fix the allowTools entry for this server (a list of tool-name strings); the other MCP servers are unaffected.',
236
260
  'config.mcp.allowToolsNotArray': '{path} must be an array of strings (got {got})',
237
261
  'config.mcp.allowToolsElementNotString': '{path} must be a string (got {got})',
238
262
  'config.mcp.allowToolsHole': '{path} is missing: a list with gaps is not allowed, every position must hold a string',
@@ -281,6 +305,7 @@ const EN = {
281
305
  'approval.rowUnresumable.askNotSurfaced': 'the pending row (task {taskId}) cannot be continued by this engine, so it is not surfaced as a card that can be answered: {sentence}',
282
306
  'approval.park.stillParked': '{gate} gate could not be answered: {reason} — the run is still parked on this approval.',
283
307
  'approval.park.refusedNotResumable': '{gate} gate could not be answered: {reason} — this engine cannot resume this approval as things stand; cancel the run if it is still parked.',
308
+ 'approval.park.newerWorker': '{gate} gate could not be answered: {reason} — the run is still parked on this approval, but {wayOut}.',
284
309
  'approval.park.resume.card': '{gate} gate could not be answered: {reason} — the run is still parked on this approval: decide it on the card when it is shown again, or cancel the run.',
285
310
  'approval.park.resume.speak': '{gate} gate could not be answered: {reason} — the run is still parked on this approval: send a message to reopen the card, then decide it there, or cancel the run.',
286
311
  'approval.park.argsFromModelCall': "the pending approval record has no tool arguments that will run, so the arguments shown are the model's original call from the conversation — if they were changed after that call (for example by a hook), what runs differs from what is shown. Edits are not accepted on this card: the arguments shown are not the ones that will run",
@@ -288,14 +313,17 @@ const EN = {
288
313
  'approval.policyDeny.denyRule': 'Permission for this tool use was denied by a deny rule in the permission settings. {tail}',
289
314
  'approval.policyDeny.dontAsk': 'Permission for this tool use was denied: this session no longer asks for approval, so a call that would need approval is refused. {tail}',
290
315
  'approval.policyDeny.engineFloor': 'Permission for this tool use was denied by a safeguard on the engine side that permission settings cannot override. {tail}',
316
+ 'approval.policyDeny.hook': 'Permission for this tool use was denied by a PermissionRequest hook. The action was NOT performed. Do not claim it succeeded, and do not retry it unchanged — report what was blocked, or suggest an alternative.',
291
317
  'approval.policyDeny.tail': 'The action was NOT performed. Do not claim it succeeded, and do not retry it in this session — report the limitation to the user, or suggest an alternative.',
292
318
  'approval.decision.grantChanged': 'The engine refused this approval because the skill grant it was bound to has changed since the card was shown · Nothing was decided and the request is still waiting, but approving it again will be refused the same way · Deny this request so the model can activate the skill again',
293
319
  'approval.decision.answerInvalid': 'The engine rejected the answer itself because it does not fit the question that was asked · Nothing was decided and the question is still waiting · Correct the answer and send it again',
294
- 'approval.editRefusal.line': 'That approval was NOT sent: this request does not expose its tool arguments here, so an edited approval cannot be applied. ' +
295
- 'The request is still waiting — approve or deny it as it is.',
320
+ 'approval.editRefusal.stem': 'this request does not expose its tool arguments here, so an edited approval cannot be applied',
321
+ 'approval.editRefusal.line': 'That approval was NOT sent: {stem}. The request is still waiting — approve or deny it as it is.',
322
+ 'approval.editRefusal.parkReason': 'the card returned an edited approval, but {stem} — nothing was sent (the arguments are missing from the pending approval record, or replaced there by a size marker); approve or deny it as it is',
296
323
  'approval.decision.settledElsewhereContrary.deniedFirst': 'This request was already answered elsewhere and denied, so your approval did not take effect.',
297
324
  'approval.decision.settledElsewhereContrary.approvedFirst': 'This request was already answered elsewhere and approved, so your denial did not take effect.',
298
325
  'approval.decision.unconfirmedAfterRetry': "It is not known whether your answer took effect: an earlier attempt to send it was not confirmed, and by the time it was sent again the request was no longer waiting · Check the task's current state before acting on it",
326
+ 'approval.decideAck.unconfirmed': "It is not known whether your answer took effect · Check the request's current state before answering it again",
299
327
  'notice.decide.rowUnrevivable': 'The engine can no longer recover this approval card, so neither approving nor denying it will take effect · The card can only be cleared on the server side — wait for that, or contact whoever operates the engine',
300
328
  'approval.askPark.autoReopenBlocked.policyInteractive': "The engine's admission policy refused to resume this parked step (run {run}), so sema will not put its card back on screen by itself. Switch to a permission mode this deployment allows, or ask whoever operates the deployment, then send a message to bring the card back.",
301
329
  'approval.askPark.autoReopenBlocked.policyPrint': "The engine's admission policy refused to resume this parked step (run {run}), so sema will not put its card back on screen by itself. Switch to a permission mode this deployment allows, or ask whoever operates the deployment, then send a message to bring the card back; or stop the run ({cancel}).",
@@ -420,6 +448,9 @@ const EN = {
420
448
  'resume.refusal.park.printHolds': '{head}{configMayReturn} The parked run still holds this session ({code}): cancel it ({cancel}), then submit the work again as a new task.{blocked}',
421
449
  'resume.refusal.park.interactiveEnded': '{head} The engine ended that parked run, so this conversation is free: send the work again as a new message.',
422
450
  'resume.refusal.park.interactiveBusy': '{head}{configMayReturn} The parked run keeps this conversation busy until it is cancelled.',
451
+ 'resume.refusal.park.whyNewerEngine': 'it was parked by a newer engine version than this one',
452
+ 'resume.refusal.park.interactiveNewerWorker': '{head}{configMayReturn} The parked run still holds this conversation, but {wayOut}.',
453
+ 'resume.refusal.park.printNewerWorker': '{head}{configMayReturn} The parked run still holds this session ({code}), but {wayOut} ({cancel}).{blocked}',
423
454
  'resume.refusal.park.blockedPrint': 'sema will not put the card for run {run} back on screen by itself: this engine version refuses to resume it. Cancel the run ({cancel}) and submit the work again as a new task.',
424
455
  'resume.refusal.park.blockedInteractive': 'sema will not put the card for run {run} back on screen by itself: this engine version refuses to resume it. To free this conversation, send a message — sema then offers to cancel that run (if the card comes back instead, answer it first), after which you can send the work again as a new message.',
425
456
  'session.selfHeal.wayOut.interactive': 'run /clear to keep working in a fresh session',
@@ -461,6 +492,9 @@ const EN = {
461
492
  'session.selfHeal.injected.notDelivered': '{lead} was not delivered: this session was still busy with an earlier reply{id}, and there was no open card you could answer to free it{noView}. sema did not retry, so the model has not seen it.',
462
493
  'session.selfHeal.injected.redundant': '{lead} was not passed on: the reply it was about{id} resumed on its own after that decision, so it has nothing to add.',
463
494
  'session.selfHeal.injected.deferred': '{lead} is waiting: this session is busy with an earlier reply{id}, so sema kept the message and will send it as a new message once that reply has finished or paused.',
495
+ 'session.selfHeal.injected.resendWithheldLeftConfirmed': '{lead} was not delivered: the earlier reply{id} let go of the conversation the message was meant for, but this screen switched to another conversation before sema could send it, and sema does not send it into a different conversation — the model has not seen it.',
496
+ 'session.selfHeal.injected.resendWithheldUnconfirmed': '{lead} was not delivered: sema could not confirm that this screen is still on the conversation it was meant for, so it did not send it — the model has not seen it.',
497
+ 'session.selfHeal.injected.resendWithheldLeftInferred': '{lead} was not delivered: the earlier reply{id} is now reported as finished in the conversation the message was meant for, but this screen switched to another conversation before sema could send it, and sema does not send it into a different conversation — the model has not seen it.',
464
498
  'session.selfHeal.decisionInFlight': 'The previous turn is parked {parkedOn} and your answer to that card is still on its way to the engine, so sema did not show the card again — answering it a second time would send a second decision. It did NOT cancel the run. Your message was NOT sent; send it again in a moment, once the engine has applied that decision.',
465
499
  'session.selfHeal.parkedOn.ask': 'waiting for your decision (run {taskId})',
466
500
  'session.selfHeal.parkedOn.plan': 'on a plan review (run {taskId})',
@@ -500,6 +534,17 @@ const EN = {
500
534
  'session.selfHeal.row.attach': '{disclosure} Your message was NOT sent; send it again once that run has finished.',
501
535
  'session.selfHeal.row.cancelled.confirmed': 'You chose to cancel run {taskId}. The engine confirmed it is no longer holding this session, so sema is sending your message now.',
502
536
  'session.selfHeal.row.cancelled.reported': 'You chose to cancel run {taskId}. The engine now reports that run as finished, so sema is sending your message now; if that run has not fully let go of the session yet, you may have to send it once more.',
537
+ 'session.selfHeal.row.resendWithheldLeft.confirmed': 'Your message was NOT sent: run {taskId} no longer holds the conversation you typed it in, but this screen switched to another conversation before sema could send it again, and sema does not send a message into a different conversation. Switch back to that conversation and send it again if you still want it.',
538
+ 'session.selfHeal.row.resendWithheldLeft.reported': 'Your message was NOT sent: run {taskId} is now reported as finished in the conversation you typed it in, but this screen switched to another conversation before sema could send it again, and sema does not send a message into a different conversation. Switch back to that conversation and send it again if you still want it (if that run has not fully let go of it yet, you may have to send it once more).',
539
+ 'session.selfHeal.row.resendWithheldUnconfirmed': 'Your message was NOT sent: sema could not confirm that this screen is still on the conversation you typed it in, so it did not send it again — sending a message into a different conversation would be worse than not sending it. If this is still that conversation, send it again.',
540
+ 'session.selfHeal.stopLeft.untouched': 'sema left run {taskId} alone: this screen switched to another conversation while sema was checking that run, and sema does not end a run for a conversation that is no longer on screen. That run may still hold the conversation it belongs to — switch back to that conversation, then {endRun}.',
541
+ 'session.selfHeal.stopLeft.waiting.certain': 'Run {taskId} is waiting on a decision from you in the conversation it belongs to, and sema does not end a run that is waiting for your answer. This screen has switched to another conversation since — switch back to that conversation to answer it.',
542
+ 'session.selfHeal.stopLeft.waiting.uncertain': 'Run {taskId} may be waiting on a decision from you in the conversation it belongs to — sema could not confirm that it is not — so sema left it alone. This screen has switched to another conversation since — switch back to that conversation to answer it; if nothing is waiting there, {endRun}.',
543
+ 'session.selfHeal.stopLeft.ended.confirmed': 'Run {taskId} has ended — the engine confirmed it no longer holds the conversation it belongs to. This screen has switched to another conversation since — switch back to that conversation to send your message again.',
544
+ 'session.selfHeal.stopLeft.ended.reported': 'Run {taskId} has ended — the engine reports it finished. This screen has switched to another conversation since — switch back to that conversation to send your message again.',
545
+ 'session.selfHeal.stopLeft.nothingToEnd': 'Run {taskId} had already finished, so there was nothing to end. This screen has switched to another conversation since — switch back to that conversation to send your message again.',
546
+ 'session.selfHeal.stopLeft.refused': 'sema could not end run {taskId}: the engine refused ({detail}), so nothing was ended. This screen has switched to another conversation since — switch back to the conversation that run belongs to and try again there: {endRun}.',
547
+ 'session.selfHeal.stopLeft.notConfirmed': 'sema could not confirm that run {taskId} has let go of the conversation it belongs to, and this screen has switched to another conversation since. Switch back to that conversation to check there; to end it, {endRun}.',
503
548
  'session.selfHeal.row.cancelTimeout.aborted': 'sema asked the engine to cancel run {taskId} and you interrupted while it was still confirming ({waited} in). Cancelling is asynchronous, so that run may still be winding down and may still hold this session. Your message was NOT sent; send it again in a moment, or {wayOut}.',
504
549
  'session.selfHeal.row.cancelTimeout.unread': "sema asked the engine to cancel run {taskId} but could not read that run's state back within {waited}, so it cannot confirm whether the session was released. Your message was NOT sent; send it again in a moment (if that run really is gone it will just run), or {wayOut}.",
505
550
  'session.selfHeal.row.cancelTimeout.held': 'sema asked the engine to cancel run {taskId}, but that run still held this session {waited} later — cancelling is asynchronous and it may still be winding down. Your message was NOT sent; send it again in a moment, or {wayOut}.',
@@ -660,6 +705,21 @@ const EN = {
660
705
  'session.hostSettings.styleSafeMode': 'Safe mode is on, so the output style from your settings is not applied.',
661
706
  'session.hostSettings.styleOversize': 'Your output style was not applied to this request: together with the built-in product context it is longer than the {limit}-character limit. Shorten the style to apply it.',
662
707
  'session.hostSettings.styleUnreadable': 'Your output style could not be read as text, so it is not applied to this request.',
708
+ 'session.hostSettings.allowKept.managed.inProgress.one': '{held} permissions.allow rule was not sent to the engine for this run because the managed policy for your account has not been received yet (sema keeps fetching it; allow rules apply once it arrives). Run again once it has been received (deny and ask rules, and rules given with --allowedTools, are still sent).',
709
+ 'session.hostSettings.allowKept.managed.inProgress.other': '{held} permissions.allow rules were not sent to the engine for this run because the managed policy for your account has not been received yet (sema keeps fetching it; allow rules apply once it arrives). Run again once it has been received (deny and ask rules, and rules given with --allowedTools, are still sent).',
710
+ 'session.hostSettings.allowKept.managed.failed.one': '{held} permissions.allow rule was not sent to the engine for this run because the managed policy for your account has not been received yet (this run will not fetch again; the next run retries). Run again to retry fetching it (deny and ask rules, and rules given with --allowedTools, are still sent).',
711
+ 'session.hostSettings.allowKept.managed.failed.other': '{held} permissions.allow rules were not sent to the engine for this run because the managed policy for your account has not been received yet (this run will not fetch again; the next run retries). Run again to retry fetching it (deny and ask rules, and rules given with --allowedTools, are still sent).',
712
+ 'session.hostSettings.allowKept.managed.unknown.one': '{held} permissions.allow rule was not sent to the engine for this run because the managed policy for your account has not been received yet. Run again once it has been received (deny and ask rules, and rules given with --allowedTools, are still sent).',
713
+ 'session.hostSettings.allowKept.managed.unknown.other': '{held} permissions.allow rules were not sent to the engine for this run because the managed policy for your account has not been received yet. Run again once it has been received (deny and ask rules, and rules given with --allowedTools, are still sent).',
714
+ 'session.hostSettings.allowKept.generic.one': '{held} permissions.allow rule was not sent to the engine for this run because {why}; an allow rule from a settings file is only sent from a settings read with no problems. Fix the reported settings, then run again (deny and ask rules from this read, and rules given with --allowedTools, are still sent).',
715
+ 'session.hostSettings.allowKept.generic.other': '{held} permissions.allow rules were not sent to the engine for this run because {why}; an allow rule from a settings file is only sent from a settings read with no problems. Fix the reported settings, then run again (deny and ask rules from this read, and rules given with --allowedTools, are still sent).',
716
+ 'session.hostSettings.allowKept.why.problems': 'the settings read reported problems',
717
+ 'session.hostSettings.allowKept.why.problemsWhere': 'the settings read reported problems ({where})',
718
+ 'session.hostSettings.allowKept.why.counted.one': 'the settings read reported {count} problem',
719
+ 'session.hostSettings.allowKept.why.counted.other': 'the settings read reported {count} problems',
720
+ 'session.hostSettings.allowKept.why.countedWhere.one': 'the settings read reported {count} problem ({where})',
721
+ 'session.hostSettings.allowKept.why.countedWhere.other': 'the settings read reported {count} problems ({where})',
722
+ 'session.hostSettings.allowKept.why.unreadable': 'the health of this settings read could not be checked',
663
723
  'model.identity.lane.processEnv': 'the environment this client was started with',
664
724
  'model.identity.lane.settingsEnv': "this client's settings file",
665
725
  'model.identity.lane.modelCatalogFile': 'the local model catalog file',
@@ -671,6 +731,24 @@ const EN = {
671
731
  'model.identity.catalogAdoption.refused': '{lane} lists models, but the engine is reported to refuse this catalog as written, so none of them can serve as its default',
672
732
  'model.identity.catalogAdoption.notResolvable': 'no model name is configured for the local engine to start with — {clause}, and the engine does not start without one',
673
733
  'model.identity.catalogAdoption.notResolvableWithPartial': 'no model name is configured for the local engine to start with — {clause}, and {partial}, and the engine does not start without one',
734
+ 'model.configGap.head.model': 'no model is configured yet',
735
+ 'model.configGap.head.gatewayUrl': 'no model gateway base URL is configured',
736
+ 'model.configGap.head.apiKey': 'no API key is configured',
737
+ 'model.configGap.head.anthropicKey': 'no Anthropic key is configured (ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN)',
738
+ 'model.configGap.head.incomplete': 'model configuration is incomplete',
739
+ 'model.configGap.item.model': 'the model name (MODEL_ID)',
740
+ 'model.configGap.item.gatewayUrl': 'the gateway base URL (MODEL_GATEWAY_BASEURL)',
741
+ 'model.configGap.item.apiKey': 'the API key (MODEL_API_KEY)',
742
+ 'model.configGap.item.anthropicKey': 'an Anthropic key (ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN)',
743
+ 'model.configGap.lead.one': '{a} is not configured',
744
+ 'model.configGap.lead.two': '{a} and {b} are not configured',
745
+ 'model.configGap.lead.three': '{a}, {b} and {c} are not configured',
746
+ 'model.configGap.reason.noModel': 'the engine does not start without a model name',
747
+ 'model.configGap.reason.anthropicCatalog.one': "the model catalog's only enabled entry is on the anthropic channel, so the engine cannot serve it",
748
+ 'model.configGap.reason.anthropicCatalog.other': "the model catalog's {count} enabled entries are all on the anthropic channel, so the engine cannot serve any of them",
749
+ 'model.configGap.reason.gatewayCatalog.one': "the model catalog's only enabled entry has no base URL of its own, so the engine cannot serve it",
750
+ 'model.configGap.reason.gatewayCatalog.other': "none of the model catalog's {count} enabled entries has a base URL of its own, so the engine cannot serve any of them",
751
+ 'model.configGap.detail.withReason': '{missing} — {reason}',
674
752
  'notice.injectionLane.sentence': "On this engine's {lane} lane the tools run on a different machine than the engine, so the {items} sent with a task run there rather than on this machine — any that rely on programs or credentials on this machine will fail there",
675
753
  'notice.injectionLane.item.stdioMcp': 'local stdio MCP servers',
676
754
  'notice.injectionLane.item.credentialedMcp': 'MCP servers that use credentials from this machine',
@@ -701,7 +779,7 @@ const EN = {
701
779
  'notice.durableGate.exit.other': 'To use durable approval, a checkpoint store has to be available.',
702
780
  'notice.durableGate.exitAlt.forceDurableGate': 'Or ask whoever runs the deployment to drop the requirement for this account.',
703
781
  'notice.durableGate.exitAlt.durableApproval': 'Or run the task where a live approver is attached.',
704
- 'notice.memory.sessionPolluted': 'Memory for this session is marked externally exposed ({reason}). From here on, memory it writes may be held back for review instead of being saved to the long-term library; what each batch actually held back is announced separately.',
782
+ 'notice.memory.sessionPolluted': 'A tool in this session can reach content from outside it ({reason}). From here on, memory it writes may be held back for review instead of being saved to the long-term library; what each batch actually held back is announced separately.',
705
783
  'notice.memory.harvestQuarantined.counts': 'Memory harvest held back entry files written or changed in this session instead of adding them to the long-term library — withheld {count}, moved aside for review {moved}, flagged for follow-up {escalated}; the last two counts can overlap.',
706
784
  'notice.memory.harvestQuarantined.indexOnly': "Memory harvest rolled this session's changes to the memory index back to where they started; no entry files were withheld.",
707
785
  'notice.memory.harvestQuarantined.indexAlso': 'The memory index was also rolled back.',
@@ -755,6 +833,8 @@ const EN = {
755
833
  'notice.sessionBox.idle.unavailable': '{peer} is unavailable.',
756
834
  'notice.sessionBox.idle.expired': '{peer} did not answer before the wait ran out.',
757
835
  'notice.sessionBox.idle.other': 'There is a status update from {peer}.',
836
+ 'notice.resupply.truncated.one': 'This notice was shortened: the full record is {bytes} bytes, over the notice size limit, so 1 field was left out. The full content can still be viewed in the run record.',
837
+ 'notice.resupply.truncated.other': 'This notice was shortened: the full record is {bytes} bytes, over the notice size limit, so {count} fields were left out. The full content can still be viewed in the run record.',
758
838
  'notice.peer.held.deliveredApproved': '{subject} was approved and delivered.',
759
839
  'notice.peer.held.deliveredRejudged': '{subject} was re-judged and delivered, because the policy now accepts it.',
760
840
  'notice.peer.held.droppedRejudged': '{subject} was approved, but the policy now refuses it, so it was dropped.',
@@ -912,6 +992,20 @@ const EN = {
912
992
  'notice.capability.mcpProbe.notReported': 'per-server MCP status face not reported by this engine — this says nothing about whether the face exists, so that path may not exist here (asking it may answer with a machine-readable route-not-found, though a timeout or an uncoded gateway answer says nothing either way); prefer the session panel last-leg roster where that panel carries one, and otherwise show this reason rather than an entry that cannot answer',
913
993
  'notice.capability.mcpProbe.absent': 'per-server MCP status face reported off on this deployment — this engine answers no readings there; this client does not guess why, and whether caller-supplied declarations are honored is a separate position with its own answer',
914
994
  'notice.capability.mcpProbe.present': 'per-server MCP status face on — this engine dials its own declared MCP servers on request, with no run, and a probe of caller-supplied declarations answers with the very same body shape',
995
+ 'notice.capability.subject.storePosture': 'store posture',
996
+ 'notice.capability.storePosture.unobserved': 'store posture not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it, so whether this deployment persists its state is unknown',
997
+ 'notice.capability.storePosture.notReported': 'store posture not reported by this engine; this does not say whether this deployment persists its state',
998
+ 'notice.capability.storePosture.assembled': 'store {backend}',
999
+ 'notice.capability.storePosture.assembledDeclared': 'store declared {declared}, running on {backend}',
1000
+ 'notice.capability.storePosture.durable': '{assembled} — durable: this replica persists its state, so it survives a restart',
1001
+ 'notice.capability.storePosture.notDurableHead': 'NOT durable',
1002
+ 'notice.capability.storePosture.memory': '{assembled} — {head}: this replica holds its state in memory and loses it on restart',
1003
+ 'notice.capability.storePosture.ephemeral': '{assembled} — {head}: the engine reports that this replica keeps state on storage that does not survive a restart',
1004
+ 'notice.capability.storePosture.unknown': "{assembled} — durability unknown: the engine reports that it cannot tell whether this replica's state survives a restart",
1005
+ 'notice.capability.storePosture.unrecognized': '{assembled} — durability unknown: the engine reported a durability word this client does not know yet: "{word}"',
1006
+ 'notice.capability.storePosture.degraded.dbUnreachable': '{line} (degraded: the declared database could not be opened at start-up, so the engine fell back rather than refusing to start)',
1007
+ 'notice.capability.storePosture.degraded.localUnwritable': '{line} (degraded: the default local file store could not be created — a read-only or full data directory is one possible cause, and this client cannot tell which applies)',
1008
+ 'notice.capability.storePosture.degraded.other': '{line} (degraded for a reason this client does not know yet: "{reason}")',
915
1009
  'notice.capability.hands.noneStem': 'this leg of the run was assembled with NO built-in file-and-shell tools',
916
1010
  'notice.capability.hands.noneTail': "so on this leg the model had no tool of the engine's own for editing files or running commands (tools mounted by other conditions, such as external servers, and sub-runs delegated to other legs are not covered by this reading)",
917
1011
  'notice.capability.hands.noneLine': '{stem} — {why}, {tail}',
@@ -1247,6 +1341,7 @@ const EN = {
1247
1341
  'config.hooks.plan.reason.closedUntrusted': 'this workspace is not trusted, so no hooks run in it',
1248
1342
  'config.hooks.plan.reason.closedGovernanceUnreadable': 'the managed policy could not be read, so no hooks run this turn',
1249
1343
  'config.hooks.plan.reason.closedDisableAll': 'managed settings turn off all hooks (disableAllHooks)',
1344
+ 'config.hooks.plan.reason.noExecutor': 'neither the engine nor this client runs this event',
1250
1345
  'config.hooks.plan.keyNotRead.oneKey': '{layer}: {hooks} will not run — the connected server does not read the key {coordinates}. Remove the key, or use a server that reads it.',
1251
1346
  'config.hooks.plan.keyNotRead.manyKeys': '{layer}: {hooks} will not run — the connected server does not read the keys {coordinates}. Remove those keys, or use a server that reads them.',
1252
1347
  'config.hooks.plan.keyNotRead.more': '{shown} and {rest} more',
@@ -1298,6 +1393,79 @@ const EN = {
1298
1393
  'config.mods.rewrite.inputBy': 'Arguments changed by {by} before the call was let through',
1299
1394
  'config.mods.session.unreadable': "The mods used by this conversation's last run couldn't be read",
1300
1395
  'config.mods.session.unarmed': 'Mods show up here once this conversation has run on this engine',
1396
+ 'config.hooks.roster.unreadable': "This conversation's hooks plan couldn't be read",
1397
+ 'config.hooks.roster.unarmed': 'Hooks show up here once this app has this conversation open',
1398
+ 'config.localConfig.refused.invalidRequest': 'The change could not be read as a valid request — nothing was saved.',
1399
+ 'config.localConfig.refused.scopeUnreadable': "The configuration file can't be read, so it was not overwritten — nothing was saved.",
1400
+ 'config.localConfig.refused.scopeUnwritable': "This setting can't be saved in that file — it would not take effect there. Nothing was saved.",
1401
+ 'config.localConfig.refused.untrustedFolder': "This folder isn't trusted, so its settings files can't carry this setting — nothing was saved.",
1402
+ 'config.localConfig.refused.policyDenied': "Your organization's managed settings don't allow this change — nothing was saved.",
1403
+ 'config.localConfig.refused.notFound': 'The item to change was not found — nothing was saved.',
1404
+ 'config.localConfig.refused.alreadyExists': 'That item already exists — nothing was saved.',
1405
+ 'config.localConfig.refused.lockBusy': 'Another program is changing this configuration right now — nothing was saved. Try again in a moment.',
1406
+ 'config.localConfig.refused.lockFailed': "The configuration file couldn't be locked for writing (a permission or folder problem) — the file was not changed.",
1407
+ 'config.localConfig.refused.changedDuringWrite': 'Another program changed this configuration while saving — nothing was saved. Try again.',
1408
+ 'config.localConfig.refused.writeFailed': "The configuration file couldn't be written — the file was not changed.",
1409
+ 'config.localConfig.refused.notWritten': 'The change was not saved.',
1410
+ 'config.localConfig.refused.skillLockedByHigherLayer': "A higher-priority configuration sets this skill's state; it cannot be changed here.",
1411
+ 'config.localConfig.refused.skillManagedByPlugin': 'A plugin skill is managed with the plugin, not here.',
1412
+ 'config.localConfig.refused.skillLockedByAuthor': "This skill's own file turns model invocation off; its state cannot be changed here.",
1413
+ 'config.localConfig.refused.skillNameUnstorable': "Settings can't store an entry with this skill's name; rename its folder or file to configure it.",
1414
+ 'config.localConfig.refused.entryInUse': 'That model is still in use (as the default model, by a role, or in an old tier setting) — point those at another model first. Nothing was saved.',
1415
+ 'config.localConfig.refused.credentialUnpaired': "That model couldn't be reached with the key or address it has — nothing was saved.",
1416
+ 'config.localConfig.refused.envCatalogPresent': 'The engine is using the models set in its environment; adding one here would take those out of use. Import the environment models first — nothing was saved.',
1417
+ 'config.localConfig.refused.probeFailed': 'The provider showed that a model in this change is set up wrong (key, model name or reply format) — nothing was saved.',
1418
+ 'config.localConfig.refused.probeUnverified': "A model in this change hasn't been checked against its provider (or the check couldn't finish) — nothing was saved. Check it again, or save it as unverified.",
1419
+ 'config.localConfig.unavailable.engineIsRemote': "The Cloud engine is in use — local configuration doesn't apply to it. Switch to the local engine first.",
1420
+ 'config.localConfig.unavailable.notSingleUser': "This engine isn't confirmed to serve only you, so local configuration isn't used with it.",
1421
+ 'config.localConfig.unavailable.configHomeUnpinned': "This app hasn't settled which configuration folder to use, so local configuration is neither shown nor changed.",
1422
+ 'config.localConfig.unavailable.domainNotHosted': "This app doesn't offer this kind of configuration change on this device yet.",
1423
+ 'config.localConfig.unknown.commitUnconfirmed': "It isn't certain whether the change was saved — refresh to check.",
1424
+ 'config.localConfig.unknown.reportUnreadable': "The app's answer after saving couldn't be read, so it isn't certain whether the change was saved — refresh to check.",
1425
+ 'config.localConfig.applied.nextTurn': 'Saved. It takes effect from the next turn.',
1426
+ 'config.localConfig.applied.engineReload': 'Saved. The engine picks it up when it next reloads its configuration, usually within a minute.',
1427
+ 'config.localConfig.applied.nextEngineStart': 'Saved. It takes effect the next time the local engine starts.',
1428
+ 'config.localConfig.applied.unchanged': 'Already set this way — nothing needed to change.',
1429
+ 'config.localConfig.preview.nextTurn': 'Not saved yet. Once saved, it takes effect from the next turn.',
1430
+ 'config.localConfig.preview.engineReload': 'Not saved yet. Once saved, the engine picks it up when it next reloads its configuration.',
1431
+ 'config.localConfig.preview.nextEngineStart': 'Not saved yet. Once saved, it takes effect the next time the local engine starts.',
1432
+ 'config.localConfig.preview.unchanged': 'Already set this way — saving would change nothing.',
1433
+ 'config.localConfig.residue.orphanKeySlot': 'A stored key slot was left with no model using it; it does nothing.',
1434
+ 'config.localConfig.residue.legacyTierGroupsLeft': 'The old tier settings were left in the settings file; they are no longer used.',
1435
+ 'config.localConfig.disclosure.decidedBy': 'The setting in effect comes from {layer}.',
1436
+ 'config.localConfig.disclosure.shadowed': 'This setting is overridden by {layer}, so it has no effect for now.',
1437
+ 'config.localConfig.disclosure.tierGroupOverridden': 'Some tier groups in your old settings share a name with groups already in {layer}; the ones in {layer} were kept and the old ones were not copied over.',
1438
+ 'config.localConfig.disclosure.tierGroupOverriddenNamed': 'These tier groups in your old settings share a name with groups already in {layer}; the ones in {layer} were kept and the old ones were not copied over: {names}.',
1439
+ 'config.localConfig.layer.userSettings': 'your user settings',
1440
+ 'config.localConfig.layer.projectSettings': "this project's shared settings",
1441
+ 'config.localConfig.layer.localSettings': "this project's local settings",
1442
+ 'config.localConfig.layer.globalConfig': "this app's state file",
1443
+ 'config.localConfig.layer.projectMcp': "this project's MCP server file",
1444
+ 'config.localConfig.layer.models': 'the model catalog',
1445
+ 'config.localConfig.layer.deploymentMcp': "the engine's MCP server declaration",
1446
+ 'config.localConfig.layer.policySettings': "your organization's managed settings",
1447
+ 'config.localConfig.layer.other': 'another settings file',
1448
+ 'config.localConfig.refused.nameUnusable': 'That server name can\'t be used — nothing was saved.',
1449
+ 'config.localConfig.refused.nameReserved': 'That server name is reserved by the app\'s own built-in server — nothing was saved.',
1450
+ 'config.localConfig.refused.mcpEntryInvalid': 'The server entry has problems that would keep it from loading — nothing was saved.',
1451
+ 'config.localConfig.refused.ambiguousScope': 'A server with that name is configured in more than one place; choose which one to change — nothing was saved.',
1452
+ 'config.localConfig.refused.credentialsNeedReentry': 'The server\'s address or command changed, so the secrets stored for it must be entered again or removed — nothing was saved.',
1453
+ 'config.localConfig.refused.baseConflict': 'This server\'s configuration changed after it was shown — nothing was saved. Refresh and try again.',
1454
+ 'config.mcpServers.notice.shadowed': 'A server with the same name in the {scope} configuration takes precedence over this one.',
1455
+ 'config.mcpServers.notice.endpointDiffers': 'A server with the same name in the {scope} configuration points somewhere else.',
1456
+ 'config.mcpServers.notice.deploymentWins': 'The engine\'s own deployment declares a server with this name; the deployment\'s server is used instead.',
1457
+ 'config.mcpServers.notice.envMissing': 'These variables are not set, so they stay as written: {names}.',
1458
+ 'config.mcpServers.notice.narrowingWouldConflict': 'Other places ({scopes}) declare a different tool list for this name; the server will not load until they agree.',
1459
+ 'config.mcpServers.withheld.narrowingConflict': 'Not loaded: the places that configure this server disagree on its tool list.',
1460
+ 'config.mcpServers.withheld.narrowingInvalid': 'Not loaded: a tool list for this server is written incorrectly in one of the places that configure it.',
1461
+ 'config.mcpServers.withheld.layerUnreadable': 'Not loaded: a configuration file that can add or limit MCP servers could not be read, so no MCP servers are loaded until it is fixed.',
1462
+ 'config.mcpServers.withheld.policyLocked': 'Not loaded: your organization\'s managed settings only allow the MCP servers it provides.',
1463
+ 'config.mcpServers.problem.nameReserved': 'This name belongs to the app\'s own built-in server.',
1464
+ 'config.mcpServers.approvalsWithheld': 'MCP approvals written in {layer} are not used because this folder is not trusted.',
1465
+ 'config.mcpServers.probe.removed': 'Nothing to test: this change removes the server.',
1466
+ 'config.mcpServers.probe.notActive': 'Nothing to test: the server would not be active after this change.',
1467
+ 'config.mcpServers.probe.envMissing': 'Not tested: some variables the server uses are not set.',
1468
+ 'config.mcpServers.probe.editRefusal': 'Not tested: the change itself could not be accepted.',
1301
1469
  'follow.notFollowed.headRun': 'This screen is no longer following run {taskId}{reason}{ending}{exit}',
1302
1470
  'follow.notFollowed.headTurn': "This screen is no longer following this turn's run{reason}{ending}{exit}",
1303
1471
  'follow.notFollowed.reason.exhaustedDraining': ": the engine instance serving it was going down when its last event stream closed, and this client's re-attach allowance has run out.",
@@ -1383,6 +1551,7 @@ const EN = {
1383
1551
  'localEngine.down.spawnRefused': 'The local engine was not started: the preparation step did not pass.',
1384
1552
  'localEngine.down.stopFailed': 'The old local engine did not stop in time, so it was not replaced.',
1385
1553
  'localEngine.down.crashLoop': 'The local engine keeps stopping unexpectedly, so automatic restarts are paused.',
1554
+ 'localEngine.down.exitedOnce': 'The local engine exited after it started, and Sema does not restart it automatically.',
1386
1555
  'localEngine.down.highWaterUnreadable': 'The record of the newest engine version used on this machine cannot be read, so the local engine is not started; check the engine data directory.',
1387
1556
  'localEngine.crashLoop.retry': 'The local engine keeps stopping unexpectedly; Sema tries again in about {seconds} seconds.',
1388
1557
  'localEngine.crashLoop.stopped': 'The local engine keeps stopping unexpectedly; Sema has stopped retrying on its own. Restart it manually.',
@@ -1409,11 +1578,80 @@ const EN = {
1409
1578
  'localEngine.restartOutcome.pendingBusy': 'Other sessions are using the local engine; it restarts once nothing is using it.',
1410
1579
  'localEngine.restartOutcome.failedPrepare': 'The local engine was not restarted; the current engine keeps running.',
1411
1580
  'localEngine.restartOutcome.failedDown': 'The local engine could not be restarted: {detail}',
1581
+ 'localEngine.swapGuard.newer': 'The local engine (version {running}) was started by a newer Sema than this one ({own}), so Sema keeps it running instead of replacing it with an older engine.',
1582
+ 'localEngine.swapGuard.newer.highWater': "This machine's local engine data was last used by a newer Sema (engine version {running}) than this one ({own}), so Sema does not start an older engine on it.",
1583
+ 'localEngine.swapGuard.newer.cliUpdate': 'To apply the change, run `sema update`.',
1584
+ 'localEngine.swapGuard.newer.appUpdate': 'To apply the change, update this app.',
1585
+ 'localEngine.swapGuard.hold': 'The local engine is not replaced yet: work still waiting on it may not continue on the replacement.',
1586
+ 'localEngine.swapGuard.unknown': 'Sema cannot tell whether the running local engine is newer than this Sema, so it is not replaced unless you confirm.',
1587
+ 'localEngine.swapGuard.parked.one': 'One approval card is still waiting for an answer.',
1588
+ 'localEngine.swapGuard.parked.oneSession': '{count} approval cards are still waiting for an answer in one session.',
1589
+ 'localEngine.swapGuard.parked.manySessions': '{count} approval cards are still waiting for an answer across {sessions} sessions.',
1590
+ 'localEngine.swapGuard.parked.failed': 'Whether approval cards are still waiting for an answer could not be read.',
1591
+ 'localEngine.swapGuard.parked.unsupported': 'Whether approval cards are still waiting for an answer cannot be read from this engine.',
1592
+ 'localEngine.swapGuard.wayOut.interactive': 'Answer waiting cards first, or confirm to replace the engine now.',
1593
+ 'localEngine.swapGuard.wayOut.print': 'This command keeps using the current engine; open Sema interactively to answer waiting cards or to replace it.',
1594
+ 'localEngine.swapGuard.told.one': 'The local engine was replaced; the approval card that was still waiting may no longer be answerable. If it says it cannot continue, send that turn again.',
1595
+ 'localEngine.swapGuard.told.other': 'The local engine was replaced; {count} approval cards that were still waiting may no longer be answerable. If one says it cannot continue, send that turn again.',
1596
+ 'localEngine.swapGuard.told.unknown': 'The local engine was replaced; approval cards that were still waiting, if any, may no longer be answerable. If one says it cannot continue, send that turn again.',
1597
+ 'engine.unavailable.line': '[sema] engine-fatal · {tag} — {head}, so nothing can reach a model on this session: {detail}. {fix}',
1598
+ 'engine.unavailable.lineNoDetail': '[sema] engine-fatal · {tag} — {head}, so nothing can reach a model on this session. {fix}',
1599
+ 'engine.unavailable.lineNoFix': '[sema] engine-fatal · {tag} — {head}, so nothing can reach a model on this session: {detail}',
1600
+ 'engine.unavailable.lineBare': '[sema] engine-fatal · {tag} — {head}, so nothing can reach a model on this session.',
1601
+ 'engine.unavailable.lineRefusedUse': '[sema] engine-fatal · {tag} — {head}, so nothing was sent to a model on this session: {detail}',
1602
+ 'engine.unavailable.lineRefusedUseNoDetail': '[sema] engine-fatal · {tag} — {head}, so nothing was sent to a model on this session.',
1603
+ 'engine.unavailable.head.notRunning': 'the sema engine is not running',
1604
+ 'engine.unavailable.head.refused': 'the sema engine refused to start',
1605
+ 'engine.unavailable.head.notAnswering': 'the sema engine is not answering',
1606
+ 'engine.unavailable.head.noHealthyAnswer': 'the sema engine has not given a healthy answer',
1607
+ 'engine.unavailable.head.drainStuck': 'the previous sema engine has not finished stopping',
1608
+ 'engine.unavailable.head.addressRefused': 'sema did not connect to the engine named in SEMA_ENGINE_URL',
1609
+ 'engine.unavailable.head.versionRefused': 'an engine is running, but this sema refused to use it',
1610
+ 'engine.unavailable.head.unknown': 'the sema engine is unavailable',
1611
+ 'engine.unavailable.again.session': 'start sema again',
1612
+ 'engine.unavailable.again.command': 'run the command again',
1613
+ 'engine.unavailable.again.app': 'open this app again',
1614
+ 'engine.unavailable.retry.session': 'restart sema to retry',
1615
+ 'engine.unavailable.retry.command': 'run the command again to retry',
1616
+ 'engine.unavailable.fix.diagnose': 'Fix: run `sema doctor` to diagnose, or {retry}.',
1617
+ 'engine.unavailable.fix.modelSetup': 'Fix: run `sema onboard` to finish model setup, then {again}.',
1618
+ 'engine.unavailable.fix.credentialConflict': 'Fix: unset one of the two and keep the one your endpoint expects, then {again}.',
1619
+ 'engine.unavailable.fix.credentialMalformed': 'Fix: run `sema cloud login` to sign in again (it rewrites the file sema manages), or `sema cloud logout` to stop using it; if you set {tokenFile} yourself, fix that file. Then {again}.',
1620
+ 'engine.unavailable.fix.credentialMultiTenant': 'Fix: give the engine the worker pull token ({token}, or one bare line in the file {tokenFile} names), or unset REQUIRE_PRINCIPAL for a single-user engine, then {again}.',
1621
+ 'engine.unavailable.fix.credential': 'Fix: correct the sign-in credential the engine named, then {again}.',
1622
+ 'engine.unavailable.wait.respond': 'wait for it to respond',
1623
+ 'engine.unavailable.wait.healthy': 'wait for it to give a healthy answer',
1624
+ 'engine.unavailable.wait.exit': 'wait for it to exit',
1625
+ 'engine.unavailable.fix.waitPid': 'Fix: {wait} and {again}, or stop it yourself (kill {pid}) and {again}.',
1626
+ 'engine.unavailable.fix.wait': 'Fix: {wait} and {again}, or stop that engine process yourself and {again}.',
1627
+ 'engine.bootRefusal.withWaysOut': 'The local engine refused to start: {reason} {waysOut}',
1628
+ 'engine.bootRefusal.withFix': 'The local engine refused to start: {reason} {fix}',
1629
+ 'engine.bootRefusal.waysOut': 'Ways out: (1) {newer} — {separate}; (2) {restore}; (3) {repair}.',
1630
+ 'engine.bootRefusal.who.sema': 'a newer sema',
1631
+ 'engine.bootRefusal.who.semaAtLeast': 'a newer sema (its engine is version {version} or later)',
1632
+ 'engine.bootRefusal.who.app': 'a newer version of this app',
1633
+ 'engine.bootRefusal.who.appAtLeast': 'a newer version of this app (its engine is version {version} or later)',
1634
+ 'engine.bootRefusal.who.build': 'a newer build',
1635
+ 'engine.bootRefusal.who.buildAtLeast': 'a newer build (engine {version} or later)',
1636
+ 'engine.bootRefusal.newer.update': '{who} has used this data folder: update this sema with `sema update` and {again}, or start that newer sema again',
1637
+ 'engine.bootRefusal.newer.projectLocal': '{who} has used this data folder: update the copy of sema installed in this project where it was installed, then {again}; or start that newer sema again',
1638
+ 'engine.bootRefusal.newer.devTree': '{who} has used this data folder: switch this working tree to the newer build, then {again}; or start that newer sema again',
1639
+ 'engine.bootRefusal.newer.app': '{who} has used this data folder: update this app, or start that newer version again',
1640
+ 'engine.bootRefusal.newer.unknown': '{who} has used this data folder: start that newer sema again',
1641
+ 'engine.bootRefusal.newer.deployment': '{who} wrote this data root: deploy that build',
1642
+ 'engine.bootRefusal.separate.embedded': 'to keep using this sema on this computer, start it with its own configuration folder: `{key}=<another-folder> sema` (it starts without your settings and sessions)',
1643
+ 'engine.bootRefusal.separate.app': 'to keep using this version, start it with its own configuration folder (`{key}=<another-folder>`); it starts without your settings and sessions',
1644
+ 'engine.bootRefusal.separate.deployment': 'to run this older build on this machine, give it its own data root (LOCAL_DATA_ROOT)',
1645
+ 'engine.bootRefusal.restore': 'put back a copy of {folder} made before the newer engine first opened it, then {again} (also the way out when a file named above is damaged; changes made after that copy are lost)',
1646
+ 'engine.bootRefusal.restoreDeployment': 'restore the data-root backup taken before the upgrade, then start this build (also the way out when a file named above is damaged)',
1647
+ 'engine.bootRefusal.folder.default': 'the engine-data folder in your sema configuration folder',
1648
+ 'engine.bootRefusal.repair': 'if a file named above could not be read at all (an I/O error such as EACCES), repair access to it (permissions, disk) and {again}',
1649
+ 'engine.bootRefusal.repairDeployment': 'if a file named above could not be read at all (an I/O error such as EACCES), repair access to it (permissions, mount, disk) and restart',
1412
1650
  'session.devices.repoint.done': "Done: this machine's device record and sessions now follow the new engine address. The device kept its identity — nothing was enrolled again.",
1413
1651
  'session.devices.repoint.unverified': "Nothing was changed: the new address could not be confirmed to hold this device. If it is the same engine, check that you are signed in as the device's owner and try again. Otherwise enroll this machine again at the engine's own address, then remove the old device from the engine's device list.",
1414
1652
  'session.devices.repoint.undetermined': "Nothing was changed: a check against the new address could not be read, so it is not known whether this device is registered there. Try again. Or enroll this machine again at the engine's own address, then remove the old device from the engine's device list.",
1415
1653
  'session.devices.repoint.partial': 'The device record now follows the new address, but not every session could be updated. Run the same command again to finish — sessions that were already updated are left as they are.',
1416
- 'session.devices.repoint.storeFailed': "The device record could not be moved, so nothing was changed. Run the command again; if it keeps failing, enroll this machine again at the engine's own address.",
1654
+ 'session.devices.repoint.storeFailed': "The device record could not be confirmed as moved, so no session was touched. Run the same command again; if it keeps failing, enroll this machine again at the engine's own address.",
1417
1655
  'session.devices.repoint.refused.addressInvalid': 'Nothing was changed: an address is not usable. Give the full https:// address of the engine (plain http:// is only accepted for this machine).',
1418
1656
  'session.devices.repoint.refused.sameAddress': 'Nothing was changed: the new address is the same engine address as the old one.',
1419
1657
  'session.devices.repoint.refused.recordAbsent': 'Nothing was changed: this machine has no device record for the old address.',
@@ -1421,5 +1659,58 @@ const EN = {
1421
1659
  'session.devices.repoint.refused.recordUnreadable': 'Nothing was changed: a device record could not be read, so it was left alone.',
1422
1660
  'session.devices.repoint.refused.targetOccupied': 'Nothing was changed: this machine already has a different device record for the new address.',
1423
1661
  'session.devices.repoint.refused.unarmed': 'Nothing was changed: this app is not set up to move the device record and its sessions.',
1662
+ 'session.devices.repoint.refused.rosterUnbound': 'Nothing was changed: this app is not set up to read the device list at the new address, so the move cannot be checked. This is a setup problem in the app, and trying again will not fix it.',
1663
+ 'attachments.withheld.toolsElsewhere.row': "the tools in this session do not work on this machine's files",
1664
+ 'attachments.withheld.toolsLocationUnconfirmed.row': "could not confirm that the tools in this session work on this machine's files",
1665
+ 'attachments.withheld.toolsElsewhere.model': "the tools in this session do not work on the files of the machine this client runs on, so the client did not attach that machine's copy; it may differ from the file the tools read and change, or the file may exist only where the tools run",
1666
+ 'attachments.withheld.toolsLocationUnconfirmed.model': "the client could not confirm that the tools in this session work on the files of the machine it runs on, so it did not attach that machine's copy; it may differ from the file the tools read and change, or the file may exist only where the tools run",
1667
+ 'attachments.localCopy.model': "The user shared this from the machine this client runs on: it is that machine's copy, and any path shown with it is a path on that machine. The tools in this session may not work on that machine's files, so the file they read and change may differ or may not exist.",
1668
+ 'session.compaction.canceled': 'Compaction canceled.',
1669
+ 'localEngine.health.answer.unansweredTimeout': 'did not answer in time',
1670
+ 'localEngine.health.answer.unansweredNetwork': 'could not be reached',
1671
+ 'localEngine.health.answer.ok': 'answered with status "ok"',
1672
+ 'localEngine.health.answer.notOkHttp': 'answered HTTP {http}',
1673
+ 'localEngine.health.answer.notOkStatus': 'answered HTTP {http} but not with status "ok"',
1674
+ 'centerTrust.refusal.badInput': 'This check was given a value it cannot read; that is a defect in the client, not in what you entered.',
1675
+ 'centerTrust.refusal.empty': 'No address was given.',
1676
+ 'centerTrust.refusal.tooLong': 'The address is too long (at most {addressMax} characters, and at most {authorityMax} for the host part).',
1677
+ 'centerTrust.refusal.unsafeCharacter': 'The address contains whitespace, a control character or a backslash.',
1678
+ 'centerTrust.refusal.scheme': 'The address must be written in full, starting with `https://` for an invitation link, or with `http://` or `https://` for a center address.',
1679
+ 'centerTrust.refusal.userinfo': 'The address must not carry a user name or password before the host.',
1680
+ 'centerTrust.refusal.percentInHost': 'The host part of the address must not contain percent-encoding.',
1681
+ 'centerTrust.refusal.unparseable': 'The address is not a parseable http(s) URL.',
1682
+ 'centerTrust.refusal.query': 'The address must not carry a query (`?`).',
1683
+ 'centerTrust.refusal.fragment': 'The address must not carry a fragment (`#`); only an invitation link may end with a `#ca=` list of fingerprints.',
1684
+ 'centerTrust.refusal.trailingDot': 'The host name must not end with a dot.',
1685
+ 'centerTrust.refusal.ipNotCanonical': 'An IP address must be written in its standard form (for example `127.0.0.1`, not a shortened or hexadecimal form).',
1686
+ 'centerTrust.refusal.plaintextRemote': 'Plain `http://` is allowed only for this machine; a remote center must use `https://`.',
1687
+ 'centerTrust.refusal.path': 'The address path is not allowed: an invitation link takes no path, and a center address path must not start with `//` or contain `.` or `..` segments.',
1688
+ 'centerTrust.refusal.fingerprint': 'A fingerprint must be `sha256:` followed by 64 hexadecimal digits (an invitation link takes lowercase digits only).',
1689
+ 'centerTrust.refusal.tooManyFingerprints': 'At most {fingerprintsMax} fingerprints can be given.',
1690
+ 'centerTrust.refusal.prefix': 'A fingerprint must start with `sha256:`.',
1691
+ 'centerTrust.refusal.parserUnavailable': "This client cannot read certificates on this platform, so it cannot pin the center's certificate.",
1692
+ 'centerTrust.refusal.bodyTooLarge': "The center's certificate answer is larger than {bodyMax} bytes.",
1693
+ 'centerTrust.refusal.bodyNotJson': "The center's certificate answer is not valid UTF-8 JSON.",
1694
+ 'centerTrust.refusal.bodyShape': "The center's certificate answer does not have the expected shape.",
1695
+ 'centerTrust.refusal.servedCount': 'The center must serve from 1 to {servedMax} certificates.',
1696
+ 'centerTrust.refusal.certificateTooLarge': 'A certificate from the center is longer than {pemMax} characters.',
1697
+ 'centerTrust.refusal.certificateNotCanonical': 'A certificate from the center is not exactly one certificate in standard PEM form (64-character lines, LF line ends) with standard DER lengths.',
1698
+ 'centerTrust.refusal.certificateUnparseable': 'A certificate from the center could not be read on this platform.',
1699
+ 'centerTrust.refusal.servedDuplicate': 'The center served the same certificate more than once.',
1700
+ 'centerTrust.refusal.namedNotServed': 'A fingerprint you gave does not match any certificate the center serves.',
1701
+ 'centerTrust.refusal.anchorNotSelfSigned': 'A certificate you named is not self-signed, so it cannot be pinned as a trust anchor.',
1702
+ 'centerTrust.refusal.unconfiguredWithFingerprints': 'You gave fingerprints, but the center says it has no certificate authority configured.',
1703
+ 'centerTrust.refusal.cancelled': "Fetching the center's certificates was cancelled.",
1704
+ 'centerTrust.refusal.timedOut': "Fetching the center's certificates timed out (each attempt waits at most {roundSec} seconds).",
1705
+ 'centerTrust.refusal.transportFailed': 'The center could not be reached to fetch its certificates.',
1706
+ 'centerTrust.refusal.contentType': "The center's certificate answer is not JSON (wrong content type).",
1707
+ 'centerTrust.refusal.caUnavailable': 'The center reports that its certificate authority is unavailable right now.',
1708
+ 'centerTrust.refusal.endpointMissing': 'The center does not offer certificates for pinning (it may be an older version).',
1709
+ 'centerTrust.refusal.unexpectedStatus': 'The center answered the certificate request with an unexpected status.',
1710
+ 'centerTrust.refusal.retryAfterUnusable': 'The center asked to retry later without a usable wait time, so the client stopped.',
1711
+ 'centerTrust.refusal.retryAfterTooLong': 'The center asked to wait more than {waitCapSec} seconds before retrying, so the client stopped; try again later.',
1712
+ 'centerTrust.refusal.retriesExhausted': 'The center kept asking to retry; the client stopped after {attemptsMax} attempts.',
1713
+ 'centerTrust.refusal.budgetExhausted': "Fetching the center's certificates used up its {budgetSec}-second time budget.",
1714
+ 'centerTrust.refusal.unknown': "The center's certificate could not be checked.",
1424
1715
  };
1425
1716
  export const EN_MESSAGES = Object.freeze(EN);