switchroom 0.20.9 → 0.20.11

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 (59) hide show
  1. package/bin/handoff-briefing.sh +57 -5
  2. package/bin/working-state-reload-hook.sh +262 -0
  3. package/dist/agent-scheduler/index.js +65 -2
  4. package/dist/auth-broker/index.js +204 -24
  5. package/dist/cli/notion-write-pretool.mjs +65 -2
  6. package/dist/cli/self-improve-apply-guard-pretool.mjs +357 -92
  7. package/dist/cli/self-improve-stop.mjs +889 -7
  8. package/dist/cli/skill-validate-pretool.mjs +82 -3
  9. package/dist/cli/switchroom.js +3699 -2110
  10. package/dist/host-control/main.js +67 -4
  11. package/dist/vault/approvals/kernel-server.js +66 -3
  12. package/dist/vault/broker/server.js +66 -3
  13. package/package.json +1 -1
  14. package/profiles/_base/start.sh.hbs +49 -0
  15. package/profiles/_shared/agent-self-service.md.hbs +15 -22
  16. package/profiles/_shared/delegation-golden-rule.md.hbs +1 -1
  17. package/profiles/_shared/dev-protocol.md.hbs +1 -1
  18. package/profiles/_shared/execution-discipline.md.hbs +4 -4
  19. package/profiles/_shared/vault-protocol.md.hbs +2 -18
  20. package/profiles/default/CLAUDE.md.hbs +3 -5
  21. package/telegram-plugin/auto-fallback-fleet.ts +37 -2
  22. package/telegram-plugin/dist/gateway/gateway.js +1414 -918
  23. package/telegram-plugin/fallback-card-collapse.ts +1 -0
  24. package/telegram-plugin/gateway/auth-command.ts +11 -1
  25. package/telegram-plugin/gateway/callback-query-handlers.ts +100 -0
  26. package/telegram-plugin/gateway/eval-case-proposal-card.ts +86 -0
  27. package/telegram-plugin/gateway/fleet-fallback-notice-cooldown.test.ts +74 -0
  28. package/telegram-plugin/gateway/fleet-fallback-notice-cooldown.ts +71 -0
  29. package/telegram-plugin/gateway/gateway.ts +85 -90
  30. package/telegram-plugin/gateway/ipc-protocol.ts +43 -0
  31. package/telegram-plugin/gateway/ipc-server.ts +28 -0
  32. package/telegram-plugin/gateway/narrative-lane.ts +33 -2
  33. package/telegram-plugin/gateway/privacy-reset.test.ts +216 -0
  34. package/telegram-plugin/gateway/privacy-reset.ts +87 -0
  35. package/telegram-plugin/gateway/privacy-state.test.ts +165 -0
  36. package/telegram-plugin/gateway/privacy-state.ts +206 -0
  37. package/telegram-plugin/gateway/self-improve-proposal-wiring.ts +176 -0
  38. package/telegram-plugin/gateway/stale-pin-sweep-wiring.ts +24 -14
  39. package/telegram-plugin/gateway/stale-pin-sweep.test.ts +123 -26
  40. package/telegram-plugin/gateway/stale-pin-sweep.ts +48 -32
  41. package/telegram-plugin/gateway/throttle-tier-wiring.ts +15 -4
  42. package/telegram-plugin/slot-banner-driver.ts +42 -5
  43. package/telegram-plugin/tests/auto-fallback-fleet.test.ts +24 -0
  44. package/telegram-plugin/tests/gateway-handler-registration-wiring.test.ts +2 -0
  45. package/telegram-plugin/tests/narrative-lane-golden.test.ts +97 -0
  46. package/telegram-plugin/tests/privacy-reset-call-sites.test.ts +120 -0
  47. package/telegram-plugin/tests/status-pin-store.test.ts +25 -0
  48. package/telegram-plugin/tests/throttle-tier.test.ts +16 -0
  49. package/telegram-plugin/tests/turn-flush-safety.test.ts +67 -0
  50. package/telegram-plugin/throttle-tier.ts +12 -3
  51. package/telegram-plugin/turn-flush-safety.ts +97 -0
  52. package/vendor/hindsight-memory/CHANGELOG.md +31 -0
  53. package/vendor/hindsight-memory/hooks/hooks.json +2 -1
  54. package/vendor/hindsight-memory/scripts/retain.py +306 -0
  55. package/vendor/hindsight-memory/scripts/session_start.py +35 -8
  56. package/vendor/hindsight-memory/scripts/subagent_retain.py +29 -1
  57. package/vendor/hindsight-memory/scripts/tests/test_private_mode.py +415 -0
  58. package/vendor/hindsight-memory/scripts/tests/test_self_improve_correction_tag.py +167 -0
  59. package/vendor/hindsight-memory/scripts/tests/test_session_start_durability.py +107 -0
