@cohortapp/agent-sdk 2.3.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 (731) hide show
  1. package/.claude/commands/init-agent.md +104 -0
  2. package/.claude/commands/init-maestro.md +1187 -0
  3. package/.claude/settings.json +161 -0
  4. package/.env.example +216 -0
  5. package/README.md +632 -0
  6. package/agents/browser-operator/agent.md +52 -0
  7. package/agents/calendar-ops/agent.md +50 -0
  8. package/agents/communications/agent.md +96 -0
  9. package/agents/decision-log/agent.md +65 -0
  10. package/agents/desktop-operator/agent.md +59 -0
  11. package/agents/gmail-operator/agent.md +62 -0
  12. package/agents/inbound-dispatcher/agent.md +66 -0
  13. package/agents/inbox-processor/agent.md +39 -0
  14. package/agents/pmo-execution/agent.md +60 -0
  15. package/agents/session-spawner/agent.md +64 -0
  16. package/agents/slack-operator/agent.md +60 -0
  17. package/agents/whatsapp-operator/agent.md +60 -0
  18. package/agents/workflow-automation/agent.md +61 -0
  19. package/archetypes/altitudes/c-suite.yaml +58 -0
  20. package/archetypes/altitudes/founder.yaml +68 -0
  21. package/archetypes/altitudes/senior-manager.yaml +63 -0
  22. package/archetypes/altitudes/svp.yaml +60 -0
  23. package/archetypes/altitudes/vp.yaml +50 -0
  24. package/archetypes/archetype.schema.json +77 -0
  25. package/archetypes/base.yaml +47 -0
  26. package/archetypes/capabilities/commercial-leader.yaml +159 -0
  27. package/archetypes/capabilities/compliance-officer.yaml +159 -0
  28. package/archetypes/capabilities/executive-operator.yaml +169 -0
  29. package/archetypes/capabilities/finance-leader.yaml +162 -0
  30. package/archetypes/capabilities/operations-leader.yaml +154 -0
  31. package/archetypes/capabilities/product-leader.yaml +148 -0
  32. package/archetypes/capabilities/technical-leader.yaml +146 -0
  33. package/archetypes/functions/commercial-leader.yaml +62 -0
  34. package/archetypes/functions/compliance-officer.yaml +64 -0
  35. package/archetypes/functions/executive-operator.yaml +70 -0
  36. package/archetypes/functions/finance-leader.yaml +70 -0
  37. package/archetypes/functions/operations-leader.yaml +62 -0
  38. package/archetypes/functions/product-leader.yaml +61 -0
  39. package/archetypes/functions/technical-leader.yaml +57 -0
  40. package/bin/cohort-mcp.mjs +81 -0
  41. package/bin/maestro.mjs +3516 -0
  42. package/bin/maestro.test.mjs +1015 -0
  43. package/desktop-control/README.md +56 -0
  44. package/desktop-control/app-profiles/gmail.yaml +120 -0
  45. package/desktop-control/app-profiles/slack.yaml +315 -0
  46. package/desktop-control/app-profiles/whatsapp.yaml +107 -0
  47. package/docs/architecture/agent-topology.md +2239 -0
  48. package/docs/architecture/archetype-agent-factory.md +110 -0
  49. package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
  50. package/docs/architecture/continuous-monitoring.md +221 -0
  51. package/docs/architecture/mcp-capability-map.md +585 -0
  52. package/docs/architecture/system-architecture.md +1272 -0
  53. package/docs/company-context/README.md +40 -0
  54. package/docs/guides/agent-persona-setup.md +600 -0
  55. package/docs/guides/agents-observe-setup.md +64 -0
  56. package/docs/guides/billing-console-keys.md +88 -0
  57. package/docs/guides/ccxray-diagnostics.md +65 -0
  58. package/docs/guides/channel-bus.md +127 -0
  59. package/docs/guides/claude-mem-setup.md +79 -0
  60. package/docs/guides/claude-pace-setup.md +56 -0
  61. package/docs/guides/claudraband-sessions.md +98 -0
  62. package/docs/guides/clawteam-swarm.md +116 -0
  63. package/docs/guides/code-review-graph-setup.md +86 -0
  64. package/docs/guides/email-setup.md +431 -0
  65. package/docs/guides/mac-mini.md +119 -0
  66. package/docs/guides/media-generation-setup.md +349 -0
  67. package/docs/guides/model-routing.md +162 -0
  68. package/docs/guides/observability-otel.md +265 -0
  69. package/docs/guides/org-onboarding.md +132 -0
  70. package/docs/guides/outbound-governance-setup.md +437 -0
  71. package/docs/guides/pdf-generation-setup.md +315 -0
  72. package/docs/guides/poller-daemon-setup.md +563 -0
  73. package/docs/guides/rag-context-setup.md +459 -0
  74. package/docs/guides/self-optimization-pattern.md +82 -0
  75. package/docs/guides/setup-wizard.md +178 -0
  76. package/docs/guides/slack-setup.md +350 -0
  77. package/docs/guides/telegram-setup.md +227 -0
  78. package/docs/guides/twilio-subaccounts-setup.md +223 -0
  79. package/docs/guides/verification.md +128 -0
  80. package/docs/guides/voice-mode.md +188 -0
  81. package/docs/guides/voice-sms-setup.md +698 -0
  82. package/docs/guides/webhook-relay-setup.md +349 -0
  83. package/docs/guides/whatsapp-setup.md +288 -0
  84. package/docs/prompts/board-pack-cover-template.md +36 -0
  85. package/docs/prompts/decision-recommendation-template.md +88 -0
  86. package/docs/prompts/followup-message-template.md +141 -0
  87. package/docs/prompts/investor-letter-template.md +52 -0
  88. package/docs/prompts/morning-brief-template.md +82 -0
  89. package/docs/prompts/presentation-template.md +58 -0
  90. package/docs/prompts/weekly-strategic-memo-template.md +104 -0
  91. package/docs/research/hallucinated-tool-output-investigation.md +151 -0
  92. package/docs/runbooks/backup-restore.md +205 -0
  93. package/docs/runbooks/cohort-cutover.md +129 -0
  94. package/docs/runbooks/fleet-operations.md +200 -0
  95. package/docs/runbooks/incident-response.md +226 -0
  96. package/docs/runbooks/mac-mini-bootstrap.md +431 -0
  97. package/docs/runbooks/perpetual-operations.md +509 -0
  98. package/docs/runbooks/recovery-and-failover.md +260 -0
  99. package/framework-features.json +267 -0
  100. package/ingest/README.md +87 -0
  101. package/lib/action-executor.js +689 -0
  102. package/lib/action-executor.test.mjs +871 -0
  103. package/lib/agent-root.mjs +37 -0
  104. package/lib/archetype.mjs +236 -0
  105. package/lib/archetype.test.mjs +132 -0
  106. package/lib/autonomy.mjs +114 -0
  107. package/lib/autonomy.test.mjs +66 -0
  108. package/lib/backlog.mjs +358 -0
  109. package/lib/backlog.test.mjs +266 -0
  110. package/lib/budget-guard.mjs +279 -0
  111. package/lib/budget-guard.test.mjs +291 -0
  112. package/lib/cadence-bus-schedule.test.mjs +194 -0
  113. package/lib/cadence-bus.mjs +1120 -0
  114. package/lib/cadence-bus.test.mjs +720 -0
  115. package/lib/cadences.mjs +205 -0
  116. package/lib/cadences.test.mjs +125 -0
  117. package/lib/capability.mjs +154 -0
  118. package/lib/capability.test.mjs +78 -0
  119. package/lib/channels/base-adapter.mjs +719 -0
  120. package/lib/channels/base-adapter.test.mjs +590 -0
  121. package/lib/channels/channel.mjs +128 -0
  122. package/lib/channels/channels.test.mjs +371 -0
  123. package/lib/channels/contract.mjs +215 -0
  124. package/lib/channels/contract.test.mjs +137 -0
  125. package/lib/channels/conversation-resolver.mjs +95 -0
  126. package/lib/channels/gmail/adapter.mjs +87 -0
  127. package/lib/channels/inbox-item.mjs +255 -0
  128. package/lib/channels/inbox-item.test.mjs +335 -0
  129. package/lib/channels/index.mjs +94 -0
  130. package/lib/channels/orgmail/adapter.mjs +353 -0
  131. package/lib/channels/orgmail/adapter.test.mjs +311 -0
  132. package/lib/channels/pairing.mjs +363 -0
  133. package/lib/channels/pairing.test.mjs +270 -0
  134. package/lib/channels/registry.mjs +164 -0
  135. package/lib/channels/slack/adapter.mjs +317 -0
  136. package/lib/channels/slack-adapter.test.mjs +212 -0
  137. package/lib/channels/sms/adapter.mjs +43 -0
  138. package/lib/channels/telegram/adapter.mjs +432 -0
  139. package/lib/channels/telegram-adapter.test.mjs +306 -0
  140. package/lib/channels/voice/adapter.mjs +301 -0
  141. package/lib/channels/voice/adapter.test.mjs +278 -0
  142. package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
  143. package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
  144. package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
  145. package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
  146. package/lib/charter.mjs +256 -0
  147. package/lib/charter.test.mjs +89 -0
  148. package/lib/claude-bin.mjs +134 -0
  149. package/lib/claude-bin.test.mjs +75 -0
  150. package/lib/collective/capture.mjs +185 -0
  151. package/lib/collective/capture.test.mjs +121 -0
  152. package/lib/collective/cards.mjs +201 -0
  153. package/lib/collective/cards.test.mjs +114 -0
  154. package/lib/collective/config.mjs +186 -0
  155. package/lib/collective/config.test.mjs +123 -0
  156. package/lib/collective/global-config.mjs +113 -0
  157. package/lib/collective/global-config.test.mjs +75 -0
  158. package/lib/collective/presence.mjs +201 -0
  159. package/lib/collective/presence.test.mjs +95 -0
  160. package/lib/collective/recall.mjs +215 -0
  161. package/lib/collective/recall.test.mjs +116 -0
  162. package/lib/comms/send-gate.mjs +554 -0
  163. package/lib/comms/send-gate.test.mjs +577 -0
  164. package/lib/comms.mjs +67 -0
  165. package/lib/comms.test.mjs +41 -0
  166. package/lib/diagnostics/alerts.mjs +424 -0
  167. package/lib/diagnostics/alerts.test.mjs +318 -0
  168. package/lib/diagnostics/backup-freshness.mjs +188 -0
  169. package/lib/diagnostics/backup-freshness.test.mjs +185 -0
  170. package/lib/diagnostics/counters.mjs +269 -0
  171. package/lib/diagnostics/counters.test.mjs +206 -0
  172. package/lib/diagnostics/events.mjs +188 -0
  173. package/lib/diagnostics/events.test.mjs +290 -0
  174. package/lib/diagnostics/otel.mjs +237 -0
  175. package/lib/diagnostics/otel.test.mjs +196 -0
  176. package/lib/diagnostics/trace.mjs +216 -0
  177. package/lib/diagnostics/trace.test.mjs +251 -0
  178. package/lib/env-compat.mjs +74 -0
  179. package/lib/env-compat.test.mjs +104 -0
  180. package/lib/feature-init.mjs +331 -0
  181. package/lib/fs-atomic.mjs +112 -0
  182. package/lib/fs-atomic.test.mjs +72 -0
  183. package/lib/fs-ownership.mjs +111 -0
  184. package/lib/fs-ownership.test.mjs +158 -0
  185. package/lib/hooks/bus.mjs +347 -0
  186. package/lib/hooks/bus.test.mjs +387 -0
  187. package/lib/index.js +16 -0
  188. package/lib/learning/config.mjs +106 -0
  189. package/lib/learning/config.test.mjs +75 -0
  190. package/lib/learning/counters.mjs +156 -0
  191. package/lib/learning/counters.test.mjs +69 -0
  192. package/lib/learning/curator-consolidate.test.mjs +238 -0
  193. package/lib/learning/curator.mjs +453 -0
  194. package/lib/learning/curator.test.mjs +106 -0
  195. package/lib/learning/log.mjs +40 -0
  196. package/lib/learning/reflect.mjs +534 -0
  197. package/lib/learning/reflect.test.mjs +0 -0
  198. package/lib/learning/session-index.mjs +352 -0
  199. package/lib/learning/session-index.test.mjs +125 -0
  200. package/lib/learning/skill-writer.mjs +474 -0
  201. package/lib/learning/skill-writer.test.mjs +210 -0
  202. package/lib/mcp/server.mjs +328 -0
  203. package/lib/mcp/server.test.mjs +400 -0
  204. package/lib/model-router/auth-profiles.mjs +758 -0
  205. package/lib/model-router/auth-profiles.test.mjs +580 -0
  206. package/lib/model-router/catalog/anthropic.yaml +153 -0
  207. package/lib/model-router/catalog/deepseek.yaml +86 -0
  208. package/lib/model-router/catalog/moonshot.yaml +81 -0
  209. package/lib/model-router/catalog/qwen.yaml +114 -0
  210. package/lib/model-router/catalog.mjs +925 -0
  211. package/lib/model-router/catalog.test.mjs +385 -0
  212. package/lib/model-router/economics.mjs +564 -0
  213. package/lib/model-router/economics.test.mjs +344 -0
  214. package/lib/model-router/failover.mjs +298 -0
  215. package/lib/model-router/failover.test.mjs +439 -0
  216. package/lib/model-router/health.mjs +453 -0
  217. package/lib/model-router/health.test.mjs +338 -0
  218. package/lib/model-router/integration-coverage.test.mjs +829 -0
  219. package/lib/model-router/integration.test.mjs +564 -0
  220. package/lib/model-router/ledger.mjs +402 -0
  221. package/lib/model-router/ledger.test.mjs +382 -0
  222. package/lib/model-router/llm-task.mjs +515 -0
  223. package/lib/model-router/llm-task.test.mjs +392 -0
  224. package/lib/model-router/org-credentials.mjs +260 -0
  225. package/lib/model-router/org-credentials.test.mjs +265 -0
  226. package/lib/model-router/pricing-refresh.mjs +463 -0
  227. package/lib/model-router/pricing-refresh.test.mjs +286 -0
  228. package/lib/model-router/reconcile.mjs +429 -0
  229. package/lib/model-router/reconcile.test.mjs +316 -0
  230. package/lib/model-router/repair.mjs +471 -0
  231. package/lib/model-router/repair.test.mjs +180 -0
  232. package/lib/model-router/resolve.mjs +1206 -0
  233. package/lib/model-router/spawn.mjs +497 -0
  234. package/lib/model-router/spawn.test.mjs +425 -0
  235. package/lib/model-router/taxonomy.mjs +893 -0
  236. package/lib/model-router/taxonomy.test.mjs +410 -0
  237. package/lib/model-router.mjs +677 -0
  238. package/lib/model-router.test.mjs +907 -0
  239. package/lib/org/activity.mjs +211 -0
  240. package/lib/org/activity.test.mjs +134 -0
  241. package/lib/org/approvals.mjs +448 -0
  242. package/lib/org/approvals.test.mjs +216 -0
  243. package/lib/org/awareness.mjs +222 -0
  244. package/lib/org/awareness.test.mjs +159 -0
  245. package/lib/org/board.mjs +229 -0
  246. package/lib/org/board.test.mjs +177 -0
  247. package/lib/org/bootstrap-context.mjs +169 -0
  248. package/lib/org/bootstrap-context.test.mjs +153 -0
  249. package/lib/org/client.mjs +1628 -0
  250. package/lib/org/client.test.mjs +1107 -0
  251. package/lib/org/cohort-client.mjs +67 -0
  252. package/lib/org/cohort-client.test.mjs +126 -0
  253. package/lib/org/cost-sync.mjs +227 -0
  254. package/lib/org/cost-sync.test.mjs +153 -0
  255. package/lib/org/doctor.mjs +212 -0
  256. package/lib/org/doctor.test.mjs +212 -0
  257. package/lib/org/handoff.mjs +293 -0
  258. package/lib/org/handoff.test.mjs +269 -0
  259. package/lib/org/integration-tools.mjs +182 -0
  260. package/lib/org/integration-tools.test.mjs +160 -0
  261. package/lib/org/keys.mjs +131 -0
  262. package/lib/org/keys.test.mjs +92 -0
  263. package/lib/org/knowledge.mjs +463 -0
  264. package/lib/org/knowledge.test.mjs +319 -0
  265. package/lib/org/leases.mjs +335 -0
  266. package/lib/org/leases.test.mjs +235 -0
  267. package/lib/org/mesh-integration.test.mjs +127 -0
  268. package/lib/org/mesh.mjs +459 -0
  269. package/lib/org/mesh.test.mjs +345 -0
  270. package/lib/org/messaging.mjs +503 -0
  271. package/lib/org/messaging.test.mjs +238 -0
  272. package/lib/org/policy.mjs +345 -0
  273. package/lib/org/policy.test.mjs +237 -0
  274. package/lib/org/protocol.checksum +1 -0
  275. package/lib/org/protocol.checksum.test.mjs +90 -0
  276. package/lib/org/protocol.mjs +967 -0
  277. package/lib/org/protocol.test.mjs +264 -0
  278. package/lib/org/registry.mjs +194 -0
  279. package/lib/org/registry.test.mjs +100 -0
  280. package/lib/org/tool-surface-integration.test.mjs +120 -0
  281. package/lib/org/tool-surface.mjs +2535 -0
  282. package/lib/org/tool-surface.test.mjs +589 -0
  283. package/lib/org/ui-parity.mjs +3236 -0
  284. package/lib/org/ui-parity.test.mjs +348 -0
  285. package/lib/org/verify.mjs +176 -0
  286. package/lib/org/verify.test.mjs +194 -0
  287. package/lib/rag/embed.mjs +188 -0
  288. package/lib/rag/indexer.mjs +425 -0
  289. package/lib/rag/rag.test.mjs +505 -0
  290. package/lib/rag/search.mjs +475 -0
  291. package/lib/rate-guard.mjs +246 -0
  292. package/lib/rate-guard.test.mjs +201 -0
  293. package/lib/render.mjs +112 -0
  294. package/lib/render.test.mjs +68 -0
  295. package/lib/resource-governor.mjs +297 -0
  296. package/lib/resource-governor.test.mjs +262 -0
  297. package/lib/scheduling/dynamic-jobs.mjs +675 -0
  298. package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
  299. package/lib/scheduling/jitter.mjs +0 -0
  300. package/lib/scheduling/jitter.test.mjs +140 -0
  301. package/lib/secrets/broker.mjs +315 -0
  302. package/lib/secrets/broker.test.mjs +280 -0
  303. package/lib/secrets/providers.mjs +461 -0
  304. package/lib/secrets/providers.test.mjs +274 -0
  305. package/lib/security/audit-engine.mjs +684 -0
  306. package/lib/security/audit-engine.test.mjs +389 -0
  307. package/lib/security/coerce-args.mjs +552 -0
  308. package/lib/security/coerce-args.test.mjs +281 -0
  309. package/lib/security/dangerous-tools.mjs +97 -0
  310. package/lib/security/dangerous-tools.test.mjs +68 -0
  311. package/lib/security/external-content.mjs +145 -0
  312. package/lib/security/external-content.test.mjs +67 -0
  313. package/lib/security/redact.mjs +592 -0
  314. package/lib/security/redact.test.mjs +441 -0
  315. package/lib/security/secret-equal.mjs +73 -0
  316. package/lib/security/secret-equal.test.mjs +55 -0
  317. package/lib/session-permissions.mjs +101 -0
  318. package/lib/session-permissions.test.mjs +100 -0
  319. package/lib/setup/claude-probe.mjs +74 -0
  320. package/lib/setup/completeness.mjs +175 -0
  321. package/lib/setup/completeness.test.mjs +110 -0
  322. package/lib/setup/context-pack.mjs +173 -0
  323. package/lib/setup/context-pack.test.mjs +89 -0
  324. package/lib/setup/enrich.mjs +277 -0
  325. package/lib/setup/enrich.test.mjs +115 -0
  326. package/lib/setup/enroll-from-cohort.mjs +441 -0
  327. package/lib/setup/enroll-from-cohort.test.mjs +233 -0
  328. package/lib/setup/integration.test.mjs +162 -0
  329. package/lib/setup/io.mjs +360 -0
  330. package/lib/setup/io.test.mjs +77 -0
  331. package/lib/setup/run-generator.mjs +81 -0
  332. package/lib/setup/runner.mjs +244 -0
  333. package/lib/setup/runner.test.mjs +132 -0
  334. package/lib/setup/sections/comms.mjs +173 -0
  335. package/lib/setup/sections/company.mjs +120 -0
  336. package/lib/setup/sections/enrich.mjs +138 -0
  337. package/lib/setup/sections/identity.mjs +182 -0
  338. package/lib/setup/sections/identity.test.mjs +140 -0
  339. package/lib/setup/sections/learning.mjs +153 -0
  340. package/lib/setup/sections/learning.test.mjs +81 -0
  341. package/lib/setup/sections/messaging.mjs +219 -0
  342. package/lib/setup/sections/messaging.test.mjs +127 -0
  343. package/lib/setup/sections/model.mjs +102 -0
  344. package/lib/setup/sections/operating-model.mjs +78 -0
  345. package/lib/setup/sections/org.mjs +475 -0
  346. package/lib/setup/sections/org.test.mjs +313 -0
  347. package/lib/setup/sections/orgmail.mjs +173 -0
  348. package/lib/setup/sections/orgmail.test.mjs +118 -0
  349. package/lib/setup/sections/recovery.mjs +159 -0
  350. package/lib/setup/sections/recovery.test.mjs +98 -0
  351. package/lib/setup/sections/tools.mjs +132 -0
  352. package/lib/setup/sections/verify.mjs +97 -0
  353. package/lib/setup/sot.mjs +205 -0
  354. package/lib/setup/sot.test.mjs +81 -0
  355. package/lib/setup/state.mjs +151 -0
  356. package/lib/setup/state.test.mjs +92 -0
  357. package/lib/singleton.js +229 -0
  358. package/lib/singleton.test.mjs +135 -0
  359. package/lib/telemetry/alerts.mjs +216 -0
  360. package/lib/telemetry/alerts.test.mjs +109 -0
  361. package/lib/telemetry/collect.mjs +512 -0
  362. package/lib/telemetry/collect.test.mjs +202 -0
  363. package/lib/tool-definitions-integration.test.mjs +83 -0
  364. package/lib/tool-definitions.js +738 -0
  365. package/lib/tool-definitions.test.mjs +437 -0
  366. package/lib/util/fetch-timeout.mjs +136 -0
  367. package/lib/util/fetch-timeout.test.mjs +202 -0
  368. package/lib/util/reconnect.mjs +343 -0
  369. package/lib/util/reconnect.test.mjs +369 -0
  370. package/lib/util/unhandled.mjs +205 -0
  371. package/lib/util/unhandled.test.mjs +216 -0
  372. package/lib/voice/context-loader.mjs +466 -0
  373. package/lib/voice/index.mjs +100 -0
  374. package/lib/voice/openai-realtime.mjs +510 -0
  375. package/lib/voice/outbound.mjs +542 -0
  376. package/lib/voice/outbound.test.mjs +69 -0
  377. package/lib/voice/post-call-brief.mjs +428 -0
  378. package/lib/voice/provider.mjs +52 -0
  379. package/lib/voice/session-rotation.mjs +257 -0
  380. package/lib/voice/stt.mjs +161 -0
  381. package/lib/voice/stt.test.mjs +226 -0
  382. package/lib/voice/tool-bridge.mjs +370 -0
  383. package/lib/voice/tts.mjs +104 -0
  384. package/lib/voice/twilio-sip-bridge.mjs +288 -0
  385. package/lib/voice/voice.test.mjs +990 -0
  386. package/mcp/README.md +80 -0
  387. package/package.json +151 -0
  388. package/plugins/maestro-skills/plugin.json +139 -0
  389. package/plugins/maestro-skills/skills/agents-observe.md +110 -0
  390. package/plugins/maestro-skills/skills/board-deck.md +68 -0
  391. package/plugins/maestro-skills/skills/books-close.md +77 -0
  392. package/plugins/maestro-skills/skills/brand-steward.md +121 -0
  393. package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
  394. package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
  395. package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
  396. package/plugins/maestro-skills/skills/claude-pace.md +61 -0
  397. package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
  398. package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
  399. package/plugins/maestro-skills/skills/decision-brief.md +89 -0
  400. package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
  401. package/plugins/maestro-skills/skills/draft-comms.md +84 -0
  402. package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
  403. package/plugins/maestro-skills/skills/files-find.md +65 -0
  404. package/plugins/maestro-skills/skills/generative-ui.md +228 -0
  405. package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
  406. package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
  407. package/plugins/maestro-skills/skills/mail-triage.md +86 -0
  408. package/plugins/maestro-skills/skills/morning-brief.md +54 -0
  409. package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
  410. package/plugins/maestro-skills/skills/org-board.md +133 -0
  411. package/plugins/maestro-skills/skills/org-credential.md +68 -0
  412. package/plugins/maestro-skills/skills/org-recall.md +81 -0
  413. package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
  414. package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
  415. package/plugins/maestro-skills/skills/router-why.md +78 -0
  416. package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
  417. package/plugins/maestro-skills/skills/session-search.md +71 -0
  418. package/plugins/maestro-skills/skills/set-reminder.md +93 -0
  419. package/plugins/maestro-skills/skills/slack-followup.md +64 -0
  420. package/plugins/maestro-skills/skills/team-activity.md +86 -0
  421. package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
  422. package/policies/action-classification.yaml +114 -0
  423. package/policies/ai-disclosure.yaml +294 -0
  424. package/policies/communication-style.md +139 -0
  425. package/policies/information-barriers.yaml +118 -0
  426. package/policies/prompt-injection-defence.yaml +138 -0
  427. package/public/assets/icon-dark.png +0 -0
  428. package/public/assets/icon-dark.svg +9 -0
  429. package/public/assets/icon-light.svg +9 -0
  430. package/public/assets/logo-dark.svg +15 -0
  431. package/public/assets/logo-light.svg +15 -0
  432. package/scaffold/.mcp.json +7 -0
  433. package/scaffold/CLAUDE.md +368 -0
  434. package/scaffold/config/agent.json +55 -0
  435. package/scaffold/config/agent.ts +76 -0
  436. package/scaffold/config/agent.ts.example +89 -0
  437. package/scaffold/config/alerts.yaml +23 -0
  438. package/scaffold/config/allowlist.yaml.example +25 -0
  439. package/scaffold/config/caller-id-map.yaml +46 -0
  440. package/scaffold/config/collective.yaml +49 -0
  441. package/scaffold/config/company.json +20 -0
  442. package/scaffold/config/known-agents.json +6 -0
  443. package/scaffold/config/learning.yaml +55 -0
  444. package/scaffold/config/model-routing.yaml.example +104 -0
  445. package/scaffold/config/org.yaml +25 -0
  446. package/scaffold/config/orgmail.yaml.example +19 -0
  447. package/scaffold/config/recovery.yaml +72 -0
  448. package/scaffold/config/secrets.yaml +27 -0
  449. package/scaffold/config/slack.yaml.example +35 -0
  450. package/scaffold/config/telegram.yaml.example +38 -0
  451. package/scaffold/config/voice.yaml.example +89 -0
  452. package/scaffold/config/whatsapp.yaml.example +39 -0
  453. package/schedules/README.md +49 -0
  454. package/schedules/triggers/backlog-executor.md +102 -0
  455. package/schedules/triggers/brand-steward.md +72 -0
  456. package/schedules/triggers/daily-evening-wrap.md +159 -0
  457. package/schedules/triggers/daily-midday-sweep.md +58 -0
  458. package/schedules/triggers/daily-morning-brief.md +55 -0
  459. package/schedules/triggers/directory-hygiene.md +81 -0
  460. package/schedules/triggers/dynamic-jobs.md +40 -0
  461. package/schedules/triggers/inbox-processor.md +115 -0
  462. package/schedules/triggers/meeting-action-capture.md +60 -0
  463. package/schedules/triggers/meeting-prep.md +69 -0
  464. package/schedules/triggers/messaging-inbound.md +50 -0
  465. package/schedules/triggers/org-pulse.md +24 -0
  466. package/schedules/triggers/quarterly-self-assessment.md +54 -0
  467. package/schedules/triggers/weekly-engineering-health.md +37 -0
  468. package/schedules/triggers/weekly-execution.md +65 -0
  469. package/schedules/triggers/weekly-hiring.md +53 -0
  470. package/schedules/triggers/weekly-priorities.md +38 -0
  471. package/schedules/triggers/weekly-strategic-memo.md +124 -0
  472. package/scripts/archive-email.sh +55 -0
  473. package/scripts/cadence/cadence-status.mjs +36 -0
  474. package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
  475. package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
  476. package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
  477. package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
  478. package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
  479. package/scripts/ci/check-docs-accuracy.mjs +493 -0
  480. package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
  481. package/scripts/ci/check-exports-exist.mjs +140 -0
  482. package/scripts/ci/check-files-exist.mjs +107 -0
  483. package/scripts/ci/check-no-build-artifacts.mjs +111 -0
  484. package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
  485. package/scripts/ci/check-no-confidential.mjs +198 -0
  486. package/scripts/ci/check-no-conflict-markers.mjs +169 -0
  487. package/scripts/ci/check-no-residual-identity.mjs +163 -0
  488. package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
  489. package/scripts/ci/check-tarball-fidelity.mjs +205 -0
  490. package/scripts/ci/check-unresolved-tokens.mjs +83 -0
  491. package/scripts/ci/check.mjs +109 -0
  492. package/scripts/ci/check.test.mjs +194 -0
  493. package/scripts/ci/run-coverage.mjs +82 -0
  494. package/scripts/ci/run-tests.mjs +71 -0
  495. package/scripts/cloud-relay/README.md +59 -0
  496. package/scripts/cloud-relay/index.mjs +233 -0
  497. package/scripts/cloud-relay/package.json +15 -0
  498. package/scripts/cloud-relay/railway.json +13 -0
  499. package/scripts/cloud-relay/voice/README.md +94 -0
  500. package/scripts/cloud-relay/voice/package-lock.json +39 -0
  501. package/scripts/cloud-relay/voice/package.json +16 -0
  502. package/scripts/cloud-relay/voice/railway.json +13 -0
  503. package/scripts/cloud-relay/voice/server.mjs +532 -0
  504. package/scripts/collective/hook-runner.mjs +211 -0
  505. package/scripts/collective/hook-runner.test.mjs +90 -0
  506. package/scripts/collective/org-pulse.mjs +72 -0
  507. package/scripts/collective/org-sync.mjs +61 -0
  508. package/scripts/collective/recall.mjs +45 -0
  509. package/scripts/collective/who.mjs +30 -0
  510. package/scripts/comms-monitor.sh +288 -0
  511. package/scripts/configure-whatsapp-sandbox.sh +201 -0
  512. package/scripts/continuous-monitor.sh +91 -0
  513. package/scripts/cost/fleet-digest.mjs +407 -0
  514. package/scripts/cost/fleet-digest.test.mjs +207 -0
  515. package/scripts/cost/track-claude-usage.mjs +169 -0
  516. package/scripts/daemon/agent-daemon.mjs +989 -0
  517. package/scripts/daemon/agent-daemon.test.mjs +525 -0
  518. package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
  519. package/scripts/daemon/cadence-consumer.mjs +1080 -0
  520. package/scripts/daemon/cadence-consumer.test.mjs +770 -0
  521. package/scripts/daemon/cadence-handlers.mjs +1121 -0
  522. package/scripts/daemon/cadence-handlers.test.mjs +617 -0
  523. package/scripts/daemon/classifier.mjs +704 -0
  524. package/scripts/daemon/classifier.test.mjs +238 -0
  525. package/scripts/daemon/classify-kind.mjs +54 -0
  526. package/scripts/daemon/classify-kind.test.mjs +40 -0
  527. package/scripts/daemon/context-compiler.mjs +605 -0
  528. package/scripts/daemon/context-compiler.test.mjs +300 -0
  529. package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
  530. package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
  531. package/scripts/daemon/dispatcher.mjs +1516 -0
  532. package/scripts/daemon/health.mjs +72 -0
  533. package/scripts/daemon/inbox-deferral.mjs +210 -0
  534. package/scripts/daemon/inbox-deferral.test.mjs +242 -0
  535. package/scripts/daemon/integration.test.mjs +149 -0
  536. package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
  537. package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
  538. package/scripts/daemon/launchd-wrapper.sh +91 -0
  539. package/scripts/daemon/lib/session-router.mjs +274 -0
  540. package/scripts/daemon/lib/session-router.test.mjs +295 -0
  541. package/scripts/daemon/maestro-daemon.mjs +275 -0
  542. package/scripts/daemon/prompt-builder.mjs +685 -0
  543. package/scripts/daemon/prompt-builder.test.mjs +213 -0
  544. package/scripts/daemon/responder.mjs +854 -0
  545. package/scripts/daemon/session-lock.mjs +721 -0
  546. package/scripts/daemon/session-lock.test.mjs +252 -0
  547. package/scripts/daemon/session-outcomes.mjs +640 -0
  548. package/scripts/daemon/session-outcomes.test.mjs +533 -0
  549. package/scripts/daemon/typing-registry.mjs +90 -0
  550. package/scripts/daemon/typing-registry.test.mjs +77 -0
  551. package/scripts/daemon/voice-webhook-server.mjs +804 -0
  552. package/scripts/decisions/capture-decision.mjs +116 -0
  553. package/scripts/disclosure_assessment.py +873 -0
  554. package/scripts/disclosure_boundaries.py +562 -0
  555. package/scripts/email-signature-principal.html +52 -0
  556. package/scripts/email-signature.html +60 -0
  557. package/scripts/email_quote_thread.py +167 -0
  558. package/scripts/email_thread_dedup.py +362 -0
  559. package/scripts/emergency-stop.sh +81 -0
  560. package/scripts/healthcheck.sh +116 -0
  561. package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
  562. package/scripts/hooks/block-mcp-slack-send.sh +7 -0
  563. package/scripts/hooks/post-action-log.sh +126 -0
  564. package/scripts/hooks/pre-send-audit.sh +174 -0
  565. package/scripts/hooks/pre-send-audit.test.mjs +215 -0
  566. package/scripts/hooks/session-end-log.sh +27 -0
  567. package/scripts/hooks/session-start-banner.sh +115 -0
  568. package/scripts/huddle/audio-bridge.mjs +664 -0
  569. package/scripts/huddle/boot-slack-cdp.sh +102 -0
  570. package/scripts/huddle/huddle-controller.mjs +942 -0
  571. package/scripts/huddle/huddle-server.mjs +1229 -0
  572. package/scripts/huddle/launch-slack.sh +232 -0
  573. package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
  574. package/scripts/huddle/package-lock.json +62 -0
  575. package/scripts/huddle/package.json +22 -0
  576. package/scripts/huddle/setup-audio.sh +239 -0
  577. package/scripts/huddle/start-call.mjs +318 -0
  578. package/scripts/huddle/test-pipeline.mjs +263 -0
  579. package/scripts/learning/consolidate-skills.mjs +72 -0
  580. package/scripts/learning/session-search.mjs +125 -0
  581. package/scripts/llm_email_dedup.py +442 -0
  582. package/scripts/local-triggers/generate-plists.sh +432 -0
  583. package/scripts/local-triggers/generate-plists.test.mjs +413 -0
  584. package/scripts/local-triggers/install-all.sh +49 -0
  585. package/scripts/local-triggers/plists/.gitkeep +0 -0
  586. package/scripts/local-triggers/run-trigger.sh +63 -0
  587. package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
  588. package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
  589. package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
  590. package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
  591. package/scripts/maintenance/backup-to-cloud.sh +124 -0
  592. package/scripts/maintenance/health-check.sh +377 -0
  593. package/scripts/media-generation/README.md +105 -0
  594. package/scripts/media-generation/gemini-image-client.mjs +173 -0
  595. package/scripts/media-generation/generate-assets.mjs +289 -0
  596. package/scripts/media-generation/veo-video-client.mjs +219 -0
  597. package/scripts/org/send-orgmail.mjs +227 -0
  598. package/scripts/outbound-dedup-cleanup.sh +43 -0
  599. package/scripts/outbound-dedup.sh +477 -0
  600. package/scripts/outbound_dedup.py +115 -0
  601. package/scripts/parse-voice-transcript.mjs +481 -0
  602. package/scripts/pdf-generation/README.md +63 -0
  603. package/scripts/pdf-generation/build-document.mjs +247 -0
  604. package/scripts/pdf-generation/templates/board-pack.latex +136 -0
  605. package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
  606. package/scripts/pdf-generation/templates/memo.latex +114 -0
  607. package/scripts/poll-slack-events.sh +35 -0
  608. package/scripts/poller/calendar-poller.mjs +12 -0
  609. package/scripts/poller/gmail-poller.mjs +192 -0
  610. package/scripts/poller/imap-client.mjs +289 -0
  611. package/scripts/poller/inbox-scan-poller.mjs +156 -0
  612. package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
  613. package/scripts/poller/index.mjs +73 -0
  614. package/scripts/poller/intra-session-check.mjs +285 -0
  615. package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
  616. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
  617. package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
  618. package/scripts/poller/secondary-gmail-poller.mjs +132 -0
  619. package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
  620. package/scripts/poller/slack-poller.mjs +854 -0
  621. package/scripts/poller/slack-socket-mode.mjs +917 -0
  622. package/scripts/poller/slack-socket-mode.test.mjs +753 -0
  623. package/scripts/poller/trigger.mjs +75 -0
  624. package/scripts/poller/utils.mjs +371 -0
  625. package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
  626. package/scripts/poller/voice-poller.mjs +236 -0
  627. package/scripts/poller-launchd/install.sh +66 -0
  628. package/scripts/poller-launchd/poller.plist.template +40 -0
  629. package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
  630. package/scripts/post-interaction-indexer.py +1598 -0
  631. package/scripts/pre-draft-context.py +994 -0
  632. package/scripts/pre_draft_lookup.py +258 -0
  633. package/scripts/rag/build-index.mjs +47 -0
  634. package/scripts/rag/ingest.mjs +111 -0
  635. package/scripts/rag/search.mjs +119 -0
  636. package/scripts/rag-indexer.py +629 -0
  637. package/scripts/restore-from-backup.sh +248 -0
  638. package/scripts/restore-from-backup.test.mjs +178 -0
  639. package/scripts/resume-operations.sh +80 -0
  640. package/scripts/search-secondary-inbox.py +181 -0
  641. package/scripts/secondary-inbox-poller.py +437 -0
  642. package/scripts/self-optimization/compute-metrics.py +398 -0
  643. package/scripts/send-email-as-principal.py +369 -0
  644. package/scripts/send-email-threaded.py +392 -0
  645. package/scripts/send-email-with-attachment.py +377 -0
  646. package/scripts/send-email.sh +131 -0
  647. package/scripts/send-sms.sh +175 -0
  648. package/scripts/send-whatsapp.sh +292 -0
  649. package/scripts/session-start.sh +106 -0
  650. package/scripts/setup/boot-claude-session.sh +94 -0
  651. package/scripts/setup/configure-macos.sh +674 -0
  652. package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
  653. package/scripts/setup/configure-voice-tunnel.mjs +182 -0
  654. package/scripts/setup/generate-agent-env.mjs +92 -0
  655. package/scripts/setup/generate-agent-package-json.mjs +222 -0
  656. package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
  657. package/scripts/setup/generate-autonomy.mjs +60 -0
  658. package/scripts/setup/generate-backlog.mjs +101 -0
  659. package/scripts/setup/generate-cadences.mjs +92 -0
  660. package/scripts/setup/generate-capability.mjs +162 -0
  661. package/scripts/setup/generate-charter.mjs +76 -0
  662. package/scripts/setup/generate-comms.mjs +59 -0
  663. package/scripts/setup/generate-company.mjs +92 -0
  664. package/scripts/setup/init-agent.sh +547 -0
  665. package/scripts/setup/init-agent.test.mjs +151 -0
  666. package/scripts/setup/init-archetype.mjs +74 -0
  667. package/scripts/setup/init-backup.mjs +54 -0
  668. package/scripts/setup/init-cadence-bus.mjs +60 -0
  669. package/scripts/setup/init-channel-bus.mjs +46 -0
  670. package/scripts/setup/init-cost-tracking.mjs +45 -0
  671. package/scripts/setup/init-decision-capture.mjs +66 -0
  672. package/scripts/setup/init-known-agents.mjs +57 -0
  673. package/scripts/setup/init-learning.mjs +70 -0
  674. package/scripts/setup/init-memory-executive.mjs +45 -0
  675. package/scripts/setup/init-model-router.mjs +124 -0
  676. package/scripts/setup/init-rag.mjs +174 -0
  677. package/scripts/setup/init-session-router.mjs +38 -0
  678. package/scripts/setup/init-slack-socket-mode.mjs +260 -0
  679. package/scripts/setup/init-telegram.mjs +165 -0
  680. package/scripts/setup/init-voice-realtime.mjs +204 -0
  681. package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
  682. package/scripts/setup/install-dev-tools.sh +150 -0
  683. package/scripts/setup/lib/install-plist.mjs +95 -0
  684. package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
  685. package/scripts/setup/render-environment-yaml.mjs +133 -0
  686. package/scripts/slack-events-ctl.sh +177 -0
  687. package/scripts/slack-events-server.mjs +1045 -0
  688. package/scripts/slack-react.mjs +89 -0
  689. package/scripts/slack-responded.sh +232 -0
  690. package/scripts/slack-send.sh +287 -0
  691. package/scripts/slack-typing.mjs +196 -0
  692. package/scripts/slack-upload-v2.py +95 -0
  693. package/scripts/sms-handler.mjs +450 -0
  694. package/scripts/spawn-session.sh +120 -0
  695. package/scripts/sync-protocol.mjs +217 -0
  696. package/scripts/system-verify.sh +184 -0
  697. package/scripts/test-email-thread-dedup.py +239 -0
  698. package/scripts/test-information-barriers.py +484 -0
  699. package/scripts/test-llm-email-dedup.py +251 -0
  700. package/scripts/test-pre-draft-integration.py +203 -0
  701. package/scripts/test-rag-phase2.sh +442 -0
  702. package/scripts/test-rag-search.sh +251 -0
  703. package/scripts/test-voice-parser.mjs +316 -0
  704. package/scripts/user-context-search.py +659 -0
  705. package/scripts/validate_outbound.py +1504 -0
  706. package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
  707. package/scripts/watchdog/force-reboot.sh +157 -0
  708. package/scripts/watchdog/memory-watchdog.sh +473 -0
  709. package/scripts/whatsapp-handler.mjs +538 -0
  710. package/teams/desktop-operations.yaml +34 -0
  711. package/teams/executive-office.yaml +27 -0
  712. package/teams/legal-and-regulatory.yaml +24 -0
  713. package/teams/platform-and-engineering.yaml +23 -0
  714. package/teams/strategy-and-growth.yaml +29 -0
  715. package/workflows/continuous/backlog-executor.yaml +141 -0
  716. package/workflows/continuous/inbound-monitor.yaml +168 -0
  717. package/workflows/daily/applicant-triage.yaml +197 -0
  718. package/workflows/daily/comms-triage.yaml +80 -0
  719. package/workflows/daily/evening-wrap.yaml +105 -0
  720. package/workflows/daily/morning-brief.yaml +164 -0
  721. package/workflows/daily/slack-followup-sweep.yaml +87 -0
  722. package/workflows/event-driven/README.md +50 -0
  723. package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
  724. package/workflows/event-driven/pr-review.yaml +107 -0
  725. package/workflows/monthly/board-readiness.yaml +76 -0
  726. package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
  727. package/workflows/session-protocol.md +171 -0
  728. package/workflows/weekly/engineering-health.yaml +154 -0
  729. package/workflows/weekly/hiring-review.yaml +169 -0
  730. package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
  731. package/workflows/weekly/strategic-memo.yaml +79 -0
