@sema-agent/client-core 0.94.0 → 0.96.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 (332) hide show
  1. package/CHANGELOG.md +521 -0
  2. package/README.md +104 -57
  3. package/dist/adapt/arms.js +12 -7
  4. package/dist/adapt/panelTasks.js +4 -10
  5. package/dist/adapt/toolCards.d.ts +1 -0
  6. package/dist/adapt/toolCards.js +18 -5
  7. package/dist/adapt/wireShapes.js +5 -24
  8. package/dist/adapter/activeRunSelfHeal.d.ts +12 -3
  9. package/dist/adapter/activeRunSelfHeal.js +50 -16
  10. package/dist/adapter/downstream/eventToSdkMessage.js +33 -18
  11. package/dist/adapter/downstream/terminalToSdkResult.js +19 -12
  12. package/dist/adapter/runStream.js +30 -46
  13. package/dist/adapter/types.d.ts +7 -0
  14. package/dist/adapter/types.js +15 -0
  15. package/dist/agentSession/backgroundView.js +5 -1
  16. package/dist/agentSession/engineAgentRegistryRead.js +7 -5
  17. package/dist/agentSession/engineSessionBackgroundStop.js +25 -17
  18. package/dist/agentsWireCaps.d.ts +2 -0
  19. package/dist/agentsWireCaps.js +13 -2
  20. package/dist/approvalDecidedByCapability.d.ts +0 -1
  21. package/dist/approvalDecidedByCapability.js +2 -7
  22. package/dist/approvalsStreamLiveCapability.d.ts +0 -1
  23. package/dist/approvalsStreamLiveCapability.js +2 -6
  24. package/dist/atMostOnce.d.ts +8 -0
  25. package/dist/atMostOnce.js +36 -0
  26. package/dist/attachmentSeatCapability.d.ts +0 -1
  27. package/dist/attachmentSeatCapability.js +0 -3
  28. package/dist/attachmentsWireCaps.js +11 -6
  29. package/dist/bashExitReading.d.ts +10 -0
  30. package/dist/bashExitReading.js +12 -0
  31. package/dist/callerCwdCapability.d.ts +0 -5
  32. package/dist/callerCwdCapability.js +2 -13
  33. package/dist/centerWiringCapability.d.ts +1 -7
  34. package/dist/centerWiringCapability.js +18 -27
  35. package/dist/classifierStatus.js +4 -4
  36. package/dist/classifierVerdictWire.js +4 -16
  37. package/dist/clientSlice.js +1 -1
  38. package/dist/cloudConfigWireCaps.d.ts +3 -3
  39. package/dist/cloudConfigWireCaps.js +85 -43
  40. package/dist/compensations.js +1 -1
  41. package/dist/coreValuePorts.d.ts +11 -7
  42. package/dist/coreValuePorts.js +5 -8
  43. package/dist/credentialProvenance.d.ts +28 -0
  44. package/dist/credentialProvenance.js +76 -0
  45. package/dist/cycleOrder.d.ts +15 -0
  46. package/dist/cycleOrder.js +45 -0
  47. package/dist/decideFailureNote.js +7 -2
  48. package/dist/decideReceipt.d.ts +2 -1
  49. package/dist/decideReceipt.js +39 -14
  50. package/dist/declared/supportFloorDeclared.d.ts +1 -0
  51. package/dist/declared/supportFloorDeclared.js +5 -0
  52. package/dist/deviceExecutorManagementCapability.d.ts +0 -1
  53. package/dist/deviceExecutorManagementCapability.js +7 -16
  54. package/dist/deviceRebind.d.ts +88 -0
  55. package/dist/deviceRebind.js +242 -0
  56. package/dist/displayUntrusted.d.ts +8 -3
  57. package/dist/displayUntrusted.js +661 -63
  58. package/dist/engineAgentAbsence.d.ts +2 -2
  59. package/dist/engineAgentPanelStore.d.ts +8 -18
  60. package/dist/engineAgentPanelStore.js +19 -537
  61. package/dist/engineCapReader.d.ts +6 -6
  62. package/dist/engineCapReader.js +30 -43
  63. package/dist/engineCapsCache.d.ts +13 -2
  64. package/dist/engineCapsCache.js +276 -44
  65. package/dist/engineCredentialRequirement.d.ts +9 -0
  66. package/dist/engineCredentialRequirement.js +23 -0
  67. package/dist/engineDirectory.d.ts +79 -0
  68. package/dist/engineDirectory.js +186 -0
  69. package/dist/engineEnvSourcing.d.ts +53 -0
  70. package/dist/engineEnvSourcing.js +81 -0
  71. package/dist/engineErrorCodes.d.ts +28 -4
  72. package/dist/engineErrorCodes.js +68 -25
  73. package/dist/engineIdentity.js +2 -0
  74. package/dist/engineNoticeCodes.d.ts +17 -0
  75. package/dist/engineNoticeCodes.js +57 -3
  76. package/dist/engineWireSdk.js +2 -2
  77. package/dist/engineWordRenames.d.ts +8 -0
  78. package/dist/engineWordRenames.js +13 -0
  79. package/dist/executionLaneCapability.d.ts +2 -3
  80. package/dist/executionLaneCapability.js +18 -23
  81. package/dist/fileHistoryCaptureCapability.d.ts +14 -1
  82. package/dist/fileHistoryCaptureCapability.js +72 -6
  83. package/dist/fileHistoryLegNotice.d.ts +3 -2
  84. package/dist/fileHistoryLegNotice.js +51 -2
  85. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  86. package/dist/fleet/bgSubagentRow.js +67 -0
  87. package/dist/fleet/fleetLedger.d.ts +3 -0
  88. package/dist/fleet/fleetLedger.js +153 -122
  89. package/dist/fleet/fleetProjection.d.ts +1 -3
  90. package/dist/fleet/fleetProjection.js +19 -19
  91. package/dist/fleetAgentPanelProjection.d.ts +4 -17
  92. package/dist/fleetAgentPanelProjection.js +7 -197
  93. package/dist/fleetAgentRowLike.d.ts +16 -0
  94. package/dist/fleetAgentRowLike.js +1 -0
  95. package/dist/fleetTaskDesc.js +4 -17
  96. package/dist/gateOutcome.d.ts +12 -1
  97. package/dist/gateOutcome.js +87 -18
  98. package/dist/gateVocabulary.d.ts +7 -2
  99. package/dist/gateVocabulary.js +5 -1
  100. package/dist/generated/engineAskFaceTables.js +1 -1
  101. package/dist/generated/engineFactTables.d.ts +5 -3
  102. package/dist/generated/engineFactTables.js +17 -4
  103. package/dist/generated/engineNoticeTables.js +12 -3
  104. package/dist/generated/sdkFactTables.d.ts +2 -0
  105. package/dist/generated/sdkFactTables.js +17 -0
  106. package/dist/generated/settingsSchemaFns.d.ts +13 -0
  107. package/dist/generated/settingsSchemaFns.js +75 -0
  108. package/dist/generated/toolNameTables.d.ts +1 -0
  109. package/dist/generated/toolNameTables.js +1 -0
  110. package/dist/headlessPermissionModeWire.d.ts +1 -1
  111. package/dist/headlessPermissionModeWire.js +1 -1
  112. package/dist/headlessReconnectWire.js +49 -20
  113. package/dist/hitl/allowRuleShadow.d.ts +1 -1
  114. package/dist/hitl/allowRuleShadow.js +49 -8
  115. package/dist/hitl/approvalCompleteParked.d.ts +1 -0
  116. package/dist/hitl/approvalCompleteParked.js +14 -0
  117. package/dist/hitl/approvalEndingCause.d.ts +7 -0
  118. package/dist/hitl/approvalEndingCause.js +71 -0
  119. package/dist/hitl/approvalHolds.d.ts +12 -2
  120. package/dist/hitl/approvalHolds.js +53 -2
  121. package/dist/hitl/approvalsFeed.js +23 -11
  122. package/dist/hitl/askGateWire.d.ts +2 -1
  123. package/dist/hitl/askGateWire.js +26 -1
  124. package/dist/hitl/askParkRowRouting.js +1 -1
  125. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  126. package/dist/hitl/automaticAnswerVerdict.js +15 -10
  127. package/dist/hitl/crashConverged.js +2 -0
  128. package/dist/hitl/decisionConflict.d.ts +3 -0
  129. package/dist/hitl/decisionConflict.js +41 -0
  130. package/dist/hitl/decisionRefusal.d.ts +12 -0
  131. package/dist/hitl/decisionRefusal.js +63 -4
  132. package/dist/hitl/frameRouter.d.ts +0 -1
  133. package/dist/hitl/frameRouter.js +32 -57
  134. package/dist/hitl/gateLedger.d.ts +5 -0
  135. package/dist/hitl/gateLedger.js +21 -0
  136. package/dist/hitl/hitlBridge.d.ts +17 -2
  137. package/dist/hitl/hitlBridge.js +91 -55
  138. package/dist/hitl/hitlHostSurface.js +3 -11
  139. package/dist/hitl/livePendingAsk.d.ts +16 -6
  140. package/dist/hitl/livePendingAsk.js +36 -4
  141. package/dist/hitl/localAllowRule.d.ts +1 -0
  142. package/dist/hitl/localAllowRule.js +2 -2
  143. package/dist/hitl/noAllowCause.d.ts +2 -1
  144. package/dist/hitl/noAllowCause.js +3 -2
  145. package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
  146. package/dist/hitl/parkExpiryJudgements.js +46 -0
  147. package/dist/hitl/parkResolver.d.ts +4 -7
  148. package/dist/hitl/parkResolver.js +12 -34
  149. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  150. package/dist/hitl/parkRowBirthWait.js +2 -2
  151. package/dist/hitl/persistedRulesWire.js +5 -1
  152. package/dist/hitl/planReviewWire.d.ts +3 -2
  153. package/dist/hitl/planReviewWire.js +154 -50
  154. package/dist/hitl/replayedApproval.d.ts +9 -0
  155. package/dist/hitl/replayedApproval.js +139 -10
  156. package/dist/hitl/resumeRunningCard.d.ts +2 -0
  157. package/dist/hitl/resumeRunningCard.js +15 -4
  158. package/dist/hitl/sessionPolicyDeliverable.js +8 -6
  159. package/dist/hitl/standingRows.d.ts +18 -0
  160. package/dist/hitl/standingRows.js +127 -0
  161. package/dist/hitl/toolApprovalWire.d.ts +39 -7
  162. package/dist/hitl/toolApprovalWire.js +351 -61
  163. package/dist/hookMatcherVerdict.d.ts +1 -9
  164. package/dist/hookMatcherVerdict.js +21 -61
  165. package/dist/hooksWireCaps.js +40 -8
  166. package/dist/host.d.ts +5 -0
  167. package/dist/host.js +3 -1
  168. package/dist/hostCallbackGuard.d.ts +2 -0
  169. package/dist/hostCallbackGuard.js +31 -0
  170. package/dist/index.d.ts +48 -17
  171. package/dist/index.js +36 -15
  172. package/dist/interactiveInterrupt.d.ts +8 -0
  173. package/dist/interactiveInterrupt.js +54 -0
  174. package/dist/limitsWire.d.ts +5 -0
  175. package/dist/limitsWire.js +49 -3
  176. package/dist/liveModelCatalog.d.ts +95 -0
  177. package/dist/liveModelCatalog.js +297 -32
  178. package/dist/mcpEngineLeg.d.ts +25 -0
  179. package/dist/mcpEngineLeg.js +71 -15
  180. package/dist/mcpPanel.js +2 -1
  181. package/dist/mcpProbeCapability.d.ts +0 -5
  182. package/dist/mcpProbeCapability.js +2 -12
  183. package/dist/mcpReconnect.d.ts +1 -3
  184. package/dist/mcpReconnect.js +10 -5
  185. package/dist/memoryComplianceCapability.d.ts +0 -5
  186. package/dist/memoryComplianceCapability.js +2 -12
  187. package/dist/memoryOriginCapability.d.ts +0 -5
  188. package/dist/memoryOriginCapability.js +2 -12
  189. package/dist/memorySpecWire.js +2 -2
  190. package/dist/memoryVerbsWire.d.ts +1 -1
  191. package/dist/memoryVerbsWire.js +4 -0
  192. package/dist/model/liveCatalogShape.d.ts +14 -0
  193. package/dist/model/liveCatalogShape.js +71 -0
  194. package/dist/model/modelSupplyRules.d.ts +1 -0
  195. package/dist/model/modelSupplyRules.js +30 -9
  196. package/dist/model/modelsPolicy.d.ts +21 -0
  197. package/dist/model/modelsPolicy.js +90 -0
  198. package/dist/modelIdentityResolvability.d.ts +2 -2
  199. package/dist/modelIdentityResolvability.js +14 -12
  200. package/dist/modelSwitchFallback.d.ts +69 -0
  201. package/dist/modelSwitchFallback.js +206 -0
  202. package/dist/noticePresentation.d.ts +68 -0
  203. package/dist/noticePresentation.js +247 -0
  204. package/dist/notifications.js +12 -11
  205. package/dist/outputStyleSeatCapability.d.ts +0 -2
  206. package/dist/outputStyleSeatCapability.js +2 -10
  207. package/dist/ownKey.d.ts +8 -0
  208. package/dist/ownKey.js +66 -0
  209. package/dist/panelReduce.d.ts +114 -0
  210. package/dist/panelReduce.js +1135 -0
  211. package/dist/panelStateHolder.d.ts +17 -0
  212. package/dist/panelStateHolder.js +201 -0
  213. package/dist/peerFrames.js +13 -9
  214. package/dist/peerLaneCapability.d.ts +0 -1
  215. package/dist/peerLaneCapability.js +2 -6
  216. package/dist/permissionModesCapability.d.ts +0 -5
  217. package/dist/permissionModesCapability.js +5 -16
  218. package/dist/permissionRuleIssue.js +0 -3
  219. package/dist/permissionRulesWriteCapability.d.ts +0 -1
  220. package/dist/permissionRulesWriteCapability.js +2 -6
  221. package/dist/permissionsAllowGrantCapability.d.ts +0 -1
  222. package/dist/permissionsAllowGrantCapability.js +3 -9
  223. package/dist/permissionsDeclaration.d.ts +8 -0
  224. package/dist/permissionsDeclaration.js +101 -41
  225. package/dist/printPermissionOutcome.d.ts +12 -0
  226. package/dist/printPermissionOutcome.js +50 -0
  227. package/dist/printToolResultFrame.d.ts +1 -0
  228. package/dist/printToolResultFrame.js +5 -17
  229. package/dist/promptBlockedCopy.d.ts +5 -0
  230. package/dist/promptBlockedCopy.js +35 -0
  231. package/dist/promptDelivery.js +0 -8
  232. package/dist/protocolSegment.d.ts +9 -6
  233. package/dist/protocolSegment.js +31 -21
  234. package/dist/providerRejection.d.ts +4 -0
  235. package/dist/providerRejection.js +75 -14
  236. package/dist/replayBody.d.ts +12 -0
  237. package/dist/replayBody.js +25 -0
  238. package/dist/resumeRefusalCopy.d.ts +18 -1
  239. package/dist/resumeRefusalCopy.js +127 -32
  240. package/dist/retryStatus.d.ts +9 -1
  241. package/dist/retryStatus.js +9 -2
  242. package/dist/rewindArchiveCapability.d.ts +5 -14
  243. package/dist/rewindArchiveCapability.js +18 -61
  244. package/dist/rewindArchiveReading.d.ts +15 -0
  245. package/dist/rewindArchiveReading.js +56 -0
  246. package/dist/rewindEngineAction.d.ts +21 -0
  247. package/dist/rewindEngineAction.js +36 -0
  248. package/dist/rewindWireCaps.d.ts +2 -1
  249. package/dist/rewindWireCaps.js +1 -0
  250. package/dist/ruleCompileVerdict.d.ts +9 -1
  251. package/dist/ruleCompileVerdict.js +29 -4
  252. package/dist/runTerminal.d.ts +15 -12
  253. package/dist/runTerminal.js +60 -35
  254. package/dist/sandboxWire.js +13 -0
  255. package/dist/sdkRegistryTransit.d.ts +2 -1
  256. package/dist/sdkRegistryTransit.js +1 -0
  257. package/dist/sealedKeyCapability.d.ts +0 -5
  258. package/dist/sealedKeyCapability.js +3 -15
  259. package/dist/seam.js +4 -2
  260. package/dist/seatContract.d.ts +125 -34
  261. package/dist/seatContract.js +583 -179
  262. package/dist/sessionIdSegment.d.ts +1 -0
  263. package/dist/sessionIdSegment.js +11 -0
  264. package/dist/sessionMemoryErase.d.ts +1 -1
  265. package/dist/sessionMemoryErase.js +6 -1
  266. package/dist/sessionMemoryStatus.js +3 -2
  267. package/dist/sessionPolicyCapability.d.ts +0 -1
  268. package/dist/sessionPolicyCapability.js +2 -6
  269. package/dist/sessionReadRedactionCapability.d.ts +0 -5
  270. package/dist/sessionReadRedactionCapability.js +2 -13
  271. package/dist/sessionSyncFileHistory.d.ts +4 -0
  272. package/dist/sessionSyncFileHistory.js +66 -0
  273. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -2
  274. package/dist/sessionSyncFileHistoryCapability.js +2 -9
  275. package/dist/skillToolListsCapability.d.ts +0 -2
  276. package/dist/skillToolListsCapability.js +2 -9
  277. package/dist/skillsWireCaps.d.ts +4 -0
  278. package/dist/skillsWireCaps.js +66 -1
  279. package/dist/sqlEngineCapability.d.ts +0 -1
  280. package/dist/sqlEngineCapability.js +9 -14
  281. package/dist/steerPriorityCapability.d.ts +0 -2
  282. package/dist/steerPriorityCapability.js +3 -12
  283. package/dist/storePostureCapability.d.ts +1 -5
  284. package/dist/storePostureCapability.js +16 -22
  285. package/dist/streamDrainingLegs.d.ts +6 -0
  286. package/dist/streamDrainingLegs.js +23 -0
  287. package/dist/subagent/engineCompactWire.js +13 -38
  288. package/dist/subagent/engineDelegatedPrompt.js +10 -6
  289. package/dist/subagent/engineSubagentOutput.d.ts +0 -1
  290. package/dist/subagent/engineSubagentOutput.js +5 -20
  291. package/dist/subagent/engineSubagentSteer.js +7 -5
  292. package/dist/subagent/engineSubagentTail.d.ts +0 -1
  293. package/dist/subagent/engineSubagentTail.js +7 -32
  294. package/dist/subagentContentStore.js +7 -18
  295. package/dist/supportFloor.d.ts +1 -0
  296. package/dist/supportFloor.js +15 -14
  297. package/dist/systemReminderTag.d.ts +1 -0
  298. package/dist/systemReminderTag.js +8 -0
  299. package/dist/terminalStatuses.d.ts +30 -0
  300. package/dist/terminalStatuses.js +67 -0
  301. package/dist/toolHistoryMismatch.d.ts +0 -3
  302. package/dist/toolHistoryMismatch.js +3 -7
  303. package/dist/toolResult.d.ts +6 -1
  304. package/dist/toolResult.js +90 -37
  305. package/dist/toolResultContent.d.ts +2 -0
  306. package/dist/toolResultContent.js +63 -0
  307. package/dist/types/engineState.d.ts +2 -1
  308. package/dist/usageAnalytics.d.ts +146 -0
  309. package/dist/usageAnalytics.js +335 -0
  310. package/dist/userInvokedSkillsCapability.d.ts +0 -2
  311. package/dist/userInvokedSkillsCapability.js +2 -9
  312. package/dist/webSearchBackendCapability.d.ts +0 -1
  313. package/dist/webSearchBackendCapability.js +3 -7
  314. package/dist/webSearchWireCaps.js +3 -11
  315. package/dist/wireErrorTriage.d.ts +2 -0
  316. package/dist/wireErrorTriage.js +34 -5
  317. package/dist/wireFailureShape.d.ts +23 -2
  318. package/dist/wireFailureShape.js +88 -43
  319. package/dist/wireRefusalCopy.js +2 -18
  320. package/dist/workflowClient.js +7 -11
  321. package/dist/workflowsJournalCapability.d.ts +0 -1
  322. package/dist/workflowsJournalCapability.js +2 -6
  323. package/dist/writeProtectionCapability.d.ts +0 -1
  324. package/dist/writeProtectionCapability.js +5 -10
  325. package/docs/INTEGRATION-CLIENTS.md +2279 -27
  326. package/package.json +5 -5
  327. package/dist/engineCapsGenerationGuard.d.ts +0 -4
  328. package/dist/engineCapsGenerationGuard.js +0 -19
  329. package/dist/panelRunningHistory.d.ts +0 -22
  330. package/dist/panelRunningHistory.js +0 -82
  331. package/dist/registryConflict.d.ts +0 -3
  332. package/dist/registryConflict.js +0 -44