@@ -6919,7 +6919,7 @@ var require_public_api = __commonJS((exports) => {
6919
6919
 
6920
6920
  // src/cli/skill-validate-pretool.ts
6921
6921
  import { readFileSync, lstatSync, readdirSync } from "node:fs";
6922
- import { join } from "node:path";
6922
+ import { join, resolve } from "node:path";
6923
6923
 
6924
6924
  // node_modules/.bun/yaml@2.8.3/node_modules/yaml/dist/index.js
6925
6925
  var composer = require_composer();
@@ -7219,9 +7219,16 @@ function validateSkillMd(content, expectedName) {
7219
7219
  }
7220
7220
  var BANNED_PHRASE = "claude" + " -p";
7221
7221
 
7222
+ // src/self-improve/config.ts
7223
+ function selfImproveEnabled() {
7224
+ return process.env.SWITCHROOM_SELF_IMPROVE !== "0";
7225
+ }
7226
+
7222
7227
  // src/cli/skill-validate-pretool.ts
7223
7228
  var SKILLS_SEGMENT = "/.claude/skills/";
7224
7229
  var EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit"]);
7230
+ var EVALS_JSON_REL = "evals/evals.json";
7231
+ var ABS_SKILL_EVALS_RE = /\/\.claude\/skills\/[^/]+\/evals\/evals\.json$/;
7225
7232
  function readStdin() {
7226
7233
  try {
7227
7234
  return readFileSync(0, "utf8");
@@ -7280,6 +7287,72 @@ function fileSize(p) {
7280
7287
  return 0;
7281
7288
  }
7282
7289
  }
7290
+ var BASH_WRITERS = new Set([
7291
+ "tee",
7292
+ "cp",
7293
+ "mv",
7294
+ "dd",
7295
+ "install",
7296
+ "truncate",
7297
+ "rsync"
7298
+ ]);
7299
+ function tokenIsSkillEvalsJson(token) {
7300
+ const t = token.replace(/^['"]+/, "").replace(/['"]+$/, "");
7301
+ if (!t.includes(".claude/skills/"))
7302
+ return false;
7303
+ return ABS_SKILL_EVALS_RE.test(resolve("/", t));
7304
+ }
7305
+ function redirectWritesEvals(command) {
7306
+ const re = /(?:^|[^<>&\d])(?:\d+|&)?>>?(?:&(?![\d-]))?\|?\s*(['"]?)([^\s'"|;&()<>]+)\1/g;
7307
+ let m;
7308
+ while ((m = re.exec(command)) !== null) {
7309
+ if (m[2] && tokenIsSkillEvalsJson(m[2]))
7310
+ return true;
7311
+ }
7312
+ return false;
7313
+ }
7314
+ function writerVerbWritesEvals(command) {
7315
+ for (const seg of command.split(/&&|\|\||[;|\n]/g)) {
7316
+ const tokens = seg.trim().split(/\s+/).filter((s) => s.length > 0);
7317
+ if (tokens.length === 0)
7318
+ continue;
7319
+ const verb = tokens[0].replace(/^['"]+/, "");
7320
+ const rest = tokens.slice(1);
7321
+ if (BASH_WRITERS.has(verb)) {
7322
+ for (const tok of rest) {
7323
+ const p = tok.startsWith("of=") ? tok.slice(3) : tok;
7324
+ if (tokenIsSkillEvalsJson(p))
7325
+ return true;
7326
+ }
7327
+ }
7328
+ if (verb === "sed" && rest.some((r) => r === "-i" || r.startsWith("-i"))) {
7329
+ for (const tok of rest)
7330
+ if (tokenIsSkillEvalsJson(tok))
7331
+ return true;
7332
+ }
7333
+ }
7334
+ return false;
7335
+ }
7336
+ function detectBashEvalsWrite(command) {
7337
+ if (redirectWritesEvals(command))
7338
+ return "a shell redirect into";
7339
+ if (writerVerbWritesEvals(command))
7340
+ return "a shell write into";
7341
+ return null;
7342
+ }
7343
+ function handleBash(event) {
7344
+ if (!selfImproveEnabled())
7345
+ allow();
7346
+ const input = event.tool_input && typeof event.tool_input === "object" ? event.tool_input : {};
7347
+ const command = typeof input.command === "string" ? input.command : "";
7348
+ if (!command)
7349
+ allow();
7350
+ const how = detectBashEvalsWrite(command);
7351
+ if (how) {
7352
+ block(`evals/evals.json is machine-managed under self-improvement \u2014 ${how} it ` + `via Bash bypasses the PII/secret scan and the operator's one-tap ` + `approval. Add a case with: switchroom self-improve add-eval-case ` + `--skill <slug> --prompt "<the correction, as a test prompt>". ` + `(To hand-author evals via skill-creator instead, set ` + `SWITCHROOM_SELF_IMPROVE=0.)`);
7353
+ }
7354
+ allow();
7355
+ }
7283
7356
  function main() {
7284
7357
  const raw = readStdin().trim();
7285
7358
  if (!raw)
@@ -7291,12 +7364,15 @@ function main() {
7291
7364
  allow();
7292
7365
  }
7293
7366
  const toolName = typeof event.tool_name === "string" ? event.tool_name : "";
7367
+ if (toolName === "Bash")
7368
+ handleBash(event);
7294
7369
  if (!EDIT_TOOLS.has(toolName))
7295
7370
  allow();
7296
7371
  const input = event.tool_input && typeof event.tool_input === "object" ? event.tool_input : {};
7297
- const filePath = typeof input.file_path === "string" ? input.file_path : "";
7298
- if (!filePath)
7372
+ const rawFilePath = typeof input.file_path === "string" ? input.file_path : "";
7373
+ if (!rawFilePath)
7299
7374
  allow();
7375
+ const filePath = resolve(rawFilePath);
7300
7376
  const segIdx = filePath.indexOf(SKILLS_SEGMENT);
7301
7377
  if (segIdx < 0)
7302
7378
  allow();
@@ -7307,6 +7383,9 @@ function main() {
7307
7383
  const slug = segs[0];
7308
7384
  const relPath = segs.slice(1).join("/");
7309
7385
  const skillDir = filePath.slice(0, segIdx + SKILLS_SEGMENT.length) + slug;
7386
+ if (selfImproveEnabled() && relPath === EVALS_JSON_REL) {
7387
+ block(`evals/evals.json is machine-managed under self-improvement \u2014 a direct ` + `write bypasses the PII/secret scan and the operator's one-tap ` + `approval. Add a case with: switchroom self-improve add-eval-case ` + `--skill ${slug} --prompt "<the correction, as a test prompt>". ` + `(To hand-author evals via skill-creator instead, set ` + `SWITCHROOM_SELF_IMPROVE=0.)`);
7388
+ }
7310
7389
  const warnings = [];
7311
7390
  if (!validateSkillName(slug)) {
7312
7391
  warnings.push(`skill slug "${slug}" is invalid \u2014 must match ` + `[a-z0-9][a-z0-9_-]{0,62}. Claude won't discover a skill at an ` + `invalid slug.`);