@@ -0,0 +1,592 @@
1
+ /**
2
+ * lib/security/redact.mjs
3
+ *
4
+ * URL / secret REDACTION and private-IP classification.
5
+ *
6
+ * Ported from OpenClaw's net-policy package
7
+ * (redact-sensitive-url.ts, url-userinfo.ts, ip.ts) and adapted to maestro
8
+ * conventions: pure ESM, JSDoc instead of TypeScript types, zero third-party
9
+ * dependencies (node:url + node:net only). All functions are pure and
10
+ * side-effect free.
11
+ *
12
+ * Two concerns live here:
13
+ * 1. redactSensitiveUrl(url) — make a URL safe to log/echo by stripping
14
+ * embedded credentials (user:pass@) and masking sensitive query params.
15
+ * 2. isPrivateOrReservedIp(host) — classify a host as a private / loopback /
16
+ * link-local / reserved address. Used for SSRF-style guardrails; it must
17
+ * not be foolable by IPv4-mapped-IPv6 representations (e.g. ::ffff:10.0.0.1)
18
+ * that would otherwise bypass a naive IPv4-only check.
19
+ *
20
+ * Faithful to OpenClaw behaviour: malformed input never throws — callers get a
21
+ * best-effort redaction (or a conservative classification) instead of an
22
+ * exception, because this code runs on the logging / security path.
23
+ */
24
+
25
+ import { isIP } from "node:net";
26
+
27
+ /**
28
+ * Mask value placeholder used in place of a redacted secret.
29
+ * @type {string}
30
+ */
31
+ export const REDACTED = "***";
32
+
33
+ /**
34
+ * Query-parameter names whose values are treated as secrets and masked.
35
+ * Matching is case-insensitive and substring-based so e.g. `apiKey`,
36
+ * `access_token`, `client_secret`, `X-Api-Key` all match.
37
+ * @type {readonly string[]}
38
+ */
39
+ export const SENSITIVE_PARAM_KEYS = Object.freeze([
40
+ "token",
41
+ "key",
42
+ "secret",
43
+ "password",
44
+ "passwd",
45
+ "pwd",
46
+ "apikey",
47
+ "api_key",
48
+ "auth",
49
+ "access_token",
50
+ "refresh_token",
51
+ "sig",
52
+ "signature",
53
+ "credential",
54
+ ]);
55
+
56
+ /**
57
+ * True if a query-parameter name looks sensitive (case-insensitive substring
58
+ * match against {@link SENSITIVE_PARAM_KEYS}).
59
+ *
60
+ * @param {string} name - The parameter name.
61
+ * @returns {boolean}
62
+ */
63
+ export function isSensitiveParamName(name) {
64
+ if (typeof name !== "string" || name.length === 0) return false;
65
+ const lower = name.toLowerCase();
66
+ for (const needle of SENSITIVE_PARAM_KEYS) {
67
+ if (lower.includes(needle)) return true;
68
+ }
69
+ return false;
70
+ }
71
+
72
+ /**
73
+ * Strip the `user:password@` userinfo component from a parsed URL in place,
74
+ * returning whether anything was removed. Mirrors OpenClaw's url-userinfo
75
+ * helper: both username and password are cleared so neither leaks.
76
+ *
77
+ * @param {URL} u - A parsed WHATWG URL (mutated).
78
+ * @returns {boolean} True if userinfo was present and removed.
79
+ */
80
+ function stripUserinfo(u) {
81
+ const had = u.username !== "" || u.password !== "";
82
+ if (had) {
83
+ u.username = "";
84
+ u.password = "";
85
+ }
86
+ return had;
87
+ }
88
+
89
+ /**
90
+ * Best-effort regex fallback for inputs the WHATWG URL parser rejects.
91
+ * Removes a `scheme://user:pass@` style userinfo segment and masks obvious
92
+ * `key=value` secret pairs in the query string. Never throws.
93
+ *
94
+ * @param {string} url
95
+ * @returns {string}
96
+ */
97
+ function redactWithRegex(url) {
98
+ let out = url;
99
+
100
+ // Strip userinfo: matches `://something@` where `something` has no slash.
101
+ // Keeps the scheme and the host that follows the `@`.
102
+ out = out.replace(/(\/\/)[^/@\s]+@/g, "$1");
103
+
104
+ // Mask sensitive query/fragment params of the form key=value. The leading
105
+ // delimiter is `?`, `&`, `#`, or start-of-string (so a bare `token=...`
106
+ // query fragment with no preceding `?` is still caught — slightly hardened
107
+ // vs. OpenClaw's redactSensitiveUrlLikeString, which only matched `[?&]`).
108
+ out = out.replace(
109
+ /(^|[?&#])([^=&#\s]+)=([^&#\s]*)/g,
110
+ (match, sep, rawName, _value) => {
111
+ let name = rawName;
112
+ try {
113
+ name = decodeURIComponent(rawName);
114
+ } catch {
115
+ // keep raw name if it is not valid percent-encoding
116
+ }
117
+ return isSensitiveParamName(name)
118
+ ? `${sep}${rawName}=${REDACTED}`
119
+ : match;
120
+ }
121
+ );
122
+
123
+ return out;
124
+ }
125
+
126
+ /**
127
+ * Return a copy of `url` that is safe to log: any embedded `user:pass@`
128
+ * credentials are removed and any sensitive query-parameter values
129
+ * (token / key / secret / password / apikey / etc.) are replaced with `***`.
130
+ *
131
+ * Benign URLs are returned effectively unchanged (the WHATWG parser may
132
+ * normalise trailing details, but no information is added or masked).
133
+ *
134
+ * Never throws — malformed URLs fall back to a regex-based redaction.
135
+ *
136
+ * @param {string} url - The URL to redact.
137
+ * @returns {string} The redacted URL, or the input coerced to string on total
138
+ * failure.
139
+ */
140
+ export function redactSensitiveUrl(url) {
141
+ if (typeof url !== "string") {
142
+ if (url === null || url === undefined) return "";
143
+ url = String(url);
144
+ }
145
+ if (url.length === 0) return url;
146
+
147
+ let u;
148
+ try {
149
+ u = new URL(url);
150
+ } catch {
151
+ return redactWithRegex(url);
152
+ }
153
+
154
+ stripUserinfo(u);
155
+
156
+ // Mask sensitive query params. Iterate over a snapshot of keys because we
157
+ // mutate searchParams while walking it.
158
+ const keys = [...u.searchParams.keys()];
159
+ for (const key of keys) {
160
+ if (isSensitiveParamName(key)) {
161
+ // set() collapses repeated keys to one; rebuild to preserve multiplicity.
162
+ const values = u.searchParams.getAll(key);
163
+ u.searchParams.delete(key);
164
+ for (let i = 0; i < values.length; i++) {
165
+ u.searchParams.append(key, REDACTED);
166
+ }
167
+ }
168
+ }
169
+
170
+ return u.toString();
171
+ }
172
+
173
+ /* ------------------------------------------------------------------------- *
174
+ * Free-text PII / secret masking
175
+ *
176
+ * `maskText` is the general masker the URL/param redactor above is NOT: it walks
177
+ * arbitrary free text (LLM prompts on non-Anthropic routes, log lines, message
178
+ * bodies) and replaces things that look like secrets or PII with a typed
179
+ * placeholder, returning both the cleaned string and a count of substitutions.
180
+ *
181
+ * Design notes (mirrors the Hermes/OpenClaw pattern corpus referenced in
182
+ * gaps-enterprise-ops G19):
183
+ * - High-signal, low-false-positive patterns only. We mask things with a
184
+ * distinctive shape (vendor key prefixes, bearer tokens, email/phone) plus
185
+ * long high-entropy hex/base64 runs; we deliberately do NOT mask ordinary
186
+ * words, numbers, or short identifiers.
187
+ * - Ordering matters: the most specific / longest patterns run first so a
188
+ * bearer token isn't half-eaten by the generic-secret pass, and an email's
189
+ * local part isn't mistaken for a key.
190
+ * - Bounded: every replacement is a fixed-width placeholder, so masked output
191
+ * can never be longer than a small multiple of the input.
192
+ * - Never throws. A masker that crashes on the logging path is worse than one
193
+ * that lets a borderline token through, so all input is coerced and any
194
+ * internal failure falls back to returning the (coerced) input unchanged.
195
+ * ------------------------------------------------------------------------- */
196
+
197
+ /**
198
+ * Ordered masking rules. Each `re` is a global regex; matched spans are replaced
199
+ * by `{label}` and counted. Order is significant — see the note above.
200
+ *
201
+ * @type {ReadonlyArray<{label:string, re:RegExp}>}
202
+ */
203
+ const MASK_RULES = Object.freeze([
204
+ // Anthropic keys: sk-ant-... (must precede the generic sk- rule).
205
+ { label: "ANTHROPIC_KEY", re: /\bsk-ant-[A-Za-z0-9_-]{8,}/g },
206
+ // OpenAI-style project / legacy keys: sk-... and sk-proj-...
207
+ { label: "API_KEY", re: /\bsk-(?:proj-)?[A-Za-z0-9_-]{16,}/g },
208
+ // AWS access key id: AKIA / ASIA + 16 uppercase-alphanumerics.
209
+ { label: "AWS_KEY", re: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
210
+ // GitHub tokens: ghp_/gho_/ghu_/ghs_/ghr_ + 36+ chars; fine-grained github_pat_.
211
+ { label: "GITHUB_TOKEN", re: /\b(?:gh[pousr]_[A-Za-z0-9]{36,}|github_pat_[A-Za-z0-9_]{22,})\b/g },
212
+ // Slack tokens: xoxb-/xoxp-/xoxa-/xoxr-...
213
+ { label: "SLACK_TOKEN", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}/g },
214
+ // Google API keys: AIza + 35 chars.
215
+ { label: "GOOGLE_KEY", re: /\bAIza[0-9A-Za-z_-]{35}\b/g },
216
+ // Bearer / Basic auth tokens in an Authorization-style position.
217
+ { label: "BEARER_TOKEN", re: /\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]{8,}/gi },
218
+ // JWTs: three dot-separated base64url segments, first starts with eyJ.
219
+ { label: "JWT", re: /\beyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\b/g },
220
+ // Private-key PEM blocks.
221
+ { label: "PRIVATE_KEY", re: /-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z ]+ )?PRIVATE KEY-----/g },
222
+ // Email addresses.
223
+ { label: "EMAIL", re: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g },
224
+ // E.164-ish / common phone numbers: optional +, 10–15 digits with separators.
225
+ { label: "PHONE", re: /(?<![\w.])\+?\d[\d\s().-]{8,16}\d(?![\w.])/g },
226
+ // Long hex secrets (32+ hex chars) — token/session/hash material.
227
+ { label: "HEX_SECRET", re: /\b[0-9a-fA-F]{32,}\b/g },
228
+ // Long high-entropy base64/base64url runs (40+ chars) — generic secrets.
229
+ { label: "B64_SECRET", re: /\b[A-Za-z0-9+/_-]{40,}={0,2}\b/g },
230
+ ]);
231
+
232
+ /**
233
+ * Mask PII and secret-shaped tokens in free text.
234
+ *
235
+ * Replaces each recognized span (vendor API keys, bearer/JWT tokens, PEM private
236
+ * keys, emails, phone numbers, long hex/base64 secrets) with a typed placeholder
237
+ * like `[REDACTED:EMAIL]` and reports how many substitutions were made. Benign
238
+ * text — ordinary words, short numbers, identifiers — is returned untouched.
239
+ *
240
+ * Never throws: non-string input is coerced; on any internal failure the coerced
241
+ * input is returned with `count: 0`. Suitable for the logging / model-router
242
+ * path where a crash is unacceptable.
243
+ *
244
+ * @param {string} text - The text to mask.
245
+ * @param {object} [opts]
246
+ * @param {(label:string)=>string} [opts.placeholder] - Custom placeholder
247
+ * factory; defaults to ``[REDACTED:${label}]``.
248
+ * @returns {{text:string, count:number}} The masked text and substitution count.
249
+ */
250
+ export function maskText(text, opts = {}) {
251
+ if (typeof text !== "string") {
252
+ if (text === null || text === undefined) return { text: "", count: 0 };
253
+ text = String(text);
254
+ }
255
+ if (text.length === 0) return { text, count: 0 };
256
+
257
+ const placeholder =
258
+ opts && typeof opts.placeholder === "function"
259
+ ? opts.placeholder
260
+ : (label) => `[${REDACTED_LABEL_PREFIX}${label}]`;
261
+
262
+ let out = text;
263
+ let count = 0;
264
+ try {
265
+ for (const { label, re } of MASK_RULES) {
266
+ // Fresh lastIndex per pass (global regexes are stateful).
267
+ re.lastIndex = 0;
268
+ out = out.replace(re, (match) => {
269
+ count += 1;
270
+ return placeholder(label);
271
+ });
272
+ }
273
+ } catch {
274
+ // Fail-open: never let masking crash the caller.
275
+ return { text, count: 0 };
276
+ }
277
+ return { text: out, count };
278
+ }
279
+
280
+ /**
281
+ * Placeholder prefix for {@link maskText}. Kept distinct from {@link REDACTED}
282
+ * (the URL/param mask placeholder) so the two redaction concerns don't collide.
283
+ * @type {string}
284
+ */
285
+ export const REDACTED_LABEL_PREFIX = "REDACTED:";
286
+
287
+ /**
288
+ * Convenience: mask free text and return only the cleaned string. Drop-in for
289
+ * an `(input:string)=>string` masker hook (e.g. `llmTask`'s `opts.maskInput`).
290
+ *
291
+ * @param {string} text
292
+ * @param {object} [opts] - Forwarded to {@link maskText}.
293
+ * @returns {string}
294
+ */
295
+ export function maskTextString(text, opts = {}) {
296
+ return maskText(text, opts).text;
297
+ }
298
+
299
+ /**
300
+ * Deep-mask an arbitrary value, applying {@link maskText} to every string found
301
+ * (object values, array elements, nested structures). Returns a new value of the
302
+ * same shape with the total substitution count; the input is never mutated.
303
+ *
304
+ * Strings are masked; numbers / booleans / null / undefined pass through; keys
305
+ * are NOT masked (only values) so structure stays inspectable. Cycles are
306
+ * handled (a revisited reference is left as-is). Never throws.
307
+ *
308
+ * @param {*} obj - The value to deep-mask.
309
+ * @param {object} [opts] - Forwarded to {@link maskText}.
310
+ * @returns {{value:*, count:number}}
311
+ */
312
+ export function redactObject(obj, opts = {}) {
313
+ let count = 0;
314
+ const seen = new WeakSet();
315
+
316
+ const walk = (value) => {
317
+ if (typeof value === "string") {
318
+ const r = maskText(value, opts);
319
+ count += r.count;
320
+ return r.text;
321
+ }
322
+ if (value === null || typeof value !== "object") return value;
323
+
324
+ if (seen.has(value)) return value; // cycle guard
325
+ seen.add(value);
326
+
327
+ if (Array.isArray(value)) {
328
+ return value.map((v) => walk(v));
329
+ }
330
+ // Plain object: walk own enumerable values, preserve keys verbatim.
331
+ const out = {};
332
+ for (const key of Object.keys(value)) {
333
+ out[key] = walk(value[key]);
334
+ }
335
+ return out;
336
+ };
337
+
338
+ try {
339
+ const value = walk(obj);
340
+ return { value, count };
341
+ } catch {
342
+ return { value: obj, count };
343
+ }
344
+ }
345
+
346
+ /* ------------------------------------------------------------------------- *
347
+ * IP classification
348
+ * ------------------------------------------------------------------------- */
349
+
350
+ /**
351
+ * Parse a dotted-quad IPv4 string into its four octets.
352
+ *
353
+ * @param {string} ip
354
+ * @returns {number[] | null} `[a,b,c,d]` or null if not a valid IPv4 literal.
355
+ */
356
+ function parseIPv4(ip) {
357
+ if (isIP(ip) !== 4) return null;
358
+ const parts = ip.split(".");
359
+ if (parts.length !== 4) return null;
360
+ const octets = parts.map((p) => Number(p));
361
+ for (const o of octets) {
362
+ if (!Number.isInteger(o) || o < 0 || o > 255) return null;
363
+ }
364
+ return octets;
365
+ }
366
+
367
+ /**
368
+ * Classify an IPv4 address (given as octets) as private / loopback /
369
+ * link-local / reserved / unspecified / broadcast.
370
+ *
371
+ * Covers, per RFC 1918 / 3927 / 5735 / 6598 / 5771 etc.:
372
+ * 0.0.0.0/8 unspecified / "this network"
373
+ * 10.0.0.0/8 private
374
+ * 100.64.0.0/10 CGNAT shared address space
375
+ * 127.0.0.0/8 loopback
376
+ * 169.254.0.0/16 link-local
377
+ * 172.16.0.0/12 private
378
+ * 192.0.0.0/24 IETF protocol assignments
379
+ * 192.0.2.0/24 TEST-NET-1 (documentation)
380
+ * 192.168.0.0/16 private
381
+ * 198.18.0.0/15 benchmarking
382
+ * 198.51.100.0/24 TEST-NET-2
383
+ * 203.0.113.0/24 TEST-NET-3
384
+ * 224.0.0.0/4 multicast (reserved for our purposes)
385
+ * 240.0.0.0/4 reserved (incl. 255.255.255.255 broadcast)
386
+ *
387
+ * @param {number[]} o - Four octets.
388
+ * @returns {boolean}
389
+ */
390
+ function isPrivateOrReservedIPv4(o) {
391
+ const [a, b] = o;
392
+
393
+ if (a === 0) return true; // 0.0.0.0/8
394
+ if (a === 10) return true; // 10.0.0.0/8
395
+ if (a === 127) return true; // 127.0.0.0/8 loopback
396
+ if (a === 169 && b === 254) return true; // 169.254.0.0/16 link-local
397
+ if (a === 172 && b >= 16 && b <= 31) return true; // 172.16.0.0/12
398
+ if (a === 192 && b === 168) return true; // 192.168.0.0/16
399
+ if (a === 100 && b >= 64 && b <= 127) return true; // 100.64.0.0/10 CGNAT
400
+ if (a === 192 && b === 0 && o[2] === 0) return true; // 192.0.0.0/24
401
+ if (a === 192 && b === 0 && o[2] === 2) return true; // 192.0.2.0/24 TEST-NET-1
402
+ if (a === 198 && (b === 18 || b === 19)) return true; // 198.18.0.0/15 bench
403
+ if (a === 198 && b === 51 && o[2] === 100) return true; // 198.51.100.0/24
404
+ if (a === 203 && b === 0 && o[2] === 113) return true; // 203.0.113.0/24
405
+ if (a >= 224 && a <= 239) return true; // 224.0.0.0/4 multicast
406
+ if (a >= 240) return true; // 240.0.0.0/4 reserved + broadcast
407
+
408
+ return false;
409
+ }
410
+
411
+ /**
412
+ * Expand an IPv6 literal into an array of 8 16-bit groups (numbers).
413
+ * Handles `::` zero-compression and trailing IPv4-dotted form
414
+ * (e.g. `::ffff:10.0.0.1`). Returns null on anything invalid.
415
+ *
416
+ * @param {string} ip
417
+ * @returns {number[] | null} Eight 16-bit groups, or null.
418
+ */
419
+ function parseIPv6Groups(ip) {
420
+ if (isIP(ip) !== 6) return null;
421
+
422
+ // Strip a zone id (%eth0) if present — irrelevant to classification.
423
+ const pct = ip.indexOf("%");
424
+ if (pct !== -1) ip = ip.slice(0, pct);
425
+
426
+ let head = ip;
427
+ let tailV4Groups = [];
428
+
429
+ // Embedded IPv4 (last 32 bits written in dotted-quad form).
430
+ const lastColon = head.lastIndexOf(":");
431
+ const maybeV4 = lastColon === -1 ? "" : head.slice(lastColon + 1);
432
+ if (maybeV4.includes(".")) {
433
+ const v4 = parseIPv4(maybeV4);
434
+ if (!v4) return null;
435
+ tailV4Groups = [(v4[0] << 8) | v4[1], (v4[2] << 8) | v4[3]];
436
+ head = head.slice(0, lastColon + 1); // keep trailing ':' for splitting
437
+ // remove the now-dangling segment after the colon
438
+ head = head.slice(0, -1);
439
+ }
440
+
441
+ const doubleColon = head.indexOf("::");
442
+ /** @type {string[]} */
443
+ let leftParts = [];
444
+ /** @type {string[]} */
445
+ let rightParts = [];
446
+
447
+ if (doubleColon !== -1) {
448
+ const left = head.slice(0, doubleColon);
449
+ const right = head.slice(doubleColon + 2);
450
+ leftParts = left.length ? left.split(":") : [];
451
+ rightParts = right.length ? right.split(":") : [];
452
+ } else {
453
+ leftParts = head.length ? head.split(":") : [];
454
+ }
455
+
456
+ /** @type {number[]} */
457
+ const leftGroups = leftParts.map((h) => parseInt(h, 16));
458
+ /** @type {number[]} */
459
+ const rightGroups = rightParts.map((h) => parseInt(h, 16));
460
+
461
+ for (const g of leftGroups) if (!Number.isInteger(g) || g < 0 || g > 0xffff) return null;
462
+ for (const g of rightGroups) if (!Number.isInteger(g) || g < 0 || g > 0xffff) return null;
463
+
464
+ const totalKnown = leftGroups.length + rightGroups.length + tailV4Groups.length;
465
+ if (doubleColon === -1) {
466
+ if (totalKnown !== 8) return null;
467
+ return [...leftGroups, ...tailV4Groups];
468
+ }
469
+
470
+ const fill = 8 - totalKnown;
471
+ if (fill < 0) return null;
472
+ return [
473
+ ...leftGroups,
474
+ ...new Array(fill).fill(0),
475
+ ...rightGroups,
476
+ ...tailV4Groups,
477
+ ];
478
+ }
479
+
480
+ /**
481
+ * Classify an IPv6 address (given as 8 groups) as private / loopback /
482
+ * link-local / reserved.
483
+ *
484
+ * Covers:
485
+ * :: unspecified
486
+ * ::1 loopback
487
+ * ::ffff:0:0/96 IPv4-mapped → delegated to the embedded IPv4 check
488
+ * ::/96 (deprecated IPv4-compatible) → embedded IPv4 check
489
+ * 64:ff9b::/96 NAT64 → embedded IPv4 check
490
+ * fc00::/7 unique local (ULA)
491
+ * fe80::/10 link-local
492
+ * fec0::/10 site-local (deprecated, reserved)
493
+ * ff00::/8 multicast
494
+ *
495
+ * @param {number[]} g - Eight 16-bit groups.
496
+ * @returns {boolean}
497
+ */
498
+ function isPrivateOrReservedIPv6(g) {
499
+ // Unspecified ::
500
+ if (g.every((x) => x === 0)) return true;
501
+ // Loopback ::1
502
+ if (g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0 && g[6] === 0 && g[7] === 1) {
503
+ return true;
504
+ }
505
+
506
+ const firstSixZero = g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0;
507
+
508
+ // IPv4-mapped ::ffff:a.b.c.d → classify by the embedded IPv4.
509
+ if (firstSixZero && g[5] === 0xffff) {
510
+ return isPrivateOrReservedIPv4(groupsToV4Octets(g[6], g[7]));
511
+ }
512
+ // IPv4-compatible ::a.b.c.d (deprecated) — also bypass-prone; check embedded.
513
+ if (g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0 && !(g[6] === 0 && g[7] === 0) && !(g[6] === 0 && g[7] === 1)) {
514
+ return isPrivateOrReservedIPv4(groupsToV4Octets(g[6], g[7]));
515
+ }
516
+ // NAT64 64:ff9b::/96 — embeds an IPv4; classify by it.
517
+ if (g[0] === 0x64 && g[1] === 0xff9b && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) {
518
+ return isPrivateOrReservedIPv4(groupsToV4Octets(g[6], g[7]));
519
+ }
520
+
521
+ const first = g[0];
522
+ if ((first & 0xfe00) === 0xfc00) return true; // fc00::/7 ULA
523
+ if ((first & 0xffc0) === 0xfe80) return true; // fe80::/10 link-local
524
+ if ((first & 0xffc0) === 0xfec0) return true; // fec0::/10 site-local
525
+ if ((first & 0xff00) === 0xff00) return true; // ff00::/8 multicast
526
+
527
+ return false;
528
+ }
529
+
530
+ /**
531
+ * Convert two 16-bit groups into four IPv4 octets.
532
+ *
533
+ * @param {number} hi
534
+ * @param {number} lo
535
+ * @returns {number[]}
536
+ */
537
+ function groupsToV4Octets(hi, lo) {
538
+ return [(hi >> 8) & 0xff, hi & 0xff, (lo >> 8) & 0xff, lo & 0xff];
539
+ }
540
+
541
+ /**
542
+ * True if `host` is a private, loopback, link-local, or otherwise
543
+ * reserved/non-routable IP address.
544
+ *
545
+ * Accepts IPv4 and IPv6 literals, with or without surrounding brackets
546
+ * (`[::1]`) and with an optional IPv6 zone id (`fe80::1%eth0`). Crucially it is
547
+ * NOT fooled by IPv4-mapped-IPv6 forms such as `::ffff:10.0.0.1` or
548
+ * `::ffff:127.0.0.1`, which embed a private/loopback IPv4 inside an IPv6
549
+ * literal — those return true.
550
+ *
551
+ * Hostnames (anything that is not a valid IP literal) return false: this
552
+ * function classifies addresses, not names. Resolve names to addresses first
553
+ * if you need to guard against DNS-based bypasses. Never throws.
554
+ *
555
+ * @param {string} host - An IP literal (IPv4 or IPv6), optionally bracketed.
556
+ * @returns {boolean}
557
+ */
558
+ export function isPrivateOrReservedIp(host) {
559
+ if (typeof host !== "string") return false;
560
+
561
+ let h = host.trim();
562
+ if (h.length === 0) return false;
563
+
564
+ // Strip surrounding brackets used for IPv6 in URLs: [::1] -> ::1
565
+ if (h.startsWith("[") && h.endsWith("]")) {
566
+ h = h.slice(1, -1);
567
+ }
568
+
569
+ const kind = isIP(h);
570
+ if (kind === 4) {
571
+ const o = parseIPv4(h);
572
+ return o ? isPrivateOrReservedIPv4(o) : false;
573
+ }
574
+ if (kind === 6) {
575
+ const g = parseIPv6Groups(h);
576
+ return g ? isPrivateOrReservedIPv6(g) : false;
577
+ }
578
+
579
+ return false; // not an IP literal
580
+ }
581
+
582
+ export default {
583
+ REDACTED,
584
+ SENSITIVE_PARAM_KEYS,
585
+ isSensitiveParamName,
586
+ redactSensitiveUrl,
587
+ isPrivateOrReservedIp,
588
+ REDACTED_LABEL_PREFIX,
589
+ maskText,
590
+ maskTextString,
591
+ redactObject,
592
+ };