@sema-agent/server 7.136.0 → 7.138.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 (327) hide show
  1. package/MIGRATION.md +501 -139
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +149 -34
  5. package/deploy/sema-up/README.md +14 -0
  6. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +21 -14
  9. package/dist/approval-card.js +1 -0
  10. package/dist/approval-content-kind.d.ts +6 -0
  11. package/dist/approval-content-kind.js +7 -0
  12. package/dist/approval-gate-currency.d.ts +48 -6
  13. package/dist/approval-gate-currency.js +16 -9
  14. package/dist/approval-hmac.d.ts +13 -1
  15. package/dist/approval-hmac.js +1 -1
  16. package/dist/approval.js +3 -3
  17. package/dist/audit.js +1 -0
  18. package/dist/auth-bridge.js +2 -2
  19. package/dist/background-agent-name.d.ts +5 -0
  20. package/dist/background-agent-name.js +5 -0
  21. package/dist/boot/budget-tracing.d.ts +1 -12
  22. package/dist/boot/deployment-mods.d.ts +46 -16
  23. package/dist/boot/deployment-mods.js +82 -6
  24. package/dist/boot/execution-env.d.ts +24 -1
  25. package/dist/boot/execution-env.js +69 -6
  26. package/dist/boot/governance-seams.d.ts +10 -17
  27. package/dist/boot/governance-seams.js +5 -17
  28. package/dist/boot/leader.d.ts +3 -0
  29. package/dist/boot/leader.js +1 -0
  30. package/dist/boot/org-delivery.js +15 -2
  31. package/dist/boot/reapers.d.ts +3 -0
  32. package/dist/boot/reapers.js +15 -1
  33. package/dist/boot/resolve-spec.d.ts +7 -0
  34. package/dist/boot/resolve-spec.js +36 -26
  35. package/dist/boot/retention-lane.d.ts +11 -5
  36. package/dist/boot/retention-lane.js +2 -2
  37. package/dist/boot/runner-deps.d.ts +7 -3
  38. package/dist/boot/runner-deps.js +1 -0
  39. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  40. package/dist/boot/stage-04-stores.d.ts +2 -13
  41. package/dist/boot/stage-05-execution-env.d.ts +6 -13
  42. package/dist/boot/stage-05-execution-env.js +17 -5
  43. package/dist/boot/stage-06-runners.d.ts +6 -13
  44. package/dist/boot/stage-06-runners.js +10 -3
  45. package/dist/boot/stage-07-capability-layer.d.ts +7 -13
  46. package/dist/boot/stage-07-capability-layer.js +3 -3
  47. package/dist/boot/stage-08-reapers.d.ts +7 -13
  48. package/dist/boot/stage-08-reapers.js +2 -1
  49. package/dist/boot/stage-09-leader.d.ts +7 -13
  50. package/dist/boot/stage-09-leader.js +2 -2
  51. package/dist/boot/stage-10-http-server.d.ts +7 -13
  52. package/dist/boot/stage-10-http-server.js +6 -3
  53. package/dist/boot/stores.d.ts +1 -1
  54. package/dist/boot/web-admin.d.ts +5 -2
  55. package/dist/boot/web-admin.js +3 -3
  56. package/dist/brain.js +5 -5
  57. package/dist/broker/broker.d.ts +89 -0
  58. package/dist/broker/broker.js +287 -0
  59. package/dist/broker/constants.d.ts +39 -0
  60. package/dist/broker/constants.js +15 -0
  61. package/dist/broker/http1.d.ts +111 -0
  62. package/dist/broker/http1.js +256 -0
  63. package/dist/broker/lease-book.d.ts +87 -0
  64. package/dist/broker/lease-book.js +142 -0
  65. package/dist/broker/lease-file.d.ts +60 -0
  66. package/dist/broker/lease-file.js +127 -0
  67. package/dist/broker/main.d.ts +2 -0
  68. package/dist/broker/main.js +20 -0
  69. package/dist/budget.d.ts +17 -15
  70. package/dist/budget.js +2 -2
  71. package/dist/capabilities/composite-members.d.ts +2 -1
  72. package/dist/capabilities/composite-members.js +2 -1
  73. package/dist/capabilities/engine-capabilities.js +1 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -11
  75. package/dist/capabilities/mcp-probe.js +44 -5
  76. package/dist/capabilities/scenarios.d.ts +23 -8
  77. package/dist/capabilities/scenarios.js +13 -8
  78. package/dist/capabilities/skills.d.ts +28 -5
  79. package/dist/capabilities/skills.js +8 -0
  80. package/dist/capability-facts.d.ts +6 -0
  81. package/dist/capability-facts.js +5 -0
  82. package/dist/center-credential-renewer.js +5 -1
  83. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  84. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  85. package/dist/checkpoint-identity.d.ts +13 -6
  86. package/dist/config-catalog.js +16 -7
  87. package/dist/config-types.d.ts +24 -7
  88. package/dist/config.d.ts +1 -1
  89. package/dist/config.js +42 -13
  90. package/dist/deployment-governance.d.ts +2 -2
  91. package/dist/deployment-governance.js +7 -9
  92. package/dist/deployment-shape.d.ts +6 -6
  93. package/dist/device-ws-protocol.d.ts +1 -0
  94. package/dist/device-ws-protocol.js +2 -1
  95. package/dist/file-history-disclosure.d.ts +4 -2
  96. package/dist/file-history-disclosure.js +2 -0
  97. package/dist/gate-settlement.d.ts +71 -0
  98. package/dist/gate-settlement.js +40 -0
  99. package/dist/hooks/classic-stations.d.ts +12 -54
  100. package/dist/hooks/classic-stations.js +1 -0
  101. package/dist/hooks/command-spawn.d.ts +2 -2
  102. package/dist/hooks/hook-runner.js +14 -14
  103. package/dist/http/admission.js +14 -9
  104. package/dist/http/approval-sweeps.js +4 -3
  105. package/dist/http/caller-trust.d.ts +2 -1
  106. package/dist/http/caller-trust.js +1 -3
  107. package/dist/http/checkpoint-ctx.d.ts +48 -7
  108. package/dist/http/checkpoint-ctx.js +40 -0
  109. package/dist/http/dispatch.d.ts +4 -0
  110. package/dist/http/dispatch.js +18 -10
  111. package/dist/http/durable-run-leg.d.ts +5 -1
  112. package/dist/http/durable-run-leg.js +5 -3
  113. package/dist/http/health-self-report.d.ts +2 -2
  114. package/dist/http/memory-compliance-failure-reply.js +3 -0
  115. package/dist/http/principal-gate.d.ts +15 -10
  116. package/dist/http/principal-gate.js +48 -9
  117. package/dist/http/resume-legs.d.ts +7 -31
  118. package/dist/http/resume-legs.js +185 -126
  119. package/dist/http/route-ctx.d.ts +38 -53
  120. package/dist/http/route-ctx.js +2 -5
  121. package/dist/http/routes/a2a-serve.js +10 -4
  122. package/dist/http/routes/agents-roster.d.ts +1 -1
  123. package/dist/http/routes/agents-roster.js +5 -1
  124. package/dist/http/routes/approvals-assistant.js +24 -10
  125. package/dist/http/routes/capabilities.js +23 -11
  126. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  127. package/dist/http/routes/mcp-reconnect.js +7 -7
  128. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/rules.js +3 -3
  131. package/dist/http/routes/runs.js +13 -8
  132. package/dist/http/routes/session-sync.js +42 -6
  133. package/dist/http/routes/sessions.js +6 -3
  134. package/dist/http/routes/side-query.js +2 -3
  135. package/dist/http/routes/tasks.js +794 -780
  136. package/dist/http/server.d.ts +35 -25
  137. package/dist/http/stored-body-replay.d.ts +3 -3
  138. package/dist/http/stored-body-replay.js +6 -1
  139. package/dist/http/wire-types.d.ts +66 -33
  140. package/dist/identity-source.d.ts +65 -0
  141. package/dist/identity-source.js +45 -0
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +1 -0
  144. package/dist/leader/wire.d.ts +7 -0
  145. package/dist/leader/wire.js +5 -4
  146. package/dist/mcp-assertion-header.d.ts +51 -40
  147. package/dist/mcp-assertion-header.js +10 -11
  148. package/dist/mcp-authorization-face.d.ts +27 -0
  149. package/dist/mcp-authorization-face.js +15 -0
  150. package/dist/memory-operator-faces.d.ts +13 -4
  151. package/dist/memory-operator-faces.js +1 -17
  152. package/dist/memory-store-refusal.d.ts +3 -3
  153. package/dist/memory-sync-client.js +72 -57
  154. package/dist/memory-sync.d.ts +1 -1
  155. package/dist/model-entry-refusal.d.ts +2 -0
  156. package/dist/model-entry-refusal.js +11 -0
  157. package/dist/model-route-gap.d.ts +6 -22
  158. package/dist/model-route-gap.js +7 -5
  159. package/dist/model-select.d.ts +6 -17
  160. package/dist/model-select.js +0 -3
  161. package/dist/mods-declaration.d.ts +110 -0
  162. package/dist/mods-declaration.js +109 -0
  163. package/dist/namespaced-rule-name.d.ts +1 -1
  164. package/dist/observability/err-text.d.ts +5 -0
  165. package/dist/observability/err-text.js +9 -0
  166. package/dist/observability/fail-open.d.ts +17 -1
  167. package/dist/observability/fail-open.js +17 -1
  168. package/dist/observability/metrics.js +1 -1
  169. package/dist/observability/run-terminal.js +1 -0
  170. package/dist/observability/secret-env-scrub.d.ts +1 -1
  171. package/dist/observability/secret-env-scrub.js +1 -1
  172. package/dist/operator-ask.d.ts +2 -2
  173. package/dist/org-delivery-gate.js +1 -1
  174. package/dist/org-memory-admission.d.ts +2 -2
  175. package/dist/org-memory-admission.js +39 -2
  176. package/dist/parked-decide.d.ts +15 -2
  177. package/dist/parked-decide.js +17 -10
  178. package/dist/peer-directory.js +2 -0
  179. package/dist/peer-seat.d.ts +150 -0
  180. package/dist/peer-seat.js +239 -0
  181. package/dist/permission-rule-list.d.ts +2 -2
  182. package/dist/permission-rule-vocab.d.ts +7 -7
  183. package/dist/permission-rule-vocab.js +3 -3
  184. package/dist/plain-string-record.d.ts +38 -0
  185. package/dist/plain-string-record.js +38 -0
  186. package/dist/plugins/background-agent-store-sql.js +6 -3
  187. package/dist/plugins/caching-session-store.d.ts +5 -0
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
  190. package/dist/plugins/checkpoint-store-sql.js +14 -14
  191. package/dist/plugins/file-history-store-sql.js +10 -16
  192. package/dist/plugins/file-run-store.js +8 -2
  193. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  194. package/dist/plugins/k8s-exec-protocol.js +116 -28
  195. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  196. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  197. package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
  198. package/dist/plugins/k8s-pod-reaper.js +122 -0
  199. package/dist/plugins/local-checkpoint-store.d.ts +4 -17
  200. package/dist/plugins/local-checkpoint-store.js +3 -4
  201. package/dist/plugins/local-session-store.d.ts +66 -27
  202. package/dist/plugins/local-session-store.js +60 -28
  203. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  204. package/dist/plugins/mailbox-store-sql.js +103 -15
  205. package/dist/plugins/memory-run-store.js +2 -0
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +34 -12
  209. package/dist/plugins/one-time-migrations.js +51 -9
  210. package/dist/plugins/permission-rule-store-file.js +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  212. package/dist/plugins/permission-rule-store-sql.js +37 -30
  213. package/dist/plugins/pg-pool.js +4 -0
  214. package/dist/plugins/pg-session-storage.d.ts +10 -2
  215. package/dist/plugins/pg-session-storage.js +20 -7
  216. package/dist/plugins/remote-env-adb.d.ts +6 -1
  217. package/dist/plugins/remote-env-adb.js +2 -1
  218. package/dist/plugins/remote-env-device.d.ts +6 -1
  219. package/dist/plugins/remote-env-device.js +5 -1
  220. package/dist/plugins/remote-env-e2b.d.ts +5 -0
  221. package/dist/plugins/remote-env-e2b.js +2 -1
  222. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  223. package/dist/plugins/remote-env-file-error.js +7 -1
  224. package/dist/plugins/remote-env-host.d.ts +10 -2
  225. package/dist/plugins/remote-env-host.js +8 -2
  226. package/dist/plugins/remote-env-k8s.d.ts +140 -11
  227. package/dist/plugins/remote-env-k8s.js +277 -15
  228. package/dist/plugins/remote-env-local-docker.d.ts +5 -0
  229. package/dist/plugins/remote-env-local-docker.js +2 -1
  230. package/dist/plugins/remote-env-ssh.d.ts +6 -1
  231. package/dist/plugins/remote-env-ssh.js +2 -1
  232. package/dist/plugins/retention-store-sql.d.ts +14 -2
  233. package/dist/plugins/retention-store-sql.js +6 -0
  234. package/dist/plugins/run-store-sql.js +10 -4
  235. package/dist/plugins/session-fork.d.ts +10 -13
  236. package/dist/plugins/session-fork.js +5 -25
  237. package/dist/plugins/session-ownership.d.ts +24 -3
  238. package/dist/plugins/session-ownership.js +24 -5
  239. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  240. package/dist/plugins/session-workspace-cell.js +38 -0
  241. package/dist/plugins/sql-errors.d.ts +23 -2
  242. package/dist/plugins/sql-errors.js +15 -0
  243. package/dist/plugins/store-backend.js +7 -7
  244. package/dist/plugins/store-contracts.d.ts +10 -1
  245. package/dist/plugins/store-fault.d.ts +2 -2
  246. package/dist/plugins/store-fault.js +4 -2
  247. package/dist/plugins/tidb-pool.js +13 -0
  248. package/dist/plugins/tidb-session-store.d.ts +17 -2
  249. package/dist/plugins/tidb-session-store.js +18 -7
  250. package/dist/plugins/tool-result-store-sql.d.ts +13 -6
  251. package/dist/plugins/tool-result-store-sql.js +8 -7
  252. package/dist/plugins/worktree-isolation.d.ts +3 -2
  253. package/dist/plugins/worktree-isolation.js +1 -7
  254. package/dist/project-identity.d.ts +1 -14
  255. package/dist/project-identity.js +0 -4
  256. package/dist/request-key-closure.js +1 -1
  257. package/dist/request-value-closure.d.ts +31 -2
  258. package/dist/request-value-closure.js +7 -1
  259. package/dist/rule-entry-list.d.ts +3 -2
  260. package/dist/rule-entry-list.js +2 -2
  261. package/dist/rules-consent.js +12 -7
  262. package/dist/run-local.d.ts +2 -2
  263. package/dist/run-local.js +12 -6
  264. package/dist/runs.d.ts +7 -1
  265. package/dist/runs.js +8 -2
  266. package/dist/runtime-governance.d.ts +5 -5
  267. package/dist/sandbox-git-lease.d.ts +49 -0
  268. package/dist/sandbox-git-lease.js +60 -0
  269. package/dist/sandbox-git-plane.d.ts +84 -0
  270. package/dist/sandbox-git-plane.js +105 -0
  271. package/dist/security.d.ts +16 -4
  272. package/dist/security.js +8 -3
  273. package/dist/server-secret-env.d.ts +12 -3
  274. package/dist/server-secret-env.js +18 -2
  275. package/dist/session-error-wire.d.ts +14 -6
  276. package/dist/session-error-wire.js +2 -1
  277. package/dist/session-incarnation.d.ts +4 -5
  278. package/dist/session-incarnation.js +2 -2
  279. package/dist/session-policy-wire.d.ts +1 -1
  280. package/dist/session-policy-wire.js +2 -2
  281. package/dist/session-sync.d.ts +1 -1
  282. package/dist/session-workspace.d.ts +130 -0
  283. package/dist/session-workspace.js +83 -0
  284. package/dist/spec-fields.d.ts +44 -14
  285. package/dist/spec-fields.js +33 -12
  286. package/dist/standing-answer-grant.d.ts +2 -13
  287. package/dist/standing-answer-grant.js +0 -7
  288. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  289. package/dist/stored-request-prompt-profile-m30.js +25 -0
  290. package/dist/task-a2a.d.ts +44 -14
  291. package/dist/task-a2a.js +46 -20
  292. package/dist/task-mcp.d.ts +34 -21
  293. package/dist/task-mcp.js +46 -22
  294. package/dist/task-settings.d.ts +2 -2
  295. package/dist/tool-approval.d.ts +43 -9
  296. package/dist/tool-approval.js +57 -15
  297. package/dist/tool-rule-names.d.ts +5 -0
  298. package/dist/trace/core-keyset-guard.d.ts +34 -19
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +4 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +5 -2
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/ledger-sink.d.ts +4 -5
  306. package/dist/trace/ledger-sink.js +3 -7
  307. package/dist/trace/project.d.ts +62 -10
  308. package/dist/trace/project.js +49 -9
  309. package/dist/trace/redact.d.ts +18 -6
  310. package/dist/trace/redact.js +154 -60
  311. package/dist/trace/self-minted-wire.d.ts +500 -7
  312. package/dist/trace/self-minted-wire.js +182 -1
  313. package/dist/trace/wire-projection-faces.d.ts +7 -5
  314. package/dist/trace/wire-projection-faces.js +9 -4
  315. package/dist/user-authored-text.d.ts +2 -2
  316. package/dist/user-authored-text.js +16 -1
  317. package/dist/web-admin-client/apply-effective.js +0 -1
  318. package/dist/web-admin-client/center-request.d.ts +23 -4
  319. package/dist/web-admin-client/center-request.js +42 -8
  320. package/dist/web-admin-client/http-client.js +6 -6
  321. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  322. package/dist/web-admin-client/skills-mcp.js +31 -18
  323. package/dist/web-admin-client/types.d.ts +10 -5
  324. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  325. package/package.json +3 -3
  326. package/wire-changes/server@7.137.0.json +825 -0
  327. package/wire-changes/server@7.138.0.json +446 -0
