@sema-agent/server 7.145.0 → 7.146.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 (275) hide show
  1. package/MIGRATION.md +492 -0
  2. package/USAGE.md +218 -47
  3. package/deploy/facts/CHANGES.json +25 -0
  4. package/deploy/facts/README.md +57 -0
  5. package/deploy/facts/lanes.json +54 -0
  6. package/deploy/facts/lanes.schema.json +57 -0
  7. package/deploy/facts/sandbox-rbac.json +113 -0
  8. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  9. package/deploy/facts/sealed-key.json +9 -0
  10. package/deploy/facts/sealed-key.schema.json +52 -0
  11. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  12. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  13. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  14. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  15. package/deploy/sema-up/chart/values.yaml +7 -0
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  17. package/dist/adoption/import-limits.d.ts +6 -0
  18. package/dist/adoption/import-limits.js +7 -0
  19. package/dist/adoption/import.d.ts +62 -0
  20. package/dist/adoption/import.js +107 -0
  21. package/dist/adoption/wire.d.ts +52 -0
  22. package/dist/adoption/wire.js +9 -0
  23. package/dist/approval-ask-machine.d.ts +2 -2
  24. package/dist/approval-card.d.ts +3 -12
  25. package/dist/approval-card.js +0 -4
  26. package/dist/approval-gate-currency.d.ts +1 -1
  27. package/dist/approval-gate-currency.js +1 -1
  28. package/dist/approval-reconciler.d.ts +1 -1
  29. package/dist/boot/deployment-mods.d.ts +11 -1
  30. package/dist/boot/deployment-mods.js +15 -2
  31. package/dist/boot/device-lane.js +2 -0
  32. package/dist/boot/engine-lease.d.ts +193 -21
  33. package/dist/boot/engine-lease.js +146 -20
  34. package/dist/boot/execution-env.d.ts +4 -0
  35. package/dist/boot/execution-env.js +12 -0
  36. package/dist/boot/exit-boundary.d.ts +50 -0
  37. package/dist/boot/exit-boundary.js +32 -0
  38. package/dist/boot/exit-last.d.ts +20 -4
  39. package/dist/boot/exit-last.js +21 -4
  40. package/dist/boot/governance-seams.js +1 -0
  41. package/dist/boot/memory-consolidation.d.ts +29 -17
  42. package/dist/boot/memory-consolidation.js +26 -15
  43. package/dist/boot/reapers.d.ts +12 -4
  44. package/dist/boot/reapers.js +39 -15
  45. package/dist/boot/resolve-spec.d.ts +2 -0
  46. package/dist/boot/resolve-spec.js +38 -15
  47. package/dist/boot/runner-deps.js +1 -1
  48. package/dist/boot/session-faces.js +3 -1
  49. package/dist/boot/shutdown.js +27 -9
  50. package/dist/boot/stage-01-config.js +1 -1
  51. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  52. package/dist/boot/stage-03-store-backend.js +2 -2
  53. package/dist/boot/stage-04-stores.d.ts +1 -0
  54. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  55. package/dist/boot/stage-05-execution-env.js +3 -3
  56. package/dist/boot/stage-06-runners.d.ts +3 -0
  57. package/dist/boot/stage-06-runners.js +11 -10
  58. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  59. package/dist/boot/stage-07-capability-layer.js +7 -2
  60. package/dist/boot/stage-08-reapers.d.ts +3 -0
  61. package/dist/boot/stage-08-reapers.js +3 -3
  62. package/dist/boot/stage-09-leader.d.ts +3 -0
  63. package/dist/boot/stage-10-http-server.d.ts +3 -0
  64. package/dist/boot/stage-10-http-server.js +3 -2
  65. package/dist/boot/stores.d.ts +1 -0
  66. package/dist/boot/stores.js +35 -19
  67. package/dist/boot/workflow-orchestration.d.ts +1 -1
  68. package/dist/boot/workflow-orchestration.js +2 -1
  69. package/dist/capabilities/composite-members.d.ts +3 -1
  70. package/dist/capabilities/composite-members.js +3 -1
  71. package/dist/capabilities/scenarios.d.ts +2 -2
  72. package/dist/capability-facts.d.ts +18 -1
  73. package/dist/capability-facts.js +25 -7
  74. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  75. package/dist/config-catalog.js +13 -4
  76. package/dist/config-provider.d.ts +2 -2
  77. package/dist/config-types.d.ts +43 -4
  78. package/dist/config.d.ts +6 -1
  79. package/dist/config.js +67 -11
  80. package/dist/deleted-session-ids.d.ts +19 -0
  81. package/dist/deleted-session-ids.js +26 -0
  82. package/dist/deploy-facts.d.ts +155 -0
  83. package/dist/deploy-facts.js +94 -0
  84. package/dist/device-ws-hub.d.ts +48 -3
  85. package/dist/device-ws-hub.js +48 -2
  86. package/dist/error-code-family.d.ts +35 -0
  87. package/dist/error-code-family.js +26 -0
  88. package/dist/fleet/drain-entry.d.ts +39 -3
  89. package/dist/fleet/drain-entry.js +6 -0
  90. package/dist/fleet/fleet-bus.d.ts +2 -1
  91. package/dist/hooks/branch-transcript.d.ts +1 -1
  92. package/dist/hooks/branch-transcript.js +1 -0
  93. package/dist/hooks/classic-stations.d.ts +25 -8
  94. package/dist/hooks/classic-stations.js +29 -3
  95. package/dist/hooks/hook-runner.d.ts +33 -16
  96. package/dist/hooks/hook-runner.js +166 -73
  97. package/dist/hooks/hook-source.d.ts +14 -2
  98. package/dist/hooks/hook-source.js +8 -0
  99. package/dist/http/active-run-conflict.d.ts +1 -1
  100. package/dist/http/active-run-conflict.js +1 -1
  101. package/dist/http/admission.js +11 -1
  102. package/dist/http/checkpoint-ctx.d.ts +59 -71
  103. package/dist/http/checkpoint-ctx.js +34 -40
  104. package/dist/http/dispatch.js +18 -2
  105. package/dist/http/durable-run-leg.d.ts +5 -0
  106. package/dist/http/durable-run-leg.js +1 -0
  107. package/dist/http/execution-context.d.ts +4 -0
  108. package/dist/http/execution-context.js +9 -0
  109. package/dist/http/health-self-report.d.ts +6 -2
  110. package/dist/http/health-self-report.js +3 -2
  111. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  112. package/dist/http/memory-compliance-failure-reply.js +2 -15
  113. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  114. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  115. package/dist/http/principal-gate.d.ts +35 -12
  116. package/dist/http/principal-gate.js +16 -12
  117. package/dist/http/request-guards.d.ts +1 -1
  118. package/dist/http/request-guards.js +5 -5
  119. package/dist/http/resume-legs.d.ts +22 -0
  120. package/dist/http/resume-legs.js +26 -17
  121. package/dist/http/route-ctx.d.ts +11 -10
  122. package/dist/http/route-table.js +2 -0
  123. package/dist/http/routes/adoption.d.ts +11 -0
  124. package/dist/http/routes/adoption.js +80 -6
  125. package/dist/http/routes/agents-roster.js +1 -0
  126. package/dist/http/routes/approvals-assistant.js +2 -1
  127. package/dist/http/routes/background.js +1 -0
  128. package/dist/http/routes/capabilities.js +4 -1
  129. package/dist/http/routes/diagnostics.d.ts +9 -14
  130. package/dist/http/routes/diagnostics.js +10 -20
  131. package/dist/http/routes/engine.d.ts +31 -0
  132. package/dist/http/routes/engine.js +81 -0
  133. package/dist/http/routes/memory-bundle.js +3 -0
  134. package/dist/http/routes/memory-consolidation.js +3 -5
  135. package/dist/http/routes/memory-origin.d.ts +1 -1
  136. package/dist/http/routes/memory-origin.js +2 -4
  137. package/dist/http/routes/memory-policy.js +5 -1
  138. package/dist/http/routes/observability.js +3 -6
  139. package/dist/http/routes/runs.js +7 -3
  140. package/dist/http/routes/session-sync.js +12 -25
  141. package/dist/http/routes/sessions-list.d.ts +1 -1
  142. package/dist/http/routes/sessions.js +4 -0
  143. package/dist/http/routes/tasks.js +23 -5
  144. package/dist/http/routes/trace-usage.js +1 -1
  145. package/dist/http/run-concurrency-cap.d.ts +86 -0
  146. package/dist/http/run-concurrency-cap.js +54 -0
  147. package/dist/http/server.d.ts +15 -12
  148. package/dist/http/server.js +18 -3
  149. package/dist/http/stored-body-replay.d.ts +9 -6
  150. package/dist/http/stored-body-replay.js +19 -5
  151. package/dist/http/wire-types.d.ts +8 -3
  152. package/dist/json-body-limit.d.ts +8 -0
  153. package/dist/json-body-limit.js +2 -0
  154. package/dist/leader/diffout.d.ts +1 -1
  155. package/dist/local-data-root.d.ts +2 -2
  156. package/dist/memory-operator-faces.d.ts +9 -4
  157. package/dist/memory-scope-stores.d.ts +9 -7
  158. package/dist/memory-scope-stores.js +3 -14
  159. package/dist/memory-scope.d.ts +36 -0
  160. package/dist/memory-scope.js +32 -1
  161. package/dist/net-address.d.ts +53 -0
  162. package/dist/net-address.js +111 -0
  163. package/dist/observability/fail-open.d.ts +14 -10
  164. package/dist/observability/fail-open.js +14 -10
  165. package/dist/orchestration/workflow-notify-journal.js +2 -3
  166. package/dist/org-delivery-gate.js +1 -1
  167. package/dist/peer-directory.d.ts +6 -12
  168. package/dist/peer-directory.js +5 -1
  169. package/dist/plugins/caching-session-store.d.ts +3 -1
  170. package/dist/plugins/caching-session-store.js +3 -0
  171. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  172. package/dist/plugins/checkpoint-store-face.js +152 -0
  173. package/dist/plugins/file-run-store.d.ts +0 -6
  174. package/dist/plugins/file-run-store.js +1 -12
  175. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  176. package/dist/plugins/fork-routing-session-store.js +2 -2
  177. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  178. package/dist/plugins/local-checkpoint-store.d.ts +2 -2
  179. package/dist/plugins/local-checkpoint-store.js +2 -1
  180. package/dist/plugins/local-session-store.d.ts +28 -5
  181. package/dist/plugins/local-session-store.js +32 -8
  182. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  183. package/dist/plugins/memory-engine-pg.js +96 -214
  184. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  185. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  186. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  187. package/dist/plugins/memory-engine-tidb.js +97 -227
  188. package/dist/plugins/memory-key-guards.d.ts +1 -1
  189. package/dist/plugins/memory-origin-law.d.ts +3 -3
  190. package/dist/plugins/one-time-migrations.d.ts +32 -56
  191. package/dist/plugins/one-time-migrations.js +25 -117
  192. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  193. package/dist/plugins/permission-rule-store-file.js +8 -1
  194. package/dist/plugins/pg-pool.js +1 -1
  195. package/dist/plugins/pg-session-storage.d.ts +17 -4
  196. package/dist/plugins/pg-session-storage.js +8 -4
  197. package/dist/plugins/run-store-sql.js +2 -2
  198. package/dist/plugins/schema-ensure-legs.js +2 -2
  199. package/dist/plugins/session-fork.d.ts +31 -9
  200. package/dist/plugins/session-fork.js +3 -2
  201. package/dist/plugins/session-placement.d.ts +4 -2
  202. package/dist/plugins/sql-json-column.d.ts +5 -1
  203. package/dist/plugins/store-backend.d.ts +11 -8
  204. package/dist/plugins/store-backend.js +8 -7
  205. package/dist/plugins/store-contracts.d.ts +1 -11
  206. package/dist/plugins/store-contracts.js +0 -9
  207. package/dist/plugins/store-sweep.d.ts +63 -0
  208. package/dist/plugins/store-sweep.js +48 -0
  209. package/dist/plugins/tidb-pool.js +1 -1
  210. package/dist/plugins/tidb-session-store.d.ts +16 -3
  211. package/dist/plugins/tidb-session-store.js +8 -4
  212. package/dist/prompt-screen.d.ts +6 -9
  213. package/dist/prompt-screen.js +2 -5
  214. package/dist/rules-consent.d.ts +20 -27
  215. package/dist/rules-consent.js +82 -6
  216. package/dist/run-cancel-context.d.ts +4 -1
  217. package/dist/run-cancel-context.js +2 -1
  218. package/dist/runs.js +1 -1
  219. package/dist/sandbox-egress-policy.js +6 -11
  220. package/dist/sandbox-rbac-rules.d.ts +88 -0
  221. package/dist/sandbox-rbac-rules.js +80 -0
  222. package/dist/sealed-key-layout.d.ts +17 -0
  223. package/dist/sealed-key-layout.js +4 -0
  224. package/dist/sealed-key.js +5 -5
  225. package/dist/security.d.ts +38 -6
  226. package/dist/security.js +9 -2
  227. package/dist/session-notify-door.d.ts +5 -3
  228. package/dist/session-resident-background.d.ts +57 -0
  229. package/dist/session-resident-background.js +20 -0
  230. package/dist/session-sync-kernel.d.ts +53 -14
  231. package/dist/session-sync-kernel.js +70 -1
  232. package/dist/session-sync.d.ts +5 -3
  233. package/dist/session-workspace.d.ts +1 -0
  234. package/dist/session-workspace.js +1 -0
  235. package/dist/sighup-idle.d.ts +9 -7
  236. package/dist/sighup-idle.js +4 -5
  237. package/dist/spec-fields.d.ts +16 -0
  238. package/dist/spec-fields.js +7 -0
  239. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  240. package/dist/stored-request-env-credentials-m38.js +8 -0
  241. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  242. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +13 -427
  243. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +33 -194
  244. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  245. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  246. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  247. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  248. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  249. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  250. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  251. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  252. package/dist/task-settings.d.ts +59 -4
  253. package/dist/task-settings.js +50 -4
  254. package/dist/tool-approval.d.ts +2 -2
  255. package/dist/trace/core-keyset-guard.d.ts +8 -7
  256. package/dist/trace/engine-notice-wire.d.ts +1 -1
  257. package/dist/trace/engine-notice-wire.js +2 -0
  258. package/dist/trace/exit-seat.d.ts +6 -0
  259. package/dist/trace/exit-seat.js +1 -0
  260. package/dist/trace/project.js +9 -0
  261. package/dist/trace/redact.d.ts +13 -2
  262. package/dist/trace/redact.js +305 -24
  263. package/dist/trace/self-minted-wire.d.ts +326 -8
  264. package/dist/trace/self-minted-wire.js +125 -7
  265. package/dist/trace/wire-projection-faces.d.ts +1 -1
  266. package/dist/trace/wire-projection-faces.js +1 -1
  267. package/dist/usage-analytics.d.ts +4 -0
  268. package/package.json +12 -4
  269. package/scripts/drain-check-local.mjs +8 -29
  270. package/scripts/drain-check.mysql.sql +3 -24
  271. package/scripts/drain-check.pg.sql +3 -24
  272. package/skills/update-config.md +1 -1
  273. package/wire-changes/server@7.146.0.json +3221 -0
  274. package/dist/approval-batch-census.d.ts +0 -27
  275. package/dist/approval-batch-census.js +0 -27
