switchroom 0.14.76 → 0.14.77
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/switchroom.js +96 -19
- package/package.json +1 -1
- package/profiles/default/workspace/CLAUDE.md.hbs +11 -13
- package/telegram-plugin/dist/gateway/gateway.js +5 -5
- package/telegram-plugin/hooks/secret-guard-pretool.mjs +10 -1
- package/telegram-plugin/tests/secret-guard-pretool.test.ts +7 -1
package/dist/cli/switchroom.js
CHANGED
|
@@ -20876,7 +20876,7 @@ function getHindsightSettingsEntry(agentName, config) {
|
|
|
20876
20876
|
}
|
|
20877
20877
|
const collection = getCollectionForAgent(agentName, config);
|
|
20878
20878
|
const mcpConfig = generateHindsightMcpConfig(collection, memoryConfig);
|
|
20879
|
-
return { key: "hindsight", value: mcpConfig };
|
|
20879
|
+
return { key: "hindsight", value: { ...mcpConfig, alwaysLoad: true } };
|
|
20880
20880
|
}
|
|
20881
20881
|
function getPlaywrightMcpSettingsEntry() {
|
|
20882
20882
|
return {
|
|
@@ -49681,8 +49681,8 @@ var {
|
|
|
49681
49681
|
} = import__.default;
|
|
49682
49682
|
|
|
49683
49683
|
// src/build-info.ts
|
|
49684
|
-
var VERSION = "0.14.
|
|
49685
|
-
var COMMIT_SHA = "
|
|
49684
|
+
var VERSION = "0.14.77";
|
|
49685
|
+
var COMMIT_SHA = "2473dbbf";
|
|
49686
49686
|
|
|
49687
49687
|
// src/cli/agent.ts
|
|
49688
49688
|
init_source();
|
|
@@ -50534,16 +50534,16 @@ Every turn that answers a user message ends with a user-visible
|
|
|
50534
50534
|
sees; your terminal output never reaches them.`;
|
|
50535
50535
|
var MEMORY_GUIDANCE = `## Memory \u2014 proactive, conversational
|
|
50536
50536
|
|
|
50537
|
-
You have Hindsight tools: \`mcp__hindsight__sync_retain\`, \`
|
|
50537
|
+
You have Hindsight tools: \`mcp__hindsight__sync_retain\`, \`mcp__hindsight__delete_document\`, \`mcp__hindsight__recall\`, \`mcp__hindsight__reflect\`. Use them without being asked.
|
|
50538
50538
|
|
|
50539
50539
|
### Retain proactively
|
|
50540
50540
|
When the user shares a fact, preference, decision, or plan worth keeping across sessions, call \`sync_retain\` in the same turn. Briefly acknowledge in your reply ("got it, April 2nd anniversary"). Don't narrate the tool call. Skip small talk and transient tool output, the auto-retain hook handles conversation-level signal.
|
|
50541
50541
|
|
|
50542
50542
|
### Correct proactively
|
|
50543
|
-
When the user corrects you or contradicts a prior memory, call \`
|
|
50543
|
+
When the user corrects you or contradicts a prior memory, call \`delete_document\` on the wrong entry, then \`sync_retain\` the correction. Acknowledge the correction in one line ("noted, Alice not Bob").
|
|
50544
50544
|
|
|
50545
50545
|
### Forget proactively
|
|
50546
|
-
When the user asks you to forget something ("forget that", "delete X", "drop what I said about Y"), call \`
|
|
50546
|
+
When the user asks you to forget something ("forget that", "delete X", "drop what I said about Y"), call \`delete_document\` for matching entries and confirm what was removed.
|
|
50547
50547
|
|
|
50548
50548
|
### Inspect proactively
|
|
50549
50549
|
When the user asks "what do you know about X / me", "what do you remember about Y", or any memory audit, use \`reflect\` to synthesize an answer across the bank. Return it as honest prose, not a raw dump. If the bank has little on the topic, say so.
|
|
@@ -50600,7 +50600,18 @@ name from that list.
|
|
|
50600
50600
|
Only call the \`vault_request_access\` MCP tool \u2014 which pings the
|
|
50601
50601
|
operator for a Telegram approval \u2014 for a key you've **confirmed via
|
|
50602
50602
|
\`vault list\` you don't already have.** Requesting access to a guessed
|
|
50603
|
-
or already-held key wastes the operator's tap and fails
|
|
50603
|
+
or already-held key wastes the operator's tap and fails.
|
|
50604
|
+
|
|
50605
|
+
**Never put a secret's value \u2014 or a \`vault:<key>\` placeholder \u2014 in a
|
|
50606
|
+
tool call.** Tool arguments are sent to the underlying API verbatim;
|
|
50607
|
+
nothing resolves a \`vault:\` reference for them. A real secret never
|
|
50608
|
+
needs to appear in a tool call \u2014 the launcher injects it into the
|
|
50609
|
+
tool's environment for you. A value you genuinely must pass literally
|
|
50610
|
+
(an account or customer ID) is a public identifier, not a secret, and
|
|
50611
|
+
belongs in plain config, not the vault. If a tool call is **blocked for
|
|
50612
|
+
containing a vaulted secret**, report that exact block message to the
|
|
50613
|
+
operator and stop \u2014 don't theorise about auth or tokens; it just means
|
|
50614
|
+
a stored value reached a tool argument.`;
|
|
50604
50615
|
function renderFleetInvariants() {
|
|
50605
50616
|
return [
|
|
50606
50617
|
"<!--",
|
|
@@ -51111,6 +51122,11 @@ function buildHumanizerEnvVars(agentDir, agent) {
|
|
|
51111
51122
|
const resolved = expanded.startsWith("/") ? expanded : resolve11(agentDir, expanded);
|
|
51112
51123
|
return { HUMANIZER_VOICE_FILE: resolved };
|
|
51113
51124
|
}
|
|
51125
|
+
function buildToolSearchEnvVars() {
|
|
51126
|
+
if (process.env.SWITCHROOM_DISABLE_TOOL_SEARCH === "1")
|
|
51127
|
+
return {};
|
|
51128
|
+
return { ENABLE_TOOL_SEARCH: process.env.SWITCHROOM_TOOL_SEARCH_MODE ?? "auto" };
|
|
51129
|
+
}
|
|
51114
51130
|
var SWITCHROOM_OWNED_SETTINGS_KEYS = new Set([
|
|
51115
51131
|
"permissions",
|
|
51116
51132
|
"mcpServers",
|
|
@@ -51440,6 +51456,7 @@ function buildWorkspaceContext(args) {
|
|
|
51440
51456
|
fallbackModelQ: agentConfig.fallback_model ? shellSingleQuote(agentConfig.fallback_model) : undefined,
|
|
51441
51457
|
userEnvQuoted: (() => {
|
|
51442
51458
|
const combined = {
|
|
51459
|
+
...buildToolSearchEnvVars(),
|
|
51443
51460
|
...channelsToEnv(agentConfig),
|
|
51444
51461
|
...agentConfig.env ?? {},
|
|
51445
51462
|
...buildRepoEnvVars(name, agentDir, agentConfig),
|
|
@@ -51750,7 +51767,8 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
51750
51767
|
TELEGRAM_STATE_DIR: telegramStateDir,
|
|
51751
51768
|
SWITCHROOM_CONFIG: resolvedConfigPath,
|
|
51752
51769
|
SWITCHROOM_CLI_PATH: switchroomCliPath
|
|
51753
|
-
}
|
|
51770
|
+
},
|
|
51771
|
+
alwaysLoad: true
|
|
51754
51772
|
},
|
|
51755
51773
|
"agent-config": {
|
|
51756
51774
|
command: switchroomCliPath,
|
|
@@ -51758,7 +51776,8 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
51758
51776
|
env: {
|
|
51759
51777
|
SWITCHROOM_AGENT_NAME: name,
|
|
51760
51778
|
SWITCHROOM_CONFIG: resolvedConfigPath
|
|
51761
|
-
}
|
|
51779
|
+
},
|
|
51780
|
+
alwaysLoad: true
|
|
51762
51781
|
}
|
|
51763
51782
|
};
|
|
51764
51783
|
if (agentConfig.admin === true) {
|
|
@@ -52503,6 +52522,7 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
|
|
|
52503
52522
|
fallbackModelQ: agentConfig.fallback_model ? shellSingleQuote(agentConfig.fallback_model) : undefined,
|
|
52504
52523
|
userEnvQuoted: (() => {
|
|
52505
52524
|
const combined = {
|
|
52525
|
+
...buildToolSearchEnvVars(),
|
|
52506
52526
|
...channelsToEnv(agentConfig),
|
|
52507
52527
|
...agentConfig.env ?? {},
|
|
52508
52528
|
...buildRepoEnvVars(name, agentDir, agentConfig)
|
|
@@ -52785,7 +52805,8 @@ ${body}
|
|
|
52785
52805
|
TELEGRAM_STATE_DIR: telegramStateDir,
|
|
52786
52806
|
SWITCHROOM_CONFIG: resolvedConfigPath,
|
|
52787
52807
|
SWITCHROOM_CLI_PATH: switchroomCliPath
|
|
52788
|
-
}
|
|
52808
|
+
},
|
|
52809
|
+
alwaysLoad: true
|
|
52789
52810
|
},
|
|
52790
52811
|
"agent-config": {
|
|
52791
52812
|
command: switchroomCliPath,
|
|
@@ -52793,7 +52814,8 @@ ${body}
|
|
|
52793
52814
|
env: {
|
|
52794
52815
|
SWITCHROOM_AGENT_NAME: name,
|
|
52795
52816
|
SWITCHROOM_CONFIG: resolvedConfigPath
|
|
52796
|
-
}
|
|
52817
|
+
},
|
|
52818
|
+
alwaysLoad: true
|
|
52797
52819
|
}
|
|
52798
52820
|
};
|
|
52799
52821
|
if (agentConfig.admin === true) {
|
|
@@ -64069,6 +64091,15 @@ import { existsSync as existsSync37 } from "node:fs";
|
|
|
64069
64091
|
|
|
64070
64092
|
// src/vault/doctor.ts
|
|
64071
64093
|
var SENSITIVE_KEY_RE = /oauth(?![a-zA-Z])|token(?![a-zA-Z])|secret(?![a-zA-Z])|api[-_]?key(?![a-zA-Z])|password(?![a-zA-Z])/i;
|
|
64094
|
+
function looksLikeIdentifierValue(value) {
|
|
64095
|
+
const v = value.trim();
|
|
64096
|
+
if (v.length < 8 || v.length > 24)
|
|
64097
|
+
return false;
|
|
64098
|
+
if (!/^[0-9][0-9 -]*[0-9]$/.test(v))
|
|
64099
|
+
return false;
|
|
64100
|
+
const digitCount = v.replace(/[^0-9]/g, "").length;
|
|
64101
|
+
return digitCount >= 8;
|
|
64102
|
+
}
|
|
64072
64103
|
function analyseVaultHealth(input) {
|
|
64073
64104
|
const diagnostics = [];
|
|
64074
64105
|
if (input.brokerConfigured && input.brokerRunning === false) {
|
|
@@ -64124,6 +64155,23 @@ ${keyList}`,
|
|
|
64124
64155
|
fix: "Consider `switchroom vault set <key> --allow <agent>` to restrict access"
|
|
64125
64156
|
});
|
|
64126
64157
|
}
|
|
64158
|
+
const identifierKeys = [];
|
|
64159
|
+
for (const [keyName, entry] of Object.entries(input.vaultKeys)) {
|
|
64160
|
+
if (entry.looksLikeIdentifier)
|
|
64161
|
+
identifierKeys.push(keyName);
|
|
64162
|
+
}
|
|
64163
|
+
if (identifierKeys.length > 0) {
|
|
64164
|
+
const keyList = identifierKeys.map((k) => ` ${k}`).join(`
|
|
64165
|
+
`);
|
|
64166
|
+
diagnostics.push({
|
|
64167
|
+
level: "warn",
|
|
64168
|
+
check: "identifier-stored-as-secret",
|
|
64169
|
+
message: `${identifierKeys.length} vault key(s) hold an identifier-like value (digits only):
|
|
64170
|
+
${keyList}
|
|
64171
|
+
` + `If an agent must pass one of these in a tool call, the secret-guard hook will block it \u2014 it cannot tell a public ID from a secret.`,
|
|
64172
|
+
fix: "If the value is a public identifier (account/customer ID), remove it from the vault and pass it as plain config (e.g. hardcode it in the MCP launcher). If it is genuinely secret, ignore this."
|
|
64173
|
+
});
|
|
64174
|
+
}
|
|
64127
64175
|
const unreferencedKeys = [];
|
|
64128
64176
|
for (const keyName of Object.keys(input.vaultKeys)) {
|
|
64129
64177
|
if (!referencedKeys.has(keyName)) {
|
|
@@ -64215,7 +64263,8 @@ function registerVaultDoctorCommand(vault, program3) {
|
|
|
64215
64263
|
vaultKeys = {};
|
|
64216
64264
|
for (const [name, entry] of Object.entries(entries)) {
|
|
64217
64265
|
vaultKeys[name] = {
|
|
64218
|
-
scope: "scope" in entry && entry.scope ? entry.scope : undefined
|
|
64266
|
+
scope: "scope" in entry && entry.scope ? entry.scope : undefined,
|
|
64267
|
+
looksLikeIdentifier: entry.kind === "string" ? looksLikeIdentifierValue(entry.value) : false
|
|
64219
64268
|
};
|
|
64220
64269
|
}
|
|
64221
64270
|
} catch (err) {
|
|
@@ -77207,7 +77256,18 @@ function formatBytes(bytes) {
|
|
|
77207
77256
|
return `${bytes.toLocaleString()} bytes`;
|
|
77208
77257
|
}
|
|
77209
77258
|
function estimateTokens(bytes) {
|
|
77210
|
-
return Math.round(bytes /
|
|
77259
|
+
return Math.round(bytes / 3.7);
|
|
77260
|
+
}
|
|
77261
|
+
function readMcpServerNames(agentDir) {
|
|
77262
|
+
const mcpPath = join64(agentDir, ".mcp.json");
|
|
77263
|
+
if (!existsSync64(mcpPath))
|
|
77264
|
+
return [];
|
|
77265
|
+
try {
|
|
77266
|
+
const parsed = JSON.parse(readFileSync56(mcpPath, "utf-8"));
|
|
77267
|
+
return Object.keys(parsed.mcpServers ?? {});
|
|
77268
|
+
} catch {
|
|
77269
|
+
return null;
|
|
77270
|
+
}
|
|
77211
77271
|
}
|
|
77212
77272
|
function sha256(content) {
|
|
77213
77273
|
return createHash13("sha256").update(content).digest("hex").slice(0, 16);
|
|
@@ -77425,14 +77485,31 @@ function registerDebugCommand(program3) {
|
|
|
77425
77485
|
const soulMdBytes = soulMdContent.length;
|
|
77426
77486
|
const perTurnBytes = dynamicResult.concatenated.length;
|
|
77427
77487
|
const userBytes = userMessage?.text.length ?? 0;
|
|
77428
|
-
const
|
|
77429
|
-
|
|
77488
|
+
const fleetDir = join64(agentsDir, "..", "fleet");
|
|
77489
|
+
const fleetInvPath = join64(fleetDir, "switchroom-invariants.md");
|
|
77490
|
+
const fleetClaudePath = join64(fleetDir, "CLAUDE.md");
|
|
77491
|
+
const fleetInvBytes = existsSync64(fleetInvPath) ? readFileSync56(fleetInvPath, "utf-8").length : 0;
|
|
77492
|
+
const fleetClaudeBytes = existsSync64(fleetClaudePath) ? readFileSync56(fleetClaudePath, "utf-8").length : 0;
|
|
77493
|
+
const fleetBytes = fleetInvBytes + fleetClaudeBytes;
|
|
77494
|
+
const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
|
|
77495
|
+
console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
|
|
77430
77496
|
console.log(`Per-session: ${formatBytes(perSessionBytes).padEnd(20)} (cache-warm until next session)`);
|
|
77431
|
-
console.log(`CLAUDE.md:
|
|
77432
|
-
console.log(`
|
|
77433
|
-
console.log(`Per-turn: ${formatBytes(perTurnBytes).padEnd(20)} (never cached)`);
|
|
77497
|
+
console.log(`CLAUDE.md (cwd): ${formatBytes(claudeMdBytes).padEnd(20)} (cache-hot)`);
|
|
77498
|
+
console.log(`Fleet invariants: ${formatBytes(fleetBytes).padEnd(20)} (--add-dir, cache-hot)`);
|
|
77499
|
+
console.log(`Per-turn: ${formatBytes(perTurnBytes).padEnd(20)} (never cached \u2014 the real per-turn $ cost)`);
|
|
77434
77500
|
console.log(`User message: ${formatBytes(userBytes).padEnd(20)}`);
|
|
77435
|
-
console.log(`
|
|
77501
|
+
console.log(`Authored text: ${formatBytes(totalBytes).padEnd(20)} (~${estimateTokens(totalBytes).toLocaleString()} tokens est.)`);
|
|
77502
|
+
const mcpServers = readMcpServerNames(agentDir);
|
|
77503
|
+
const mcpCount = mcpServers?.length ?? null;
|
|
77504
|
+
const mcpEstK = mcpCount != null ? mcpCount * 3 : null;
|
|
77505
|
+
const mcpLabel = mcpCount != null ? `${mcpCount} servers` : "(unreadable \u2014 agent-private .mcp.json)";
|
|
77506
|
+
const mcpEstLabel = mcpEstK != null ? `~${mcpEstK.toLocaleString()}k tok` : "~30k tok (audit est.)";
|
|
77507
|
+
console.log(`MCP tool surface: ${mcpLabel.padEnd(20)} (NOT counted above; ~3k tok/server \u2248 ${mcpEstLabel} \u2014 deferred under tool search)`);
|
|
77508
|
+
if (mcpServers && mcpServers.length > 0) {
|
|
77509
|
+
console.log(` [${mcpServers.join(", ")}]`);
|
|
77510
|
+
}
|
|
77511
|
+
const floorMcp = mcpEstK != null ? `~${mcpEstK.toLocaleString()}k` : "~30k";
|
|
77512
|
+
console.log(`Per-turn FLOOR: ${`~${estimateTokens(totalBytes).toLocaleString()} + ${floorMcp} MCP + ~13k CLI-base`.padEnd(20)} tokens est. (before the user msg, recall, or tool results)`);
|
|
77436
77513
|
const stableCacheInput = stableResult.concatenated + progressGuidance + baseSystemPromptAppend;
|
|
77437
77514
|
const stableHash = sha256(stableCacheInput);
|
|
77438
77515
|
console.log(`Cache stable hash: sha256:${stableHash}`);
|
package/package.json
CHANGED
|
@@ -11,23 +11,21 @@ Before answering anything non-trivial:
|
|
|
11
11
|
|
|
12
12
|
1. Confirm who you are (see `IDENTITY.md` if present).
|
|
13
13
|
2. Confirm who you're talking to (see `USER.md` if present).
|
|
14
|
-
3.
|
|
15
|
-
`
|
|
16
|
-
|
|
14
|
+
3. Recall what matters — your memory is **Hindsight**: call
|
|
15
|
+
`mcp__hindsight__recall` when you need prior context, decisions, or who
|
|
16
|
+
someone is. (Full memory protocol is in your `CLAUDE.md`.)
|
|
17
17
|
4. If tools are configured, `TOOLS.md` captures setup-specific notes
|
|
18
18
|
(host paths, credentials, endpoints) that save you discovery work.
|
|
19
19
|
|
|
20
20
|
Don't ask permission to read these files. They exist so you can use them.
|
|
21
21
|
|
|
22
|
-
## Memory
|
|
22
|
+
## Memory
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
write it down. Future-you is fresh every session. Files are your
|
|
30
|
-
continuity.
|
|
24
|
+
Memory is **Hindsight**, not files — `recall` to read, `sync_retain` to keep a
|
|
25
|
+
fact across sessions, `delete_document` to forget. Claude Code's built-in
|
|
26
|
+
file-based auto-memory is disabled for this agent; do not maintain a `MEMORY.md`
|
|
27
|
+
index or a `memory/` daily-notes directory. Your `CLAUDE.md` has the full
|
|
28
|
+
protocol.
|
|
31
29
|
|
|
32
30
|
## Safety defaults
|
|
33
31
|
|
|
@@ -55,8 +53,8 @@ Failed edits burn your own context and the user's patience. Verify first.
|
|
|
55
53
|
tool exists.
|
|
56
54
|
- Long-running commands: use the background flag and poll, rather than
|
|
57
55
|
blocking.
|
|
58
|
-
- `
|
|
59
|
-
|
|
56
|
+
- `mcp__hindsight__recall` is your interface to past context and decisions;
|
|
57
|
+
recall before asking the user something you may already know.
|
|
60
58
|
|
|
61
59
|
## Working on code repositories
|
|
62
60
|
|
|
@@ -52821,11 +52821,11 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
52821
52821
|
}
|
|
52822
52822
|
|
|
52823
52823
|
// ../src/build-info.ts
|
|
52824
|
-
var VERSION = "0.14.
|
|
52825
|
-
var COMMIT_SHA = "
|
|
52826
|
-
var COMMIT_DATE = "2026-06-
|
|
52827
|
-
var LATEST_PR =
|
|
52828
|
-
var COMMITS_AHEAD_OF_TAG =
|
|
52824
|
+
var VERSION = "0.14.77";
|
|
52825
|
+
var COMMIT_SHA = "2473dbbf";
|
|
52826
|
+
var COMMIT_DATE = "2026-06-07T00:02:11+10:00";
|
|
52827
|
+
var LATEST_PR = null;
|
|
52828
|
+
var COMMITS_AHEAD_OF_TAG = 4;
|
|
52829
52829
|
|
|
52830
52830
|
// gateway/boot-version.ts
|
|
52831
52831
|
function formatRelativeAgo(iso) {
|
|
@@ -194,10 +194,19 @@ async function main() {
|
|
|
194
194
|
}
|
|
195
195
|
const hit = scanToolInput(toolInput, vaultValues)
|
|
196
196
|
if (hit) {
|
|
197
|
+
// The reason is read by the model. It must be CORRECT and actionable:
|
|
198
|
+
// earlier versions said "reference it as vault:<key> instead", which
|
|
199
|
+
// suggested a `vault:` resolver that does not exist for tool arguments
|
|
200
|
+
// — sending agents (and operators) chasing a phantom mechanism. State
|
|
201
|
+
// the two real resolutions instead, and do NOT imply a resolver.
|
|
197
202
|
process.stdout.write(
|
|
198
203
|
JSON.stringify({
|
|
199
204
|
decision: 'block',
|
|
200
|
-
reason:
|
|
205
|
+
reason:
|
|
206
|
+
`Blocked: this tool input contains the value of vault secret '${hit.key}'. ` +
|
|
207
|
+
`Secrets must never appear in a tool call. ` +
|
|
208
|
+
`If '${hit.key}' is a real secret, do not pass it as an argument — the launcher injects it into the tool's environment, so you never type it. ` +
|
|
209
|
+
`If '${hit.key}' is actually a public identifier (e.g. an account or customer ID that must appear in the call), it should not be in the vault — ask the operator to move it to plain config.`,
|
|
201
210
|
}),
|
|
202
211
|
)
|
|
203
212
|
process.exit(0)
|
|
@@ -132,7 +132,13 @@ describe('secret-guard-pretool.mjs (broker-direct)', () => {
|
|
|
132
132
|
})
|
|
133
133
|
expect(r.status).toBe(0)
|
|
134
134
|
expect(r.stdout).toContain('"decision":"block"')
|
|
135
|
-
|
|
135
|
+
// The reason must name the offending key and explain the real fix.
|
|
136
|
+
expect(r.stdout).toContain('gh-token')
|
|
137
|
+
expect(r.stdout).toContain('Secrets must never appear in a tool call')
|
|
138
|
+
// It must NOT resurrect the old, misleading "reference it as vault:<key>"
|
|
139
|
+
// suggestion — there is no vault: resolver for tool arguments, and that
|
|
140
|
+
// advice sent agents down a dead end (see the hook's block-reason note).
|
|
141
|
+
expect(r.stdout).not.toContain('reference it as vault:')
|
|
136
142
|
})
|
|
137
143
|
|
|
138
144
|
it('allows when tool_input contains no vaulted value', async () => {
|