@@ -1,4 +1,4 @@
1
- import { displayUrlOf, stripFormatCharacters } from "@sema-agent/core";
1
+ import { REDACTION_MARK, displayUrlOf, stripFormatCharacters } from "@sema-agent/core";
2
2
  import { CONTROL_AND_BIDI_CHARS, CREDENTIAL_PARAM_NAMES, isHierarchicalUrl } from "@sema-agent/settings-schema";
3
3
  import { recordFailOpen } from "../observability/fail-open.js";
4
4
  const normalizeForRedaction = stripFormatCharacters;
@@ -819,13 +819,57 @@ if (/[\]^-]/.test(SCHEME_DELIMITER_CHARS))
819
819
  const SCHEME_DELIMITER_CODES = new Set([...SCHEME_DELIMITER_CHARS].map((c) => c.charCodeAt(0)));
820
820
  const isSchemeDelimiterCode = (c) => SCHEME_DELIMITER_CODES.has(c);
821
821
  const SCHEME_SEPARATOR_CLASS = `[\\s${SCHEME_DELIMITER_CHARS.replace(/\\/g, "\\\\")}]`;
822
- const LEXICAL_KEYWORD_ARMS = new Set();
822
+ function expandKeywordForms(src) {
823
+ let forms = [""];
824
+ for (let i = 0; i < src.length;) {
825
+ let alts;
826
+ const pair = /^\[([A-Za-z])([A-Za-z])\]/.exec(src.slice(i));
827
+ if (pair !== null) {
828
+ if (pair[1].toLowerCase() !== pair[2].toLowerCase())
829
+ throw new Error(`redact: keyword source ${src} holds a class that is not a case pair`);
830
+ alts = [pair[1], pair[2]];
831
+ i += 4;
832
+ }
833
+ else if (/[A-Za-z0-9]/.test(src.charAt(i))) {
834
+ alts = [src.charAt(i)];
835
+ i += 1;
836
+ }
837
+ else {
838
+ throw new Error(`redact: keyword source ${src} holds an atom the head reading cannot enumerate (only letters, digits and [Xx] case pairs)`);
839
+ }
840
+ forms = forms.flatMap((f) => alts.map((a) => f + a));
841
+ }
842
+ const whole = new RegExp(`^(?:${src})$`);
843
+ for (const f of forms)
844
+ if (!whole.test(f))
845
+ throw new Error(`redact: keyword source ${src} does not match its own enumerated form ${f}`);
846
+ return forms;
847
+ }
848
+ const LEXICAL_KEYWORD_ARMS = new Map();
823
849
  const keywordArm = (keywordSrc, valueClass, min, tailSrc = "", separatorClass = "\\s") => {
824
850
  const re = new RegExp(`(?:${keywordSrc}${separatorClass}+${atLeast(valueClass, min)}${tailSrc}` +
825
851
  `|(?<!${WORD_SEGMENT_CLASS})${keywordSrc}(?:${twoStrongAhead(valueClass)}|${noConnectorAhead(valueClass)})${atLeast(valueClass, min)}${tailSrc})`, "g");
826
- LEXICAL_KEYWORD_ARMS.add(re);
852
+ const separator = new RegExp(`^${separatorClass}$`);
853
+ const value = new RegExp(`^${valueClass}$`);
854
+ LEXICAL_KEYWORD_ARMS.set(re, { forms: expandKeywordForms(keywordSrc), min, isSeparator: (u) => separator.test(u), isValue: (u) => value.test(u) });
827
855
  return re;
828
856
  };
