@kenkaiiii/ggcoder 5.74.3 → 5.75.0
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 +1 -1
- package/assets/skills/bulletproof/SKILL.md +1 -1
- package/assets/skills/clarify/SKILL.md +1 -1
- package/assets/skills/code-review/SKILL.md +1 -1
- package/assets/skills/compliance-guard/SKILL.md +1 -1
- package/assets/skills/durable/SKILL.md +1 -1
- package/assets/skills/evidence-led-ui/SKILL.md +1 -1
- package/assets/skills/lean/SKILL.md +1 -1
- package/assets/skills/refactoring/SKILL.md +1 -1
- package/assets/skills/root-cause/SKILL.md +1 -1
- package/assets/skills/shared-language/SKILL.md +1 -1
- package/assets/skills/tdd/SKILL.md +1 -1
- package/dist/app-sidecar/app-settings.d.ts +65 -0
- package/dist/app-sidecar/app-settings.js +147 -0
- package/dist/app-sidecar/app-settings.js.map +1 -0
- package/dist/app-sidecar/attachments.d.ts +11 -0
- package/dist/app-sidecar/attachments.js +47 -0
- package/dist/app-sidecar/attachments.js.map +1 -0
- package/dist/app-sidecar/auth-routes.d.ts +3 -0
- package/dist/app-sidecar/auth-routes.js +290 -0
- package/dist/app-sidecar/auth-routes.js.map +1 -0
- package/dist/app-sidecar/autopilot-runner.d.ts +61 -0
- package/dist/app-sidecar/autopilot-runner.js +367 -0
- package/dist/app-sidecar/autopilot-runner.js.map +1 -0
- package/dist/app-sidecar/file-search.d.ts +15 -0
- package/dist/app-sidecar/file-search.js +103 -0
- package/dist/app-sidecar/file-search.js.map +1 -0
- package/dist/app-sidecar/hf-pull-manager.d.ts +20 -0
- package/dist/app-sidecar/hf-pull-manager.js +224 -0
- package/dist/app-sidecar/hf-pull-manager.js.map +1 -0
- package/dist/app-sidecar/history-routes.d.ts +3 -0
- package/dist/app-sidecar/history-routes.js +375 -0
- package/dist/app-sidecar/history-routes.js.map +1 -0
- package/dist/app-sidecar/history.d.ts +67 -0
- package/dist/app-sidecar/history.js +23 -0
- package/dist/app-sidecar/history.js.map +1 -0
- package/dist/app-sidecar/http.d.ts +5 -0
- package/dist/app-sidecar/http.js +27 -0
- package/dist/app-sidecar/http.js.map +1 -0
- package/dist/app-sidecar/integration-routes.d.ts +3 -0
- package/dist/app-sidecar/integration-routes.js +286 -0
- package/dist/app-sidecar/integration-routes.js.map +1 -0
- package/dist/app-sidecar/json-mode.d.ts +10 -0
- package/dist/app-sidecar/json-mode.js +73 -0
- package/dist/app-sidecar/json-mode.js.map +1 -0
- package/dist/app-sidecar/keep-awake.d.ts +4 -0
- package/dist/app-sidecar/keep-awake.js +5 -0
- package/dist/app-sidecar/keep-awake.js.map +1 -0
- package/dist/app-sidecar/ken-context.d.ts +20 -0
- package/dist/app-sidecar/ken-context.js +55 -0
- package/dist/app-sidecar/ken-context.js.map +1 -0
- package/dist/app-sidecar/mcp-routes.d.ts +3 -0
- package/dist/app-sidecar/mcp-routes.js +185 -0
- package/dist/app-sidecar/mcp-routes.js.map +1 -0
- package/dist/app-sidecar/mcp-rows.d.ts +31 -0
- package/dist/app-sidecar/mcp-rows.js +77 -0
- package/dist/app-sidecar/mcp-rows.js.map +1 -0
- package/dist/app-sidecar/progress-manager.d.ts +10 -0
- package/dist/app-sidecar/progress-manager.js +116 -0
- package/dist/app-sidecar/progress-manager.js.map +1 -0
- package/dist/app-sidecar/prompt-routes.d.ts +3 -0
- package/dist/app-sidecar/prompt-routes.js +354 -0
- package/dist/app-sidecar/prompt-routes.js.map +1 -0
- package/dist/app-sidecar/route-context.d.ts +145 -0
- package/dist/app-sidecar/route-context.js +2 -0
- package/dist/app-sidecar/route-context.js.map +1 -0
- package/dist/app-sidecar/run-control-routes.d.ts +3 -0
- package/dist/app-sidecar/run-control-routes.js +430 -0
- package/dist/app-sidecar/run-control-routes.js.map +1 -0
- package/dist/app-sidecar/session-routes.d.ts +3 -0
- package/dist/app-sidecar/session-routes.js +115 -0
- package/dist/app-sidecar/session-routes.js.map +1 -0
- package/dist/app-sidecar/session-types.d.ts +39 -0
- package/dist/app-sidecar/session-types.js +5 -0
- package/dist/app-sidecar/session-types.js.map +1 -0
- package/dist/app-sidecar/task-routes.d.ts +3 -0
- package/dist/app-sidecar/task-routes.js +149 -0
- package/dist/app-sidecar/task-routes.js.map +1 -0
- package/dist/app-sidecar/usage.d.ts +19 -0
- package/dist/app-sidecar/usage.js +153 -0
- package/dist/app-sidecar/usage.js.map +1 -0
- package/dist/app-sidecar/workspace-routes.d.ts +3 -0
- package/dist/app-sidecar/workspace-routes.js +244 -0
- package/dist/app-sidecar/workspace-routes.js.map +1 -0
- package/dist/app-sidecar.js +440 -3720
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/core/acceptance-checks.js +3 -9
- package/dist/core/acceptance-checks.js.map +1 -1
- package/dist/core/agent-session/helpers.d.ts +26 -0
- package/dist/core/agent-session/helpers.js +47 -0
- package/dist/core/agent-session/helpers.js.map +1 -0
- package/dist/core/agent-session/mcp-tools.d.ts +68 -0
- package/dist/core/agent-session/mcp-tools.js +195 -0
- package/dist/core/agent-session/mcp-tools.js.map +1 -0
- package/dist/core/agent-session/run-loop-monitor.d.ts +63 -0
- package/dist/core/agent-session/run-loop-monitor.js +164 -0
- package/dist/core/agent-session/run-loop-monitor.js.map +1 -0
- package/dist/core/agent-session/transcript-markers.d.ts +57 -0
- package/dist/core/agent-session/transcript-markers.js +166 -0
- package/dist/core/agent-session/transcript-markers.js.map +1 -0
- package/dist/core/agent-session/verification-tracker.d.ts +46 -0
- package/dist/core/agent-session/verification-tracker.js +246 -0
- package/dist/core/agent-session/verification-tracker.js.map +1 -0
- package/dist/core/agent-session.d.ts +21 -87
- package/dist/core/agent-session.js +141 -712
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.js +3 -3
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/bundled-agents.js +6 -6
- package/dist/core/bundled-agents.js.map +1 -1
- package/dist/core/checklist-git.d.ts +19 -0
- package/dist/core/checklist-git.js +54 -0
- package/dist/core/checklist-git.js.map +1 -0
- package/dist/core/checklist-items.d.ts +10 -1
- package/dist/core/checklist-items.js +22 -0
- package/dist/core/checklist-items.js.map +1 -1
- package/dist/core/checklist-prompt.d.ts +5 -1
- package/dist/core/checklist-prompt.js +16 -5
- package/dist/core/checklist-prompt.js.map +1 -1
- package/dist/core/checklist-snapshot.d.ts +5 -1
- package/dist/core/checklist-snapshot.js +19 -2
- package/dist/core/checklist-snapshot.js.map +1 -1
- package/dist/core/context-limits.js +1 -1
- package/dist/core/context-limits.js.map +1 -1
- package/dist/core/skills.js +6 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/style-packs/index.js +2 -11
- package/dist/core/style-packs/index.js.map +1 -1
- package/dist/core/style-packs/packs.d.ts +3 -12
- package/dist/core/style-packs/packs.js +132 -173
- package/dist/core/style-packs/packs.js.map +1 -1
- package/dist/system-prompt.js +55 -78
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/ask-user.js +13 -74
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/bash.js +13 -78
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/checklist.d.ts +2 -10
- package/dist/tools/checklist.js +7 -39
- package/dist/tools/checklist.js.map +1 -1
- package/dist/tools/code-nav.js +7 -29
- package/dist/tools/code-nav.js.map +1 -1
- package/dist/tools/edit.d.ts +3 -9
- package/dist/tools/edit.js +66 -65
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/enter-plan.js +2 -7
- package/dist/tools/enter-plan.js.map +1 -1
- package/dist/tools/exit-plan.js +2 -3
- package/dist/tools/exit-plan.js.map +1 -1
- package/dist/tools/find.js +3 -4
- package/dist/tools/find.js.map +1 -1
- package/dist/tools/grep.js +6 -18
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/ls.js +3 -3
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/prompt-hints.js +34 -47
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read.js +8 -20
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/search-code.js +4 -12
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/skill.js +13 -7
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.js +7 -22
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent.js +4 -7
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/task-output.js +4 -15
- package/dist/tools/task-output.js.map +1 -1
- package/dist/tools/task-send.js +5 -17
- package/dist/tools/task-send.js.map +1 -1
- package/dist/tools/task-stop.js +2 -2
- package/dist/tools/task-stop.js.map +1 -1
- package/dist/tools/tool-search.js +2 -7
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts +17 -4
- package/dist/tools/tool-tiers.js +38 -15
- package/dist/tools/tool-tiers.js.map +1 -1
- package/dist/tools/web-fetch.js +7 -33
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.js +3 -4
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/components/Footer.js +1 -2
- package/dist/ui/components/Footer.js.map +1 -1
- package/package.json +7 -4
- package/dist/core/api-benchmark.d.ts +0 -63
- package/dist/core/api-benchmark.js +0 -381
- package/dist/core/api-benchmark.js.map +0 -1
- package/dist/core/bash-spawn-benchmark.d.ts +0 -1
- package/dist/core/bash-spawn-benchmark.js +0 -139
- package/dist/core/bash-spawn-benchmark.js.map +0 -1
- package/dist/core/cache-warm-benchmark.d.ts +0 -21
- package/dist/core/cache-warm-benchmark.js +0 -170
- package/dist/core/cache-warm-benchmark.js.map +0 -1
- package/dist/core/fast-apply-benchmark.d.ts +0 -25
- package/dist/core/fast-apply-benchmark.js +0 -284
- package/dist/core/fast-apply-benchmark.js.map +0 -1
- package/dist/core/hashline-edit-benchmark.d.ts +0 -88
- package/dist/core/hashline-edit-benchmark.js +0 -518
- package/dist/core/hashline-edit-benchmark.js.map +0 -1
- package/dist/core/semantic-search-benchmark.d.ts +0 -36
- package/dist/core/semantic-search-benchmark.js +0 -211
- package/dist/core/semantic-search-benchmark.js.map +0 -1
- package/dist/core/speed-benchmark.d.ts +0 -132
- package/dist/core/speed-benchmark.js +0 -410
- package/dist/core/speed-benchmark.js.map +0 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { AuthStorage } from "../core/auth-storage.js";
|
|
3
|
+
import { advancesPhase, explainPullFailure, isGgufShard, parseOllamaPullLine, pickGgufQuant, SHARDED_MESSAGE, toHfSearchRow, } from "../hf-pull.js";
|
|
4
|
+
/** Per-session Hugging Face → Ollama pull state + Hub search (moved verbatim
|
|
5
|
+
* out of `createSession`). */
|
|
6
|
+
export function createHfPullManager(deps) {
|
|
7
|
+
const { paths, broadcast, broadcastAll, scanLocalModels, localStatePayload } = deps;
|
|
8
|
+
// ── Hugging Face → Ollama pulls (the "Add from Hugging Face" modal) ──
|
|
9
|
+
// One pull at a time: multi-GB downloads, one progress surface. State lives
|
|
10
|
+
// here (not in the webview) so a closed modal or app restart mid-pull keeps
|
|
11
|
+
// streaming; the terminal state is kept until the next pull so reopening the
|
|
12
|
+
// modal shows how the last one ended.
|
|
13
|
+
let hfPull = null;
|
|
14
|
+
const hfPullPayload = (s) => ({
|
|
15
|
+
repo: s.repo,
|
|
16
|
+
model: s.model,
|
|
17
|
+
tag: s.tag,
|
|
18
|
+
file: s.file,
|
|
19
|
+
sizeBytes: s.sizeBytes,
|
|
20
|
+
phase: s.phase,
|
|
21
|
+
percent: s.percent,
|
|
22
|
+
...(s.detail ? { detail: s.detail } : {}),
|
|
23
|
+
...(s.error ? { error: s.error } : {}),
|
|
24
|
+
});
|
|
25
|
+
/** Stored HF token, if the user connected the huggingface provider. */
|
|
26
|
+
async function hfToken() {
|
|
27
|
+
try {
|
|
28
|
+
const auth = new AuthStorage(paths.authFile);
|
|
29
|
+
const creds = await auth.resolveCredentials("huggingface");
|
|
30
|
+
return creds.accessToken || undefined;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function hfHubJson(pathname) {
|
|
37
|
+
const token = await hfToken();
|
|
38
|
+
const res = await fetch(`https://huggingface.co${pathname}`, {
|
|
39
|
+
headers: token ? { authorization: `Bearer ${token}` } : {},
|
|
40
|
+
signal: AbortSignal.timeout(10_000),
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok)
|
|
43
|
+
throw new Error(`Hugging Face responded ${res.status}`);
|
|
44
|
+
return res.json();
|
|
45
|
+
}
|
|
46
|
+
/** Search the Hub for GGUF repos (what Ollama can pull). */
|
|
47
|
+
async function hfSearch(query) {
|
|
48
|
+
// `filter=gguf` (the tag the Hub applies to repos that actually contain
|
|
49
|
+
// GGUF files) — `library=gguf` also matches safetensors-only base repos,
|
|
50
|
+
// which then fail at pull time. `expand[]=gguf` confirms per row.
|
|
51
|
+
const params = new URLSearchParams({
|
|
52
|
+
search: query,
|
|
53
|
+
filter: "gguf",
|
|
54
|
+
sort: "downloads",
|
|
55
|
+
direction: "-1",
|
|
56
|
+
limit: "12",
|
|
57
|
+
});
|
|
58
|
+
for (const field of ["gguf", "downloads", "likes", "lastModified"]) {
|
|
59
|
+
params.append("expand[]", field);
|
|
60
|
+
}
|
|
61
|
+
const data = (await hfHubJson(`/api/models?${params.toString()}`));
|
|
62
|
+
return (Array.isArray(data) ? data : [])
|
|
63
|
+
.map(toHfSearchRow)
|
|
64
|
+
.filter((r) => r !== null);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Start `ollama pull hf.co/<repo>[:quant]`. Resolves once the child is
|
|
68
|
+
* spawned; progress streams as `hf_pull` events. The chosen quant comes from
|
|
69
|
+
* the repo's real file list — the client only ever sends a repo id, so there
|
|
70
|
+
* is no injection surface into argv.
|
|
71
|
+
*/
|
|
72
|
+
async function startHfPull(repo) {
|
|
73
|
+
if (hfPull?.child) {
|
|
74
|
+
throw Object.assign(new Error("A download is already running."), { status: 409 });
|
|
75
|
+
}
|
|
76
|
+
// `recursive=true`: many repos (unsloth, mradermacher) keep quants in
|
|
77
|
+
// per-quant subfolders, and a flat listing reports them as GGUF-less.
|
|
78
|
+
const tree = (await hfHubJson(`/api/models/${repo}/tree/main?recursive=true`));
|
|
79
|
+
const files = (Array.isArray(tree) ? tree : []).flatMap((entry) => {
|
|
80
|
+
const e = entry;
|
|
81
|
+
// `type` guards a directory entry (size 0) from beating real files in the
|
|
82
|
+
// size fallback; the Hub marks folders as "directory".
|
|
83
|
+
if (e.type !== undefined && e.type !== "file")
|
|
84
|
+
return [];
|
|
85
|
+
if (typeof e.path !== "string" || !e.path.toLowerCase().endsWith(".gguf"))
|
|
86
|
+
return [];
|
|
87
|
+
const size = Number(e.lfs?.size ?? e.size ?? 0);
|
|
88
|
+
return [{ path: e.path, sizeBytes: Number.isFinite(size) ? size : 0 }];
|
|
89
|
+
});
|
|
90
|
+
const choice = pickGgufQuant(files);
|
|
91
|
+
if (!choice) {
|
|
92
|
+
const sharded = files.some((f) => isGgufShard(f.path));
|
|
93
|
+
throw Object.assign(new Error(sharded ? SHARDED_MESSAGE : "That repo has no GGUF file for Ollama to pull."), { status: 400 });
|
|
94
|
+
}
|
|
95
|
+
const model = `hf.co/${repo}${choice.tag ? `:${choice.tag}` : ""}`;
|
|
96
|
+
const token = await hfToken();
|
|
97
|
+
const state = {
|
|
98
|
+
repo,
|
|
99
|
+
model,
|
|
100
|
+
tag: choice.tag,
|
|
101
|
+
file: choice.file.path,
|
|
102
|
+
sizeBytes: choice.file.sizeBytes,
|
|
103
|
+
phase: "preparing",
|
|
104
|
+
percent: 0,
|
|
105
|
+
child: null,
|
|
106
|
+
};
|
|
107
|
+
hfPull = state;
|
|
108
|
+
broadcast("hf_pull", hfPullPayload(state));
|
|
109
|
+
// ollama prints progress to stderr (stdout on some builds); parse both.
|
|
110
|
+
let stderrTail = "";
|
|
111
|
+
let lastBroadcast = "";
|
|
112
|
+
const feed = (chunk) => {
|
|
113
|
+
// Once the pull is terminal (success, failure, or user cancel) stop
|
|
114
|
+
// parsing: a killed ollama dumps a burst of stderr that would otherwise
|
|
115
|
+
// spam the modal with garbage frames after the outcome is already shown.
|
|
116
|
+
if (state.phase === "success" || state.phase === "error")
|
|
117
|
+
return;
|
|
118
|
+
for (const line of chunk.split(/\r\n|\r|\n/)) {
|
|
119
|
+
const parsed = parseOllamaPullLine(line);
|
|
120
|
+
if (!parsed)
|
|
121
|
+
continue;
|
|
122
|
+
// A redrawn frame repeats `pulling manifest` next to live progress; it
|
|
123
|
+
// must not drag the modal back to "Contacting Ollama…".
|
|
124
|
+
if (!advancesPhase(state.phase, parsed.phase))
|
|
125
|
+
continue;
|
|
126
|
+
if (parsed.phase !== "error") {
|
|
127
|
+
state.phase = parsed.phase;
|
|
128
|
+
if (parsed.percent !== undefined)
|
|
129
|
+
state.percent = parsed.percent;
|
|
130
|
+
state.detail = parsed.detail;
|
|
131
|
+
}
|
|
132
|
+
// ollama redraws its TUI frame several times a second, mostly with
|
|
133
|
+
// identical numbers. Broadcasting each one re-rendered the modal for no
|
|
134
|
+
// visible change; only a frame that actually reads differently ships.
|
|
135
|
+
const next = JSON.stringify(hfPullPayload(state));
|
|
136
|
+
if (next === lastBroadcast)
|
|
137
|
+
continue;
|
|
138
|
+
lastBroadcast = next;
|
|
139
|
+
broadcast("hf_pull", hfPullPayload(state));
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
try {
|
|
143
|
+
const child = spawn("ollama", ["pull", model], {
|
|
144
|
+
env: { ...process.env, ...(token ? { HF_TOKEN: token } : {}) },
|
|
145
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
146
|
+
});
|
|
147
|
+
state.child = child;
|
|
148
|
+
child.stdout?.setEncoding("utf8");
|
|
149
|
+
child.stderr?.setEncoding("utf8");
|
|
150
|
+
child.stdout?.on("data", feed);
|
|
151
|
+
child.stderr?.on("data", (d) => {
|
|
152
|
+
stderrTail = (stderrTail + d).slice(-2000);
|
|
153
|
+
feed(d);
|
|
154
|
+
});
|
|
155
|
+
child.on("error", (err) => {
|
|
156
|
+
state.child = null;
|
|
157
|
+
state.phase = "error";
|
|
158
|
+
state.error =
|
|
159
|
+
err.code === "ENOENT"
|
|
160
|
+
? "Ollama isn't installed (or isn't on PATH). Install it from ollama.com, then retry."
|
|
161
|
+
: `Could not start Ollama: ${err.message}`;
|
|
162
|
+
broadcast("hf_pull", hfPullPayload(state));
|
|
163
|
+
});
|
|
164
|
+
child.on("close", (code) => {
|
|
165
|
+
state.child = null;
|
|
166
|
+
if (state.phase === "success" || state.phase === "error")
|
|
167
|
+
return; // cancelled
|
|
168
|
+
if (code === 0) {
|
|
169
|
+
state.phase = "success";
|
|
170
|
+
state.percent = 100;
|
|
171
|
+
state.detail = undefined;
|
|
172
|
+
broadcast("hf_pull", hfPullPayload(state));
|
|
173
|
+
// The new model only exists to the app once Ollama lists it. Ollama's
|
|
174
|
+
// library is machine-wide, like the shared auth file, so every window
|
|
175
|
+
// gets the refresh — not just the one that ran the download.
|
|
176
|
+
void scanLocalModels(true)
|
|
177
|
+
.then(() => broadcastAll("models_change", { local: localStatePayload() }))
|
|
178
|
+
.catch(() => undefined);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
state.phase = "error";
|
|
182
|
+
state.error = state.error ?? explainPullFailure(stderrTail);
|
|
183
|
+
broadcast("hf_pull", hfPullPayload(state));
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
state.child = null;
|
|
189
|
+
state.phase = "error";
|
|
190
|
+
state.error = `Could not start Ollama: ${err instanceof Error ? err.message : String(err)}`;
|
|
191
|
+
broadcast("hf_pull", hfPullPayload(state));
|
|
192
|
+
}
|
|
193
|
+
return hfPullPayload(state);
|
|
194
|
+
}
|
|
195
|
+
function cancelHfPull() {
|
|
196
|
+
const child = hfPull?.child;
|
|
197
|
+
if (!child)
|
|
198
|
+
return false;
|
|
199
|
+
// Terminal state FIRST, then the kill: the child's death rattle must not
|
|
200
|
+
// overwrite the clean "cancelled" outcome with raw stderr.
|
|
201
|
+
if (hfPull) {
|
|
202
|
+
hfPull.phase = "error";
|
|
203
|
+
hfPull.error = "Download cancelled.";
|
|
204
|
+
hfPull.detail = undefined;
|
|
205
|
+
hfPull.child = null;
|
|
206
|
+
broadcast("hf_pull", hfPullPayload(hfPull));
|
|
207
|
+
}
|
|
208
|
+
child.kill("SIGTERM");
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
get hfPull() {
|
|
213
|
+
return hfPull;
|
|
214
|
+
},
|
|
215
|
+
set hfPull(v) {
|
|
216
|
+
hfPull = v;
|
|
217
|
+
},
|
|
218
|
+
hfPullPayload,
|
|
219
|
+
hfSearch,
|
|
220
|
+
startHfPull,
|
|
221
|
+
cancelHfPull,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=hf-pull-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hf-pull-manager.js","sourceRoot":"","sources":["../../src/app-sidecar/hf-pull-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { restoreAppErrorPayload } from "../app-error.js";
|
|
3
|
+
import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, getHistoryMessageVisibility, replayMessagesInOrder, restoreUserRow, restoreAssistantTexts, resolveRestoredCommand, extractToolImagePaths, } from "../core/session-history.js";
|
|
4
|
+
import { spawnedTasks } from "../tools/subagent-shared.js";
|
|
5
|
+
import { PROMPT_COMMANDS } from "../core/prompt-commands.js";
|
|
6
|
+
import { loadCustomCommands } from "../core/custom-commands.js";
|
|
7
|
+
import { downscaleForPreview, IMAGE_MEDIA_TYPES } from "../utils/image.js";
|
|
8
|
+
import { readFileBounded } from "../tools/operations.js";
|
|
9
|
+
import { json } from "./http.js";
|
|
10
|
+
import { detectHookKind } from "./history.js";
|
|
11
|
+
export function handleHistoryRoutes(ctx, req, res, url, method) {
|
|
12
|
+
if (method === "GET" && url === "/history") {
|
|
13
|
+
// Reconstruct the transcript from persisted messages so resume is 1:1 with
|
|
14
|
+
// the live SSE stream. Walks ALL message types (not just user/assistant):
|
|
15
|
+
// tool result messages carry ImageContent blocks (screenshots,
|
|
16
|
+
// generate_image) that must re-render inline, and assistant tool_call
|
|
17
|
+
// blocks carry sub-agent delegations that must re-appear as group items.
|
|
18
|
+
//
|
|
19
|
+
// The `details` object (imagePreviews with path + downscaled preview) is
|
|
20
|
+
// event-only and never persisted — we reconstruct from the raw
|
|
21
|
+
// ImageContent in the tool result, downsampling on the sidecar side and
|
|
22
|
+
// extracting the path from the text block ("Generated image → /path").
|
|
23
|
+
void (async () => {
|
|
24
|
+
const commandCandidates = [...PROMPT_COMMANDS, ...(await loadCustomCommands(ctx.cwd))];
|
|
25
|
+
const messages = ctx.session.getMessages();
|
|
26
|
+
// An Ideal hook is injected immediately after the assistant's candidate
|
|
27
|
+
// no-tool response. That response is review scratch, not a user-visible
|
|
28
|
+
// final answer. Live SSE drops it when the hook event arrives; mark the
|
|
29
|
+
// same assistant message here so resumed history stays identical.
|
|
30
|
+
const hiddenIdealDrafts = new Set();
|
|
31
|
+
for (let i = 0; i < messages.length - 1; i++) {
|
|
32
|
+
const draft = messages[i];
|
|
33
|
+
const hookPrompt = messages[i + 1];
|
|
34
|
+
if (draft?.role !== "assistant" || hookPrompt?.role !== "user")
|
|
35
|
+
continue;
|
|
36
|
+
const restored = restoreUserRow(hookPrompt.content);
|
|
37
|
+
if (detectHookKind(restored.text) === "ideal")
|
|
38
|
+
hiddenIdealDrafts.add(draft);
|
|
39
|
+
}
|
|
40
|
+
// Pre-index tool results by toolCallId so we can pair tool calls with
|
|
41
|
+
// their results (for sub-agent status + image extraction).
|
|
42
|
+
const toolResultMap = new Map();
|
|
43
|
+
// Tool name per call, so restore only trusts generate_image's own text
|
|
44
|
+
// when it reads extra images from disk (an MCP server could fake it).
|
|
45
|
+
const toolNameById = new Map();
|
|
46
|
+
for (const msg of messages) {
|
|
47
|
+
if (msg.role === "assistant" && typeof msg.content !== "string") {
|
|
48
|
+
for (const c of msg.content) {
|
|
49
|
+
if (c.type === "tool_call")
|
|
50
|
+
toolNameById.set(c.id, c.name);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (msg.role !== "tool")
|
|
54
|
+
continue;
|
|
55
|
+
for (const tr of msg.content) {
|
|
56
|
+
toolResultMap.set(tr.toolCallId, {
|
|
57
|
+
content: tr.content,
|
|
58
|
+
isError: tr.isError ?? false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const history = [];
|
|
63
|
+
// Ken (mentor) turns to interleave: group by the non-system message count
|
|
64
|
+
// they were recorded after, so each lands right after that message. A
|
|
65
|
+
// turn becomes two wire rows: the `@Ken` question (user) + Ken's reply
|
|
66
|
+
// (assistant), both flagged `ken` so the webview tints them.
|
|
67
|
+
// Deduped; stale anchors are clamped to the last message (Ken turns
|
|
68
|
+
// carry real conversation, so they render at the end instead of
|
|
69
|
+
// vanishing).
|
|
70
|
+
const kenByCount = new Map();
|
|
71
|
+
for (const turn of normalizeKenTurnsForHistory(ctx.session.getKenTurns(), messages.filter((m) => m.role !== "system").length)) {
|
|
72
|
+
const list = kenByCount.get(turn.afterMessageCount) ?? [];
|
|
73
|
+
list.push(turn);
|
|
74
|
+
kenByCount.set(turn.afterMessageCount, list);
|
|
75
|
+
}
|
|
76
|
+
const flushKen = (count) => {
|
|
77
|
+
const turns = kenByCount.get(count);
|
|
78
|
+
if (!turns)
|
|
79
|
+
return;
|
|
80
|
+
kenByCount.delete(count);
|
|
81
|
+
for (const turn of turns) {
|
|
82
|
+
history.push({ role: "user", text: `@Ken ${turn.question}`, ken: true });
|
|
83
|
+
history.push({ role: "assistant", text: turn.reply, ken: true });
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
// Autopilot verdict markers to interleave, same anchor scheme as Ken
|
|
87
|
+
// turns — each becomes a single assistant row the webview renders
|
|
88
|
+
// exactly like the live `autopilot` item (never a raw verdict string).
|
|
89
|
+
// Normalization pulls anchors left over from an unrebased compaction
|
|
90
|
+
// back to where the marker was actually written, so stale all-clear
|
|
91
|
+
// bubbles no longer bunch at the bottom of a reopened session.
|
|
92
|
+
const restoredMessageCount = messages.filter((m) => m.role !== "system").length;
|
|
93
|
+
const autopilotByCount = new Map();
|
|
94
|
+
for (const marker of normalizeAutopilotMarkersForHistory(ctx.session.getAutopilotMarkers(), restoredMessageCount)) {
|
|
95
|
+
const list = autopilotByCount.get(marker.afterMessageCount) ?? [];
|
|
96
|
+
list.push(marker);
|
|
97
|
+
autopilotByCount.set(marker.afterMessageCount, list);
|
|
98
|
+
}
|
|
99
|
+
const flushAutopilot = (count) => {
|
|
100
|
+
const markers = autopilotByCount.get(count);
|
|
101
|
+
if (!markers)
|
|
102
|
+
return;
|
|
103
|
+
autopilotByCount.delete(count);
|
|
104
|
+
for (const marker of markers) {
|
|
105
|
+
history.push({
|
|
106
|
+
role: "assistant",
|
|
107
|
+
text: "",
|
|
108
|
+
autopilot: {
|
|
109
|
+
phase: marker.phase,
|
|
110
|
+
...(marker.reason !== undefined ? { reason: marker.reason } : {}),
|
|
111
|
+
...(marker.body !== undefined ? { body: marker.body } : {}),
|
|
112
|
+
copySeed: marker.copySeed,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
// App transcript markers (plan banner / task header / error rows /
|
|
118
|
+
// user-bubble hints), same anchor scheme. user_hint markers don't
|
|
119
|
+
// become rows — they decorate the user row at their anchor instead.
|
|
120
|
+
const appMarkersByCount = new Map();
|
|
121
|
+
const userHintByCount = new Map();
|
|
122
|
+
// Compaction-count markers pair with compacted summary rows in file
|
|
123
|
+
// order (FIFO), not by anchor — the summary user message is what
|
|
124
|
+
// positions the notice.
|
|
125
|
+
const compactionCounts = [];
|
|
126
|
+
for (const marker of normalizeAppMarkersForHistory(ctx.session.getAppMarkers(), restoredMessageCount)) {
|
|
127
|
+
if (marker.kind === "user_hint") {
|
|
128
|
+
userHintByCount.set(marker.afterMessageCount, marker.data);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (marker.kind === "compaction") {
|
|
132
|
+
const d = marker.data;
|
|
133
|
+
if (typeof d.originalCount === "number" && typeof d.newCount === "number") {
|
|
134
|
+
compactionCounts.push({ originalCount: d.originalCount, newCount: d.newCount });
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const list = appMarkersByCount.get(marker.afterMessageCount) ?? [];
|
|
139
|
+
list.push(marker);
|
|
140
|
+
appMarkersByCount.set(marker.afterMessageCount, list);
|
|
141
|
+
}
|
|
142
|
+
const flushAppMarkers = (count) => {
|
|
143
|
+
const markers = appMarkersByCount.get(count);
|
|
144
|
+
if (!markers)
|
|
145
|
+
return;
|
|
146
|
+
appMarkersByCount.delete(count);
|
|
147
|
+
for (const marker of markers) {
|
|
148
|
+
const d = marker.data;
|
|
149
|
+
if (marker.kind === "plan") {
|
|
150
|
+
history.push({
|
|
151
|
+
role: "assistant",
|
|
152
|
+
text: "",
|
|
153
|
+
plan: { reason: typeof d.reason === "string" ? d.reason : "" },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else if (marker.kind === "task") {
|
|
157
|
+
history.push({
|
|
158
|
+
role: "assistant",
|
|
159
|
+
text: "",
|
|
160
|
+
task: { title: typeof d.title === "string" ? d.title : "" },
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else if (marker.kind === "error" && typeof d.headline === "string") {
|
|
164
|
+
const error = restoreAppErrorPayload(d);
|
|
165
|
+
if (error)
|
|
166
|
+
history.push({ role: "assistant", text: "", error });
|
|
167
|
+
}
|
|
168
|
+
else if (marker.kind === "interrupted_run") {
|
|
169
|
+
// Rendered as an error row: the run's tools already changed the
|
|
170
|
+
// repo, so the user needs to see it and decide what to do. We
|
|
171
|
+
// never replay it — that would duplicate those changes.
|
|
172
|
+
history.push({
|
|
173
|
+
role: "assistant",
|
|
174
|
+
text: "",
|
|
175
|
+
error: {
|
|
176
|
+
scope: "interrupted_run",
|
|
177
|
+
headline: "A run was interrupted",
|
|
178
|
+
message: "GG Coder stopped mid-run, so this turn is incomplete. Any files its tools already changed are still on disk.",
|
|
179
|
+
guidance: "Review the working tree, then re-send the request if you still want it.",
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
let nonSystemCount = 0;
|
|
186
|
+
// Turns/markers recorded before any build message (anchor 0) render at
|
|
187
|
+
// the top.
|
|
188
|
+
flushKen(0);
|
|
189
|
+
flushAutopilot(0);
|
|
190
|
+
flushAppMarkers(0);
|
|
191
|
+
await replayMessagesInOrder(messages, async (msg, count) => {
|
|
192
|
+
nonSystemCount = count;
|
|
193
|
+
const visibility = getHistoryMessageVisibility(msg);
|
|
194
|
+
if (visibility === "hidden")
|
|
195
|
+
return;
|
|
196
|
+
if (msg.role === "tool") {
|
|
197
|
+
// Tool result messages: check for ImageContent blocks (screenshots,
|
|
198
|
+
// generated images) and emit a toolImages entry.
|
|
199
|
+
for (const tr of msg.content) {
|
|
200
|
+
if (typeof tr.content === "string")
|
|
201
|
+
continue;
|
|
202
|
+
const imageBlocks = tr.content.filter((c) => c.type === "image");
|
|
203
|
+
if (imageBlocks.length === 0)
|
|
204
|
+
continue;
|
|
205
|
+
// Extract the path from the text block so the restored image
|
|
206
|
+
// stays clickable (read / screenshot / generate_image formats).
|
|
207
|
+
const textBlock = tr.content.find((c) => c.type === "text" && "text" in c && typeof c.text === "string");
|
|
208
|
+
const textContent = textBlock && textBlock.type === "text" ? textBlock.text : "";
|
|
209
|
+
const imgPaths = extractToolImagePaths(textContent);
|
|
210
|
+
// Downscale each image for the webview preview. Paths pair with
|
|
211
|
+
// image blocks in order (a tool saves one file per image).
|
|
212
|
+
const toolImages = [];
|
|
213
|
+
let blockIndex = 0;
|
|
214
|
+
for (const block of imageBlocks) {
|
|
215
|
+
if (block.type !== "image")
|
|
216
|
+
continue;
|
|
217
|
+
const imgPath = imgPaths[blockIndex++];
|
|
218
|
+
const previewBuf = await downscaleForPreview(Buffer.from(block.data, "base64"));
|
|
219
|
+
toolImages.push({
|
|
220
|
+
src: `data:${block.mediaType};base64,${previewBuf.toString("base64")}`,
|
|
221
|
+
path: imgPath,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
// generate_image persists only its first image's pixels; the
|
|
225
|
+
// rest exist only on disk, so preview them from their files.
|
|
226
|
+
// Skip silently if a file was moved or deleted since.
|
|
227
|
+
const extraPaths = toolNameById.get(tr.toolCallId) === "generate_image"
|
|
228
|
+
? imgPaths.slice(blockIndex)
|
|
229
|
+
: [];
|
|
230
|
+
for (const extraPath of extraPaths) {
|
|
231
|
+
const mediaType = IMAGE_MEDIA_TYPES[path.extname(extraPath).toLowerCase()];
|
|
232
|
+
if (!mediaType)
|
|
233
|
+
continue;
|
|
234
|
+
const raw = await readFileBounded(extraPath).catch(() => null);
|
|
235
|
+
if (!raw)
|
|
236
|
+
continue;
|
|
237
|
+
const previewBuf = await downscaleForPreview(raw);
|
|
238
|
+
toolImages.push({
|
|
239
|
+
src: `data:${mediaType};base64,${previewBuf.toString("base64")}`,
|
|
240
|
+
path: extraPath,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (toolImages.length > 0) {
|
|
244
|
+
history.push({
|
|
245
|
+
role: "assistant",
|
|
246
|
+
text: "",
|
|
247
|
+
toolImages,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
// User or assistant message — text/hook/command/compacted extraction,
|
|
254
|
+
// plus sub-agent group detection for assistant tool_calls.
|
|
255
|
+
if (msg.role === "user") {
|
|
256
|
+
// Rebuild the live bubble: strip the steering wrapper, drop
|
|
257
|
+
// attachment/file notes the model saw but the bubble never showed.
|
|
258
|
+
const restored = restoreUserRow(msg.content, msg.provenance);
|
|
259
|
+
const text = restored.text;
|
|
260
|
+
const hook = msg.provenance ? null : detectHookKind(text);
|
|
261
|
+
const compacted = visibility === "summary" ||
|
|
262
|
+
(!msg.provenance && !hook && text.startsWith("[Previous conversation summary]"));
|
|
263
|
+
const hint = userHintByCount.get(nonSystemCount);
|
|
264
|
+
// The typed invocation persisted alongside the prompt is
|
|
265
|
+
// authoritative. Reversing the expanded body only works while the
|
|
266
|
+
// template is byte-identical, and templates drift (edited
|
|
267
|
+
// `.gg/commands/*.md`, reworded built-ins, app-vs-CLI phrasing) —
|
|
268
|
+
// after which the resumed session dumped the raw multi-KB body
|
|
269
|
+
// instead of the `/name` chip. Older sessions have no hint, so the
|
|
270
|
+
// body match stays as the fallback.
|
|
271
|
+
const command = !hook && !compacted
|
|
272
|
+
? resolveRestoredCommand(typeof hint?.command === "string" ? hint.command : null, text, commandCandidates)
|
|
273
|
+
: null;
|
|
274
|
+
// Autopilot injected this turn — live showed only the Ken-tinted
|
|
275
|
+
// marker for it, never a user bubble. Emitting one here would print
|
|
276
|
+
// the injected instruction a second time, unstyled.
|
|
277
|
+
//
|
|
278
|
+
// Pushed background-status updates are skipped for the same reason:
|
|
279
|
+
// the live run rendered no bubble for them, so showing them here
|
|
280
|
+
// would fill a reopened session with machine-facing status lines
|
|
281
|
+
// the user never saw while working.
|
|
282
|
+
if ((!msg.provenance || (!restored.autopilotInjected && !restored.notification)) &&
|
|
283
|
+
(text.trim() || restored.images.length > 0)) {
|
|
284
|
+
history.push({
|
|
285
|
+
role: "user",
|
|
286
|
+
text: command ?? text,
|
|
287
|
+
images: restored.images,
|
|
288
|
+
hook,
|
|
289
|
+
command: command !== null,
|
|
290
|
+
compacted,
|
|
291
|
+
// Markers accumulate across continuation files (each rewrite
|
|
292
|
+
// re-persists prior ones) but only the LATEST summary row
|
|
293
|
+
// survives compaction — so consume from the newest end.
|
|
294
|
+
...(compacted && compactionCounts.length > 0
|
|
295
|
+
? { compactionCounts: compactionCounts.pop() }
|
|
296
|
+
: {}),
|
|
297
|
+
...(hint?.kenSent === true ? { kenSent: true } : {}),
|
|
298
|
+
...(Array.isArray(hint?.enhancements) ? { enhancements: hint.enhancements } : {}),
|
|
299
|
+
});
|
|
300
|
+
// Live showed the video-capability warning right after the bubble.
|
|
301
|
+
if (restored.videoWarning) {
|
|
302
|
+
history.push({ role: "assistant", text: "", infoKind: "video_warning" });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else if (!hiddenIdealDrafts.has(msg)) {
|
|
307
|
+
// Assistant: one wire row per persisted text block — live streaming
|
|
308
|
+
// splits bubbles at server_tool_call boundaries, and the persisted
|
|
309
|
+
// content keeps those blocks separate. Ideal-review candidate drafts
|
|
310
|
+
// are intentionally omitted to match the live pre-final hook flow.
|
|
311
|
+
for (const blockText of restoreAssistantTexts(msg.content)) {
|
|
312
|
+
history.push({
|
|
313
|
+
role: "assistant",
|
|
314
|
+
text: blockText,
|
|
315
|
+
images: [],
|
|
316
|
+
hook: null,
|
|
317
|
+
command: false,
|
|
318
|
+
compacted: false,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Assistant tool_call blocks: detect sub-agent delegations.
|
|
323
|
+
if (msg.role === "assistant" && typeof msg.content !== "string") {
|
|
324
|
+
const subagentCalls = msg.content.filter((c) => c.type === "tool_call" && (c.name === "subagent" || c.name === "spawn_agent"));
|
|
325
|
+
if (subagentCalls.length > 0) {
|
|
326
|
+
const agents = subagentCalls.flatMap((c) => {
|
|
327
|
+
const result = toolResultMap.get(c.id);
|
|
328
|
+
// Async workers are intentionally non-resumable; restored rows are historical.
|
|
329
|
+
const status = result?.isError ? "error" : "done";
|
|
330
|
+
if (c.name === "spawn_agent") {
|
|
331
|
+
// One row per child: a batch call starts several.
|
|
332
|
+
return spawnedTasks(c.args).map((spawn) => ({
|
|
333
|
+
agentName: spawn.task_name ?? spawn.agent,
|
|
334
|
+
status,
|
|
335
|
+
toolUseCount: 0,
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
return [
|
|
339
|
+
{
|
|
340
|
+
agentName: typeof c.args?.agent === "string" ? c.args.agent : undefined,
|
|
341
|
+
status,
|
|
342
|
+
toolUseCount: 0,
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
});
|
|
346
|
+
history.push({
|
|
347
|
+
role: "assistant",
|
|
348
|
+
text: "",
|
|
349
|
+
subagentGroup: agents,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}, (count) => {
|
|
354
|
+
// Markers flush after every physical message, including tools and
|
|
355
|
+
// provenance-hidden runtime context.
|
|
356
|
+
flushKen(count);
|
|
357
|
+
flushAutopilot(count);
|
|
358
|
+
flushAppMarkers(count);
|
|
359
|
+
});
|
|
360
|
+
// Flush remaining Ken turns whose anchor is at/after the message count so
|
|
361
|
+
// none are dropped. Autopilot/app markers beyond the restored message
|
|
362
|
+
// count were already filtered above; any remaining marker here is valid.
|
|
363
|
+
for (const count of [...kenByCount.keys()].sort((a, b) => a - b))
|
|
364
|
+
flushKen(count);
|
|
365
|
+
for (const count of [...autopilotByCount.keys()].sort((a, b) => a - b))
|
|
366
|
+
flushAutopilot(count);
|
|
367
|
+
for (const count of [...appMarkersByCount.keys()].sort((a, b) => a - b))
|
|
368
|
+
flushAppMarkers(count);
|
|
369
|
+
json(res, 200, { history });
|
|
370
|
+
})();
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=history-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-routes.js","sourceRoot":"","sources":["../../src/app-sidecar/history-routes.ts"],"names":[],"mappings":"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"}
|