@tekmidian/pai 1.0.6 → 1.0.7

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 (130) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/auto-route-CAlZ5p-h.mjs +11 -0
  3. package/dist/{auto-route-YaEGVrFl.mjs → auto-route-PDOAYszN.mjs} +2 -2
  4. package/dist/{budget-DEiebT2A.mjs → budget-BXmsSBLI.mjs} +10 -10
  5. package/dist/{caller-identity-C6Nc96iM.mjs → caller-identity-DPDSrZE2.mjs} +2 -2
  6. package/dist/{capacity-B2PgKAg4.mjs → capacity-CThSydrd.mjs} +25 -13
  7. package/dist/{chain-CtK49-Ma.mjs → chain-BvdKqRiZ.mjs} +5 -5
  8. package/dist/cli/index.mjs +182 -111
  9. package/dist/{cockpit-actions-D1OPP6Es.mjs → cockpit-actions-BgdKB9G3.mjs} +19 -19
  10. package/dist/{cockpit-actions-C73mJAJ8.mjs → cockpit-actions-DNl0rKfW.mjs} +14 -14
  11. package/dist/cockpit-memory-CqLPjcWe.mjs +20 -0
  12. package/dist/config/defaults/config.yaml +6 -0
  13. package/dist/config/defaults/workers.yaml +2 -0
  14. package/dist/{config-DLmyEK2q.mjs → config-C2dd2SXS.mjs} +1 -1
  15. package/dist/{config-Bz8pAU5Q.mjs → config-DGV64YJa.mjs} +9 -1
  16. package/dist/{controls-rIItFeIJ.mjs → controls-ByrcupcA.mjs} +14 -14
  17. package/dist/daemon/index.mjs +29 -29
  18. package/dist/{daemon-SoUvPUOf.mjs → daemon-BjgJyJMP.mjs} +22 -22
  19. package/dist/daemon-iymy18Ie.mjs +46 -0
  20. package/dist/daemon-mcp/index.mjs +27 -27
  21. package/dist/{embed-pass-CN1D8MXl.mjs → embed-pass-DdTMn4DH.mjs} +4 -4
  22. package/dist/{endreason-C2-hYK0_.mjs → endreason-BjPom527.mjs} +4 -4
  23. package/dist/{fallback-CwPSCrX8.mjs → fallback-CQ8_CuVu.mjs} +4 -4
  24. package/dist/{health-D0mUAVdw.mjs → health-Bb2U4PNK.mjs} +4 -4
  25. package/dist/hooks/block-sleep-poll.mjs +9 -0
  26. package/dist/hooks/capture-all-events.mjs +38 -7
  27. package/dist/hooks/capture-tool-output.mjs +38 -7
  28. package/dist/hooks/handoff-link.mjs +37 -6
  29. package/dist/hooks/load-project-context.mjs +9 -0
  30. package/dist/hooks/local-model-hint.mjs +9 -0
  31. package/dist/hooks/route-agents-to-worker.mjs +9 -0
  32. package/dist/hooks/security-validator.mjs +124 -28
  33. package/dist/hooks/supervision-banner.mjs +40 -7
  34. package/dist/hooks/worker-edit-repair.mjs +9 -0
  35. package/dist/hooks/worker-guard.mjs +46 -6
  36. package/dist/hooks/worker-note.mjs +47 -7
  37. package/dist/hooks/worker-pool-host.mjs +308 -146
  38. package/dist/hooks/worker-proxy.mjs +9 -0
  39. package/dist/hooks/worker-status-line.mjs +49 -7
  40. package/dist/hooks/worker-supervision.mjs +9 -0
  41. package/dist/hooks/worker-tool-name-repair.mjs +9 -0
  42. package/dist/index.mjs +7 -7
  43. package/dist/kill-tree-BlPw1vaU.mjs +10 -0
  44. package/dist/{kill-tree-DPiMscaY.mjs → kill-tree-DTmiEb3T.mjs} +7 -7
  45. package/dist/{launch-Bn2Zf90h.mjs → launch-CV6oPHI2.mjs} +3 -3
  46. package/dist/{launch-BZT3JDoZ.mjs → launch-Dy8qQnSD.mjs} +3 -3
  47. package/dist/{lessons-CFVU0cwA.mjs → lessons-CdmqZD0G.mjs} +21 -21
  48. package/dist/{local-candidate-DFd4pp-w.mjs → local-candidate-C2FGhf54.mjs} +2 -2
  49. package/dist/{local-instances-KTh8IeOT.mjs → local-instances-GgXydQ2P.mjs} +1 -1
  50. package/dist/{local-tiers-DSlIYvvm.mjs → local-tiers-X_dQfI4Q.mjs} +1 -1
  51. package/dist/{main-config-ops-rda08BCD.mjs → main-config-ops-C_fkINDv.mjs} +2 -2
  52. package/dist/{main-resolver-BKwI0I6H.mjs → main-resolver-CN_sfG1R.mjs} +13 -13
  53. package/dist/{model-inventory-BXv15B0d.mjs → model-inventory-BYNrSTaY.mjs} +10 -10
  54. package/dist/{models-add-5yXTyz3g.mjs → models-add-Dc7VXmcu.mjs} +30 -30
  55. package/dist/operator-IrLbk8hy.mjs +7 -0
  56. package/dist/{operator-Br6GeswF.mjs → operator-lRGvYr3D.mjs} +2 -2
  57. package/dist/{pai-marker-D6OoVbM_.mjs → pai-marker-kA0iM7rP.mjs} +2 -2
  58. package/dist/{pane-audit-DLYy9-4g.mjs → pane-audit-DUuilP1V.mjs} +8 -8
  59. package/dist/{paths-CypxFTfn.mjs → paths-BwfwHOvN.mjs} +2 -2
  60. package/dist/{paths-DIOwNcj-.mjs → paths-CKGYM0Lb.mjs} +2 -2
  61. package/dist/{planner-BzZ_2lc-.mjs → planner-BDHVUkIM.mjs} +22 -22
  62. package/dist/{pool-9EsbKD-U.mjs → pool-CFeHGX7q.mjs} +2 -2
  63. package/dist/{pool-cli-Cy5mlycP.mjs → pool-cli-Bj2TeA-d.mjs} +5 -5
  64. package/dist/{pool-cli-Db0uDwB9.mjs → pool-cli-DOLgPgOM.mjs} +5 -5
  65. package/dist/{project-setup-DHxdJjEc.mjs → project-setup-i5D0xkTn.mjs} +21 -21
  66. package/dist/{providers-BNV7CzC-.mjs → providers-BC2Myo_O.mjs} +5 -5
  67. package/dist/{providers-BH6hQYbU.mjs → providers-C-mnlH1b.mjs} +11 -11
  68. package/dist/{registrable-BwFiqazy.mjs → registrable-Ct0DKNKS.mjs} +6 -6
  69. package/dist/{registrable-Dxs4oKIj.mjs → registrable-D_4qXCnq.mjs} +4 -4
  70. package/dist/{render-jPpMrudf.mjs → render-CbifCwTb.mjs} +175 -65
  71. package/dist/{render-DVGXpfaT.mjs → render-FB4Fv_fi.mjs} +10 -10
  72. package/dist/{root-C8cxhdn9.mjs → root-80ESg6b7.mjs} +21 -21
  73. package/dist/{root-DmOzMeSv.mjs → root-B-ZYiEgi.mjs} +10 -10
  74. package/dist/{route-table-COAmc1nB.mjs → route-table-DcBZCuco.mjs} +10 -10
  75. package/dist/{routing-aJKMIagQ.mjs → routing-CF0wlR-_.mjs} +10 -10
  76. package/dist/{routing-B_cg1_Xx.mjs → routing-CJ8ioPl2.mjs} +10 -10
  77. package/dist/{run-DE9Q0ldN.mjs → run-CAjfKBQV.mjs} +53 -26
  78. package/dist/{scan-CNMcltOX.mjs → scan-ew8M6tTH.mjs} +3 -3
  79. package/dist/{scope-BTWstJ1B.mjs → scope-BRcaPw5D.mjs} +4 -4
  80. package/dist/session-BmQsXF_a.mjs +35 -0
  81. package/dist/{session-HBYOABWU.mjs → session-C1JnDXvP.mjs} +14 -14
  82. package/dist/{session-scan-BZxnYN1v.mjs → session-scan-DWCUKhDM.mjs} +5 -5
  83. package/dist/{session-scan-CX3MKCNg.mjs → session-scan-DihMibI-.mjs} +4 -4
  84. package/dist/{session-usage-CCmPFFa6.mjs → session-usage-BRIWFYPS.mjs} +2 -2
  85. package/dist/{status-D52xC_i0.mjs → status-Bj4yVKj0.mjs} +3 -3
  86. package/dist/{status-Cecau8Ps.mjs → status-DTMT5lyn.mjs} +2 -2
  87. package/dist/{tool-errors-BFw1gv-z.mjs → tool-errors-BOW2n882.mjs} +2 -2
  88. package/dist/{tool-errors-COM2JGEr.mjs → tool-errors-jNJj3Gzm.mjs} +5 -5
  89. package/dist/{viewer-DvBg6N22.mjs → viewer-4BU8w_gK.mjs} +14 -14
  90. package/dist/viewer-D3VEdqhC.mjs +22 -0
  91. package/dist/{wait-C5iWILj_.mjs → wait-BindDA5w.mjs} +3 -3
  92. package/dist/{worker-config-DkONNk_H.mjs → worker-config-CdPmb4_2.mjs} +25 -25
  93. package/dist/{worker-config-BmcJ9R0U.mjs → worker-config-CfV2dgSb.mjs} +29 -29
  94. package/dist/{workers-config-DwzrtdYu.mjs → workers-config-2VipVOYk.mjs} +1 -1
  95. package/dist/{worktree-O_kU6Q3y.mjs → worktree-7ZS3RBf8.mjs} +21 -11
  96. package/gemini-extension.json +1 -1
  97. package/package.json +1 -1
  98. package/pai-plugin.json +1 -1
  99. package/plugins/context-preservation/plugin.json +1 -1
  100. package/plugins/core/plugin.json +1 -1
  101. package/plugins/creative/plugin.json +1 -1
  102. package/plugins/observability/plugin.json +1 -1
  103. package/plugins/productivity/plugin.json +1 -1
  104. package/plugins/semantic-search/plugin.json +1 -1
  105. package/plugins/ui/plugin.json +1 -1
  106. package/plugins/zettelkasten/plugin.json +1 -1
  107. package/src/hooks/ts/lib/rules/builtin/base64-decode-to-shell.rule.yaml +3 -1
  108. package/src/hooks/ts/lib/rules/builtin/chmod-zero.rule.yaml +2 -0
  109. package/src/hooks/ts/lib/rules/builtin/curl-piped-to-shell.rule.yaml +8 -1
  110. package/src/hooks/ts/lib/rules/builtin/find-root-delete.rule.yaml +4 -1
  111. package/src/hooks/ts/lib/rules/builtin/instruction-override-disregard.rule.yaml +2 -0
  112. package/src/hooks/ts/lib/rules/builtin/reverse-shell-dev-tcp.rule.yaml +3 -0
  113. package/src/hooks/ts/lib/rules/builtin/reverse-shell-interactive-bash.rule.yaml +1 -0
  114. package/src/hooks/ts/lib/rules/builtin/rm-recursive-parent.rule.yaml +3 -1
  115. package/src/hooks/ts/lib/rules/builtin/rm-recursive-relative.rule.yaml +2 -1
  116. package/src/hooks/ts/lib/rules/builtin/rm-recursive-root.rule.yaml +4 -1
  117. package/src/hooks/ts/lib/rules/builtin/rm-trailing-tilde.rule.yaml +2 -1
  118. package/src/hooks/ts/lib/rules/builtin.generated.ts +34 -7
  119. package/src/hooks/ts/lib/rules/eval.ts +6 -4
  120. package/src/hooks/ts/lib/rules/lint.ts +7 -1
  121. package/src/hooks/ts/lib/rules/load.ts +55 -20
  122. package/src/hooks/ts/lib/rules/types.ts +2 -0
  123. package/src/hooks/ts/pre-tool-use/security-validator.ts +10 -2
  124. package/dist/auto-route-Bc8xP6TQ.mjs +0 -11
  125. package/dist/cockpit-memory-CLHZD64W.mjs +0 -20
  126. package/dist/daemon-176qA79N.mjs +0 -46
  127. package/dist/kill-tree-Dxei6qlR.mjs +0 -10
  128. package/dist/operator-Bmv5tiHQ.mjs +0 -7
  129. package/dist/session-DgZifjLx.mjs +0 -35
  130. package/dist/viewer-Ce-Xa9L3.mjs +0 -22