857
+ function undecidedKeywordStart(text, t) {
858
+ const n = text.length;
859
+ let valueRun = 0;
860
+ while (valueRun < t.min && valueRun < n && t.isValue(text.charAt(n - 1 - valueRun)))
861
+ valueRun += 1;
862
+ if (valueRun >= t.min)
863
+ return -1;
864
+ let sepStart = n - valueRun;
865
+ while (sepStart > 0 && t.isSeparator(text.charAt(sepStart - 1)))
866
+ sepStart -= 1;
867
+ for (const f of t.forms) {
868
+ if (sepStart >= f.length && text.startsWith(f, sepStart - f.length))
869
+ return sepStart - f.length;
870
+ }
871
+ return -1;
872
+ }
829
873
  const CREDENTIAL_NAME_ANCHORS = {
830
874
  api_key: "structure-only", apikey: "structure-only", "api-key": "structure-only", key: "structure-only",
831
875
  token: "structure-only", access_token: "structure-only", refresh_token: "structure-only", id_token: "structure-only",
@@ -859,8 +903,9 @@ const PPK_CONTAINER_TOKEN = "«redacted:private-key»";
859
903
  const PEM_FRAGMENT_TOKEN = "«redacted:private-key:partial»";
860
904
  const HEADLESS_PPK_TOKEN = "«redacted:private-key:partial»";
861
905
  const ANCHORED_VALUE_TOKEN = "«redacted»";
906
+ const BEARER_VALUE_MIN = 20;
862
907
  const KEYWORD_SECRET_PATTERNS = [
863
- [keywordArm("[Bb]earer", "[A-Za-z0-9._~+/-]", 20, "=*", SCHEME_SEPARATOR_CLASS), "Bearer «redacted»"],
908
+ [keywordArm("[Bb]earer", "[A-Za-z0-9._~+/-]", BEARER_VALUE_MIN, "=*", SCHEME_SEPARATOR_CLASS), "Bearer «redacted»"],
864
909
  [keywordArm("Basic", "[A-Za-z0-9+/]", 16, "={0,2}", SCHEME_SEPARATOR_CLASS), "Basic «redacted»"],
865
910
  [keywordArm("[Tt]oken", "[A-Za-z0-9._~+/-]", 20), "token «redacted»"],
866
911
  ];
@@ -1166,7 +1211,7 @@ function collectSsh2FenceSpans(scan, text, span, isHead) {
1166
1211
  }
1167
1212
  const bodyFrom = fence + SSH2_FENCE_OPEN.length;
1168
1213
  if (isHead && unitCountWithin(scan, bodyFrom, text.length, SSH2_BODY_MAX)) {
1169
- span(fence, text.length);
1214
+ span(fence, text.length, true);
1170
1215
  return;
1171
1216
  }
1172
1217
  const close = nextClose(bodyFrom);
@@ -1224,7 +1269,7 @@ function collectPemFenceSpans(text, span, isHead) {
1224
1269
  earliestEndFence(bodyFrom);
1225
1270
  if (bodyFrom === PEM_LINE_OPEN || endAt < 0) {
1226
1271
  if (isHead)
1227
- span(fence, text.length);
1272
+ span(fence, text.length, true);
1228
1273
  return;
1229
1274
  }
1230
1275
  if (endAt - bodyFrom > PEM_FENCE_BODY_MAX) {
@@ -1382,20 +1427,23 @@ function collectHeadlessPpkSpans(scan, text, span, isHead) {
1382
1427
  continue;
1383
1428
  }
1384
1429
  let end = -1;
1430
+ let open = false;
1385
1431
  for (let from = p;;) {
1386
1432
  const r = bodyLineAt(from);
1387
1433
  if (r === LINE_NONE)
1388
1434
  break;
1389
1435
  end = r === LINE_OPEN ? n : r;
1390
- if (r === LINE_OPEN)
1436
+ if (r === LINE_OPEN) {
1437
+ open = true;
1391
1438
  break;
1439
+ }
1392
1440
  from = r;
1393
1441
  }
1394
1442
  if (end < 0) {
1395
1443
  search = p;
1396
1444
  continue;
1397
1445
  }
1398
- span(at, end);
1446
+ span(at, end, open);
1399
1447
  search = end;
1400
1448
  }
1401
1449
  }
@@ -1855,7 +1903,7 @@ function collectUrlCredentialSpans(scan, text, json, span, isHead) {
1855
1903
  hi = scan.footHi;
1856
1904
  urlSegmentRuns += 1;
1857
1905
  if (at >= 0 && at !== (known ? ph[pc + 1] : -2))
1858
- span(start, at);
1906
+ span(start, at, isHead && at >= text.length);
1859
1907
  }
1860
1908
  if (hw.n + URL_SEG_STRIDE <= hw.a.length || growUrlSegments(hw)) {
1861
1909
  const w = hw.a;
@@ -1951,6 +1999,7 @@ function jsonSecretFieldValueQuoteAt(text, p) {
1951
1999
  i += 1;
1952
2000
  return text.charCodeAt(i) === CH_QUOTE ? i : -1;
1953
2001
  }
2002
+ const STRING_OPEN = -2;
1954
2003
  function jsonStringEndAt(text, q, isHead) {
1955
2004
  const n = text.length;
1956
2005
  for (let i = q + 1; i < n;) {
@@ -1962,25 +2011,36 @@ function jsonStringEndAt(text, q, isHead) {
1962
2011
  i += 2;
1963
2012
  continue;
1964
2013
  }
1965
- return isHead && i + 1 >= n ? n : -1;
2014
+ return isHead && i + 1 >= n ? STRING_OPEN : -1;
1966
2015
  }
1967
2016
  i += 1;
1968
2017
  }
1969
- return isHead ? n : -1;
2018
+ return isHead ? STRING_OPEN : -1;
1970
2019
  }
1971
2020
  function collectJsonSecretFieldSpans(text, span, isHead) {
1972
2021
  for (let p = text.indexOf(JSON_FIELD_ANCHOR); p >= 0;) {
1973
2022
  const q = jsonSecretFieldValueQuoteAt(text, p);
1974
- const end = q < 0 ? -1 : jsonStringEndAt(text, q, isHead);
1975
- if (end < 0) {
2023
+ const found = q < 0 ? -1 : jsonStringEndAt(text, q, isHead);
2024
+ if (found === -1) {
1976
2025
  p = text.indexOf(JSON_FIELD_ANCHOR, p + 1);
1977
2026
  continue;
1978
2027
  }
1979
- span(q, end);
2028
+ const open = found === STRING_OPEN;
2029
+ const end = open ? text.length : found;
2030
+ span(q, end, open);
1980
2031
  p = text.indexOf(JSON_FIELD_ANCHOR, scanResumeAfterHit(p, end, JSON_FIELD_ANCHOR.length));
1981
2032
  }
1982
2033
  }
1983
2034
  const STRONG_AUTH_SCHEMES = new Set(["basic", "bearer"]);
2035
+ function isEngineMarkedCandidate(text, start, end, repl) {
2036
+ const open = repl.indexOf("«");
2037
+ const close = repl.lastIndexOf("»");
2038
+ if (open <= 0 || close < open || close === repl.length - 1)
2039
+ return false;
2040
+ const lead = repl.slice(0, open);
2041
+ const trail = repl.slice(close + 1);
2042
+ return end - start === lead.length + REDACTION_MARK.length + trail.length && text.startsWith(lead, start) && text.startsWith(REDACTION_MARK, start + lead.length) && text.startsWith(trail, end - trail.length);
2043
+ }
1984
2044
  const STRONG_AUTH_SCHEME_MAX = Math.max(...[...STRONG_AUTH_SCHEMES].map((w) => w.length));
1985
2045
  const ABSENT_OR_BOOLEAN_WORDS = new Set(["null", "nil", "none", "undefined", "true", "false", "yes", "no"]);
1986
2046
  const ABSENT_OR_BOOLEAN_MAX = Math.max(...[...ABSENT_OR_BOOLEAN_WORDS].map((w) => w.length));
@@ -2144,7 +2204,7 @@ function quotedValueEnd(text, cs, quote, json, isHead) {
2144
2204
  i += unitLenOf(escaped);
2145
2205
  }
2146
2206
  }
2147
- return isHead ? n : -1;
2207
+ return isHead ? STRING_OPEN : -1;
2148
2208
  }