@@ -38,18 +38,12 @@ function scanForSecretLiteral(s) {
38
38
  return true;
39
39
  return s.split(/[^A-Za-z0-9_-]+/).some(tok => tok !== '' && SECRET_LITERAL_RE.test(tok));
40
40
  }
41
- function decodeAsciiEscapes(s) {
42
- return s.replace(/%[0-9A-Fa-f]{2}/g, esc => {
43
- const code = Number.parseInt(esc.slice(1), 16);
44
- return code < 0x80 ? String.fromCharCode(code) : esc;
45
- });
46
- }
47
41
  export function looksLikeKnownSecret(s) {
48
42
  let cur = s;
49
43
  for (let layer = 0; layer < 4; layer++) {
50
44
  if (scanForSecretLiteral(cur))
51
45
  return true;
52
- const next = decodeAsciiEscapes(cur);
46
+ const next = percentDecodeForMatching(cur).decoded;
53
47
  if (next === cur)
54
48
  break;
55
49
  cur = next;
@@ -103,8 +97,8 @@ function valueIsWholeMarker(S, start, end, tokenInner = true) {
103
97
  return j >= end || !isKeyWordChar(text.charCodeAt(j)) || credentialWordStartsExactlyAt(text, j, tokenInner) || credentialPairAt(S, j);
104
98
  }
105
99
  const CREDENTIAL_NAME = /(?:(?:access|refresh|id|client|api|x[-_]api|session|auth)[-_]?)?(?:token|key|secret|password|authorization|credential)s?|bearer|basic/iy;
106
- const LABEL_SEPARATOR = /(?:\\*["'])?[\s\u115F\u1160\u3164\uFFA0\u2800]*[:=\uFF1A\uFF1D]/y;
107
- const SCHEME_SEPARATOR = /[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]/y;
100
+ const LABEL_SEPARATOR = /(?:\\*["'])?(?:[\s\u115F\u1160\u3164\uFFA0\u2800]|\\t)*[:=\uFF1A\uFF1D]/y;
101
+ const SCHEME_SEPARATOR = /(?:[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]|\\t)/y;
108
102
  function credentialPairAt(S, at) {
109
103
  const text = S.text;
110
104
  const re = new RegExp(CREDENTIAL_NAME.source, 'iy');
@@ -261,21 +255,23 @@ function isKnownSecretSegment(value) {
261
255
  const core = valueCoreForJudging(value);
262
256
  return core.length > 0 && looksLikeKnownSecret(core);
263
257
  }
264
- function queryCandidates(src, base, query, edits, soft) {
258
+ function queryCandidates(src, base, query, edits, soft, byShape = false) {
259
+ const relax = byShape === 'relaxed';
265
260
  let pos = base;
266
261
  for (const part of query.split('&')) {
267
262
  if (part.length > 0) {
268
263
  const eq = part.indexOf('=');
269
264
  if (eq === -1) {
270
265
  const at = pos;
271
- if (!slotIsWholeMarker(part, soft && ((i) => soft(at + i))))
266
+ if (!slotIsWholeMarker(part, soft && ((i) => soft(at + i))) && (!byShape || queryPartCarriesCredential(null, part, relax)))
272
267
  pushEdit(edits, src, pos, pos + part.length, REDACTED_QUERY);
273
268
  }
274
269
  else {
275
270
  const value = part.slice(eq + 1);
276
271
  const at = pos + eq + 1;
277
- if (value.length > 0 && !slotIsWholeMarker(value, soft && ((i) => soft(at + i))))
272
+ if (value.length > 0 && !slotIsWholeMarker(value, soft && ((i) => soft(at + i))) && (!byShape || queryPartCarriesCredential(part.slice(0, eq), value, relax))) {
278
273
  pushEdit(edits, src, pos + eq + 1, pos + part.length, REDACTED_QUERY);
274
+ }
279
275
  }
280
276
  }
281
277
  pos += part.length + 1;
@@ -286,15 +282,22 @@ function pathCandidates(src, base, path, opaqueSegments, edits, soft) {
286
282
  for (const segment of path.split('/')) {
287
283
  const semi = segment.indexOf(';');
288
284
  const head = semi === -1 ? segment : segment.slice(0, semi);
289
- if (opaqueSegments && isKnownSecretSegment(head)) {
285
+ if (opaqueSegments) {
290
286
  let a = 0;
291
287
  let b = head.length;
292
288
  while (a < b && !isKeyWordChar(head.charCodeAt(a)))
293
289
  a++;
294
290
  while (b > a && !isKeyWordChar(head.charCodeAt(b - 1)))
295
291
  b--;
296
- if (b > a)
297
- pushEdit(edits, src, pos + a, pos + b, REDACTED_SECRET);
292
+ if (isKnownSecretSegment(head)) {
293
+ if (b > a)
294
+ pushEdit(edits, src, pos + a, pos + b, REDACTED_SECRET);
295
+ }
296
+ else if (b > a) {
297
+ const glued = gluedLiteralStart(head.slice(a, b));
298
+ if (glued > 0)
299
+ pushEdit(edits, src, pos + a + glued, pos + b, REDACTED_SECRET);
300
+ }
298
301
  }
299
302
  if (semi !== -1) {
300
303
  let ppos = pos + semi + 1;
@@ -312,7 +315,7 @@ function pathCandidates(src, base, path, opaqueSegments, edits, soft) {
312
315
  pos += segment.length + 1;
313
316
  }
314
317
  }
315
- function urlTokenCandidatesAt(src, start, end, edits, soft) {
318
+ function urlTokenCandidatesAt(src, start, end, edits, soft, byShape = false) {
316
319
  const token = src.slice(start, end);
317
320
  const schemeEnd = token.indexOf('://') + '://'.length;
318
321
  const scheme = token.slice(0, schemeEnd);
@@ -330,7 +333,7 @@ function urlTokenCandidatesAt(src, start, end, edits, soft) {
330
333
  const path = question === -1 ? beforeHash : beforeHash.slice(0, question);
331
334
  pathCandidates(src, start + tailStart, path, !/^file:/i.test(scheme), edits, soft);
332
335
  if (question !== -1)
333
- queryCandidates(src, start + tailStart + question + 1, beforeHash.slice(question + 1), edits, soft);
336
+ queryCandidates(src, start + tailStart + question + 1, beforeHash.slice(question + 1), edits, soft, byShape);
334
337
  if (hash !== -1) {
335
338
  const rawFragment = tail.slice(hash + 1);
336
339
  const at = start + tailStart + hash + 1;
@@ -338,7 +341,7 @@ function urlTokenCandidatesAt(src, start, end, edits, soft) {
338
341
  pushEdit(edits, src, start + tailStart + hash + 1, end, REDACTED_FRAGMENT);
339
342
  }
340
343
  }
341
- function urlCandidates(text, out, regions, unitPos = () => false, soft) {
344
+ function urlCandidates(text, out, regions, unitPos = () => false, soft, byShape = false) {
342
345
  let mark = text.indexOf('://');
343
346
  while (mark !== -1) {
344
347
  let start = mark;
@@ -401,8 +404,9 @@ function urlCandidates(text, out, regions, unitPos = () => false, soft) {
401
404
  runStart--;
402
405
  if (runStart < end && !VALUE_BOUNDARY_TAIL.test(text.slice(start, runStart)))
403
406
  end = runStart;
407
+ end = trailingCloserEnd(text, start, mark + 3, end, unitPos);
404
408
  const tokenEdits = [];
405
- urlTokenCandidatesAt(text, start, end, tokenEdits, soft);
409
+ urlTokenCandidatesAt(text, start, end, tokenEdits, soft, byShape);
406
410
  editsToCandidates(tokenEdits, 'url', out, end);
407
411
  const token = text.slice(start, end);
408
412
  const schemeEnd = token.indexOf('://') + 3;
@@ -420,6 +424,47 @@ function urlCandidates(text, out, regions, unitPos = () => false, soft) {
420
424
  mark = text.indexOf('://', end > mark + 3 ? end : mark + 3);
421
425
  }
422
426
  }
427
+ function trailingCloserEnd(text, start, floor, end, unitPos) {
428
+ const opens = new Map();
429
+ const closes = new Map();
430
+ for (const [o, c] of BRACKET_PAIRS) {
431
+ opens.set(o, 0);
432
+ closes.set(c, 0);
433
+ }
434
+ for (let k = start; k < end; k++) {
435
+ if (unitPos(k))
436
+ continue;
437
+ const ch = text.charAt(k);
438
+ const o = opens.get(ch);
439
+ if (o !== undefined)
440
+ opens.set(ch, o + 1);
441
+ const c = closes.get(ch);
442
+ if (c !== undefined)
443
+ closes.set(ch, c + 1);
444
+ }
445
+ let e = end;
446
+ for (;;) {
447
+ if (e <= floor || unitPos(e - 1))
448
+ return e;
449
+ const ch = text.charAt(e - 1);
450
+ const c = closes.get(ch);
451
+ if (c === undefined)
452
+ return e;
453
+ let open = '';
454
+ for (const [o, cl] of BRACKET_PAIRS)
455
+ if (cl === ch)
456
+ open = o;
457
+ if (c <= (opens.get(open) ?? 0))
458
+ return e;
459
+ closes.set(ch, c - 1);
460
+ e--;
461
+ let runStart = e;
462
+ while (runStart > floor && TRAILING_PUNCTUATION.has(text.charAt(runStart - 1)))
463
+ runStart--;
464
+ if (runStart < e && !VALUE_BOUNDARY_TAIL.test(text.slice(start, runStart)))
465
+ e = runStart;
466
+ }
467
+ }
423
468
  function atInAuthority(text, from) {
424
469
  for (let p = from; p < text.length; p++) {
425
470
  const ch = text.charAt(p);
@@ -763,9 +808,17 @@ const NAME_BLANK_RANGES = [
763
808
  const isNameBlank = (cp) => NAME_BLANK_RANGES.some(([a, b]) => cp >= a && cp <= b);
764
809
  const isFoldedBlank = (c) => isNameBlank(c) && isRegexSpace(c);
765
810
  const isUnicodeBlank = (c) => (c > 0x7f && isRegexSpace(c) && c !== 0xfeff) || isNameBlank(c);
766
- const SECRET_SCHEME_WORD = /(?:\b|(?<=\\[A-Za-z"']))(bearer|basic|token)[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]+/gi;
811
+ const SECRET_SCHEME_WORD = /(?:\b|(?<=\\[A-Za-z"']))(?!(?<=(?<!\\)\\)(?:bearer|basic|token)\\t)(bearer|basic|token)(?:[\s:=\uFF1A\uFF1D\u115F\u1160\u3164\uFFA0\u2800]|\\t)+/gi;
812
+ const SCHEME_LEFT_STRICT = String.raw `(?:\b|(?<=\\[A-Za-z"']))`;
813
+ const SCHEME_WORD_OUTER_SOURCE = widenLeft(SECRET_SCHEME_WORD.source, SCHEME_LEFT_STRICT, String.raw `(?=bearer|basic)`);
767
814
  const schemeWordIsInner = (word, tokenInner) => tokenInner || word.toLowerCase() !== 'token';
768
- const SECRET_LABELLED_WORD = /(?:\b|(?<=_)|(?<=\\[A-Za-z"']))((?:access[-_ ]?|refresh[-_ ]?|id[-_ ]?|client[-_ ]?|api[-_ ]?|x[-_]api[-_ ]?|session[-_ ]?|auth[-_ ]?)?(?:token|key|secret|password|authorization|credential)s?)(?:\\*["'])?[\s\u115F\u1160\u3164\uFFA0\u2800]*[:=\uFF1A\uFF1D][\s\u115F\u1160\u3164\uFFA0\u2800]*/gi;
815
+ const SECRET_LABELLED_WORD = /(?:\b|(?<=_)|(?<=\\[A-Za-z"']))((?:access[-_ ]?|refresh[-_ ]?|id[-_ ]?|client[-_ ]?|api[-_ ]?|x[-_]api[-_ ]?|session[-_ ]?|auth[-_ ]?)?(?:token|key|secret|password|authorization|credential)s?)(?:\\*["'])?(?:[\s\u115F\u1160\u3164\uFFA0\u2800]|\\t)*[:=\uFF1A\uFF1D](?:[\s\u115F\u1160\u3164\uFFA0\u2800]|\\t)*/gi;
816
+ function widenLeft(source, strictLeft, extraAlt) {
817
+ return source.startsWith(strictLeft) ? `${strictLeft.slice(0, -1)}|${extraAlt})${source.slice(strictLeft.length)}` : source;
818
+ }
819
+ const LABEL_LEFT_STRICT = String.raw `(?:\b|(?<=_)|(?<=\\[A-Za-z"']))`;
820
+ const LABEL_LEFT_GLUED_ALT = String.raw `(?<=[A-Za-z0-9])(?:(?=(?:token|secret|password|authorization|credential)(?!s))|(?<!mon|tur|don|hoc|whis|joc|lac)(?=key(?!s)))`;
821
+ const LABEL_WORD_OUTER_SOURCE = widenLeft(SECRET_LABELLED_WORD.source, LABEL_LEFT_STRICT, LABEL_LEFT_GLUED_ALT);
769
822
  const DIAGNOSTIC_VALUE_WORDS = new Set([
770
823
  'missing', 'required', 'invalid', 'expired', 'unauthorized', 'unauthenticated', 'authentication',
771
824
  'authorization', 'credential', 'credentials', 'unsupported', 'malformed', 'rejected', 'absent',
@@ -820,18 +873,67 @@ const AUTH_SCHEME_WORDS = new Set([
820
873
  const AUTH_SIGNATURE_SCHEME = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+){2,}$/;
821
874
  const BARE_VALUE_STOP_CHARS = new Set([',', ';', '"', "'", '\\', '(', ')', '[', ']', '{', '}', '<', '>']);
822
875
  const isBareValueStop = (ch) => ch <= ' ' || BARE_VALUE_STOP_CHARS.has(ch);
876
+ function isPlainAt(S, rawUnit, k) {
877
+ if (S.dropped(k) || S.painted(k) || S.unitAt(k) !== UNIT_NONE)
878
+ return false;
879
+ return rawUnit === null || rawUnit[S.rawStart(k)] !== 1;
880
+ }
881
+ function codeSpanClose(text, plain) {
882
+ const n = text.length;
883
+ const close = new Int32Array(n + 1).fill(-1);
884
+ let openLen = 0;
885
+ let spanFrom = -1;
886
+ let k = 0;
887
+ while (k < n) {
888
+ const c = text.charCodeAt(k);
889
+ if (c === 0x0a || c === 0x0d || c === 0x2028 || c === 0x2029) {
890
+ openLen = 0;
891
+ spanFrom = -1;
892
+ k++;
893
+ continue;
894
+ }
895
+ if (c !== 0x60 || !plain(k)) {
896
+ k++;
897
+ continue;
898
+ }
899
+ let e = k;
900
+ while (e < n && text.charCodeAt(e) === 0x60 && plain(e))
901
+ e++;
902
+ const len = e - k;
903
+ if (openLen === 0) {
904
+ openLen = len;
905
+ spanFrom = e;
906
+ }
907
+ else if (len === openLen) {
908
+ for (let x = spanFrom; x < k; x++)
909
+ close[x] = k;
910
+ openLen = 0;
911
+ spanFrom = -1;
912
+ }
913
+ k = e;
914
+ }
915
+ return close;
916
+ }
917
+ const BRACKET_PAIRS = new Map([['(', ')'], ['[', ']']]);
823
918
  class InnerWordIndex {
824
919
  text;
825
920
  tokenInner;
826
921
  probes;
827
- constructor(text, tokenInner = true) {
922
+ plain;
923
+ spanClose = null;
924
+ constructor(text, tokenInner = true, plain = () => true) {
828
925
  this.text = text;
829
926
  this.tokenInner = tokenInner;
927
+ this.plain = plain;
830
928
  this.probes = [
831
929
  { re: new RegExp(SECRET_LABELLED_WORD.source, SECRET_LABELLED_WORD.flags), scheme: false, from: -1, hit: null },
832
930
  { re: new RegExp(SECRET_SCHEME_WORD.source, SECRET_SCHEME_WORD.flags), scheme: true, from: -1, hit: null },
833
931
  ];
834
932
  }
933
+ closingTickFrom(i) {
934
+ this.spanClose ??= codeSpanClose(this.text, this.plain);
935
+ return this.spanClose[i] ?? -1;
936
+ }
835
937
  next(q) {
836
938
  let best = null;
837
939
  for (const p of this.probes) {
@@ -857,6 +959,45 @@ class InnerWordIndex {
857
959
  return best;
858
960
  }
859
961
  }
962
+ const WRAPPED_PLACEHOLDER = /^(?:[A-Z]{1,12}(?:_[A-Z]{1,12})*|[a-z]{1,12}(?:-[a-z]{1,12})*)$/;
963
+ function wrappedValueAt(text, from, idx) {
964
+ let k = from;
965
+ while (k < text.length && text[k] === VIEW_SEPARATOR)
966
+ k++;
967
+ const close = BRACKET_PAIRS.get(text.charAt(k));
968
+ if (close === undefined || credentialWordStartsAt(text, k + 1, idx.tokenInner))
969
+ return null;
970
+ const inner = scanSecretValue(text, k + 1, idx);
971
+ if (inner === null || inner.start !== k + 1)
972
+ return null;
973
+ let c = inner.end;
974
+ while (c < text.length && text[c] === VIEW_SEPARATOR)
975
+ c++;
976
+ if (text.charAt(c) !== close || (close === ']' && text.charAt(c + 1) === '('))
977
+ return null;
978
+ return inner;
979
+ }
980
+ function tokenSchemeValueEnd(text, start, end, idx) {
981
+ if (withoutSeparators(text.slice(start, end)).toLowerCase() !== 'token')
982
+ return -1;
983
+ const re = new RegExp(SECRET_SCHEME_WORD.source, 'iy');
984
+ re.lastIndex = start;
985
+ const m = re.exec(text);
986
+ if (m === null || (m[1] ?? '').toLowerCase() !== 'token')
987
+ return -1;
988
+ const sepEnd = start + m[0].length;
989
+ if (/[\n\r\u2028\u2029:=\uFF1A\uFF1D]/.test(text.slice(start + (m[1] ?? '').length, sepEnd)))
990
+ return -1;
991
+ if (credentialWordStartsAt(text, sepEnd, idx.tokenInner))
992
+ return -1;
993
+ const iv = scanSecretValue(text, sepEnd, idx);
994
+ if (iv === null)
995
+ return -1;
996
+ const inner = withoutSeparators(text.slice(iv.start, iv.end));
997
+ if (schemeFollowerReleased('token', inner, false) || isDiagnosticWord(inner))
998
+ return -1;
999
+ return iv.end;
1000
+ }
860
1001
  function innerWordFits(text, w) {
861
1002
  for (let k = w.start; k <= w.sepAt && k < text.length; k++)
862
1003
  if (isBareValueStop(text.charAt(k)))
@@ -912,6 +1053,7 @@ function scanSecretValue(text, from, idx) {
912
1053
  let pending = cuttable ? idx.next(i + 1) : null;
913
1054
  let cut = false;
914
1055
  let j = i;
1056
+ const closingTick = idx === undefined ? -1 : idx.closingTickFrom(i);
915
1057
  while (j < text.length) {
916
1058
  if (pending !== null && j >= pending.start) {
917
1059
  if (j === pending.start && innerWordFits(text, pending)) {
@@ -936,6 +1078,18 @@ function scanSecretValue(text, from, idx) {
936
1078
  }
937
1079
  while (j > i && text[j - 1] === VIEW_SEPARATOR)
938
1080
  j--;
1081
+ if (closingTick > i && closingTick < j) {
1082
+ let t = closingTick;
1083
+ while (t < j && text.charCodeAt(t) === 0x60)
1084
+ t++;
1085
+ while (t < j && TRAILING_PUNCTUATION.has(text.charAt(t)))
1086
+ t++;
1087
+ if (t === j && text.charCodeAt(closingTick) === 0x60) {
1088
+ j = closingTick;
1089
+ while (j > i && text[j - 1] === VIEW_SEPARATOR)
1090
+ j--;
1091
+ }
1092
+ }
939
1093
  if (cut) {
940
1094
  while (j > i && isCutDelimiter(text.charAt(j - 1))) {
941
1095
  j--;
@@ -955,6 +1109,9 @@ function isDiagnosticValue(value, raw = value) {
955
1109
  return true;
956
1110
  if (ADDRESS_SCHEME_RE.test(raw))
957
1111
  return true;
1112
+ return isDiagnosticWord(value);
1113
+ }
1114
+ function isDiagnosticWord(value) {
958
1115
  const bare = value.replace(/^\.+/, '').replace(/[.,;:!?)\]}'"]{0,8}$/, '').toLowerCase();
959
1116
  return bare === '' || DIAGNOSTIC_VALUE_WORDS.has(bare);
960
1117
  }
@@ -1014,6 +1171,26 @@ function isNamedNotValue(label, value) {
1014
1171
  return true;
1015
1172
  return isBacktickedCredentialName(value);
1016
1173
  }
1174
+ function schemeIsLabelValue(text, at) {
1175
+ let k = at;
1176
+ while (k > 0 && text[k - 1] === VIEW_SEPARATOR)
1177
+ k--;
1178
+ if (k > 0 && isQuoteChar(text.charAt(k - 1))) {
1179
+ k--;
1180
+ while (k > 0 && text.charCodeAt(k - 1) === 0x5c)
1181
+ k--;
1182
+ }
1183
+ return k > 0 && labelEndsAt(text, k);
1184
+ }
1185
+ function labelQuotedAt(text, at, sep) {
1186
+ const q = text.charAt(at - 1);
1187
+ if (!isQuoteChar(q))
1188
+ return false;
1189
+ let k = 0;
1190
+ while (sep.charCodeAt(k) === 0x5c)
1191
+ k++;
1192
+ return sep.charAt(k) === q;
1193
+ }
1017
1194
  function labelStartsAt(text, at) {
1018
1195
  const re = new RegExp(SECRET_LABELLED_WORD.source, 'iy');
1019
1196
  re.lastIndex = at;
@@ -1093,6 +1270,35 @@ function percentDecodeForMatching(text) {
1093
1270
  offsets.push(text.length);
1094
1271
  return { decoded: chars.join(''), offsets };
1095
1272
  }
1273
+ const PERCENT_ESCAPE_ASCII = /%[0-7][0-9A-Fa-f]/;
1274
+ const MAX_PERCENT_VIEW_LAYERS = 3;
1275
+ function percentLayers(text) {
1276
+ const out = [];
1277
+ if (!PERCENT_ESCAPE_ASCII.test(text))
1278
+ return out;
1279
+ let cur = text;
1280
+ let ps = null;
1281
+ let pe = null;
1282
+ for (let layer = 0; layer < MAX_PERCENT_VIEW_LAYERS; layer++) {
1283
+ const { decoded, offsets } = percentDecodeForMatching(cur);
1284
+ if (decoded === cur)
1285
+ break;
1286
+ const n = decoded.length;
1287
+ const nps = new Int32Array(n);
1288
+ const npe = new Int32Array(n);
1289
+ for (let k = 0; k < n; k++) {
1290
+ const a = offsets[k] ?? 0;
1291
+ const b = offsets[k + 1] ?? cur.length;
1292
+ nps[k] = ps === null ? a : (ps[a] ?? 0);
1293
+ npe[k] = pe === null ? b : (pe[b - 1] ?? 0);
1294
+ }
1295
+ out.push({ text: decoded, ps: nps, pe: npe });
1296
+ cur = decoded;
1297
+ ps = nps;
1298
+ pe = npe;
1299
+ }
1300
+ return out;
1301
+ }
1096
1302
  function firstLabelCutInPath(path) {
1097
1303
  let cut = -1;
1098
1304
  for (const src of [SECRET_SCHEME_WORD, SECRET_LABELLED_WORD]) {
@@ -1347,7 +1553,7 @@ function quoteSwallowedBefore(S, at) {
1347
1553
  return '';
1348
1554
  return dq === -1 ? "'" : sq === -1 ? '"' : dq < sq ? '"' : "'";
1349
1555
  }
1350
- function labelEndsAt(text, end, atLeast = false) {
1556
+ function labelEndsAt(text, end, atLeast = false, outer = false) {
1351
1557
  let k = end;
1352
1558
  while (k > 0 && isRegexSpace(text.charCodeAt(k - 1)))
1353
1559
  k--;
@@ -1366,7 +1572,7 @@ function labelEndsAt(text, end, atLeast = false) {
1366
1572
  let w = k;
1367
1573
  while (w > 0 && isIdentOrDash(text.charAt(w - 1)))
1368
1574
  w--;
1369
- const re = new RegExp(SECRET_LABELLED_WORD.source, 'iy');
1575
+ const re = new RegExp(outer ? LABEL_WORD_OUTER_SOURCE : SECRET_LABELLED_WORD.source, 'iy');
1370
1576
  for (let s = w; s < k; s++) {
1371
1577
  re.lastIndex = s;
1372
1578
  const m = re.exec(text);
@@ -1924,15 +2130,19 @@ function blockSeqEntries(scan, rawFrom, rawLabel) {
1924
2130
  }
1925
2131
  return out;
1926
2132
  }
1927
- function labelCandidates(S, pass, regions, out, blocks) {
2133
+ function labelCandidates(S, pass, regions, out, blocks, outer = false) {
1928
2134
  const text = S.text;
1929
2135
  const unitAt = (k) => S.unitAt(k);
1930
- const re = pass === 'label' ? SECRET_LABELLED_WORD : SECRET_SCHEME_WORD;
2136
+ const strictSource = pass === 'label' ? SECRET_LABELLED_WORD.source : SECRET_SCHEME_WORD.source;
2137
+ const re = new RegExp(outer ? (pass === 'label' ? LABEL_WORD_OUTER_SOURCE : SCHEME_WORD_OUTER_SOURCE) : strictSource, 'gi');
2138
+ const strictAt = outer ? new RegExp(strictSource, 'iy') : null;
1931
2139
  const schemePass = pass !== 'label';
1932
2140
  const tokenPass = pass === 'token';
1933
- const idx = new InnerWordIndex(text, tokenPass);
2141
+ const rawUnitMap = blocks?.view.rawUnit ?? null;
2142
+ const plainAt = (k) => isPlainAt(S, rawUnitMap, k);
2143
+ const idx = new InnerWordIndex(text, tokenPass, plainAt);
1934
2144
  let listIdx = null;
1935
- const listIndex = () => (listIdx ??= new InnerWordIndex(text, idx.tokenInner));
2145
+ const listIndex = () => (listIdx ??= new InnerWordIndex(text, idx.tokenInner, plainAt));
1936
2146
  let skipFrom = -1;
1937
2147
  let skipTo = -1;
1938
2148
  const flowBudget = { left: 4 * text.length + 4096, pairs: null };
@@ -2171,6 +2381,11 @@ function labelCandidates(S, pass, regions, out, blocks) {
2171
2381
  re.lastIndex = 0;
2172
2382
  hits: for (let hit = re.exec(text); hit !== null; hit = re.exec(text)) {
2173
2383
  const label = hit[1] ?? '';
2384
+ if (strictAt !== null) {
2385
+ strictAt.lastIndex = hit.index;
2386
+ if (strictAt.test(text))
2387
+ continue;
2388
+ }
2174
2389
  if (hit.index >= skipFrom && hit.index < skipTo)
2175
2390
  continue;
2176
2391
  if (schemePass && (label.toLowerCase() === 'token') !== tokenPass)
@@ -2182,6 +2397,16 @@ function labelCandidates(S, pass, regions, out, blocks) {
2182
2397
  if (schemePass && labelStartsAt(text, hit.index))
2183
2398
  continue;
2184
2399
  let from = hit.index + hit[0].length;
2400
+ if (!schemePass && text.charCodeAt(from) === 0x3e && text.charCodeAt(from - 1) === 0x3d && labelQuotedAt(text, hit.index, hit[0].slice(label.length))) {
2401
+ let k = from + 1;
2402
+ while (k < text.length && isInlineBlank(text.charAt(k)))
2403
+ k++;
2404
+ let q = k;
2405
+ while (text.charCodeAt(q) === 0x5c)
2406
+ q++;
2407
+ if (isQuoteChar(text.charAt(q)))
2408
+ from = k;
2409
+ }
2185
2410
  const colonSep = isColonSeparator(hit[0].slice((hit[1] ?? '').length));
2186
2411
  let bulletSkipped = false;
2187
2412
  for (;;) {
@@ -2244,6 +2469,16 @@ function labelCandidates(S, pass, regions, out, blocks) {
2244
2469
  }
2245
2470
  }
2246
2471
  let v0s = scanSecretValue(text, from, idx);
2472
+ let wrapEnd = -1;
2473
+ if (v0s === null) {
2474
+ const w = wrappedValueAt(text, from, idx);
2475
+ if (w !== null) {
2476
+ if (WRAPPED_PLACEHOLDER.test(withoutSeparators(text.slice(w.start, w.end))))
2477
+ continue;
2478
+ v0s = w;
2479
+ wrapEnd = w.end;
2480
+ }
2481
+ }
2247
2482
  if (v0s === null) {
2248
2483
  let k = from;
2249
2484
  while (k < text.length && text[k] === VIEW_SEPARATOR)
@@ -2340,6 +2575,13 @@ function labelCandidates(S, pass, regions, out, blocks) {
2340
2575
  if (a !== -1)
2341
2576
  v.end = a;
2342
2577
  }
2578
+ if (wrapEnd !== -1 && v.end > wrapEnd)
2579
+ v.end = wrapEnd;
2580
+ if (!schemePass && !quoted && wrapEnd === -1 && !inQuery(v.start) && !/authorizations?$/i.test(label)) {
2581
+ const ext = tokenSchemeValueEnd(text, v.start, v.end, idx);
2582
+ if (ext > v.end)
2583
+ v.end = ext;
2584
+ }
2343
2585
  if (!quoted) {
2344
2586
  const trailing = trailingLabelStart(text, v.start, v.end, idx.tokenInner);
2345
2587
  if (trailing > 0 && innerWordHasValue(text, v.start + trailing, idx)) {
@@ -2402,6 +2644,11 @@ function labelCandidates(S, pass, regions, out, blocks) {
2402
2644
  const trailing = trailingLabelStart(text, v.start, end, idx.tokenInner);
2403
2645
  if (trailing !== -1)
2404
2646
  end = v.start + trailing;
2647
+ if (schemePass && schemeIsLabelValue(text, hit.index)) {
2648
+ push(v.start, Math.max(end, v.end), REDACTED_SECRET);
2649
+ re.lastIndex = quoted ? from : Math.max(end, v.end);
2650
+ continue;
2651
+ }
2405
2652
  if (gluedToSingleUnit(v.start, hit.index, unitAt) || userinfoHostHidden(text, v.start, unitAt)) {
2406
2653
  const cut = trailing !== -1 ? end : Math.max(end, v.end);
2407
2654
  const schemeHit = ADDRESS_SCHEME_RE.exec(text.slice(v.start, v.start + 20))?.[0] ?? '';
@@ -2458,6 +2705,19 @@ function isAuthScheme(value) {
2458
2705
  const isKeyWordChar = (c) => (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) || c === 0x5f || c === 0x2d;
2459
2706
  const isAlnumCode = (c) => (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a);
2460
2707
  const PROSE_LITERAL_MIN_RUN = 16;
2708
+ const PROSE_SHORT_LITERAL_MIN_TAIL = 6;
2709
+ function shortLiteralTail(word) {
2710
+ const lit = SECRET_LITERAL_RE.exec(word);
2711
+ if (lit === null)
2712
+ return false;
2713
+ const tail = word.slice(lit[0].length);
2714
+ if (tail.length < PROSE_SHORT_LITERAL_MIN_TAIL)
2715
+ return false;
2716
+ for (let k = 0; k < tail.length; k++)
2717
+ if (!isAlnumCode(tail.charCodeAt(k)))
2718
+ return false;
2719
+ return true;
2720
+ }
2461
2721
  function longestAlnumRun(word) {
2462
2722
  let best = 0;
2463
2723
  let run = 0;
@@ -2799,8 +3059,112 @@ function authParamEdits(text) {
2799
3059
  }
2800
3060
  return edits;
2801
3061
  }
3062
+ const LITERAL_PROBE_WINDOW = 64;
3063
+ function gluedLiteralStart(word) {
3064
+ const n = word.length;
3065
+ if (n < PROSE_SHORT_LITERAL_MIN_TAIL + 4)
3066
+ return 0;
3067
+ const runFrom = new Int32Array(n + 1);
3068
+ let best = 0;
3069
+ let run = 0;
3070
+ for (let k = n - 1; k >= 0; k--) {
3071
+ if (isAlnumCode(word.charCodeAt(k))) {
3072
+ run++;
3073
+ if (run > best)
3074
+ best = run;
3075
+ }
3076
+ else
3077
+ run = 0;
3078
+ runFrom[k] = best;
3079
+ }
3080
+ for (let k = 1; k < n; k++) {
3081
+ const left = word.charCodeAt(k - 1);
3082
+ if ((left !== 0x5f && left !== 0x2d) || !isAlnumCode(word.charCodeAt(k)))
3083
+ continue;
3084
+ const run = runFrom[k] ?? 0;
3085
+ if (run < PROSE_SHORT_LITERAL_MIN_TAIL)
3086
+ return 0;
3087
+ if (SECRET_LITERAL_RE.test(word.slice(k, k + LITERAL_PROBE_WINDOW)) && (run >= PROSE_LITERAL_MIN_RUN || shortLiteralTail(word.slice(k))))
3088
+ return k;
3089
+ }
3090
+ return 0;
3091
+ }
3092
+ const OPAQUE_MIN_LENGTH = 24;
3093
+ const OPAQUE_MIN_ENTROPY = 3.5;
3094
+ const OPAQUE_MAX_AVG_SEGMENT = 2.5;
3095
+ const BASE64_FILE_SIGNATURES = ['iVBORw0KGgo', 'R0lGOD', 'UklGR', 'JVBERi0', 'UEsDB', 'H4sI', 'PHN2Zy', 'PD94bWwg', 'AAABAA'];
3096
+ const NON_SECRET_ID_PREFIXES = new Set(['toolu', 'srvtoolu', 'msg', 'msgbatch', 'req', 'file', 'chatcmpl', 'call', 'resp']);
3097
+ function isOpaqueWord(text, i, end) {
3098
+ if (end - i < OPAQUE_MIN_LENGTH)
3099
+ return false;
3100
+ const prev = text.charAt(i - 1);
3101
+ const next = text.charAt(end);
3102
+ if (prev === '+' || prev === '@' || next === '+' || next === '/' || next === '=' || next === '@')
3103
+ return false;
3104
+ if (next === '.' && isKeyWordChar(text.charCodeAt(end + 1)))
3105
+ return false;
3106
+ if (text.slice(Math.max(0, i - 7), i).toLowerCase() === 'base64,')
3107
+ return false;
3108
+ const word = text.slice(i, end);
3109
+ if (/^[0-9A-Fa-f_-]+$/.test(word) || /^sha(?:1|256|384|512)-/i.test(word))
3110
+ return false;
3111
+ if (BASE64_FILE_SIGNATURES.some((sig) => word.startsWith(sig)))
3112
+ return false;
3113
+ const typed = /^([a-z]+)[_-]/.exec(word);
3114
+ if (typed !== null && NON_SECRET_ID_PREFIXES.has(typed[1] ?? ''))
3115
+ return false;
3116
+ let upper = false;
3117
+ let lower = false;
3118
+ let digit = false;
3119
+ const counts = new Map();
3120
+ for (let k = 0; k < word.length; k++) {
3121
+ const c = word.charCodeAt(k);
3122
+ if (c >= 0x41 && c <= 0x5a)
3123
+ upper = true;
3124
+ else if (c >= 0x61 && c <= 0x7a)
3125
+ lower = true;
3126
+ else if (c >= 0x30 && c <= 0x39)
3127
+ digit = true;
3128
+ counts.set(c, (counts.get(c) ?? 0) + 1);
3129
+ }
3130
+ if (!upper || !lower || !digit)
3131
+ return false;
3132
+ let entropy = 0;
3133
+ for (const n of counts.values()) {
3134
+ const p = n / word.length;
3135
+ entropy -= p * Math.log2(p);
3136
+ }
3137
+ if (entropy < OPAQUE_MIN_ENTROPY)
3138
+ return false;
3139
+ let segments = 0;
3140
+ let segmentChars = 0;
3141
+ for (const m of word.matchAll(/[A-Z]?[a-z]+|[A-Z]+(?![a-z])|[0-9]+/g)) {
3142
+ segments++;
3143
+ segmentChars += m[0].length;
3144
+ }
3145
+ return segments > 0 && segmentChars / segments <= OPAQUE_MAX_AVG_SEGMENT;
3146
+ }
3147
+ const FILE_URL_OPENERS = new Set(['(', '[', '<', "'", ',', ';']);
3148
+ function fileUrlPositions(text) {
3149
+ let marks = null;
3150
+ const re = /file:/gi;
3151
+ for (let hit = re.exec(text); hit !== null; hit = re.exec(text)) {
3152
+ const s = hit.index;
3153
+ if (s > 0 && !endsUrlFragmentAt(text, s - 1) && !FILE_URL_OPENERS.has(text.charAt(s - 1)))
3154
+ continue;
3155
+ let e = s + hit[0].length;
3156
+ while (e < text.length && !endsUrlFragmentAt(text, e))
3157
+ e++;
3158
+ marks ??= new Uint8Array(text.length);
3159
+ for (let k = s; k < e; k++)
3160
+ marks[k] = 1;
3161
+ re.lastIndex = e;
3162
+ }
3163
+ return marks;
3164
+ }
2802
3165
  function proseLiteralEdits(text) {
2803
3166
  const edits = [];
3167
+ let fileAt;
2804
3168
  let i = 0;
2805
3169
  while (i < text.length) {
2806
3170
  const c = text.charCodeAt(i);
@@ -2811,6 +3175,7 @@ function proseLiteralEdits(text) {
2811
3175
  let end = i;
2812
3176
  while (end < text.length && isKeyWordChar(text.charCodeAt(end)))
2813
3177
  end++;
3178
+ const escHead = i > 0 && text.charCodeAt(i - 1) === 0x25 && PERCENT_ESCAPE_ASCII.test(text.slice(i - 1, i + 2)) && i + 2 < end ? 2 : 0;
2814
3179
  const word = text.slice(i, end);
2815
3180
  if (word.startsWith('eyJ')) {
2816
3181
  let segEnd = end;
@@ -2829,15 +3194,33 @@ function proseLiteralEdits(text) {
2829
3194
  }
2830
3195
  const prev = i > 0 ? text.charAt(i - 1) : '';
2831
3196
  const hostSlot = prev === '/' && i > 1 && text.charAt(i - 2) === '/';
2832
- const pathish = (prev === '/' && !hostSlot) || prev === '\\' || prev === '.';
2833
- if (!pathish && SECRET_LITERAL_RE.test(word) && longestAlnumRun(word) >= PROSE_LITERAL_MIN_RUN) {
2834
- pushEdit(edits, text, i, end, REDACTED_SECRET);
3197
+ const slashSegment = prev === '/' && !hostSlot;
3198
+ if (slashSegment && fileAt === undefined)
3199
+ fileAt = fileUrlPositions(text);
3200
+ const localPath = prev === '\\' || prev === '.' || (slashSegment && fileAt != null && fileAt[i] === 1);
3201
+ const pathish = slashSegment || localPath;
3202
+ if (!localPath && SECRET_LITERAL_RE.test(word) && (longestAlnumRun(word) >= PROSE_LITERAL_MIN_RUN || shortLiteralTail(word))) {
3203
+ pushEdit(edits, text, i + escHead, end, REDACTED_SECRET);
3204
+ }
3205
+ else if (!localPath) {
3206
+ const glued = gluedLiteralStart(word);
3207
+ if (glued > 0)
3208
+ pushEdit(edits, text, i + Math.max(glued, escHead), end, REDACTED_SECRET);
3209
+ else if (!pathish && !hostSlot && isOpaqueWord(text, i, end))
3210
+ pushEdit(edits, text, i + escHead, end, REDACTED_SECRET);
2835
3211
  }
2836
3212
  i = end;
2837
3213
  }
2838
3214
  return edits;
2839
3215
  }
3216
+ const C0_ALL = '\\u0000-\\u001F';
3217
+ const C0_KEEP_LAYOUT = '\\u0000-\\u0008\\u000B-\\u001F';
3218
+ const DEL_C1 = '\\u007F-\\u009F';
3219
+ const LONE_SURROGATE = '\\uD800-\\uDFFF';
3220
+ const LINE_SEPARATORS = '\\u2028\\u2029';
2840
3221
  const FORMAT_CHAR = /^\p{Cf}$/u;
3222
+ const FORMAT_CLASS = FORMAT_CHAR.source.slice(1, -1);
3223
+ const FACE_MARKED_CHAR = new RegExp(`^(?:[${C0_ALL}${DEL_C1}${LONE_SURROGATE}${LINE_SEPARATORS}]|${FORMAT_CLASS})$`, 'u');
2841
3224
  const isStrippableControl = (c) => (c <= 0x1f && (c < 0x09 || c > 0x0d)) || (c >= 0x7f && c <= 0x9f);
2842
3225
  class SequenceReader {
2843
3226
  text;
@@ -2965,13 +3348,7 @@ function c1SequenceAfter(text, c1, at, seq) {
2965
3348
  return null;
2966
3349
  }
2967
3350
  function isFaceMarkedCodePoint(cp) {
2968
- if (cp <= 0x1f || (cp >= 0x7f && cp <= 0x9f))
2969
- return true;
2970
- if (cp >= 0xd800 && cp <= 0xdfff)
2971
- return true;
2972
- if (cp === 0x2028 || cp === 0x2029)
2973
- return true;
2974
- return cp >= 0xad && cp <= 0x10ffff && FORMAT_CHAR.test(String.fromCodePoint(cp));
3351
+ return cp >= 0 && cp <= 0x10ffff && FACE_MARKED_CHAR.test(String.fromCodePoint(cp));
2975
3352
  }
2976
3353
  function escapeTokenAt(text, at) {
2977
3354
  const four = /^\\u([0-9A-Fa-f]{4})/.exec(text.slice(at, at + 6));
@@ -3287,8 +3664,39 @@ function screenSurfaces(text, o) {
3287
3664
  if (joinedSpaced !== null)
3288
3665
  out.push(joinedSpaced);
3289
3666
  const contents = V.contents.map(([a, b]) => ({ sub: screen.slice(a, b), rawAt: (k) => M.ps[a + k] ?? 0, rawEndAt: (k) => M.pe[a + k] ?? 0 }));
3667
+ const decoded = percentSurfaces(text, screen, M, o);
3668
+ out.push(...decoded.surfaces);
3669
+ contents.push(...decoded.contents);
3290
3670
  return { surfaces: out, rawSoft, rawPlain, contents };
3291
3671
  }
3672
+ function percentSurfaces(raw, text, base, o) {
3673
+ const surfaces = [];
3674
+ const contents = [];
3675
+ for (const layer of percentLayers(text)) {
3676
+ const n = layer.text.length;
3677
+ const ps = new Int32Array(n);
3678
+ const pe = new Int32Array(n);
3679
+ const pdot = new Uint8Array(n);
3680
+ for (let k = 0; k < n; k++) {
3681
+ const a = layer.ps[k] ?? 0;
3682
+ const b = layer.pe[k] ?? 0;
3683
+ ps[k] = base === null ? a : (base.ps[a] ?? 0);
3684
+ pe[k] = base === null ? b : (base.pe[b - 1] ?? 0);
3685
+ if (base !== null && b - a === 1)
3686
+ pdot[k] = base.pdot[a] ?? 0;
3687
+ }
3688
+ const M = { ps, pe, pdot, rawDot: base === null ? new Uint8Array(raw.length) : base.rawDot };
3689
+ const VD = buildScanView(layer.text, o);
3690
+ const sep = separatedSurface(raw, VD, M);
3691
+ surfaces.push(base === null ? { ...sep, rawDot: null } : sep);
3692
+ const joined = joinedSurface(raw, VD, false, M);
3693
+ if (joined !== null)
3694
+ surfaces.push(base === null ? { ...joined, rawDot: null } : joined);
3695
+ for (const [a, b] of VD.contents)
3696
+ contents.push({ sub: layer.text.slice(a, b), rawAt: (k) => ps[a + k] ?? 0, rawEndAt: (k) => pe[a + k] ?? 0 });
3697
+ }
3698
+ return { surfaces, contents };
3699
+ }
3292
3700
  function finalIsStructural(text, at) {
3293
3701
  if (text.charCodeAt(at) !== 0x5c)
3294
3702
  return false;
@@ -3557,6 +3965,9 @@ function collectCandidates(text, o, nested) {
3557
3965
  surfaces.push(joinedSpaced);
3558
3966
  const screen = screenSurfaces(text, o);
3559
3967
  surfaces.push(...screen.surfaces);
3968
+ const decoded = percentSurfaces(text, text, null, o);
3969
+ surfaces.push(...decoded.surfaces);
3970
+ const decodedContents = decoded.contents;
3560
3971
  const raw = [];
3561
3972
  const blocks = { raw: text, view: V, out: raw, lines: [null, null], marks: null };
3562
3973
  const regionSurface = screen.surfaces[0] ?? separated;
@@ -3566,7 +3977,7 @@ function collectCandidates(text, o, nested) {
3566
3977
  const regions = [];
3567
3978
  if (o.urls) {
3568
3979
  const unitPos = (k) => S.dropped(k) || V.rawUnit[S.rawStart(k)] === 1;
3569
- urlCandidates(S.text, cands, regions, unitPos, (k) => unitPos(k) || S.painted(k));
3980
+ urlCandidates(S.text, cands, regions, unitPos, (k) => unitPos(k) || S.painted(k), o.queryByShape ?? false);
3570
3981
  userinfoCandidates(S, cands, o.words);
3571
3982
  }
3572
3983
  if (o.words) {
@@ -3575,6 +3986,8 @@ function collectCandidates(text, o, nested) {
3575
3986
  labelCandidates(S, 'scheme', regions, cands, blocks);
3576
3987
  labelCandidates(S, 'token', regions, cands, blocks);
3577
3988
  labelCandidates(S, 'label', regions, cands, blocks);
3989
+ labelCandidates(S, 'scheme', regions, cands, blocks, true);
3990
+ labelCandidates(S, 'label', regions, cands, blocks, true);
3578
3991
  editsToCandidates(authParamEdits(S.text), 'param', cands);
3579
3992
  editsToCandidates(proseLiteralEdits(S.text), 'prose', cands);
3580
3993
  }
@@ -3592,7 +4005,7 @@ function collectCandidates(text, o, nested) {
3592
4005
  raw.push({ start: a + iv.start, end: a + iv.end, kind: iv.kind, cls: 'nested', tokenEnd: a + iv.end, pretrimmed: true });
3593
4006
  }
3594
4007
  }
3595
- for (const c of screen.contents) {
4008
+ for (const c of [...screen.contents, ...decodedContents]) {
3596
4009
  const inner = collectCandidates(c.sub, o, true);
3597
4010
  for (const iv of resolveCandidates(c.sub, inner.cands, inner.rawUnit, inner.rawDot, o.words ? pemRegions(inner.pemBlocksSeen) : [], inner.rawSoft, inner.rawPlain)) {
3598
4011
  const start = c.rawAt(iv.start);
@@ -3661,11 +4074,6 @@ export function washCredentials(text) {
3661
4074
  return text;
3662
4075
  return scanAndMask(text, WASH_OPTIONS, false).text;
3663
4076
  }
3664
- const C0_ALL = '\\u0000-\\u001F';
3665
- const C0_KEEP_LAYOUT = '\\u0000-\\u0008\\u000B-\\u001F';
3666
- const DEL_C1 = '\\u007F-\\u009F';
3667
- const LONE_SURROGATE = '\\uD800-\\uDFFF';
3668
- const LINE_SEPARATORS = '\\u2028\\u2029';
3669
4077
  const NAME_BLANKS = NAME_BLANK_RANGES.map(([a, b]) => (a === b ? classEscape(a) : `${classEscape(a)}-${classEscape(b)}`)).join('');
3670
4078
  function classEscape(cp) {
3671
4079
  return `\\u${cp.toString(16).toUpperCase().padStart(4, '0')}`;
@@ -3770,9 +4178,7 @@ function faceHitKept(ch, at, text) {
3770
4178
  const c = ch.charCodeAt(0);
3771
4179
  return ch.length === 1 && (c === 0x200d || c === 0x200c) && joinerKept(text, at, c === 0x200d);
3772
4180
  }
3773
- const FORMAT_CLASS = '\\p{Cf}';
3774
4181
  const RGI_TAG_FLAG = '\\u{1F3F4}\\u{E0067}\\u{E0062}(?:\\u{E0065}\\u{E006E}\\u{E0067}|\\u{E0073}\\u{E0063}\\u{E0074}|\\u{E0077}\\u{E006C}\\u{E0073})\\u{E007F}';
3775
- const BIDI_REORDER = '\\u061C\\u200E\\u200F\\u2028\\u2029\\u202A-\\u202E\\u2066-\\u2069';
3776
4182
  function unsafeClass(members, withFormatClass) {
3777
4183
  if (members === '' && !withFormatClass)
3778
4184
  return null;
@@ -3783,17 +4189,6 @@ function unsafeClass(members, withFormatClass) {
3783
4189
  ];
3784
4190
  return new RegExp(parts.join('|'), 'gu');
3785
4191
  }
3786
- export const LEGACY_ESCAPE_FACE = Object.freeze({
3787
- unsafe: unsafeClass(`${C0_ALL}${DEL_C1}${BIDI_REORDER}${LONE_SURROGATE}`, false),
3788
- fold: false,
3789
- mark: 'escape',
3790
- });
3791
- export const LEGACY_LABEL_FACE = Object.freeze({ ...LEGACY_ESCAPE_FACE, fold: true });
3792
- export const LEGACY_NAME_FACE = Object.freeze({
3793
- unsafe: unsafeClass(`${C0_ALL}\\u007F${LINE_SEPARATORS}`, false),
3794
- fold: true,
3795
- mark: 'space',
3796
- });
3797
4192
  function markOf(ch, mark) {
3798
4193
  if (mark === 'dot')
3799
4194
  return '.';
@@ -3971,8 +4366,11 @@ function publicFace(opts) {
3971
4366
  const index = (opts.controls !== false ? 8 : 0) + (opts.bidi !== false ? 4 : 0) + (keep ? 2 : 0) + (blanks ? 1 : 0);
3972
4367
  return { unsafe: PUBLIC_UNSAFE_BY_NETS[index] ?? null, fold, mark: opts.mark ?? 'escape', keepBlanks: blanks };
3973
4368
  }
4369
+ export const ESCAPE_FACE = Object.freeze({ ...publicFace({ foldLines: false }) });
4370
+ export const LABEL_FACE = Object.freeze({ ...publicFace({}) });
4371
+ export const PEER_NAME_FACE = Object.freeze({ ...publicFace({ mark: 'space' }) });
3974
4372
  const ESCAPE_TOKEN_AT = /^\\u(?:[0-9A-F]{4}|\{[0-9A-F]{1,6}\})/;
3975
- function capDisplay(text, max, mark) {
4373
+ export function capDisplay(text, max, mark) {
3976
4374
  if (typeof max !== 'number' || !Number.isFinite(max))
3977
4375
  return text;
3978
4376
  const limit = Math.max(0, Math.floor(max));
@@ -4011,6 +4409,14 @@ function runDisplaySteps(start, steps) {
4011
4409
  }
4012
4410
  return out;
4013
4411
  }
4412
+ export function paintAndCap(text, face, max) {
4413
+ return runDisplaySteps(text, {
4414
+ wash: (s) => s,
4415
+ paint: (s) => applyDisplayFace(s, face),
4416
+ cap: (s) => capDisplay(s, max, face.mark),
4417
+ text: (s) => s,
4418
+ });
4419
+ }
4014
4420
  function escapeSpacesFor(o, face) {
4015
4421
  if (face.mark !== 'escape' || face.fold)
4016
4422
  return null;
@@ -4029,9 +4435,10 @@ function escapeSpacesFor(o, face) {
4029
4435
  }
4030
4436
  return set.size === 0 ? null : set;
4031
4437
  }
4032
- function scanOptionsOf(o, face) {
4438
+ function scanOptionsOf(o, face, queryByShape = false) {
4033
4439
  return {
4034
4440
  urls: o.credentialUrls !== false,
4441
+ queryByShape,
4035
4442
  words: o.credentialWords !== false,
4036
4443
  blanks: face.keepBlanks === true,
4037
4444
  fold: face.fold,
@@ -4046,11 +4453,11 @@ export function credentialWashPasses(text, opts = {}) {
4046
4453
  scanAndMask(input, scan, false, stats);
4047
4454
  return { passes: stats.passes, capped: stats.capped };
4048
4455
  }
4049
- function renderUntrusted(text, opts, ledger) {
4456
+ function renderUntrusted(text, opts, ledger, queryByShape = false) {
4050
4457
  const input = typeof text === 'string' ? text : String(text ?? '');
4051
4458
  const o = opts ?? {};
4052
4459
  const face = publicFace(o);
4053
- const scan = scanOptionsOf(o, face);
4460
+ const scan = scanOptionsOf(o, face, queryByShape);
4054
4461
  const pairBackslashes = o.escapeBackslashes === true && face.mark !== 'dot' && face.mark !== 'space';
4055
4462
  const book = ledger ?? (pairBackslashes ? { cps: [], lens: [] } : null);
4056
4463
  if (book === null) {
@@ -4081,6 +4488,197 @@ export function displayUntrusted(text, opts = {}) {
4081
4488
  const out = renderUntrusted(text, opts, null);
4082
4489
  return typeof out === 'string' ? out : out.text;
4083
4490
  }
4491
+ const NON_SECRET_FIELD_NAMES = new Set([
4492
+ 'deployment', 'deploymentname', 'deploymentid', 'name', 'tenant', 'tenantname', 'tenantid', 'region', 'location', 'zone',
4493
+ 'project', 'projectname', 'projectid', 'workspace', 'workspacename', 'workspaceid', 'resource', 'resourcename', 'resourcegroup',
4494
+ 'model', 'modelname', 'modelid', 'apiversion', 'version', 'env', 'environment', 'stage', 'cluster', 'namespace', 'instance',
4495
+ 'service', 'servicename', 'app', 'appname', 'application', 'team', 'site', 'org', 'organization',
4496
+ ]);
4497
+ function isNonSecretFieldName(key) {
4498
+ const view = percentDecodeForMatching(key).decoded;
4499
+ return NON_SECRET_FIELD_NAMES.has(view.toLowerCase().replace(/[-_]/g, ''));
4500
+ }
4501
+ function isCredentialLabelName(name) {
4502
+ if (name.length === 0)
4503
+ return false;
4504
+ const decoded = percentDecodeForMatching(name).decoded;
4505
+ for (const view of decoded === name ? [name] : [name, decoded]) {
4506
+ const probe = `${view}=`;
4507
+ if (labelEndsAt(probe, probe.length, false, true))
4508
+ return true;
4509
+ }
4510
+ return false;
4511
+ }
4512
+ const WORD_CHAIN_MAX_SUFFIX_DIGITS = 4;
4513
+ const WORD_CHAIN_MAX_DIGIT_RUN = 8;
4514
+ function isReadableWordChain(value) {
4515
+ const core = valueCoreForJudging(value);
4516
+ if (core.length === 0 || !core.includes('-'))
4517
+ return false;
4518
+ const segments = core.split('-');
4519
+ if (segments.length < 2)
4520
+ return false;
4521
+ if (!segments.some((seg) => seg.length >= 3 && [...seg].every(isAlpha)))
4522
+ return false;
4523
+ if ([...core].every((ch) => ch === '-' || isHexDigit(ch)))
4524
+ return false;
4525
+ for (const seg of segments) {
4526
+ const letters = seg.replace(/[0-9]+$/, '').toLowerCase();
4527
+ if (/[bcdfghjklmnpqrstvwxz]{4,}/.test(letters))
4528
+ return false;
4529
+ if (letters.length >= 5 && !/[aeiouy]/.test(letters))
4530
+ return false;
4531
+ }
4532
+ for (const seg of segments) {
4533
+ if (seg.length === 0)
4534
+ return false;
4535
+ let i = 0;
4536
+ while (i < seg.length && isAlpha(seg.charAt(i)))
4537
+ i++;
4538
+ const letters = seg.slice(0, i);
4539
+ const digits = seg.slice(i);
4540
+ for (const ch of digits)
4541
+ if (ch < '0' || ch > '9')
4542
+ return false;
4543
+ if (letters.length === 0) {
4544
+ if (digits.length === 0 || digits.length > WORD_CHAIN_MAX_DIGIT_RUN)
4545
+ return false;
4546
+ continue;
4547
+ }
4548
+ const caseOk = letters === letters.toLowerCase() || letters === letters.toUpperCase() ||
4549
+ (letters.charAt(0) === letters.charAt(0).toUpperCase() && letters.slice(1) === letters.slice(1).toLowerCase());
4550
+ if (!caseOk)
4551
+ return false;
4552
+ if (digits.length > 0 && (letters.length < 2 || digits.length > WORD_CHAIN_MAX_SUFFIX_DIGITS))
4553
+ return false;
4554
+ }
4555
+ return true;
4556
+ }
4557
+ const OPAQUE_TOKEN_PUNCTUATION = new Set(['-', '_', '.', '~', '+', '/', '=']);
4558
+ const HIGH_ENTROPY_MIN_ALNUM = 20;
4559
+ function isHighEntropyQueryValue(value) {
4560
+ const { decoded } = percentDecodeForMatching(value);
4561
+ let alnum = 0;
4562
+ let mixed = 0;
4563
+ let run = 0;
4564
+ let runHasLetter = false;
4565
+ let runHasDigit = false;
4566
+ let anyLetter = false;
4567
+ let anyDigit = false;
4568
+ let allHex = true;
4569
+ const flush = () => {
4570
+ alnum += run;
4571
+ if (runHasLetter && runHasDigit)
4572
+ mixed += run;
4573
+ run = 0;
4574
+ runHasLetter = false;
4575
+ runHasDigit = false;
4576
+ };
4577
+ for (const ch of decoded) {
4578
+ if (isAlpha(ch)) {
4579
+ run += 1;
4580
+ runHasLetter = true;
4581
+ anyLetter = true;
4582
+ if (!isHexDigit(ch))
4583
+ allHex = false;
4584
+ continue;
4585
+ }
4586
+ if (ch >= '0' && ch <= '9') {
4587
+ run += 1;
4588
+ runHasDigit = true;
4589
+ anyDigit = true;
4590
+ continue;
4591
+ }
4592
+ if (!OPAQUE_TOKEN_PUNCTUATION.has(ch))
4593
+ return false;
4594
+ flush();
4595
+ }
4596
+ flush();
4597
+ if (alnum < HIGH_ENTROPY_MIN_ALNUM)
4598
+ return false;
4599
+ return mixed * 2 >= alnum || (allHex && anyLetter && anyDigit);
4600
+ }
4601
+ function isOpaqueSecretValue(value) {
4602
+ const core = valueCoreForJudging(value);
4603
+ return core.length > 0 && (looksLikeKnownSecret(core) || isHighEntropyQueryValue(core));
4604
+ }
4605
+ const VALUE_PIECE_SEPARATORS = new Set(['/', '\\', '?', '#', '&', '=', ';', ':', '@', ',', '+']);
4606
+ function hasOpaquePiece(text) {
4607
+ let start = 0;
4608
+ for (let i = 0; i <= text.length; i++) {
4609
+ const ch = text.charAt(i);
4610
+ if (i === text.length || ch <= ' ' || VALUE_PIECE_SEPARATORS.has(ch)) {
4611
+ if (i > start && isOpaqueSecretValue(text.slice(start, i)))
4612
+ return true;
4613
+ start = i + 1;
4614
+ }
4615
+ }
4616
+ return false;
4617
+ }
4618
+ function carriesCredentialStructure(value) {
4619
+ const netChanges = (v) => {
4620
+ if (washCredentials(v) !== v || hasOpaquePiece(v))
4621
+ return true;
4622
+ if (!v.includes('+'))
4623
+ return false;
4624
+ const spaced = v.split('+').join(' ');
4625
+ return washCredentials(spaced) !== spaced;
4626
+ };
4627
+ let view = value;
4628
+ for (let layer = 0; layer < MAX_PERCENT_VIEW_LAYERS; layer++) {
4629
+ if (netChanges(view))
4630
+ return true;
4631
+ const next = percentDecodeForMatching(view).decoded;
4632
+ if (next === view)
4633
+ return false;
4634
+ view = next;
4635
+ }
4636
+ if (netChanges(view))
4637
+ return true;
4638
+ return percentDecodeForMatching(view).decoded !== view;
4639
+ }
4640
+ function queryPartCarriesCredential(key, value, relax) {
4641
+ if (value.length === 0 || isMarker(value))
4642
+ return false;
4643
+ if (key !== null) {
4644
+ if (isCredentialLabelName(key))
4645
+ return true;
4646
+ if (relax && isNonSecretFieldName(key) && isReadableWordChain(value))
4647
+ return isKnownSecretSegment(value);
4648
+ }
4649
+ return isOpaqueSecretValue(value) || carriesCredentialStructure(value);
4650
+ }
4651
+ const UPLOAD_PROBE_PREFIX = 'https://q.invalid/?';
4652
+ const UPLOAD_SCAN_OPTIONS = Object.freeze({ urls: true, queryByShape: 'strict', words: true, blanks: false, fold: false, face: null, escapeSpaces: null });
4653
+ export function queryCarriesCredential(query) {
4654
+ if (typeof query !== 'string' || query.length === 0)
4655
+ return false;
4656
+ const probe = `${UPLOAD_PROBE_PREFIX}${query}`;
4657
+ return scanOnce(probe, UPLOAD_SCAN_OPTIONS, false).text !== probe;
4658
+ }
4659
+ export function displayConfiguredUrl(url, opts = {}) {
4660
+ const out = renderUntrusted(typeof url === 'string' ? configuredUrlScannable(url) : url, opts, null, 'relaxed');
4661
+ return typeof out === 'string' ? out : out.text;
4662
+ }
4663
+ function configuredUrlScannable(url) {
4664
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(url) || !/^[A-Za-z][A-Za-z0-9+.-]*:/.test(url))
4665
+ return url;
4666
+ let u;
4667
+ try {
4668
+ u = new URL(url);
4669
+ }
4670
+ catch {
4671
+ return url;
4672
+ }
4673
+ if (u.host === '')
4674
+ return url;
4675
+ const userinfo = u.username !== '' || u.password !== '' ? `${u.username}${u.password !== '' ? `:${u.password}` : ''}@` : '';
4676
+ return `${u.protocol}//${userinfo}${u.host}${u.pathname}${u.search}${u.hash}`;
4677
+ }
4678
+ export function quoteUntrustedForSentence(text, max) {
4679
+ const shown = displayUntrusted(text, { max, blanks: true, escapeBackslashes: true });
4680
+ return shown.trim() === '' ? undefined : `"${shown.replace(/"/g, '\\"')}"`;
4681
+ }
4084
4682
  export function displayUntrustedMarks(text, opts = {}) {
4085
4683
  const ledger = { cps: [], lens: [] };
4086
4684
  const out = renderUntrusted(text, opts, ledger);
@@ -4088,4 +4686,4 @@ export function displayUntrustedMarks(text, opts = {}) {
4088
4686
  return { text: out, marks: [] };
4089
4687
  return { text: out.text, marks: collectMarks(out, ledger) };
4090
4688
  }
4091
- const isQuoteChar = (c) => c.charCodeAt(0) === 0x22 || c.charCodeAt(0) === 0x27 || (c === '' && /`/.test(c));
4689
+ const isQuoteChar = (c) => c.charCodeAt(0) === 0x22 || c.charCodeAt(0) === 0x27;