@@ -1,8 +1,8 @@
1
1
  import { _ as paiHomePath } from "./runtime-paths-twfV23YL.mjs";
2
2
  import { t as writeFileAtomic } from "./atomic-file-BorMa4T3.mjs";
3
- import { M as readWorkersSection, m as isLocalProvider } from "./config-Bz8pAU5Q.mjs";
4
- import { u as workersLogDir } from "./paths-CypxFTfn.mjs";
5
- import { g as isLive, y as loadStatuses } from "./status-Cecau8Ps.mjs";
3
+ import { M as readWorkersSection, m as isLocalProvider } from "./config-DGV64YJa.mjs";
4
+ import { u as workersLogDir } from "./paths-BwfwHOvN.mjs";
5
+ import { g as isLive, y as loadStatuses } from "./status-DTMT5lyn.mjs";
6
6
  import { readFileSync } from "node:fs";
7
7
  import { loadavg } from "node:os";
8
8
 
@@ -161,4 +161,4 @@ async function runEmbedCycle(d) {
161
161
 
162
162
  //#endregion
163
163
  export { EMBED_PASS_BATCH_SIZE as a, liveYieldCheck as c, runEmbedCycle as d, DEFAULT_EMBED_RESUME_MINUTES as i, readEmbedPasses as l, DEFAULT_EMBED_MAX_LOAD as n, formatEmbedStatus as o, DEFAULT_EMBED_MAX_MINUTES as r, lastRecordedEmbedPass as s, DEFAULT_EMBED_CYCLE_MAX_MINUTES as t, recordEmbedPass as u };
164
- //# sourceMappingURL=embed-pass-CN1D8MXl.mjs.map
164
+ //# sourceMappingURL=embed-pass-DdTMn4DH.mjs.map
@@ -1,7 +1,7 @@
1
1
  import { t as writeFileAtomic } from "./atomic-file-BorMa4T3.mjs";
2
- import { Et as appendLedger } from "./config-Bz8pAU5Q.mjs";
3
- import { r as eventsPath } from "./paths-CypxFTfn.mjs";
4
- import { D as pidAlive } from "./status-Cecau8Ps.mjs";
2
+ import { Et as appendLedger } from "./config-DGV64YJa.mjs";
3
+ import { r as eventsPath } from "./paths-BwfwHOvN.mjs";
4
+ import { D as pidAlive } from "./status-DTMT5lyn.mjs";
5
5
  import { appendFileSync, existsSync, readFileSync, unlinkSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { execFileSync } from "node:child_process";
@@ -151,4 +151,4 @@ function appendStopEvent(logDir, id, stop) {
151
151
 
152
152
  //#endregion
153
153
  export { endLabel as a, endFields as i, callerDescription as n, parentInfo as o, decideEndReason as r, requestKill as s, appendStopEvent as t };
154
- //# sourceMappingURL=endreason-C2-hYK0_.mjs.map
154
+ //# sourceMappingURL=endreason-BjPom527.mjs.map
@@ -1,8 +1,8 @@
1
1
  import { l as claudeHomeDir, t as aibrokerHomeDir } from "./runtime-paths-twfV23YL.mjs";
2
- import { F as resolveProviderKey, L as writeWorkersSection, M as readWorkersSection, P as resolveModelCapability, c as WorkersConfigError } from "./config-Bz8pAU5Q.mjs";
2
+ import { F as resolveProviderKey, L as writeWorkersSection, M as readWorkersSection, P as resolveModelCapability, c as WorkersConfigError } from "./config-DGV64YJa.mjs";
3
3
  import { O as readJsonStrict, k as writeJsonAtomic } from "./config-SlZ-Z52i.mjs";
4
- import { u as workersLogDir } from "./paths-CypxFTfn.mjs";
5
- import { _ as resolveTarget } from "./routing-aJKMIagQ.mjs";
4
+ import { u as workersLogDir } from "./paths-BwfwHOvN.mjs";
5
+ import { _ as resolveTarget } from "./routing-CF0wlR-_.mjs";
6
6
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
7
7
  import { join } from "node:path";
8
8
  import { execFileSync } from "node:child_process";
@@ -272,4 +272,4 @@ function fallbackStatusText(s) {
272
272
 
273
273
  //#endregion
274
274
  export { fallbackStatusText as i, fallbackOn as n, fallbackStatus as r, fallbackOff as t };
275
- //# sourceMappingURL=fallback-CwPSCrX8.mjs.map
275
+ //# sourceMappingURL=fallback-CQ8_CuVu.mjs.map
@@ -1,7 +1,7 @@
1
1
  import { _ as paiHomePath } from "./runtime-paths-twfV23YL.mjs";
2
- import { t as ANTHROPIC_NATIVE } from "./config-Bz8pAU5Q.mjs";
3
- import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-aJKMIagQ.mjs";
4
- import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-DFd4pp-w.mjs";
2
+ import { t as ANTHROPIC_NATIVE } from "./config-DGV64YJa.mjs";
3
+ import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-CF0wlR-_.mjs";
4
+ import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-C2FGhf54.mjs";
5
5
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
6
6
  import { Chalk } from "chalk";
7
7
 
@@ -311,4 +311,4 @@ function saveBudgetSnapshot(map, now = Date.now()) {
311
311
 
312
312
  //#endregion
313
313
  export { colorEnabled as a, renderCommandHelp as c, renderOverview as d, renderTable as f, saveBudgetSnapshot as i, renderMarkdown as l, usageLine as m, readBudget as n, makeStyle as o, suggest as p, readBudgetSnapshot as r, mdCommand as s, providerHealth as t, renderMore as u };
314
- //# sourceMappingURL=health-D0mUAVdw.mjs.map
314
+ //# sourceMappingURL=health-Bb2U4PNK.mjs.map
@@ -8174,6 +8174,7 @@ function defaultWorkersConfig() {
8174
8174
  cacheKeepaliveSecs: num(w.cacheKeepaliveSecs, 0),
8175
8175
  defaultMaxMinutes: num(w.defaultMaxMinutes, 60),
8176
8176
  waitAlarmMinutes: num(w.waitAlarmMinutes, 120),
8177
+ scanBudgetMs: num(w.scanBudgetMs, 5e3),
8177
8178
  stagger: {
8178
8179
  enabled: bool(stagger.enabled, true),
8179
8180
  localDefaultSec: num(stagger.localDefaultSec, 20),
@@ -8768,6 +8769,13 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8768
8769
  }
8769
8770
  waitAlarmMinutes = w.waitAlarmMinutes;
8770
8771
  }
8772
+ let scanBudgetMs = d.scanBudgetMs ?? 5e3;
8773
+ if (w.scanBudgetMs !== void 0) {
8774
+ if (typeof w.scanBudgetMs !== "number" || !Number.isInteger(w.scanBudgetMs) || w.scanBudgetMs < 1) {
8775
+ bad(".scanBudgetMs", "must be a positive integer (milliseconds)");
8776
+ }
8777
+ scanBudgetMs = w.scanBudgetMs;
8778
+ }
8771
8779
  const stagger = { ...d.stagger };
8772
8780
  if (w.stagger !== void 0) {
8773
8781
  if (typeof w.stagger !== "object" || w.stagger === null || Array.isArray(w.stagger)) {
@@ -8904,6 +8912,7 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8904
8912
  cacheKeepaliveSecs,
8905
8913
  defaultMaxMinutes,
8906
8914
  waitAlarmMinutes,
8915
+ scanBudgetMs,
8907
8916
  stagger,
8908
8917
  capacity,
8909
8918
  localIdle,
@@ -7728,20 +7728,50 @@ var PS_MAX_BUFFER = 64 * 1024 * 1024;
7728
7728
  var REDACTED = "[REDACTED]";
7729
7729
  var REDACTED_RE = String.raw`\[REDACTED\]`;
7730
7730
  var KEY_WORDS = "password|passwd|secret|token|api[_-]?key|credential|auth(?:orization)?|bearer";
7731
+ var PROSE = "is|are|was|were|be|to|of|in|on|for|and|or|the|a|an|that|this|it|not|out|here|there|so|as|at|by|with|if|when|which";
7731
7732
  var VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
7732
7733
  var REDACT_RULES = [
7733
7734
  {
7734
7735
  // `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
7735
7736
  id: "authorization",
7736
- re: /(Authorization\s*:\s*)(Bearer|Basic)\s+(\S+)/gi,
7737
+ re: /(Authorization\s*:\s*)(Bearer|Basic)\s+([^\s'"]+)/gi,
7737
7738
  replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
7738
7739
  },
7740
+ {
7741
+ // `Cookie: a=b; c=d` — keep the cookie names, redact every value
7742
+ id: "cookie",
7743
+ re: /((?:Set-)?Cookie\s*:\s*)([^\n]+)/gi,
7744
+ replace: (_m, head, rest) => `${head}${rest.replace(/([^=;\s'"]+=)[^;'"]*/g, `$1${REDACTED}`)}`
7745
+ },
7739
7746
  {
7740
7747
  // `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
7741
- // the word must be a whole key segment, so `monkeys=` stays untouched
7748
+ // the word must be a whole key segment, so `monkeys=` stays untouched.
7749
+ // The separator may start with the key's closing quote (JSON); it is kept.
7742
7750
  id: "key-value",
7743
- re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(${VAL})`, "gi"),
7744
- replace: (_m, key, sep2) => `${key}${sep2}${REDACTED}`
7751
+ re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(["']?\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(?!(?:${PROSE})\b)(${VAL})`, "gi"),
7752
+ replace: (m, key, sep2, val) => {
7753
+ if (/[_-](?:count|length|len|size|limit|max|min|budget)$/i.test(key) && /^\d+$/.test(val)) return m;
7754
+ const q = sep2[0] === '"' || sep2[0] === "'" ? val[0] : "";
7755
+ return q && (q === '"' || q === "'") ? `${key}${sep2}${q}${REDACTED}${q}` : `${key}${sep2}${REDACTED}`;
7756
+ }
7757
+ },
7758
+ {
7759
+ // npmrc `//registry/:_authToken=xxx`
7760
+ id: "npm-auth-token",
7761
+ re: new RegExp(String.raw`(_authToken\s*=\s*)(${VAL})`, "g"),
7762
+ replace: (_m, head) => `${head}${REDACTED}`
7763
+ },
7764
+ {
7765
+ // `curl -u user:pass` / `--user user:pass` — keep the user
7766
+ id: "curl-user",
7767
+ re: /(\bcurl\b[^\n]{0,500}?\s(?:-u|--user)[\s=]+['"]?[^\s:'"]+:)([^\s'"]+)/g,
7768
+ replace: (_m, head) => `${head}${REDACTED}`
7769
+ },
7770
+ {
7771
+ // `mysql -phunter2` / `mysqldump -p'hunter2'` — attached password only
7772
+ id: "mysql-p",
7773
+ re: /(\bmysql(?:dump)?\b[^\n]{0,300}?\s-p)('[^']*'|"[^"]*"|[^\s'"-][^\s'"]*)/g,
7774
+ replace: (_m, head) => `${head}${REDACTED}`
7745
7775
  },
7746
7776
  {
7747
7777
  // `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
@@ -7765,13 +7795,13 @@ var REDACT_RULES = [
7765
7795
  // provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
7766
7796
  // glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
7767
7797
  id: "token-prefix",
7768
- re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
7798
+ re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}|[sr]k_(?:live|test)_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{36}|hf_[A-Za-z0-9]{30,}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
7769
7799
  replace: REDACTED
7770
7800
  },
7771
7801
  {
7772
7802
  // 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
7773
7803
  id: "long-run",
7774
- re: /\b[A-Za-z0-9+/]{40,}={0,2}(?![\w/])/g,
7804
+ re: /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40,4096}={0,2}(?![\w/])/g,
7775
7805
  // a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
7776
7806
  replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
7777
7807
  }
@@ -7779,11 +7809,12 @@ var REDACT_RULES = [
7779
7809
  var PEM_BLOCK = /-----BEGIN[^-\n]*PRIVATE KEY-----[\s\S]*?(?:-----END[^-\n]*PRIVATE KEY-----|$)/g;
7780
7810
  var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
7781
7811
  var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
7812
+ var LONG_RUN_MAX_LINE = 64 * 1024;
7782
7813
  var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
7783
7814
  function redactLine(line) {
7784
7815
  let out = line;
7785
7816
  for (const r of LINE_RULES) out = out.replace(r.re, r.replace);
7786
- if (KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
7817
+ if (out.length <= LONG_RUN_MAX_LINE && KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
7787
7818
  return out;
7788
7819
  }
7789
7820
  function redactSecrets(text) {
@@ -145,20 +145,50 @@ var PS_MAX_BUFFER = 64 * 1024 * 1024;
145
145
  var REDACTED = "[REDACTED]";
146
146
  var REDACTED_RE = String.raw`\[REDACTED\]`;
147
147
  var KEY_WORDS = "password|passwd|secret|token|api[_-]?key|credential|auth(?:orization)?|bearer";
148
+ var PROSE = "is|are|was|were|be|to|of|in|on|for|and|or|the|a|an|that|this|it|not|out|here|there|so|as|at|by|with|if|when|which";
148
149
  var VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
149
150
  var REDACT_RULES = [
150
151
  {
151
152
  // `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
152
153
  id: "authorization",
153
- re: /(Authorization\s*:\s*)(Bearer|Basic)\s+(\S+)/gi,
154
+ re: /(Authorization\s*:\s*)(Bearer|Basic)\s+([^\s'"]+)/gi,
154
155
  replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
155
156
  },
157
+ {
158
+ // `Cookie: a=b; c=d` — keep the cookie names, redact every value
159
+ id: "cookie",
160
+ re: /((?:Set-)?Cookie\s*:\s*)([^\n]+)/gi,
161
+ replace: (_m, head, rest) => `${head}${rest.replace(/([^=;\s'"]+=)[^;'"]*/g, `$1${REDACTED}`)}`
162
+ },
156
163
  {
157
164
  // `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
158
- // the word must be a whole key segment, so `monkeys=` stays untouched
165
+ // the word must be a whole key segment, so `monkeys=` stays untouched.
166
+ // The separator may start with the key's closing quote (JSON); it is kept.
159
167
  id: "key-value",
160
- re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(${VAL})`, "gi"),
161
- replace: (_m, key, sep) => `${key}${sep}${REDACTED}`
168
+ re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(["']?\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(?!(?:${PROSE})\b)(${VAL})`, "gi"),
169
+ replace: (m, key, sep, val) => {
170
+ if (/[_-](?:count|length|len|size|limit|max|min|budget)$/i.test(key) && /^\d+$/.test(val)) return m;
171
+ const q = sep[0] === '"' || sep[0] === "'" ? val[0] : "";
172
+ return q && (q === '"' || q === "'") ? `${key}${sep}${q}${REDACTED}${q}` : `${key}${sep}${REDACTED}`;
173
+ }
174
+ },
175
+ {
176
+ // npmrc `//registry/:_authToken=xxx`
177
+ id: "npm-auth-token",
178
+ re: new RegExp(String.raw`(_authToken\s*=\s*)(${VAL})`, "g"),
179
+ replace: (_m, head) => `${head}${REDACTED}`
180
+ },
181
+ {
182
+ // `curl -u user:pass` / `--user user:pass` — keep the user
183
+ id: "curl-user",
184
+ re: /(\bcurl\b[^\n]{0,500}?\s(?:-u|--user)[\s=]+['"]?[^\s:'"]+:)([^\s'"]+)/g,
185
+ replace: (_m, head) => `${head}${REDACTED}`
186
+ },
187
+ {
188
+ // `mysql -phunter2` / `mysqldump -p'hunter2'` — attached password only
189
+ id: "mysql-p",
190
+ re: /(\bmysql(?:dump)?\b[^\n]{0,300}?\s-p)('[^']*'|"[^"]*"|[^\s'"-][^\s'"]*)/g,
191
+ replace: (_m, head) => `${head}${REDACTED}`
162
192
  },
163
193
  {
164
194
  // `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
@@ -182,13 +212,13 @@ var REDACT_RULES = [
182
212
  // provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
183
213
  // glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
184
214
  id: "token-prefix",
185
- re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
215
+ re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}|[sr]k_(?:live|test)_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{36}|hf_[A-Za-z0-9]{30,}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
186
216
  replace: REDACTED
187
217
  },
188
218
  {
189
219
  // 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
190
220
  id: "long-run",
191
- re: /\b[A-Za-z0-9+/]{40,}={0,2}(?![\w/])/g,
221
+ re: /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40,4096}={0,2}(?![\w/])/g,
192
222
  // a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
193
223
  replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
194
224
  }
@@ -196,11 +226,12 @@ var REDACT_RULES = [
196
226
  var PEM_BLOCK = /-----BEGIN[^-\n]*PRIVATE KEY-----[\s\S]*?(?:-----END[^-\n]*PRIVATE KEY-----|$)/g;
197
227
  var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
198
228
  var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
229
+ var LONG_RUN_MAX_LINE = 64 * 1024;
199
230
  var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
200
231
  function redactLine(line) {
201
232
  let out = line;
202
233
  for (const r of LINE_RULES) out = out.replace(r.re, r.replace);
203
- if (KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
234
+ if (out.length <= LONG_RUN_MAX_LINE && KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
204
235
  return out;
205
236
  }
206
237
  function redactSecrets(text) {
@@ -14,20 +14,50 @@ var PS_MAX_BUFFER = 64 * 1024 * 1024;
14
14
  var REDACTED = "[REDACTED]";
15
15
  var REDACTED_RE = String.raw`\[REDACTED\]`;
16
16
  var KEY_WORDS = "password|passwd|secret|token|api[_-]?key|credential|auth(?:orization)?|bearer";
17
+ var PROSE = "is|are|was|were|be|to|of|in|on|for|and|or|the|a|an|that|this|it|not|out|here|there|so|as|at|by|with|if|when|which";
17
18
  var VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
18
19
  var REDACT_RULES = [
19
20
  {
20
21
  // `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
21
22
  id: "authorization",
22
- re: /(Authorization\s*:\s*)(Bearer|Basic)\s+(\S+)/gi,
23
+ re: /(Authorization\s*:\s*)(Bearer|Basic)\s+([^\s'"]+)/gi,
23
24
  replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
24
25
  },
26
+ {
27
+ // `Cookie: a=b; c=d` — keep the cookie names, redact every value
28
+ id: "cookie",
29
+ re: /((?:Set-)?Cookie\s*:\s*)([^\n]+)/gi,
30
+ replace: (_m, head, rest) => `${head}${rest.replace(/([^=;\s'"]+=)[^;'"]*/g, `$1${REDACTED}`)}`
31
+ },
25
32
  {
26
33
  // `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
27
- // the word must be a whole key segment, so `monkeys=` stays untouched
34
+ // the word must be a whole key segment, so `monkeys=` stays untouched.
35
+ // The separator may start with the key's closing quote (JSON); it is kept.
28
36
  id: "key-value",
29
- re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(${VAL})`, "gi"),
30
- replace: (_m, key, sep) => `${key}${sep}${REDACTED}`
37
+ re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(["']?\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(?!(?:${PROSE})\b)(${VAL})`, "gi"),
38
+ replace: (m, key, sep, val) => {
39
+ if (/[_-](?:count|length|len|size|limit|max|min|budget)$/i.test(key) && /^\d+$/.test(val)) return m;
40
+ const q = sep[0] === '"' || sep[0] === "'" ? val[0] : "";
41
+ return q && (q === '"' || q === "'") ? `${key}${sep}${q}${REDACTED}${q}` : `${key}${sep}${REDACTED}`;
42
+ }
43
+ },
44
+ {
45
+ // npmrc `//registry/:_authToken=xxx`
46
+ id: "npm-auth-token",
47
+ re: new RegExp(String.raw`(_authToken\s*=\s*)(${VAL})`, "g"),
48
+ replace: (_m, head) => `${head}${REDACTED}`
49
+ },
50
+ {
51
+ // `curl -u user:pass` / `--user user:pass` — keep the user
52
+ id: "curl-user",
53
+ re: /(\bcurl\b[^\n]{0,500}?\s(?:-u|--user)[\s=]+['"]?[^\s:'"]+:)([^\s'"]+)/g,
54
+ replace: (_m, head) => `${head}${REDACTED}`
55
+ },
56
+ {
57
+ // `mysql -phunter2` / `mysqldump -p'hunter2'` — attached password only
58
+ id: "mysql-p",
59
+ re: /(\bmysql(?:dump)?\b[^\n]{0,300}?\s-p)('[^']*'|"[^"]*"|[^\s'"-][^\s'"]*)/g,
60
+ replace: (_m, head) => `${head}${REDACTED}`
31
61
  },
32
62
  {
33
63
  // `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
@@ -51,19 +81,20 @@ var REDACT_RULES = [
51
81
  // provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
52
82
  // glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
53
83
  id: "token-prefix",
54
- re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
84
+ re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}|[sr]k_(?:live|test)_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{36}|hf_[A-Za-z0-9]{30,}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
55
85
  replace: REDACTED
56
86
  },
57
87
  {
58
88
  // 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
59
89
  id: "long-run",
60
- re: /\b[A-Za-z0-9+/]{40,}={0,2}(?![\w/])/g,
90
+ re: /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40,4096}={0,2}(?![\w/])/g,
61
91
  // a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
62
92
  replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
63
93
  }
64
94
  ];
65
95
  var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
66
96
  var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
97
+ var LONG_RUN_MAX_LINE = 64 * 1024;
67
98
  var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
68
99
 
69
100
  // src/hooks/ts/lib/loop-guard.ts
@@ -8177,6 +8177,7 @@ function defaultWorkersConfig() {
8177
8177
  cacheKeepaliveSecs: num(w.cacheKeepaliveSecs, 0),
8178
8178
  defaultMaxMinutes: num(w.defaultMaxMinutes, 60),
8179
8179
  waitAlarmMinutes: num(w.waitAlarmMinutes, 120),
8180
+ scanBudgetMs: num(w.scanBudgetMs, 5e3),
8180
8181
  stagger: {
8181
8182
  enabled: bool(stagger.enabled, true),
8182
8183
  localDefaultSec: num(stagger.localDefaultSec, 20),
@@ -8771,6 +8772,13 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8771
8772
  }
8772
8773
  waitAlarmMinutes = w.waitAlarmMinutes;
8773
8774
  }
8775
+ let scanBudgetMs = d.scanBudgetMs ?? 5e3;
8776
+ if (w.scanBudgetMs !== void 0) {
8777
+ if (typeof w.scanBudgetMs !== "number" || !Number.isInteger(w.scanBudgetMs) || w.scanBudgetMs < 1) {
8778
+ bad(".scanBudgetMs", "must be a positive integer (milliseconds)");
8779
+ }
8780
+ scanBudgetMs = w.scanBudgetMs;
8781
+ }
8774
8782
  const stagger = { ...d.stagger };
8775
8783
  if (w.stagger !== void 0) {
8776
8784
  if (typeof w.stagger !== "object" || w.stagger === null || Array.isArray(w.stagger)) {
@@ -8907,6 +8915,7 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8907
8915
  cacheKeepaliveSecs,
8908
8916
  defaultMaxMinutes,
8909
8917
  waitAlarmMinutes,
8918
+ scanBudgetMs,
8910
8919
  stagger,
8911
8920
  capacity,
8912
8921
  localIdle,
@@ -8191,6 +8191,7 @@ function defaultWorkersConfig() {
8191
8191
  cacheKeepaliveSecs: num(w.cacheKeepaliveSecs, 0),
8192
8192
  defaultMaxMinutes: num(w.defaultMaxMinutes, 60),
8193
8193
  waitAlarmMinutes: num(w.waitAlarmMinutes, 120),
8194
+ scanBudgetMs: num(w.scanBudgetMs, 5e3),
8194
8195
  stagger: {
8195
8196
  enabled: bool(stagger.enabled, true),
8196
8197
  localDefaultSec: num(stagger.localDefaultSec, 20),
@@ -8785,6 +8786,13 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8785
8786
  }
8786
8787
  waitAlarmMinutes = w.waitAlarmMinutes;
8787
8788
  }
8789
+ let scanBudgetMs = d.scanBudgetMs ?? 5e3;
8790
+ if (w.scanBudgetMs !== void 0) {
8791
+ if (typeof w.scanBudgetMs !== "number" || !Number.isInteger(w.scanBudgetMs) || w.scanBudgetMs < 1) {
8792
+ bad(".scanBudgetMs", "must be a positive integer (milliseconds)");
8793
+ }
8794
+ scanBudgetMs = w.scanBudgetMs;
8795
+ }
8788
8796
  const stagger = { ...d.stagger };
8789
8797
  if (w.stagger !== void 0) {
8790
8798
  if (typeof w.stagger !== "object" || w.stagger === null || Array.isArray(w.stagger)) {
@@ -8921,6 +8929,7 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8921
8929
  cacheKeepaliveSecs,
8922
8930
  defaultMaxMinutes,
8923
8931
  waitAlarmMinutes,
8932
+ scanBudgetMs,
8924
8933
  stagger,
8925
8934
  capacity,
8926
8935
  localIdle,
@@ -8194,6 +8194,7 @@ function defaultWorkersConfig() {
8194
8194
  cacheKeepaliveSecs: num(w.cacheKeepaliveSecs, 0),
8195
8195
  defaultMaxMinutes: num(w.defaultMaxMinutes, 60),
8196
8196
  waitAlarmMinutes: num(w.waitAlarmMinutes, 120),
8197
+ scanBudgetMs: num(w.scanBudgetMs, 5e3),
8197
8198
  stagger: {
8198
8199
  enabled: bool(stagger.enabled, true),
8199
8200
  localDefaultSec: num(stagger.localDefaultSec, 20),
@@ -8788,6 +8789,13 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8788
8789
  }
8789
8790
  waitAlarmMinutes = w.waitAlarmMinutes;
8790
8791
  }
8792
+ let scanBudgetMs = d.scanBudgetMs ?? 5e3;
8793
+ if (w.scanBudgetMs !== void 0) {
8794
+ if (typeof w.scanBudgetMs !== "number" || !Number.isInteger(w.scanBudgetMs) || w.scanBudgetMs < 1) {
8795
+ bad(".scanBudgetMs", "must be a positive integer (milliseconds)");
8796
+ }
8797
+ scanBudgetMs = w.scanBudgetMs;
8798
+ }
8791
8799
  const stagger = { ...d.stagger };
8792
8800
  if (w.stagger !== void 0) {
8793
8801
  if (typeof w.stagger !== "object" || w.stagger === null || Array.isArray(w.stagger)) {
@@ -8924,6 +8932,7 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
8924
8932
  cacheKeepaliveSecs,
8925
8933
  defaultMaxMinutes,
8926
8934
  waitAlarmMinutes,
8935
+ scanBudgetMs,
8927
8936
  stagger,
8928
8937
  capacity,
8929
8938
  localIdle,