cc-claw 0.18.2 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +492 -88
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var VERSION;
|
|
|
33
33
|
var init_version = __esm({
|
|
34
34
|
"src/version.ts"() {
|
|
35
35
|
"use strict";
|
|
36
|
-
VERSION = true ? "0.18.
|
|
36
|
+
VERSION = true ? "0.18.4" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -9717,6 +9717,14 @@ function parseAnalysisOutput(raw) {
|
|
|
9717
9717
|
if (!VALID_CATEGORIES.includes(category)) continue;
|
|
9718
9718
|
const confidence = confidenceMatch ? parseFloat(confidenceMatch[1].trim()) : 0.5;
|
|
9719
9719
|
if (isNaN(confidence)) continue;
|
|
9720
|
+
let proposedDiff = diffMatch?.[1]?.trim() ?? "";
|
|
9721
|
+
if (proposedDiff.startsWith("```")) {
|
|
9722
|
+
proposedDiff = proposedDiff.replace(/^```[a-zA-Z0-9-]*\r?\n/, "");
|
|
9723
|
+
if (proposedDiff.endsWith("```")) {
|
|
9724
|
+
proposedDiff = proposedDiff.replace(/\r?\n```$/, "");
|
|
9725
|
+
}
|
|
9726
|
+
proposedDiff = proposedDiff.trim();
|
|
9727
|
+
}
|
|
9720
9728
|
results.push({
|
|
9721
9729
|
insight: insightMatch[1].trim(),
|
|
9722
9730
|
category,
|
|
@@ -9724,7 +9732,7 @@ function parseAnalysisOutput(raw) {
|
|
|
9724
9732
|
targetFile: targetMatch?.[1]?.trim() ?? "",
|
|
9725
9733
|
confidence: Math.max(0, Math.min(1, confidence)),
|
|
9726
9734
|
proposedAction: actionMatch?.[1]?.trim() ?? "",
|
|
9727
|
-
proposedDiff
|
|
9735
|
+
proposedDiff,
|
|
9728
9736
|
conflictsWith: conflictsMatch?.[1]?.trim() ?? "none"
|
|
9729
9737
|
});
|
|
9730
9738
|
}
|
|
@@ -10128,6 +10136,181 @@ var init_analyze = __esm({
|
|
|
10128
10136
|
}
|
|
10129
10137
|
});
|
|
10130
10138
|
|
|
10139
|
+
// src/reflection/ai-apply.ts
|
|
10140
|
+
var ai_apply_exports = {};
|
|
10141
|
+
__export(ai_apply_exports, {
|
|
10142
|
+
applyWithAI: () => applyWithAI
|
|
10143
|
+
});
|
|
10144
|
+
import { spawn as spawn5 } from "child_process";
|
|
10145
|
+
import { createInterface as createInterface4 } from "readline";
|
|
10146
|
+
function buildApplyPrompt(originalContent, instruction, proposedDiff, targetFile) {
|
|
10147
|
+
return `You are a precise markdown document editor. Your ONLY job is to apply the requested change to the document while preserving its structural integrity.
|
|
10148
|
+
|
|
10149
|
+
=== CURRENT FILE: ${targetFile} ===
|
|
10150
|
+
${originalContent}
|
|
10151
|
+
=== END FILE ===
|
|
10152
|
+
|
|
10153
|
+
=== CHANGE TO APPLY ===
|
|
10154
|
+
Instruction: ${instruction}
|
|
10155
|
+
|
|
10156
|
+
Diff guidance:
|
|
10157
|
+
${proposedDiff}
|
|
10158
|
+
=== END CHANGE ===
|
|
10159
|
+
|
|
10160
|
+
Rules:
|
|
10161
|
+
1. Place new content under the semantically correct section heading (## heading)
|
|
10162
|
+
2. Maintain consistent formatting (bullet style, indentation) with the target section
|
|
10163
|
+
3. Do NOT add, remove, or modify any content other than what the change requires
|
|
10164
|
+
4. Do NOT wrap your output in markdown code fences
|
|
10165
|
+
5. Do NOT add explanations, commentary, or notes
|
|
10166
|
+
6. Preserve all existing headings and their order
|
|
10167
|
+
7. Return ONLY the complete updated file content
|
|
10168
|
+
|
|
10169
|
+
Output the complete updated file now:`;
|
|
10170
|
+
}
|
|
10171
|
+
async function spawnApplyLLM(adapter, model2, prompt) {
|
|
10172
|
+
const config2 = adapter.buildSpawnConfig({
|
|
10173
|
+
prompt,
|
|
10174
|
+
model: model2,
|
|
10175
|
+
permMode: "yolo",
|
|
10176
|
+
allowedTools: []
|
|
10177
|
+
});
|
|
10178
|
+
const env = adapter.getEnv();
|
|
10179
|
+
let resultText = "";
|
|
10180
|
+
let accumulatedText = "";
|
|
10181
|
+
await new Promise((resolve) => {
|
|
10182
|
+
const proc = spawn5(config2.executable, config2.args, {
|
|
10183
|
+
env,
|
|
10184
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
10185
|
+
...config2.cwd ? { cwd: config2.cwd } : {}
|
|
10186
|
+
});
|
|
10187
|
+
proc.stderr?.resume();
|
|
10188
|
+
const rl2 = createInterface4({ input: proc.stdout });
|
|
10189
|
+
const timeout = setTimeout(() => {
|
|
10190
|
+
warn("[ai-apply] LLM spawn timeout");
|
|
10191
|
+
rl2.close();
|
|
10192
|
+
proc.kill("SIGTERM");
|
|
10193
|
+
setTimeout(() => proc.kill("SIGKILL"), 2e3);
|
|
10194
|
+
}, AI_APPLY_TIMEOUT_MS);
|
|
10195
|
+
rl2.on("line", (line) => {
|
|
10196
|
+
if (!line.trim()) return;
|
|
10197
|
+
let msg;
|
|
10198
|
+
try {
|
|
10199
|
+
msg = JSON.parse(line);
|
|
10200
|
+
} catch {
|
|
10201
|
+
return;
|
|
10202
|
+
}
|
|
10203
|
+
const events = adapter.parseLine(msg);
|
|
10204
|
+
for (const ev of events) {
|
|
10205
|
+
if (ev.type === "text" && ev.text) accumulatedText = appendTextChunk(accumulatedText, ev.text);
|
|
10206
|
+
if (ev.type === "result") {
|
|
10207
|
+
resultText = ev.resultText || accumulatedText;
|
|
10208
|
+
if (adapter.shouldKillOnResult()) {
|
|
10209
|
+
rl2.close();
|
|
10210
|
+
proc.kill("SIGTERM");
|
|
10211
|
+
}
|
|
10212
|
+
}
|
|
10213
|
+
}
|
|
10214
|
+
});
|
|
10215
|
+
proc.on("error", () => {
|
|
10216
|
+
clearTimeout(timeout);
|
|
10217
|
+
resolve();
|
|
10218
|
+
});
|
|
10219
|
+
proc.on("close", () => {
|
|
10220
|
+
clearTimeout(timeout);
|
|
10221
|
+
resolve();
|
|
10222
|
+
});
|
|
10223
|
+
});
|
|
10224
|
+
if (!resultText) resultText = accumulatedText;
|
|
10225
|
+
return resultText;
|
|
10226
|
+
}
|
|
10227
|
+
function resolveApplyAdapter(chatId) {
|
|
10228
|
+
try {
|
|
10229
|
+
const adapter = getAdapterForChat(chatId);
|
|
10230
|
+
return { adapter, model: adapter.defaultModel };
|
|
10231
|
+
} catch {
|
|
10232
|
+
try {
|
|
10233
|
+
const adapter = getAdapter("claude");
|
|
10234
|
+
return { adapter, model: adapter.defaultModel };
|
|
10235
|
+
} catch {
|
|
10236
|
+
return null;
|
|
10237
|
+
}
|
|
10238
|
+
}
|
|
10239
|
+
}
|
|
10240
|
+
function extractHeadings(content) {
|
|
10241
|
+
return content.split("\n").filter((line) => /^#{1,6}\s/.test(line)).map((line) => line.trim());
|
|
10242
|
+
}
|
|
10243
|
+
function validateOutput(original, output2) {
|
|
10244
|
+
if (!output2.trim()) {
|
|
10245
|
+
return { valid: false, reason: "LLM returned empty output" };
|
|
10246
|
+
}
|
|
10247
|
+
const originalLines = original.split("\n").length;
|
|
10248
|
+
const outputLines = output2.split("\n").length;
|
|
10249
|
+
if (originalLines > 5 && outputLines < originalLines * MIN_LINE_RETENTION) {
|
|
10250
|
+
return {
|
|
10251
|
+
valid: false,
|
|
10252
|
+
reason: `Output has ${outputLines} lines vs original ${originalLines} (${Math.round(outputLines / originalLines * 100)}% retained, min ${MIN_LINE_RETENTION * 100}%)`
|
|
10253
|
+
};
|
|
10254
|
+
}
|
|
10255
|
+
const originalHeadings = extractHeadings(original);
|
|
10256
|
+
const outputHeadings = extractHeadings(output2);
|
|
10257
|
+
for (const heading4 of originalHeadings) {
|
|
10258
|
+
if (!outputHeadings.includes(heading4)) {
|
|
10259
|
+
return {
|
|
10260
|
+
valid: false,
|
|
10261
|
+
reason: `Missing heading: "${heading4}"`
|
|
10262
|
+
};
|
|
10263
|
+
}
|
|
10264
|
+
}
|
|
10265
|
+
if (output2.trim() === original.trim()) {
|
|
10266
|
+
return { valid: false, reason: "Output is identical to original (no changes applied)" };
|
|
10267
|
+
}
|
|
10268
|
+
return { valid: true };
|
|
10269
|
+
}
|
|
10270
|
+
function stripMarkdownFences(text) {
|
|
10271
|
+
const fencePattern = /^```(?:markdown|md)?\s*\n([\s\S]*?)\n```\s*$/;
|
|
10272
|
+
const match = text.match(fencePattern);
|
|
10273
|
+
if (match) return match[1];
|
|
10274
|
+
return text;
|
|
10275
|
+
}
|
|
10276
|
+
async function applyWithAI(chatId, originalContent, instruction, proposedDiff, targetFile) {
|
|
10277
|
+
const resolved = resolveApplyAdapter(chatId);
|
|
10278
|
+
if (!resolved) {
|
|
10279
|
+
return { success: false, newContent: "", error: "No backend adapter available" };
|
|
10280
|
+
}
|
|
10281
|
+
const { adapter, model: model2 } = resolved;
|
|
10282
|
+
log(`[ai-apply] Using ${adapter.id}:${model2} for structural apply on ${targetFile}`);
|
|
10283
|
+
try {
|
|
10284
|
+
const prompt = buildApplyPrompt(originalContent, instruction, proposedDiff, targetFile);
|
|
10285
|
+
const rawOutput = await spawnApplyLLM(adapter, model2, prompt);
|
|
10286
|
+
if (!rawOutput.trim()) {
|
|
10287
|
+
return { success: false, newContent: "", error: "LLM returned empty response" };
|
|
10288
|
+
}
|
|
10289
|
+
const cleanOutput = stripMarkdownFences(rawOutput);
|
|
10290
|
+
const validation = validateOutput(originalContent, cleanOutput);
|
|
10291
|
+
if (!validation.valid) {
|
|
10292
|
+
return { success: false, newContent: "", error: `Validation failed: ${validation.reason}` };
|
|
10293
|
+
}
|
|
10294
|
+
log(`[ai-apply] Successfully applied change to ${targetFile}`);
|
|
10295
|
+
return { success: true, newContent: cleanOutput };
|
|
10296
|
+
} catch (err) {
|
|
10297
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10298
|
+
warn(`[ai-apply] LLM apply failed: ${msg}`);
|
|
10299
|
+
return { success: false, newContent: "", error: msg };
|
|
10300
|
+
}
|
|
10301
|
+
}
|
|
10302
|
+
var AI_APPLY_TIMEOUT_MS, MIN_LINE_RETENTION;
|
|
10303
|
+
var init_ai_apply = __esm({
|
|
10304
|
+
"src/reflection/ai-apply.ts"() {
|
|
10305
|
+
"use strict";
|
|
10306
|
+
init_log();
|
|
10307
|
+
init_text_utils();
|
|
10308
|
+
init_backends();
|
|
10309
|
+
AI_APPLY_TIMEOUT_MS = 6e4;
|
|
10310
|
+
MIN_LINE_RETENTION = 0.7;
|
|
10311
|
+
}
|
|
10312
|
+
});
|
|
10313
|
+
|
|
10131
10314
|
// src/reflection/apply.ts
|
|
10132
10315
|
var apply_exports = {};
|
|
10133
10316
|
__export(apply_exports, {
|
|
@@ -10258,7 +10441,31 @@ async function applyInsight(insightId) {
|
|
|
10258
10441
|
writeFileSync5(backupPath, original, "utf-8");
|
|
10259
10442
|
pruneBackups(absolutePath);
|
|
10260
10443
|
}
|
|
10261
|
-
|
|
10444
|
+
let newContent;
|
|
10445
|
+
if (insight.proposedAction !== "create") {
|
|
10446
|
+
try {
|
|
10447
|
+
const { applyWithAI: applyWithAI2 } = await Promise.resolve().then(() => (init_ai_apply(), ai_apply_exports));
|
|
10448
|
+
const aiResult = await applyWithAI2(
|
|
10449
|
+
chatId,
|
|
10450
|
+
original,
|
|
10451
|
+
insight.insight,
|
|
10452
|
+
insight.proposedDiff,
|
|
10453
|
+
insight.targetFile
|
|
10454
|
+
);
|
|
10455
|
+
if (aiResult.success) {
|
|
10456
|
+
newContent = aiResult.newContent;
|
|
10457
|
+
log(`[reflection/apply] AI apply succeeded for insight #${insightId}`);
|
|
10458
|
+
} else {
|
|
10459
|
+
warn(`[reflection/apply] AI apply failed (${aiResult.error}), falling back to static diff`);
|
|
10460
|
+
newContent = applyDiff(original, insight.proposedDiff, insight.proposedAction);
|
|
10461
|
+
}
|
|
10462
|
+
} catch (aiErr) {
|
|
10463
|
+
warn(`[reflection/apply] AI apply threw (${aiErr}), falling back to static diff`);
|
|
10464
|
+
newContent = applyDiff(original, insight.proposedDiff, insight.proposedAction);
|
|
10465
|
+
}
|
|
10466
|
+
} else {
|
|
10467
|
+
newContent = applyDiff(original, insight.proposedDiff, insight.proposedAction);
|
|
10468
|
+
}
|
|
10262
10469
|
writeFileSync5(absolutePath, newContent, "utf-8");
|
|
10263
10470
|
const rollbackData = JSON.stringify({ original, backupPath, appliedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10264
10471
|
updateInsightRollback(db3, insightId, rollbackData);
|
|
@@ -10947,6 +11154,7 @@ var init_detect = __esm({
|
|
|
10947
11154
|
// src/agent.ts
|
|
10948
11155
|
var agent_exports = {};
|
|
10949
11156
|
__export(agent_exports, {
|
|
11157
|
+
CONTENT_SILENCE_TIMEOUT_ERROR: () => CONTENT_SILENCE_TIMEOUT_ERROR,
|
|
10950
11158
|
FIRST_RESPONSE_TIMEOUT_ERROR: () => FIRST_RESPONSE_TIMEOUT_ERROR,
|
|
10951
11159
|
FREE_SLOTS_EXHAUSTED: () => FREE_SLOTS_EXHAUSTED,
|
|
10952
11160
|
askAgent: () => askAgent,
|
|
@@ -10956,8 +11164,8 @@ __export(agent_exports, {
|
|
|
10956
11164
|
stopAgent: () => stopAgent,
|
|
10957
11165
|
stopAllActiveAgents: () => stopAllActiveAgents
|
|
10958
11166
|
});
|
|
10959
|
-
import { spawn as
|
|
10960
|
-
import { createInterface as
|
|
11167
|
+
import { spawn as spawn6 } from "child_process";
|
|
11168
|
+
import { createInterface as createInterface5 } from "readline";
|
|
10961
11169
|
function isSyntheticChatId(chatId) {
|
|
10962
11170
|
return chatId.startsWith("sq:") || chatId.startsWith("cron:");
|
|
10963
11171
|
}
|
|
@@ -11021,7 +11229,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11021
11229
|
const env = opts?.envOverride ? thinkingConfig?.envOverrides ? { ...opts.envOverride, ...thinkingConfig.envOverrides } : opts.envOverride : adapter.getEnv(thinkingConfig?.envOverrides);
|
|
11022
11230
|
const finalArgs = thinkingConfig?.extraArgs ? [...config2.args, ...thinkingConfig.extraArgs] : config2.args;
|
|
11023
11231
|
log(`[agent:spawn] backend=${adapter.id} exe=${config2.executable} model=${model2} timeout=${effectiveTimeout / 1e3}s cwd=${config2.cwd ?? "(inherited)"}`);
|
|
11024
|
-
const proc =
|
|
11232
|
+
const proc = spawn6(config2.executable, finalArgs, {
|
|
11025
11233
|
env,
|
|
11026
11234
|
stdio: ["ignore", "pipe", "pipe"],
|
|
11027
11235
|
detached: true,
|
|
@@ -11054,7 +11262,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11054
11262
|
const pendingTools = /* @__PURE__ */ new Map();
|
|
11055
11263
|
const stderrChunks = [];
|
|
11056
11264
|
proc.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
|
|
11057
|
-
const rl2 =
|
|
11265
|
+
const rl2 = createInterface5({ input: proc.stdout });
|
|
11058
11266
|
let firstLine = true;
|
|
11059
11267
|
const frTimeoutMs = adapter.id === "gemini" ? opts?.firstResponseTimeoutMs ?? FIRST_RESPONSE_TIMEOUT_MS : 0;
|
|
11060
11268
|
let firstResponseTimer;
|
|
@@ -11070,6 +11278,20 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11070
11278
|
}
|
|
11071
11279
|
}, frTimeoutMs);
|
|
11072
11280
|
}
|
|
11281
|
+
let contentSilenceTimer;
|
|
11282
|
+
const silenceTimeoutMs = CONTENT_SILENCE_TIMEOUT_MS;
|
|
11283
|
+
function resetContentSilenceTimer() {
|
|
11284
|
+
if (silenceTimeoutMs <= 0) return;
|
|
11285
|
+
if (contentSilenceTimer) clearTimeout(contentSilenceTimer);
|
|
11286
|
+
contentSilenceTimer = setTimeout(() => {
|
|
11287
|
+
if (cancelState.cancelled || timedOut) return;
|
|
11288
|
+
warn(`[agent] Content silence timeout after ${silenceTimeoutMs / 1e3}s for ${adapter.id} \u2014 no content events, killing`);
|
|
11289
|
+
timedOut = true;
|
|
11290
|
+
cancelState.__contentSilenceTimeout = true;
|
|
11291
|
+
killProcessGroup(proc, "SIGTERM");
|
|
11292
|
+
sigkillTimer = setTimeout(() => killProcessGroup(proc, "SIGKILL"), 3e3);
|
|
11293
|
+
}, silenceTimeoutMs);
|
|
11294
|
+
}
|
|
11073
11295
|
rl2.on("line", (line) => {
|
|
11074
11296
|
if (!line.trim()) return;
|
|
11075
11297
|
if (firstLine) {
|
|
@@ -11092,6 +11314,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11092
11314
|
case "init":
|
|
11093
11315
|
log(`[agent] Session init at ${elapsed()}`);
|
|
11094
11316
|
if (ev.sessionId) sessionId = ev.sessionId;
|
|
11317
|
+
resetContentSilenceTimer();
|
|
11095
11318
|
break;
|
|
11096
11319
|
case "text":
|
|
11097
11320
|
if (!gotModelContent) {
|
|
@@ -11101,6 +11324,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11101
11324
|
firstResponseTimer = void 0;
|
|
11102
11325
|
}
|
|
11103
11326
|
}
|
|
11327
|
+
resetContentSilenceTimer();
|
|
11104
11328
|
if (ev.text) {
|
|
11105
11329
|
accumulatedText = appendTextChunk(accumulatedText, ev.text);
|
|
11106
11330
|
if (opts?.onStream) opts.onStream(ev.text);
|
|
@@ -11114,6 +11338,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11114
11338
|
firstResponseTimer = void 0;
|
|
11115
11339
|
}
|
|
11116
11340
|
}
|
|
11341
|
+
resetContentSilenceTimer();
|
|
11117
11342
|
if (ev.text) {
|
|
11118
11343
|
accumulatedThinking = appendTextChunk(accumulatedThinking, ev.text);
|
|
11119
11344
|
if (opts?.onThinking) opts.onThinking(ev.text);
|
|
@@ -11127,6 +11352,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11127
11352
|
firstResponseTimer = void 0;
|
|
11128
11353
|
}
|
|
11129
11354
|
}
|
|
11355
|
+
resetContentSilenceTimer();
|
|
11130
11356
|
sawToolEvents = true;
|
|
11131
11357
|
if (opts?.onToolAction && ev.toolName) {
|
|
11132
11358
|
const toolInput = ev.toolInput ?? {};
|
|
@@ -11153,6 +11379,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11153
11379
|
}
|
|
11154
11380
|
break;
|
|
11155
11381
|
case "tool_end":
|
|
11382
|
+
resetContentSilenceTimer();
|
|
11156
11383
|
if (opts?.onToolAction) {
|
|
11157
11384
|
const pending = ev.toolId ? pendingTools.get(ev.toolId) : void 0;
|
|
11158
11385
|
if (pending) {
|
|
@@ -11206,6 +11433,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11206
11433
|
proc.on("error", (err) => {
|
|
11207
11434
|
clearTimeout(spawnTimeout);
|
|
11208
11435
|
if (firstResponseTimer) clearTimeout(firstResponseTimer);
|
|
11436
|
+
if (contentSilenceTimer) clearTimeout(contentSilenceTimer);
|
|
11209
11437
|
if (sigkillTimer) clearTimeout(sigkillTimer);
|
|
11210
11438
|
rl2.close();
|
|
11211
11439
|
cancelState.process = void 0;
|
|
@@ -11217,6 +11445,10 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11217
11445
|
clearTimeout(firstResponseTimer);
|
|
11218
11446
|
firstResponseTimer = void 0;
|
|
11219
11447
|
}
|
|
11448
|
+
if (contentSilenceTimer) {
|
|
11449
|
+
clearTimeout(contentSilenceTimer);
|
|
11450
|
+
contentSilenceTimer = void 0;
|
|
11451
|
+
}
|
|
11220
11452
|
if (sigkillTimer) {
|
|
11221
11453
|
clearTimeout(sigkillTimer);
|
|
11222
11454
|
sigkillTimer = void 0;
|
|
@@ -11237,6 +11469,11 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
11237
11469
|
reject(new Error(`${FIRST_RESPONSE_TIMEOUT_ERROR}: No response from ${adapter.id} within ${frTimeoutMs / 1e3}s${stderr ? ` \u2014 ${stderr.slice(-300)}` : ""}`));
|
|
11238
11470
|
return;
|
|
11239
11471
|
}
|
|
11472
|
+
if (cancelState.__contentSilenceTimeout) {
|
|
11473
|
+
delete cancelState.__contentSilenceTimeout;
|
|
11474
|
+
reject(new Error(`${CONTENT_SILENCE_TIMEOUT_ERROR}: ${adapter.id} produced no content events for ${silenceTimeoutMs / 1e3}s after init`));
|
|
11475
|
+
return;
|
|
11476
|
+
}
|
|
11240
11477
|
let msg = `Spawn timeout after ${effectiveTimeout / 1e3}s`;
|
|
11241
11478
|
if (pendingTools.size > 0) {
|
|
11242
11479
|
const tools2 = Array.from(pendingTools.values()).map((t) => typeof t === "string" ? t : t.name).join(", ");
|
|
@@ -11589,6 +11826,26 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
11589
11826
|
})();
|
|
11590
11827
|
result = await spawnQuery(adapter, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, retryOpts);
|
|
11591
11828
|
}
|
|
11829
|
+
} else if (errMsg.startsWith(CONTENT_SILENCE_TIMEOUT_ERROR) && existingSessionId) {
|
|
11830
|
+
warn(`[agent] Content silence on ${adapter.id} \u2014 clearing session ${existingSessionId} and retrying fresh`);
|
|
11831
|
+
clearSession(chatId);
|
|
11832
|
+
if (useGeminiRotation) {
|
|
11833
|
+
const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
|
|
11834
|
+
const downgradeCb = onModelDowngrade ? (from, to, reason) => onModelDowngrade(chatId, from, to, reason) : void 0;
|
|
11835
|
+
result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, geminiRotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
|
|
11836
|
+
} else if (useBackendRotation) {
|
|
11837
|
+
const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
|
|
11838
|
+
result = await spawnWithSlotRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, backendRotationMode, allowPaid, spawnOpts, rotationCb);
|
|
11839
|
+
} else {
|
|
11840
|
+
const retryOpts = (() => {
|
|
11841
|
+
if (adapter.id !== "gemini") return spawnOpts;
|
|
11842
|
+
const geminiAdapter = adapter;
|
|
11843
|
+
const { env, slot } = geminiAdapter.resolveSlotEnv(chatId);
|
|
11844
|
+
if (slot) return { ...spawnOpts, envOverride: env };
|
|
11845
|
+
return spawnOpts;
|
|
11846
|
+
})();
|
|
11847
|
+
result = await spawnQuery(adapter, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, retryOpts);
|
|
11848
|
+
}
|
|
11592
11849
|
} else {
|
|
11593
11850
|
if (!isSyntheticChatId(chatId)) {
|
|
11594
11851
|
try {
|
|
@@ -11693,7 +11950,7 @@ function injectMcpConfig(adapterId, args, mcpConfigPath) {
|
|
|
11693
11950
|
if (!flag) return args;
|
|
11694
11951
|
return [...args, ...flag, mcpConfigPath];
|
|
11695
11952
|
}
|
|
11696
|
-
var activeChats, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_ERROR, FREE_SLOTS_EXHAUSTED, GEMINI_FALLBACK_CHAIN, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
|
|
11953
|
+
var activeChats, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, CONTENT_SILENCE_TIMEOUT_MS, CONTENT_SILENCE_TIMEOUT_ERROR, FIRST_RESPONSE_TIMEOUT_ERROR, FREE_SLOTS_EXHAUSTED, GEMINI_FALLBACK_CHAIN, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
|
|
11697
11954
|
var init_agent = __esm({
|
|
11698
11955
|
"src/agent.ts"() {
|
|
11699
11956
|
"use strict";
|
|
@@ -11718,6 +11975,8 @@ var init_agent = __esm({
|
|
|
11718
11975
|
chatLocks = /* @__PURE__ */ new Map();
|
|
11719
11976
|
SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
11720
11977
|
FIRST_RESPONSE_TIMEOUT_MS = parseInt(process.env.GEMINI_FIRST_RESPONSE_TIMEOUT_MS ?? "30000", 10);
|
|
11978
|
+
CONTENT_SILENCE_TIMEOUT_MS = parseInt(process.env.CONTENT_SILENCE_TIMEOUT_MS ?? "90000", 10);
|
|
11979
|
+
CONTENT_SILENCE_TIMEOUT_ERROR = "CONTENT_SILENCE_TIMEOUT";
|
|
11721
11980
|
FIRST_RESPONSE_TIMEOUT_ERROR = "FIRST_RESPONSE_TIMEOUT";
|
|
11722
11981
|
FREE_SLOTS_EXHAUSTED = "FREE_SLOTS_EXHAUSTED";
|
|
11723
11982
|
GEMINI_FALLBACK_CHAIN = {
|
|
@@ -17024,8 +17283,8 @@ __export(analyze_exports2, {
|
|
|
17024
17283
|
runIdentityAudit: () => runIdentityAudit,
|
|
17025
17284
|
runSkillAudit: () => runSkillAudit
|
|
17026
17285
|
});
|
|
17027
|
-
import { spawn as
|
|
17028
|
-
import { createInterface as
|
|
17286
|
+
import { spawn as spawn7 } from "child_process";
|
|
17287
|
+
import { createInterface as createInterface6 } from "readline";
|
|
17029
17288
|
import { readFileSync as readFileSync12, existsSync as existsSync21, readdirSync as readdirSync11 } from "fs";
|
|
17030
17289
|
import { join as join22 } from "path";
|
|
17031
17290
|
import { homedir as homedir7 } from "os";
|
|
@@ -17047,6 +17306,14 @@ function parseOptimizeOutput(raw, validAreas) {
|
|
|
17047
17306
|
if (!validAreas.includes(area)) continue;
|
|
17048
17307
|
const severity = severityMatch?.[1]?.trim().toLowerCase() ?? "info";
|
|
17049
17308
|
if (!VALID_SEVERITIES.includes(severity)) continue;
|
|
17309
|
+
let proposedDiff = diffMatch?.[1]?.trim() ?? "";
|
|
17310
|
+
if (proposedDiff.startsWith("```")) {
|
|
17311
|
+
proposedDiff = proposedDiff.replace(/^```[a-zA-Z0-9-]*\r?\n/, "");
|
|
17312
|
+
if (proposedDiff.endsWith("```")) {
|
|
17313
|
+
proposedDiff = proposedDiff.replace(/\r?\n```$/, "");
|
|
17314
|
+
}
|
|
17315
|
+
proposedDiff = proposedDiff.trim();
|
|
17316
|
+
}
|
|
17050
17317
|
results.push({
|
|
17051
17318
|
title: findingMatch[1].trim().slice(0, 80),
|
|
17052
17319
|
area,
|
|
@@ -17054,7 +17321,7 @@ function parseOptimizeOutput(raw, validAreas) {
|
|
|
17054
17321
|
detail: detailMatch?.[1]?.trim() ?? "",
|
|
17055
17322
|
location: locationMatch?.[1]?.trim() ?? "",
|
|
17056
17323
|
suggestion: suggestionMatch?.[1]?.trim() ?? "",
|
|
17057
|
-
proposedDiff
|
|
17324
|
+
proposedDiff
|
|
17058
17325
|
});
|
|
17059
17326
|
}
|
|
17060
17327
|
return results;
|
|
@@ -17070,13 +17337,13 @@ async function spawnAnalysis2(adapter, model2, prompt, timeoutMs = ANALYSIS_TIME
|
|
|
17070
17337
|
let resultText = "";
|
|
17071
17338
|
let accumulatedText = "";
|
|
17072
17339
|
await new Promise((resolve) => {
|
|
17073
|
-
const proc =
|
|
17340
|
+
const proc = spawn7(config2.executable, config2.args, {
|
|
17074
17341
|
env,
|
|
17075
17342
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17076
17343
|
...config2.cwd ? { cwd: config2.cwd } : {}
|
|
17077
17344
|
});
|
|
17078
17345
|
proc.stderr?.resume();
|
|
17079
|
-
const rl2 =
|
|
17346
|
+
const rl2 = createInterface6({ input: proc.stdout });
|
|
17080
17347
|
const timeout = setTimeout(() => {
|
|
17081
17348
|
warn(`[optimizer] Analysis timeout (${adapter.id}:${model2})`);
|
|
17082
17349
|
rl2.close();
|
|
@@ -17558,8 +17825,8 @@ var init_ui2 = __esm({
|
|
|
17558
17825
|
});
|
|
17559
17826
|
|
|
17560
17827
|
// src/router/optimize.ts
|
|
17561
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync22 } from "fs";
|
|
17562
|
-
import { join as join23 } from "path";
|
|
17828
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync22, readdirSync as readdirSync12, unlinkSync as unlinkSync6 } from "fs";
|
|
17829
|
+
import { join as join23, dirname as dirname4 } from "path";
|
|
17563
17830
|
import { homedir as homedir8 } from "os";
|
|
17564
17831
|
async function handleOptimizeCommand(chatId, channel, _args) {
|
|
17565
17832
|
const { getModelDisplayInfo: getModelDisplayInfo2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
@@ -17664,13 +17931,38 @@ async function runIdentityAuditFlow(chatId, channel) {
|
|
|
17664
17931
|
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17665
17932
|
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17666
17933
|
if (!modelInfo) return;
|
|
17667
|
-
await channel.
|
|
17934
|
+
const progressMsgId = typeof channel.sendTextReturningId === "function" ? await channel.sendTextReturningId(
|
|
17668
17935
|
chatId,
|
|
17669
17936
|
buildProgressMessage2("identity files", modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17670
|
-
|
|
17671
|
-
);
|
|
17937
|
+
"plain"
|
|
17938
|
+
) : void 0;
|
|
17939
|
+
if (!progressMsgId) {
|
|
17940
|
+
await channel.sendText(
|
|
17941
|
+
chatId,
|
|
17942
|
+
buildProgressMessage2("identity files", modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17943
|
+
{ parseMode: "plain" }
|
|
17944
|
+
);
|
|
17945
|
+
}
|
|
17946
|
+
const startTime = Date.now();
|
|
17947
|
+
const progressInterval = setInterval(async () => {
|
|
17948
|
+
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
17949
|
+
try {
|
|
17950
|
+
if (channel.sendTyping) await channel.sendTyping(chatId);
|
|
17951
|
+
if (progressMsgId && channel.editText) {
|
|
17952
|
+
await channel.editText(
|
|
17953
|
+
chatId,
|
|
17954
|
+
progressMsgId,
|
|
17955
|
+
buildProgressMessage2("identity files", modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel) + `
|
|
17956
|
+
\u23F3 Analyzing... (${elapsed}s)`,
|
|
17957
|
+
"plain"
|
|
17958
|
+
);
|
|
17959
|
+
}
|
|
17960
|
+
} catch {
|
|
17961
|
+
}
|
|
17962
|
+
}, 5e3);
|
|
17672
17963
|
try {
|
|
17673
17964
|
const result = await runIdentityAudit2(chatId);
|
|
17965
|
+
clearInterval(progressInterval);
|
|
17674
17966
|
activeSessions.set(chatId, {
|
|
17675
17967
|
chatId,
|
|
17676
17968
|
result,
|
|
@@ -17685,6 +17977,7 @@ async function runIdentityAuditFlow(chatId, channel) {
|
|
|
17685
17977
|
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
17686
17978
|
}
|
|
17687
17979
|
} catch (e) {
|
|
17980
|
+
clearInterval(progressInterval);
|
|
17688
17981
|
await channel.sendText(chatId, `Identity audit failed: ${e}`, { parseMode: "plain" });
|
|
17689
17982
|
}
|
|
17690
17983
|
}
|
|
@@ -17715,13 +18008,38 @@ async function runSkillAuditFlow(chatId, channel, skillName) {
|
|
|
17715
18008
|
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17716
18009
|
if (!modelInfo) return;
|
|
17717
18010
|
const skillPath = join23(homedir8(), ".cc-claw", "workspace", "skills", skillName, "SKILL.md");
|
|
17718
|
-
await channel.
|
|
18011
|
+
const progressMsgId = typeof channel.sendTextReturningId === "function" ? await channel.sendTextReturningId(
|
|
17719
18012
|
chatId,
|
|
17720
18013
|
buildProgressMessage2(`skill: ${skillName}`, modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17721
|
-
|
|
17722
|
-
);
|
|
18014
|
+
"plain"
|
|
18015
|
+
) : void 0;
|
|
18016
|
+
if (!progressMsgId) {
|
|
18017
|
+
await channel.sendText(
|
|
18018
|
+
chatId,
|
|
18019
|
+
buildProgressMessage2(`skill: ${skillName}`, modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
18020
|
+
{ parseMode: "plain" }
|
|
18021
|
+
);
|
|
18022
|
+
}
|
|
18023
|
+
const startTime = Date.now();
|
|
18024
|
+
const progressInterval = setInterval(async () => {
|
|
18025
|
+
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
18026
|
+
try {
|
|
18027
|
+
if (channel.sendTyping) await channel.sendTyping(chatId);
|
|
18028
|
+
if (progressMsgId && channel.editText) {
|
|
18029
|
+
await channel.editText(
|
|
18030
|
+
chatId,
|
|
18031
|
+
progressMsgId,
|
|
18032
|
+
buildProgressMessage2(`skill: ${skillName}`, modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel) + `
|
|
18033
|
+
\u23F3 Analyzing... (${elapsed}s)`,
|
|
18034
|
+
"plain"
|
|
18035
|
+
);
|
|
18036
|
+
}
|
|
18037
|
+
} catch {
|
|
18038
|
+
}
|
|
18039
|
+
}, 5e3);
|
|
17723
18040
|
try {
|
|
17724
18041
|
const result = await runSkillAudit2(chatId, skillPath);
|
|
18042
|
+
clearInterval(progressInterval);
|
|
17725
18043
|
activeSessions.set(chatId, {
|
|
17726
18044
|
chatId,
|
|
17727
18045
|
result,
|
|
@@ -17736,6 +18054,7 @@ async function runSkillAuditFlow(chatId, channel, skillName) {
|
|
|
17736
18054
|
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
17737
18055
|
}
|
|
17738
18056
|
} catch (e) {
|
|
18057
|
+
clearInterval(progressInterval);
|
|
17739
18058
|
await channel.sendText(chatId, `Skill audit failed: ${e}`, { parseMode: "plain" });
|
|
17740
18059
|
}
|
|
17741
18060
|
}
|
|
@@ -17787,8 +18106,28 @@ async function applyFinding(chatId, channel, index) {
|
|
|
17787
18106
|
const backupPath = targetPath + `.bak.${Date.now()}`;
|
|
17788
18107
|
writeFileSync7(backupPath, original, "utf-8");
|
|
17789
18108
|
pruneBackups2(targetPath);
|
|
17790
|
-
|
|
17791
|
-
|
|
18109
|
+
let newContent;
|
|
18110
|
+
try {
|
|
18111
|
+
const { applyWithAI: applyWithAI2 } = await Promise.resolve().then(() => (init_ai_apply(), ai_apply_exports));
|
|
18112
|
+
const aiResult = await applyWithAI2(
|
|
18113
|
+
chatId,
|
|
18114
|
+
original,
|
|
18115
|
+
finding.suggestion || finding.title,
|
|
18116
|
+
finding.proposedDiff,
|
|
18117
|
+
finding.location.split(":")[0] || "unknown"
|
|
18118
|
+
);
|
|
18119
|
+
if (aiResult.success) {
|
|
18120
|
+
newContent = aiResult.newContent;
|
|
18121
|
+
} else {
|
|
18122
|
+
warn(`[optimizer] AI apply failed (${aiResult.error}), falling back to static diff`);
|
|
18123
|
+
const { applyDiff: applyDiff2 } = await Promise.resolve().then(() => (init_apply(), apply_exports));
|
|
18124
|
+
newContent = applyDiff2(original, finding.proposedDiff, "replace");
|
|
18125
|
+
}
|
|
18126
|
+
} catch (aiErr) {
|
|
18127
|
+
warn(`[optimizer] AI apply threw (${aiErr}), falling back to static diff`);
|
|
18128
|
+
const { applyDiff: applyDiff2 } = await Promise.resolve().then(() => (init_apply(), apply_exports));
|
|
18129
|
+
newContent = applyDiff2(original, finding.proposedDiff, "replace");
|
|
18130
|
+
}
|
|
17792
18131
|
if (newContent === original) {
|
|
17793
18132
|
await channel.sendText(chatId, `\u26A0\uFE0F Diff produced no changes. The content may have already been modified.`, { parseMode: "plain" });
|
|
17794
18133
|
session2.skipped.push(index);
|
|
@@ -17850,16 +18189,14 @@ function resolveTargetFile(location, auditTarget) {
|
|
|
17850
18189
|
return null;
|
|
17851
18190
|
}
|
|
17852
18191
|
function pruneBackups2(absolutePath) {
|
|
17853
|
-
const
|
|
17854
|
-
const { dirname: dirName } = __require("path");
|
|
17855
|
-
const dir = dirName(absolutePath);
|
|
18192
|
+
const dir = dirname4(absolutePath);
|
|
17856
18193
|
const baseName = absolutePath.split("/").pop() ?? "";
|
|
17857
18194
|
try {
|
|
17858
|
-
const backups =
|
|
18195
|
+
const backups = readdirSync12(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join23(dir, f));
|
|
17859
18196
|
while (backups.length > 3) {
|
|
17860
18197
|
const oldest = backups.shift();
|
|
17861
18198
|
try {
|
|
17862
|
-
|
|
18199
|
+
unlinkSync6(oldest);
|
|
17863
18200
|
} catch {
|
|
17864
18201
|
}
|
|
17865
18202
|
}
|
|
@@ -17870,6 +18207,7 @@ var activeSessions;
|
|
|
17870
18207
|
var init_optimize = __esm({
|
|
17871
18208
|
"src/router/optimize.ts"() {
|
|
17872
18209
|
"use strict";
|
|
18210
|
+
init_log();
|
|
17873
18211
|
activeSessions = /* @__PURE__ */ new Map();
|
|
17874
18212
|
}
|
|
17875
18213
|
});
|
|
@@ -19534,7 +19872,14 @@ var init_commands = __esm({
|
|
|
19534
19872
|
|
|
19535
19873
|
// src/router/callbacks.ts
|
|
19536
19874
|
import { readFile as readFile7 } from "fs/promises";
|
|
19537
|
-
async function handleCallback(chatId, data, channel) {
|
|
19875
|
+
async function handleCallback(chatId, data, channel, messageId) {
|
|
19876
|
+
const replaceWithText = async (text) => {
|
|
19877
|
+
if (messageId && channel.editText) {
|
|
19878
|
+
await channel.editText(chatId, messageId, text, "plain");
|
|
19879
|
+
} else {
|
|
19880
|
+
await channel.sendText(chatId, text, { parseMode: "plain" });
|
|
19881
|
+
}
|
|
19882
|
+
};
|
|
19538
19883
|
if (data.startsWith("menu:")) {
|
|
19539
19884
|
const action = data.slice(5);
|
|
19540
19885
|
const synth = { chatId, messageId: "", text: "", senderName: "User", type: "command", source: "telegram", command: "", commandArgs: "" };
|
|
@@ -19770,7 +20115,7 @@ ${PERM_MODES[chosen]}`,
|
|
|
19770
20115
|
return;
|
|
19771
20116
|
}
|
|
19772
20117
|
removePendingPlan(chatId);
|
|
19773
|
-
await
|
|
20118
|
+
await replaceWithText("\u2705 Approved. Executing...");
|
|
19774
20119
|
bypassBusyCheck.add(chatId);
|
|
19775
20120
|
const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router(), router_exports));
|
|
19776
20121
|
const overrideMsg = `[SYSTEM: Planning mode disabled. Execution APPROVED. Please execute the plan.]
|
|
@@ -20263,14 +20608,14 @@ ${rotationNote}`, { parseMode: "html" });
|
|
|
20263
20608
|
}
|
|
20264
20609
|
} else if (action === "discard") {
|
|
20265
20610
|
pendingInterrupts.delete(targetChatId);
|
|
20266
|
-
await
|
|
20611
|
+
await replaceWithText("\u{1F5D1} Message discarded.");
|
|
20267
20612
|
} else {
|
|
20268
20613
|
await channel.sendText(chatId, "Message already processed or expired.", { parseMode: "plain" });
|
|
20269
20614
|
}
|
|
20270
20615
|
} else if (data.startsWith("sq:cancel:")) {
|
|
20271
20616
|
const sqId = data.slice("sq:cancel:".length);
|
|
20272
20617
|
stopAgent(sqId);
|
|
20273
|
-
await
|
|
20618
|
+
await replaceWithText("\u{1F5FA} Side quest cancelled.");
|
|
20274
20619
|
} else if (data.startsWith("fallback:")) {
|
|
20275
20620
|
const parts = data.split(":");
|
|
20276
20621
|
const targetBackend = parts[1];
|
|
@@ -20658,9 +21003,9 @@ __export(session_log_exports2, {
|
|
|
20658
21003
|
startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
|
|
20659
21004
|
tailSessionLog: () => tailSessionLog
|
|
20660
21005
|
});
|
|
20661
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync9, appendFileSync, readdirSync as
|
|
21006
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync9, appendFileSync, readdirSync as readdirSync13, unlinkSync as unlinkSync7, statSync as statSync7, createReadStream } from "fs";
|
|
20662
21007
|
import { join as join24, basename as basename3 } from "path";
|
|
20663
|
-
import { createInterface as
|
|
21008
|
+
import { createInterface as createInterface7 } from "readline";
|
|
20664
21009
|
function getRetentionDays() {
|
|
20665
21010
|
const env = process.env.SESSION_LOG_RETENTION_DAYS;
|
|
20666
21011
|
if (env) {
|
|
@@ -20675,13 +21020,13 @@ function cleanupSessionLogs(retentionDays) {
|
|
|
20675
21020
|
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
20676
21021
|
let cleaned = 0;
|
|
20677
21022
|
try {
|
|
20678
|
-
for (const file of
|
|
21023
|
+
for (const file of readdirSync13(SESSION_LOGS_PATH)) {
|
|
20679
21024
|
if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
|
|
20680
21025
|
const filePath = join24(SESSION_LOGS_PATH, file);
|
|
20681
21026
|
try {
|
|
20682
21027
|
const { mtimeMs } = statSync7(filePath);
|
|
20683
21028
|
if (mtimeMs < cutoff) {
|
|
20684
|
-
|
|
21029
|
+
unlinkSync7(filePath);
|
|
20685
21030
|
cleaned++;
|
|
20686
21031
|
}
|
|
20687
21032
|
} catch {
|
|
@@ -20705,7 +21050,7 @@ function startSessionLogCleanupTimer() {
|
|
|
20705
21050
|
function listSessionLogs() {
|
|
20706
21051
|
if (!existsSync23(SESSION_LOGS_PATH)) return [];
|
|
20707
21052
|
const logs = [];
|
|
20708
|
-
for (const file of
|
|
21053
|
+
for (const file of readdirSync13(SESSION_LOGS_PATH)) {
|
|
20709
21054
|
if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
|
|
20710
21055
|
const filePath = join24(SESSION_LOGS_PATH, file);
|
|
20711
21056
|
try {
|
|
@@ -20731,7 +21076,7 @@ async function* tailSessionLog(filePath, lines = 50) {
|
|
|
20731
21076
|
return;
|
|
20732
21077
|
}
|
|
20733
21078
|
const allLines = [];
|
|
20734
|
-
const rl2 =
|
|
21079
|
+
const rl2 = createInterface7({
|
|
20735
21080
|
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
20736
21081
|
crlfDelay: Infinity
|
|
20737
21082
|
});
|
|
@@ -20897,13 +21242,14 @@ function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking)
|
|
|
20897
21242
|
};
|
|
20898
21243
|
return { liveStatus, toolCb };
|
|
20899
21244
|
}
|
|
20900
|
-
var
|
|
21245
|
+
var FLUSH_INTERVAL_DM_MS, FLUSH_INTERVAL_GROUP_MS, MAX_THINKING_CHARS, TRIM_THRESHOLD, MAX_ENTRIES, LiveStatusMessage;
|
|
20901
21246
|
var init_live_status = __esm({
|
|
20902
21247
|
"src/router/live-status.ts"() {
|
|
20903
21248
|
"use strict";
|
|
20904
21249
|
init_log();
|
|
20905
21250
|
init_helpers();
|
|
20906
|
-
|
|
21251
|
+
FLUSH_INTERVAL_DM_MS = 1e3;
|
|
21252
|
+
FLUSH_INTERVAL_GROUP_MS = 3e3;
|
|
20907
21253
|
MAX_THINKING_CHARS = 800;
|
|
20908
21254
|
TRIM_THRESHOLD = 3500;
|
|
20909
21255
|
MAX_ENTRIES = 200;
|
|
@@ -20925,6 +21271,11 @@ var init_live_status = __esm({
|
|
|
20925
21271
|
nextFlushAllowedAt = 0;
|
|
20926
21272
|
/** Tracks whether entries have been trimmed at least once (for display hint). */
|
|
20927
21273
|
hasTrimmed = false;
|
|
21274
|
+
/** Resolve flush interval based on chat type (group chats are rate-limited more aggressively). */
|
|
21275
|
+
get flushIntervalMs() {
|
|
21276
|
+
const numericId = parseInt(this.chatId);
|
|
21277
|
+
return numericId < 0 ? FLUSH_INTERVAL_GROUP_MS : FLUSH_INTERVAL_DM_MS;
|
|
21278
|
+
}
|
|
20928
21279
|
/** Send the initial status message. Must be called before adding entries. */
|
|
20929
21280
|
async init() {
|
|
20930
21281
|
if (!this.channel.sendTextReturningId) return;
|
|
@@ -20933,7 +21284,7 @@ var init_live_status = __esm({
|
|
|
20933
21284
|
this.messageId = await this.channel.sendTextReturningId(this.chatId, initial, "plain") ?? null;
|
|
20934
21285
|
if (this.messageId) {
|
|
20935
21286
|
this.flushTimer = setInterval(() => this.flush().catch(() => {
|
|
20936
|
-
}),
|
|
21287
|
+
}), this.flushIntervalMs);
|
|
20937
21288
|
}
|
|
20938
21289
|
} catch (err) {
|
|
20939
21290
|
log(`[live-status] init failed: ${err}`);
|
|
@@ -22158,7 +22509,7 @@ var init_wrap_backend = __esm({
|
|
|
22158
22509
|
});
|
|
22159
22510
|
|
|
22160
22511
|
// src/agents/runners/config-loader.ts
|
|
22161
|
-
import { readFileSync as readFileSync14, readdirSync as
|
|
22512
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync14, existsSync as existsSync24, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
|
|
22162
22513
|
import { join as join26 } from "path";
|
|
22163
22514
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
22164
22515
|
function resolveExecutable(config2) {
|
|
@@ -22312,7 +22663,7 @@ function loadAllRunnerConfigs() {
|
|
|
22312
22663
|
mkdirSync10(RUNNERS_PATH, { recursive: true });
|
|
22313
22664
|
return [];
|
|
22314
22665
|
}
|
|
22315
|
-
const files =
|
|
22666
|
+
const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
22316
22667
|
const configs = [];
|
|
22317
22668
|
for (const file of files) {
|
|
22318
22669
|
const config2 = loadRunnerConfig(join26(RUNNERS_PATH, file));
|
|
@@ -22343,7 +22694,7 @@ function watchRunnerConfigs(onChange) {
|
|
|
22343
22694
|
watchedFiles.delete(prev);
|
|
22344
22695
|
}
|
|
22345
22696
|
}
|
|
22346
|
-
const files =
|
|
22697
|
+
const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
22347
22698
|
for (const file of files) {
|
|
22348
22699
|
const fullPath = join26(RUNNERS_PATH, file);
|
|
22349
22700
|
if (watchedFiles.has(fullPath)) continue;
|
|
@@ -22646,7 +22997,26 @@ ${body.replace(/<[^>]*>/g, "").trim()}</code>
|
|
|
22646
22997
|
});
|
|
22647
22998
|
|
|
22648
22999
|
// src/channels/telegram.ts
|
|
22649
|
-
import { Bot, InlineKeyboard, InputFile } from "grammy";
|
|
23000
|
+
import { Bot, GrammyError, InlineKeyboard, InputFile } from "grammy";
|
|
23001
|
+
async function withRetry(label2, fn) {
|
|
23002
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
23003
|
+
try {
|
|
23004
|
+
return await fn();
|
|
23005
|
+
} catch (err) {
|
|
23006
|
+
if (err instanceof GrammyError && err.error_code === 429) {
|
|
23007
|
+
const retrySec = Math.min(err.parameters?.retry_after ?? FALLBACK_RETRY_SEC, MAX_RETRY_WAIT_SEC);
|
|
23008
|
+
if (attempt < MAX_RETRIES2) {
|
|
23009
|
+
warn(`[telegram] 429 on ${label2} (attempt ${attempt + 1}/${MAX_RETRIES2}) \u2014 retrying in ${retrySec}s`);
|
|
23010
|
+
await new Promise((r) => setTimeout(r, retrySec * 1e3));
|
|
23011
|
+
continue;
|
|
23012
|
+
}
|
|
23013
|
+
warn(`[telegram] 429 on ${label2} \u2014 exhausted ${MAX_RETRIES2} retries, giving up`);
|
|
23014
|
+
}
|
|
23015
|
+
throw err;
|
|
23016
|
+
}
|
|
23017
|
+
}
|
|
23018
|
+
throw new Error(`withRetry: unreachable`);
|
|
23019
|
+
}
|
|
22650
23020
|
function isFastPathMessage(msg) {
|
|
22651
23021
|
if (msg.type === "command" && msg.command && FAST_PATH_COMMANDS.has(msg.command)) {
|
|
22652
23022
|
return true;
|
|
@@ -22666,13 +23036,16 @@ function numericChatId(chatId) {
|
|
|
22666
23036
|
const raw = chatId.includes(":") ? chatId.split(":").pop() : chatId;
|
|
22667
23037
|
return parseInt(raw);
|
|
22668
23038
|
}
|
|
22669
|
-
var FAST_PATH_COMMANDS, TelegramChannel;
|
|
23039
|
+
var MAX_RETRIES2, FALLBACK_RETRY_SEC, MAX_RETRY_WAIT_SEC, FAST_PATH_COMMANDS, TelegramChannel;
|
|
22670
23040
|
var init_telegram2 = __esm({
|
|
22671
23041
|
"src/channels/telegram.ts"() {
|
|
22672
23042
|
"use strict";
|
|
22673
23043
|
init_telegram();
|
|
22674
23044
|
init_log();
|
|
22675
23045
|
init_store5();
|
|
23046
|
+
MAX_RETRIES2 = 3;
|
|
23047
|
+
FALLBACK_RETRY_SEC = 3;
|
|
23048
|
+
MAX_RETRY_WAIT_SEC = 30;
|
|
22676
23049
|
FAST_PATH_COMMANDS = /* @__PURE__ */ new Set(["stop", "status", "new", "newchat"]);
|
|
22677
23050
|
TelegramChannel = class {
|
|
22678
23051
|
name = "telegram";
|
|
@@ -22823,11 +23196,12 @@ var init_telegram2 = __esm({
|
|
|
22823
23196
|
return;
|
|
22824
23197
|
}
|
|
22825
23198
|
const data = ctx.callbackQuery.data;
|
|
23199
|
+
const messageId = ctx.callbackQuery.message?.message_id?.toString();
|
|
22826
23200
|
ctx.answerCallbackQuery().catch(() => {
|
|
22827
23201
|
});
|
|
22828
23202
|
(async () => {
|
|
22829
23203
|
for (const handler2 of this.callbackHandlers) {
|
|
22830
|
-
await handler2(chatId, data, this);
|
|
23204
|
+
await handler2(chatId, data, this, messageId);
|
|
22831
23205
|
}
|
|
22832
23206
|
})().catch((err) => {
|
|
22833
23207
|
error("[telegram] Callback handler error:", err);
|
|
@@ -22880,7 +23254,10 @@ var init_telegram2 = __esm({
|
|
|
22880
23254
|
if (parseMode === "plain") {
|
|
22881
23255
|
const plainChunks = splitMessage(text);
|
|
22882
23256
|
for (const chunk of plainChunks) {
|
|
22883
|
-
const sent = await
|
|
23257
|
+
const sent = await withRetry(
|
|
23258
|
+
"sendText:plain",
|
|
23259
|
+
() => this.bot.api.sendMessage(numericChatId(chatId), chunk, { ...threadOpts, ...replyOpts })
|
|
23260
|
+
);
|
|
22884
23261
|
this.trackAgentMessage(sent.message_id, chatId);
|
|
22885
23262
|
}
|
|
22886
23263
|
return;
|
|
@@ -22889,32 +23266,44 @@ var init_telegram2 = __esm({
|
|
|
22889
23266
|
const chunks = splitMessage(formatted);
|
|
22890
23267
|
for (const chunk of chunks) {
|
|
22891
23268
|
try {
|
|
22892
|
-
const sent = await
|
|
22893
|
-
|
|
22894
|
-
|
|
22895
|
-
|
|
22896
|
-
|
|
23269
|
+
const sent = await withRetry(
|
|
23270
|
+
"sendText:html",
|
|
23271
|
+
() => this.bot.api.sendMessage(numericChatId(chatId), chunk, {
|
|
23272
|
+
parse_mode: "HTML",
|
|
23273
|
+
...threadOpts,
|
|
23274
|
+
...replyOpts
|
|
23275
|
+
})
|
|
23276
|
+
);
|
|
22897
23277
|
this.trackAgentMessage(sent.message_id, chatId);
|
|
22898
23278
|
} catch {
|
|
22899
|
-
const sent = await
|
|
22900
|
-
|
|
22901
|
-
|
|
22902
|
-
|
|
23279
|
+
const sent = await withRetry(
|
|
23280
|
+
"sendText:fallback",
|
|
23281
|
+
() => this.bot.api.sendMessage(
|
|
23282
|
+
numericChatId(chatId),
|
|
23283
|
+
chunk.replace(/<[^>]+>/g, ""),
|
|
23284
|
+
{ ...threadOpts, ...replyOpts }
|
|
23285
|
+
)
|
|
22903
23286
|
);
|
|
22904
23287
|
this.trackAgentMessage(sent.message_id, chatId);
|
|
22905
23288
|
}
|
|
22906
23289
|
}
|
|
22907
23290
|
}
|
|
22908
23291
|
async sendVoice(chatId, audioBuffer, fileName) {
|
|
22909
|
-
await
|
|
22910
|
-
|
|
22911
|
-
|
|
23292
|
+
await withRetry(
|
|
23293
|
+
"sendVoice",
|
|
23294
|
+
() => this.bot.api.sendVoice(
|
|
23295
|
+
numericChatId(chatId),
|
|
23296
|
+
new InputFile(audioBuffer, fileName ?? "response.ogg")
|
|
23297
|
+
)
|
|
22912
23298
|
);
|
|
22913
23299
|
}
|
|
22914
23300
|
async sendFile(chatId, buffer, fileName) {
|
|
22915
|
-
await
|
|
22916
|
-
|
|
22917
|
-
|
|
23301
|
+
await withRetry(
|
|
23302
|
+
"sendFile",
|
|
23303
|
+
() => this.bot.api.sendDocument(
|
|
23304
|
+
numericChatId(chatId),
|
|
23305
|
+
new InputFile(buffer, fileName)
|
|
23306
|
+
)
|
|
22918
23307
|
);
|
|
22919
23308
|
}
|
|
22920
23309
|
async downloadFile(fileId) {
|
|
@@ -22927,7 +23316,10 @@ var init_telegram2 = __esm({
|
|
|
22927
23316
|
try {
|
|
22928
23317
|
const formatted = parseMode === "html" ? text : parseMode === "plain" ? text : formatForTelegram(text);
|
|
22929
23318
|
const opts = parseMode === "plain" ? {} : { parse_mode: "HTML" };
|
|
22930
|
-
const msg = await
|
|
23319
|
+
const msg = await withRetry(
|
|
23320
|
+
"sendTextReturningId",
|
|
23321
|
+
() => this.bot.api.sendMessage(numericChatId(chatId), formatted, opts)
|
|
23322
|
+
);
|
|
22931
23323
|
return msg.message_id.toString();
|
|
22932
23324
|
} catch {
|
|
22933
23325
|
return void 0;
|
|
@@ -22936,16 +23328,22 @@ var init_telegram2 = __esm({
|
|
|
22936
23328
|
async editText(chatId, messageId, text, parseMode) {
|
|
22937
23329
|
const formatted = parseMode === "html" ? text : formatForTelegram(text);
|
|
22938
23330
|
try {
|
|
22939
|
-
await
|
|
22940
|
-
|
|
22941
|
-
|
|
23331
|
+
await withRetry(
|
|
23332
|
+
"editText:html",
|
|
23333
|
+
() => this.bot.api.editMessageText(numericChatId(chatId), parseInt(messageId), formatted, {
|
|
23334
|
+
parse_mode: "HTML"
|
|
23335
|
+
})
|
|
23336
|
+
);
|
|
22942
23337
|
return true;
|
|
22943
23338
|
} catch {
|
|
22944
23339
|
try {
|
|
22945
|
-
await
|
|
22946
|
-
|
|
22947
|
-
|
|
22948
|
-
|
|
23340
|
+
await withRetry(
|
|
23341
|
+
"editText:fallback",
|
|
23342
|
+
() => this.bot.api.editMessageText(
|
|
23343
|
+
numericChatId(chatId),
|
|
23344
|
+
parseInt(messageId),
|
|
23345
|
+
formatted.replace(/<[^>]+>/g, "")
|
|
23346
|
+
)
|
|
22949
23347
|
);
|
|
22950
23348
|
return true;
|
|
22951
23349
|
} catch {
|
|
@@ -22975,16 +23373,22 @@ var init_telegram2 = __esm({
|
|
|
22975
23373
|
const MAX_KEYBOARD_TEXT = 4e3;
|
|
22976
23374
|
const safeText = text.length > MAX_KEYBOARD_TEXT ? text.slice(0, MAX_KEYBOARD_TEXT) + "\n\n\u2026(truncated)" : text;
|
|
22977
23375
|
try {
|
|
22978
|
-
const msg = await
|
|
22979
|
-
|
|
22980
|
-
|
|
23376
|
+
const msg = await withRetry(
|
|
23377
|
+
"sendKeyboard",
|
|
23378
|
+
() => this.bot.api.sendMessage(numericChatId(chatId), safeText, {
|
|
23379
|
+
reply_markup: keyboard
|
|
23380
|
+
})
|
|
23381
|
+
);
|
|
22981
23382
|
return msg.message_id.toString();
|
|
22982
23383
|
} catch (err) {
|
|
22983
23384
|
error(`[telegram] sendKeyboard failed (chat=${chatId}, textLen=${text.length}):`, err);
|
|
22984
23385
|
try {
|
|
22985
|
-
const fallbackMsg = await
|
|
22986
|
-
|
|
22987
|
-
|
|
23386
|
+
const fallbackMsg = await withRetry(
|
|
23387
|
+
"sendKeyboard:fallback",
|
|
23388
|
+
() => this.bot.api.sendMessage(numericChatId(chatId), "\u2B06\uFE0F (see above for details)", {
|
|
23389
|
+
reply_markup: keyboard
|
|
23390
|
+
})
|
|
23391
|
+
);
|
|
22988
23392
|
return fallbackMsg.message_id.toString();
|
|
22989
23393
|
} catch (fallbackErr) {
|
|
22990
23394
|
error(`[telegram] sendKeyboard fallback also failed:`, fallbackErr);
|
|
@@ -24333,7 +24737,7 @@ __export(service_exports, {
|
|
|
24333
24737
|
serviceStatus: () => serviceStatus,
|
|
24334
24738
|
uninstallService: () => uninstallService
|
|
24335
24739
|
});
|
|
24336
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as
|
|
24740
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync8 } from "fs";
|
|
24337
24741
|
import { execFileSync as execFileSync3, execSync as execSync6 } from "child_process";
|
|
24338
24742
|
import { homedir as homedir10, platform } from "os";
|
|
24339
24743
|
import { join as join30, dirname as dirname6 } from "path";
|
|
@@ -24442,7 +24846,7 @@ function uninstallMacOS() {
|
|
|
24442
24846
|
execFileSync3("launchctl", ["unload", PLIST_PATH]);
|
|
24443
24847
|
} catch {
|
|
24444
24848
|
}
|
|
24445
|
-
|
|
24849
|
+
unlinkSync8(PLIST_PATH);
|
|
24446
24850
|
console.log(" Service uninstalled.");
|
|
24447
24851
|
}
|
|
24448
24852
|
function formatUptime(seconds) {
|
|
@@ -24531,7 +24935,7 @@ function uninstallLinux() {
|
|
|
24531
24935
|
execFileSync3("systemctl", ["--user", "disable", "cc-claw"]);
|
|
24532
24936
|
} catch {
|
|
24533
24937
|
}
|
|
24534
|
-
|
|
24938
|
+
unlinkSync8(UNIT_PATH);
|
|
24535
24939
|
execFileSync3("systemctl", ["--user", "daemon-reload"]);
|
|
24536
24940
|
console.log(" Service uninstalled.");
|
|
24537
24941
|
}
|
|
@@ -25297,7 +25701,7 @@ __export(gemini_exports, {
|
|
|
25297
25701
|
});
|
|
25298
25702
|
import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync22, chmodSync } from "fs";
|
|
25299
25703
|
import { join as join31 } from "path";
|
|
25300
|
-
import { createInterface as
|
|
25704
|
+
import { createInterface as createInterface8 } from "readline";
|
|
25301
25705
|
function requireDb() {
|
|
25302
25706
|
if (!existsSync34(DB_PATH)) {
|
|
25303
25707
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
@@ -25370,7 +25774,7 @@ async function geminiList(globalOpts) {
|
|
|
25370
25774
|
}
|
|
25371
25775
|
async function geminiAddKey(globalOpts, opts) {
|
|
25372
25776
|
await requireWriteDb();
|
|
25373
|
-
const rl2 =
|
|
25777
|
+
const rl2 = createInterface8({ input: process.stdin, output: process.stdout });
|
|
25374
25778
|
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
25375
25779
|
const key = await ask2("Paste your Gemini API key: ");
|
|
25376
25780
|
rl2.close();
|
|
@@ -25562,7 +25966,7 @@ __export(backend_cmd_factory_exports, {
|
|
|
25562
25966
|
});
|
|
25563
25967
|
import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync23 } from "fs";
|
|
25564
25968
|
import { join as join32 } from "path";
|
|
25565
|
-
import { createInterface as
|
|
25969
|
+
import { createInterface as createInterface9 } from "readline";
|
|
25566
25970
|
function requireDb2() {
|
|
25567
25971
|
if (!existsSync35(DB_PATH)) {
|
|
25568
25972
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
@@ -25623,7 +26027,7 @@ Add one with: cc-claw ${backend2} add-account or cc-claw ${backend2} add-key`)
|
|
|
25623
26027
|
function makeAddKey(backend2, displayName) {
|
|
25624
26028
|
return async function addKey(_globalOpts, opts) {
|
|
25625
26029
|
await requireWriteDb2();
|
|
25626
|
-
const rl2 =
|
|
26030
|
+
const rl2 = createInterface9({ input: process.stdin, output: process.stdout });
|
|
25627
26031
|
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
25628
26032
|
const key = await ask2(`Paste your ${displayName} API key: `);
|
|
25629
26033
|
rl2.close();
|
|
@@ -27838,7 +28242,7 @@ var tui_exports = {};
|
|
|
27838
28242
|
__export(tui_exports, {
|
|
27839
28243
|
tuiCommand: () => tuiCommand
|
|
27840
28244
|
});
|
|
27841
|
-
import { createInterface as
|
|
28245
|
+
import { createInterface as createInterface10 } from "readline";
|
|
27842
28246
|
import pc2 from "picocolors";
|
|
27843
28247
|
async function tuiCommand(globalOpts, cmdOpts) {
|
|
27844
28248
|
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
@@ -27848,7 +28252,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
|
|
|
27848
28252
|
}
|
|
27849
28253
|
const chatId = resolveChatId(globalOpts);
|
|
27850
28254
|
const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat2(), chat_exports2));
|
|
27851
|
-
const rl2 =
|
|
28255
|
+
const rl2 = createInterface10({
|
|
27852
28256
|
input: process.stdin,
|
|
27853
28257
|
output: process.stdout,
|
|
27854
28258
|
prompt: pc2.cyan("you > "),
|
|
@@ -28649,7 +29053,7 @@ var init_optimize2 = __esm({
|
|
|
28649
29053
|
var setup_exports = {};
|
|
28650
29054
|
import { existsSync as existsSync55, writeFileSync as writeFileSync12, readFileSync as readFileSync26, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
|
|
28651
29055
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
28652
|
-
import { createInterface as
|
|
29056
|
+
import { createInterface as createInterface11 } from "readline";
|
|
28653
29057
|
import { join as join34 } from "path";
|
|
28654
29058
|
function divider2() {
|
|
28655
29059
|
console.log(dim("\u2500".repeat(55)));
|
|
@@ -29012,7 +29416,7 @@ var init_setup = __esm({
|
|
|
29012
29416
|
"src/setup.ts"() {
|
|
29013
29417
|
"use strict";
|
|
29014
29418
|
init_paths();
|
|
29015
|
-
rl =
|
|
29419
|
+
rl = createInterface11({ input: process.stdin, output: process.stdout });
|
|
29016
29420
|
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
29017
29421
|
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
29018
29422
|
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
package/package.json
CHANGED