@wrongstack/core 0.309.0 → 0.310.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 (129) hide show
  1. package/dist/chronicle/index.js +113 -41
  2. package/dist/chronicle/metrics-ingest.d.ts +7 -0
  3. package/dist/chronicle/metrics-schema.d.ts +4 -1
  4. package/dist/chronicle/project-server.js +94 -38
  5. package/dist/chronicle/query.d.ts +1 -0
  6. package/dist/chronicle/sqlite-journal-schema.d.ts +2 -1
  7. package/dist/chronicle/types.d.ts +2 -0
  8. package/dist/{agent-status-helpers.d.ts → coordination/agent-status-helpers.d.ts} +1 -1
  9. package/dist/{agent-status-tracker.d.ts → coordination/agent-status-tracker.d.ts} +2 -2
  10. package/dist/{middleware → coordination}/collab-pause.d.ts +1 -1
  11. package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -1
  12. package/dist/coordination/director.d.ts +7 -0
  13. package/dist/coordination/explore-companion.d.ts +9 -6
  14. package/dist/coordination/fleet-status-tool.d.ts +1 -1
  15. package/dist/coordination/index.d.ts +5 -1
  16. package/dist/coordination/index.js +2392 -405
  17. package/dist/coordination/kanban-dispatch-port.d.ts +30 -0
  18. package/dist/coordination/kanban-ops-port.d.ts +21 -0
  19. package/dist/coordination/mailbox-hooks.d.ts +1 -1
  20. package/dist/coordination/mailbox-project-server.js +14 -9
  21. package/dist/coordination/mutation-engine.d.ts +5 -3
  22. package/dist/core/context.d.ts +35 -44
  23. package/dist/core/conversation-state.d.ts +16 -52
  24. package/dist/core/index.js +92 -25
  25. package/dist/core/provider-runner.d.ts +2 -2
  26. package/dist/core/run-env.d.ts +7 -28
  27. package/dist/core/streaming-response-builder.d.ts +2 -2
  28. package/dist/execution/index.js +138 -162
  29. package/dist/goal/index.js +100 -22
  30. package/dist/hq/auth-store.d.ts +9 -0
  31. package/dist/hq/cost-bridge.d.ts +1 -1
  32. package/dist/hq/index.js +69 -7
  33. package/dist/index.d.ts +12 -5
  34. package/dist/index.js +21185 -26807
  35. package/dist/infrastructure/index.js +232 -135
  36. package/dist/infrastructure/provider-cache-ledger.d.ts +1 -1
  37. package/dist/infrastructure/token-counter.d.ts +5 -1
  38. package/dist/kernel/events/file-events.d.ts +6 -0
  39. package/dist/kernel/events/provider-events.d.ts +10 -7
  40. package/dist/kernel/events/session-events.d.ts +4 -4
  41. package/dist/kernel/events/tool-events.d.ts +12 -2
  42. package/dist/observability/index.js +1 -1
  43. package/dist/plugin/index.js +218 -47
  44. package/dist/prompts/index.js +360 -3
  45. package/dist/security/auto-approve-policy.d.ts +2 -2
  46. package/dist/security/index.d.ts +1 -0
  47. package/dist/security/index.js +224 -68
  48. package/dist/security/kanban-boundary.d.ts +1 -1
  49. package/dist/security/kanban-governance-port.d.ts +28 -0
  50. package/dist/security/permission-helpers.d.ts +11 -0
  51. package/dist/security/permission-policy.d.ts +10 -1
  52. package/dist/security/yolo-risk.d.ts +17 -0
  53. package/dist/session-catalog/index.js +34 -5
  54. package/dist/session-catalog/project-server.js +34 -5
  55. package/dist/session-catalog/protocol.d.ts +1 -1
  56. package/dist/session-catalog/registry.d.ts +1 -1
  57. package/dist/session-catalog/store-schema.d.ts +1 -1
  58. package/dist/session-catalog/store.d.ts +1 -1
  59. package/dist/skills/index.js +39 -6
  60. package/dist/storage/annotations-store.d.ts +1 -1
  61. package/dist/storage/board-store-port.d.ts +45 -0
  62. package/dist/storage/completed-work-checkpoint.d.ts +1 -1
  63. package/dist/storage/config-loader/types.d.ts +1 -1
  64. package/dist/storage/event-bus-port.d.ts +27 -0
  65. package/dist/storage/file-session-writer.d.ts +47 -5
  66. package/dist/storage/goal-coordination.d.ts +1 -1
  67. package/dist/storage/goal-store.d.ts +1 -1
  68. package/dist/storage/index.d.ts +3 -4
  69. package/dist/storage/index.js +1107 -1462
  70. package/dist/storage/plan-store.d.ts +1 -1
  71. package/dist/storage/queue-store.d.ts +1 -1
  72. package/dist/storage/replay-log-store.d.ts +1 -1
  73. package/dist/storage/session-recovery.d.ts +10 -0
  74. package/dist/storage/session-resume-validation.d.ts +13 -1
  75. package/dist/storage/session-store/events.d.ts +1 -1
  76. package/dist/storage/session-store/load-session-data.d.ts +1 -1
  77. package/dist/storage/session-store/rename-session.d.ts +1 -1
  78. package/dist/storage/session-store/resume-session.d.ts +3 -1
  79. package/dist/storage/session-store/session-store-index.d.ts +2 -1
  80. package/dist/storage/session-store/types.d.ts +1 -1
  81. package/dist/storage/session-store.d.ts +70 -0
  82. package/dist/storage/session-summary-tracker.d.ts +8 -0
  83. package/dist/storage/session-write-buffer.d.ts +31 -2
  84. package/dist/storage/task-store.d.ts +1 -1
  85. package/dist/storage/todos-checkpoint.d.ts +1 -1
  86. package/dist/storage/tool-audit-log.d.ts +1 -1
  87. package/dist/tasking/index.js +100 -22
  88. package/dist/tasking/task-tracker.d.ts +24 -1
  89. package/dist/types/compactor.d.ts +2 -2
  90. package/dist/types/context.d.ts +212 -0
  91. package/dist/types/conversation-state.d.ts +109 -0
  92. package/dist/types/error-handler.d.ts +2 -2
  93. package/dist/types/file-event-record.d.ts +6 -0
  94. package/dist/types/index.d.ts +3 -3
  95. package/dist/types/index.js +17 -1
  96. package/dist/types/permission.d.ts +3 -3
  97. package/dist/types/plugin.d.ts +3 -3
  98. package/dist/types/provider-runner.d.ts +2 -2
  99. package/dist/types/provider.d.ts +10 -0
  100. package/dist/types/run-env.d.ts +32 -0
  101. package/dist/types/session.d.ts +3 -0
  102. package/dist/types/slash-command.d.ts +2 -2
  103. package/dist/types/token-counter.d.ts +30 -1
  104. package/dist/types/tool-executor.d.ts +2 -2
  105. package/dist/types/tool.d.ts +20 -5
  106. package/dist/utils/context-breakdown.d.ts +2 -2
  107. package/dist/utils/context-evidence.d.ts +12 -12
  108. package/dist/utils/crash-shield.d.ts +9 -0
  109. package/dist/utils/heap-watchdog.js +11 -3
  110. package/dist/utils/index.d.ts +2 -1
  111. package/dist/utils/index.js +126 -160
  112. package/dist/utils/regex-guard.d.ts +7 -30
  113. package/dist/utils/terminal-sanitize.d.ts +41 -0
  114. package/dist/utils/todos-format.d.ts +1 -1
  115. package/dist/utils/tool-subject.d.ts +1 -1
  116. package/dist/utils/tree-kill.d.ts +2 -0
  117. package/dist/utils/tree-kill.js +1 -0
  118. package/instructions/agents/chaos-monkey.md +5 -1
  119. package/instructions/coordination/subagent-baseline.md +10 -0
  120. package/instructions/system-lite.md +2 -0
  121. package/instructions/system-pro.md +40 -0
  122. package/instructions/system.md +15 -0
  123. package/package.json +7 -10
  124. package/dist/defaults/index.d.ts +0 -69
  125. package/dist/defaults/index.js +0 -37755
  126. /package/dist/{fleet-notifier.d.ts → coordination/fleet-notifier.d.ts} +0 -0
  127. /package/dist/{session-registry-atomic-file.d.ts → session-catalog/session-registry-atomic-file.d.ts} +0 -0
  128. /package/dist/{session-registry-types.d.ts → session-catalog/session-registry-types.d.ts} +0 -0
  129. /package/dist/{session-registry.d.ts → session-catalog/session-registry.d.ts} +0 -0
