kimiflare 0.80.0 → 0.82.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/dist/index.js +575 -139
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +10 -0
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7198,6 +7198,41 @@ function isNewer(local, remote) {
|
|
|
7198
7198
|
}
|
|
7199
7199
|
return false;
|
|
7200
7200
|
}
|
|
7201
|
+
async function readOptionalDepVersion(name) {
|
|
7202
|
+
try {
|
|
7203
|
+
const here = dirname6(fileURLToPath2(import.meta.url));
|
|
7204
|
+
const candidate = join12(here, "..", "..", "node_modules", name, "package.json");
|
|
7205
|
+
const raw = await readFile7(candidate, "utf8");
|
|
7206
|
+
const parsed = JSON.parse(raw);
|
|
7207
|
+
return parsed.version ?? null;
|
|
7208
|
+
} catch {
|
|
7209
|
+
return null;
|
|
7210
|
+
}
|
|
7211
|
+
}
|
|
7212
|
+
async function fetchDistTagVersion(name, tag2) {
|
|
7213
|
+
try {
|
|
7214
|
+
const res = await fetch(`https://registry.npmjs.org/${name}/${tag2}`, {
|
|
7215
|
+
headers: { "User-Agent": getUserAgent(), Accept: "application/json" }
|
|
7216
|
+
});
|
|
7217
|
+
if (!res.ok) return null;
|
|
7218
|
+
const data = await res.json();
|
|
7219
|
+
return data.version ?? null;
|
|
7220
|
+
} catch {
|
|
7221
|
+
return null;
|
|
7222
|
+
}
|
|
7223
|
+
}
|
|
7224
|
+
async function checkOptionalDependency(name, tag2) {
|
|
7225
|
+
const localVersion = await readOptionalDepVersion(name);
|
|
7226
|
+
if (!localVersion) {
|
|
7227
|
+
return { name, hasUpdate: false, localVersion: null, latestVersion: null };
|
|
7228
|
+
}
|
|
7229
|
+
const latestVersion = await fetchDistTagVersion(name, tag2);
|
|
7230
|
+
if (!latestVersion) {
|
|
7231
|
+
return { name, hasUpdate: false, localVersion, latestVersion: null };
|
|
7232
|
+
}
|
|
7233
|
+
const hasUpdate = isNewer(localVersion, latestVersion);
|
|
7234
|
+
return { name, hasUpdate, localVersion, latestVersion };
|
|
7235
|
+
}
|
|
7201
7236
|
async function checkForUpdate(force = false) {
|
|
7202
7237
|
const localVersion = await readLocalVersion();
|
|
7203
7238
|
if (!localVersion) return { hasUpdate: false, localVersion: null, latestVersion: null };
|
|
@@ -12236,6 +12271,8 @@ var init_supervisor = __esm({
|
|
|
12236
12271
|
_phase = "idle";
|
|
12237
12272
|
_killRequested = false;
|
|
12238
12273
|
_activeWorkers = /* @__PURE__ */ new Map();
|
|
12274
|
+
/** Injectable LLM client for synthesis (overridable in tests). */
|
|
12275
|
+
_runKimi = runKimi;
|
|
12239
12276
|
/** Coordinator-side MemoryManager for proxying memories to workers */
|
|
12240
12277
|
memoryManager = null;
|
|
12241
12278
|
/** Coordinator-side LspManager for proxying LSP context to workers */
|
|
@@ -12631,17 +12668,8 @@ ${w.context ?? ""}` : w.context ?? "",
|
|
|
12631
12668
|
}
|
|
12632
12669
|
return results;
|
|
12633
12670
|
}
|
|
12634
|
-
/**
|
|
12635
|
-
|
|
12636
|
-
* Steps:
|
|
12637
|
-
* 1. Deduplicate findings by topic (case-insensitive), keeping the highest-confidence version.
|
|
12638
|
-
* 2. Detect conflicts — same topic with different recommendations.
|
|
12639
|
-
* 3. Tie-breaker: when conflicting recommendations exist, prefer the one from
|
|
12640
|
-
* the worker with higher average confidence.
|
|
12641
|
-
* 4. Produce a markdown execution plan the coordinator can present to the user
|
|
12642
|
-
* or feed into an executor worker.
|
|
12643
|
-
*/
|
|
12644
|
-
synthesizeFindings(results) {
|
|
12671
|
+
/** Heuristic synthesis — exact legacy behavior, preserved as fallback. */
|
|
12672
|
+
synthesizeFindingsHeuristic(results) {
|
|
12645
12673
|
const allFindings = results.flatMap((r) => r.findings);
|
|
12646
12674
|
const allRecommendations = results.flatMap((r) => r.recommendations);
|
|
12647
12675
|
const CONFIDENCE_SCORE = { high: 3, medium: 2, low: 1 };
|
|
@@ -12710,6 +12738,119 @@ ${w.context ?? ""}` : w.context ?? "",
|
|
|
12710
12738
|
recommendations: resolvedRecommendations
|
|
12711
12739
|
};
|
|
12712
12740
|
}
|
|
12741
|
+
/** LLM-based synthesis with graceful fallback to heuristic. */
|
|
12742
|
+
async synthesizeFindingsLlm(results, opts2) {
|
|
12743
|
+
const MAX_RAW_OUTPUT = 2e3;
|
|
12744
|
+
const MAX_REASONING = 2e3;
|
|
12745
|
+
const workerBlocks = results.map((r, i) => {
|
|
12746
|
+
const findings = r.findings.map(
|
|
12747
|
+
(f) => ` - Topic: ${f.topic}
|
|
12748
|
+
Summary: ${f.summary}
|
|
12749
|
+
Confidence: ${f.confidence}
|
|
12750
|
+
Relevance: ${f.relevance}
|
|
12751
|
+
Sources: ${f.sources.join(", ") || "none"}`
|
|
12752
|
+
).join("\n");
|
|
12753
|
+
const recs = r.recommendations.map((rec) => ` - ${rec}`).join("\n") || " (none)";
|
|
12754
|
+
const reasoning = r.reasoning ? r.reasoning.slice(0, MAX_REASONING) : "(none)";
|
|
12755
|
+
const rawOutput = r.rawOutput ? r.rawOutput.slice(0, MAX_RAW_OUTPUT) : "(none)";
|
|
12756
|
+
return [
|
|
12757
|
+
`--- Worker ${r.workerId || `w${i + 1}`} ---`,
|
|
12758
|
+
`Task: ${r.task}`,
|
|
12759
|
+
`Status: ${r.status}`,
|
|
12760
|
+
`Findings:
|
|
12761
|
+
${findings || " (none)"}`,
|
|
12762
|
+
`Recommendations:
|
|
12763
|
+
${recs}`,
|
|
12764
|
+
`Reasoning:
|
|
12765
|
+
${reasoning}`,
|
|
12766
|
+
`Raw Output (truncated):
|
|
12767
|
+
${rawOutput}`
|
|
12768
|
+
].join("\n");
|
|
12769
|
+
});
|
|
12770
|
+
const userContent = [
|
|
12771
|
+
opts2.prompt ? `Original user request:
|
|
12772
|
+
${opts2.prompt}` : "",
|
|
12773
|
+
"",
|
|
12774
|
+
"Worker outputs:",
|
|
12775
|
+
workerBlocks.join("\n\n"),
|
|
12776
|
+
"",
|
|
12777
|
+
"Instructions:",
|
|
12778
|
+
"1. Synthesize the worker findings into a coherent execution plan.",
|
|
12779
|
+
"2. Detect and resolve any conflicts between workers.",
|
|
12780
|
+
"3. Cite sources inline using [worker: <id>] notation.",
|
|
12781
|
+
"4. Return ONLY valid JSON in this exact shape (no markdown fences):",
|
|
12782
|
+
'{"plan":"markdown plan","conflicts":["string"],"recommendations":["string"],"reasoning":"optional string"}'
|
|
12783
|
+
].filter(Boolean).join("\n");
|
|
12784
|
+
const messages = [
|
|
12785
|
+
{
|
|
12786
|
+
role: "system",
|
|
12787
|
+
content: "You are a synthesis engine. Combine findings from multiple research workers into a single coherent execution plan. Be concise. Return only valid JSON."
|
|
12788
|
+
},
|
|
12789
|
+
{ role: "user", content: userContent }
|
|
12790
|
+
];
|
|
12791
|
+
let text = "";
|
|
12792
|
+
const events = this._runKimi({
|
|
12793
|
+
accountId: opts2.accountId,
|
|
12794
|
+
apiToken: opts2.apiToken,
|
|
12795
|
+
model: opts2.model,
|
|
12796
|
+
messages,
|
|
12797
|
+
temperature: 0.2,
|
|
12798
|
+
maxCompletionTokens: 4096,
|
|
12799
|
+
reasoningEffort: "low",
|
|
12800
|
+
gateway: opts2.gateway,
|
|
12801
|
+
signal: opts2.signal
|
|
12802
|
+
});
|
|
12803
|
+
for await (const ev of events) {
|
|
12804
|
+
if (ev.type === "text") {
|
|
12805
|
+
text += ev.delta;
|
|
12806
|
+
opts2.onDelta?.(ev.delta);
|
|
12807
|
+
}
|
|
12808
|
+
}
|
|
12809
|
+
const cleaned = text.replace(/```(?:json)?\s*/gi, "").replace(/```\s*$/gi, "").trim();
|
|
12810
|
+
const parsed = JSON.parse(cleaned);
|
|
12811
|
+
if (!parsed.plan || !Array.isArray(parsed.conflicts) || !Array.isArray(parsed.recommendations)) {
|
|
12812
|
+
throw new Error("LLM synthesis returned malformed JSON");
|
|
12813
|
+
}
|
|
12814
|
+
return {
|
|
12815
|
+
plan: parsed.plan,
|
|
12816
|
+
conflicts: parsed.conflicts,
|
|
12817
|
+
recommendations: parsed.recommendations
|
|
12818
|
+
};
|
|
12819
|
+
}
|
|
12820
|
+
/** Synthesize findings from multiple workers into a unified execution plan.
|
|
12821
|
+
*
|
|
12822
|
+
* Uses LLM-based synthesis by default (configurable via synthesisStrategy).
|
|
12823
|
+
* Falls back to the heuristic path when credentials are missing, the strategy
|
|
12824
|
+
* demands it, or the LLM call fails.
|
|
12825
|
+
*/
|
|
12826
|
+
async synthesizeFindings(results, opts2) {
|
|
12827
|
+
const strategy = opts2?.strategy ?? "llm";
|
|
12828
|
+
const disableLlm = opts2?.disableLlmSynthesis ?? false;
|
|
12829
|
+
const hasCreds = !!opts2?.accountId && !!opts2?.apiToken;
|
|
12830
|
+
const useHeuristic = !hasCreds || strategy === "heuristic" || disableLlm;
|
|
12831
|
+
if (useHeuristic) {
|
|
12832
|
+
return this.synthesizeFindingsHeuristic(results);
|
|
12833
|
+
}
|
|
12834
|
+
try {
|
|
12835
|
+
const llmResult = await this.synthesizeFindingsLlm(results, {
|
|
12836
|
+
prompt: opts2?.prompt,
|
|
12837
|
+
accountId: opts2.accountId,
|
|
12838
|
+
apiToken: opts2.apiToken,
|
|
12839
|
+
model: opts2?.model ?? "@cf/moonshotai/kimi-k2.5",
|
|
12840
|
+
gateway: opts2?.gateway,
|
|
12841
|
+
signal: opts2?.signal,
|
|
12842
|
+
onDelta: opts2?.onDelta
|
|
12843
|
+
});
|
|
12844
|
+
return llmResult;
|
|
12845
|
+
} catch (err) {
|
|
12846
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12847
|
+
logger.warn("supervisor:synthesis_llm_failed", { error: msg });
|
|
12848
|
+
if (strategy === "hybrid") {
|
|
12849
|
+
return this.synthesizeFindingsHeuristic(results);
|
|
12850
|
+
}
|
|
12851
|
+
throw err;
|
|
12852
|
+
}
|
|
12853
|
+
}
|
|
12713
12854
|
/** Automatically spawn research workers for a heavy prompt.
|
|
12714
12855
|
*
|
|
12715
12856
|
* Decomposes the prompt into 2-4 parallel research tasks using a simple
|
|
@@ -12735,7 +12876,22 @@ ${w.context ?? ""}` : w.context ?? "",
|
|
|
12735
12876
|
try {
|
|
12736
12877
|
const results = await this.spawnWorkers(workers, onUpdate, signal);
|
|
12737
12878
|
onPhaseChange?.("synthesizing");
|
|
12738
|
-
const
|
|
12879
|
+
const gateway = cfg?.aiGatewayId ? {
|
|
12880
|
+
id: cfg.aiGatewayId,
|
|
12881
|
+
cacheTtl: cfg.aiGatewayCacheTtl,
|
|
12882
|
+
skipCache: cfg.aiGatewaySkipCache,
|
|
12883
|
+
metadata: { feature: "synthesis", ...cfg.aiGatewayMetadata ?? {} }
|
|
12884
|
+
} : void 0;
|
|
12885
|
+
const synth = await this.synthesizeFindings(results, {
|
|
12886
|
+
prompt,
|
|
12887
|
+
accountId: cfg?.accountId,
|
|
12888
|
+
apiToken: cfg?.apiToken,
|
|
12889
|
+
model: cfg?.synthesisModel,
|
|
12890
|
+
gateway,
|
|
12891
|
+
signal,
|
|
12892
|
+
strategy: cfg?.synthesisStrategy,
|
|
12893
|
+
disableLlmSynthesis: cfg?.disableLlmSynthesis
|
|
12894
|
+
});
|
|
12739
12895
|
const cfg2 = await loadConfig().catch(() => null);
|
|
12740
12896
|
const autoExecute = cfg2?.autoExecute ?? /^(1|true|yes|on)$/i.test(process.env.KIMIFLARE_AUTO_EXECUTE ?? "");
|
|
12741
12897
|
if (!autoExecute || synth.recommendations.length === 0) {
|
|
@@ -13876,6 +14032,30 @@ Do not include speculation. Do not include chat-style pleasantries. Use short bu
|
|
|
13876
14032
|
}
|
|
13877
14033
|
});
|
|
13878
14034
|
|
|
14035
|
+
// src/agent/distill.ts
|
|
14036
|
+
function distillSessionPlan(messages) {
|
|
14037
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
14038
|
+
const m = messages[i];
|
|
14039
|
+
if (m?.role !== "assistant") continue;
|
|
14040
|
+
let text = "";
|
|
14041
|
+
if (typeof m.content === "string") {
|
|
14042
|
+
text = m.content;
|
|
14043
|
+
} else if (Array.isArray(m.content)) {
|
|
14044
|
+
text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
14045
|
+
}
|
|
14046
|
+
text = text.trim();
|
|
14047
|
+
if (text.length > 20) {
|
|
14048
|
+
return text;
|
|
14049
|
+
}
|
|
14050
|
+
}
|
|
14051
|
+
return null;
|
|
14052
|
+
}
|
|
14053
|
+
var init_distill = __esm({
|
|
14054
|
+
"src/agent/distill.ts"() {
|
|
14055
|
+
"use strict";
|
|
14056
|
+
}
|
|
14057
|
+
});
|
|
14058
|
+
|
|
13879
14059
|
// src/ui/greetings.ts
|
|
13880
14060
|
function pick(arr) {
|
|
13881
14061
|
if (arr.length === 0) throw new Error("pick() called with empty array");
|
|
@@ -14740,6 +14920,40 @@ var init_theme = __esm({
|
|
|
14740
14920
|
}
|
|
14741
14921
|
});
|
|
14742
14922
|
|
|
14923
|
+
// src/util/clipboard.ts
|
|
14924
|
+
import { execSync as execSync3 } from "child_process";
|
|
14925
|
+
import { platform as platform3 } from "os";
|
|
14926
|
+
function writeToClipboard(text) {
|
|
14927
|
+
const os2 = platform3();
|
|
14928
|
+
try {
|
|
14929
|
+
if (os2 === "darwin") {
|
|
14930
|
+
execSync3("pbcopy", { input: text, timeout: 5e3 });
|
|
14931
|
+
return { success: true, message: "Copied to clipboard" };
|
|
14932
|
+
}
|
|
14933
|
+
if (os2 === "win32") {
|
|
14934
|
+
execSync3("clip", { input: text, timeout: 5e3 });
|
|
14935
|
+
return { success: true, message: "Copied to clipboard" };
|
|
14936
|
+
}
|
|
14937
|
+
try {
|
|
14938
|
+
execSync3("xclip -selection clipboard", { input: text, timeout: 5e3 });
|
|
14939
|
+
return { success: true, message: "Copied to clipboard" };
|
|
14940
|
+
} catch {
|
|
14941
|
+
execSync3("xsel --clipboard --input", { input: text, timeout: 5e3 });
|
|
14942
|
+
return { success: true, message: "Copied to clipboard" };
|
|
14943
|
+
}
|
|
14944
|
+
} catch {
|
|
14945
|
+
return {
|
|
14946
|
+
success: false,
|
|
14947
|
+
message: "Clipboard not available \u2014 plan will be shown below"
|
|
14948
|
+
};
|
|
14949
|
+
}
|
|
14950
|
+
}
|
|
14951
|
+
var init_clipboard = __esm({
|
|
14952
|
+
"src/util/clipboard.ts"() {
|
|
14953
|
+
"use strict";
|
|
14954
|
+
}
|
|
14955
|
+
});
|
|
14956
|
+
|
|
14743
14957
|
// src/cloud/ai-gateway-api.ts
|
|
14744
14958
|
function baseUrl(accountId) {
|
|
14745
14959
|
return `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(accountId)}/ai-gateway/gateways`;
|
|
@@ -15967,11 +16181,11 @@ __export(ui_mode_exports, {
|
|
|
15967
16181
|
runCamouflageOnboarding: () => runCamouflageOnboarding,
|
|
15968
16182
|
runUiMode: () => runUiMode
|
|
15969
16183
|
});
|
|
15970
|
-
import { execSync as
|
|
16184
|
+
import { execSync as execSync4, spawn as spawn5 } from "child_process";
|
|
15971
16185
|
import { appendFileSync, openSync } from "fs";
|
|
15972
|
-
import { readdir as readdir7 } from "fs/promises";
|
|
16186
|
+
import { readdir as readdir7, unlink as unlink4 } from "fs/promises";
|
|
15973
16187
|
import { join as join28, relative as relative6 } from "path";
|
|
15974
|
-
import { platform as
|
|
16188
|
+
import { platform as platform4 } from "os";
|
|
15975
16189
|
function kimiLog(payload) {
|
|
15976
16190
|
if (!KIMI_LOG_PATH) return;
|
|
15977
16191
|
try {
|
|
@@ -16088,6 +16302,17 @@ ${err instanceof Error ? err.message : err}`);
|
|
|
16088
16302
|
}
|
|
16089
16303
|
} catch {
|
|
16090
16304
|
}
|
|
16305
|
+
try {
|
|
16306
|
+
const dep = await checkOptionalDependency("camouflage-tui", "beta");
|
|
16307
|
+
if (dep.hasUpdate && dep.latestVersion) {
|
|
16308
|
+
cam.send("ShowToast", {
|
|
16309
|
+
text: `camouflage-tui update available: ${dep.localVersion} \u2192 ${dep.latestVersion} \xB7 run npm update camouflage-tui`,
|
|
16310
|
+
kind: "info",
|
|
16311
|
+
ttl_ms: 6e3
|
|
16312
|
+
});
|
|
16313
|
+
}
|
|
16314
|
+
} catch {
|
|
16315
|
+
}
|
|
16091
16316
|
})();
|
|
16092
16317
|
cam.send("ShowToast", {
|
|
16093
16318
|
text: "EXPERIMENTAL \u2014 switch back any time with `kimiflare --ui ink`",
|
|
@@ -17504,20 +17729,41 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
17504
17729
|
return true;
|
|
17505
17730
|
}
|
|
17506
17731
|
case "update": {
|
|
17507
|
-
|
|
17508
|
-
|
|
17509
|
-
|
|
17510
|
-
|
|
17511
|
-
|
|
17512
|
-
|
|
17513
|
-
|
|
17514
|
-
|
|
17515
|
-
|
|
17516
|
-
|
|
17517
|
-
|
|
17732
|
+
const updateArg = (rest[0] ?? "").toLowerCase();
|
|
17733
|
+
if (updateArg === "camouflage") {
|
|
17734
|
+
cam.send("ShowToast", { text: "checking camouflage-tui for updates\u2026", kind: "info", ttl_ms: 1500 });
|
|
17735
|
+
try {
|
|
17736
|
+
const dep = await checkOptionalDependency("camouflage-tui", "beta");
|
|
17737
|
+
if (dep.hasUpdate && dep.latestVersion) {
|
|
17738
|
+
cam.send("ShowToast", {
|
|
17739
|
+
text: `camouflage-tui update available: ${dep.localVersion} \u2192 ${dep.latestVersion}. Run: npm update camouflage-tui`,
|
|
17740
|
+
kind: "success",
|
|
17741
|
+
ttl_ms: 5e3
|
|
17742
|
+
});
|
|
17743
|
+
} else if (dep.localVersion) {
|
|
17744
|
+
cam.send("ShowToast", { text: `camouflage-tui up to date (${dep.localVersion})`, kind: "info", ttl_ms: 2500 });
|
|
17745
|
+
} else {
|
|
17746
|
+
cam.send("ShowToast", { text: "camouflage-tui is not installed", kind: "info", ttl_ms: 2500 });
|
|
17747
|
+
}
|
|
17748
|
+
} catch (err) {
|
|
17749
|
+
cam.send("ShowToast", { text: `camouflage-tui update check failed: ${err instanceof Error ? err.message : String(err)}`, kind: "error", ttl_ms: 3e3 });
|
|
17750
|
+
}
|
|
17751
|
+
} else {
|
|
17752
|
+
cam.send("ShowToast", { text: "checking for updates\u2026", kind: "info", ttl_ms: 1500 });
|
|
17753
|
+
try {
|
|
17754
|
+
const r = await checkForUpdate(true);
|
|
17755
|
+
if (r.hasUpdate && r.latestVersion) {
|
|
17756
|
+
cam.send("ShowToast", {
|
|
17757
|
+
text: `update available: ${r.localVersion} \u2192 ${r.latestVersion}. Run: npm i -g kimiflare@latest`,
|
|
17758
|
+
kind: "success",
|
|
17759
|
+
ttl_ms: 5e3
|
|
17760
|
+
});
|
|
17761
|
+
} else {
|
|
17762
|
+
cam.send("ShowToast", { text: `up to date (${r.localVersion ?? "unknown"})`, kind: "info", ttl_ms: 2500 });
|
|
17763
|
+
}
|
|
17764
|
+
} catch (err) {
|
|
17765
|
+
cam.send("ShowToast", { text: `update check failed: ${err instanceof Error ? err.message : String(err)}`, kind: "error", ttl_ms: 3e3 });
|
|
17518
17766
|
}
|
|
17519
|
-
} catch (err) {
|
|
17520
|
-
cam.send("ShowToast", { text: `update check failed: ${err instanceof Error ? err.message : String(err)}`, kind: "error", ttl_ms: 3e3 });
|
|
17521
17767
|
}
|
|
17522
17768
|
return true;
|
|
17523
17769
|
}
|
|
@@ -17859,8 +18105,43 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
17859
18105
|
ttl_ms: 4e3
|
|
17860
18106
|
});
|
|
17861
18107
|
return true;
|
|
18108
|
+
case "fresh": {
|
|
18109
|
+
if (currentPhase !== "idle") {
|
|
18110
|
+
cam.send("ShowToast", { text: "can't /fresh while model is running \u2014 press Esc to interrupt first", kind: "warn", ttl_ms: 2500 });
|
|
18111
|
+
return true;
|
|
18112
|
+
}
|
|
18113
|
+
const plan = distillSessionPlan(messages);
|
|
18114
|
+
if (!plan) {
|
|
18115
|
+
cam.send("ShowToast", { text: "No plan found to start fresh with.", kind: "error", ttl_ms: 2500 });
|
|
18116
|
+
return true;
|
|
18117
|
+
}
|
|
18118
|
+
const clipResult = writeToClipboard(plan);
|
|
18119
|
+
const systemMessages = messages.filter((m) => m.role === "system");
|
|
18120
|
+
messages.length = 0;
|
|
18121
|
+
messages.push(...systemMessages);
|
|
18122
|
+
sessionCostUsd = 0;
|
|
18123
|
+
promptTokens = 0;
|
|
18124
|
+
cachedTokens = 0;
|
|
18125
|
+
completionTokens = 0;
|
|
18126
|
+
cam.send("TranscriptCleared", {});
|
|
18127
|
+
cam.send("StatusUpdate", {
|
|
18128
|
+
segments: { tokens: "in 0", cost: "$0.00", elapsed: "" }
|
|
18129
|
+
});
|
|
18130
|
+
messages.push({ role: "user", content: plan });
|
|
18131
|
+
cam.send("ShowToast", {
|
|
18132
|
+
text: clipResult.success ? "Plan copied to clipboard. Starting fresh session with plan only\u2026" : "Clipboard unavailable. Starting fresh session with plan only\u2026",
|
|
18133
|
+
kind: "info",
|
|
18134
|
+
ttl_ms: 3e3
|
|
18135
|
+
});
|
|
18136
|
+
if (!clipResult.success) {
|
|
18137
|
+
cam.send("UserMessageCreated", { text: "--- Plan ---\n" + plan });
|
|
18138
|
+
}
|
|
18139
|
+
return true;
|
|
18140
|
+
}
|
|
17862
18141
|
case "logout": {
|
|
17863
|
-
|
|
18142
|
+
unlink4(configPath()).catch(() => {
|
|
18143
|
+
});
|
|
18144
|
+
cam.send("ShowToast", { text: `credentials cleared from ${configPath()}`, kind: "success", ttl_ms: 2500 });
|
|
17864
18145
|
return true;
|
|
17865
18146
|
}
|
|
17866
18147
|
case "remote": {
|
|
@@ -17969,7 +18250,7 @@ function formatShortDate(iso) {
|
|
|
17969
18250
|
}
|
|
17970
18251
|
}
|
|
17971
18252
|
function openBrowser(url) {
|
|
17972
|
-
const cmd =
|
|
18253
|
+
const cmd = platform4() === "darwin" ? "open" : platform4() === "win32" ? "start" : "xdg-open";
|
|
17973
18254
|
const child = spawn5(cmd, [url], { detached: true, stdio: "ignore" });
|
|
17974
18255
|
child.unref();
|
|
17975
18256
|
}
|
|
@@ -17989,7 +18270,7 @@ function formatElapsed2(secs) {
|
|
|
17989
18270
|
}
|
|
17990
18271
|
function tryGitBranch2() {
|
|
17991
18272
|
try {
|
|
17992
|
-
const out =
|
|
18273
|
+
const out = execSync4("git rev-parse --abbrev-ref HEAD 2>/dev/null", {
|
|
17993
18274
|
encoding: "utf8",
|
|
17994
18275
|
timeout: 200
|
|
17995
18276
|
}).trim();
|
|
@@ -18099,9 +18380,11 @@ var init_ui_mode = __esm({
|
|
|
18099
18380
|
init_builtins();
|
|
18100
18381
|
init_sessions();
|
|
18101
18382
|
init_llm_summarize();
|
|
18383
|
+
init_distill();
|
|
18102
18384
|
init_greetings();
|
|
18103
18385
|
init_theme();
|
|
18104
18386
|
init_update_check();
|
|
18387
|
+
init_clipboard();
|
|
18105
18388
|
init_pricing();
|
|
18106
18389
|
init_config();
|
|
18107
18390
|
init_ai_gateway_api();
|
|
@@ -19524,12 +19807,19 @@ var init_chat = __esm({
|
|
|
19524
19807
|
for (const [sig, count] of toolCounts) {
|
|
19525
19808
|
if (count >= 3) repeatedSigs.add(sig);
|
|
19526
19809
|
}
|
|
19810
|
+
let lastAssistantIndex = -1;
|
|
19811
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
19812
|
+
if (events[i].kind === "assistant") {
|
|
19813
|
+
lastAssistantIndex = i;
|
|
19814
|
+
break;
|
|
19815
|
+
}
|
|
19816
|
+
}
|
|
19527
19817
|
return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: events.map((e, i) => {
|
|
19528
19818
|
const prev = events[i - 1];
|
|
19529
19819
|
const showSeparator = !!(prev && (e.kind === "user" && prev.kind !== "user" || e.kind === "assistant" && prev.kind !== "assistant" && prev.kind !== "tool"));
|
|
19530
19820
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
19531
19821
|
showSeparator && /* @__PURE__ */ jsx6(Box5, { marginY: 1, children: /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
|
|
19532
|
-
/* @__PURE__ */ jsx6(EventView, { evt: e, showReasoning, verbose, repeatedSigs, intentTier })
|
|
19822
|
+
/* @__PURE__ */ jsx6(EventView, { evt: e, showReasoning, verbose, repeatedSigs, intentTier, isLastAssistant: i === lastAssistantIndex })
|
|
19533
19823
|
] }, e.key);
|
|
19534
19824
|
}) });
|
|
19535
19825
|
});
|
|
@@ -19538,7 +19828,8 @@ var init_chat = __esm({
|
|
|
19538
19828
|
showReasoning,
|
|
19539
19829
|
verbose,
|
|
19540
19830
|
repeatedSigs,
|
|
19541
|
-
intentTier
|
|
19831
|
+
intentTier,
|
|
19832
|
+
isLastAssistant
|
|
19542
19833
|
}) {
|
|
19543
19834
|
const theme = useTheme();
|
|
19544
19835
|
if (evt.kind === "user") {
|
|
@@ -19583,7 +19874,7 @@ var init_chat = __esm({
|
|
|
19583
19874
|
evt.reasoning.length > 400 ? evt.reasoning.slice(0, 400) + "\u2026" : evt.reasoning
|
|
19584
19875
|
] }) }) : null,
|
|
19585
19876
|
evt.text ? /* @__PURE__ */ jsx6(MD, { text: evt.text }) : null,
|
|
19586
|
-
evt.streaming && /* @__PURE__ */ jsx6(Text5, { color: theme.spinner, children: /* @__PURE__ */ jsx6(Spinner2, { type: "dots" }) })
|
|
19877
|
+
evt.streaming && isLastAssistant && /* @__PURE__ */ jsx6(Text5, { color: theme.spinner, children: /* @__PURE__ */ jsx6(Spinner2, { type: "dots" }) })
|
|
19587
19878
|
] })
|
|
19588
19879
|
] }) });
|
|
19589
19880
|
}
|
|
@@ -20284,7 +20575,7 @@ var init_source = __esm({
|
|
|
20284
20575
|
|
|
20285
20576
|
// src/ui/text-input.tsx
|
|
20286
20577
|
import { useState as useState3, useEffect as useEffect3, useRef } from "react";
|
|
20287
|
-
import { Text as Text7, useInput } from "ink";
|
|
20578
|
+
import { Text as Text7, useInput, usePaste } from "ink";
|
|
20288
20579
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
20289
20580
|
function shouldTreatAsPaste(input) {
|
|
20290
20581
|
if (input.length >= PASTE_CHAR_THRESHOLD) return true;
|
|
@@ -20301,6 +20592,9 @@ function makePastePreview(input, lines, id) {
|
|
|
20301
20592
|
function countLines(s) {
|
|
20302
20593
|
return s.split("\n").length;
|
|
20303
20594
|
}
|
|
20595
|
+
function sanitizeInput(input) {
|
|
20596
|
+
return input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\t/g, " ");
|
|
20597
|
+
}
|
|
20304
20598
|
function findWordBoundaryForward(text, pos) {
|
|
20305
20599
|
while (pos < text.length && /\w/.test(text[pos])) pos++;
|
|
20306
20600
|
while (pos < text.length && !/\w/.test(text[pos])) pos++;
|
|
@@ -20338,13 +20632,51 @@ function CustomTextInput({
|
|
|
20338
20632
|
};
|
|
20339
20633
|
const pastesRef = useRef(/* @__PURE__ */ new Map());
|
|
20340
20634
|
const pasteCounterRef = useRef(0);
|
|
20635
|
+
const prevValueRef = useRef(value);
|
|
20636
|
+
const cursorOffsetRef = useRef(cursorOffset);
|
|
20637
|
+
cursorOffsetRef.current = cursorOffset;
|
|
20341
20638
|
useEffect3(() => {
|
|
20342
20639
|
if (!focus) return;
|
|
20343
|
-
const
|
|
20344
|
-
|
|
20640
|
+
const prevValue = prevValueRef.current;
|
|
20641
|
+
prevValueRef.current = value;
|
|
20642
|
+
if (value === prevValue) return;
|
|
20643
|
+
const currentCursor = cursorOffsetRef.current;
|
|
20644
|
+
if (currentCursor === prevValue.length) {
|
|
20645
|
+
if (currentCursor !== value.length) {
|
|
20646
|
+
setCursorOffset(value.length);
|
|
20647
|
+
}
|
|
20648
|
+
return;
|
|
20649
|
+
}
|
|
20650
|
+
const next = currentCursor > value.length ? value.length : currentCursor;
|
|
20651
|
+
if (next !== currentCursor) {
|
|
20345
20652
|
setCursorOffset(next);
|
|
20346
20653
|
}
|
|
20347
|
-
}, [value, focus
|
|
20654
|
+
}, [value, focus]);
|
|
20655
|
+
const handleInsert = (rawInput) => {
|
|
20656
|
+
let toInsert = sanitizeInput(rawInput);
|
|
20657
|
+
if (enablePaste && shouldTreatAsPaste(toInsert)) {
|
|
20658
|
+
const lines = countLines(toInsert);
|
|
20659
|
+
const id = ++pasteCounterRef.current;
|
|
20660
|
+
const placeholder = makePastePreview(toInsert, lines, id);
|
|
20661
|
+
pastesRef.current.set(placeholder, toInsert);
|
|
20662
|
+
toInsert = placeholder;
|
|
20663
|
+
}
|
|
20664
|
+
const nextValue = value.slice(0, cursorOffset) + toInsert + value.slice(cursorOffset);
|
|
20665
|
+
const nextCursor = cursorOffset + toInsert.length;
|
|
20666
|
+
if (nextCursor !== cursorOffset) {
|
|
20667
|
+
setCursorOffset(nextCursor);
|
|
20668
|
+
}
|
|
20669
|
+
if (nextValue !== value) {
|
|
20670
|
+
onChange(nextValue);
|
|
20671
|
+
}
|
|
20672
|
+
};
|
|
20673
|
+
usePaste(
|
|
20674
|
+
(input) => {
|
|
20675
|
+
if (!focus || !enablePaste) return;
|
|
20676
|
+
handleInsert(input);
|
|
20677
|
+
},
|
|
20678
|
+
{ isActive: focus && enablePaste }
|
|
20679
|
+
);
|
|
20348
20680
|
useInput(
|
|
20349
20681
|
(input, key) => {
|
|
20350
20682
|
if (!focus) return;
|
|
@@ -20469,12 +20801,13 @@ function CustomTextInput({
|
|
|
20469
20801
|
didDelete = true;
|
|
20470
20802
|
nextValue = value.slice(0, cursorOffset);
|
|
20471
20803
|
} else if (input.length > 0 && !key.ctrl && !key.meta) {
|
|
20472
|
-
|
|
20473
|
-
|
|
20474
|
-
|
|
20804
|
+
const sanitized = sanitizeInput(input);
|
|
20805
|
+
let toInsert = sanitized;
|
|
20806
|
+
if (enablePaste && shouldTreatAsPaste(toInsert)) {
|
|
20807
|
+
const lines = countLines(toInsert);
|
|
20475
20808
|
const id = ++pasteCounterRef.current;
|
|
20476
|
-
const placeholder = makePastePreview(
|
|
20477
|
-
pastesRef.current.set(placeholder,
|
|
20809
|
+
const placeholder = makePastePreview(toInsert, lines, id);
|
|
20810
|
+
pastesRef.current.set(placeholder, toInsert);
|
|
20478
20811
|
toInsert = placeholder;
|
|
20479
20812
|
}
|
|
20480
20813
|
nextValue = value.slice(0, cursorOffset) + toInsert + value.slice(cursorOffset);
|
|
@@ -20496,10 +20829,9 @@ function CustomTextInput({
|
|
|
20496
20829
|
);
|
|
20497
20830
|
const displayValue = mask ? mask.repeat(value.length) : value;
|
|
20498
20831
|
let renderedValue = "";
|
|
20499
|
-
let i = 0;
|
|
20500
|
-
|
|
20832
|
+
for (let i = 0; i < displayValue.length; i++) {
|
|
20833
|
+
const char = displayValue[i];
|
|
20501
20834
|
renderedValue += i === cursorOffset ? source_default.inverse(char) : char;
|
|
20502
|
-
i++;
|
|
20503
20835
|
}
|
|
20504
20836
|
if (displayValue.length === 0) {
|
|
20505
20837
|
renderedValue = source_default.inverse(" ");
|
|
@@ -20530,7 +20862,7 @@ var init_text_input = __esm({
|
|
|
20530
20862
|
// src/ui/permission.tsx
|
|
20531
20863
|
import { useState as useState4, useCallback } from "react";
|
|
20532
20864
|
import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
|
|
20533
|
-
import { platform as
|
|
20865
|
+
import { platform as platform5 } from "os";
|
|
20534
20866
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
20535
20867
|
function formatSelection(label, shortcut) {
|
|
20536
20868
|
return `${label} [${MOD_KEY}+${shortcut}]`;
|
|
@@ -20694,7 +21026,7 @@ var init_permission = __esm({
|
|
|
20694
21026
|
{ value: { decision: "deny", scope: "once" }, label: "Something else", key: 3 }
|
|
20695
21027
|
];
|
|
20696
21028
|
DENY = { decision: "deny", scope: "once" };
|
|
20697
|
-
MOD_KEY =
|
|
21029
|
+
MOD_KEY = platform5() === "darwin" ? "\u2325" : "Alt";
|
|
20698
21030
|
}
|
|
20699
21031
|
});
|
|
20700
21032
|
|
|
@@ -23620,8 +23952,9 @@ function useModalHost() {
|
|
|
23620
23952
|
const [showGatewayPicker, setShowGatewayPicker] = useState15(false);
|
|
23621
23953
|
const [showSkillsPicker, setShowSkillsPicker] = useState15(false);
|
|
23622
23954
|
const [showShellPicker, setShowShellPicker] = useState15(false);
|
|
23955
|
+
const [showPlanCompletePicker, setShowPlanCompletePicker] = useState15(false);
|
|
23623
23956
|
const flags = useMemo4(() => {
|
|
23624
|
-
const hasFullscreenModal = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || showThemePicker || showUiPicker || showModelPicker || showModePicker || keyEntryFor !== null || billingChooserFor !== null || unifiedProbeFor !== null || showRemoteDashboard || showInboxModal || showMultiAgentModal || showHooksDashboard || showHelpMenu || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker;
|
|
23957
|
+
const hasFullscreenModal = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || showThemePicker || showUiPicker || showModelPicker || showModePicker || keyEntryFor !== null || billingChooserFor !== null || unifiedProbeFor !== null || showRemoteDashboard || showInboxModal || showMultiAgentModal || showHooksDashboard || showHelpMenu || showMemoryPicker || showGatewayPicker || showSkillsPicker || showShellPicker || showPlanCompletePicker;
|
|
23625
23958
|
const hasOverlayModal = limitModal !== null || loopModal !== null;
|
|
23626
23959
|
return {
|
|
23627
23960
|
hasFullscreenModal,
|
|
@@ -23650,6 +23983,7 @@ function useModalHost() {
|
|
|
23650
23983
|
showGatewayPicker,
|
|
23651
23984
|
showSkillsPicker,
|
|
23652
23985
|
showShellPicker,
|
|
23986
|
+
showPlanCompletePicker,
|
|
23653
23987
|
limitModal,
|
|
23654
23988
|
loopModal
|
|
23655
23989
|
]);
|
|
@@ -23700,6 +24034,8 @@ function useModalHost() {
|
|
|
23700
24034
|
setShowSkillsPicker,
|
|
23701
24035
|
showShellPicker,
|
|
23702
24036
|
setShowShellPicker,
|
|
24037
|
+
showPlanCompletePicker,
|
|
24038
|
+
setShowPlanCompletePicker,
|
|
23703
24039
|
...flags
|
|
23704
24040
|
};
|
|
23705
24041
|
}
|
|
@@ -25582,10 +25918,10 @@ var init_inbox_modal = __esm({
|
|
|
25582
25918
|
});
|
|
25583
25919
|
|
|
25584
25920
|
// src/ui/app-helpers.ts
|
|
25585
|
-
import { execSync as
|
|
25921
|
+
import { execSync as execSync5, spawn as spawn7 } from "child_process";
|
|
25586
25922
|
import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync5 } from "fs";
|
|
25587
25923
|
import { join as join30 } from "path";
|
|
25588
|
-
import { platform as
|
|
25924
|
+
import { platform as platform6 } from "os";
|
|
25589
25925
|
function buildFilePickerIgnoreList(cwd) {
|
|
25590
25926
|
const hardcoded = [
|
|
25591
25927
|
// Dependencies
|
|
@@ -25704,7 +26040,7 @@ function gatewayUsageLookupFromConfig(cfg, meta) {
|
|
|
25704
26040
|
};
|
|
25705
26041
|
}
|
|
25706
26042
|
function openBrowser2(url) {
|
|
25707
|
-
const cmd =
|
|
26043
|
+
const cmd = platform6() === "darwin" ? "open" : platform6() === "win32" ? "start" : "xdg-open";
|
|
25708
26044
|
const child = spawn7(cmd, [url], { detached: true, stdio: "ignore" });
|
|
25709
26045
|
child.unref();
|
|
25710
26046
|
}
|
|
@@ -25714,7 +26050,7 @@ function detectGitHubRepo(cachedRepo) {
|
|
|
25714
26050
|
if (parts.length === 2) return { owner: parts[0], name: parts[1] };
|
|
25715
26051
|
}
|
|
25716
26052
|
try {
|
|
25717
|
-
const remoteUrl =
|
|
26053
|
+
const remoteUrl = execSync5("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim();
|
|
25718
26054
|
const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
|
|
25719
26055
|
if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
|
|
25720
26056
|
const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
|
|
@@ -25725,7 +26061,7 @@ function detectGitHubRepo(cachedRepo) {
|
|
|
25725
26061
|
}
|
|
25726
26062
|
function detectGitBranch() {
|
|
25727
26063
|
try {
|
|
25728
|
-
return
|
|
26064
|
+
return execSync5("git branch --show-current", { cwd: process.cwd(), encoding: "utf8" }).trim() || null;
|
|
25729
26065
|
} catch {
|
|
25730
26066
|
return null;
|
|
25731
26067
|
}
|
|
@@ -26165,7 +26501,7 @@ var init_multi_agent_modal = __esm({
|
|
|
26165
26501
|
});
|
|
26166
26502
|
|
|
26167
26503
|
// src/hooks/recommended.ts
|
|
26168
|
-
import { platform as
|
|
26504
|
+
import { platform as platform7 } from "os";
|
|
26169
26505
|
function getRecommendedHook(id) {
|
|
26170
26506
|
return RECOMMENDED_HOOKS.find((r) => r.id === id);
|
|
26171
26507
|
}
|
|
@@ -26173,7 +26509,7 @@ var isMac, RECOMMENDED_HOOKS;
|
|
|
26173
26509
|
var init_recommended = __esm({
|
|
26174
26510
|
"src/hooks/recommended.ts"() {
|
|
26175
26511
|
"use strict";
|
|
26176
|
-
isMac =
|
|
26512
|
+
isMac = platform7() === "darwin";
|
|
26177
26513
|
RECOMMENDED_HOOKS = [
|
|
26178
26514
|
// ── Stop notifications ───────────────────────────────────────────────
|
|
26179
26515
|
{
|
|
@@ -27068,6 +27404,7 @@ var init_help_menu = __esm({
|
|
|
27068
27404
|
{ command: "/cost", description: "show cost report" },
|
|
27069
27405
|
{ command: "/model", description: "show current model" },
|
|
27070
27406
|
{ command: "/update", description: "check for updates" },
|
|
27407
|
+
{ command: "/update camouflage", description: "check for camouflage-tui updates" },
|
|
27071
27408
|
{ command: "/hello", description: "send a voice note to the creator" }
|
|
27072
27409
|
]
|
|
27073
27410
|
},
|
|
@@ -27428,6 +27765,38 @@ var init_modal_host = __esm({
|
|
|
27428
27765
|
}
|
|
27429
27766
|
});
|
|
27430
27767
|
|
|
27768
|
+
// src/ui/plan-complete-picker.tsx
|
|
27769
|
+
import { Box as Box39, Text as Text40 } from "ink";
|
|
27770
|
+
import SelectInput22 from "ink-select-input";
|
|
27771
|
+
import { jsx as jsx41, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
27772
|
+
function PlanCompletePicker({ onPick }) {
|
|
27773
|
+
const theme = useTheme();
|
|
27774
|
+
const items = [
|
|
27775
|
+
{ label: "\u25B8 Execute this plan and accept changes (auto mode)", value: "auto", key: "auto" },
|
|
27776
|
+
{ label: "\u25B8 Start building and ask for permission (edit mode)", value: "edit", key: "edit" },
|
|
27777
|
+
{ label: "\u25B8 Continue planning / ask a question", value: "continue", key: "continue" }
|
|
27778
|
+
];
|
|
27779
|
+
return /* @__PURE__ */ jsxs39(Box39, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
27780
|
+
/* @__PURE__ */ jsx41(Text40, { color: theme.accent, bold: true, children: "Plan complete \u2014 what next?" }),
|
|
27781
|
+
/* @__PURE__ */ jsx41(Text40, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
|
|
27782
|
+
/* @__PURE__ */ jsx41(Box39, { marginTop: 1, children: /* @__PURE__ */ jsx41(
|
|
27783
|
+
SelectInput22,
|
|
27784
|
+
{
|
|
27785
|
+
items,
|
|
27786
|
+
onSelect: (item) => onPick(item.value),
|
|
27787
|
+
onHighlight: () => {
|
|
27788
|
+
}
|
|
27789
|
+
}
|
|
27790
|
+
) })
|
|
27791
|
+
] });
|
|
27792
|
+
}
|
|
27793
|
+
var init_plan_complete_picker = __esm({
|
|
27794
|
+
"src/ui/plan-complete-picker.tsx"() {
|
|
27795
|
+
"use strict";
|
|
27796
|
+
init_theme_context();
|
|
27797
|
+
}
|
|
27798
|
+
});
|
|
27799
|
+
|
|
27431
27800
|
// src/ui/use-session-manager.ts
|
|
27432
27801
|
import { useCallback as useCallback8, useRef as useRef5, useState as useState25 } from "react";
|
|
27433
27802
|
function extractFirstUserText(messages) {
|
|
@@ -27764,64 +28133,6 @@ var init_input_handlers = __esm({
|
|
|
27764
28133
|
}
|
|
27765
28134
|
});
|
|
27766
28135
|
|
|
27767
|
-
// src/agent/distill.ts
|
|
27768
|
-
function distillSessionPlan(messages) {
|
|
27769
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
27770
|
-
const m = messages[i];
|
|
27771
|
-
if (m?.role !== "assistant") continue;
|
|
27772
|
-
let text = "";
|
|
27773
|
-
if (typeof m.content === "string") {
|
|
27774
|
-
text = m.content;
|
|
27775
|
-
} else if (Array.isArray(m.content)) {
|
|
27776
|
-
text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
27777
|
-
}
|
|
27778
|
-
text = text.trim();
|
|
27779
|
-
if (text.length > 20) {
|
|
27780
|
-
return text;
|
|
27781
|
-
}
|
|
27782
|
-
}
|
|
27783
|
-
return null;
|
|
27784
|
-
}
|
|
27785
|
-
var init_distill = __esm({
|
|
27786
|
-
"src/agent/distill.ts"() {
|
|
27787
|
-
"use strict";
|
|
27788
|
-
}
|
|
27789
|
-
});
|
|
27790
|
-
|
|
27791
|
-
// src/util/clipboard.ts
|
|
27792
|
-
import { execSync as execSync5 } from "child_process";
|
|
27793
|
-
import { platform as platform7 } from "os";
|
|
27794
|
-
function writeToClipboard(text) {
|
|
27795
|
-
const os2 = platform7();
|
|
27796
|
-
try {
|
|
27797
|
-
if (os2 === "darwin") {
|
|
27798
|
-
execSync5("pbcopy", { input: text, timeout: 5e3 });
|
|
27799
|
-
return { success: true, message: "Copied to clipboard" };
|
|
27800
|
-
}
|
|
27801
|
-
if (os2 === "win32") {
|
|
27802
|
-
execSync5("clip", { input: text, timeout: 5e3 });
|
|
27803
|
-
return { success: true, message: "Copied to clipboard" };
|
|
27804
|
-
}
|
|
27805
|
-
try {
|
|
27806
|
-
execSync5("xclip -selection clipboard", { input: text, timeout: 5e3 });
|
|
27807
|
-
return { success: true, message: "Copied to clipboard" };
|
|
27808
|
-
} catch {
|
|
27809
|
-
execSync5("xsel --clipboard --input", { input: text, timeout: 5e3 });
|
|
27810
|
-
return { success: true, message: "Copied to clipboard" };
|
|
27811
|
-
}
|
|
27812
|
-
} catch {
|
|
27813
|
-
return {
|
|
27814
|
-
success: false,
|
|
27815
|
-
message: "Clipboard not available \u2014 plan will be shown below"
|
|
27816
|
-
};
|
|
27817
|
-
}
|
|
27818
|
-
}
|
|
27819
|
-
var init_clipboard = __esm({
|
|
27820
|
-
"src/util/clipboard.ts"() {
|
|
27821
|
-
"use strict";
|
|
27822
|
-
}
|
|
27823
|
-
});
|
|
27824
|
-
|
|
27825
28136
|
// src/cost-attribution/tui-report.ts
|
|
27826
28137
|
var tui_report_exports = {};
|
|
27827
28138
|
__export(tui_report_exports, {
|
|
@@ -27905,7 +28216,7 @@ var init_tui_report = __esm({
|
|
|
27905
28216
|
|
|
27906
28217
|
// src/ui/slash-commands.ts
|
|
27907
28218
|
import { join as join32 } from "path";
|
|
27908
|
-
import { unlink as
|
|
28219
|
+
import { unlink as unlink5 } from "fs/promises";
|
|
27909
28220
|
import QRCode from "qrcode";
|
|
27910
28221
|
function dispatchSlashCommand(ctx, cmd) {
|
|
27911
28222
|
const raw = cmd.trim();
|
|
@@ -28771,8 +29082,27 @@ ${lines.join("\n")}` }]);
|
|
|
28771
29082
|
void ctx.runInit();
|
|
28772
29083
|
return true;
|
|
28773
29084
|
};
|
|
28774
|
-
handleUpdate = (ctx) => {
|
|
29085
|
+
handleUpdate = (ctx, _rest, arg) => {
|
|
28775
29086
|
const { setEvents, mkKey: mkKey2 } = ctx;
|
|
29087
|
+
if (arg === "camouflage") {
|
|
29088
|
+
void checkOptionalDependency("camouflage-tui", "beta").then((dep) => {
|
|
29089
|
+
if (dep.hasUpdate && dep.latestVersion) {
|
|
29090
|
+
setEvents((e) => [
|
|
29091
|
+
...e,
|
|
29092
|
+
{ kind: "info", key: mkKey2(), text: `camouflage-tui update available: ${dep.localVersion} \u2192 ${dep.latestVersion}` }
|
|
29093
|
+
]);
|
|
29094
|
+
setEvents((e) => [
|
|
29095
|
+
...e,
|
|
29096
|
+
{ kind: "info", key: mkKey2(), text: "run: npm update camouflage-tui" }
|
|
29097
|
+
]);
|
|
29098
|
+
} else if (dep.localVersion) {
|
|
29099
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `camouflage-tui up to date (${dep.localVersion})` }]);
|
|
29100
|
+
} else {
|
|
29101
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "camouflage-tui is not installed" }]);
|
|
29102
|
+
}
|
|
29103
|
+
});
|
|
29104
|
+
return true;
|
|
29105
|
+
}
|
|
28776
29106
|
void checkForUpdate(true).then((result) => {
|
|
28777
29107
|
if (result.hasUpdate) {
|
|
28778
29108
|
ctx.setHasUpdate(true);
|
|
@@ -29027,7 +29357,7 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
29027
29357
|
return true;
|
|
29028
29358
|
};
|
|
29029
29359
|
handleLogout = (ctx) => {
|
|
29030
|
-
|
|
29360
|
+
unlink5(configPath()).catch(() => {
|
|
29031
29361
|
});
|
|
29032
29362
|
ctx.setEvents((e) => [
|
|
29033
29363
|
...e,
|
|
@@ -30397,10 +30727,10 @@ __export(app_exports, {
|
|
|
30397
30727
|
renderApp: () => renderApp
|
|
30398
30728
|
});
|
|
30399
30729
|
import React23, { useState as useState27, useRef as useRef7, useEffect as useEffect11, useCallback as useCallback10, useMemo as useMemo6 } from "react";
|
|
30400
|
-
import { Box as
|
|
30730
|
+
import { Box as Box40, Text as Text41, useApp, useInput as useInput19, render } from "ink";
|
|
30401
30731
|
import { existsSync as existsSync8 } from "fs";
|
|
30402
30732
|
import { join as join37 } from "path";
|
|
30403
|
-
import { jsx as
|
|
30733
|
+
import { jsx as jsx42, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
30404
30734
|
function App({
|
|
30405
30735
|
initialCfg,
|
|
30406
30736
|
initialUpdateResult,
|
|
@@ -30530,6 +30860,8 @@ function App({
|
|
|
30530
30860
|
setShowSkillsPicker,
|
|
30531
30861
|
showShellPicker,
|
|
30532
30862
|
setShowShellPicker,
|
|
30863
|
+
showPlanCompletePicker,
|
|
30864
|
+
setShowPlanCompletePicker,
|
|
30533
30865
|
hasFullscreenModal,
|
|
30534
30866
|
hasAnyModal
|
|
30535
30867
|
} = modals;
|
|
@@ -30823,6 +31155,26 @@ ${wcagWarnings.join("\n")}` }
|
|
|
30823
31155
|
]);
|
|
30824
31156
|
}
|
|
30825
31157
|
});
|
|
31158
|
+
void checkOptionalDependency("camouflage-tui", "beta").then((dep) => {
|
|
31159
|
+
if (dep.hasUpdate && dep.latestVersion) {
|
|
31160
|
+
setEvents((e) => [
|
|
31161
|
+
...e,
|
|
31162
|
+
{
|
|
31163
|
+
kind: "info",
|
|
31164
|
+
key: mkKey(),
|
|
31165
|
+
text: `camouflage-tui update available: ${dep.localVersion} \u2192 ${dep.latestVersion}`
|
|
31166
|
+
}
|
|
31167
|
+
]);
|
|
31168
|
+
setEvents((e) => [
|
|
31169
|
+
...e,
|
|
31170
|
+
{
|
|
31171
|
+
kind: "info",
|
|
31172
|
+
key: mkKey(),
|
|
31173
|
+
text: "run: npm update camouflage-tui"
|
|
31174
|
+
}
|
|
31175
|
+
]);
|
|
31176
|
+
}
|
|
31177
|
+
});
|
|
30826
31178
|
}, [cfg, initialUpdateResult]);
|
|
30827
31179
|
useEffect11(() => {
|
|
30828
31180
|
modeRef.current = mode;
|
|
@@ -30882,6 +31234,26 @@ ${wcagWarnings.join("\n")}` }
|
|
|
30882
31234
|
}
|
|
30883
31235
|
}
|
|
30884
31236
|
});
|
|
31237
|
+
void checkOptionalDependency("camouflage-tui", "beta").then((dep) => {
|
|
31238
|
+
if (dep.hasUpdate && dep.latestVersion) {
|
|
31239
|
+
setEvents((e) => [
|
|
31240
|
+
...e,
|
|
31241
|
+
{
|
|
31242
|
+
kind: "info",
|
|
31243
|
+
key: mkKey(),
|
|
31244
|
+
text: `camouflage-tui update available: ${dep.localVersion} \u2192 ${dep.latestVersion}`
|
|
31245
|
+
}
|
|
31246
|
+
]);
|
|
31247
|
+
setEvents((e) => [
|
|
31248
|
+
...e,
|
|
31249
|
+
{
|
|
31250
|
+
kind: "info",
|
|
31251
|
+
key: mkKey(),
|
|
31252
|
+
text: "run: npm update camouflage-tui"
|
|
31253
|
+
}
|
|
31254
|
+
]);
|
|
31255
|
+
}
|
|
31256
|
+
});
|
|
30885
31257
|
}, 30 * 60 * 1e3);
|
|
30886
31258
|
return () => clearInterval(id);
|
|
30887
31259
|
}, [cfg]);
|
|
@@ -31287,6 +31659,61 @@ ${wcagWarnings.join("\n")}` }
|
|
|
31287
31659
|
},
|
|
31288
31660
|
[mkKey, setShowUiPicker]
|
|
31289
31661
|
);
|
|
31662
|
+
const handlePlanCompletePick = useCallback10(
|
|
31663
|
+
(picked) => {
|
|
31664
|
+
setShowPlanCompletePicker(false);
|
|
31665
|
+
if (!picked || picked === "continue") return;
|
|
31666
|
+
const plan = distillSessionPlan(messagesRef.current);
|
|
31667
|
+
if (!plan) {
|
|
31668
|
+
setEvents((e) => [
|
|
31669
|
+
...e,
|
|
31670
|
+
{ kind: "error", key: mkKey(), text: "No plan found to start fresh with." }
|
|
31671
|
+
]);
|
|
31672
|
+
setMode(picked);
|
|
31673
|
+
return;
|
|
31674
|
+
}
|
|
31675
|
+
const clipResult = writeToClipboard(plan);
|
|
31676
|
+
if (cacheStableRef.current && messagesRef.current.length >= 2) {
|
|
31677
|
+
messagesRef.current = [messagesRef.current[0], messagesRef.current[1]];
|
|
31678
|
+
} else {
|
|
31679
|
+
messagesRef.current = [messagesRef.current[0]];
|
|
31680
|
+
}
|
|
31681
|
+
resetSession();
|
|
31682
|
+
executorRef.current.clearArtifacts();
|
|
31683
|
+
if (flushTimeoutRef.current) {
|
|
31684
|
+
clearTimeout(flushTimeoutRef.current);
|
|
31685
|
+
flushTimeoutRef.current = null;
|
|
31686
|
+
}
|
|
31687
|
+
pendingTextRef.current.clear();
|
|
31688
|
+
activeAsstIdRef.current = null;
|
|
31689
|
+
pendingToolCallsRef.current.clear();
|
|
31690
|
+
usageRef.current = null;
|
|
31691
|
+
turnCounterRef.current = 0;
|
|
31692
|
+
setEvents([]);
|
|
31693
|
+
setUsage(null);
|
|
31694
|
+
setSessionUsage(null);
|
|
31695
|
+
gatewayMetaRef.current = null;
|
|
31696
|
+
setGatewayMeta(null);
|
|
31697
|
+
clearTaskTracking();
|
|
31698
|
+
compactSuggestedRef.current = false;
|
|
31699
|
+
updateNudgedRef.current = false;
|
|
31700
|
+
setEvents((e) => [
|
|
31701
|
+
...e,
|
|
31702
|
+
{
|
|
31703
|
+
kind: "info",
|
|
31704
|
+
key: mkKey(),
|
|
31705
|
+
text: clipResult.success ? `Plan copied to clipboard. Starting fresh session in ${picked} mode with plan only\u2026` : `Clipboard unavailable. Starting fresh session in ${picked} mode with plan only\u2026`
|
|
31706
|
+
}
|
|
31707
|
+
]);
|
|
31708
|
+
if (!clipResult.success) {
|
|
31709
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "--- Plan ---\n" + plan }]);
|
|
31710
|
+
}
|
|
31711
|
+
setMode(picked);
|
|
31712
|
+
modeRef.current = picked;
|
|
31713
|
+
submitRef.current(plan);
|
|
31714
|
+
},
|
|
31715
|
+
[mkKey, setShowPlanCompletePicker, setMode, setEvents, setUsage, setSessionUsage, setGatewayMeta, clearTaskTracking, resetSession, submitRef]
|
|
31716
|
+
);
|
|
31290
31717
|
const handleModelPick = useCallback10(
|
|
31291
31718
|
(picked) => {
|
|
31292
31719
|
setShowModelPicker(false);
|
|
@@ -32149,6 +32576,12 @@ ${conflicts.join("\n")}` }
|
|
|
32149
32576
|
}
|
|
32150
32577
|
})();
|
|
32151
32578
|
cleanupTurn();
|
|
32579
|
+
if (modeRef.current === "plan") {
|
|
32580
|
+
const plan = distillSessionPlan(messagesRef.current);
|
|
32581
|
+
if (plan) {
|
|
32582
|
+
setShowPlanCompletePicker(true);
|
|
32583
|
+
}
|
|
32584
|
+
}
|
|
32152
32585
|
},
|
|
32153
32586
|
onError: async (e) => {
|
|
32154
32587
|
if (e.name === "AbortError") {
|
|
@@ -32182,7 +32615,7 @@ ${conflicts.join("\n")}` }
|
|
|
32182
32615
|
}
|
|
32183
32616
|
);
|
|
32184
32617
|
},
|
|
32185
|
-
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
|
|
32618
|
+
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta, setShowPlanCompletePicker]
|
|
32186
32619
|
);
|
|
32187
32620
|
useEffect11(() => {
|
|
32188
32621
|
if (!busy && queue2.length > 0 && supervisorRef.current.phase === "idle") {
|
|
@@ -32243,7 +32676,7 @@ ${conflicts.join("\n")}` }
|
|
|
32243
32676
|
});
|
|
32244
32677
|
}, [usage, modelContextLimit, busy, runCompact2]);
|
|
32245
32678
|
if (!cfg) {
|
|
32246
|
-
return /* @__PURE__ */
|
|
32679
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(
|
|
32247
32680
|
Onboarding,
|
|
32248
32681
|
{
|
|
32249
32682
|
onCancel: () => exit(),
|
|
@@ -32258,7 +32691,7 @@ ${conflicts.join("\n")}` }
|
|
|
32258
32691
|
) });
|
|
32259
32692
|
}
|
|
32260
32693
|
if (checkpointSession !== null) {
|
|
32261
|
-
return /* @__PURE__ */
|
|
32694
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(
|
|
32262
32695
|
CheckpointPicker,
|
|
32263
32696
|
{
|
|
32264
32697
|
session: checkpointSession,
|
|
@@ -32268,10 +32701,10 @@ ${conflicts.join("\n")}` }
|
|
|
32268
32701
|
) }) });
|
|
32269
32702
|
}
|
|
32270
32703
|
if (resumeSessions !== null) {
|
|
32271
|
-
return /* @__PURE__ */
|
|
32704
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", children: /* @__PURE__ */ jsx42(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
|
|
32272
32705
|
}
|
|
32273
32706
|
if (hasFullscreenModal) {
|
|
32274
|
-
return /* @__PURE__ */
|
|
32707
|
+
return /* @__PURE__ */ jsx42(
|
|
32275
32708
|
ModalHost,
|
|
32276
32709
|
{
|
|
32277
32710
|
modals,
|
|
@@ -32415,9 +32848,9 @@ ${conflicts.join("\n")}` }
|
|
|
32415
32848
|
);
|
|
32416
32849
|
}
|
|
32417
32850
|
const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
|
|
32418
|
-
return /* @__PURE__ */
|
|
32419
|
-
!hasConversation && events.length === 0 ? /* @__PURE__ */
|
|
32420
|
-
perm ? /* @__PURE__ */
|
|
32851
|
+
return /* @__PURE__ */ jsx42(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs40(Box40, { flexDirection: "column", children: [
|
|
32852
|
+
!hasConversation && events.length === 0 ? /* @__PURE__ */ jsx42(Welcome, {}) : /* @__PURE__ */ jsx42(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
|
|
32853
|
+
perm ? /* @__PURE__ */ jsx42(
|
|
32421
32854
|
PermissionModal,
|
|
32422
32855
|
{
|
|
32423
32856
|
tool: perm.tool,
|
|
@@ -32427,7 +32860,7 @@ ${conflicts.join("\n")}` }
|
|
|
32427
32860
|
submitRef.current(text);
|
|
32428
32861
|
}
|
|
32429
32862
|
}
|
|
32430
|
-
) : limitModal || loopModal ? /* @__PURE__ */
|
|
32863
|
+
) : limitModal || loopModal ? /* @__PURE__ */ jsx42(
|
|
32431
32864
|
ModalOverlay,
|
|
32432
32865
|
{
|
|
32433
32866
|
modals,
|
|
@@ -32438,9 +32871,9 @@ ${conflicts.join("\n")}` }
|
|
|
32438
32871
|
loopResolveRef.current = null;
|
|
32439
32872
|
}
|
|
32440
32873
|
}
|
|
32441
|
-
) : /* @__PURE__ */
|
|
32442
|
-
(activeWorkers.length > 0 || coordinatorNarration) && /* @__PURE__ */
|
|
32443
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
32874
|
+
) : showPlanCompletePicker ? /* @__PURE__ */ jsx42(PlanCompletePicker, { onPick: handlePlanCompletePick }) : /* @__PURE__ */ jsxs40(Box40, { flexDirection: "column", marginTop: 1, children: [
|
|
32875
|
+
(activeWorkers.length > 0 || coordinatorNarration) && /* @__PURE__ */ jsx42(WorkerList, { workers: activeWorkers, isSynthesizing, narration: coordinatorNarration }),
|
|
32876
|
+
tasks.length > 0 && /* @__PURE__ */ jsx42(
|
|
32444
32877
|
TaskList,
|
|
32445
32878
|
{
|
|
32446
32879
|
tasks,
|
|
@@ -32448,11 +32881,11 @@ ${conflicts.join("\n")}` }
|
|
|
32448
32881
|
tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
|
|
32449
32882
|
}
|
|
32450
32883
|
),
|
|
32451
|
-
queue2.length > 0 && /* @__PURE__ */
|
|
32884
|
+
queue2.length > 0 && /* @__PURE__ */ jsx42(Box40, { flexDirection: "column", marginBottom: 1, children: queue2.map((q, i) => /* @__PURE__ */ jsxs40(Text41, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
32452
32885
|
"\u23F3 ",
|
|
32453
32886
|
q.display
|
|
32454
32887
|
] }, `queue_${i}`)) }),
|
|
32455
|
-
/* @__PURE__ */
|
|
32888
|
+
/* @__PURE__ */ jsx42(
|
|
32456
32889
|
StatusBar,
|
|
32457
32890
|
{
|
|
32458
32891
|
usage,
|
|
@@ -32474,7 +32907,7 @@ ${conflicts.join("\n")}` }
|
|
|
32474
32907
|
intentTier: intentTier ?? void 0
|
|
32475
32908
|
}
|
|
32476
32909
|
),
|
|
32477
|
-
picker.active?.kind === "file" && /* @__PURE__ */
|
|
32910
|
+
picker.active?.kind === "file" && /* @__PURE__ */ jsx42(
|
|
32478
32911
|
FilePicker,
|
|
32479
32912
|
{
|
|
32480
32913
|
items: picker.fileItems,
|
|
@@ -32483,7 +32916,7 @@ ${conflicts.join("\n")}` }
|
|
|
32483
32916
|
recentFiles: new Set(recentFilesRef.current.keys())
|
|
32484
32917
|
}
|
|
32485
32918
|
),
|
|
32486
|
-
picker.active?.kind === "slash" && /* @__PURE__ */
|
|
32919
|
+
picker.active?.kind === "slash" && /* @__PURE__ */ jsx42(
|
|
32487
32920
|
SlashPicker,
|
|
32488
32921
|
{
|
|
32489
32922
|
items: picker.slashItems,
|
|
@@ -32491,9 +32924,9 @@ ${conflicts.join("\n")}` }
|
|
|
32491
32924
|
query: picker.query
|
|
32492
32925
|
}
|
|
32493
32926
|
),
|
|
32494
|
-
/* @__PURE__ */
|
|
32495
|
-
/* @__PURE__ */
|
|
32496
|
-
/* @__PURE__ */
|
|
32927
|
+
/* @__PURE__ */ jsxs40(Box40, { marginTop: 1, children: [
|
|
32928
|
+
/* @__PURE__ */ jsx42(Text41, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
|
|
32929
|
+
/* @__PURE__ */ jsx42(
|
|
32497
32930
|
CustomTextInput,
|
|
32498
32931
|
{
|
|
32499
32932
|
value: input,
|
|
@@ -32550,7 +32983,7 @@ ${conflicts.join("\n")}` }
|
|
|
32550
32983
|
}
|
|
32551
32984
|
async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
|
|
32552
32985
|
const instance = render(
|
|
32553
|
-
/* @__PURE__ */
|
|
32986
|
+
/* @__PURE__ */ jsx42(
|
|
32554
32987
|
App,
|
|
32555
32988
|
{
|
|
32556
32989
|
initialCfg: cfg,
|
|
@@ -32623,6 +33056,7 @@ var init_app = __esm({
|
|
|
32623
33056
|
init_use_picker_controller();
|
|
32624
33057
|
init_use_modal_host();
|
|
32625
33058
|
init_modal_host();
|
|
33059
|
+
init_plan_complete_picker();
|
|
32626
33060
|
init_use_session_manager();
|
|
32627
33061
|
init_use_turn_controller();
|
|
32628
33062
|
init_input_handlers();
|
|
@@ -32631,6 +33065,8 @@ var init_app = __esm({
|
|
|
32631
33065
|
init_run_startup_tasks();
|
|
32632
33066
|
init_manager_init();
|
|
32633
33067
|
init_run_compact();
|
|
33068
|
+
init_distill();
|
|
33069
|
+
init_clipboard();
|
|
32634
33070
|
init_command_handlers();
|
|
32635
33071
|
init_app_helpers();
|
|
32636
33072
|
}
|