@@ -1062,7 +1062,7 @@ function undecidedKeywordStart(text, t) {
1062
1062
  }
1063
1063
  const CREDENTIAL_NAME_ANCHORS = {
1064
1064
  api_key: "declarative", apikey: "declarative", "api-key": "declarative", key: "structure-only",
1065
- token: "structure-only", access_token: "declarative", refresh_token: "declarative", id_token: "declarative",
1065
+ token: "assignment", access_token: "declarative", refresh_token: "declarative", id_token: "declarative",
1066
1066
  auth: "structure-only", authorization: "auth-scheme", "proxy-authorization": "auth-scheme",
1067
1067
  password: "declarative", passwd: "any-form", pwd: "any-form",
1068
1068
  secret: "declarative", client_secret: "declarative", private_key: "declarative",
@@ -1105,6 +1105,33 @@ function credentialNameAnchor(name) {
1105
1105
  return CREDENTIAL_ANCHOR_OF.get(asciiLower(name));
1106
1106
  }
1107
1107
  const CREDENTIAL_ANCHOR_OF = new Map(Object.entries(CREDENTIAL_NAME_ANCHORS));
1108
+ const BARE_WORD_READINGS = {
1109
+ null: "absent-or-boolean", nil: "absent-or-boolean", none: "absent-or-boolean", undefined: "absent-or-boolean",
1110
+ true: "absent-or-boolean", false: "absent-or-boolean", yes: "absent-or-boolean", no: "absent-or-boolean",
1111
+ str: "type-name", string: "type-name", bytes: "type-name", int: "type-name", integer: "type-name", float: "type-name", number: "type-name",
1112
+ bool: "type-name", boolean: "type-name", any: "type-name", object: "type-name", array: "type-name", secretstr: "type-name",
1113
+ };
1114
+ for (const w of Object.keys(BARE_WORD_READINGS)) {
1115
+ if (!/^[a-z]+$/.test(w))
1116
+ throw new Error(`redact: bare value word ${JSON.stringify(w)} must be lowercase ASCII letters (values are ASCII-lowercased before the lookup)`);
1117
+ }
1118
+ const BARE_WORD_OF = new Map(Object.entries(BARE_WORD_READINGS));
1119
+ const BARE_WORD_MAX = Math.max(...Object.keys(BARE_WORD_READINGS).map((w) => w.length));
1120
+ function bareWordIsValue(reading, bare) {
1121
+ switch (reading) {
1122
+ case "absent-or-boolean":
1123
+ return false;
1124
+ case "type-name":
1125
+ return bare === "declared";
1126
+ default: {
1127
+ const unhandled = reading;
1128
+ throw new Error(`redact: unhandled bare value word reading ${String(unhandled)}`);
1129
+ }
1130
+ }
1131
+ }
1132
+ export function lineKeyTypeNamesForTest() {
1133
+ return Object.entries(BARE_WORD_READINGS).filter(([, r]) => r === "type-name").map(([w]) => w);
1134
+ }
1108
1135
  const STRUCTURAL_SECRET_PATTERNS = [
1109
1136
  [/-----BEGIN(?:[^-](?:[^-](?:[^-]|-(?!-))*)?)?PRIVATE KEY(?: BLOCK)?-----[\s\S]{0,8192}?-----END(?:[^-](?:[^-](?:[^-]|-(?!-))*)?)?PRIVATE KEY(?: BLOCK)?-----/g, "«redacted:private-key»"],
1110
1137
  [/---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----[\s\S]{0,8192}?---- END SSH2 ENCRYPTED PRIVATE KEY ----/g, "«redacted:private-key»"],
@@ -3126,8 +3153,6 @@ function isEngineMarkedCandidate(text, start, end, repl) {
3126
3153
  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);
3127
3154
  }
3128
3155
  const STRONG_AUTH_SCHEME_MAX = Math.max(...[...STRONG_AUTH_SCHEMES].map((w) => w.length));
3129
- const ABSENT_OR_BOOLEAN_WORDS = new Set(["null", "nil", "none", "undefined", "true", "false", "yes", "no"]);
3130
- const ABSENT_OR_BOOLEAN_MAX = Math.max(...[...ABSENT_OR_BOOLEAN_WORDS].map((w) => w.length));
3131
3156
  const CH_GRAVE = 96, CH_APOS = 39, CH_DOT = 46, CH_COMMA = 44, CH_SEMI = 59, CH_DOLLAR = 36;
3132
3157
  const CH_LPAREN = 40, CH_RPAREN = 41, CH_RBRACKET = 93, CH_LBRACE = 123, CH_RBRACE = 125, CH_LT = 60, CH_GT = 62;
3133
3158
  const CH_QMARK = 63, CH_AMP = 38, CH_HASH = 35;
@@ -3154,6 +3179,9 @@ const unitChOf = (unit) => (unit >> 3) - 1;
3154
3179
  const unitLenOf = (unit) => unit & 7;
3155
3180
  function readAnchorUnit(text, i, json) {
3156
3181
  anchoredScanUnits += 1;
3182
+ return readTextUnit(text, i, json);
3183
+ }
3184
+ function readTextUnit(text, i, json) {
3157
3185
  const c = text.charCodeAt(i);
3158
3186
  if (!json)
3159
3187
  return packUnit(c, 1);
@@ -3269,7 +3297,7 @@ function anchorHeadAt(scan, text, op, json) {
3269
3297
  const left = k >= 0 ? text.charCodeAt(k) : 0;
3270
3298
  listSep = left === CH_QMARK || left === CH_AMP || left === CH_HASH ? CH_AMP : left === CH_SEMI ? CH_SEMI : left === CH_COMMA || left === CH_LPAREN || left === CH_LBRACKET || left === CH_LBRACE ? CH_COMMA : 0;
3271
3299
  }
3272
- return { strength, quotedName: quote !== 0, spacedLeft, listSep };
3300
+ return { strength, quotedName: quote !== 0, spacedLeft, listSep, runStart };
3273
3301
  }
3274
3302
  function quotedValueEnd(text, cs, quote, json, isHead) {
3275
3303
  const n = text.length;
@@ -3382,7 +3410,7 @@ function bareValueEnd(text, s, json, listSep, memo) {
3382
3410
  }
3383
3411
  return e;
3384
3412
  }
3385
- function literalValueAt(text, s, json, declaredIfBare, listSep, isHead, memo) {
3413
+ function literalValueAt(text, s, json, bare, listSep, isHead, memo) {
3386
3414
  const n = text.length;
3387
3415
  if (s >= n)
3388
3416
  return undefined;
@@ -3403,8 +3431,21 @@ function literalValueAt(text, s, json, declaredIfBare, listSep, isHead, memo) {
3403
3431
  }
3404
3432
  else if (!isAsciiAlnumCode(first))
3405
3433
  return undefined;
3406
- if (!declaredIfBare)
3407
- return undefined;
3434
+ let lineKey;
3435
+ switch (bare) {
3436
+ case "never":
3437
+ return undefined;
3438
+ case "declared":
3439
+ lineKey = false;
3440
+ break;
3441
+ case "line-key":
3442
+ lineKey = true;
3443
+ break;
3444
+ default: {
3445
+ const unhandled = bare;
3446
+ throw new Error(`redact: unhandled bare literal form ${String(unhandled)}`);
3447
+ }
3448
+ }
3408
3449
  if (isProgramIdentStartCode(text.charCodeAt(vs))) {
3409
3450
  let k = vs;
3410
3451
  while (k < n && isProgramIdentCode(text.charCodeAt(k)))
@@ -3417,10 +3458,92 @@ function literalValueAt(text, s, json, declaredIfBare, listSep, isHead, memo) {
3417
3458
  const e = bareValueEnd(text, vs, json, listSep, memo);
3418
3459
  if (e <= vs)
3419
3460
  return undefined;
3420
- if (e - vs <= ABSENT_OR_BOOLEAN_MAX && ABSENT_OR_BOOLEAN_WORDS.has(text.slice(vs, e).toLowerCase()))
3421
- return undefined;
3461
+ if (e - vs <= BARE_WORD_MAX) {
3462
+ const reading = BARE_WORD_OF.get(asciiLower(text.slice(vs, e)));
3463
+ if (reading !== undefined && !bareWordIsValue(reading, lineKey ? "line-key" : "declared"))
3464
+ return undefined;
3465
+ }
3466
+ if (lineKey) {
3467
+ const rest = lineKeyRestAt(text, e, json, isHead);
3468
+ switch (rest) {
3469
+ case "ends":
3470
+ break;
3471
+ case "goes-on":
3472
+ return undefined;
3473
+ case "undecided":
3474
+ return { start: vs, end: text.length, quoted: false, open: true };
3475
+ default: {
3476
+ const unhandled = rest;
3477
+ throw new Error(`redact: unhandled line-key rest ${String(unhandled)}`);
3478
+ }
3479
+ }
3480
+ }
3422
3481
  return { start: vs, end: e, quoted: false };
3423
3482
  }
3483
+ function lineKeyRestAt(text, e, json, isHead) {
3484
+ const n = text.length;
3485
+ let i = e;
3486
+ while (i < n) {
3487
+ const unit = readAnchorUnit(text, i, json);
3488
+ const ch = unitChOf(unit);
3489
+ if (isInlineSpaceUnit(ch) || (ch >= 0 && INVISIBLE_UNIT_CLASS[ch] === 1)) {
3490
+ i += unitLenOf(unit);
3491
+ continue;
3492
+ }
3493
+ return ch === JSON_STRING_END || isLineTerminator(ch) || ch === CH_HASH ? "ends" : "goes-on";
3494
+ }
3495
+ return isHead ? "undecided" : "ends";
3496
+ }
3497
+ function unitEndingAt(text, end, json) {
3498
+ const c = text.charCodeAt(end - 1);
3499
+ anchoredScanUnits += 1;
3500
+ if (!json)
3501
+ return packUnit(c, 1);
3502
+ if (end >= 6 && text.charCodeAt(end - 6) === CH_BACKSLASH && text.charCodeAt(end - 5) === CH_u && !escapedAt(text, end - 6)) {
3503
+ const h0 = hexDigitValue(text.charCodeAt(end - 4));
3504
+ const h1 = hexDigitValue(text.charCodeAt(end - 3));
3505
+ const h2 = hexDigitValue(text.charCodeAt(end - 2));
3506
+ const h3 = hexDigitValue(text.charCodeAt(end - 1));
3507
+ if (h0 >= 0 && h1 >= 0 && h2 >= 0 && h3 >= 0)
3508
+ return packUnit((h0 << 12) | (h1 << 8) | (h2 << 4) | h3, 6);
3509
+ }
3510
+ if (end >= 2 && text.charCodeAt(end - 2) === CH_BACKSLASH && escapedAt(text, end - 1)) {
3511
+ const two = readTextUnit(text, end - 2, true);
3512
+ if (unitLenOf(two) === 2)
3513
+ return two;
3514
+ }
3515
+ return c === CH_QUOTE ? packUnit(JSON_STRING_END, 1) : packUnit(c, 1);
3516
+ }
3517
+ function lineHeadBefore(text, at, json) {
3518
+ let i = at;
3519
+ let blank = false;
3520
+ for (;;) {
3521
+ if (i <= 0)
3522
+ return true;
3523
+ const unit = unitEndingAt(text, i, json);
3524
+ const ch = unitChOf(unit);
3525
+ if (isInlineSpaceUnit(ch)) {
3526
+ i -= unitLenOf(unit);
3527
+ blank = true;
3528
+ continue;
3529
+ }
3530
+ if (ch >= 0 && INVISIBLE_UNIT_CLASS[ch] === 1) {
3531
+ i -= unitLenOf(unit);
3532
+ continue;
3533
+ }
3534
+ if (ch === CH_MINUS && blank) {
3535
+ i -= unitLenOf(unit);
3536
+ blank = false;
3537
+ continue;
3538
+ }
3539
+ return isLineTerminator(ch) || ch === JSON_STRING_END;
3540
+ }
3541
+ }
3542
+ function declarativeBareAt(text, head, spacedRight, json) {
3543
+ if (head.quotedName || (!head.spacedLeft && !spacedRight))
3544
+ return "declared";
3545
+ return spacedRight && lineHeadBefore(text, head.runStart, json) ? "line-key" : "never";
3546
+ }
3424
3547
  function schemeValueAt(text, s, json) {
3425
3548
  const n = text.length;
3426
3549
  let i = s;
@@ -3504,11 +3627,16 @@ function anchoredValueAt(scan, text, op, json, span, isHead, memo) {
3504
3627
  case "auth-scheme":
3505
3628
  v = schemeValueAt(text, s, json);
3506
3629
  break;
3630
+ case "assignment":
3631
+ if (text.charCodeAt(op) !== CH_EQ || head.quotedName || head.spacedLeft || spacedRight)
3632
+ return;
3633
+ v = literalValueAt(text, s, json, "declared", head.listSep, isHead, memo);
3634
+ break;
3507
3635
  case "declarative":
3508
- v = literalValueAt(text, s, json, head.quotedName || (!head.spacedLeft && !spacedRight), head.listSep, isHead, memo);
3636
+ v = literalValueAt(text, s, json, declarativeBareAt(text, head, spacedRight, json), head.listSep, isHead, memo);
3509
3637
  break;
3510
3638
  case "any-form":
3511
- v = literalValueAt(text, s, json, true, head.listSep, isHead, memo);
3639
+ v = literalValueAt(text, s, json, "declared", head.listSep, isHead, memo);
3512
3640
  break;
3513
3641
  default: {
3514
3642
  const unhandled = head.strength;
@@ -3592,6 +3720,142 @@ function collectAnchoredValueSpans(scan, text, json, span, isHead) {
3592
3720
  scan.footLo = armLo;
3593
3721
  scan.footHi = armHi;
3594
3722
  }
3723
+ const isRegexWordCode = (c) => isAsciiAlnumCode(c) || c === CH_UNDERSCORE;
3724
+ const isDiagnosticNameCode = (c) => isRegexWordCode(c) || c === CH_MINUS;
3725
+ const isDiagnosticValueUnit = (ch) => ch !== JSON_STRING_END && !isRegexSpace(ch) && ch !== CH_QUOTE && ch !== CH_APOS && ch !== CH_COMMA && ch !== CH_RBRACE;
3726
+ const isAsciiLetterCode = (ch) => (ch >= 0x41 && ch <= 0x5a) || (ch >= 0x61 && ch <= 0x7a);
3727
+ const isDiagnosticSchemeValueUnit = (ch) => isAsciiAlnumCode(ch) || ch === CH_DOT || ch === CH_UNDERSCORE || ch === CH_TILDE || ch === CH_PLUS || ch === CH_SLASH || ch === CH_EQ || ch === CH_MINUS;
3728
+ function diagnosticNameSlot(tier) {
3729
+ switch (tier) {
3730
+ case "assignment":
3731
+ case "declarative":
3732
+ case "any-form":
3733
+ case "auth-scheme":
3734
+ return true;
3735
+ case "structure-only":
3736
+ return false;
3737
+ default: {
3738
+ const unhandled = tier;
3739
+ throw new Error(`redact: unhandled free-text anchor strength ${String(unhandled)}`);
3740
+ }
3741
+ }
3742
+ }
3743
+ const DIAGNOSTIC_SCHEME_RE = new RegExp([...STRONG_AUTH_SCHEMES].sort((a, b) => b.length - a.length).join("|"), "gi");
3744
+ let diagnosticScanUnits = 0;
3745
+ export function diagnosticScanUnitsForTest() {
3746
+ return diagnosticScanUnits;
3747
+ }
3748
+ export function resetDiagnosticScanUnitsForTest() {
3749
+ diagnosticScanUnits = 0;
3750
+ }
3751
+ function collectDiagnosticValueSpans(text, json, span, isHead, deletedAt) {
3752
+ const n = text.length;
3753
+ const readRun = (from, isValue) => {
3754
+ let i = from;
3755
+ while (i < n) {
3756
+ const unit = readTextUnit(text, i, json);
3757
+ diagnosticScanUnits += 1;
3758
+ if (!isValue(unitChOf(unit)))
3759
+ break;
3760
+ i += unitLenOf(unit);
3761
+ }
3762
+ return i;
3763
+ };
3764
+ const skipBlank = (from) => readRun(from, isRegexSpace);
3765
+ let valueEnd = 0;
3766
+ let nextEq = text.indexOf("=");
3767
+ let nextColon = text.indexOf(":");
3768
+ while (nextEq >= 0 || nextColon >= 0) {
3769
+ let op;
3770
+ if (nextColon < 0 || (nextEq >= 0 && nextEq < nextColon)) {
3771
+ op = nextEq;
3772
+ nextEq = text.indexOf("=", op + 1);
3773
+ }
3774
+ else {
3775
+ op = nextColon;
3776
+ nextColon = text.indexOf(":", op + 1);
3777
+ }
3778
+ if (op + 1 < valueEnd)
3779
+ continue;
3780
+ let e = op;
3781
+ while (e > 0 && isRegexSpace(text.charCodeAt(e - 1)))
3782
+ e -= 1;
3783
+ diagnosticScanUnits += op - e;
3784
+ if (e === 0 || !isRegexWordCode(text.charCodeAt(e - 1)))
3785
+ continue;
3786
+ const floor = Math.max(0, e - CREDENTIAL_NAME_MAX - 1);
3787
+ let runStart = e;
3788
+ while (runStart > floor && isDiagnosticNameCode(text.charCodeAt(runStart - 1)))
3789
+ runStart -= 1;
3790
+ diagnosticScanUnits += e - runStart;
3791
+ const runOpen = runStart === floor && floor > 0 && isDiagnosticNameCode(text.charCodeAt(floor - 1));
3792
+ let nameStart = -1;
3793
+ let nameTier;
3794
+ for (let q = runStart; q < e && nameStart < 0; q++) {
3795
+ if (e - q > CREDENTIAL_NAME_MAX || !isRegexWordCode(text.charCodeAt(q)))
3796
+ continue;
3797
+ const bounded = (q === runStart && !runOpen) || text.charCodeAt(q - 1) === CH_MINUS || deletedAt(q) !== "none";
3798
+ const tier = bounded ? credentialNameAnchor(text.slice(q, e)) : undefined;
3799
+ if (tier !== undefined && diagnosticNameSlot(tier)) {
3800
+ nameStart = q;
3801
+ nameTier = tier;
3802
+ }
3803
+ }
3804
+ if (nameStart < 0)
3805
+ continue;
3806
+ let s = skipBlank(op + 1);
3807
+ if (s < n) {
3808
+ const unit = readTextUnit(text, s, json);
3809
+ if (unitChOf(unit) === CH_QUOTE)
3810
+ s += unitLenOf(unit);
3811
+ }
3812
+ if (s >= n) {
3813
+ if (isHead)
3814
+ span(nameStart, n, op, NOT_CLOSED, true);
3815
+ continue;
3816
+ }
3817
+ let end = readRun(s, isDiagnosticValueUnit);
3818
+ if (end > s && nameTier === "auth-scheme" && readRun(s, isAsciiLetterCode) === end) {
3819
+ const k = skipBlank(end);
3820
+ if (k > end && k >= n && isHead) {
3821
+ span(nameStart, n, op, NOT_CLOSED, true);
3822
+ continue;
3823
+ }
3824
+ if (k > end && k < n) {
3825
+ const credEnd = readRun(k, isDiagnosticSchemeValueUnit);
3826
+ if (credEnd > k)
3827
+ end = credEnd;
3828
+ }
3829
+ }
3830
+ if (end > s) {
3831
+ span(s, end, op, NOT_CLOSED);
3832
+ valueEnd = end;
3833
+ }
3834
+ }
3835
+ let schemeEnd = 0;
3836
+ DIAGNOSTIC_SCHEME_RE.lastIndex = 0;
3837
+ for (let m = DIAGNOSTIC_SCHEME_RE.exec(text); m !== null; m = DIAGNOSTIC_SCHEME_RE.exec(text)) {
3838
+ const at = m.index;
3839
+ const q = at + m[0].length;
3840
+ if (q < schemeEnd)
3841
+ continue;
3842
+ if (at > 0 && isRegexWordCode(text.charCodeAt(at - 1)) && deletedAt(at) === "none")
3843
+ continue;
3844
+ const k = skipBlank(q);
3845
+ if (k === q && deletedAt(q) !== "blank")
3846
+ continue;
3847
+ if (k >= n) {
3848
+ if (isHead)
3849
+ span(at, n, at, NOT_CLOSED, true);
3850
+ continue;
3851
+ }
3852
+ const end = readRun(k, isDiagnosticSchemeValueUnit);
3853
+ if (end > k) {
3854
+ span(k, end, at, NOT_CLOSED);
3855
+ schemeEnd = end;
3856
+ }
3857
+ }
3858
+ }
3595
3859
  export function structuralScannerForTest(arm) {
3596
3860
  const collect = (scan) => (text) => {
3597
3861
  const out = [];
@@ -3750,6 +4014,7 @@ const armPool = (() => {
3750
4014
  order,
3751
4015
  phase: 1,
3752
4016
  lexical: LEXICAL_KEYWORD_ARMS.has(re),
4017
+ diagnosticOnly: false,
3753
4018
  collect: (text, _json, _eat, out, isHead) => {
3754
4019
  if (boundary === undefined)
3755
4020
  collectRegexSpans(arm, text, out);
@@ -3769,16 +4034,16 @@ const armPool = (() => {
3769
4034
  prior: { kind: "bounded", gap: keywordTail === undefined ? NO_GAP : (c) => keywordTail.isSeparator(String.fromCharCode(c)) },
3770
4035
  };
3771
4036
  };
3772
- const scannerMember = (token, order, arm, reach, family, prior) => {
4037
+ const scannerMember = (token, order, arm, reach, family, prior, rank = ARM_RANK.structural, lexical = false, diagnosticOnly = false) => {
3773
4038
  const repl = spanRepl(token);
3774
- const rank = ARM_RANK.structural;
3775
4039
  return {
3776
4040
  token,
3777
4041
  rank,
3778
4042
  order,
3779
4043
  phase: 1,
3780
- lexical: false,
3781
- collect: (text, json, eat, out, isHead) => arm(text, json, eat, (start, end, anchor, closeAt, undecided, r = repl) => out.push(undecided === true ? { start, end, repl: r, rank, order, undecided, anchor, closeAt } : { start, end, repl: r, rank, order, anchor, closeAt }), isHead),
4044
+ lexical,
4045
+ diagnosticOnly,
4046
+ collect: (text, json, eat, out, isHead, deletedAt) => arm(text, json, eat, (start, end, anchor, closeAt, undecided, r = repl) => out.push(undecided === true ? { start, end, repl: r, rank, order, undecided, anchor, closeAt } : { start, end, repl: r, rank, order, anchor, closeAt }), isHead, deletedAt),
3782
4047
  retry: undefined,
3783
4048
  headSrc: undefined,
3784
4049
  headFirst: undefined,
@@ -3795,6 +4060,7 @@ const armPool = (() => {
3795
4060
  order,
3796
4061
  phase: 2,
3797
4062
  lexical,
4063
+ diagnosticOnly: false,
3798
4064
  collect: (scan, text, json, eat, out, isHead) => arm(scan, text, json, eat, (start, end, anchor, closeAt, undecided, r = repl) => out.push(undecided === true ? { start, end, repl: r, rank, order, undecided, anchor, closeAt } : { start, end, repl: r, rank, order, anchor, closeAt }), isHead),
3799
4065
  retry: undefined,
3800
4066
  headSrc: undefined,
@@ -3822,13 +4088,14 @@ const armPool = (() => {
3822
4088
  members.push(forensicMember(PPK_CONTAINER_TOKEN, members.length, (scan, text, _json, eat, span, isHead) => collectPpkContainerSpans(scan, text, eat, span, isHead), PPK_FILE_HEAD.length, "putty-ppk", { kind: "anchored", anchors: [PPK_FILE_HEAD] }));
3823
4089
  members.push(forensicMember(PEM_FRAGMENT_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectPemFragmentSpans(scan, text, json, span, isHead), PEM_FENCE_OPEN.length, "pem-armor", { kind: "anchored", anchors: [PEM_FENCE_OPEN, PEM_END_OPEN] }));
3824
4090
  members.push(forensicMember(HEADLESS_PPK_TOKEN, members.length, (scan, text, _json, _eat, span, isHead) => collectHeadlessPpkSpans(scan, text, span, isHead), PPK_LINES_FIELD.length, "putty-ppk", { kind: "anchored", anchors: [PPK_LINES_FIELD] }));
3825
- members.push(forensicMember(ANCHORED_VALUE_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectAnchoredValueSpans(scan, text, json, span, isHead), Math.max(BEARER_VALUE_MIN, ABSENT_OR_BOOLEAN_MAX + 1, STRONG_AUTH_SCHEME_MAX + 1), "anchor", { kind: "bounded", gap: (c) => isInlineSpaceUnit(c) || isSchemeDelimiterCode(c) }, ARM_RANK.keyword, true));
4091
+ members.push(forensicMember(ANCHORED_VALUE_TOKEN, members.length, (scan, text, json, _eat, span, isHead) => collectAnchoredValueSpans(scan, text, json, span, isHead), Math.max(BEARER_VALUE_MIN, BARE_WORD_MAX + 1, STRONG_AUTH_SCHEME_MAX + 1), "anchor", { kind: "bounded", gap: (c) => isInlineSpaceUnit(c) || isSchemeDelimiterCode(c) }, ARM_RANK.keyword, true));
3826
4092
  for (const row of KEYWORD_SECRET_PATTERNS)
3827
4093
  members.push(regexMember(row, ARM_RANK.keyword, members.length));
3828
4094
  for (const row of SHAPE_SECRET_PATTERNS)
3829
4095
  members.push(regexMember(row, ARM_RANK.shape, members.length));
3830
4096
  for (const row of FRAGMENT_SECRET_PATTERNS)
3831
4097
  members.push(regexMember(row, ARM_RANK.fragment, members.length));
4098
+ members.push(scannerMember(ANCHORED_VALUE_TOKEN, members.length, (text, json, _eat, span, isHead, deletedAt) => collectDiagnosticValueSpans(text, json, span, isHead, deletedAt), Math.max(CREDENTIAL_NAME_MAX, STRONG_AUTH_SCHEME_MAX) + 2, "prose", { kind: "bounded", gap: isRegexSpace }, ARM_RANK.keyword, true, true));
3832
4099
  for (const [re] of KEYWORD_SECRET_PATTERNS) {
3833
4100
  if (!LEXICAL_KEYWORD_ARMS.has(re))
3834
4101
  throw new Error(`redact: keyword arm /${re.source}/ is not registered as lexical — build it with keywordArm() so the bounded-unit scope can exclude it`);
@@ -3840,8 +4107,9 @@ const armPool = (() => {
3840
4107
  const laneOf = (scope) => {
3841
4108
  const inScope = (m) => {
3842
4109
  switch (scope) {
3843
- case "free-text": return true;
3844
- case "bounded-unit": return !m.lexical;
4110
+ case "free-text": return !m.diagnosticOnly;
4111
+ case "bounded-unit": return !m.lexical && !m.diagnosticOnly;
4112
+ case "diagnostic": return true;
3845
4113
  }
3846
4114
  };
3847
4115
  return {
@@ -3853,13 +4121,14 @@ const armPool = (() => {
3853
4121
  const LANES = {
3854
4122
  "free-text": laneOf("free-text"),
3855
4123
  "bounded-unit": laneOf("bounded-unit"),
4124
+ diagnostic: laneOf("diagnostic"),
3856
4125
  };
3857
4126
  const headScreen = new RegExp(`(?:${retryMembers.map((m) => m.headSrc).join("|")})`, "y");
3858
4127
  const headFirstUnit = unionMembers(retryMembers.map((m) => m.headFirst)) ?? new Uint32Array(0x10000 >>> 5).fill(0xffffffff);
3859
4128
  poolArmCount = members.length;
3860
4129
  poolBoundaryArmCount = retryMembers.length;
3861
4130
  const reaches = members.map((m) => ({ token: m.token, order: m.order, reach: m.reach }));
3862
- const run = (text, wantCount, json, eat, scope, reach, engineMarked) => {
4131
+ const run = (text, wantCount, json, eat, scope, reach, engineMarked, deletedAt) => {
3863
4132
  readings += 1;
3864
4133
  const isHead = reach !== undefined;
3865
4134
  const lane = LANES[scope];
@@ -3914,7 +4183,7 @@ const armPool = (() => {
3914
4183
  }
3915
4184
  };
3916
4185
  for (const m of lane.phase1)
3917
- m.collect(text, json, eat, spans, isHead);
4186
+ m.collect(text, json, eat, spans, isHead, deletedAt);
3918
4187
  closeCoveragePositions(0);
3919
4188
  if (lane.phase2.length > 0) {
3920
4189
  const scan = buildForensicScan(tokenUnits(text), buildEvidenceRows(text), lane.phase2.length);
@@ -3999,8 +4268,8 @@ let onRedaction;
3999
4268
  export function setRedactionObserver(fn) {
4000
4269
  onRedaction = fn;
4001
4270
  }
4002
- function applyRules(text, wantCount, json, eat, scope, reach, engineMarked) {
4003
- return armPool(text, wantCount, json, eat, scope, reach, engineMarked);
4271
+ function applyRules(text, wantCount, json, eat, scope, reach, engineMarked, deletedAt) {
4272
+ return armPool(text, wantCount, json, eat, scope, reach, engineMarked, deletedAt);
4004
4273
  }
4005
4274
  function reportHits(hits) {
4006
4275
  if (onRedaction === undefined)
@@ -4072,7 +4341,19 @@ function runRedaction(text, observe, json, wantHits, scope, layout, extent, obse
4072
4341
  const toOriginal = createViewToOriginal(layers);
4073
4342
  const reach = extent.kind === "head" ? (viewStart) => toOriginal.start(viewStart) < extent.emitEnd : undefined;
4074
4343
  const engineMarked = (viewStart, viewEnd, repl) => isEngineMarkedCandidate(text, toOriginal.start(viewStart), toOriginal.start(viewEnd - 1) + 1, repl);
4075
- const r = applyRules(view, wantCount, json, eat, scope, reach, engineMarked);
4344
+ const deletedAt = (viewIndex) => {
4345
+ if (viewIndex <= 0 || viewIndex > view.length)
4346
+ return "none";
4347
+ const lo = toOriginal.start(viewIndex - 1) + 1;
4348
+ const hi = viewIndex === view.length ? text.length : toOriginal.start(viewIndex);
4349
+ if (hi <= lo)
4350
+ return "none";
4351
+ for (let k = lo; k < hi; k++)
4352
+ if (isRegexSpace(text.charCodeAt(k)))
4353
+ return "blank";
4354
+ return "invisible";
4355
+ };
4356
+ const r = applyRules(view, wantCount, json, eat, scope, reach, engineMarked, deletedAt);
4076
4357
  forgetEscapedSeparatorTails();
4077
4358
  readsSoFar += 1;
4078
4359
  if (readsSoFar === 1) {
@@ -4154,7 +4435,7 @@ export function redactSecretsWithArms(text, opts) {
4154
4435
  return { text: r.text, arms: new Set(r.hits.map((h) => h.arm)) };
4155
4436
  }
4156
4437
  export function redactionSpansForTest(text, opts) {
4157
- const r = runRedaction(text, false, opts?.json === true, false, "free-text", "multi-line", WHOLE_EXTENT);
4438
+ const r = runRedaction(text, false, opts?.json === true, false, opts?.scope ?? "free-text", "multi-line", WHOLE_EXTENT);
4158
4439
  return { text: r.text, spans: r.spans.map((sp) => ({ start: sp.start, end: sp.end })) };
4159
4440
  }
4160
4441
  export function proposeRedactionSpans(text, scope, layout, extent) {