switchroom 0.15.45 → 0.16.5
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/agent-scheduler/index.js +56 -15
- package/dist/auth-broker/index.js +383 -97
- package/dist/cli/autoaccept-poll.js +4842 -35
- package/dist/cli/drive-write-pretool.mjs +7 -4
- package/dist/cli/notion-write-pretool.mjs +35 -4
- package/dist/cli/self-improve-apply-guard-pretool.mjs +626 -0
- package/dist/cli/self-improve-stop.mjs +428 -0
- package/dist/cli/switchroom.js +2894 -841
- package/dist/host-control/main.js +2685 -207
- package/dist/vault/approvals/kernel-server.js +7453 -7413
- package/dist/vault/broker/server.js +11428 -11388
- package/examples/minimal.yaml +1 -0
- package/examples/switchroom.yaml +1 -0
- package/package.json +3 -3
- package/profiles/_base/start.sh.hbs +97 -1
- package/profiles/_shared/execution-discipline.md.hbs +18 -0
- package/profiles/default/CLAUDE.md.hbs +0 -19
- package/telegram-plugin/.claude-plugin/plugin.json +2 -2
- package/telegram-plugin/answer-stream-flag.ts +12 -49
- package/telegram-plugin/answer-stream.ts +5 -150
- package/telegram-plugin/auth-snapshot-format.ts +280 -48
- package/telegram-plugin/auto-fallback-fleet.ts +44 -1
- package/telegram-plugin/context-exhaustion.ts +12 -0
- package/telegram-plugin/demo-mask.ts +154 -0
- package/telegram-plugin/dist/bridge/bridge.js +55 -12
- package/telegram-plugin/dist/gateway/gateway.js +2938 -977
- package/telegram-plugin/dist/server.js +55 -12
- package/telegram-plugin/docs/waiting-ux-spec.md +2 -2
- package/telegram-plugin/draft-stream.ts +47 -410
- package/telegram-plugin/final-answer-detect.ts +17 -12
- package/telegram-plugin/fleet-fallback-resume.ts +131 -0
- package/telegram-plugin/format.ts +56 -19
- package/telegram-plugin/gateway/auth-add-flow.ts +332 -127
- package/telegram-plugin/gateway/auth-broker-client.ts +2 -2
- package/telegram-plugin/gateway/auth-command.ts +70 -14
- package/telegram-plugin/gateway/clean-shutdown-marker.ts +44 -0
- package/telegram-plugin/gateway/config-approval-handler.test.ts +91 -4
- package/telegram-plugin/gateway/config-approval-handler.ts +94 -13
- package/telegram-plugin/gateway/current-turn-map.ts +188 -0
- package/telegram-plugin/gateway/disconnect-flush.ts +3 -1
- package/telegram-plugin/gateway/effort-command.ts +8 -3
- package/telegram-plugin/gateway/emission-authority.ts +369 -0
- package/telegram-plugin/gateway/feed-open-gate.ts +292 -0
- package/telegram-plugin/gateway/gateway.ts +1857 -292
- package/telegram-plugin/gateway/inject-handler.test.ts +2 -1
- package/telegram-plugin/gateway/model-command.ts +115 -4
- package/telegram-plugin/gateway/ms365-write-approval.test.ts +4 -4
- package/telegram-plugin/gateway/represent-guard.ts +72 -0
- package/telegram-plugin/gateway/status-surface-log.test.ts +5 -4
- package/telegram-plugin/gateway/status-surface-log.ts +14 -3
- package/telegram-plugin/history.ts +33 -11
- package/telegram-plugin/hooks/repo-context-pretool.mjs +26 -0
- package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +5 -0
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +8 -0
- package/telegram-plugin/hooks/tool-label-pretool.mjs +39 -15
- package/telegram-plugin/issues-card.ts +4 -0
- package/telegram-plugin/model-unavailable.ts +124 -0
- package/telegram-plugin/narrative-dedup.ts +69 -0
- package/telegram-plugin/over-ping-safety-net.ts +70 -4
- package/telegram-plugin/package.json +3 -3
- package/telegram-plugin/pending-work-progress.ts +12 -0
- package/telegram-plugin/permission-rule.ts +32 -5
- package/telegram-plugin/permission-title.ts +152 -9
- package/telegram-plugin/quota-check.ts +13 -0
- package/telegram-plugin/quota-watch.ts +135 -7
- package/telegram-plugin/registry/turns-schema.test.ts +24 -0
- package/telegram-plugin/registry/turns-schema.ts +9 -0
- package/telegram-plugin/runtime-metrics.ts +13 -0
- package/telegram-plugin/session-tail.ts +96 -11
- package/telegram-plugin/silence-poke.ts +170 -24
- package/telegram-plugin/slot-banner-driver.ts +3 -0
- package/telegram-plugin/status-no-truncate.ts +44 -0
- package/telegram-plugin/status-reactions.ts +20 -3
- package/telegram-plugin/stream-controller.ts +4 -23
- package/telegram-plugin/stream-reply-handler.ts +6 -24
- package/telegram-plugin/streaming-metrics.ts +91 -0
- package/telegram-plugin/subagent-watcher.ts +212 -66
- package/telegram-plugin/tests/activity-ever-opened-sticky.test.ts +47 -0
- package/telegram-plugin/tests/answer-stream-dedup.test.ts +9 -26
- package/telegram-plugin/tests/answer-stream-flag.test.ts +25 -58
- package/telegram-plugin/tests/answer-stream-silent-markers.test.ts +41 -51
- package/telegram-plugin/tests/answer-stream.test.ts +2 -411
- package/telegram-plugin/tests/auth-add-flow.test.ts +488 -253
- package/telegram-plugin/tests/auth-command-format2.test.ts +71 -1
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +376 -6
- package/telegram-plugin/tests/auto-fallback-fleet.test.ts +120 -0
- package/telegram-plugin/tests/cross-turn-card-gate.test.ts +424 -0
- package/telegram-plugin/tests/demo-mask.test.ts +127 -0
- package/telegram-plugin/tests/draft-stream.test.ts +0 -827
- package/telegram-plugin/tests/emission-authority-card-drain-gate.test.ts +236 -0
- package/telegram-plugin/tests/emission-authority-facade.test.ts +488 -0
- package/telegram-plugin/tests/emission-authority-open-gate.test.ts +179 -0
- package/telegram-plugin/tests/emission-authority-ping-gate.test.ts +395 -0
- package/telegram-plugin/tests/emission-determinism-wiring.test.ts +177 -0
- package/telegram-plugin/tests/feed-heartbeat-liveness-open.test.ts +146 -0
- package/telegram-plugin/tests/feed-open-gate.test.ts +259 -0
- package/telegram-plugin/tests/feed-survival.test.ts +526 -0
- package/telegram-plugin/tests/fleet-fallback-resume.test.ts +197 -0
- package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +117 -0
- package/telegram-plugin/tests/gateway-no-reply-single-emit.test.ts +4 -11
- package/telegram-plugin/tests/history.test.ts +60 -0
- package/telegram-plugin/tests/model-command.test.ts +134 -0
- package/telegram-plugin/tests/model-unavailable.test.ts +118 -0
- package/telegram-plugin/tests/narrative-dedup.test.ts +118 -0
- package/telegram-plugin/tests/orphaned-reply-rearm.test.ts +285 -0
- package/telegram-plugin/tests/over-ping-final-answer-decoupling.test.ts +194 -0
- package/telegram-plugin/tests/over-ping-safety-net.test.ts +2 -2
- package/telegram-plugin/tests/per-topic-current-turn.test.ts +373 -0
- package/telegram-plugin/tests/permission-card-origin-kill-switch.test.ts +42 -0
- package/telegram-plugin/tests/permission-rule.test.ts +17 -0
- package/telegram-plugin/tests/permission-title.test.ts +206 -17
- package/telegram-plugin/tests/quota-watch.test.ts +252 -9
- package/telegram-plugin/tests/reply-terminal-reaction.test.ts +6 -1
- package/telegram-plugin/tests/repo-context-pretool.test.ts +62 -0
- package/telegram-plugin/tests/represent-guard.test.ts +162 -0
- package/telegram-plugin/tests/session-tail.test.ts +147 -3
- package/telegram-plugin/tests/silence-liveness-wiring.test.ts +18 -0
- package/telegram-plugin/tests/status-card-budget-parity.test.ts +72 -0
- package/telegram-plugin/tests/status-surface-log.test.ts +146 -0
- package/telegram-plugin/tests/subagent-watcher-clip-narrative.test.ts +58 -0
- package/telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts +102 -0
- package/telegram-plugin/tests/subagent-watcher-workflow-visibility.test.ts +225 -0
- package/telegram-plugin/tests/subagent-watcher.test.ts +147 -0
- package/telegram-plugin/tests/telegram-activity-visibility-integration.test.ts +597 -0
- package/telegram-plugin/tests/telegram-format.test.ts +101 -6
- package/telegram-plugin/tests/tool-activity-summary.test.ts +550 -15
- package/telegram-plugin/tests/tool-label-pretool.test.ts +73 -0
- package/telegram-plugin/tests/tool-label-sidecar.test.ts +44 -0
- package/telegram-plugin/tests/tool-labels.test.ts +67 -0
- package/telegram-plugin/tests/turn-liveness-floor.test.ts +196 -0
- package/telegram-plugin/tests/turn-liveness-invariant.test.ts +340 -0
- package/telegram-plugin/tests/welcome-text.test.ts +32 -3
- package/telegram-plugin/tests/worker-activity-feed.test.ts +470 -22
- package/telegram-plugin/tool-activity-summary.ts +375 -58
- package/telegram-plugin/turn-liveness-floor.ts +240 -0
- package/telegram-plugin/uat/assertions.ts +115 -0
- package/telegram-plugin/uat/driver.ts +68 -0
- package/telegram-plugin/uat/scenarios/bg-sub-agent-dispatch-dm.test.ts +119 -133
- package/telegram-plugin/uat/scenarios/jtbd-answer-pings.test.ts +94 -0
- package/telegram-plugin/uat/scenarios/jtbd-cross-turn-card-dm.test.ts +109 -0
- package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-thinkgap-dm.test.ts +478 -0
- package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-visibility-dm.test.ts +396 -0
- package/telegram-plugin/uat/scenarios/jtbd-liveness-feed-open-dm.test.ts +202 -0
- package/telegram-plugin/uat/scenarios/jtbd-reply-is-last-dm.test.ts +202 -0
- package/telegram-plugin/uat/scenarios/reactions-dm.test.ts +93 -87
- package/telegram-plugin/welcome-text.ts +13 -1
- package/telegram-plugin/worker-activity-feed.ts +157 -82
- package/telegram-plugin/draft-transport.ts +0 -122
- package/telegram-plugin/tests/draft-retirement-wiring.test.ts +0 -82
- package/telegram-plugin/tests/draft-transport.test.ts +0 -211
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* demo-mask — PII masking for the `demo` suffix on Telegram status
|
|
3
|
+
* commands (`/usage demo`, `/auth demo`, `/status demo`, `/whoami demo`).
|
|
4
|
+
*
|
|
5
|
+
* Purpose: when an operator records a screen-recording / screenshot of a
|
|
6
|
+
* status command, a trailing `demo` token masks the MUST-MASK PII tier so
|
|
7
|
+
* real account emails, the operator's Telegram handle/id, and live vault key
|
|
8
|
+
* names never end up in a published clip. This is per-command and opt-in —
|
|
9
|
+
* the default output is unchanged and still shows the real values.
|
|
10
|
+
*
|
|
11
|
+
* Scope is deliberately narrow (the MUST-MASK tier only):
|
|
12
|
+
* 1. Email addresses (account labels) → maskEmail
|
|
13
|
+
* 2. Telegram username / sender id → maskUsername
|
|
14
|
+
* 3. Vault key names → maskVaultKey
|
|
15
|
+
*
|
|
16
|
+
* Explicitly OUT of scope (NOT masked): agent names, MCP server names,
|
|
17
|
+
* model ids, host paths, fleet topology. Those are not PII and masking
|
|
18
|
+
* them would make a demo recording confusingly unrepresentative.
|
|
19
|
+
*
|
|
20
|
+
* Determinism contract: every function is a pure-ish mapping with a
|
|
21
|
+
* process-lifetime stable cache. The SAME input always maps to the SAME
|
|
22
|
+
* masked output within a process; DISTINCT inputs map to DISTINCT outputs
|
|
23
|
+
* (within the size of each pool — pools are large enough for realistic
|
|
24
|
+
* fleets, and overflow falls back to a stable suffixed form so distinctness
|
|
25
|
+
* still holds). The mapping is intentionally NOT stable across process
|
|
26
|
+
* restarts — it does not need to be, and a per-process map keeps the module
|
|
27
|
+
* dependency-free (no persisted state, no hashing of secrets to disk).
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ── stable assignment helper ─────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Assign a stable masked value for `input` using a per-pool Map. The first
|
|
34
|
+
* time an input is seen it claims the next pool entry (or a deterministic
|
|
35
|
+
* overflow form once the pool is exhausted); subsequent calls return the
|
|
36
|
+
* same value. Distinct inputs never collide.
|
|
37
|
+
*/
|
|
38
|
+
function stableAssign(
|
|
39
|
+
input: string,
|
|
40
|
+
cache: Map<string, string>,
|
|
41
|
+
pool: readonly string[],
|
|
42
|
+
overflow: (index: number) => string,
|
|
43
|
+
): string {
|
|
44
|
+
const existing = cache.get(input);
|
|
45
|
+
if (existing !== undefined) return existing;
|
|
46
|
+
const index = cache.size;
|
|
47
|
+
const value = index < pool.length ? pool[index]! : overflow(index);
|
|
48
|
+
cache.set(input, value);
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── emails ───────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Fixed pool of realistic fake emails. Named after computing pioneers so a
|
|
56
|
+
* demo clip reads naturally without exposing the operator's real accounts.
|
|
57
|
+
* All on `example.com` (RFC 2606 reserved — guaranteed not a real inbox).
|
|
58
|
+
*/
|
|
59
|
+
const EMAIL_POOL: readonly string[] = [
|
|
60
|
+
'ada@example.com',
|
|
61
|
+
'grace@example.com',
|
|
62
|
+
'linus@example.com',
|
|
63
|
+
'hopper@example.com',
|
|
64
|
+
'turing@example.com',
|
|
65
|
+
'lovelace@example.com',
|
|
66
|
+
'dijkstra@example.com',
|
|
67
|
+
'knuth@example.com',
|
|
68
|
+
'ritchie@example.com',
|
|
69
|
+
'torvalds@example.com',
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const emailCache = new Map<string, string>();
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Map an account label to a stable realistic fake.
|
|
76
|
+
*
|
|
77
|
+
* Email-shaped labels map to the email pool. A non-email label (some
|
|
78
|
+
* operators use a plain nickname as an account label) still gets a stable
|
|
79
|
+
* fake email — masking a label that MIGHT carry a name to an obviously-fake
|
|
80
|
+
* address is the safe choice for a recording.
|
|
81
|
+
*/
|
|
82
|
+
export function maskEmail(label: string): string {
|
|
83
|
+
return stableAssign(
|
|
84
|
+
label,
|
|
85
|
+
emailCache,
|
|
86
|
+
EMAIL_POOL,
|
|
87
|
+
(i) => `demo${i + 1}@example.com`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── telegram username / sender id ────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Fixed pool of fake Telegram handles. First input → `@demo_user`, second
|
|
95
|
+
* distinct input → `@demo_user2`, etc., so a recording shows a believable
|
|
96
|
+
* handle and a second account (if any) stays distinct.
|
|
97
|
+
*/
|
|
98
|
+
const USERNAME_POOL: readonly string[] = [
|
|
99
|
+
'@demo_user',
|
|
100
|
+
'@demo_user2',
|
|
101
|
+
'@demo_user3',
|
|
102
|
+
'@demo_user4',
|
|
103
|
+
'@demo_user5',
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const usernameCache = new Map<string, string>();
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Map a `@handle` or a numeric sender id to a stable fake handle. The input
|
|
110
|
+
* may be `@realhandle` (when the user has a username) or a bare numeric id
|
|
111
|
+
* (when they don't) — both map into the same pool, so the masked output is
|
|
112
|
+
* always a `@demo_user…` handle regardless of the input shape. This also
|
|
113
|
+
* normalises the id case to a friendlier handle for the recording.
|
|
114
|
+
*/
|
|
115
|
+
export function maskUsername(tag: string): string {
|
|
116
|
+
return stableAssign(
|
|
117
|
+
tag,
|
|
118
|
+
usernameCache,
|
|
119
|
+
USERNAME_POOL,
|
|
120
|
+
(i) => `@demo_user${i + 1}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── vault key names ──────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
const vaultKeyCache = new Map<string, string>();
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Map a real vault key name (e.g. `coolify/api-token`, `github/token`) to a
|
|
130
|
+
* stable masked form (`demo/secret-1`, `demo/secret-2`, …). Keeps the
|
|
131
|
+
* `namespace/key` shape so a recording still reads like a real vault listing
|
|
132
|
+
* without revealing which services the operator has wired.
|
|
133
|
+
*/
|
|
134
|
+
export function maskVaultKey(name: string): string {
|
|
135
|
+
return stableAssign(
|
|
136
|
+
name,
|
|
137
|
+
vaultKeyCache,
|
|
138
|
+
[],
|
|
139
|
+
(i) => `demo/secret-${i + 1}`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ── test-only reset ──────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Clear all stable-assignment caches. Test-only — lets a test assert the
|
|
147
|
+
* pool-ordering from a known-empty state without cross-test contamination.
|
|
148
|
+
* Not used by production code paths.
|
|
149
|
+
*/
|
|
150
|
+
export function __resetDemoMaskCachesForTest(): void {
|
|
151
|
+
emailCache.clear();
|
|
152
|
+
usernameCache.clear();
|
|
153
|
+
vaultKeyCache.clear();
|
|
154
|
+
}
|
|
@@ -23199,6 +23199,23 @@ function extractToolResultErrorText(content) {
|
|
|
23199
23199
|
}
|
|
23200
23200
|
return "";
|
|
23201
23201
|
}
|
|
23202
|
+
function projectAssistantTextBlocks(content, make) {
|
|
23203
|
+
const out = new Map;
|
|
23204
|
+
let lastToolUseIdx = -1;
|
|
23205
|
+
content.forEach((c, i) => {
|
|
23206
|
+
if (c.type === "tool_use")
|
|
23207
|
+
lastToolUseIdx = i;
|
|
23208
|
+
});
|
|
23209
|
+
content.forEach((c, i) => {
|
|
23210
|
+
if (c.type !== "text")
|
|
23211
|
+
return;
|
|
23212
|
+
const text = c.text ?? "";
|
|
23213
|
+
if (text.trim().length === 0)
|
|
23214
|
+
return;
|
|
23215
|
+
out.set(i, make(text, i, i > lastToolUseIdx));
|
|
23216
|
+
});
|
|
23217
|
+
return out;
|
|
23218
|
+
}
|
|
23202
23219
|
function projectTranscriptLine(line) {
|
|
23203
23220
|
if (line.length > MAX_JSONL_LINE_BYTES)
|
|
23204
23221
|
return [];
|
|
@@ -23229,7 +23246,8 @@ function projectTranscriptLine(line) {
|
|
|
23229
23246
|
if (!Array.isArray(content))
|
|
23230
23247
|
return [];
|
|
23231
23248
|
const events = [];
|
|
23232
|
-
|
|
23249
|
+
const textEvents = projectAssistantTextBlocks(content, (text, blockIndex, lastInMessage) => ({ kind: "text", text, blockIndex, lastInMessage }));
|
|
23250
|
+
content.forEach((c, i) => {
|
|
23233
23251
|
const ct = c.type;
|
|
23234
23252
|
if (ct === "thinking") {
|
|
23235
23253
|
events.push({ kind: "thinking" });
|
|
@@ -23242,10 +23260,11 @@ function projectTranscriptLine(line) {
|
|
|
23242
23260
|
input: input && typeof input === "object" ? input : undefined
|
|
23243
23261
|
});
|
|
23244
23262
|
} else if (ct === "text") {
|
|
23245
|
-
const
|
|
23246
|
-
|
|
23263
|
+
const ev = textEvents.get(i);
|
|
23264
|
+
if (ev != null)
|
|
23265
|
+
events.push(ev);
|
|
23247
23266
|
}
|
|
23248
|
-
}
|
|
23267
|
+
});
|
|
23249
23268
|
return events;
|
|
23250
23269
|
}
|
|
23251
23270
|
if (type === "user") {
|
|
@@ -23329,7 +23348,14 @@ function projectSubagentLine(line, agentId, state) {
|
|
|
23329
23348
|
if (!Array.isArray(content))
|
|
23330
23349
|
return [];
|
|
23331
23350
|
const events = [];
|
|
23332
|
-
|
|
23351
|
+
const textEvents = projectAssistantTextBlocks(content, (text, blockIndex, lastInMessage) => ({
|
|
23352
|
+
kind: "sub_agent_text",
|
|
23353
|
+
agentId,
|
|
23354
|
+
text,
|
|
23355
|
+
blockIndex,
|
|
23356
|
+
lastInMessage
|
|
23357
|
+
}));
|
|
23358
|
+
content.forEach((c, i) => {
|
|
23333
23359
|
const ct = c.type;
|
|
23334
23360
|
if (ct === "tool_use") {
|
|
23335
23361
|
const name = c.name ?? "";
|
|
@@ -23345,10 +23371,11 @@ function projectSubagentLine(line, agentId, state) {
|
|
|
23345
23371
|
});
|
|
23346
23372
|
}
|
|
23347
23373
|
} else if (ct === "text") {
|
|
23348
|
-
const
|
|
23349
|
-
|
|
23374
|
+
const ev = textEvents.get(i);
|
|
23375
|
+
if (ev != null)
|
|
23376
|
+
events.push(ev);
|
|
23350
23377
|
}
|
|
23351
|
-
}
|
|
23378
|
+
});
|
|
23352
23379
|
const stopReason = message?.stop_reason;
|
|
23353
23380
|
if (stopReason === "end_turn") {
|
|
23354
23381
|
events.push({ kind: "sub_agent_turn_end", agentId });
|
|
@@ -24490,10 +24517,26 @@ var BROAD_ONLY_TOOLS = new Set([
|
|
|
24490
24517
|
function resolveSkillName(input) {
|
|
24491
24518
|
return readString(input, "skill") ?? readString(input, "skill_name") ?? readString(input, "skillName") ?? readString(input, "name") ?? skillBasenameFromPath(input);
|
|
24492
24519
|
}
|
|
24493
|
-
function filePathFrom(input) {
|
|
24494
|
-
if (
|
|
24520
|
+
function filePathFrom(input, rawPreview) {
|
|
24521
|
+
if (input) {
|
|
24522
|
+
const p = readString(input, "file_path") ?? readString(input, "notebook_path");
|
|
24523
|
+
if (p)
|
|
24524
|
+
return p;
|
|
24525
|
+
}
|
|
24526
|
+
if (rawPreview)
|
|
24527
|
+
return extractFilePathFromRaw(rawPreview);
|
|
24528
|
+
return null;
|
|
24529
|
+
}
|
|
24530
|
+
function extractFilePathFromRaw(raw) {
|
|
24531
|
+
const m = /"(?:file_path|notebook_path)"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(raw);
|
|
24532
|
+
if (!m)
|
|
24495
24533
|
return null;
|
|
24496
|
-
|
|
24534
|
+
try {
|
|
24535
|
+
const value = JSON.parse(`"${m[1]}"`);
|
|
24536
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
24537
|
+
} catch {
|
|
24538
|
+
return null;
|
|
24539
|
+
}
|
|
24497
24540
|
}
|
|
24498
24541
|
function bashFirstToken(command) {
|
|
24499
24542
|
const m = /^\s*([^\s|&;<>()`$]+)/.exec(command);
|
|
@@ -24558,7 +24601,7 @@ function matchesAllowRule(rule, toolName, inputPreview) {
|
|
|
24558
24601
|
return bashFirstToken(cmd) === m[1];
|
|
24559
24602
|
}
|
|
24560
24603
|
if (FILE_TOOLS.has(ruleTool)) {
|
|
24561
|
-
return filePathFrom(input) === arg;
|
|
24604
|
+
return filePathFrom(input, inputPreview) === arg;
|
|
24562
24605
|
}
|
|
24563
24606
|
return false;
|
|
24564
24607
|
}
|