@viraatdas/rudder 2.10.6 → 2.10.8
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/README.md +9 -21
- package/dist/context-audit.d.ts +21 -0
- package/dist/context-audit.js +109 -0
- package/dist/context-audit.js.map +1 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +203 -0
- package/dist/hooks.js.map +1 -0
- package/dist/main.js +23 -171
- package/dist/main.js.map +1 -1
- package/dist/native/rudder-native +0 -0
- package/dist/recipes.d.ts +11 -0
- package/dist/recipes.js +212 -0
- package/dist/recipes.js.map +1 -0
- package/dist/routines.d.ts +9 -0
- package/dist/routines.js +153 -0
- package/dist/routines.js.map +1 -0
- package/dist/run-manager.d.ts +0 -21
- package/dist/run-manager.js +0 -369
- package/dist/run-manager.js.map +1 -1
- package/dist/surfaces.js +1 -0
- package/dist/surfaces.js.map +1 -1
- package/package.json +1 -4
package/README.md
CHANGED
|
@@ -48,10 +48,9 @@ rudder
|
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
With no arguments, `rudder` opens the dashboard. Type in the bottom input and
|
|
51
|
-
press `Enter` to
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
workers.
|
|
51
|
+
press `Enter` to hand the request to the orchestrator. It can answer, inspect the
|
|
52
|
+
repo, or plan a DAG and run isolated workers. Use `/ask <text>` when you want a
|
|
53
|
+
one-off agent in the main checkout with no DAG.
|
|
55
54
|
|
|
56
55
|
If a task needs shared local context like API tokens, private URLs, account ids,
|
|
57
56
|
or environment values, save it with `/share <text>` in the task input. Rudder
|
|
@@ -91,7 +90,7 @@ to `~/.rudder/config.json`.
|
|
|
91
90
|
│ task list │ live Claude Code or Codex terminal │
|
|
92
91
|
│ status/model │ DAG-over-orchestrator, scrollback, review │
|
|
93
92
|
├───────────────┴────────────────────────────────────────────┤
|
|
94
|
-
│ task input:
|
|
93
|
+
│ task input: orchestrator by default, /ask for one-off │
|
|
95
94
|
└──────────────────────────────────────────────────────────────┘
|
|
96
95
|
```
|
|
97
96
|
|
|
@@ -191,13 +190,12 @@ reused next time. Rudder refreshes model metadata from
|
|
|
191
190
|
## One-Off and Planning
|
|
192
191
|
|
|
193
192
|
Type a fresh request in the bottom task input. When no plan is active, Rudder
|
|
194
|
-
starts
|
|
195
|
-
|
|
196
|
-
it ready to use?" out of the DAG planner.
|
|
193
|
+
starts the orchestrator, which can inspect the repo, plan the work, and spawn
|
|
194
|
+
isolated workers when needed.
|
|
197
195
|
|
|
198
|
-
Use `/
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
Use `/ask <text>` for a one-off conversational agent in the main checkout, with
|
|
197
|
+
no DAG. Use `/plan <text>` when you want to be explicit about the orchestrator /
|
|
198
|
+
DAG path; it is the same route as plain input.
|
|
201
199
|
|
|
202
200
|
For planned work, Rudder runs a dedicated Claude Code orchestrator PTY with a DAG
|
|
203
201
|
pane above it. The flow stays inside Rudder: the orchestrator researches
|
|
@@ -325,16 +323,6 @@ rudder sync <runId>
|
|
|
325
323
|
rudder cleanup
|
|
326
324
|
```
|
|
327
325
|
|
|
328
|
-
## Other interfaces
|
|
329
|
-
|
|
330
|
-
The native dashboard is the default. Older interfaces remain available:
|
|
331
|
-
|
|
332
|
-
```bash
|
|
333
|
-
rudder tmux # legacy tmux dashboard
|
|
334
|
-
rudder tui # Ink-based interactive TUI
|
|
335
|
-
rudder --no-native # skip the native binary
|
|
336
|
-
```
|
|
337
|
-
|
|
338
326
|
## Troubleshooting
|
|
339
327
|
|
|
340
328
|
- Stale behavior after an upgrade: restart any already-running Rudder dashboards
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ContextAuditSeverity = "low" | "medium" | "high";
|
|
2
|
+
export type ContextAuditFinding = {
|
|
3
|
+
severity: ContextAuditSeverity;
|
|
4
|
+
file: string;
|
|
5
|
+
message: string;
|
|
6
|
+
};
|
|
7
|
+
export type ContextAuditReport = {
|
|
8
|
+
repoRoot: string;
|
|
9
|
+
generatedAt: string;
|
|
10
|
+
findings: ContextAuditFinding[];
|
|
11
|
+
files: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
bytes: number;
|
|
14
|
+
lines: number;
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
17
|
+
export declare function auditContext(repoRoot?: string): Promise<ContextAuditReport>;
|
|
18
|
+
export declare function printContextAudit(opts?: {
|
|
19
|
+
json?: boolean;
|
|
20
|
+
repoRoot?: string;
|
|
21
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import fsp from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { findRepoRoot } from "./git.js";
|
|
4
|
+
import { pathExists } from "./util.js";
|
|
5
|
+
const CANDIDATE_FILES = [
|
|
6
|
+
"AGENTS.md",
|
|
7
|
+
"CLAUDE.md",
|
|
8
|
+
".claude/CLAUDE.md",
|
|
9
|
+
".claude/settings.json",
|
|
10
|
+
".claude/settings.local.json",
|
|
11
|
+
"RUDDER.md",
|
|
12
|
+
"DECISIONS.md",
|
|
13
|
+
"RUDDER_SHARED.md",
|
|
14
|
+
];
|
|
15
|
+
export async function auditContext(repoRoot = findRepoRoot()) {
|
|
16
|
+
const files = await collectContextFiles(repoRoot);
|
|
17
|
+
const findings = [];
|
|
18
|
+
const seenLines = new Map();
|
|
19
|
+
const summaries = [];
|
|
20
|
+
for (const rel of files) {
|
|
21
|
+
const abs = path.join(repoRoot, rel);
|
|
22
|
+
const text = await fsp.readFile(abs, "utf8").catch(() => "");
|
|
23
|
+
const stat = await fsp.stat(abs).catch(() => null);
|
|
24
|
+
const lines = text.split(/\r?\n/);
|
|
25
|
+
summaries.push({ path: rel, bytes: stat?.size ?? Buffer.byteLength(text), lines: lines.length });
|
|
26
|
+
if (lines.length > 500) {
|
|
27
|
+
findings.push({ severity: "medium", file: rel, message: "context file is over 500 lines; consider splitting or pruning" });
|
|
28
|
+
}
|
|
29
|
+
if (Buffer.byteLength(text) > 64_000) {
|
|
30
|
+
findings.push({ severity: "medium", file: rel, message: "context file is over 64KB; always-on context may be noisy" });
|
|
31
|
+
}
|
|
32
|
+
if (secretPattern().test(text)) {
|
|
33
|
+
findings.push({ severity: rel === "RUDDER_SHARED.md" ? "low" : "high", file: rel, message: "secret-like token found in a context file" });
|
|
34
|
+
}
|
|
35
|
+
if (promptInjectionPattern().test(text)) {
|
|
36
|
+
findings.push({ severity: "high", file: rel, message: "prompt-injection phrase found in a context file" });
|
|
37
|
+
}
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
const normalized = line.trim().replace(/\s+/g, " ").toLowerCase();
|
|
40
|
+
if (normalized.length < 48 || normalized.startsWith("#")) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const previous = seenLines.get(normalized);
|
|
44
|
+
if (previous && previous !== rel) {
|
|
45
|
+
findings.push({ severity: "low", file: rel, message: `duplicates a rule also present in ${previous}` });
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
seenLines.set(normalized, rel);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
repoRoot,
|
|
53
|
+
generatedAt: new Date().toISOString(),
|
|
54
|
+
findings,
|
|
55
|
+
files: summaries.sort((a, b) => a.path.localeCompare(b.path)),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function printContextAudit(opts = {}) {
|
|
59
|
+
const report = await auditContext(opts.repoRoot);
|
|
60
|
+
if (opts.json) {
|
|
61
|
+
console.log(JSON.stringify(report, null, 2));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
console.log(`Context audit for ${report.repoRoot}`);
|
|
65
|
+
if (!report.findings.length) {
|
|
66
|
+
console.log("No context issues found.");
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
for (const finding of report.findings) {
|
|
70
|
+
console.log(`${finding.severity.toUpperCase()} ${finding.file}: ${finding.message}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
console.log("");
|
|
74
|
+
console.log("Files:");
|
|
75
|
+
for (const file of report.files) {
|
|
76
|
+
console.log(` ${file.path} (${file.lines} lines, ${file.bytes} bytes)`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function collectContextFiles(repoRoot) {
|
|
80
|
+
const files = new Set();
|
|
81
|
+
for (const rel of CANDIDATE_FILES) {
|
|
82
|
+
if (await pathExists(path.join(repoRoot, rel))) {
|
|
83
|
+
files.add(rel);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const dir of [".claude/skills", ".claude/commands", ".claude/agents"]) {
|
|
87
|
+
const abs = path.join(repoRoot, dir);
|
|
88
|
+
const entries = await fsp.readdir(abs, { withFileTypes: true }).catch(() => []);
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
91
|
+
files.add(path.join(dir, entry.name));
|
|
92
|
+
}
|
|
93
|
+
if (entry.isDirectory()) {
|
|
94
|
+
const nested = path.join(abs, entry.name, "SKILL.md");
|
|
95
|
+
if (await pathExists(nested)) {
|
|
96
|
+
files.add(path.join(dir, entry.name, "SKILL.md"));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return [...files].sort();
|
|
102
|
+
}
|
|
103
|
+
function secretPattern() {
|
|
104
|
+
return /(sk-[A-Za-z0-9_-]{16,}|ghp_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|api[_-]?key\s*=\s*[A-Za-z0-9_.-]{16,})/i;
|
|
105
|
+
}
|
|
106
|
+
function promptInjectionPattern() {
|
|
107
|
+
return /(ignore (all )?(previous|prior) instructions|you are now|developer mode|<\/system>|<<SYS>>|\[INST\])/i;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=context-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-audit.js","sourceRoot":"","sources":["../src/context-audit.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { HookConfig, HookInvocation, HookResult, RudderEvent } from "./types.js";
|
|
2
|
+
export declare function hooksConfigPath(repoRoot: string): string;
|
|
3
|
+
export declare function loadHookConfig(repoRoot: string): Promise<HookConfig>;
|
|
4
|
+
export declare function runHooks(invocation: HookInvocation, emit?: (event: RudderEvent) => Promise<void> | void): Promise<HookResult[]>;
|
|
5
|
+
export declare function firstBlockingHook(results: HookResult[]): HookResult | undefined;
|
|
6
|
+
export declare function initHookTemplates(repoRoot: string): Promise<string>;
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { projectStateDir, loadConfig } from "./state.js";
|
|
4
|
+
import { nowIso, readJson, writeJson } from "./util.js";
|
|
5
|
+
export function hooksConfigPath(repoRoot) {
|
|
6
|
+
return path.join(projectStateDir(repoRoot), "hooks.json");
|
|
7
|
+
}
|
|
8
|
+
export async function loadHookConfig(repoRoot) {
|
|
9
|
+
const config = await loadConfig();
|
|
10
|
+
if (config.hooks?.enabled === false) {
|
|
11
|
+
return { version: 1, hooks: [] };
|
|
12
|
+
}
|
|
13
|
+
const configured = config.hooks?.configPath
|
|
14
|
+
? path.resolve(repoRoot, config.hooks.configPath)
|
|
15
|
+
: hooksConfigPath(repoRoot);
|
|
16
|
+
const raw = await readJson(configured);
|
|
17
|
+
if (!raw || raw.version !== 1 || !Array.isArray(raw.hooks)) {
|
|
18
|
+
return { version: 1, hooks: [] };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
version: 1,
|
|
22
|
+
hooks: raw.hooks.filter(isHookDefinition),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export async function runHooks(invocation, emit) {
|
|
26
|
+
const config = await loadHookConfig(invocation.repoRoot);
|
|
27
|
+
const hooks = config.hooks.filter((hook) => hook.event === invocation.event && hookMatches(hook, invocation));
|
|
28
|
+
const results = [];
|
|
29
|
+
for (const hook of hooks) {
|
|
30
|
+
await emit?.({
|
|
31
|
+
ts: nowIso(),
|
|
32
|
+
runId: invocation.runId ?? "hooks",
|
|
33
|
+
nodeId: invocation.nodeId,
|
|
34
|
+
type: "hook.started",
|
|
35
|
+
message: `hook ${hook.name ?? hook.command} on ${invocation.event}`,
|
|
36
|
+
data: hookData(hook),
|
|
37
|
+
});
|
|
38
|
+
const result = await runHookCommand(hook, invocation);
|
|
39
|
+
results.push(result);
|
|
40
|
+
if (result.status === "blocked") {
|
|
41
|
+
await emit?.({
|
|
42
|
+
ts: nowIso(),
|
|
43
|
+
runId: invocation.runId ?? "hooks",
|
|
44
|
+
nodeId: invocation.nodeId,
|
|
45
|
+
type: "hook.blocked",
|
|
46
|
+
message: result.reason ?? result.stderr ?? `hook blocked ${invocation.event}`,
|
|
47
|
+
data: hookData(hook),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else if (result.status === "failed" || result.status === "timeout") {
|
|
51
|
+
await emit?.({
|
|
52
|
+
ts: nowIso(),
|
|
53
|
+
runId: invocation.runId ?? "hooks",
|
|
54
|
+
nodeId: invocation.nodeId,
|
|
55
|
+
type: "hook.failed",
|
|
56
|
+
message: result.reason ?? result.stderr ?? `hook failed ${invocation.event}`,
|
|
57
|
+
data: hookData(hook),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (isBlockingEvent(invocation.event) && result.status === "blocked") {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
export function firstBlockingHook(results) {
|
|
67
|
+
return results.find((result) => result.status === "blocked");
|
|
68
|
+
}
|
|
69
|
+
export async function initHookTemplates(repoRoot) {
|
|
70
|
+
const target = hooksConfigPath(repoRoot);
|
|
71
|
+
const initial = {
|
|
72
|
+
version: 1,
|
|
73
|
+
hooks: [
|
|
74
|
+
{
|
|
75
|
+
event: "PromptSubmit",
|
|
76
|
+
name: "secret-prompt-warning",
|
|
77
|
+
command: "node -e \"let s='';process.stdin.on('data',d=>s+=d);process.stdin.on('end',()=>{const j=JSON.parse(s); if(/(sk-|ghp_|github_pat_|api[_-]?key=)/i.test(j.message||'')){console.error('prompt appears to contain a secret; use rudder share instead'); process.exit(2)}})\"",
|
|
78
|
+
timeoutMs: 5000,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
await writeJson(target, initial, { mode: 0o600 });
|
|
83
|
+
return target;
|
|
84
|
+
}
|
|
85
|
+
function runHookCommand(hook, invocation) {
|
|
86
|
+
const timeoutMs = hook.timeoutMs ?? defaultTimeout(invocation.event);
|
|
87
|
+
const input = JSON.stringify(invocation);
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
const child = spawn(hook.command, {
|
|
90
|
+
cwd: invocation.repoRoot,
|
|
91
|
+
shell: true,
|
|
92
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
93
|
+
env: {
|
|
94
|
+
...process.env,
|
|
95
|
+
RUDDER_REPO: invocation.repoRoot,
|
|
96
|
+
RUDDER_EVENT: invocation.event,
|
|
97
|
+
...(invocation.runId ? { RUDDER_RUN_ID: invocation.runId } : {}),
|
|
98
|
+
...(invocation.nodeId ? { RUDDER_NODE_ID: invocation.nodeId } : {}),
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
let stdout = "";
|
|
102
|
+
let stderr = "";
|
|
103
|
+
let settled = false;
|
|
104
|
+
const timer = setTimeout(() => {
|
|
105
|
+
if (settled) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
settled = true;
|
|
109
|
+
child.kill("SIGTERM");
|
|
110
|
+
resolve({ hook, status: "timeout", stdout, stderr, reason: `hook timed out after ${timeoutMs}ms` });
|
|
111
|
+
}, timeoutMs);
|
|
112
|
+
timer.unref?.();
|
|
113
|
+
child.stdout?.on("data", (chunk) => {
|
|
114
|
+
stdout += String(chunk);
|
|
115
|
+
});
|
|
116
|
+
child.stderr?.on("data", (chunk) => {
|
|
117
|
+
stderr += String(chunk);
|
|
118
|
+
});
|
|
119
|
+
child.on("error", (error) => {
|
|
120
|
+
if (settled) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
settled = true;
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
resolve({ hook, status: "failed", stdout, stderr, reason: error.message });
|
|
126
|
+
});
|
|
127
|
+
child.on("exit", (code) => {
|
|
128
|
+
if (settled) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
settled = true;
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
const parsed = parseHookJson(stdout);
|
|
134
|
+
const blocked = code === 2 || parsed?.decision === "block";
|
|
135
|
+
resolve({
|
|
136
|
+
hook,
|
|
137
|
+
status: blocked ? "blocked" : code === 0 ? "allowed" : "failed",
|
|
138
|
+
stdout,
|
|
139
|
+
stderr,
|
|
140
|
+
...(blocked ? { reason: parsed?.reason ?? firstLine(stderr) ?? "blocked by hook" } : {}),
|
|
141
|
+
...(code !== 0 && !blocked ? { reason: firstLine(stderr) ?? `hook exited ${code}` } : {}),
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
child.stdin?.end(input);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function hookMatches(hook, invocation) {
|
|
148
|
+
if (!hook.matcher) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
const haystack = `${invocation.message ?? ""}\n${JSON.stringify(invocation.data ?? {})}`;
|
|
152
|
+
try {
|
|
153
|
+
return new RegExp(hook.matcher).test(haystack);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return haystack.includes(hook.matcher);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function isHookDefinition(value) {
|
|
160
|
+
const hook = value;
|
|
161
|
+
return Boolean(hook && isHookEvent(hook.event) && typeof hook.command === "string" && hook.command.trim());
|
|
162
|
+
}
|
|
163
|
+
function isHookEvent(value) {
|
|
164
|
+
return (value === "PromptSubmit" ||
|
|
165
|
+
value === "RunStart" ||
|
|
166
|
+
value === "RunComplete" ||
|
|
167
|
+
value === "NodeReview" ||
|
|
168
|
+
value === "NodeMerged" ||
|
|
169
|
+
value === "MergeConflict" ||
|
|
170
|
+
value === "BudgetExceeded" ||
|
|
171
|
+
value === "WorktreeCreate" ||
|
|
172
|
+
value === "SessionEnd");
|
|
173
|
+
}
|
|
174
|
+
function isBlockingEvent(event) {
|
|
175
|
+
return event === "PromptSubmit" || event === "RunStart" || event === "WorktreeCreate";
|
|
176
|
+
}
|
|
177
|
+
function defaultTimeout(event) {
|
|
178
|
+
return event === "PromptSubmit" ? 30_000 : 600_000;
|
|
179
|
+
}
|
|
180
|
+
function parseHookJson(stdout) {
|
|
181
|
+
const trimmed = stdout.trim();
|
|
182
|
+
if (!trimmed.startsWith("{")) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
return JSON.parse(trimmed);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function firstLine(value) {
|
|
193
|
+
return value.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
194
|
+
}
|
|
195
|
+
function hookData(hook) {
|
|
196
|
+
return {
|
|
197
|
+
event: hook.event,
|
|
198
|
+
command: hook.command,
|
|
199
|
+
...(hook.name ? { name: hook.name } : {}),
|
|
200
|
+
...(hook.matcher ? { matcher: hook.matcher } : {}),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
|