2149
2209
  function bareValueEnd(text, s, json, listSep) {
2150
2210
  const n = text.length;
@@ -2203,6 +2263,8 @@ function literalValueAt(text, s, json, declaredIfBare, listSep, isHead) {
2203
2263
  if (!isAsciiAlnumCode(unitChOf(readAnchorUnit(text, vs, json))))
2204
2264
  return undefined;
2205
2265
  const close = quotedValueEnd(text, vs, first, json, isHead);
2266
+ if (close === STRING_OPEN)
2267
+ return { start: vs, end: n, quoted: true, open: true };
2206
2268
  if (close >= 0)
2207
2269
  return { start: vs, end: close, quoted: true };
2208
2270
  }
@@ -2235,11 +2297,18 @@ function schemeValueAt(text, s, json) {
2235
2297
  if (isQuoteUnit(unitChOf(opening)) || unitChOf(opening) === JSON_STRING_END)
2236
2298
  i += unitLenOf(opening);
2237
2299
  const w = i;
2238
- while (i < n && i - w <= STRONG_AUTH_SCHEME_MAX && (isIdentStartCode(text.charCodeAt(i))))
2239
- i += 1;
2240
- anchoredScanUnits += i - w;
2241
- if (i - w > STRONG_AUTH_SCHEME_MAX || !STRONG_AUTH_SCHEMES.has(text.slice(w, i).toLowerCase()))
2242
- return undefined;
2300
+ const engineMarked = text.startsWith(REDACTION_MARK, i);
2301
+ if (engineMarked) {
2302
+ i += REDACTION_MARK.length;
2303
+ anchoredScanUnits += REDACTION_MARK.length;
2304
+ }
2305
+ else {
2306
+ while (i < n && i - w <= STRONG_AUTH_SCHEME_MAX && (isIdentStartCode(text.charCodeAt(i))))
2307
+ i += 1;
2308
+ anchoredScanUnits += i - w;
2309
+ if (i - w > STRONG_AUTH_SCHEME_MAX || !STRONG_AUTH_SCHEMES.has(text.slice(w, i).toLowerCase()))
2310
+ return undefined;
2311
+ }
2243
2312
  let separated = false;
2244
2313
  while (i < n) {
2245
2314
  const unit = readAnchorUnit(text, i, json);
@@ -2252,6 +2321,17 @@ function schemeValueAt(text, s, json) {
2252
2321
  if (!separated)
2253
2322
  return undefined;
2254
2323
  const vs = i;
2324
+ if (engineMarked) {
2325
+ let k = i;
2326
+ while (k < n && isToken68Code(text.charCodeAt(k)))
2327
+ k += 1;
2328
+ while (k < n && text.charCodeAt(k) === CH_EQ)
2329
+ k += 1;
2330
+ if (k - vs >= BEARER_VALUE_MIN) {
2331
+ anchoredScanUnits += k - vs;
2332
+ return { start: vs, end: k, quoted: false };
2333
+ }
2334
+ }
2255
2335
  if (i >= n || !isAsciiAlnumCode(text.charCodeAt(i)))
2256
2336
  return undefined;
2257
2337
  while (i < n && isToken68Code(text.charCodeAt(i)))
@@ -2323,7 +2403,7 @@ function collectAnchoredValueSpans(text, json, span, isHead) {
2323
2403
  }
2324
2404
  if (v === undefined)
2325
2405
  continue;
2326
- span(v.start, v.end);
2406
+ span(v.start, v.end, v.open === true);
2327
2407
  resume = v.quoted ? v.start : v.end;
2328
2408
  }
2329
2409
  }
@@ -2400,12 +2480,15 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
2400
2480
  let pos = at + HEAD.length + 1;
2401
2481
  let end = text.length;
2402
2482
  let ateToEnd = !isHead;
2483
+ let open = false;
2403
2484
  for (;;) {
2404
2485
  const mac = find(MAC, pos);
2405
2486
  const hash = find(HASH, pos);
2406
2487
  const term = Math.min(mac, hash);
2407
- if (term === Number.POSITIVE_INFINITY)
2488
+ if (term === Number.POSITIVE_INFINITY) {
2489
+ open = isHead;
2408
2490
  break;
2491
+ }
2409
2492
  const hexStart = term + (term === mac ? MAC.length : HASH.length);
2410
2493
  const hexEnd = hexRunEnd(hexStart);
2411
2494
  if (hexEnd - hexStart < 32) {
@@ -2435,18 +2518,19 @@ function collectPpkContainerSpans(scan, text, eat, span, isHead) {
2435
2518
  const undecided = isHead && limit === Number.POSITIVE_INFINITY;
2436
2519
  ateToEnd = straggler < limit || !gapBlank;
2437
2520
  end = ateToEnd || undecided ? text.length : hexEnd;
2521
+ open = undecided;
2438
2522
  break;
2439
2523
  }
2440
2524
  if (ateToEnd && eat !== undefined && eat.from < 0) {
2441
2525
  eat.from = at;
2442
2526
  eat.len = text.length;
2443
2527
  }
2444
- span(at, end);
2528
+ span(at, end, open);
2445
2529
  at = end >= text.length ? Number.POSITIVE_INFINITY : nextVersionedHead(end);
2446
2530
  }
2447
2531
  const last = isHead ? text.lastIndexOf(HEAD) : -1;
2448
2532
  if (last >= 0 && !inOpaqueUnit(scan, last) && isOpenHead(last))
2449
- span(last, text.length);
2533
+ span(last, text.length, true);
2450
2534
  }
2451
2535
  const armPool = (() => {
2452
2536
  const spanRepl = (token) => {
@@ -2468,6 +2552,7 @@ const armPool = (() => {
2468
2552
  throw new Error(`redact: boundary arm /${re.source}/ has a zero-length structural head — the bounded head screen would admit every candidate position`);
2469
2553
  }
2470
2554
  const arm = { g: re, y, back, headSrc, headFirst, repl, rank, order };
2555
+ const keywordTail = LEXICAL_KEYWORD_ARMS.get(re);
2471
2556
  const boundary = y === undefined || headSrc === undefined || headFirst === undefined ? undefined : { ...arm, y, headSrc, headFirst };
2472
2557
  return {
2473
2558
  token,
@@ -2475,9 +2560,17 @@ const armPool = (() => {
2475
2560
  order,
2476
2561
  phase: 1,
2477
2562
  lexical: LEXICAL_KEYWORD_ARMS.has(re),
2478
- collect: boundary === undefined
2479
- ? (text, _json, _eat, out) => collectRegexSpans(arm, text, out)
2480
- : (text, _json, _eat, out) => collectValueArmSpans(boundary, text, out),
2563
+ collect: (text, _json, _eat, out, isHead) => {
2564
+ if (boundary === undefined)
2565
+ collectRegexSpans(arm, text, out);
2566
+ else
2567
+ collectValueArmSpans(boundary, text, out);
2568
+ if (isHead && keywordTail !== undefined) {
2569
+ const at = undecidedKeywordStart(text, keywordTail);
2570
+ if (at >= 0)
2571
+ out.push({ start: at, end: text.length, repl, rank, order, undecided: true });
2572
+ }
2573
+ },
2481
2574
  retry: boundary === undefined ? undefined : (text, at, out) => collectStickySpans(boundary, text, at, out),
2482
2575
  headSrc: boundary === undefined ? undefined : headSrc,
2483
2576
  headFirst: boundary === undefined ? undefined : headFirst,
@@ -2491,7 +2584,7 @@ const armPool = (() => {
2491
2584
  order,
2492
2585
  phase: 1,
2493
2586
  lexical,
2494
- collect: (text, json, eat, out, isHead) => arm(text, json, eat, (start, end) => out.push({ start, end, repl, rank, order }), isHead),
2587
+ collect: (text, json, eat, out, isHead) => arm(text, json, eat, (start, end, undecided) => out.push(undecided === true ? { start, end, repl, rank, order, undecided } : { start, end, repl, rank, order }), isHead),
2495
2588
  retry: undefined,
2496
2589
  headSrc: undefined,
2497
2590
  headFirst: undefined,
@@ -2506,7 +2599,7 @@ const armPool = (() => {
2506
2599
  order,
2507
2600
  phase: 2,
2508
2601
  lexical: false,
2509
- collect: (scan, text, json, eat, out, isHead) => arm(scan, text, json, eat, (start, end) => out.push({ start, end, repl, rank, order }), isHead),
2602
+ collect: (scan, text, json, eat, out, isHead) => arm(scan, text, json, eat, (start, end, undecided) => out.push(undecided === true ? { start, end, repl, rank, order, undecided } : { start, end, repl, rank, order }), isHead),
2510
2603
  retry: undefined,
2511
2604
  headSrc: undefined,
2512
2605
  headFirst: undefined,
@@ -2560,8 +2653,9 @@ const armPool = (() => {
2560
2653
  const headFirstUnit = unionMembers(retryMembers.map((m) => m.headFirst)) ?? new Uint32Array(0x10000 >>> 5).fill(0xffffffff);
2561
2654
  poolArmCount = members.length;
2562
2655
  poolBoundaryArmCount = retryMembers.length;
2563
- return (text, wantCount, json, eat, scope, isHead) => {
2656
+ return (text, wantCount, json, eat, scope, reach, engineMarked) => {
2564
2657
  readings += 1;
2658
+ const isHead = reach !== undefined;
2565
2659
  const lane = LANES[scope];
2566
2660
  const spans = [];
2567
2661
  let tried;
@@ -2629,11 +2723,12 @@ const armPool = (() => {
2629
2723
  }
2630
2724
  }
2631
2725
  poolSpanCount += spans.length;
2632
- const kept = resolveSpanOverlaps(spans);
2726
+ const survives = (sp) => !engineMarked(sp.start, sp.end, sp.repl) && (sp.undecided !== true || reach === undefined || reach(sp.start));
2727
+ const kept = resolveSpanOverlaps(spans.filter(survives));
2633
2728
  if (!wantCount || kept.length === 0)
2634
2729
  return { hits: NO_HITS, kept };
2635
2730
  const tokenOf = (sp) => members[sp.order].token;
2636
- const strong = spans.filter((sp) => armOfToken(tokenOf(sp)) === "full").sort((a, b) => a.start - b.start);
2731
+ const strong = spans.filter((sp) => armOfToken(tokenOf(sp)) === "full" && survives(sp)).sort((a, b) => a.start - b.start);
2637
2732
  const byArmedToken = new Map();
2638
2733
  const stamped = [];
2639
2734
  let si = 0;
@@ -2660,8 +2755,8 @@ let onRedaction;
2660
2755
  export function setRedactionObserver(fn) {
2661
2756
  onRedaction = fn;
2662
2757
  }
2663
- function applyRules(text, wantCount, json, eat, scope, isHead) {
2664
- return armPool(text, wantCount, json, eat, scope, isHead);
2758
+ function applyRules(text, wantCount, json, eat, scope, reach, engineMarked) {
2759
+ return armPool(text, wantCount, json, eat, scope, reach, engineMarked);
2665
2760
  }
2666
2761
  function reportHits(hits) {
2667
2762
  if (onRedaction === undefined)
@@ -2674,6 +2769,7 @@ function reportHits(hits) {
2674
2769
  }
2675
2770
  }
2676
2771
  }
2772
+ export const WHOLE_EXTENT = { kind: "whole" };
2677
2773
  function invisibleClassesOf(layout) {
2678
2774
  switch (layout) {
2679
2775
  case "multi-line":
@@ -2786,15 +2882,18 @@ function runRedaction(text, observe, json, wantHits, scope, layout, extent) {
2786
2882
  let readsSoFar = 0;
2787
2883
  let unioned = false;
2788
2884
  const read = (layers, view) => {
2789
- const r = applyRules(view, wantCount, json, eat, scope, extent === "head");
2885
+ const toOriginal = createViewToOriginal(layers);
2886
+ const reach = extent.kind === "head" ? (viewStart) => toOriginal.start(viewStart) < extent.emitEnd : undefined;
2887
+ const engineMarked = (viewStart, viewEnd, repl) => isEngineMarkedCandidate(text, toOriginal.start(viewStart), toOriginal.start(viewEnd - 1) + 1, repl);
2888
+ const r = applyRules(view, wantCount, json, eat, scope, reach, engineMarked);
2790
2889
  forgetEscapedSeparatorTails();
2791
2890
  readsSoFar += 1;
2792
2891
  if (readsSoFar === 1) {
2793
- spans = spansInOriginal(layers, r.kept);
2892
+ spans = toOriginal.spans(r.kept);
2794
2893
  hits = r.hits;
2795
2894
  return;
2796
2895
  }
2797
- const extra = spansInOriginal(layers, r.kept);
2896
+ const extra = toOriginal.spans(r.kept);
2798
2897
  if (extra.length === 0)
2799
2898
  return;
2800
2899
  spans = resolveSpanOverlaps([...spans, ...extra]);
@@ -2836,37 +2935,32 @@ function hitsOfSpans(spans) {
2836
2935
  }
2837
2936
  return [...by.values()].map(({ token, arm, count }) => ({ label: labelOfToken(token), count, arm }));
2838
2937
  }
2839
- function spansInOriginal(layers, kept) {
2840
- let out = kept;
2841
- for (const layer of layers) {
2842
- if (out.length === 0)
2843
- return out;
2844
- let at;
2938
+ function createViewToOriginal(layers) {
2939
+ let ats;
2940
+ const layerMaps = () => (ats ??= layers.flatMap((layer) => {
2845
2941
  if ("fold" in layer) {
2846
2942
  const fold = layer.fold;
2847
- if (fold.at === undefined)
2848
- continue;
2849
- at = (v) => viewIndexInInput(fold, v);
2850
- }
2851
- else {
2852
- if (layer.view === layer.input)
2853
- continue;
2854
- const map = mapNormalizedToOriginal(layer.input, layer.view);
2855
- at = (v) => map[v];
2943
+ return fold.at === undefined ? [] : [(v) => viewIndexInInput(fold, v)];
2856
2944
  }
2857
- out = out.map((s) => ({ ...s, start: at(s.start), end: at(s.end - 1) + 1 }));
2858
- }
2859
- return out;
2945
+ if (layer.view === layer.input)
2946
+ return [];
2947
+ const map = mapNormalizedToOriginal(layer.input, layer.view);
2948
+ return [(v) => map[v]];
2949
+ }));
2950
+ return {
2951
+ start: (viewIndex) => layerMaps().reduce((p, at) => at(p), viewIndex),
2952
+ spans: (kept) => (kept.length === 0 ? kept : layerMaps().reduce((out, at) => out.map((s) => ({ ...s, start: at(s.start), end: at(s.end - 1) + 1 })), kept)),
2953
+ };
2860
2954
  }
2861
2955
  export function redactSecrets(text, opts) {
2862
- return runRedaction(text, opts?.observe ?? true, opts?.json === true, false, "free-text", "multi-line", "whole").text;
2956
+ return runRedaction(text, opts?.observe ?? true, opts?.json === true, false, "free-text", "multi-line", WHOLE_EXTENT).text;
2863
2957
  }
2864
2958
  export function redactSecretsWithArms(text, opts) {
2865
- const r = runRedaction(text, opts?.observe ?? true, opts?.json === true, true, "free-text", "multi-line", "whole");
2959
+ const r = runRedaction(text, opts?.observe ?? true, opts?.json === true, true, "free-text", "multi-line", WHOLE_EXTENT);
2866
2960
  return { text: r.text, arms: new Set(r.hits.map((h) => h.arm)) };
2867
2961
  }
2868
2962
  export function redactionSpansForTest(text, opts) {
2869
- const r = runRedaction(text, false, opts?.json === true, false, "free-text", "multi-line", "whole");
2963
+ const r = runRedaction(text, false, opts?.json === true, false, "free-text", "multi-line", WHOLE_EXTENT);
2870
2964
  return { text: r.text, spans: r.spans.map((sp) => ({ start: sp.start, end: sp.end })) };
2871
2965
  }
2872
2966
  export function proposeRedactionSpans(text, scope, layout, extent) {
@@ -2972,7 +3066,7 @@ function unitCarriesCredential(unit) {
2972
3066
  for (const v of armValueClassViews())
2973
3067
  views.add(boundedUnitView(spelling, v.inClass, v.filler));
2974
3068
  views.delete("");
2975
- const hit = [...views].some((view) => runRedaction(view, true, false, false, "bounded-unit", "multi-line", "whole").text !== view);
3069
+ const hit = [...views].some((view) => runRedaction(view, true, false, false, "bounded-unit", "multi-line", WHOLE_EXTENT).text !== view);
2976
3070
  return { hit, unreadable: decoded.residue };
2977
3071
  }
2978
3072
  function displaySafePathname(pathname) {
@@ -3002,7 +3096,7 @@ function shapeLawCredentialInQueryOrFragment(canonical) {
3002
3096
  const boundary = canonical.indexOf("?");
3003
3097
  if (boundary < 0)
3004
3098
  return false;
3005
- if (runRedaction(canonical, false, false, false, "free-text", "multi-line", "whole").spans.some((sp) => sp.end > boundary))
3099
+ if (runRedaction(canonical, false, false, false, "free-text", "multi-line", WHOLE_EXTENT).spans.some((sp) => sp.end > boundary))
3006
3100
  return true;
3007
3101
  for (const unit of canonical.slice(boundary + 1).split("&").flatMap((sg) => {
3008
3102
  const eq = sg.indexOf("=");