switchroom 0.19.35 → 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/cli/skill-validate-pretool.mjs +15 -2
- package/dist/cli/switchroom.js +672 -441
- package/dist/host-control/main.js +149 -3
- package/package.json +4 -2
- package/profiles/_base/start.sh.hbs +37 -12
- package/telegram-plugin/dist/gateway/gateway.js +311 -93
- package/telegram-plugin/format.ts +70 -15
- package/telegram-plugin/gateway/gateway.ts +22 -29
- package/telegram-plugin/gateway/ipc-server.ts +18 -15
- package/telegram-plugin/gateway/model-command.ts +34 -0
- 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/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/tests/test_secret_redact.py +522 -0
package/dist/cli/switchroom.js
CHANGED
|
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
|
|
|
2120
2120
|
});
|
|
2121
2121
|
|
|
2122
2122
|
// src/build-info.ts
|
|
2123
|
-
var VERSION = "0.19.
|
|
2123
|
+
var VERSION = "0.19.36", COMMIT_SHA = "ba505b15";
|
|
2124
2124
|
|
|
2125
2125
|
// src/cli/resolve-version.ts
|
|
2126
2126
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -35532,7 +35532,7 @@ class AuthBrokerClient {
|
|
|
35532
35532
|
sock.once("error", onError);
|
|
35533
35533
|
sock.once("connect", () => {
|
|
35534
35534
|
sock.removeListener("error", onError);
|
|
35535
|
-
sock.on("data", (
|
|
35535
|
+
sock.on("data", (chunk2) => this.onData(chunk2));
|
|
35536
35536
|
sock.on("error", (err) => this.onSocketError(err));
|
|
35537
35537
|
sock.on("close", () => this.onSocketClose());
|
|
35538
35538
|
this.socket = sock;
|
|
@@ -35546,8 +35546,8 @@ class AuthBrokerClient {
|
|
|
35546
35546
|
this.connecting = null;
|
|
35547
35547
|
}
|
|
35548
35548
|
}
|
|
35549
|
-
onData(
|
|
35550
|
-
this.buffer +=
|
|
35549
|
+
onData(chunk2) {
|
|
35550
|
+
this.buffer += chunk2.toString("utf8");
|
|
35551
35551
|
let idx;
|
|
35552
35552
|
while ((idx = this.buffer.indexOf(`
|
|
35553
35553
|
`)) !== -1) {
|
|
@@ -39525,11 +39525,11 @@ function readAuditRaw(logPath, opts = {}) {
|
|
|
39525
39525
|
const gen = `${logPath}.${n}`;
|
|
39526
39526
|
if (!existsSync51(gen))
|
|
39527
39527
|
break;
|
|
39528
|
-
const
|
|
39529
|
-
if (
|
|
39528
|
+
const chunk2 = tailBytes(gen, budget, strict);
|
|
39529
|
+
if (chunk2.length === 0)
|
|
39530
39530
|
continue;
|
|
39531
|
-
chunks.push(
|
|
39532
|
-
budget -= Buffer.byteLength(
|
|
39531
|
+
chunks.push(chunk2);
|
|
39532
|
+
budget -= Buffer.byteLength(chunk2, "utf-8");
|
|
39533
39533
|
}
|
|
39534
39534
|
return chunks.reverse().filter((c) => c.length > 0).map((c) => c.endsWith(`
|
|
39535
39535
|
`) ? c : c + `
|
|
@@ -44451,8 +44451,8 @@ async function hostdRequest(opts, req) {
|
|
|
44451
44451
|
reject(err);
|
|
44452
44452
|
}
|
|
44453
44453
|
});
|
|
44454
|
-
socket.on("data", (
|
|
44455
|
-
buf +=
|
|
44454
|
+
socket.on("data", (chunk2) => {
|
|
44455
|
+
buf += chunk2.toString("utf8");
|
|
44456
44456
|
if (Buffer.byteLength(buf, "utf8") > MAX_FRAME_BYTES3 * 2) {
|
|
44457
44457
|
if (settled)
|
|
44458
44458
|
return;
|
|
@@ -71143,9 +71143,600 @@ import { execFileSync as execFileSync11 } from "node:child_process";
|
|
|
71143
71143
|
|
|
71144
71144
|
// src/agents/handoff-summarizer.ts
|
|
71145
71145
|
init_atomic();
|
|
71146
|
-
init_observation_scopes();
|
|
71147
71146
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync9, renameSync as renameSync7, mkdirSync as mkdirSync16, existsSync as existsSync23, statSync as statSync11, readdirSync as readdirSync10 } from "node:fs";
|
|
71148
71147
|
import { join as join18 } from "node:path";
|
|
71148
|
+
|
|
71149
|
+
// telegram-plugin/secret-detect/patterns.ts
|
|
71150
|
+
var ANCHORED_PATTERNS = [
|
|
71151
|
+
{ rule_id: "anthropic_api_key", regex: /\b(sk-ant-[A-Za-z0-9_-]{8,})\b/g, captureIndex: 1, slugHint: "anthropic_api_key" },
|
|
71152
|
+
{ rule_id: "anthropic_oauth_code", regex: /(?:^|\s)([A-Za-z0-9_-]{20,}#[A-Za-z0-9_-]{20,})(?=\s|$)/gm, captureIndex: 1, slugHint: "anthropic_oauth_code" },
|
|
71153
|
+
{ rule_id: "openai_api_key", regex: /\b(sk-[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: "openai_api_key" },
|
|
71154
|
+
{ rule_id: "github_pat_classic", regex: /\b(ghp_[A-Za-z0-9]{20,})\b/g, captureIndex: 1, slugHint: "github_pat" },
|
|
71155
|
+
{ rule_id: "github_pat_fine_grained", regex: /\b(github_pat_[A-Za-z0-9_]{20,})\b/g, captureIndex: 1, slugHint: "github_pat" },
|
|
71156
|
+
{ rule_id: "slack_token", regex: /\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g, captureIndex: 1, slugHint: "slack_token" },
|
|
71157
|
+
{ rule_id: "slack_app_token", regex: /\b(xapp-[A-Za-z0-9-]{10,})\b/g, captureIndex: 1, slugHint: "slack_app_token" },
|
|
71158
|
+
{ rule_id: "groq_api_key", regex: /\b(gsk_[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: "groq_api_key" },
|
|
71159
|
+
{ rule_id: "google_api_key", regex: /\b(AIza[0-9A-Za-z\-_]{20,})\b/g, captureIndex: 1, slugHint: "google_api_key" },
|
|
71160
|
+
{ rule_id: "perplexity_api_key", regex: /\b(pplx-[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: "perplexity_api_key" },
|
|
71161
|
+
{ rule_id: "npm_token", regex: /\b(npm_[A-Za-z0-9]{10,})\b/g, captureIndex: 1, slugHint: "npm_token" },
|
|
71162
|
+
{ rule_id: "telegram_bot_token_prefixed", regex: /\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: "telegram_bot_token" },
|
|
71163
|
+
{ rule_id: "telegram_bot_token", regex: /\b(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: "telegram_bot_token" },
|
|
71164
|
+
{ rule_id: "laravel_sanctum_token", regex: /\b(\d+\|[A-Za-z0-9]{40,})\b/g, captureIndex: 1, slugHint: "api_token" },
|
|
71165
|
+
{ rule_id: "aws_access_key", regex: /\b(AKIA[0-9A-Z]{16})\b/g, captureIndex: 1, slugHint: "aws_access_key" },
|
|
71166
|
+
{ rule_id: "jwt", regex: /\b(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: "jwt" }
|
|
71167
|
+
];
|
|
71168
|
+
var STRUCTURED_PATTERNS = [
|
|
71169
|
+
{
|
|
71170
|
+
rule_id: "env_key_value",
|
|
71171
|
+
regex: /\b([A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD))\b\s*[=:]\s*(["']?)([^\s"'\\]+)\2/g,
|
|
71172
|
+
captureIndex: 3,
|
|
71173
|
+
slugHint: "env"
|
|
71174
|
+
},
|
|
71175
|
+
{
|
|
71176
|
+
rule_id: "json_secret_field",
|
|
71177
|
+
regex: /"(?:apiKey|token|secret|password|passwd|accessToken|refreshToken)"\s*:\s*"([^"]+)"/g,
|
|
71178
|
+
captureIndex: 1,
|
|
71179
|
+
slugHint: "json_secret"
|
|
71180
|
+
},
|
|
71181
|
+
{
|
|
71182
|
+
rule_id: "cli_flag",
|
|
71183
|
+
regex: /--(?:api[-_]?key|hook[-_]?token|token|secret|password|passwd)\s+(["']?)([^\s"']+)\1/g,
|
|
71184
|
+
captureIndex: 2,
|
|
71185
|
+
slugHint: "cli_flag"
|
|
71186
|
+
},
|
|
71187
|
+
{
|
|
71188
|
+
rule_id: "bearer_auth_header",
|
|
71189
|
+
regex: /Authorization\s*[:=]\s*Bearer\s+([A-Za-z0-9._\-+=]+)/gi,
|
|
71190
|
+
captureIndex: 1,
|
|
71191
|
+
slugHint: "bearer_token"
|
|
71192
|
+
},
|
|
71193
|
+
{
|
|
71194
|
+
rule_id: "bearer_loose",
|
|
71195
|
+
regex: /\bBearer\s+([A-Za-z0-9._\-+=]{18,})\b/gi,
|
|
71196
|
+
captureIndex: 1,
|
|
71197
|
+
slugHint: "bearer_token"
|
|
71198
|
+
},
|
|
71199
|
+
{
|
|
71200
|
+
rule_id: "basic_auth_header",
|
|
71201
|
+
regex: /Authorization\s*[:=]\s*Basic\s+([A-Za-z0-9+/=]{8,})/gi,
|
|
71202
|
+
captureIndex: 1,
|
|
71203
|
+
slugHint: "basic_auth"
|
|
71204
|
+
},
|
|
71205
|
+
{
|
|
71206
|
+
rule_id: "pem_private_key",
|
|
71207
|
+
regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
71208
|
+
captureIndex: 0,
|
|
71209
|
+
slugHint: "pem_private_key"
|
|
71210
|
+
}
|
|
71211
|
+
];
|
|
71212
|
+
var PROVIDER_PATTERNS = [
|
|
71213
|
+
{ rule_id: "slack_webhook", regex: /(https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9_/]+)/g, captureIndex: 1, slugHint: "slack_webhook" },
|
|
71214
|
+
{ rule_id: "stripe_live_secret", regex: /\b(sk_live_[A-Za-z0-9]{24,})\b/g, captureIndex: 1, slugHint: "stripe_key" },
|
|
71215
|
+
{ rule_id: "stripe_restricted", regex: /\b(rk_live_[A-Za-z0-9]{24,})\b/g, captureIndex: 1, slugHint: "stripe_key" },
|
|
71216
|
+
{ rule_id: "sendgrid_api_key", regex: /\b(SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43})\b/g, captureIndex: 1, slugHint: "sendgrid_key" },
|
|
71217
|
+
{ rule_id: "gitlab_pat", regex: /\b(glpat-[A-Za-z0-9_-]{20})\b/g, captureIndex: 1, slugHint: "gitlab_pat" },
|
|
71218
|
+
{ rule_id: "huggingface_token", regex: /\b(hf_[A-Za-z0-9]{34,})\b/g, captureIndex: 1, slugHint: "huggingface_token" },
|
|
71219
|
+
{ rule_id: "twilio_api_key", regex: /\b(SK[0-9a-f]{32})\b/g, captureIndex: 1, slugHint: "twilio_api_key" },
|
|
71220
|
+
{ rule_id: "mailgun_key", regex: /\b(key-[0-9a-f]{32})\b/g, captureIndex: 1, slugHint: "mailgun_key" },
|
|
71221
|
+
{ rule_id: "digitalocean_pat", regex: /\b(dop_v1_[a-f0-9]{64})\b/g, captureIndex: 1, slugHint: "digitalocean_token" },
|
|
71222
|
+
{ rule_id: "digitalocean_oauth", regex: /\b(doo_v1_[a-f0-9]{64})\b/g, captureIndex: 1, slugHint: "digitalocean_token" },
|
|
71223
|
+
{ rule_id: "digitalocean_refresh", regex: /\b(dor_v1_[a-f0-9]{64})\b/g, captureIndex: 1, slugHint: "digitalocean_token" },
|
|
71224
|
+
{ rule_id: "doppler_token", regex: /\b(dp\.(?:pt|st|ct|sa|scim|audit)\.[A-Za-z0-9]{40,44})\b/g, captureIndex: 1, slugHint: "doppler_token" },
|
|
71225
|
+
{ rule_id: "linear_api_key", regex: /\b(lin_api_[A-Za-z0-9]{40})\b/g, captureIndex: 1, slugHint: "linear_api_key" },
|
|
71226
|
+
{ rule_id: "shopify_access_token", regex: /\b(shpat_[a-fA-F0-9]{32})\b/g, captureIndex: 1, slugHint: "shopify_token" },
|
|
71227
|
+
{ rule_id: "shopify_shared_secret", regex: /\b(shpss_[a-fA-F0-9]{32})\b/g, captureIndex: 1, slugHint: "shopify_token" },
|
|
71228
|
+
{ rule_id: "shopify_private_app", regex: /\b(shppa_[a-fA-F0-9]{32})\b/g, captureIndex: 1, slugHint: "shopify_token" },
|
|
71229
|
+
{ rule_id: "square_access_token", regex: /\b(sq0atp-[A-Za-z0-9_-]{22})\b/g, captureIndex: 1, slugHint: "square_token" },
|
|
71230
|
+
{ rule_id: "square_oauth_secret", regex: /\b(sq0csp-[A-Za-z0-9_-]{43})\b/g, captureIndex: 1, slugHint: "square_token" },
|
|
71231
|
+
{ rule_id: "newrelic_key", regex: /\b(NRAK-[A-Z0-9]{27})\b/g, captureIndex: 1, slugHint: "newrelic_key" },
|
|
71232
|
+
{ rule_id: "notion_token", regex: /\b(ntn_[A-Za-z0-9]{46})\b/g, captureIndex: 1, slugHint: "notion_token" },
|
|
71233
|
+
{ rule_id: "planetscale_password", regex: /\b(pscale_pw_[A-Za-z0-9_.-]{43})\b/g, captureIndex: 1, slugHint: "planetscale_token" },
|
|
71234
|
+
{ rule_id: "planetscale_token", regex: /\b(pscale_tkn_[A-Za-z0-9_.-]{43})\b/g, captureIndex: 1, slugHint: "planetscale_token" },
|
|
71235
|
+
{ rule_id: "supabase_service_key", regex: /\b(sbp_[a-f0-9]{40})\b/g, captureIndex: 1, slugHint: "supabase_key" },
|
|
71236
|
+
{ rule_id: "atlassian_token", regex: /\b(ATATT[A-Za-z0-9_\-=]{20,})\b/g, captureIndex: 1, slugHint: "atlassian_token" },
|
|
71237
|
+
{ rule_id: "dropbox_token", regex: /\b(sl\.[A-Za-z0-9_-]{130,})/g, captureIndex: 1, slugHint: "dropbox_token" },
|
|
71238
|
+
{ rule_id: "databricks_token", regex: /\b(dapi[a-f0-9]{32})\b/g, captureIndex: 1, slugHint: "databricks_token" },
|
|
71239
|
+
{ rule_id: "grafana_service_account", regex: /\b(glsa_[A-Za-z0-9]{32}_[a-fA-F0-9]{8})\b/g, captureIndex: 1, slugHint: "grafana_token" },
|
|
71240
|
+
{ rule_id: "pypi_token", regex: /\b(pypi-AgEIcHlwaS[A-Za-z0-9_-]{50,})/g, captureIndex: 1, slugHint: "pypi_token" },
|
|
71241
|
+
{ rule_id: "aws_temp_access_key", regex: /\b(ASIA[0-9A-Z]{16})\b/g, captureIndex: 1, slugHint: "aws_access_key" },
|
|
71242
|
+
{ rule_id: "gcp_oauth_token", regex: /\b(ya29\.[A-Za-z0-9_-]{30,})/g, captureIndex: 1, slugHint: "gcp_oauth_token" }
|
|
71243
|
+
];
|
|
71244
|
+
var ALL_PATTERNS = [...ANCHORED_PATTERNS, ...PROVIDER_PATTERNS, ...STRUCTURED_PATTERNS];
|
|
71245
|
+
|
|
71246
|
+
// telegram-plugin/secret-detect/entropy.ts
|
|
71247
|
+
function shannonEntropy(s) {
|
|
71248
|
+
if (s.length === 0)
|
|
71249
|
+
return 0;
|
|
71250
|
+
const counts = new Map;
|
|
71251
|
+
for (const ch of s) {
|
|
71252
|
+
counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
71253
|
+
}
|
|
71254
|
+
let h = 0;
|
|
71255
|
+
const len = s.length;
|
|
71256
|
+
for (const c of counts.values()) {
|
|
71257
|
+
const p = c / len;
|
|
71258
|
+
h -= p * Math.log2(p);
|
|
71259
|
+
}
|
|
71260
|
+
return h;
|
|
71261
|
+
}
|
|
71262
|
+
|
|
71263
|
+
// telegram-plugin/secret-detect/inert-values.ts
|
|
71264
|
+
var INERT_VALUE_RE = [
|
|
71265
|
+
/^\[REDACTED(?::[A-Za-z0-9_]+)?\]$/i,
|
|
71266
|
+
/^\$\{?[A-Za-z_][A-Za-z0-9_]*\}?$/,
|
|
71267
|
+
/^\{\{[^\n\r\u2028\u2029]*\}\}$/,
|
|
71268
|
+
/^<[^<>\n\r\u2028\u2029]*>$/,
|
|
71269
|
+
/^%[A-Za-z_][A-Za-z0-9_]*%$/,
|
|
71270
|
+
/^vault:[A-Za-z0-9_./-]*$/i,
|
|
71271
|
+
/^[*x\u2022.]+$/i,
|
|
71272
|
+
/^(?:process\.env|import\.meta\.env|os\.environ)(?:\.[A-Za-z_$][A-Za-z0-9_$]*|\[["']?[A-Za-z_$][A-Za-z0-9_$]*["']?\])*$/,
|
|
71273
|
+
/^(?: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,
|
|
71274
|
+
/^[a-z]+(?: [a-z]+){2,}$/
|
|
71275
|
+
];
|
|
71276
|
+
var CREDENTIAL_RUN_RE = /[A-Za-z0-9]{12,}/g;
|
|
71277
|
+
var MIXED_CLASS_RUN_MIN = 12;
|
|
71278
|
+
var SINGLE_CLASS_RUN_MIN = 16;
|
|
71279
|
+
function runIsCredentialShaped(run) {
|
|
71280
|
+
let classes = 0;
|
|
71281
|
+
if (/[a-z]/.test(run))
|
|
71282
|
+
classes++;
|
|
71283
|
+
if (/[A-Z]/.test(run))
|
|
71284
|
+
classes++;
|
|
71285
|
+
if (/[0-9]/.test(run))
|
|
71286
|
+
classes++;
|
|
71287
|
+
return run.length >= (classes >= 2 ? MIXED_CLASS_RUN_MIN : SINGLE_CLASS_RUN_MIN);
|
|
71288
|
+
}
|
|
71289
|
+
function hasCredentialShapedRun(value) {
|
|
71290
|
+
for (const run of value.match(CREDENTIAL_RUN_RE) ?? []) {
|
|
71291
|
+
if (runIsCredentialShaped(run))
|
|
71292
|
+
return true;
|
|
71293
|
+
}
|
|
71294
|
+
return false;
|
|
71295
|
+
}
|
|
71296
|
+
function isInertValue(value) {
|
|
71297
|
+
if (!INERT_VALUE_RE.some((re) => re.test(value)))
|
|
71298
|
+
return false;
|
|
71299
|
+
return !hasCredentialShapedRun(value);
|
|
71300
|
+
}
|
|
71301
|
+
var INERT_GATED_RULES = new Set([
|
|
71302
|
+
"env_key_value",
|
|
71303
|
+
"json_secret_field",
|
|
71304
|
+
"cli_flag"
|
|
71305
|
+
]);
|
|
71306
|
+
var TRAILING_PUNCT_RE = /[.,;:!?)\]}]+$/;
|
|
71307
|
+
function stripTrailingPunctuation(value) {
|
|
71308
|
+
return value.replace(TRAILING_PUNCT_RE, "");
|
|
71309
|
+
}
|
|
71310
|
+
|
|
71311
|
+
// telegram-plugin/secret-detect/kv-scanner.ts
|
|
71312
|
+
var KV_RE = /\b([A-Za-z_][A-Za-z0-9_-]*(?:password|passwd|token|secret|key|api[_-]?key))\s*[:=]\s*["']?([^\s"'\\]{8,})["']?/gi;
|
|
71313
|
+
var KV_ENTROPY_THRESHOLD = 4;
|
|
71314
|
+
var MEMORABLE_PW_RE = /\b([A-Za-z0-9_-]*(?:password|passwd|passphrase|pwd))\b\s*(?:[:=]\s*|\s+is\s+)(["']?)([^\s"']{8,64})\2/gi;
|
|
71315
|
+
var MEMORABLE_PW_RULE_ID = "memorable_password";
|
|
71316
|
+
var MEMORABLE_PW_MIN_CLASSES = 2;
|
|
71317
|
+
function charClassCount(value) {
|
|
71318
|
+
let n = 0;
|
|
71319
|
+
if (/[a-z]/.test(value))
|
|
71320
|
+
n++;
|
|
71321
|
+
if (/[A-Z]/.test(value))
|
|
71322
|
+
n++;
|
|
71323
|
+
if (/[0-9]/.test(value))
|
|
71324
|
+
n++;
|
|
71325
|
+
if (/[^A-Za-z0-9]/.test(value))
|
|
71326
|
+
n++;
|
|
71327
|
+
return n;
|
|
71328
|
+
}
|
|
71329
|
+
function looksLikeMemorablePassword(value) {
|
|
71330
|
+
if (isInertValue(value))
|
|
71331
|
+
return false;
|
|
71332
|
+
const core = stripTrailingPunctuation(value);
|
|
71333
|
+
if (core.length < 8 || core.length > 64)
|
|
71334
|
+
return false;
|
|
71335
|
+
if (isInertValue(core))
|
|
71336
|
+
return false;
|
|
71337
|
+
if (new Set(core).size < 4)
|
|
71338
|
+
return false;
|
|
71339
|
+
return charClassCount(core) >= MEMORABLE_PW_MIN_CLASSES;
|
|
71340
|
+
}
|
|
71341
|
+
function scanMemorablePasswords(text) {
|
|
71342
|
+
const hits = [];
|
|
71343
|
+
MEMORABLE_PW_RE.lastIndex = 0;
|
|
71344
|
+
let m;
|
|
71345
|
+
while ((m = MEMORABLE_PW_RE.exec(text)) !== null) {
|
|
71346
|
+
const keyName = m[1];
|
|
71347
|
+
const value = m[3];
|
|
71348
|
+
if (!value || !looksLikeMemorablePassword(value))
|
|
71349
|
+
continue;
|
|
71350
|
+
const valueOffsetInMatch = m[0].indexOf(value, keyName.length);
|
|
71351
|
+
if (valueOffsetInMatch < 0)
|
|
71352
|
+
continue;
|
|
71353
|
+
const start = m.index + valueOffsetInMatch;
|
|
71354
|
+
hits.push({
|
|
71355
|
+
rule_id: MEMORABLE_PW_RULE_ID,
|
|
71356
|
+
start,
|
|
71357
|
+
end: start + value.length,
|
|
71358
|
+
matched_text: value,
|
|
71359
|
+
key_name: keyName,
|
|
71360
|
+
confidence: "ambiguous"
|
|
71361
|
+
});
|
|
71362
|
+
}
|
|
71363
|
+
return hits;
|
|
71364
|
+
}
|
|
71365
|
+
function scanKeyValue(text) {
|
|
71366
|
+
const hits = [];
|
|
71367
|
+
KV_RE.lastIndex = 0;
|
|
71368
|
+
let m;
|
|
71369
|
+
while ((m = KV_RE.exec(text)) !== null) {
|
|
71370
|
+
const [, keyName, value] = m;
|
|
71371
|
+
if (!value)
|
|
71372
|
+
continue;
|
|
71373
|
+
if (isInertValue(value))
|
|
71374
|
+
continue;
|
|
71375
|
+
const h = shannonEntropy(value);
|
|
71376
|
+
if (h < KV_ENTROPY_THRESHOLD)
|
|
71377
|
+
continue;
|
|
71378
|
+
const valueOffsetInMatch = m[0].indexOf(value, keyName.length);
|
|
71379
|
+
if (valueOffsetInMatch < 0)
|
|
71380
|
+
continue;
|
|
71381
|
+
const start = m.index + valueOffsetInMatch;
|
|
71382
|
+
const end = start + value.length;
|
|
71383
|
+
hits.push({
|
|
71384
|
+
rule_id: "kv_entropy",
|
|
71385
|
+
start,
|
|
71386
|
+
end,
|
|
71387
|
+
matched_text: value,
|
|
71388
|
+
key_name: keyName,
|
|
71389
|
+
confidence: "ambiguous"
|
|
71390
|
+
});
|
|
71391
|
+
}
|
|
71392
|
+
return hits;
|
|
71393
|
+
}
|
|
71394
|
+
|
|
71395
|
+
// telegram-plugin/secret-detect/db-uri.ts
|
|
71396
|
+
var DB_URI_RE = /\b([a-zA-Z][a-zA-Z0-9+.-]+):\/\/([^\s:/@]+):([^\s/?#]+)@([^\s/@?#]+)/g;
|
|
71397
|
+
var DB_URI_RULE_ID = "db_uri_password";
|
|
71398
|
+
function isInertPassword(value) {
|
|
71399
|
+
if (value.startsWith("[REDACTED"))
|
|
71400
|
+
return true;
|
|
71401
|
+
return /^[*x]+$/i.test(value);
|
|
71402
|
+
}
|
|
71403
|
+
function scanDbUris(text) {
|
|
71404
|
+
const hits = [];
|
|
71405
|
+
DB_URI_RE.lastIndex = 0;
|
|
71406
|
+
let m;
|
|
71407
|
+
while ((m = DB_URI_RE.exec(text)) !== null) {
|
|
71408
|
+
const scheme = m[1];
|
|
71409
|
+
const user = m[2];
|
|
71410
|
+
const password = m[3];
|
|
71411
|
+
if (isInertPassword(password))
|
|
71412
|
+
continue;
|
|
71413
|
+
const start = m.index + scheme.length + 3 + user.length + 1;
|
|
71414
|
+
hits.push({
|
|
71415
|
+
rule_id: DB_URI_RULE_ID,
|
|
71416
|
+
start,
|
|
71417
|
+
end: start + password.length,
|
|
71418
|
+
matched_text: password,
|
|
71419
|
+
key_name: `${scheme}_password`,
|
|
71420
|
+
confidence: "ambiguous"
|
|
71421
|
+
});
|
|
71422
|
+
}
|
|
71423
|
+
return hits;
|
|
71424
|
+
}
|
|
71425
|
+
|
|
71426
|
+
// telegram-plugin/secret-detect/generic-entropy.ts
|
|
71427
|
+
var CANDIDATE_RE = /[A-Za-z0-9]{28,}/g;
|
|
71428
|
+
var GENERIC_MIN_DISTINCT = 18;
|
|
71429
|
+
var MAX_GENERIC_HITS = 20;
|
|
71430
|
+
function hasDistinctChars(tok, n) {
|
|
71431
|
+
const seen = new Uint8Array(128);
|
|
71432
|
+
let distinct = 0;
|
|
71433
|
+
for (let i = 0;i < tok.length; i++) {
|
|
71434
|
+
const c = tok.charCodeAt(i);
|
|
71435
|
+
if (seen[c] === 0) {
|
|
71436
|
+
seen[c] = 1;
|
|
71437
|
+
if (++distinct >= n)
|
|
71438
|
+
return true;
|
|
71439
|
+
}
|
|
71440
|
+
}
|
|
71441
|
+
return false;
|
|
71442
|
+
}
|
|
71443
|
+
function hasDigit(tok) {
|
|
71444
|
+
for (let i = 0;i < tok.length; i++) {
|
|
71445
|
+
const c = tok.charCodeAt(i);
|
|
71446
|
+
if (c >= 48 && c <= 57)
|
|
71447
|
+
return true;
|
|
71448
|
+
}
|
|
71449
|
+
return false;
|
|
71450
|
+
}
|
|
71451
|
+
function scanGenericSecrets(text) {
|
|
71452
|
+
const hits = [];
|
|
71453
|
+
CANDIDATE_RE.lastIndex = 0;
|
|
71454
|
+
let m;
|
|
71455
|
+
while ((m = CANDIDATE_RE.exec(text)) !== null) {
|
|
71456
|
+
if (hits.length >= MAX_GENERIC_HITS)
|
|
71457
|
+
break;
|
|
71458
|
+
const tok = m[0];
|
|
71459
|
+
if (!hasDigit(tok))
|
|
71460
|
+
continue;
|
|
71461
|
+
if (!hasDistinctChars(tok, GENERIC_MIN_DISTINCT))
|
|
71462
|
+
continue;
|
|
71463
|
+
hits.push({
|
|
71464
|
+
rule_id: "generic_high_entropy",
|
|
71465
|
+
start: m.index,
|
|
71466
|
+
end: m.index + tok.length,
|
|
71467
|
+
matched_text: tok,
|
|
71468
|
+
confidence: "ambiguous"
|
|
71469
|
+
});
|
|
71470
|
+
}
|
|
71471
|
+
return hits;
|
|
71472
|
+
}
|
|
71473
|
+
|
|
71474
|
+
// telegram-plugin/secret-detect/chunker.ts
|
|
71475
|
+
var CHUNK_THRESHOLD = 32 * 1024;
|
|
71476
|
+
var WINDOW_SIZE = 16 * 1024;
|
|
71477
|
+
var OVERLAP = 8 * 1024;
|
|
71478
|
+
function chunk(text) {
|
|
71479
|
+
if (text.length <= CHUNK_THRESHOLD) {
|
|
71480
|
+
return [{ offset: 0, text }];
|
|
71481
|
+
}
|
|
71482
|
+
const out = [];
|
|
71483
|
+
let offset = 0;
|
|
71484
|
+
while (offset < text.length) {
|
|
71485
|
+
const end = Math.min(offset + WINDOW_SIZE, text.length);
|
|
71486
|
+
out.push({ offset, text: text.slice(offset, end) });
|
|
71487
|
+
if (end >= text.length)
|
|
71488
|
+
break;
|
|
71489
|
+
offset = end - OVERLAP;
|
|
71490
|
+
}
|
|
71491
|
+
return out;
|
|
71492
|
+
}
|
|
71493
|
+
|
|
71494
|
+
// telegram-plugin/secret-detect/suppressor.ts
|
|
71495
|
+
var MARKERS = ["test", "mock", "example", "fixture", "dummy"];
|
|
71496
|
+
var WINDOW = 40;
|
|
71497
|
+
var MARKER_RE = new RegExp(`\\b(?:${MARKERS.join("|")})\\b`, "i");
|
|
71498
|
+
function isSuppressed(text, start, end) {
|
|
71499
|
+
const left = Math.max(0, start - WINDOW);
|
|
71500
|
+
const right = Math.min(text.length, end + WINDOW);
|
|
71501
|
+
const context = text.slice(left, start) + text.slice(end, right);
|
|
71502
|
+
return MARKER_RE.test(context);
|
|
71503
|
+
}
|
|
71504
|
+
|
|
71505
|
+
// telegram-plugin/secret-detect/slug.ts
|
|
71506
|
+
function sanitizeKeyName(raw) {
|
|
71507
|
+
const up = raw.toUpperCase();
|
|
71508
|
+
const cleaned = up.replace(/[^A-Z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
71509
|
+
return cleaned.length > 0 ? cleaned : "SECRET";
|
|
71510
|
+
}
|
|
71511
|
+
function datePart(now = new Date) {
|
|
71512
|
+
const y = now.getUTCFullYear();
|
|
71513
|
+
const m = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
71514
|
+
const d = String(now.getUTCDate()).padStart(2, "0");
|
|
71515
|
+
return `${y}${m}${d}`;
|
|
71516
|
+
}
|
|
71517
|
+
function deriveSlug(inputs, existing) {
|
|
71518
|
+
let base;
|
|
71519
|
+
if (inputs.key_name && inputs.key_name.trim().length > 0) {
|
|
71520
|
+
base = sanitizeKeyName(inputs.key_name);
|
|
71521
|
+
} else {
|
|
71522
|
+
base = `${inputs.rule_id}_${datePart(inputs.now)}`;
|
|
71523
|
+
}
|
|
71524
|
+
if (!existing.has(base))
|
|
71525
|
+
return base;
|
|
71526
|
+
let n = 2;
|
|
71527
|
+
while (existing.has(`${base}_${n}`))
|
|
71528
|
+
n++;
|
|
71529
|
+
return `${base}_${n}`;
|
|
71530
|
+
}
|
|
71531
|
+
// telegram-plugin/secret-detect/url-redact.ts
|
|
71532
|
+
var SENSITIVE_PARAMS = new Set([
|
|
71533
|
+
"token",
|
|
71534
|
+
"key",
|
|
71535
|
+
"api_key",
|
|
71536
|
+
"apikey",
|
|
71537
|
+
"secret",
|
|
71538
|
+
"access_token",
|
|
71539
|
+
"password",
|
|
71540
|
+
"pass",
|
|
71541
|
+
"auth",
|
|
71542
|
+
"client_secret",
|
|
71543
|
+
"refresh_token",
|
|
71544
|
+
"signature"
|
|
71545
|
+
]);
|
|
71546
|
+
var URL_RE = /\b(?:https?|wss?|ftp):\/\/[^\s<>"']+/gi;
|
|
71547
|
+
function redactUrls(text) {
|
|
71548
|
+
return text.replace(URL_RE, (m) => {
|
|
71549
|
+
const redacted = redactOne(m);
|
|
71550
|
+
return redacted ?? m;
|
|
71551
|
+
});
|
|
71552
|
+
}
|
|
71553
|
+
function redactOne(raw) {
|
|
71554
|
+
let u;
|
|
71555
|
+
try {
|
|
71556
|
+
u = new URL(raw);
|
|
71557
|
+
} catch {
|
|
71558
|
+
return null;
|
|
71559
|
+
}
|
|
71560
|
+
let changed = false;
|
|
71561
|
+
if (u.username || u.password) {
|
|
71562
|
+
u.username = "***";
|
|
71563
|
+
u.password = "";
|
|
71564
|
+
changed = true;
|
|
71565
|
+
}
|
|
71566
|
+
for (const [key] of u.searchParams) {
|
|
71567
|
+
if (SENSITIVE_PARAMS.has(key.toLowerCase())) {
|
|
71568
|
+
u.searchParams.set(key, "***");
|
|
71569
|
+
changed = true;
|
|
71570
|
+
}
|
|
71571
|
+
}
|
|
71572
|
+
return changed ? u.toString() : null;
|
|
71573
|
+
}
|
|
71574
|
+
|
|
71575
|
+
// telegram-plugin/secret-detect/index.ts
|
|
71576
|
+
function detectSecrets(text) {
|
|
71577
|
+
if (!text || text.length === 0)
|
|
71578
|
+
return [];
|
|
71579
|
+
const windows = chunk(text);
|
|
71580
|
+
const raw = [];
|
|
71581
|
+
for (const win of windows) {
|
|
71582
|
+
for (const p of ALL_PATTERNS) {
|
|
71583
|
+
const re = new RegExp(p.regex.source, p.regex.flags.includes("g") ? p.regex.flags : p.regex.flags + "g");
|
|
71584
|
+
let m;
|
|
71585
|
+
while ((m = re.exec(win.text)) !== null) {
|
|
71586
|
+
if (m[0].length === 0) {
|
|
71587
|
+
re.lastIndex++;
|
|
71588
|
+
continue;
|
|
71589
|
+
}
|
|
71590
|
+
const cap = p.captureIndex === 0 ? m[0] : m[p.captureIndex];
|
|
71591
|
+
if (!cap)
|
|
71592
|
+
continue;
|
|
71593
|
+
const matchStart = p.captureIndex === 0 ? m.index : m.index + m[0].indexOf(cap);
|
|
71594
|
+
if (matchStart < 0)
|
|
71595
|
+
continue;
|
|
71596
|
+
const globalStart = win.offset + matchStart;
|
|
71597
|
+
const globalEnd = globalStart + cap.length;
|
|
71598
|
+
const keyName = p.rule_id === "env_key_value" ? m[1] : undefined;
|
|
71599
|
+
if (INERT_GATED_RULES.has(p.rule_id) && isInertValue(cap))
|
|
71600
|
+
continue;
|
|
71601
|
+
if (p.rule_id === "env_key_value") {
|
|
71602
|
+
const ENV_KV_MIN_LEN = 12;
|
|
71603
|
+
const ENV_KV_MIN_ENTROPY = 3.5;
|
|
71604
|
+
if (cap.length < ENV_KV_MIN_LEN)
|
|
71605
|
+
continue;
|
|
71606
|
+
if (shannonEntropy(cap) < ENV_KV_MIN_ENTROPY)
|
|
71607
|
+
continue;
|
|
71608
|
+
}
|
|
71609
|
+
raw.push({
|
|
71610
|
+
rule_id: p.rule_id,
|
|
71611
|
+
start: globalStart,
|
|
71612
|
+
end: globalEnd,
|
|
71613
|
+
matched_text: cap,
|
|
71614
|
+
key_name: keyName,
|
|
71615
|
+
confidence: "high"
|
|
71616
|
+
});
|
|
71617
|
+
}
|
|
71618
|
+
}
|
|
71619
|
+
const kvHits = scanKeyValue(win.text);
|
|
71620
|
+
for (const h of kvHits) {
|
|
71621
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
71622
|
+
}
|
|
71623
|
+
for (const h of scanDbUris(win.text)) {
|
|
71624
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
71625
|
+
}
|
|
71626
|
+
for (const h of scanMemorablePasswords(win.text)) {
|
|
71627
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
71628
|
+
}
|
|
71629
|
+
const genHits = scanGenericSecrets(win.text);
|
|
71630
|
+
for (const h of genHits) {
|
|
71631
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
71632
|
+
}
|
|
71633
|
+
}
|
|
71634
|
+
const deduped = dedupeRaw(raw);
|
|
71635
|
+
const final = dropOverlaps(deduped);
|
|
71636
|
+
const existing = new Set;
|
|
71637
|
+
const out = [];
|
|
71638
|
+
for (const h of final) {
|
|
71639
|
+
const suggested_slug = deriveSlug({ key_name: h.key_name, rule_id: h.rule_id }, existing);
|
|
71640
|
+
existing.add(suggested_slug);
|
|
71641
|
+
out.push({
|
|
71642
|
+
rule_id: h.rule_id,
|
|
71643
|
+
matched_text: h.matched_text,
|
|
71644
|
+
start: h.start,
|
|
71645
|
+
end: h.end,
|
|
71646
|
+
confidence: h.confidence,
|
|
71647
|
+
suppressed: isSuppressed(text, h.start, h.end),
|
|
71648
|
+
suggested_slug,
|
|
71649
|
+
key_name: h.key_name
|
|
71650
|
+
});
|
|
71651
|
+
}
|
|
71652
|
+
out.sort((a, b) => a.start - b.start);
|
|
71653
|
+
return out;
|
|
71654
|
+
}
|
|
71655
|
+
function dedupeRaw(raw) {
|
|
71656
|
+
const seen = new Map;
|
|
71657
|
+
for (const h of raw) {
|
|
71658
|
+
const key = `${h.start}:${h.end}`;
|
|
71659
|
+
const existing = seen.get(key);
|
|
71660
|
+
if (!existing) {
|
|
71661
|
+
seen.set(key, h);
|
|
71662
|
+
continue;
|
|
71663
|
+
}
|
|
71664
|
+
if (existing.confidence === "ambiguous" && h.confidence === "high") {
|
|
71665
|
+
seen.set(key, h);
|
|
71666
|
+
}
|
|
71667
|
+
}
|
|
71668
|
+
return Array.from(seen.values());
|
|
71669
|
+
}
|
|
71670
|
+
function dropOverlaps(hits) {
|
|
71671
|
+
const out = hits.filter((h) => !(h.confidence === "ambiguous" && hits.some((o) => o !== h && o.start <= h.start && o.end >= h.end && !(o.start === h.start && o.end === h.end))));
|
|
71672
|
+
out.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
71673
|
+
return out;
|
|
71674
|
+
}
|
|
71675
|
+
|
|
71676
|
+
// telegram-plugin/secret-detect/redact.ts
|
|
71677
|
+
var REDACTED_MARKER = "[REDACTED]";
|
|
71678
|
+
function redact(text) {
|
|
71679
|
+
if (!text || text.length === 0)
|
|
71680
|
+
return text;
|
|
71681
|
+
const urlScrubbed = redactUrls(text);
|
|
71682
|
+
const hits = detectSecrets(urlScrubbed).filter((h) => h.rule_id !== "generic_high_entropy");
|
|
71683
|
+
if (hits.length === 0)
|
|
71684
|
+
return urlScrubbed;
|
|
71685
|
+
const sorted = [...hits].sort((a, b) => b.start - a.start);
|
|
71686
|
+
let out = urlScrubbed;
|
|
71687
|
+
for (const h of sorted) {
|
|
71688
|
+
out = out.slice(0, h.start) + redactedMarker(h.rule_id) + out.slice(h.end);
|
|
71689
|
+
}
|
|
71690
|
+
return out;
|
|
71691
|
+
}
|
|
71692
|
+
function redactedMarker(ruleId) {
|
|
71693
|
+
const trimmed = ruleId.replace(/^(kv|env)_/, "");
|
|
71694
|
+
if (!trimmed || trimmed === "key_value" || trimmed === "kv_entropy") {
|
|
71695
|
+
return REDACTED_MARKER;
|
|
71696
|
+
}
|
|
71697
|
+
return `[REDACTED:${trimmed}]`;
|
|
71698
|
+
}
|
|
71699
|
+
// src/memory/hindsight-write-redaction.ts
|
|
71700
|
+
function redactJsonStrings(value) {
|
|
71701
|
+
if (typeof value === "string")
|
|
71702
|
+
return redact(value);
|
|
71703
|
+
if (Array.isArray(value))
|
|
71704
|
+
return value.map(redactJsonStrings);
|
|
71705
|
+
if (value && typeof value === "object") {
|
|
71706
|
+
const out = {};
|
|
71707
|
+
for (const [k, v] of Object.entries(value)) {
|
|
71708
|
+
out[k] = redactJsonStrings(v);
|
|
71709
|
+
}
|
|
71710
|
+
return out;
|
|
71711
|
+
}
|
|
71712
|
+
return value;
|
|
71713
|
+
}
|
|
71714
|
+
var REDACTED_ITEM_FIELDS = ["content", "context"];
|
|
71715
|
+
function redactMemoryWriteBody(body) {
|
|
71716
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
71717
|
+
return body;
|
|
71718
|
+
const src = body;
|
|
71719
|
+
if (!Array.isArray(src.items))
|
|
71720
|
+
return body;
|
|
71721
|
+
const items = src.items.map((item) => {
|
|
71722
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
71723
|
+
return item;
|
|
71724
|
+
const row = { ...item };
|
|
71725
|
+
for (const field of REDACTED_ITEM_FIELDS) {
|
|
71726
|
+
if (typeof row[field] === "string") {
|
|
71727
|
+
row[field] = redact(row[field]);
|
|
71728
|
+
}
|
|
71729
|
+
}
|
|
71730
|
+
if (row.metadata && typeof row.metadata === "object") {
|
|
71731
|
+
row.metadata = redactJsonStrings(row.metadata);
|
|
71732
|
+
}
|
|
71733
|
+
return row;
|
|
71734
|
+
});
|
|
71735
|
+
return { ...src, items };
|
|
71736
|
+
}
|
|
71737
|
+
|
|
71738
|
+
// src/agents/handoff-summarizer.ts
|
|
71739
|
+
init_observation_scopes();
|
|
71149
71740
|
var HANDOFF_STATUS_MIRROR_SKIPPED = "mirror-skipped-invalid-scope";
|
|
71150
71741
|
var DEFAULT_MAX_TURNS = 50;
|
|
71151
71742
|
var TOPIC_MAX_CHARS = 117;
|
|
@@ -71332,7 +71923,7 @@ async function mirrorToHindsight(briefing, opts) {
|
|
|
71332
71923
|
`);
|
|
71333
71924
|
return false;
|
|
71334
71925
|
}
|
|
71335
|
-
const body = {
|
|
71926
|
+
const body = redactMemoryWriteBody({
|
|
71336
71927
|
items: [
|
|
71337
71928
|
{
|
|
71338
71929
|
content: briefing,
|
|
@@ -71342,7 +71933,7 @@ async function mirrorToHindsight(briefing, opts) {
|
|
|
71342
71933
|
}
|
|
71343
71934
|
],
|
|
71344
71935
|
async: true
|
|
71345
|
-
};
|
|
71936
|
+
});
|
|
71346
71937
|
try {
|
|
71347
71938
|
await fetchFn(endpoint, {
|
|
71348
71939
|
method: "POST",
|
|
@@ -74348,8 +74939,8 @@ Bootstrapping agent: ${name}
|
|
|
74348
74939
|
const code = await new Promise((resolve24) => {
|
|
74349
74940
|
process.stdin.setEncoding("utf-8");
|
|
74350
74941
|
let buf = "";
|
|
74351
|
-
process.stdin.on("data", (
|
|
74352
|
-
buf +=
|
|
74942
|
+
process.stdin.on("data", (chunk2) => {
|
|
74943
|
+
buf += chunk2.toString();
|
|
74353
74944
|
const newlineIdx = buf.indexOf(`
|
|
74354
74945
|
`);
|
|
74355
74946
|
if (newlineIdx !== -1) {
|
|
@@ -74431,8 +75022,8 @@ switchroom agent add: ${name}
|
|
|
74431
75022
|
return new Promise((resolveLine) => {
|
|
74432
75023
|
process.stdin.setEncoding("utf-8");
|
|
74433
75024
|
let buf = "";
|
|
74434
|
-
const onData = (
|
|
74435
|
-
buf +=
|
|
75025
|
+
const onData = (chunk2) => {
|
|
75026
|
+
buf += chunk2.toString();
|
|
74436
75027
|
const newlineIdx = buf.indexOf(`
|
|
74437
75028
|
`);
|
|
74438
75029
|
if (newlineIdx !== -1) {
|
|
@@ -76463,8 +77054,8 @@ async function readHiddenLine2(prompt) {
|
|
|
76463
77054
|
stdin.setRawMode(true);
|
|
76464
77055
|
}
|
|
76465
77056
|
let line = "";
|
|
76466
|
-
const onData = (
|
|
76467
|
-
const s =
|
|
77057
|
+
const onData = (chunk2) => {
|
|
77058
|
+
const s = chunk2.toString("utf8");
|
|
76468
77059
|
for (const ch of s) {
|
|
76469
77060
|
if (ch === `
|
|
76470
77061
|
` || ch === "\r") {
|
|
@@ -77393,7 +77984,7 @@ function getVaultPath2(configPath) {
|
|
|
77393
77984
|
return resolvePath("~/.switchroom/vault.enc");
|
|
77394
77985
|
}
|
|
77395
77986
|
}
|
|
77396
|
-
function
|
|
77987
|
+
function maskToken2(s) {
|
|
77397
77988
|
if (s.length >= 18)
|
|
77398
77989
|
return `${s.slice(0, 6)}...${s.slice(-4)}`;
|
|
77399
77990
|
return "***";
|
|
@@ -77681,7 +78272,7 @@ function registerVaultSweep(vault, program3) {
|
|
|
77681
78272
|
console.log("");
|
|
77682
78273
|
console.log(source_default.dim(`masked values for display only:`));
|
|
77683
78274
|
for (const v of values) {
|
|
77684
|
-
console.log(` vault:${v.key} \u2192 ${
|
|
78275
|
+
console.log(` vault:${v.key} \u2192 ${maskToken2(v.value)}`);
|
|
77685
78276
|
}
|
|
77686
78277
|
if (opts.dryRun) {
|
|
77687
78278
|
console.log(source_default.yellow("dry-run \u2014 no files modified. Rerun without --dry-run to apply."));
|
|
@@ -80654,8 +81245,8 @@ class VaultBroker {
|
|
|
80654
81245
|
peer = this.testOpts._testIdentify ? this.testOpts._testIdentify(listenerSocketPath, socket) : identify(listenerSocketPath, socket);
|
|
80655
81246
|
}
|
|
80656
81247
|
let buffer = "";
|
|
80657
|
-
socket.on("data", (
|
|
80658
|
-
buffer +=
|
|
81248
|
+
socket.on("data", (chunk2) => {
|
|
81249
|
+
buffer += chunk2.toString("utf8");
|
|
80659
81250
|
if (Buffer.byteLength(buffer, "utf8") > MAX_FRAME_BYTES) {
|
|
80660
81251
|
const resp = encodeResponse(errorResponse("BAD_REQUEST", "Frame exceeds 64 KiB limit"));
|
|
80661
81252
|
socket.end(resp);
|
|
@@ -81764,8 +82355,8 @@ class VaultBroker {
|
|
|
81764
82355
|
const auditCaller = isOperator ? "operator" : unlockPeer !== null ? callerFromPeer(unlockPeer) : `pid:${process.pid}`;
|
|
81765
82356
|
const auditCgroup = isOperator ? undefined : unlockPeer?.systemdUnit ?? undefined;
|
|
81766
82357
|
let buffer = "";
|
|
81767
|
-
socket.on("data", (
|
|
81768
|
-
buffer +=
|
|
82358
|
+
socket.on("data", (chunk2) => {
|
|
82359
|
+
buffer += chunk2.toString("utf8");
|
|
81769
82360
|
const newlineIdx = buffer.indexOf(`
|
|
81770
82361
|
`);
|
|
81771
82362
|
if (newlineIdx === -1) {
|
|
@@ -83332,7 +83923,7 @@ function promptLine2(prompt, hidden = false) {
|
|
|
83332
83923
|
function readStdinToEnd() {
|
|
83333
83924
|
return new Promise((resolve30, reject) => {
|
|
83334
83925
|
const chunks = [];
|
|
83335
|
-
process.stdin.on("data", (
|
|
83926
|
+
process.stdin.on("data", (chunk2) => chunks.push(chunk2));
|
|
83336
83927
|
process.stdin.on("end", () => {
|
|
83337
83928
|
resolve30(Buffer.concat(chunks).toString("utf8"));
|
|
83338
83929
|
});
|
|
@@ -85484,9 +86075,9 @@ Repairing vector index coverage for ${target}${opts.dryRun ? source_default.yell
|
|
|
85484
86075
|
`));
|
|
85485
86076
|
const child = spawn5("docker", argv, { stdio: ["ignore", "pipe", "inherit"] });
|
|
85486
86077
|
let captured = "";
|
|
85487
|
-
child.stdout?.on("data", (
|
|
85488
|
-
captured +=
|
|
85489
|
-
process.stdout.write(
|
|
86078
|
+
child.stdout?.on("data", (chunk2) => {
|
|
86079
|
+
captured += chunk2.toString();
|
|
86080
|
+
process.stdout.write(chunk2);
|
|
85490
86081
|
});
|
|
85491
86082
|
const childExit = await new Promise((resolve30) => {
|
|
85492
86083
|
child.on("error", () => resolve30(127));
|
|
@@ -85587,14 +86178,21 @@ Demoting memory ${source_default.cyan(memoryId)}`));
|
|
|
85587
86178
|
const timeoutMs = Math.max(1000, parseInt(opts.timeout, 10) || 60000);
|
|
85588
86179
|
const ctrl = new AbortController;
|
|
85589
86180
|
const t = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
86181
|
+
const payload = redactMemoryWriteBody({
|
|
86182
|
+
items: [{ content, tags: ["operator-authored", "profile"] }],
|
|
86183
|
+
async: false
|
|
86184
|
+
});
|
|
86185
|
+
const stored = payload.items[0].content;
|
|
86186
|
+
if (stored !== content) {
|
|
86187
|
+
console.error(source_default.yellow(`\u26a0 Credential-shaped text in this fact was replaced with a
|
|
86188
|
+
` + ` [REDACTED] marker before it was stored. Put secrets in the
|
|
86189
|
+
` + " vault (`switchroom vault set <key>`) and reference them as\n" + " `vault:<key>` instead."));
|
|
86190
|
+
}
|
|
85590
86191
|
try {
|
|
85591
86192
|
const res = await fetch(url, {
|
|
85592
86193
|
method: "POST",
|
|
85593
86194
|
headers: { "Content-Type": "application/json" },
|
|
85594
|
-
body: JSON.stringify(
|
|
85595
|
-
items: [{ content, tags: ["operator-authored", "profile"] }],
|
|
85596
|
-
async: false
|
|
85597
|
-
}),
|
|
86195
|
+
body: JSON.stringify(payload),
|
|
85598
86196
|
signal: ctrl.signal
|
|
85599
86197
|
});
|
|
85600
86198
|
if (!res.ok) {
|
|
@@ -85602,7 +86200,7 @@ Demoting memory ${source_default.cyan(memoryId)}`));
|
|
|
85602
86200
|
process.exit(1);
|
|
85603
86201
|
}
|
|
85604
86202
|
console.log(source_default.green(`\u2713 Added to profile bank "${bank}"`));
|
|
85605
|
-
console.log(source_default.gray(` ${
|
|
86203
|
+
console.log(source_default.gray(` ${stored}`));
|
|
85606
86204
|
console.log(source_default.gray(" (fact extraction runs in the background \u2014 `profile list` may lag a few seconds)"));
|
|
85607
86205
|
console.log(source_default.gray(`
|
|
85608
86206
|
Wire it into agents via memory.recall.additional_banks: ["${bank}"] in switchroom.yaml,
|
|
@@ -87895,8 +88493,8 @@ function forwardToGateway(socketPath, req, opts = {}) {
|
|
|
87895
88493
|
conn.write(JSON.stringify(req) + `
|
|
87896
88494
|
`);
|
|
87897
88495
|
});
|
|
87898
|
-
conn.on("data", (
|
|
87899
|
-
buf +=
|
|
88496
|
+
conn.on("data", (chunk2) => {
|
|
88497
|
+
buf += chunk2;
|
|
87900
88498
|
const nl = buf.indexOf(`
|
|
87901
88499
|
`);
|
|
87902
88500
|
if (nl === -1)
|
|
@@ -94075,410 +94673,6 @@ function computeFingerprint(source, code) {
|
|
|
94075
94673
|
return `${source}::${code}`;
|
|
94076
94674
|
}
|
|
94077
94675
|
|
|
94078
|
-
// telegram-plugin/secret-detect/patterns.ts
|
|
94079
|
-
var ANCHORED_PATTERNS = [
|
|
94080
|
-
{ rule_id: "anthropic_api_key", regex: /\b(sk-ant-[A-Za-z0-9_-]{8,})\b/g, captureIndex: 1, slugHint: "anthropic_api_key" },
|
|
94081
|
-
{ rule_id: "anthropic_oauth_code", regex: /(?:^|\s)([A-Za-z0-9_-]{20,}#[A-Za-z0-9_-]{20,})(?=\s|$)/gm, captureIndex: 1, slugHint: "anthropic_oauth_code" },
|
|
94082
|
-
{ rule_id: "openai_api_key", regex: /\b(sk-[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: "openai_api_key" },
|
|
94083
|
-
{ rule_id: "github_pat_classic", regex: /\b(ghp_[A-Za-z0-9]{20,})\b/g, captureIndex: 1, slugHint: "github_pat" },
|
|
94084
|
-
{ rule_id: "github_pat_fine_grained", regex: /\b(github_pat_[A-Za-z0-9_]{20,})\b/g, captureIndex: 1, slugHint: "github_pat" },
|
|
94085
|
-
{ rule_id: "slack_token", regex: /\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g, captureIndex: 1, slugHint: "slack_token" },
|
|
94086
|
-
{ rule_id: "slack_app_token", regex: /\b(xapp-[A-Za-z0-9-]{10,})\b/g, captureIndex: 1, slugHint: "slack_app_token" },
|
|
94087
|
-
{ rule_id: "groq_api_key", regex: /\b(gsk_[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: "groq_api_key" },
|
|
94088
|
-
{ rule_id: "google_api_key", regex: /\b(AIza[0-9A-Za-z\-_]{20,})\b/g, captureIndex: 1, slugHint: "google_api_key" },
|
|
94089
|
-
{ rule_id: "perplexity_api_key", regex: /\b(pplx-[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: "perplexity_api_key" },
|
|
94090
|
-
{ rule_id: "npm_token", regex: /\b(npm_[A-Za-z0-9]{10,})\b/g, captureIndex: 1, slugHint: "npm_token" },
|
|
94091
|
-
{ rule_id: "telegram_bot_token_prefixed", regex: /\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: "telegram_bot_token" },
|
|
94092
|
-
{ rule_id: "telegram_bot_token", regex: /\b(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: "telegram_bot_token" },
|
|
94093
|
-
{ rule_id: "laravel_sanctum_token", regex: /\b(\d+\|[A-Za-z0-9]{40,})\b/g, captureIndex: 1, slugHint: "api_token" },
|
|
94094
|
-
{ rule_id: "aws_access_key", regex: /\b(AKIA[0-9A-Z]{16})\b/g, captureIndex: 1, slugHint: "aws_access_key" },
|
|
94095
|
-
{ rule_id: "jwt", regex: /\b(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: "jwt" }
|
|
94096
|
-
];
|
|
94097
|
-
var STRUCTURED_PATTERNS = [
|
|
94098
|
-
{
|
|
94099
|
-
rule_id: "env_key_value",
|
|
94100
|
-
regex: /\b([A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD))\b\s*[=:]\s*(["']?)([^\s"'\\]+)\2/g,
|
|
94101
|
-
captureIndex: 3,
|
|
94102
|
-
slugHint: "env"
|
|
94103
|
-
},
|
|
94104
|
-
{
|
|
94105
|
-
rule_id: "json_secret_field",
|
|
94106
|
-
regex: /"(?:apiKey|token|secret|password|passwd|accessToken|refreshToken)"\s*:\s*"([^"]+)"/g,
|
|
94107
|
-
captureIndex: 1,
|
|
94108
|
-
slugHint: "json_secret"
|
|
94109
|
-
},
|
|
94110
|
-
{
|
|
94111
|
-
rule_id: "cli_flag",
|
|
94112
|
-
regex: /--(?:api[-_]?key|hook[-_]?token|token|secret|password|passwd)\s+(["']?)([^\s"']+)\1/g,
|
|
94113
|
-
captureIndex: 2,
|
|
94114
|
-
slugHint: "cli_flag"
|
|
94115
|
-
},
|
|
94116
|
-
{
|
|
94117
|
-
rule_id: "bearer_auth_header",
|
|
94118
|
-
regex: /Authorization\s*[:=]\s*Bearer\s+([A-Za-z0-9._\-+=]+)/g,
|
|
94119
|
-
captureIndex: 1,
|
|
94120
|
-
slugHint: "bearer_token"
|
|
94121
|
-
},
|
|
94122
|
-
{
|
|
94123
|
-
rule_id: "bearer_loose",
|
|
94124
|
-
regex: /\bBearer\s+([A-Za-z0-9._\-+=]{18,})\b/g,
|
|
94125
|
-
captureIndex: 1,
|
|
94126
|
-
slugHint: "bearer_token"
|
|
94127
|
-
},
|
|
94128
|
-
{
|
|
94129
|
-
rule_id: "pem_private_key",
|
|
94130
|
-
regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
94131
|
-
captureIndex: 0,
|
|
94132
|
-
slugHint: "pem_private_key"
|
|
94133
|
-
}
|
|
94134
|
-
];
|
|
94135
|
-
var PROVIDER_PATTERNS = [
|
|
94136
|
-
{ rule_id: "slack_webhook", regex: /(https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9_/]+)/g, captureIndex: 1, slugHint: "slack_webhook" },
|
|
94137
|
-
{ rule_id: "stripe_live_secret", regex: /\b(sk_live_[A-Za-z0-9]{24,})\b/g, captureIndex: 1, slugHint: "stripe_key" },
|
|
94138
|
-
{ rule_id: "stripe_restricted", regex: /\b(rk_live_[A-Za-z0-9]{24,})\b/g, captureIndex: 1, slugHint: "stripe_key" },
|
|
94139
|
-
{ rule_id: "sendgrid_api_key", regex: /\b(SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43})\b/g, captureIndex: 1, slugHint: "sendgrid_key" },
|
|
94140
|
-
{ rule_id: "gitlab_pat", regex: /\b(glpat-[A-Za-z0-9_-]{20})\b/g, captureIndex: 1, slugHint: "gitlab_pat" },
|
|
94141
|
-
{ rule_id: "huggingface_token", regex: /\b(hf_[A-Za-z0-9]{34,})\b/g, captureIndex: 1, slugHint: "huggingface_token" },
|
|
94142
|
-
{ rule_id: "twilio_api_key", regex: /\b(SK[0-9a-f]{32})\b/g, captureIndex: 1, slugHint: "twilio_api_key" },
|
|
94143
|
-
{ rule_id: "mailgun_key", regex: /\b(key-[0-9a-f]{32})\b/g, captureIndex: 1, slugHint: "mailgun_key" },
|
|
94144
|
-
{ rule_id: "digitalocean_pat", regex: /\b(dop_v1_[a-f0-9]{64})\b/g, captureIndex: 1, slugHint: "digitalocean_token" },
|
|
94145
|
-
{ rule_id: "digitalocean_oauth", regex: /\b(doo_v1_[a-f0-9]{64})\b/g, captureIndex: 1, slugHint: "digitalocean_token" },
|
|
94146
|
-
{ rule_id: "digitalocean_refresh", regex: /\b(dor_v1_[a-f0-9]{64})\b/g, captureIndex: 1, slugHint: "digitalocean_token" },
|
|
94147
|
-
{ rule_id: "doppler_token", regex: /\b(dp\.(?:pt|st|ct|sa|scim|audit)\.[A-Za-z0-9]{40,44})\b/g, captureIndex: 1, slugHint: "doppler_token" },
|
|
94148
|
-
{ rule_id: "linear_api_key", regex: /\b(lin_api_[A-Za-z0-9]{40})\b/g, captureIndex: 1, slugHint: "linear_api_key" },
|
|
94149
|
-
{ rule_id: "shopify_access_token", regex: /\b(shpat_[a-fA-F0-9]{32})\b/g, captureIndex: 1, slugHint: "shopify_token" },
|
|
94150
|
-
{ rule_id: "shopify_shared_secret", regex: /\b(shpss_[a-fA-F0-9]{32})\b/g, captureIndex: 1, slugHint: "shopify_token" },
|
|
94151
|
-
{ rule_id: "shopify_private_app", regex: /\b(shppa_[a-fA-F0-9]{32})\b/g, captureIndex: 1, slugHint: "shopify_token" },
|
|
94152
|
-
{ rule_id: "square_access_token", regex: /\b(sq0atp-[A-Za-z0-9_-]{22})\b/g, captureIndex: 1, slugHint: "square_token" },
|
|
94153
|
-
{ rule_id: "square_oauth_secret", regex: /\b(sq0csp-[A-Za-z0-9_-]{43})\b/g, captureIndex: 1, slugHint: "square_token" },
|
|
94154
|
-
{ rule_id: "newrelic_key", regex: /\b(NRAK-[A-Z0-9]{27})\b/g, captureIndex: 1, slugHint: "newrelic_key" },
|
|
94155
|
-
{ rule_id: "notion_token", regex: /\b(ntn_[A-Za-z0-9]{46})\b/g, captureIndex: 1, slugHint: "notion_token" },
|
|
94156
|
-
{ rule_id: "planetscale_password", regex: /\b(pscale_pw_[A-Za-z0-9_.-]{43})\b/g, captureIndex: 1, slugHint: "planetscale_token" },
|
|
94157
|
-
{ rule_id: "planetscale_token", regex: /\b(pscale_tkn_[A-Za-z0-9_.-]{43})\b/g, captureIndex: 1, slugHint: "planetscale_token" },
|
|
94158
|
-
{ rule_id: "supabase_service_key", regex: /\b(sbp_[a-f0-9]{40})\b/g, captureIndex: 1, slugHint: "supabase_key" },
|
|
94159
|
-
{ rule_id: "atlassian_token", regex: /\b(ATATT[A-Za-z0-9_\-=]{20,})\b/g, captureIndex: 1, slugHint: "atlassian_token" },
|
|
94160
|
-
{ rule_id: "dropbox_token", regex: /\b(sl\.[A-Za-z0-9_-]{130,})/g, captureIndex: 1, slugHint: "dropbox_token" },
|
|
94161
|
-
{ rule_id: "databricks_token", regex: /\b(dapi[a-f0-9]{32})\b/g, captureIndex: 1, slugHint: "databricks_token" },
|
|
94162
|
-
{ rule_id: "grafana_service_account", regex: /\b(glsa_[A-Za-z0-9]{32}_[a-fA-F0-9]{8})\b/g, captureIndex: 1, slugHint: "grafana_token" },
|
|
94163
|
-
{ rule_id: "pypi_token", regex: /\b(pypi-AgEIcHlwaS[A-Za-z0-9_-]{50,})/g, captureIndex: 1, slugHint: "pypi_token" },
|
|
94164
|
-
{ rule_id: "aws_temp_access_key", regex: /\b(ASIA[0-9A-Z]{16})\b/g, captureIndex: 1, slugHint: "aws_access_key" },
|
|
94165
|
-
{ rule_id: "gcp_oauth_token", regex: /\b(ya29\.[A-Za-z0-9_-]{30,})/g, captureIndex: 1, slugHint: "gcp_oauth_token" }
|
|
94166
|
-
];
|
|
94167
|
-
var ALL_PATTERNS = [...ANCHORED_PATTERNS, ...PROVIDER_PATTERNS, ...STRUCTURED_PATTERNS];
|
|
94168
|
-
|
|
94169
|
-
// telegram-plugin/secret-detect/entropy.ts
|
|
94170
|
-
function shannonEntropy(s) {
|
|
94171
|
-
if (s.length === 0)
|
|
94172
|
-
return 0;
|
|
94173
|
-
const counts = new Map;
|
|
94174
|
-
for (const ch of s) {
|
|
94175
|
-
counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
94176
|
-
}
|
|
94177
|
-
let h = 0;
|
|
94178
|
-
const len = s.length;
|
|
94179
|
-
for (const c of counts.values()) {
|
|
94180
|
-
const p = c / len;
|
|
94181
|
-
h -= p * Math.log2(p);
|
|
94182
|
-
}
|
|
94183
|
-
return h;
|
|
94184
|
-
}
|
|
94185
|
-
|
|
94186
|
-
// telegram-plugin/secret-detect/kv-scanner.ts
|
|
94187
|
-
var KV_RE = /\b([A-Za-z_][A-Za-z0-9_-]*(?:password|passwd|token|secret|key|api[_-]?key))\s*[:=]\s*["']?([^\s"'\\]{8,})["']?/gi;
|
|
94188
|
-
var KV_ENTROPY_THRESHOLD = 4;
|
|
94189
|
-
function scanKeyValue(text) {
|
|
94190
|
-
const hits = [];
|
|
94191
|
-
KV_RE.lastIndex = 0;
|
|
94192
|
-
let m;
|
|
94193
|
-
while ((m = KV_RE.exec(text)) !== null) {
|
|
94194
|
-
const [, keyName, value] = m;
|
|
94195
|
-
if (!value)
|
|
94196
|
-
continue;
|
|
94197
|
-
const h = shannonEntropy(value);
|
|
94198
|
-
if (h < KV_ENTROPY_THRESHOLD)
|
|
94199
|
-
continue;
|
|
94200
|
-
const valueOffsetInMatch = m[0].indexOf(value, keyName.length);
|
|
94201
|
-
if (valueOffsetInMatch < 0)
|
|
94202
|
-
continue;
|
|
94203
|
-
const start = m.index + valueOffsetInMatch;
|
|
94204
|
-
const end = start + value.length;
|
|
94205
|
-
hits.push({
|
|
94206
|
-
rule_id: "kv_entropy",
|
|
94207
|
-
start,
|
|
94208
|
-
end,
|
|
94209
|
-
matched_text: value,
|
|
94210
|
-
key_name: keyName,
|
|
94211
|
-
confidence: "ambiguous"
|
|
94212
|
-
});
|
|
94213
|
-
}
|
|
94214
|
-
return hits;
|
|
94215
|
-
}
|
|
94216
|
-
|
|
94217
|
-
// telegram-plugin/secret-detect/generic-entropy.ts
|
|
94218
|
-
var CANDIDATE_RE = /[A-Za-z0-9]{28,}/g;
|
|
94219
|
-
var GENERIC_MIN_DISTINCT = 18;
|
|
94220
|
-
var MAX_GENERIC_HITS = 20;
|
|
94221
|
-
function hasDistinctChars(tok, n) {
|
|
94222
|
-
const seen = new Uint8Array(128);
|
|
94223
|
-
let distinct = 0;
|
|
94224
|
-
for (let i = 0;i < tok.length; i++) {
|
|
94225
|
-
const c = tok.charCodeAt(i);
|
|
94226
|
-
if (seen[c] === 0) {
|
|
94227
|
-
seen[c] = 1;
|
|
94228
|
-
if (++distinct >= n)
|
|
94229
|
-
return true;
|
|
94230
|
-
}
|
|
94231
|
-
}
|
|
94232
|
-
return false;
|
|
94233
|
-
}
|
|
94234
|
-
function hasDigit(tok) {
|
|
94235
|
-
for (let i = 0;i < tok.length; i++) {
|
|
94236
|
-
const c = tok.charCodeAt(i);
|
|
94237
|
-
if (c >= 48 && c <= 57)
|
|
94238
|
-
return true;
|
|
94239
|
-
}
|
|
94240
|
-
return false;
|
|
94241
|
-
}
|
|
94242
|
-
function scanGenericSecrets(text) {
|
|
94243
|
-
const hits = [];
|
|
94244
|
-
CANDIDATE_RE.lastIndex = 0;
|
|
94245
|
-
let m;
|
|
94246
|
-
while ((m = CANDIDATE_RE.exec(text)) !== null) {
|
|
94247
|
-
if (hits.length >= MAX_GENERIC_HITS)
|
|
94248
|
-
break;
|
|
94249
|
-
const tok = m[0];
|
|
94250
|
-
if (!hasDigit(tok))
|
|
94251
|
-
continue;
|
|
94252
|
-
if (!hasDistinctChars(tok, GENERIC_MIN_DISTINCT))
|
|
94253
|
-
continue;
|
|
94254
|
-
hits.push({
|
|
94255
|
-
rule_id: "generic_high_entropy",
|
|
94256
|
-
start: m.index,
|
|
94257
|
-
end: m.index + tok.length,
|
|
94258
|
-
matched_text: tok,
|
|
94259
|
-
confidence: "ambiguous"
|
|
94260
|
-
});
|
|
94261
|
-
}
|
|
94262
|
-
return hits;
|
|
94263
|
-
}
|
|
94264
|
-
|
|
94265
|
-
// telegram-plugin/secret-detect/chunker.ts
|
|
94266
|
-
var CHUNK_THRESHOLD = 32 * 1024;
|
|
94267
|
-
var WINDOW_SIZE = 16 * 1024;
|
|
94268
|
-
var OVERLAP = 8 * 1024;
|
|
94269
|
-
function chunk(text) {
|
|
94270
|
-
if (text.length <= CHUNK_THRESHOLD) {
|
|
94271
|
-
return [{ offset: 0, text }];
|
|
94272
|
-
}
|
|
94273
|
-
const out = [];
|
|
94274
|
-
let offset = 0;
|
|
94275
|
-
while (offset < text.length) {
|
|
94276
|
-
const end = Math.min(offset + WINDOW_SIZE, text.length);
|
|
94277
|
-
out.push({ offset, text: text.slice(offset, end) });
|
|
94278
|
-
if (end >= text.length)
|
|
94279
|
-
break;
|
|
94280
|
-
offset = end - OVERLAP;
|
|
94281
|
-
}
|
|
94282
|
-
return out;
|
|
94283
|
-
}
|
|
94284
|
-
|
|
94285
|
-
// telegram-plugin/secret-detect/suppressor.ts
|
|
94286
|
-
var MARKERS = ["test", "mock", "example", "fixture", "dummy"];
|
|
94287
|
-
var WINDOW = 40;
|
|
94288
|
-
var MARKER_RE = new RegExp(`\\b(?:${MARKERS.join("|")})\\b`, "i");
|
|
94289
|
-
function isSuppressed(text, start, end) {
|
|
94290
|
-
const left = Math.max(0, start - WINDOW);
|
|
94291
|
-
const right = Math.min(text.length, end + WINDOW);
|
|
94292
|
-
const context = text.slice(left, start) + text.slice(end, right);
|
|
94293
|
-
return MARKER_RE.test(context);
|
|
94294
|
-
}
|
|
94295
|
-
|
|
94296
|
-
// telegram-plugin/secret-detect/slug.ts
|
|
94297
|
-
function sanitizeKeyName(raw) {
|
|
94298
|
-
const up = raw.toUpperCase();
|
|
94299
|
-
const cleaned = up.replace(/[^A-Z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
94300
|
-
return cleaned.length > 0 ? cleaned : "SECRET";
|
|
94301
|
-
}
|
|
94302
|
-
function datePart(now = new Date) {
|
|
94303
|
-
const y = now.getUTCFullYear();
|
|
94304
|
-
const m = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
94305
|
-
const d = String(now.getUTCDate()).padStart(2, "0");
|
|
94306
|
-
return `${y}${m}${d}`;
|
|
94307
|
-
}
|
|
94308
|
-
function deriveSlug(inputs, existing) {
|
|
94309
|
-
let base;
|
|
94310
|
-
if (inputs.key_name && inputs.key_name.trim().length > 0) {
|
|
94311
|
-
base = sanitizeKeyName(inputs.key_name);
|
|
94312
|
-
} else {
|
|
94313
|
-
base = `${inputs.rule_id}_${datePart(inputs.now)}`;
|
|
94314
|
-
}
|
|
94315
|
-
if (!existing.has(base))
|
|
94316
|
-
return base;
|
|
94317
|
-
let n = 2;
|
|
94318
|
-
while (existing.has(`${base}_${n}`))
|
|
94319
|
-
n++;
|
|
94320
|
-
return `${base}_${n}`;
|
|
94321
|
-
}
|
|
94322
|
-
// telegram-plugin/secret-detect/url-redact.ts
|
|
94323
|
-
var SENSITIVE_PARAMS = new Set([
|
|
94324
|
-
"token",
|
|
94325
|
-
"key",
|
|
94326
|
-
"api_key",
|
|
94327
|
-
"apikey",
|
|
94328
|
-
"secret",
|
|
94329
|
-
"access_token",
|
|
94330
|
-
"password",
|
|
94331
|
-
"pass",
|
|
94332
|
-
"auth",
|
|
94333
|
-
"client_secret",
|
|
94334
|
-
"refresh_token",
|
|
94335
|
-
"signature"
|
|
94336
|
-
]);
|
|
94337
|
-
var URL_RE = /\b(?:https?|wss?|ftp):\/\/[^\s<>"']+/gi;
|
|
94338
|
-
function redactUrls(text) {
|
|
94339
|
-
return text.replace(URL_RE, (m) => {
|
|
94340
|
-
const redacted = redactOne(m);
|
|
94341
|
-
return redacted ?? m;
|
|
94342
|
-
});
|
|
94343
|
-
}
|
|
94344
|
-
function redactOne(raw) {
|
|
94345
|
-
let u;
|
|
94346
|
-
try {
|
|
94347
|
-
u = new URL(raw);
|
|
94348
|
-
} catch {
|
|
94349
|
-
return null;
|
|
94350
|
-
}
|
|
94351
|
-
let changed = false;
|
|
94352
|
-
if (u.username || u.password) {
|
|
94353
|
-
u.username = "***";
|
|
94354
|
-
u.password = "";
|
|
94355
|
-
changed = true;
|
|
94356
|
-
}
|
|
94357
|
-
for (const [key] of u.searchParams) {
|
|
94358
|
-
if (SENSITIVE_PARAMS.has(key.toLowerCase())) {
|
|
94359
|
-
u.searchParams.set(key, "***");
|
|
94360
|
-
changed = true;
|
|
94361
|
-
}
|
|
94362
|
-
}
|
|
94363
|
-
return changed ? u.toString() : null;
|
|
94364
|
-
}
|
|
94365
|
-
|
|
94366
|
-
// telegram-plugin/secret-detect/index.ts
|
|
94367
|
-
function detectSecrets(text) {
|
|
94368
|
-
if (!text || text.length === 0)
|
|
94369
|
-
return [];
|
|
94370
|
-
const windows = chunk(text);
|
|
94371
|
-
const raw = [];
|
|
94372
|
-
for (const win of windows) {
|
|
94373
|
-
for (const p of ALL_PATTERNS) {
|
|
94374
|
-
const re = new RegExp(p.regex.source, p.regex.flags.includes("g") ? p.regex.flags : p.regex.flags + "g");
|
|
94375
|
-
let m;
|
|
94376
|
-
while ((m = re.exec(win.text)) !== null) {
|
|
94377
|
-
if (m[0].length === 0) {
|
|
94378
|
-
re.lastIndex++;
|
|
94379
|
-
continue;
|
|
94380
|
-
}
|
|
94381
|
-
const cap = p.captureIndex === 0 ? m[0] : m[p.captureIndex];
|
|
94382
|
-
if (!cap)
|
|
94383
|
-
continue;
|
|
94384
|
-
const matchStart = p.captureIndex === 0 ? m.index : m.index + m[0].indexOf(cap);
|
|
94385
|
-
if (matchStart < 0)
|
|
94386
|
-
continue;
|
|
94387
|
-
const globalStart = win.offset + matchStart;
|
|
94388
|
-
const globalEnd = globalStart + cap.length;
|
|
94389
|
-
const keyName = p.rule_id === "env_key_value" ? m[1] : undefined;
|
|
94390
|
-
if (p.rule_id === "env_key_value") {
|
|
94391
|
-
const ENV_KV_MIN_LEN = 12;
|
|
94392
|
-
const ENV_KV_MIN_ENTROPY = 3.5;
|
|
94393
|
-
if (cap.length < ENV_KV_MIN_LEN)
|
|
94394
|
-
continue;
|
|
94395
|
-
if (shannonEntropy(cap) < ENV_KV_MIN_ENTROPY)
|
|
94396
|
-
continue;
|
|
94397
|
-
}
|
|
94398
|
-
raw.push({
|
|
94399
|
-
rule_id: p.rule_id,
|
|
94400
|
-
start: globalStart,
|
|
94401
|
-
end: globalEnd,
|
|
94402
|
-
matched_text: cap,
|
|
94403
|
-
key_name: keyName,
|
|
94404
|
-
confidence: "high"
|
|
94405
|
-
});
|
|
94406
|
-
}
|
|
94407
|
-
}
|
|
94408
|
-
const kvHits = scanKeyValue(win.text);
|
|
94409
|
-
for (const h of kvHits) {
|
|
94410
|
-
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
94411
|
-
}
|
|
94412
|
-
const genHits = scanGenericSecrets(win.text);
|
|
94413
|
-
for (const h of genHits) {
|
|
94414
|
-
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset });
|
|
94415
|
-
}
|
|
94416
|
-
}
|
|
94417
|
-
const deduped = dedupeRaw(raw);
|
|
94418
|
-
const final = dropOverlaps(deduped);
|
|
94419
|
-
const existing = new Set;
|
|
94420
|
-
const out = [];
|
|
94421
|
-
for (const h of final) {
|
|
94422
|
-
const suggested_slug = deriveSlug({ key_name: h.key_name, rule_id: h.rule_id }, existing);
|
|
94423
|
-
existing.add(suggested_slug);
|
|
94424
|
-
out.push({
|
|
94425
|
-
rule_id: h.rule_id,
|
|
94426
|
-
matched_text: h.matched_text,
|
|
94427
|
-
start: h.start,
|
|
94428
|
-
end: h.end,
|
|
94429
|
-
confidence: h.confidence,
|
|
94430
|
-
suppressed: isSuppressed(text, h.start, h.end),
|
|
94431
|
-
suggested_slug,
|
|
94432
|
-
key_name: h.key_name
|
|
94433
|
-
});
|
|
94434
|
-
}
|
|
94435
|
-
out.sort((a, b) => a.start - b.start);
|
|
94436
|
-
return out;
|
|
94437
|
-
}
|
|
94438
|
-
function dedupeRaw(raw) {
|
|
94439
|
-
const seen = new Map;
|
|
94440
|
-
for (const h of raw) {
|
|
94441
|
-
const key = `${h.start}:${h.end}`;
|
|
94442
|
-
const existing = seen.get(key);
|
|
94443
|
-
if (!existing) {
|
|
94444
|
-
seen.set(key, h);
|
|
94445
|
-
continue;
|
|
94446
|
-
}
|
|
94447
|
-
if (existing.confidence === "ambiguous" && h.confidence === "high") {
|
|
94448
|
-
seen.set(key, h);
|
|
94449
|
-
}
|
|
94450
|
-
}
|
|
94451
|
-
return Array.from(seen.values());
|
|
94452
|
-
}
|
|
94453
|
-
function dropOverlaps(hits) {
|
|
94454
|
-
const out = hits.filter((h) => !(h.confidence === "ambiguous" && hits.some((o) => o !== h && o.start <= h.start && o.end >= h.end && !(o.start === h.start && o.end === h.end))));
|
|
94455
|
-
out.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
94456
|
-
return out;
|
|
94457
|
-
}
|
|
94458
|
-
|
|
94459
|
-
// telegram-plugin/secret-detect/redact.ts
|
|
94460
|
-
var REDACTED_MARKER = "[REDACTED]";
|
|
94461
|
-
function redact(text) {
|
|
94462
|
-
if (!text || text.length === 0)
|
|
94463
|
-
return text;
|
|
94464
|
-
const urlScrubbed = redactUrls(text);
|
|
94465
|
-
const hits = detectSecrets(urlScrubbed).filter((h) => h.rule_id !== "generic_high_entropy");
|
|
94466
|
-
if (hits.length === 0)
|
|
94467
|
-
return urlScrubbed;
|
|
94468
|
-
const sorted = [...hits].sort((a, b) => b.start - a.start);
|
|
94469
|
-
let out = urlScrubbed;
|
|
94470
|
-
for (const h of sorted) {
|
|
94471
|
-
out = out.slice(0, h.start) + redactedMarker(h.rule_id) + out.slice(h.end);
|
|
94472
|
-
}
|
|
94473
|
-
return out;
|
|
94474
|
-
}
|
|
94475
|
-
function redactedMarker(ruleId) {
|
|
94476
|
-
const trimmed = ruleId.replace(/^(kv|env)_/, "");
|
|
94477
|
-
if (!trimmed || trimmed === "key_value" || trimmed === "kv_entropy") {
|
|
94478
|
-
return REDACTED_MARKER;
|
|
94479
|
-
}
|
|
94480
|
-
return `[REDACTED:${trimmed}]`;
|
|
94481
|
-
}
|
|
94482
94676
|
// src/issues/store.ts
|
|
94483
94677
|
var ISSUES_FILE = "issues.jsonl";
|
|
94484
94678
|
var ISSUES_LOCK = "issues.lock";
|
|
@@ -98428,6 +98622,42 @@ function withSynthesizedTools(result) {
|
|
|
98428
98622
|
]
|
|
98429
98623
|
};
|
|
98430
98624
|
}
|
|
98625
|
+
var READ_ONLY_TOOL_NAMES = new Set([
|
|
98626
|
+
"recall",
|
|
98627
|
+
"reflect",
|
|
98628
|
+
"search",
|
|
98629
|
+
"list_memories",
|
|
98630
|
+
"list_directives",
|
|
98631
|
+
"list_mental_models",
|
|
98632
|
+
"get_mental_model",
|
|
98633
|
+
"get_memory",
|
|
98634
|
+
"get_bank"
|
|
98635
|
+
]);
|
|
98636
|
+
function redactToolArguments(value) {
|
|
98637
|
+
if (typeof value === "string")
|
|
98638
|
+
return redact(value);
|
|
98639
|
+
if (Array.isArray(value))
|
|
98640
|
+
return value.map(redactToolArguments);
|
|
98641
|
+
if (value && typeof value === "object") {
|
|
98642
|
+
const out = {};
|
|
98643
|
+
for (const [k, v] of Object.entries(value)) {
|
|
98644
|
+
out[k] = redactToolArguments(v);
|
|
98645
|
+
}
|
|
98646
|
+
return out;
|
|
98647
|
+
}
|
|
98648
|
+
return value;
|
|
98649
|
+
}
|
|
98650
|
+
function redactToolCallParams(params) {
|
|
98651
|
+
const called = params;
|
|
98652
|
+
if (!called || typeof called !== "object")
|
|
98653
|
+
return params;
|
|
98654
|
+
if (called.arguments === undefined || called.arguments === null)
|
|
98655
|
+
return params;
|
|
98656
|
+
if (typeof called.name === "string" && READ_ONLY_TOOL_NAMES.has(called.name)) {
|
|
98657
|
+
return params;
|
|
98658
|
+
}
|
|
98659
|
+
return { ...called, arguments: redactToolArguments(called.arguments) };
|
|
98660
|
+
}
|
|
98431
98661
|
function buildFallbackToolsList() {
|
|
98432
98662
|
const tools = Object.entries(FALLBACK_TOOL_TABLE).map(([name, [required, props]]) => ({
|
|
98433
98663
|
name,
|
|
@@ -98754,8 +98984,9 @@ class HindsightShim {
|
|
|
98754
98984
|
if (called?.name && SYNTHESIZED_TOOL_NAMES.includes(called.name)) {
|
|
98755
98985
|
return this.synthesizedCall(called.name, called.arguments);
|
|
98756
98986
|
}
|
|
98987
|
+
const forwarded = redactToolCallParams(params);
|
|
98757
98988
|
try {
|
|
98758
|
-
const res = await this.upstream.request("tools/call",
|
|
98989
|
+
const res = await this.upstream.request("tools/call", forwarded, this.opts.toolsCallTimeoutMs ?? TOOLS_CALL_TIMEOUT_MS);
|
|
98759
98990
|
this.notifyIfRecovered();
|
|
98760
98991
|
if (res.error) {
|
|
98761
98992
|
return {
|