@@ -326,6 +326,361 @@ var PromptManifestStore = class {
326
326
  // src/prompts/prompt-journal.ts
327
327
  import * as fs2 from "node:fs/promises";
328
328
  import * as path2 from "node:path";
329
+
330
+ // src/security/secret-scrubber.ts
331
+ var JSON_CREDENTIAL_KEY_ANCHORS = [
332
+ 'Key"',
333
+ 'key"',
334
+ 'KEY"',
335
+ 'token"',
336
+ 'Token"',
337
+ 'TOKEN"',
338
+ 'secret"',
339
+ 'Secret"',
340
+ 'SECRET"',
341
+ 'password"',
342
+ 'Password"',
343
+ 'PASSWORD"',
344
+ 'authorization"',
345
+ 'Authorization"',
346
+ 'bearer"',
347
+ 'Bearer"'
348
+ ];
349
+ var PATTERNS = [
350
+ // Anchored at the start where possible so partial matches inside larger
351
+ // strings don't trigger false positives.
352
+ {
353
+ type: "anthropic_key",
354
+ regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g,
355
+ anchor: "sk-ant-"
356
+ },
357
+ { type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g, anchor: "sk-" },
358
+ {
359
+ // `xai` is a first-class provider in this codebase, but its key shape was
360
+ // absent here — so the one credential format WrongStack itself hands users
361
+ // was the one the scrubber could not recognize (audit 2026-08-20).
362
+ type: "xai_key",
363
+ regex: /(?<![A-Za-z0-9])xai-[A-Za-z0-9]{20,}(?![A-Za-z0-9])/g,
364
+ anchor: "xai-"
365
+ },
366
+ { type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g, anchor: "ghp_" },
367
+ { type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g, anchor: "github_pat_" },
368
+ { type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g, anchor: "AKIA" },
369
+ { type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g, anchor: "AIza" },
370
+ { type: "slack_token", regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g, anchor: "xox" },
371
+ {
372
+ type: "stripe_key",
373
+ regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g,
374
+ anchor: "sk_"
375
+ },
376
+ {
377
+ type: "twilio_sid",
378
+ regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g,
379
+ anchor: "AC"
380
+ },
381
+ {
382
+ type: "telegram_bot_token",
383
+ // Telegram tokens are of the form bot<digits>:<alphanum> in URL paths
384
+ regex: /\/bot\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
385
+ anchor: "/bot"
386
+ },
387
+ {
388
+ type: "jwt",
389
+ // Anchored: look for literal "eyJ" which is unambiguous for JWT header
390
+ regex: /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g,
391
+ anchor: "eyJ"
392
+ },
393
+ {
394
+ type: "private_key",
395
+ // Anchored: start must be BEGIN, end must be END with no extra dashes after END
396
+ regex: /(?:^|\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\s\S]*?-----END[^-]*-----(?:\n|$)/g,
397
+ anchor: "-----BEGIN"
398
+ },
399
+ { type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s"'`]+/g, anchor: "mongodb" },
400
+ { type: "postgres_uri", regex: /postgres(?:ql)?:\/\/[^\s"'`]+/g, anchor: "postgres" },
401
+ { type: "mysql_uri", regex: /mysql:\/\/[^\s"'`]+/g, anchor: "mysql://" },
402
+ { type: "redis_uri", regex: /redis:\/\/[^\s"'`]+/g, anchor: "redis://" },
403
+ // AI/ML provider keys — modern LLM services with well-known prefixes
404
+ {
405
+ type: "huggingface_token",
406
+ // HuggingFace tokens: hf_ followed by 34 alphanumeric chars
407
+ regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g,
408
+ anchor: "hf_"
409
+ },
410
+ {
411
+ type: "replicate_token",
412
+ // Replicate tokens: r8_ followed by 40+ alphanumeric chars
413
+ regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
414
+ anchor: "r8_"
415
+ },
416
+ {
417
+ type: "perplexity_key",
418
+ // Perplexity API keys: pplx- followed by 40+ alphanumeric chars
419
+ regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
420
+ anchor: "pplx-"
421
+ },
422
+ {
423
+ type: "groq_key",
424
+ // Groq API keys: gsk_ followed by 40+ alphanumeric chars
425
+ regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
426
+ anchor: "gsk_"
427
+ },
428
+ {
429
+ type: "bearer_token",
430
+ // Anchored with alternation instead of negative lookahead — avoids V8
431
+ // backtracking risk on adversarial input. Bounded at 512 chars.
432
+ // Min 12 chars: some OAuth providers issue shorter-lived tokens (< 20
433
+ // chars). A 12-char base64 string has ~71 bits of entropy — above the
434
+ // threshold where random strings are unlikely to produce false matches.
435
+ // The trailing boundary is a NON-consuming lookahead: two adjacent bearer
436
+ // tokens sharing a single delimiter (`Bearer a… Bearer b…`) must both be
437
+ // redacted. A consuming trailing delimiter would eat the separator the
438
+ // next match needs for its leading anchor, leaking the second token.
439
+ regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?=$|[^A-Za-z0-9_.~+/-])/g,
440
+ anchor: "Bearer"
441
+ },
442
+ {
443
+ type: "high_entropy_env",
444
+ // Anchored with alternation instead of lookbehind to avoid backtracking.
445
+ // Value bounded at 512 chars.
446
+ // The trailing boundary is a NON-consuming lookahead so two secrets
447
+ // separated by a single delimiter (one space OR one newline, e.g.
448
+ // `printenv` / `.env` dumps: `API_KEY=… \n SESSION_TOKEN=…`) are BOTH
449
+ // redacted. A consuming trailing `\s` would swallow the separator the
450
+ // next match needs for its leading anchor, so every other secret would
451
+ // leak in plaintext.
452
+ // The leading delimiter is CAPTURED (group 1) and re-emitted by the
453
+ // replacement so the separator between adjacent secrets is preserved
454
+ // rather than collapsed. Capture groups are therefore: 1=leading
455
+ // delimiter, 2=key name, 3=value.
456
+ regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD|PASSPHRASE))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g,
457
+ anchor: ["KEY", "TOKEN", "SECRET", "PASSWORD", "PWD", "PASSPHRASE"]
458
+ },
459
+ {
460
+ type: "json_credential_key",
461
+ // The JSON counterpart to `high_entropy_env`, and the pattern that the
462
+ // now-deleted `JSON_KEY_ANCHORS` list was written for. Without it those
463
+ // anchors only widened the cheap pre-scan — `hasCredentialAnchors` said
464
+ // "this text may hold a secret", every pattern then declined to match, and
465
+ // the value went out verbatim. `high_entropy_env` cannot cover these: it
466
+ // requires an UPPERCASE unquoted key (`API_KEY=…`), so `{"apiKey":"…"}`
467
+ // never matched.
468
+ //
469
+ // Tool results are routinely serialised as JSON, and a credential with no
470
+ // recognisable prefix (Azure, self-hosted gateways, Anthropic/Codex OAuth)
471
+ // has no other pattern that can catch it — this is the only thing standing
472
+ // between such a value and the session JSONL, chronicle, HQ broadcast and
473
+ // the model's own context.
474
+ //
475
+ // The key may carry a prefix (`"anthropicApiKey"`), but the credential word
476
+ // must END the key: `"tokenCount"` and `"maxTokens"` do not match, because
477
+ // the closing quote has to follow the word immediately.
478
+ // Value floor of 8 chars keeps enum-ish values (`"authorization":"none"`)
479
+ // out. Capture groups: 1=key + punctuation, 2=value, 3=closing quote.
480
+ regex: /("[A-Za-z0-9_]*(?:apiKey|api_key|token|secret|password|authorization|bearer|private_key|access_token|refresh_token|client_secret)"\s*:\s*")([^"\\]{8,512})(")/gi,
481
+ anchor: JSON_CREDENTIAL_KEY_ANCHORS
482
+ },
483
+ // ── Ported from packages/plugins credential-patterns.ts (WS-034) ─────────
484
+ // The plugin runtime carried 37 patterns while this scrubber — the one that
485
+ // guards session JSONL, chronicle, HQ broadcast, WebUI events and the auth
486
+ // audit — carried 22. The plugin side already had a parity test; it just did
487
+ // not cover core. Most consequential: WrongStack mints `gho_` tokens itself
488
+ // in the Copilot OAuth flow, and `gh[ousr]_` was absent here.
489
+ {
490
+ type: "github_oauth_token",
491
+ regex: /(?<![A-Za-z0-9])gh[ousr]_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g,
492
+ anchor: ["gho_", "ghu_", "ghs_", "ghr_"]
493
+ },
494
+ {
495
+ type: "gitlab_pat",
496
+ regex: /(?<![A-Za-z0-9])glpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
497
+ anchor: "glpat-"
498
+ },
499
+ {
500
+ type: "gitlab_runner_token",
501
+ regex: /(?<![A-Za-z0-9])glrt-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
502
+ anchor: "glrt-"
503
+ },
504
+ {
505
+ type: "npm_token",
506
+ regex: /(?<![A-Za-z0-9])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g,
507
+ anchor: "npm_"
508
+ },
509
+ {
510
+ type: "slack_app_token",
511
+ regex: /(?<![A-Za-z0-9-])xapp-\d-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g,
512
+ anchor: "xapp-"
513
+ },
514
+ {
515
+ type: "slack_webhook",
516
+ regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9_-]+\/B[A-Za-z0-9_-]+\/[A-Za-z0-9]{16,}/g,
517
+ anchor: "hooks.slack.com"
518
+ },
519
+ {
520
+ type: "sendgrid_key",
521
+ regex: /(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
522
+ anchor: "SG."
523
+ },
524
+ {
525
+ type: "digitalocean_token",
526
+ regex: /(?<![A-Za-z0-9])dop_v1_[a-f0-9]{64}(?![A-Za-z0-9])/g,
527
+ anchor: "dop_v1_"
528
+ },
529
+ {
530
+ type: "doppler_token",
531
+ regex: /(?<![A-Za-z0-9])dp\.(?:pt|st|sa|scim|audit)\.[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
532
+ anchor: "dp."
533
+ },
534
+ {
535
+ type: "shopify_token",
536
+ regex: /(?<![A-Za-z0-9])shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}(?![A-Za-z0-9])/g,
537
+ anchor: "shp"
538
+ },
539
+ {
540
+ type: "docker_pat",
541
+ regex: /(?<![A-Za-z0-9])dckr_pat_[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
542
+ anchor: "dckr_pat_"
543
+ },
544
+ {
545
+ type: "linear_key",
546
+ regex: /(?<![A-Za-z0-9])lin_api_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
547
+ anchor: "lin_api_"
548
+ },
549
+ {
550
+ type: "atlassian_token",
551
+ regex: /(?<![A-Za-z0-9])ATATT3[A-Za-z0-9_\-=]{40,}(?![A-Za-z0-9_\-=])/g,
552
+ anchor: "ATATT3"
553
+ },
554
+ {
555
+ type: "square_token",
556
+ regex: /(?<![A-Za-z0-9])(?:sq0(?:atp|csp)-|EAAA)[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
557
+ anchor: ["sq0atp-", "sq0csp-", "EAAA"]
558
+ },
559
+ {
560
+ type: "google_oauth_client_secret",
561
+ regex: /(?<![A-Za-z0-9_-])GOCSPX-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
562
+ anchor: "GOCSPX-"
563
+ }
564
+ ];
565
+ var SIMPLE_PATTERNS = PATTERNS.filter(
566
+ (p) => p.type !== "high_entropy_env" && p.type !== "json_credential_key"
567
+ );
568
+ var COMBINED_REGEX = new RegExp(SIMPLE_PATTERNS.map((p) => `(${p.regex.source})`).join("|"), "g");
569
+ var HIGH_ENTROPY_REGEX = PATTERNS.find((p) => p.type === "high_entropy_env").regex;
570
+ var JSON_CREDENTIAL_REGEX = PATTERNS.find((p) => p.type === "json_credential_key").regex;
571
+ var COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);
572
+ var SCRUB_CHUNK_BYTES = 64 * 1024;
573
+ var SCRUB_OVERLAP_BYTES = 1024;
574
+ var PEM_PRIVATE_KEY_BEGIN_RE = /-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----/;
575
+ var PEM_END_MARKER = "-----END";
576
+ var MAX_PEM_BLOCK_BYTES = 64 * 1024;
577
+ var PEM_END_LINE_TOLERANCE = 64;
578
+ function extendChunkBoundaryPastPem(text, chunkStart, proposedEnd) {
579
+ const head = text.slice(chunkStart, proposedEnd);
580
+ const lastBegin = head.lastIndexOf("-----BEGIN ");
581
+ if (lastBegin === -1) return proposedEnd;
582
+ const fromBegin = text.slice(chunkStart + lastBegin);
583
+ const marker = PEM_PRIVATE_KEY_BEGIN_RE.exec(fromBegin);
584
+ if (!marker || marker.index !== 0) return proposedEnd;
585
+ const bodyStart = marker[0].length;
586
+ const cap = Math.min(text.length, chunkStart + lastBegin + MAX_PEM_BLOCK_BYTES);
587
+ const closeIdx = fromBegin.indexOf(PEM_END_MARKER, bodyStart);
588
+ if (closeIdx === -1 || chunkStart + lastBegin + closeIdx >= cap + PEM_END_LINE_TOLERANCE) {
589
+ return proposedEnd;
590
+ }
591
+ const lineEnd = fromBegin.indexOf("\n", closeIdx);
592
+ const end = lineEnd === -1 ? text.length : chunkStart + lastBegin + lineEnd + 1;
593
+ return Math.max(proposedEnd, end);
594
+ }
595
+ var PATTERN_ANCHORS = [
596
+ ...new Set(
597
+ PATTERNS.flatMap(
598
+ (pattern) => typeof pattern.anchor === "string" ? [pattern.anchor] : [...pattern.anchor]
599
+ )
600
+ )
601
+ ];
602
+ var ALL_ANCHORS = PATTERN_ANCHORS;
603
+ function hasCredentialAnchors(text) {
604
+ for (const anchor of ALL_ANCHORS) {
605
+ if (text.includes(anchor)) return true;
606
+ }
607
+ return false;
608
+ }
609
+ var DefaultSecretScrubber = class {
610
+ scrub(text) {
611
+ if (!text) return text;
612
+ if (!hasCredentialAnchors(text)) return text;
613
+ if (text.length <= SCRUB_CHUNK_BYTES) {
614
+ return this.scrubOne(text);
615
+ }
616
+ const out = [];
617
+ let i = 0;
618
+ while (i < text.length) {
619
+ let end = Math.min(i + SCRUB_CHUNK_BYTES, text.length);
620
+ if (end < text.length) {
621
+ const limit = Math.min(end + SCRUB_OVERLAP_BYTES, text.length);
622
+ let safe = -1;
623
+ for (let j = end; j < limit; j++) {
624
+ const ch = text.charCodeAt(j);
625
+ if (ch === 32 || ch === 9 || ch === 10 || ch === 13) {
626
+ safe = j;
627
+ break;
628
+ }
629
+ }
630
+ end = safe === -1 ? end : safe + 1;
631
+ end = extendChunkBoundaryPastPem(text, i, end);
632
+ }
633
+ out.push(this.scrubOne(text.slice(i, end)));
634
+ i = end;
635
+ }
636
+ return out.join("");
637
+ }
638
+ scrubOne(text) {
639
+ if (!hasCredentialAnchors(text)) return text;
640
+ let out = text.replace(
641
+ COMBINED_REGEX,
642
+ (match, ...groups) => {
643
+ const idx = groups.findIndex((g) => g !== void 0);
644
+ if (idx < 0) return match;
645
+ const replacement = COMBINED_REPLACEMENTS[idx];
646
+ return replacement !== void 0 ? replacement : match;
647
+ }
648
+ );
649
+ out = out.replace(HIGH_ENTROPY_REGEX, (_match, lead, key, _value) => {
650
+ return `${lead}${key}=[REDACTED:high_entropy_env]`;
651
+ });
652
+ out = out.replace(JSON_CREDENTIAL_REGEX, (_match, keyPrefix, _value, closingQuote) => {
653
+ return `${keyPrefix}[REDACTED:json_credential_key]${closingQuote}`;
654
+ });
655
+ return out;
656
+ }
657
+ /**
658
+ * Recursively scrub every string value in an object/array graph. Secrets can
659
+ * appear under any key — a URL query param, an `authorization` header, an
660
+ * arbitrarily-named nested field — so we don't gate recursion on key names.
661
+ * The per-string `scrub()` fast-path (anchor pre-scan) keeps this cheap: any
662
+ * value without a credential anchor returns immediately without regex work.
663
+ */
664
+ scrubObject(obj) {
665
+ const seen = /* @__PURE__ */ new WeakSet();
666
+ const visit = (v) => {
667
+ if (typeof v === "string") return this.scrub(v);
668
+ if (v === null || typeof v !== "object") return v;
669
+ if (seen.has(v)) return v;
670
+ seen.add(v);
671
+ if (Array.isArray(v)) return v.map(visit);
672
+ const out = {};
673
+ for (const [k, val] of Object.entries(v)) {
674
+ out[k] = visit(val);
675
+ }
676
+ return out;
677
+ };
678
+ return visit(obj);
679
+ }
680
+ };
681
+
682
+ // src/prompts/prompt-journal.ts
683
+ var defaultScrubber = new DefaultSecretScrubber();
329
684
  var PROMPT_JOURNAL_RAW_MARKER = "promptJournal.raw";
330
685
  async function ensureGitignore(projectRoot) {
331
686
  const gitignorePath = path2.join(projectRoot, ".gitignore");
@@ -354,7 +709,9 @@ async function recordPromptJournalEntry(opts) {
354
709
  const monthStr = dateStr.slice(0, 7);
355
710
  const sessionId = opts.sessionId && opts.sessionId.trim() ? opts.sessionId.trim() : "general";
356
711
  const id = `pmt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
357
- const content = opts.content ?? "";
712
+ const content = defaultScrubber.scrub(opts.content ?? "");
713
+ const rawContent = typeof opts.rawContent === "string" && opts.rawContent.length > 0 ? defaultScrubber.scrub(opts.rawContent) : opts.rawContent;
714
+ const decisionReason = typeof opts.decisionReason === "string" && opts.decisionReason.length > 0 ? defaultScrubber.scrub(opts.decisionReason) : opts.decisionReason;
358
715
  const lines = content.split("\n");
359
716
  const characterCount = content.length;
360
717
  const lineCount = lines.length;
@@ -367,7 +724,7 @@ async function recordPromptJournalEntry(opts) {
367
724
  role: opts.role ?? (opts.category === "system_prompt" ? "system" : "user"),
368
725
  category: opts.category,
369
726
  content,
370
- rawContent: opts.rawContent,
727
+ rawContent,
371
728
  metadata: {
372
729
  model: opts.model,
373
730
  provider: opts.provider,
@@ -378,7 +735,7 @@ async function recordPromptJournalEntry(opts) {
378
735
  activeTools: opts.activeTools,
379
736
  contextFiles: opts.contextFiles,
380
737
  durationMs: opts.durationMs,
381
- decisionReason: opts.decisionReason,
738
+ decisionReason,
382
739
  tags: opts.tags
383
740
  }
384
741
  };
@@ -26,12 +26,12 @@ export declare class AutoApprovePermissionPolicy implements PermissionPolicy {
26
26
  private readonly allowedCapabilities;
27
27
  constructor(allowedCapabilities?: readonly string[]);
28
28
  private static isMcpTool;
29
- evaluate(tool: Tool): Promise<PermissionDecision>;
29
+ evaluate(tool: Tool, input?: unknown): Promise<PermissionDecision>;
30
30
  trust(): Promise<void>;
31
31
  deny(): Promise<void>;
32
32
  denyOnce(): void;
33
33
  allowOnce(): void;
34
- explain(tool: Tool): Promise<PermissionTrace>;
34
+ explain(tool: Tool, input?: unknown): Promise<PermissionTrace>;
35
35
  reload(): Promise<void>;
36
36
  }
37
37
  //# sourceMappingURL=auto-approve-policy.d.ts.map
@@ -1,6 +1,7 @@
1
1
  export { noOpVault } from '../types/secret-vault.js';
2
2
  export { clampSubagentCapabilities, DANGEROUS_FOR_SUBAGENTS, getDangerousCapabilities, hasCapability, hasDangerousCapabilityForSubagents, ToolCapabilities, type ToolCapability, WIDE_SUBAGENT_CAPABILITIES, } from './capabilities.js';
3
3
  export { decryptConfigSecrets, encryptConfigSecrets, isSecretField } from './config-secrets.js';
4
+ export { kanbanGovernance, type KanbanGovernancePort, setKanbanGovernance, } from './kanban-governance-port.js';
4
5
  export { DirectoryPermissionPolicy, type DirectoryPermissionPolicyOptions, matchRule, resolveTargetPath, } from './directory-permission-policy.js';
5
6
  export { DIRECTORY_POLICY_LIMITS, DIRECTORY_POLICY_SCHEMA_VERSION, type DirectoryPolicyDiagnostic, type DirectoryPolicyDiagnosticCode, type DirectoryPolicyValidationResult, validateDirectoryPolicy, } from './directory-policy-schema.js';
6
7
  export { ERROR_DETAIL_MAX, sanitizeApiError, scrubErrorDetail, scrubErrorText, } from './error-sanitize.js';