switchroom 0.19.34 → 0.19.36
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.
- package/dist/auth-broker/index.js +7 -1
- package/dist/cli/skill-validate-pretool.mjs +15 -2
- package/dist/cli/switchroom.js +1005 -482
- package/dist/host-control/main.js +156 -4
- package/dist/vault/approvals/kernel-server.js +7 -1
- package/dist/vault/broker/server.js +7 -1
- package/package.json +4 -2
- package/profiles/_base/start.sh.hbs +37 -12
- package/telegram-plugin/dist/gateway/gateway.js +476 -116
- package/telegram-plugin/format.ts +70 -15
- package/telegram-plugin/gateway/gateway.ts +27 -31
- package/telegram-plugin/gateway/ipc-server.ts +18 -15
- package/telegram-plugin/gateway/model-command.ts +279 -23
- package/telegram-plugin/gateway/outbound-send-path.ts +12 -1
- package/telegram-plugin/operator-events.ts +40 -16
- package/telegram-plugin/secret-detect/db-uri.ts +90 -0
- package/telegram-plugin/secret-detect/index.ts +24 -1
- package/telegram-plugin/secret-detect/inert-values.ts +147 -0
- package/telegram-plugin/secret-detect/kv-scanner.ts +108 -0
- package/telegram-plugin/secret-detect/patterns.ts +24 -4
- package/telegram-plugin/tests/format-consistency.test.ts +93 -0
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +40 -2
- package/telegram-plugin/tests/ipc-server-validate-operator.test.ts +20 -11
- package/telegram-plugin/tests/model-command.test.ts +415 -4
- package/telegram-plugin/tests/outbound-send-path.test.ts +1 -1
- package/telegram-plugin/tests/secret-detect-cross-engine.test.ts +263 -0
- package/telegram-plugin/tests/secret-detect-write-path.test.ts +403 -0
- package/telegram-plugin/tests/turn-flush-safety.test.ts +2 -2
- package/vendor/hindsight-memory/scripts/lib/client.py +58 -0
- package/vendor/hindsight-memory/scripts/lib/secret_patterns.json +431 -0
- package/vendor/hindsight-memory/scripts/lib/secret_redact.py +563 -0
- package/vendor/hindsight-memory/scripts/lib/secret_redaction_vectors.json +397 -0
- package/vendor/hindsight-memory/scripts/subagent_retain.py +103 -7
- package/vendor/hindsight-memory/scripts/tests/test_secret_redact.py +522 -0
- package/vendor/hindsight-memory/scripts/tests/test_subagent_retain_learnings.py +377 -0
|
@@ -21311,7 +21311,7 @@ function allocateAgentUid(name) {
|
|
|
21311
21311
|
}
|
|
21312
21312
|
|
|
21313
21313
|
// src/build-info.ts
|
|
21314
|
-
var VERSION = "0.19.
|
|
21314
|
+
var VERSION = "0.19.36";
|
|
21315
21315
|
|
|
21316
21316
|
// src/setup/hindsight-recall-tunables.ts
|
|
21317
21317
|
var RECALL_DEADLINE_HEADROOM_SECONDS = 2;
|
|
@@ -21323,6 +21323,9 @@ init_schema();
|
|
|
21323
21323
|
// src/config/users.ts
|
|
21324
21324
|
init_merge();
|
|
21325
21325
|
|
|
21326
|
+
// src/config/thinking-effort-risk.ts
|
|
21327
|
+
var RISKY_EFFORTS = new Set(["medium", "high", "xhigh", "max"]);
|
|
21328
|
+
|
|
21326
21329
|
// src/agents/scaffold.ts
|
|
21327
21330
|
init_merge();
|
|
21328
21331
|
init_timezone();
|
|
@@ -21444,12 +21447,15 @@ function pgMib(mib) {
|
|
|
21444
21447
|
}
|
|
21445
21448
|
var HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE";
|
|
21446
21449
|
var HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS";
|
|
21450
|
+
var HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC";
|
|
21451
|
+
var HINDSIGHT_PG_DEFAULT_FSYNC = "on";
|
|
21447
21452
|
var HINDSIGHT_PG_DEFAULTS = [
|
|
21448
21453
|
[
|
|
21449
21454
|
HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV,
|
|
21450
21455
|
pgMib(HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB)
|
|
21451
21456
|
],
|
|
21452
|
-
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)]
|
|
21457
|
+
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)],
|
|
21458
|
+
[HINDSIGHT_PG_FSYNC_ENV, HINDSIGHT_PG_DEFAULT_FSYNC]
|
|
21453
21459
|
];
|
|
21454
21460
|
var HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
|
|
21455
21461
|
|
|
@@ -27284,16 +27290,22 @@ var STRUCTURED_PATTERNS = [
|
|
|
27284
27290
|
},
|
|
27285
27291
|
{
|
|
27286
27292
|
rule_id: "bearer_auth_header",
|
|
27287
|
-
regex: /Authorization\s*[:=]\s*Bearer\s+([A-Za-z0-9._\-+=]+)/
|
|
27293
|
+
regex: /Authorization\s*[:=]\s*Bearer\s+([A-Za-z0-9._\-+=]+)/gi,
|
|
27288
27294
|
captureIndex: 1,
|
|
27289
27295
|
slugHint: "bearer_token"
|
|
27290
27296
|
},
|
|
27291
27297
|
{
|
|
27292
27298
|
rule_id: "bearer_loose",
|
|
27293
|
-
regex: /\bBearer\s+([A-Za-z0-9._\-+=]{18,})\b/
|
|
27299
|
+
regex: /\bBearer\s+([A-Za-z0-9._\-+=]{18,})\b/gi,
|
|
27294
27300
|
captureIndex: 1,
|
|
27295
27301
|
slugHint: "bearer_token"
|
|
27296
27302
|
},
|
|
27303
|
+
{
|
|
27304
|
+
rule_id: "basic_auth_header",
|
|
27305
|
+
regex: /Authorization\s*[:=]\s*Basic\s+([A-Za-z0-9+/=]{8,})/gi,
|
|
27306
|
+
captureIndex: 1,
|
|
27307
|
+
slugHint: "basic_auth"
|
|
27308
|
+
},
|
|
27297
27309
|
{
|
|
27298
27310
|
rule_id: "pem_private_key",
|
|
27299
27311
|
regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
@@ -27352,9 +27364,108 @@ function shannonEntropy(s) {
|
|
|
27352
27364
|
return h;
|
|
27353
27365
|
}
|
|
27354
27366
|
|
|
27367
|
+
// telegram-plugin/secret-detect/inert-values.ts
|
|
27368
|
+
var INERT_VALUE_RE = [
|
|
27369
|
+
/^\[REDACTED(?::[A-Za-z0-9_]+)?\]$/i,
|
|
27370
|
+
/^\$\{?[A-Za-z_][A-Za-z0-9_]*\}?$/,
|
|
27371
|
+
/^\{\{[^\n\r\u2028\u2029]*\}\}$/,
|
|
27372
|
+
/^<[^<>\n\r\u2028\u2029]*>$/,
|
|
27373
|
+
/^%[A-Za-z_][A-Za-z0-9_]*%$/,
|
|
27374
|
+
/^vault:[A-Za-z0-9_./-]*$/i,
|
|
27375
|
+
/^[*x•.]+$/i,
|
|
27376
|
+
/^(?:process\.env|import\.meta\.env|os\.environ)(?:\.[A-Za-z_$][A-Za-z0-9_$]*|\[["']?[A-Za-z_$][A-Za-z0-9_$]*["']?\])*$/,
|
|
27377
|
+
/^(?:changeme|change-me|replaceme|replace-me|placeholder|todo|tbd|yourkey|your-key|yourpassword|your-password|yoursecret|your-secret|yourtoken|your-token)(?:[-_][A-Za-z0-9-]+)?$/i,
|
|
27378
|
+
/^[a-z]+(?: [a-z]+){2,}$/
|
|
27379
|
+
];
|
|
27380
|
+
var CREDENTIAL_RUN_RE = /[A-Za-z0-9]{12,}/g;
|
|
27381
|
+
var MIXED_CLASS_RUN_MIN = 12;
|
|
27382
|
+
var SINGLE_CLASS_RUN_MIN = 16;
|
|
27383
|
+
function runIsCredentialShaped(run) {
|
|
27384
|
+
let classes = 0;
|
|
27385
|
+
if (/[a-z]/.test(run))
|
|
27386
|
+
classes++;
|
|
27387
|
+
if (/[A-Z]/.test(run))
|
|
27388
|
+
classes++;
|
|
27389
|
+
if (/[0-9]/.test(run))
|
|
27390
|
+
classes++;
|
|
27391
|
+
return run.length >= (classes >= 2 ? MIXED_CLASS_RUN_MIN : SINGLE_CLASS_RUN_MIN);
|
|
27392
|
+
}
|
|
27393
|
+
function hasCredentialShapedRun(value) {
|
|
27394
|
+
for (const run of value.match(CREDENTIAL_RUN_RE) ?? []) {
|
|
27395
|
+
if (runIsCredentialShaped(run))
|
|
27396
|
+
return true;
|
|
27397
|
+
}
|
|
27398
|
+
return false;
|
|
27399
|
+
}
|
|
27400
|
+
function isInertValue(value) {
|
|
27401
|
+
if (!INERT_VALUE_RE.some((re) => re.test(value)))
|
|
27402
|
+
return false;
|
|
27403
|
+
return !hasCredentialShapedRun(value);
|
|
27404
|
+
}
|
|
27405
|
+
var INERT_GATED_RULES = new Set([
|
|
27406
|
+
"env_key_value",
|
|
27407
|
+
"json_secret_field",
|
|
27408
|
+
"cli_flag"
|
|
27409
|
+
]);
|
|
27410
|
+
var TRAILING_PUNCT_RE = /[.,;:!?)\]}]+$/;
|
|
27411
|
+
function stripTrailingPunctuation(value) {
|
|
27412
|
+
return value.replace(TRAILING_PUNCT_RE, "");
|
|
27413
|
+
}
|
|
27414
|
+
|
|
27355
27415
|
// telegram-plugin/secret-detect/kv-scanner.ts
|
|
27356
27416
|
var KV_RE = /\b([A-Za-z_][A-Za-z0-9_-]*(?:password|passwd|token|secret|key|api[_-]?key))\s*[:=]\s*["']?([^\s"'\\]{8,})["']?/gi;
|
|
27357
27417
|
var KV_ENTROPY_THRESHOLD = 4;
|
|
27418
|
+
var MEMORABLE_PW_RE = /\b([A-Za-z0-9_-]*(?:password|passwd|passphrase|pwd))\b\s*(?:[:=]\s*|\s+is\s+)(["']?)([^\s"']{8,64})\2/gi;
|
|
27419
|
+
var MEMORABLE_PW_RULE_ID = "memorable_password";
|
|
27420
|
+
var MEMORABLE_PW_MIN_CLASSES = 2;
|
|
27421
|
+
function charClassCount(value) {
|
|
27422
|
+
let n = 0;
|
|
27423
|
+
if (/[a-z]/.test(value))
|
|
27424
|
+
n++;
|
|
27425
|
+
if (/[A-Z]/.test(value))
|
|
27426
|
+
n++;
|
|
27427
|
+
if (/[0-9]/.test(value))
|
|
27428
|
+
n++;
|
|
27429
|
+
if (/[^A-Za-z0-9]/.test(value))
|
|
27430
|
+
n++;
|
|
27431
|
+
return n;
|
|
27432
|
+
}
|
|
27433
|
+
function looksLikeMemorablePassword(value) {
|
|
27434
|
+
if (isInertValue(value))
|
|
27435
|
+
return false;
|
|
27436
|
+
const core = stripTrailingPunctuation(value);
|
|
27437
|
+
if (core.length < 8 || core.length > 64)
|
|
27438
|
+
return false;
|
|
27439
|
+
if (isInertValue(core))
|
|
27440
|
+
return false;
|
|
27441
|
+
if (new Set(core).size < 4)
|
|
27442
|
+
return false;
|
|
27443
|
+
return charClassCount(core) >= MEMORABLE_PW_MIN_CLASSES;
|
|
27444
|
+
}
|
|
27445
|
+
function scanMemorablePasswords(text) {
|
|
27446
|
+
const hits = [];
|
|
27447
|
+
MEMORABLE_PW_RE.lastIndex = 0;
|
|
27448
|
+
let m;
|
|
27449
|
+
while ((m = MEMORABLE_PW_RE.exec(text)) !== null) {
|
|
27450
|
+
const keyName = m[1];
|
|
27451
|
+
const value = m[3];
|
|
27452
|
+
if (!value || !looksLikeMemorablePassword(value))
|
|
27453
|
+
continue;
|
|
27454
|
+
const valueOffsetInMatch = m[0].indexOf(value, keyName.length);
|
|
27455
|
+
if (valueOffsetInMatch < 0)
|
|
27456
|
+
continue;
|
|
27457
|
+
const start = m.index + valueOffsetInMatch;
|
|
27458
|
+
hits.push({
|
|
27459
|
+
rule_id: MEMORABLE_PW_RULE_ID,
|
|
27460
|
+
start,
|
|
27461
|
+
end: start + value.length,
|
|
27462
|
+
matched_text: value,
|
|
27463
|
+
key_name: keyName,
|
|
27464
|
+
confidence: "ambiguous"
|
|
27465
|
+
});
|
|
27466
|
+
}
|
|
27467
|
+
return hits;
|
|
27468
|
+
}
|
|
27358
27469
|
function scanKeyValue(text) {
|
|
27359
27470
|
const hits = [];
|
|
27360
27471
|
KV_RE.lastIndex = 0;
|
|
@@ -27363,6 +27474,8 @@ function scanKeyValue(text) {
|
|
|
27363
27474
|
const [, keyName, value] = m;
|
|
27364
27475
|
if (!value)
|
|
27365
27476
|
continue;
|
|
27477
|
+
if (isInertValue(value))
|
|
27478
|
+
continue;
|
|
27366
27479
|
const h = shannonEntropy(value);
|
|
27367
27480
|
if (h < KV_ENTROPY_THRESHOLD)
|
|
27368
27481
|
continue;
|
|
@@ -27383,6 +27496,37 @@ function scanKeyValue(text) {
|
|
|
27383
27496
|
return hits;
|
|
27384
27497
|
}
|
|
27385
27498
|
|
|
27499
|
+
// telegram-plugin/secret-detect/db-uri.ts
|
|
27500
|
+
var DB_URI_RE = /\b([a-zA-Z][a-zA-Z0-9+.-]+):\/\/([^\s:/@]+):([^\s/?#]+)@([^\s/@?#]+)/g;
|
|
27501
|
+
var DB_URI_RULE_ID = "db_uri_password";
|
|
27502
|
+
function isInertPassword(value) {
|
|
27503
|
+
if (value.startsWith("[REDACTED"))
|
|
27504
|
+
return true;
|
|
27505
|
+
return /^[*x]+$/i.test(value);
|
|
27506
|
+
}
|
|
27507
|
+
function scanDbUris(text) {
|
|
27508
|
+
const hits = [];
|
|
27509
|
+
DB_URI_RE.lastIndex = 0;
|
|
27510
|
+
let m;
|
|
27511
|
+
while ((m = DB_URI_RE.exec(text)) !== null) {
|
|
27512
|
+
const scheme = m[1];
|
|
27513
|
+
const user = m[2];
|
|
27514
|
+
const password = m[3];
|
|
27515
|
+
if (isInertPassword(password))
|
|
27516
|
+
continue;
|
|
27517
|
+
const start = m.index + scheme.length + 3 + user.length + 1;
|
|
27518
|
+
hits.push({
|
|
27519
|
+
rule_id: DB_URI_RULE_ID,
|
|
27520
|
+
start,
|
|
27521
|
+
end: start + password.length,
|
|
27522
|
+
matched_text: password,
|
|
27523
|
+
key_name: `${scheme}_password`,
|
|
27524
|
+
confidence: "ambiguous"
|
|
27525
|
+
});
|
|
27526
|
+
}
|
|
27527
|
+
return hits;
|
|
27528
|
+
}
|
|
27529
|
+
|
|
27386
27530
|
// telegram-plugin/secret-detect/generic-entropy.ts
|
|
27387
27531
|
var CANDIDATE_RE = /[A-Za-z0-9]{28,}/g;
|
|
27388
27532
|
var GENERIC_MIN_DISTINCT = 18;
|
|
@@ -27556,6 +27700,8 @@ function detectSecrets(text) {
|
|
|
27556
27700
|
const globalStart = win.offset + matchStart;
|
|
27557
27701
|
const globalEnd = globalStart + cap.length;
|
|
27558
27702
|
const keyName = p.rule_id === "env_key_value" ? m[1] : undefined;
|
|
27703
|
+
if (INERT_GATED_RULES.has(p.rule_id) && isInertValue(cap))
|
|
27704
|
+
continue;
|
|
27559
27705
|
if (p.rule_id === "env_key_value") {
|
|
27560
27706
|
const ENV_KV_MIN_LEN = 12;
|
|
27561
27707
|
const ENV_KV_MIN_ENTROPY = 3.5;
|
|
@@ -27578,6 +27724,12 @@ function detectSecrets(text) {
|
|
|
27578
27724
|
for (const h of kvHits) {
|
|
27579
27725
|
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
27580
27726
|
}
|
|
27727
|
+
for (const h of scanDbUris(win.text)) {
|
|
27728
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
27729
|
+
}
|
|
27730
|
+
for (const h of scanMemorablePasswords(win.text)) {
|
|
27731
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
27732
|
+
}
|
|
27581
27733
|
const genHits = scanGenericSecrets(win.text);
|
|
27582
27734
|
for (const h of genHits) {
|
|
27583
27735
|
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
@@ -19220,6 +19220,9 @@ init_schema();
|
|
|
19220
19220
|
// src/config/users.ts
|
|
19221
19221
|
init_merge();
|
|
19222
19222
|
|
|
19223
|
+
// src/config/thinking-effort-risk.ts
|
|
19224
|
+
var RISKY_EFFORTS = new Set(["medium", "high", "xhigh", "max"]);
|
|
19225
|
+
|
|
19223
19226
|
// src/agents/scaffold.ts
|
|
19224
19227
|
init_merge();
|
|
19225
19228
|
init_timezone();
|
|
@@ -19341,12 +19344,15 @@ function pgMib(mib) {
|
|
|
19341
19344
|
}
|
|
19342
19345
|
var HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE";
|
|
19343
19346
|
var HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS";
|
|
19347
|
+
var HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC";
|
|
19348
|
+
var HINDSIGHT_PG_DEFAULT_FSYNC = "on";
|
|
19344
19349
|
var HINDSIGHT_PG_DEFAULTS = [
|
|
19345
19350
|
[
|
|
19346
19351
|
HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV,
|
|
19347
19352
|
pgMib(HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB)
|
|
19348
19353
|
],
|
|
19349
|
-
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)]
|
|
19354
|
+
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)],
|
|
19355
|
+
[HINDSIGHT_PG_FSYNC_ENV, HINDSIGHT_PG_DEFAULT_FSYNC]
|
|
19350
19356
|
];
|
|
19351
19357
|
var HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
|
|
19352
19358
|
|
|
@@ -19461,6 +19461,9 @@ init_schema();
|
|
|
19461
19461
|
// src/config/users.ts
|
|
19462
19462
|
init_merge();
|
|
19463
19463
|
|
|
19464
|
+
// src/config/thinking-effort-risk.ts
|
|
19465
|
+
var RISKY_EFFORTS = new Set(["medium", "high", "xhigh", "max"]);
|
|
19466
|
+
|
|
19464
19467
|
// src/agents/scaffold.ts
|
|
19465
19468
|
init_merge();
|
|
19466
19469
|
init_timezone();
|
|
@@ -19754,12 +19757,15 @@ function pgMib(mib) {
|
|
|
19754
19757
|
}
|
|
19755
19758
|
var HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE";
|
|
19756
19759
|
var HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS";
|
|
19760
|
+
var HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC";
|
|
19761
|
+
var HINDSIGHT_PG_DEFAULT_FSYNC = "on";
|
|
19757
19762
|
var HINDSIGHT_PG_DEFAULTS = [
|
|
19758
19763
|
[
|
|
19759
19764
|
HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV,
|
|
19760
19765
|
pgMib(HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB)
|
|
19761
19766
|
],
|
|
19762
|
-
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)]
|
|
19767
|
+
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)],
|
|
19768
|
+
[HINDSIGHT_PG_FSYNC_ENV, HINDSIGHT_PG_DEFAULT_FSYNC]
|
|
19763
19769
|
];
|
|
19764
19770
|
var HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
|
|
19765
19771
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchroom",
|
|
3
3
|
"//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
|
|
4
|
-
"version": "0.19.
|
|
4
|
+
"version": "0.19.36",
|
|
5
5
|
"description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -28,8 +28,10 @@
|
|
|
28
28
|
"test:vitest": "vitest run",
|
|
29
29
|
"test:bun": "bun test telegram-plugin/tests/agent-state-dir-preload.test.ts telegram-plugin/tests/catch-all-forwarded-history.test.ts src/vault/grants.test.ts src/vault/grants-db.test.ts src/vault/write-grants.test.ts src/vault/broker/server-grants.test.ts src/vault/broker/server-write-grants.test.ts src/vault/broker/server-scope-persist.test.ts src/vault/broker/server-tokenless-scope.test.ts src/vault/broker/server-mint-grant-passphrase-attest.test.ts src/vault/broker/server-passphrase-attest.test.ts src/vault/broker/server-mint-grant-posture-attest.test.ts src/vault/broker/server-admin-only-keys.test.ts src/vault/broker/client-token.test.ts src/vault/broker/server-unlock.test.ts src/vault/broker/auto-unlock.test.ts src/vault/broker/drift-detection.test.ts tests/vault-broker-passphrase.test.ts src/cli/vault-get-broker.test.ts src/vault/resolver-via-broker.test.ts src/vault/broker/scope.test.ts src/vault/broker/server.test.ts src/litellm/provision-apply-e2e.test.ts src/drive/disconnect.test.ts src/drive/grants.test.ts src/drive/oauth.test.ts src/drive/onboarding.test.ts src/drive/reconciler.test.ts src/drive/vault-slots.test.ts src/drive/wrapper.test.ts src/vault/approvals/kernel.test.ts src/vault/approvals/approval-origin.test.ts src/vault/approvals/self-approval-bypass.test.ts src/vault/approvals/schema-idempotent.test.ts src/vault/broker/server-approvals.test.ts telegram-plugin/tests/boot-probes.test.ts telegram-plugin/tests/boot-version-string.test.ts telegram-plugin/tests/history.test.ts telegram-plugin/tests/cross-turn-card-gate.test.ts telegram-plugin/tests/emission-authority-open-gate.test.ts telegram-plugin/tests/emission-authority-ping-gate.test.ts telegram-plugin/tests/emission-authority-card-drain-gate.test.ts telegram-plugin/tests/per-topic-current-turn.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/ipc-server-query-pending-permission.test.ts telegram-plugin/tests/ipc-server-check-pre-approved.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/registry/subagents-bugs.test.ts telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts telegram-plugin/tests/subagent-nested-dispatch.test.ts telegram-plugin/tests/nested-worker-visibility-harness.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resume-inbound-builder.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts telegram-plugin/tests/status-query-telemetry.test.ts telegram-plugin/tests/reaction-trigger.test.ts telegram-plugin/tests/reaction-trigger-flow.test.ts telegram-plugin/tests/subagent-watcher-workflow-visibility.test.ts telegram-plugin/uat/load-env.test.ts telegram-plugin/uat/feed-matcher.test.ts telegram-plugin/uat/uat-driver.test.ts telegram-plugin/gateway/webhook-ingest-server.test.ts telegram-plugin/tests/skill-proposal-card.test.ts",
|
|
30
30
|
"test:watch": "vitest",
|
|
31
|
-
"lint": "tsc --noEmit && node scripts/check-plugin-references.mjs && bash scripts/check-bot-api-wrapping.sh && node scripts/check-bun-test-imports.mjs && node scripts/check-test-runner-coverage.mjs && node scripts/check-bun-module-mock-scope.mjs && node scripts/check-no-pii-secrets.mjs && node scripts/check-vault-test-hermeticity.mjs && node scripts/check-auth-test-hermeticity.mjs && node scripts/check-agent-state-dir-hermeticity.mjs && node scripts/check-no-broadcast-delivery.mjs && node scripts/check-stale-tool-descriptions.mjs && node scripts/check-mcp-instructions-budget.mjs && node scripts/check-web-subscription-honest.mjs && node scripts/check-no-unpinned-npx-playwright.mjs && node scripts/check-gateway-line-ratchet.mjs && node scripts/check-retry-flood-hooks.mjs && node scripts/check-callback-ctx-wrapping.mjs && node scripts/check-status-pin-single-path.mjs && node scripts/check-litellm-config-guard.mjs && node scripts/check-release-asset-names.mjs && node scripts/check-agent-attribution-trailers.mjs",
|
|
31
|
+
"lint": "tsc --noEmit && node scripts/check-plugin-references.mjs && bash scripts/check-bot-api-wrapping.sh && node scripts/check-bun-test-imports.mjs && node scripts/check-test-runner-coverage.mjs && node scripts/check-bun-module-mock-scope.mjs && node scripts/check-no-pii-secrets.mjs && node scripts/check-vault-test-hermeticity.mjs && node scripts/check-auth-test-hermeticity.mjs && node scripts/check-agent-state-dir-hermeticity.mjs && node scripts/check-no-broadcast-delivery.mjs && node scripts/check-stale-tool-descriptions.mjs && node scripts/check-mcp-instructions-budget.mjs && node scripts/check-web-subscription-honest.mjs && node scripts/check-no-unpinned-npx-playwright.mjs && node scripts/check-gateway-line-ratchet.mjs && node scripts/check-retry-flood-hooks.mjs && node scripts/check-callback-ctx-wrapping.mjs && node scripts/check-status-pin-single-path.mjs && node scripts/check-litellm-config-guard.mjs && node scripts/check-release-asset-names.mjs && node scripts/check-agent-attribution-trailers.mjs && node scripts/check-hindsight-write-redaction.mjs && bun scripts/check-secret-pattern-parity.ts",
|
|
32
32
|
"lint:tsc": "tsc --noEmit",
|
|
33
|
+
"lint:hindsight-write-redaction": "node scripts/check-hindsight-write-redaction.mjs",
|
|
34
|
+
"lint:secret-pattern-parity": "bun scripts/check-secret-pattern-parity.ts",
|
|
33
35
|
"lint:plugin-references": "node scripts/check-plugin-references.mjs",
|
|
34
36
|
"lint:bot-api-wrapping": "bash scripts/check-bot-api-wrapping.sh",
|
|
35
37
|
"lint:bun-test-imports": "node scripts/check-bun-test-imports.mjs",
|
|
@@ -390,6 +390,10 @@ x-litellm-tags: agent:$SWITCHROOM_AGENT_NAME,profile:${SWITCHROOM_AGENT_PROFILE:
|
|
|
390
390
|
# ephemeral). Refresh-or-remove every boot so a stale snapshot can never
|
|
391
391
|
# re-apply a consumed override on a later restart.
|
|
392
392
|
rm -f "{{agentDir}}/.session-model.boot-snapshot" "{{agentDir}}/.session-model-boot-attempts.boot-snapshot"
|
|
393
|
+
# Resolution runs later, after the bounded LiteLLM probe. Remove the prior
|
|
394
|
+
# boot's completion barrier before forking the gateway so it cannot consume
|
|
395
|
+
# stale active-model/effort/alert files while this boot is still resolving.
|
|
396
|
+
rm -f "{{agentDir}}/.session-model-resolved"
|
|
393
397
|
if [ -f "{{agentDir}}/.session-model" ]; then
|
|
394
398
|
# A failed copy (ENOSPC, perms) must not be a SILENT drop — the resolution
|
|
395
399
|
# block still falls back to the live carrier, but the gateway may consume
|
|
@@ -1954,6 +1958,13 @@ rm -f "{{agentDir}}/.session-model.boot-snapshot" "{{agentDir}}/.session-model-b
|
|
|
1954
1958
|
# this guard covers only the configured default, which the live-config read
|
|
1955
1959
|
# above makes a mainline path (pinning `model: fable` in yaml is the normal
|
|
1956
1960
|
# way to run Fable).
|
|
1961
|
+
#
|
|
1962
|
+
# Snapshot the resolved model BEFORE this guard can rewrite it. _DECLARED_
|
|
1963
|
+
# ROUTING (below) must reflect this boot's actual INTENT — the resolved
|
|
1964
|
+
# override or configured default — not a post-demotion landing, or the exact
|
|
1965
|
+
# divergence this file exists to catch (missing key silently demoting
|
|
1966
|
+
# fable → opus) becomes invisible to the check built to catch it.
|
|
1967
|
+
_DECLARED_MODEL="$_EFFECTIVE_MODEL"
|
|
1957
1968
|
case "$_EFFECTIVE_MODEL" in
|
|
1958
1969
|
fable|claude-fable-5)
|
|
1959
1970
|
if [ -z "$_LITELLM_OK" ]; then
|
|
@@ -2080,23 +2091,27 @@ export SWITCHROOM_SESSION_MODEL="$_EFFECTIVE_MODEL"
|
|
|
2080
2091
|
#
|
|
2081
2092
|
# Deterministic record of WHERE this boot actually landed, written immediately
|
|
2082
2093
|
# before exec claude (overwrite-per-boot, one line). Consumers: the gateway
|
|
2083
|
-
# boot card's "routing" row and any operator shell. _DECLARED_ROUTING is
|
|
2084
|
-
#
|
|
2085
|
-
#
|
|
2086
|
-
#
|
|
2087
|
-
#
|
|
2094
|
+
# boot card's "routing" row and any operator shell. _DECLARED_ROUTING is derived
|
|
2095
|
+
# from $_DECLARED_MODEL (the resolved override/default snapshotted BEFORE the
|
|
2096
|
+
# missing-key opus demotion above), so a legitimate session override is
|
|
2097
|
+
# compared against its own POST-REPOINT intent rather than the configured
|
|
2098
|
+
# default's render-time model class — and a missing-key demotion still reads
|
|
2099
|
+
# as a genuine divergence instead of chasing its own landed model.
|
|
2088
2100
|
# Divergence (landed ≠ declared) appends a consume-once .session-model-alert
|
|
2089
2101
|
# line the gateway relays to the operator, but ONLY when the (landed, declared)
|
|
2090
2102
|
# PAIR differs from the PREVIOUS boot's pair — a persistently degraded agent
|
|
2091
2103
|
# alerts once, not on every restart, yet a declared-only flip (operator changes
|
|
2092
2104
|
# the configured model class while the agent stays stuck on the same wrong
|
|
2093
2105
|
# landed mode) still re-alerts.
|
|
2094
|
-
|
|
2095
|
-
#
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2106
|
+
if [ -z "${SWITCHROOM_LITELLM_DECLARED:-}" ]; then
|
|
2107
|
+
# No LiteLLM routing was configured for this agent at boot entry.
|
|
2108
|
+
_DECLARED_ROUTING="direct-oauth"
|
|
2109
|
+
else
|
|
2110
|
+
case "$_DECLARED_MODEL" in
|
|
2111
|
+
sr-*|fable|claude-fable-5) _DECLARED_ROUTING="router-root" ;;
|
|
2112
|
+
*) _DECLARED_ROUTING="passthrough" ;;
|
|
2113
|
+
esac
|
|
2114
|
+
fi
|
|
2100
2115
|
case "${ANTHROPIC_BASE_URL:-}" in
|
|
2101
2116
|
"") _ROUTING_MODE="direct-oauth" ;;
|
|
2102
2117
|
*/anthropic) _ROUTING_MODE="passthrough" ;;
|
|
@@ -2114,7 +2129,17 @@ echo "routing: $_routing_line" >&2
|
|
|
2114
2129
|
if [ "$_ROUTING_MODE" != "$_DECLARED_ROUTING" ] && { [ "$_ROUTING_MODE" != "$_prev_routing_mode" ] || [ "$_DECLARED_ROUTING" != "$_prev_declared_routing" ]; }; then
|
|
2115
2130
|
printf 'Routing divergence: this agent landed on `%s` (base `%s`, model `%s`) but its declared routing is `%s`. Check `%s/.routing-mode` and the boot log for the cause (LiteLLM key/provision or proxy reachability).\n' "$_ROUTING_MODE" "${ANTHROPIC_BASE_URL:-direct}" "$_EFFECTIVE_MODEL" "$_DECLARED_ROUTING" "{{agentDir}}" >> "{{agentDir}}/.session-model-alert" 2>/dev/null || true
|
|
2116
2131
|
fi
|
|
2117
|
-
unset _prev_routing_mode _prev_declared_routing _routing_line
|
|
2132
|
+
unset _prev_routing_mode _prev_declared_routing _routing_line _DECLARED_MODEL
|
|
2133
|
+
|
|
2134
|
+
# Publish completion only after every boot-resolution output is final: active
|
|
2135
|
+
# model, active effort, routing mode, and any alert append. Atomic rename keeps
|
|
2136
|
+
# the gateway from observing a partially-written barrier.
|
|
2137
|
+
_session_model_resolved_tmp="{{agentDir}}/.session-model-resolved.tmp.$$"
|
|
2138
|
+
if printf '%s\n' "$$" > "$_session_model_resolved_tmp" 2>/dev/null; then
|
|
2139
|
+
mv -f "$_session_model_resolved_tmp" "{{agentDir}}/.session-model-resolved" 2>/dev/null || true
|
|
2140
|
+
fi
|
|
2141
|
+
rm -f "$_session_model_resolved_tmp"
|
|
2142
|
+
unset _session_model_resolved_tmp
|
|
2118
2143
|
|
|
2119
2144
|
{{#if useSwitchroomPlugin}}
|
|
2120
2145
|
if [ -n "$APPEND_PROMPT" ]; then
|