cc-claw 0.3.3 → 0.3.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/README.md +1 -0
- package/dist/cli.js +235 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -124,6 +124,7 @@ Read commands work offline (direct DB access). Write commands require the daemon
|
|
|
124
124
|
| `/help` | All commands |
|
|
125
125
|
| `/status` | Backend, model, session, usage |
|
|
126
126
|
| `/newchat` | Start fresh (summarizes current session) |
|
|
127
|
+
| `/summarize` | Save session to memory without resetting |
|
|
127
128
|
| `/stop` | Cancel running task |
|
|
128
129
|
|
|
129
130
|
### Backend & Model
|
package/dist/cli.js
CHANGED
|
@@ -48,7 +48,7 @@ var VERSION;
|
|
|
48
48
|
var init_version = __esm({
|
|
49
49
|
"src/version.ts"() {
|
|
50
50
|
"use strict";
|
|
51
|
-
VERSION = true ? "0.3.
|
|
51
|
+
VERSION = true ? "0.3.4" : (() => {
|
|
52
52
|
try {
|
|
53
53
|
return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
54
54
|
} catch {
|
|
@@ -1143,6 +1143,7 @@ function initDatabase() {
|
|
|
1143
1143
|
backend TEXT,
|
|
1144
1144
|
model TEXT,
|
|
1145
1145
|
thinking TEXT,
|
|
1146
|
+
timeout INTEGER,
|
|
1146
1147
|
session_type TEXT NOT NULL DEFAULT 'isolated',
|
|
1147
1148
|
channel TEXT,
|
|
1148
1149
|
target TEXT,
|
|
@@ -1177,6 +1178,7 @@ function initDatabase() {
|
|
|
1177
1178
|
backend TEXT,
|
|
1178
1179
|
model TEXT,
|
|
1179
1180
|
thinking TEXT,
|
|
1181
|
+
timeout INTEGER,
|
|
1180
1182
|
session_type TEXT NOT NULL DEFAULT 'isolated',
|
|
1181
1183
|
channel TEXT,
|
|
1182
1184
|
target TEXT,
|
|
@@ -1257,6 +1259,10 @@ function initDatabase() {
|
|
|
1257
1259
|
db.exec("ALTER TABLE jobs ADD COLUMN consecutive_failures INTEGER NOT NULL DEFAULT 0");
|
|
1258
1260
|
} catch {
|
|
1259
1261
|
}
|
|
1262
|
+
try {
|
|
1263
|
+
db.exec("ALTER TABLE jobs ADD COLUMN timeout INTEGER");
|
|
1264
|
+
} catch {
|
|
1265
|
+
}
|
|
1260
1266
|
}
|
|
1261
1267
|
} catch {
|
|
1262
1268
|
}
|
|
@@ -1949,8 +1955,8 @@ function getBackendUsageInWindow(backend2, windowType) {
|
|
|
1949
1955
|
function insertJob(params) {
|
|
1950
1956
|
const result = db.prepare(`
|
|
1951
1957
|
INSERT INTO jobs (schedule_type, cron, at_time, every_ms, description, chat_id,
|
|
1952
|
-
backend, model, thinking, session_type, channel, target, delivery_mode, timezone)
|
|
1953
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1958
|
+
backend, model, thinking, timeout, session_type, channel, target, delivery_mode, timezone)
|
|
1959
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1954
1960
|
`).run(
|
|
1955
1961
|
params.scheduleType,
|
|
1956
1962
|
params.cron ?? null,
|
|
@@ -1961,6 +1967,7 @@ function insertJob(params) {
|
|
|
1961
1967
|
params.backend ?? null,
|
|
1962
1968
|
params.model ?? null,
|
|
1963
1969
|
params.thinking ?? null,
|
|
1970
|
+
params.timeout ?? null,
|
|
1964
1971
|
params.sessionType ?? "isolated",
|
|
1965
1972
|
params.channel ?? null,
|
|
1966
1973
|
params.target ?? null,
|
|
@@ -2012,6 +2019,7 @@ function updateJob(id, fields) {
|
|
|
2012
2019
|
backend: "backend",
|
|
2013
2020
|
model: "model",
|
|
2014
2021
|
thinking: "thinking",
|
|
2022
|
+
timeout: "timeout",
|
|
2015
2023
|
sessionType: "session_type",
|
|
2016
2024
|
channel: "channel",
|
|
2017
2025
|
target: "target",
|
|
@@ -2275,7 +2283,7 @@ var init_store4 = __esm({
|
|
|
2275
2283
|
ALL_TOOLS = ["Read", "Glob", "Grep", "Bash", "Write", "Edit", "WebFetch", "WebSearch", "Agent", "AskUserQuestion"];
|
|
2276
2284
|
JOB_SELECT = `
|
|
2277
2285
|
SELECT id, schedule_type as scheduleType, cron, at_time as atTime, every_ms as everyMs,
|
|
2278
|
-
description, chat_id as chatId, backend, model, thinking,
|
|
2286
|
+
description, chat_id as chatId, backend, model, thinking, timeout,
|
|
2279
2287
|
session_type as sessionType, channel, target, delivery_mode as deliveryMode,
|
|
2280
2288
|
timezone, enabled, active, created_at as createdAt, last_run_at as lastRunAt,
|
|
2281
2289
|
next_run_at as nextRunAt, consecutive_failures as consecutiveFailures
|
|
@@ -5230,9 +5238,14 @@ data: ${JSON.stringify(data)}
|
|
|
5230
5238
|
`);
|
|
5231
5239
|
};
|
|
5232
5240
|
try {
|
|
5233
|
-
const response = await askAgent2(chatId, body.message,
|
|
5234
|
-
|
|
5235
|
-
|
|
5241
|
+
const response = await askAgent2(chatId, body.message, {
|
|
5242
|
+
cwd,
|
|
5243
|
+
onStream: (partial) => {
|
|
5244
|
+
sendSSE("text", partial);
|
|
5245
|
+
},
|
|
5246
|
+
model: model2,
|
|
5247
|
+
permMode: mode
|
|
5248
|
+
});
|
|
5236
5249
|
if (response.usage) addUsage2(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2 ?? "unknown");
|
|
5237
5250
|
sendSSE("done", JSON.stringify({ text: response.text, usage: response.usage }));
|
|
5238
5251
|
res.end();
|
|
@@ -5241,7 +5254,7 @@ data: ${JSON.stringify(data)}
|
|
|
5241
5254
|
res.end();
|
|
5242
5255
|
}
|
|
5243
5256
|
} else {
|
|
5244
|
-
const response = await askAgent2(chatId, body.message, cwd,
|
|
5257
|
+
const response = await askAgent2(chatId, body.message, { cwd, model: model2, permMode: mode });
|
|
5245
5258
|
if (response.usage) addUsage2(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2 ?? "unknown");
|
|
5246
5259
|
return jsonResponse(res, { text: response.text, usage: response.usage, sessionId: response.sessionId });
|
|
5247
5260
|
}
|
|
@@ -5696,24 +5709,32 @@ function stopAgent(chatId) {
|
|
|
5696
5709
|
function isAgentActive(chatId) {
|
|
5697
5710
|
return activeChats.has(chatId);
|
|
5698
5711
|
}
|
|
5699
|
-
function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolAction, thinkingLevel) {
|
|
5712
|
+
function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolAction, thinkingLevel, timeoutMs) {
|
|
5713
|
+
const effectiveTimeout = timeoutMs ?? SPAWN_TIMEOUT_MS;
|
|
5700
5714
|
return new Promise((resolve, reject) => {
|
|
5701
5715
|
const thinkingConfig = thinkingLevel && thinkingLevel !== "auto" ? adapter.applyThinkingConfig(thinkingLevel, model2) : void 0;
|
|
5702
5716
|
const env = adapter.getEnv(thinkingConfig?.envOverrides);
|
|
5703
5717
|
const finalArgs = thinkingConfig?.extraArgs ? [...config2.args, ...thinkingConfig.extraArgs] : config2.args;
|
|
5704
|
-
log(`[agent:spawn] backend=${adapter.id} exe=${config2.executable} model=${model2} cwd=${config2.cwd ?? "(inherited)"}`);
|
|
5718
|
+
log(`[agent:spawn] backend=${adapter.id} exe=${config2.executable} model=${model2} timeout=${effectiveTimeout / 1e3}s cwd=${config2.cwd ?? "(inherited)"}`);
|
|
5705
5719
|
const proc = spawn4(config2.executable, finalArgs, {
|
|
5706
5720
|
env,
|
|
5707
5721
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5708
5722
|
...config2.cwd ? { cwd: config2.cwd } : {}
|
|
5709
5723
|
});
|
|
5710
5724
|
cancelState.process = proc;
|
|
5725
|
+
let timedOut = false;
|
|
5726
|
+
let sigkillTimer;
|
|
5711
5727
|
const spawnTimeout = setTimeout(() => {
|
|
5712
|
-
|
|
5713
|
-
|
|
5728
|
+
timedOut = true;
|
|
5729
|
+
warn(`[agent] Spawn timeout after ${effectiveTimeout / 1e3}s for ${adapter.id} \u2014 killing process`);
|
|
5714
5730
|
proc.kill("SIGTERM");
|
|
5715
|
-
setTimeout(() =>
|
|
5716
|
-
|
|
5731
|
+
sigkillTimer = setTimeout(() => {
|
|
5732
|
+
try {
|
|
5733
|
+
proc.kill("SIGKILL");
|
|
5734
|
+
} catch {
|
|
5735
|
+
}
|
|
5736
|
+
}, 3e3);
|
|
5737
|
+
}, effectiveTimeout);
|
|
5717
5738
|
let resultText = "";
|
|
5718
5739
|
let accumulatedText = "";
|
|
5719
5740
|
let sessionId;
|
|
@@ -5808,12 +5829,17 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
5808
5829
|
});
|
|
5809
5830
|
proc.on("error", (err) => {
|
|
5810
5831
|
clearTimeout(spawnTimeout);
|
|
5832
|
+
if (sigkillTimer) clearTimeout(sigkillTimer);
|
|
5811
5833
|
rl2.close();
|
|
5812
5834
|
cancelState.process = void 0;
|
|
5813
5835
|
reject(err);
|
|
5814
5836
|
});
|
|
5815
5837
|
proc.on("close", (code, signal) => {
|
|
5816
5838
|
clearTimeout(spawnTimeout);
|
|
5839
|
+
if (sigkillTimer) {
|
|
5840
|
+
clearTimeout(sigkillTimer);
|
|
5841
|
+
sigkillTimer = void 0;
|
|
5842
|
+
}
|
|
5817
5843
|
if (cancelState.killTimer) {
|
|
5818
5844
|
clearTimeout(cancelState.killTimer);
|
|
5819
5845
|
cancelState.killTimer = void 0;
|
|
@@ -5823,6 +5849,10 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
5823
5849
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
5824
5850
|
if (stderr) warn(`[agent] stderr: ${stderr.slice(0, 500)}`);
|
|
5825
5851
|
}
|
|
5852
|
+
if (timedOut) {
|
|
5853
|
+
reject(new Error(`Spawn timeout after ${effectiveTimeout / 1e3}s`));
|
|
5854
|
+
return;
|
|
5855
|
+
}
|
|
5826
5856
|
if (code && code !== 0 && !cancelState.cancelled && !resultText) {
|
|
5827
5857
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
5828
5858
|
reject(new Error(`CLI exited with code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`));
|
|
@@ -5832,10 +5862,11 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
5832
5862
|
});
|
|
5833
5863
|
});
|
|
5834
5864
|
}
|
|
5835
|
-
function askAgent(chatId, userMessage,
|
|
5836
|
-
return withChatLock(chatId, () => askAgentImpl(chatId, userMessage,
|
|
5865
|
+
function askAgent(chatId, userMessage, opts) {
|
|
5866
|
+
return withChatLock(chatId, () => askAgentImpl(chatId, userMessage, opts));
|
|
5837
5867
|
}
|
|
5838
|
-
async function askAgentImpl(chatId, userMessage,
|
|
5868
|
+
async function askAgentImpl(chatId, userMessage, opts) {
|
|
5869
|
+
const { cwd, onStream, model: model2, permMode, onToolAction, bootstrapTier, timeoutMs } = opts ?? {};
|
|
5839
5870
|
const adapter = getAdapterForChat(chatId);
|
|
5840
5871
|
const mode = permMode ?? "yolo";
|
|
5841
5872
|
const thinkingLevel = getThinkingLevel(chatId);
|
|
@@ -5876,13 +5907,13 @@ async function askAgentImpl(chatId, userMessage, cwd, onStream, model2, permMode
|
|
|
5876
5907
|
const resolvedModel = model2 ?? adapter.defaultModel;
|
|
5877
5908
|
let result = { resultText: "", sessionId: void 0, input: 0, output: 0, cacheRead: 0, sawToolEvents: false, sawResultEvent: false };
|
|
5878
5909
|
try {
|
|
5879
|
-
result = await spawnQuery(adapter, configWithSession, resolvedModel, cancelState, onStream, onToolAction, thinkingLevel);
|
|
5910
|
+
result = await spawnQuery(adapter, configWithSession, resolvedModel, cancelState, onStream, onToolAction, thinkingLevel, timeoutMs);
|
|
5880
5911
|
const wasEmptyResponse = !result.resultText && !result.sawToolEvents && !result.sawResultEvent;
|
|
5881
5912
|
if (wasEmptyResponse && !cancelState.cancelled && existingSessionId) {
|
|
5882
5913
|
warn(`[agent] No result with session ${existingSessionId} for chat ${chatId} \u2014 retrying fresh`);
|
|
5883
5914
|
await summarizeSession(chatId);
|
|
5884
5915
|
clearSession(chatId);
|
|
5885
|
-
result = await spawnQuery(adapter, baseConfig, resolvedModel, cancelState, onStream, onToolAction, thinkingLevel);
|
|
5916
|
+
result = await spawnQuery(adapter, baseConfig, resolvedModel, cancelState, onStream, onToolAction, thinkingLevel, timeoutMs);
|
|
5886
5917
|
}
|
|
5887
5918
|
} finally {
|
|
5888
5919
|
activeChats.delete(chatId);
|
|
@@ -6429,7 +6460,8 @@ async function runWithRetry(job, model2, runId, t0) {
|
|
|
6429
6460
|
}
|
|
6430
6461
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
6431
6462
|
try {
|
|
6432
|
-
const
|
|
6463
|
+
const timeoutMs = job.timeout ? job.timeout * 1e3 : void 0;
|
|
6464
|
+
const response = await askAgent(chatId, job.description, { model: model2, bootstrapTier: "slim", timeoutMs });
|
|
6433
6465
|
return response;
|
|
6434
6466
|
} catch (err) {
|
|
6435
6467
|
lastError = err;
|
|
@@ -7069,6 +7101,7 @@ var init_telegram2 = __esm({
|
|
|
7069
7101
|
{ command: "help", description: "Show available commands" },
|
|
7070
7102
|
{ command: "status", description: "Session, backend, model, and usage" },
|
|
7071
7103
|
{ command: "newchat", description: "Start a fresh conversation" },
|
|
7104
|
+
{ command: "summarize", description: "Save session to memory (or 'all' for pre-restart)" },
|
|
7072
7105
|
{ command: "stop", description: "Cancel the current running task" },
|
|
7073
7106
|
// Backend & model
|
|
7074
7107
|
{ command: "backend", description: "Switch AI backend (Claude/Gemini/Codex)" },
|
|
@@ -7856,7 +7889,7 @@ async function runHeartbeat(chatId, config2) {
|
|
|
7856
7889
|
cleanExpiredWatches();
|
|
7857
7890
|
const prompt = assembleHeartbeatPrompt(chatId);
|
|
7858
7891
|
try {
|
|
7859
|
-
const response = await askAgent(chatId, prompt,
|
|
7892
|
+
const response = await askAgent(chatId, prompt, { bootstrapTier: "heartbeat" });
|
|
7860
7893
|
if (response.usage) {
|
|
7861
7894
|
let heartbeatModel;
|
|
7862
7895
|
try {
|
|
@@ -7988,6 +8021,52 @@ var init_heartbeat = __esm({
|
|
|
7988
8021
|
}
|
|
7989
8022
|
});
|
|
7990
8023
|
|
|
8024
|
+
// src/format-time.ts
|
|
8025
|
+
function formatLocalDate(utcDatetime) {
|
|
8026
|
+
const d = parseUtcDatetime(utcDatetime);
|
|
8027
|
+
if (!d) return utcDatetime.split("T")[0] ?? utcDatetime.split(" ")[0];
|
|
8028
|
+
const year = d.getFullYear();
|
|
8029
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
8030
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
8031
|
+
return `${year}-${month}-${day}`;
|
|
8032
|
+
}
|
|
8033
|
+
function formatLocalDateTime(utcDatetime) {
|
|
8034
|
+
const d = parseUtcDatetime(utcDatetime);
|
|
8035
|
+
if (!d) return utcDatetime;
|
|
8036
|
+
const year = d.getFullYear();
|
|
8037
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
8038
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
8039
|
+
const hours = String(d.getHours()).padStart(2, "0");
|
|
8040
|
+
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
8041
|
+
const tzAbbr = getTimezoneAbbr(d);
|
|
8042
|
+
return `${year}-${month}-${day} ${hours}:${minutes} ${tzAbbr}`;
|
|
8043
|
+
}
|
|
8044
|
+
function parseUtcDatetime(utcDatetime) {
|
|
8045
|
+
if (!utcDatetime) return null;
|
|
8046
|
+
const normalized = utcDatetime.includes("T") ? utcDatetime : utcDatetime.replace(" ", "T");
|
|
8047
|
+
const withZ = normalized.endsWith("Z") ? normalized : normalized + "Z";
|
|
8048
|
+
const d = new Date(withZ);
|
|
8049
|
+
return isNaN(d.getTime()) ? null : d;
|
|
8050
|
+
}
|
|
8051
|
+
function getTimezoneAbbr(date) {
|
|
8052
|
+
try {
|
|
8053
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
8054
|
+
timeZone: systemTimezone,
|
|
8055
|
+
timeZoneName: "short"
|
|
8056
|
+
}).formatToParts(date);
|
|
8057
|
+
return parts.find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
8058
|
+
} catch {
|
|
8059
|
+
return "";
|
|
8060
|
+
}
|
|
8061
|
+
}
|
|
8062
|
+
var systemTimezone;
|
|
8063
|
+
var init_format_time = __esm({
|
|
8064
|
+
"src/format-time.ts"() {
|
|
8065
|
+
"use strict";
|
|
8066
|
+
systemTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
8067
|
+
}
|
|
8068
|
+
});
|
|
8069
|
+
|
|
7991
8070
|
// src/voice/stt.ts
|
|
7992
8071
|
import crypto from "crypto";
|
|
7993
8072
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -8092,10 +8171,13 @@ var init_stt = __esm({
|
|
|
8092
8171
|
});
|
|
8093
8172
|
|
|
8094
8173
|
// src/scheduler/types.ts
|
|
8095
|
-
var COMMON_TIMEZONES;
|
|
8174
|
+
var TIMEOUT_MIN_SECONDS, TIMEOUT_MAX_SECONDS, TIMEOUT_DEFAULT_SECONDS, COMMON_TIMEZONES;
|
|
8096
8175
|
var init_types2 = __esm({
|
|
8097
8176
|
"src/scheduler/types.ts"() {
|
|
8098
8177
|
"use strict";
|
|
8178
|
+
TIMEOUT_MIN_SECONDS = 30;
|
|
8179
|
+
TIMEOUT_MAX_SECONDS = 3600;
|
|
8180
|
+
TIMEOUT_DEFAULT_SECONDS = 600;
|
|
8099
8181
|
COMMON_TIMEZONES = {
|
|
8100
8182
|
"US/Eastern": "America/New_York",
|
|
8101
8183
|
"US/Central": "America/Chicago",
|
|
@@ -8311,8 +8393,23 @@ async function handleWizardText(chatId, text, channel) {
|
|
|
8311
8393
|
case "thinking": {
|
|
8312
8394
|
const level = text.trim().toLowerCase();
|
|
8313
8395
|
pending.thinking = level || "auto";
|
|
8314
|
-
pending.step = "
|
|
8315
|
-
await
|
|
8396
|
+
pending.step = "timeout";
|
|
8397
|
+
await promptTimeout(chatId, channel);
|
|
8398
|
+
break;
|
|
8399
|
+
}
|
|
8400
|
+
case "timeout": {
|
|
8401
|
+
const val = parseInt(text.trim(), 10);
|
|
8402
|
+
if (text.trim().toLowerCase() === "default") {
|
|
8403
|
+
pending.timeout = void 0;
|
|
8404
|
+
pending.step = "session";
|
|
8405
|
+
await promptSession(chatId, channel);
|
|
8406
|
+
} else if (isNaN(val) || val < TIMEOUT_MIN_SECONDS || val > TIMEOUT_MAX_SECONDS) {
|
|
8407
|
+
await channel.sendText(chatId, `Invalid timeout. Enter a value between ${TIMEOUT_MIN_SECONDS} and ${TIMEOUT_MAX_SECONDS} seconds, or "default" for ${TIMEOUT_DEFAULT_SECONDS}s.`, "plain");
|
|
8408
|
+
} else {
|
|
8409
|
+
pending.timeout = val;
|
|
8410
|
+
pending.step = "session";
|
|
8411
|
+
await promptSession(chatId, channel);
|
|
8412
|
+
}
|
|
8316
8413
|
break;
|
|
8317
8414
|
}
|
|
8318
8415
|
case "session": {
|
|
@@ -8390,7 +8487,18 @@ async function handleWizardCallback(chatId, data, channel) {
|
|
|
8390
8487
|
await promptThinking(chatId, channel);
|
|
8391
8488
|
} else if (data.startsWith("sched:thinking:")) {
|
|
8392
8489
|
pending.thinking = data.slice(15);
|
|
8490
|
+
pending.step = "timeout";
|
|
8491
|
+
await promptTimeout(chatId, channel);
|
|
8492
|
+
} else if (data.startsWith("sched:timeout:")) {
|
|
8493
|
+
const val = data.slice(14);
|
|
8494
|
+
if (val === "default") {
|
|
8495
|
+
pending.timeout = void 0;
|
|
8496
|
+
} else {
|
|
8497
|
+
pending.timeout = parseInt(val, 10);
|
|
8498
|
+
}
|
|
8393
8499
|
pending.step = "session";
|
|
8500
|
+
const label2 = pending.timeout ? `${pending.timeout}s (${Math.round(pending.timeout / 60)} min)` : `Default (${TIMEOUT_DEFAULT_SECONDS}s)`;
|
|
8501
|
+
await channel.sendText(chatId, `Timeout: ${label2}`, "plain");
|
|
8394
8502
|
await promptSession(chatId, channel);
|
|
8395
8503
|
} else if (data.startsWith("sched:session:")) {
|
|
8396
8504
|
pending.sessionType = data.slice(14);
|
|
@@ -8484,10 +8592,27 @@ async function promptThinking(chatId, channel) {
|
|
|
8484
8592
|
await channel.sendKeyboard(chatId, "Thinking/effort level for this job?", buttons);
|
|
8485
8593
|
} else {
|
|
8486
8594
|
pending.thinking = "auto";
|
|
8487
|
-
pending.step = "
|
|
8488
|
-
await
|
|
8595
|
+
pending.step = "timeout";
|
|
8596
|
+
await promptTimeout(chatId, channel);
|
|
8489
8597
|
}
|
|
8490
8598
|
}
|
|
8599
|
+
async function promptTimeout(chatId, channel) {
|
|
8600
|
+
if (typeof channel.sendKeyboard !== "function") {
|
|
8601
|
+
await channel.sendText(chatId, `Job timeout in seconds (${TIMEOUT_MIN_SECONDS}-${TIMEOUT_MAX_SECONDS}), or "default" for ${TIMEOUT_DEFAULT_SECONDS}s:`, "plain");
|
|
8602
|
+
return;
|
|
8603
|
+
}
|
|
8604
|
+
await channel.sendKeyboard(chatId, "Maximum runtime for this job?", [
|
|
8605
|
+
[
|
|
8606
|
+
{ label: `5 min (300s)`, data: "sched:timeout:300" },
|
|
8607
|
+
{ label: `10 min (600s)`, data: "sched:timeout:600" }
|
|
8608
|
+
],
|
|
8609
|
+
[
|
|
8610
|
+
{ label: `15 min (900s)`, data: "sched:timeout:900" },
|
|
8611
|
+
{ label: `30 min (1800s)`, data: "sched:timeout:1800" }
|
|
8612
|
+
],
|
|
8613
|
+
[{ label: `Default (${TIMEOUT_DEFAULT_SECONDS}s)`, data: "sched:timeout:default" }]
|
|
8614
|
+
]);
|
|
8615
|
+
}
|
|
8491
8616
|
async function promptSession(chatId, channel) {
|
|
8492
8617
|
if (typeof channel.sendKeyboard !== "function") {
|
|
8493
8618
|
await channel.sendText(chatId, "Session type: isolated (fresh, no history) or main (uses conversation context)?", "plain");
|
|
@@ -8523,6 +8648,7 @@ async function promptConfirm(chatId, channel) {
|
|
|
8523
8648
|
const pending = pendingJobs.get(chatId);
|
|
8524
8649
|
if (!pending) return;
|
|
8525
8650
|
const backendName = pending.backend ? getAdapter(pending.backend).displayName : "default";
|
|
8651
|
+
const timeoutLabel = pending.timeout ? `${pending.timeout}s (${Math.round(pending.timeout / 60)} min)` : `Default (${TIMEOUT_DEFAULT_SECONDS}s)`;
|
|
8526
8652
|
const lines = [
|
|
8527
8653
|
"Job configuration:",
|
|
8528
8654
|
"",
|
|
@@ -8532,6 +8658,7 @@ async function promptConfirm(chatId, channel) {
|
|
|
8532
8658
|
` Backend: ${backendName}`,
|
|
8533
8659
|
` Model: ${pending.model ?? "default"}`,
|
|
8534
8660
|
` Thinking: ${pending.thinking ?? "auto"}`,
|
|
8661
|
+
` Timeout: ${timeoutLabel}`,
|
|
8535
8662
|
` Session: ${pending.sessionType ?? "isolated"}`,
|
|
8536
8663
|
` Delivery: ${pending.deliveryMode ?? "announce"}`
|
|
8537
8664
|
];
|
|
@@ -8562,6 +8689,7 @@ async function finalizeJob(chatId, channel) {
|
|
|
8562
8689
|
backend: pending.backend ?? null,
|
|
8563
8690
|
model: pending.model ?? null,
|
|
8564
8691
|
thinking: pending.thinking ?? null,
|
|
8692
|
+
timeout: pending.timeout ?? null,
|
|
8565
8693
|
sessionType: pending.sessionType ?? "isolated",
|
|
8566
8694
|
channel: pending.channel ?? null,
|
|
8567
8695
|
target: pending.target ?? null,
|
|
@@ -8622,6 +8750,7 @@ async function startEditWizard(chatId, jobId, channel) {
|
|
|
8622
8750
|
backend: job.backend,
|
|
8623
8751
|
model: job.model ?? void 0,
|
|
8624
8752
|
thinking: job.thinking ?? void 0,
|
|
8753
|
+
timeout: job.timeout ?? void 0,
|
|
8625
8754
|
sessionType: job.sessionType,
|
|
8626
8755
|
deliveryMode: job.deliveryMode,
|
|
8627
8756
|
channel: job.channel ?? void 0,
|
|
@@ -9006,7 +9135,7 @@ async function handleCommand(msg, channel) {
|
|
|
9006
9135
|
case "help":
|
|
9007
9136
|
await channel.sendText(
|
|
9008
9137
|
chatId,
|
|
9009
|
-
"Hey! I'm CC-Claw \u2014 your personal AI assistant on Telegram.\n\nI use AI coding CLIs (Claude, Gemini, Codex) as my brain. Just send me a message to get started.\n\nCommands:\n/backend [name] - Switch AI backend (or /claude /gemini /codex)\n/model - Switch model for active backend\n/summarizer - Configure session summarization model\n/status - Show session, model, backend, and usage\n/cost - Show estimated API cost (use /cost all for all-time)\n/usage - Show usage per backend with limits\n/limits - Configure usage limits per backend\n/newchat - Start a fresh conversation\n/cwd <path> - Set working directory\n/cwd - Show current working directory\n/memory - List stored memories\n/forget <keyword> - Remove a memory\n/voice - Toggle voice responses\n/cron <description> - Schedule a task (or /schedule)\n/cron - List scheduled jobs (or /jobs)\n/cron cancel <id> - Cancel a job\n/cron pause <id> - Pause a job\n/cron resume <id> - Resume a job\n/cron run <id> - Trigger a job now\n/cron runs [id] - View run history\n/cron edit <id> - Edit a job\n/cron health - Scheduler health\n/skills - List skills from all backends\n/skill-install <url> - Install a skill from GitHub\n/setup-profile - Set up your user profile\n/chats - List authorized chats and aliases\n/heartbeat - Proactive awareness (on/off/interval/hours)\n/history - List recent session summaries\n/stop - Cancel the current running task\n/tools - Configure which tools the agent can use\n/permissions - Switch permission mode (yolo/safe/readonly/plan)\n/verbose - Tool visibility (off/normal/verbose)\n/agents - List active sub-agents\n/tasks - Show task board for current orchestration\n/stopagent <id> - Cancel a specific sub-agent\n/stopall - Cancel all sub-agents in this chat\n/runners - List registered CLI runners\n/mcps - List registered MCP servers\n/help - Show this message",
|
|
9138
|
+
"Hey! I'm CC-Claw \u2014 your personal AI assistant on Telegram.\n\nI use AI coding CLIs (Claude, Gemini, Codex) as my brain. Just send me a message to get started.\n\nCommands:\n/backend [name] - Switch AI backend (or /claude /gemini /codex)\n/model - Switch model for active backend\n/summarizer - Configure session summarization model\n/status - Show session, model, backend, and usage\n/cost - Show estimated API cost (use /cost all for all-time)\n/usage - Show usage per backend with limits\n/limits - Configure usage limits per backend\n/newchat - Start a fresh conversation\n/summarize - Save session to memory (without resetting)\n/summarize all - Summarize all pending sessions (pre-restart)\n/cwd <path> - Set working directory\n/cwd - Show current working directory\n/memory - List stored memories\n/forget <keyword> - Remove a memory\n/voice - Toggle voice responses\n/cron <description> - Schedule a task (or /schedule)\n/cron - List scheduled jobs (or /jobs)\n/cron cancel <id> - Cancel a job\n/cron pause <id> - Pause a job\n/cron resume <id> - Resume a job\n/cron run <id> - Trigger a job now\n/cron runs [id] - View run history\n/cron edit <id> - Edit a job\n/cron health - Scheduler health\n/skills - List skills from all backends\n/skill-install <url> - Install a skill from GitHub\n/setup-profile - Set up your user profile\n/chats - List authorized chats and aliases\n/heartbeat - Proactive awareness (on/off/interval/hours)\n/history - List recent session summaries\n/stop - Cancel the current running task\n/tools - Configure which tools the agent can use\n/permissions - Switch permission mode (yolo/safe/readonly/plan)\n/verbose - Tool visibility (off/normal/verbose)\n/agents - List active sub-agents\n/tasks - Show task board for current orchestration\n/stopagent <id> - Cancel a specific sub-agent\n/stopall - Cancel all sub-agents in this chat\n/runners - List registered CLI runners\n/mcps - List registered MCP servers\n/help - Show this message",
|
|
9010
9139
|
"plain"
|
|
9011
9140
|
);
|
|
9012
9141
|
break;
|
|
@@ -9088,6 +9217,32 @@ Tap to toggle:`,
|
|
|
9088
9217
|
await channel.sendText(chatId, msg2, "plain");
|
|
9089
9218
|
break;
|
|
9090
9219
|
}
|
|
9220
|
+
case "summarize": {
|
|
9221
|
+
if (commandArgs?.toLowerCase() === "all") {
|
|
9222
|
+
const pendingIds = getLoggedChatIds();
|
|
9223
|
+
if (pendingIds.length === 0) {
|
|
9224
|
+
await channel.sendText(chatId, "No pending sessions to summarize.", "plain");
|
|
9225
|
+
break;
|
|
9226
|
+
}
|
|
9227
|
+
await channel.sendText(chatId, `Summarizing ${pendingIds.length} pending session(s)...`, "plain");
|
|
9228
|
+
await summarizeAllPending();
|
|
9229
|
+
await channel.sendText(chatId, `Done. ${pendingIds.length} session(s) summarized and saved to memory.`, "plain");
|
|
9230
|
+
} else {
|
|
9231
|
+
const pairs = getMessagePairCount(chatId);
|
|
9232
|
+
if (pairs < 2) {
|
|
9233
|
+
await channel.sendText(chatId, "Not enough conversation to summarize (need at least 2 exchanges). Session log is preserved.", "plain");
|
|
9234
|
+
break;
|
|
9235
|
+
}
|
|
9236
|
+
await channel.sendText(chatId, `Summarizing current session (${pairs} exchanges)...`, "plain");
|
|
9237
|
+
const success2 = await summarizeSession(chatId);
|
|
9238
|
+
if (success2) {
|
|
9239
|
+
await channel.sendText(chatId, "Session summarized and saved to memory. Session continues (use /newchat to also reset).", "plain");
|
|
9240
|
+
} else {
|
|
9241
|
+
await channel.sendText(chatId, "Summarization failed. Session log preserved for retry.", "plain");
|
|
9242
|
+
}
|
|
9243
|
+
}
|
|
9244
|
+
break;
|
|
9245
|
+
}
|
|
9091
9246
|
case "status": {
|
|
9092
9247
|
const sessionId = getSessionId(chatId);
|
|
9093
9248
|
const cwd = getCwd(chatId);
|
|
@@ -9564,7 +9719,7 @@ ${lines.join("\n")}`, "plain");
|
|
|
9564
9719
|
Error: ${r.error.slice(0, 100)}` : "";
|
|
9565
9720
|
const usage2 = r.usageInput ? `
|
|
9566
9721
|
Tokens: ${r.usageInput}in / ${r.usageOutput}out` : "";
|
|
9567
|
-
return `#${r.jobId} [${r.status}] ${r.startedAt}${duration}${error3}${usage2}`;
|
|
9722
|
+
return `#${r.jobId} [${r.status}] ${formatLocalDateTime(r.startedAt)}${duration}${error3}${usage2}`;
|
|
9568
9723
|
});
|
|
9569
9724
|
await channel.sendText(chatId, lines.join("\n\n"), "plain");
|
|
9570
9725
|
break;
|
|
@@ -9591,7 +9746,7 @@ ${lines.join("\n")}`, "plain");
|
|
|
9591
9746
|
return;
|
|
9592
9747
|
}
|
|
9593
9748
|
const lines = summaries.map((s) => {
|
|
9594
|
-
const date =
|
|
9749
|
+
const date = formatLocalDate(s.created_at);
|
|
9595
9750
|
const shortSummary = s.summary.length > 200 ? s.summary.slice(0, 200) + "\u2026" : s.summary;
|
|
9596
9751
|
return `${date} (${s.message_count} msgs)
|
|
9597
9752
|
${shortSummary}
|
|
@@ -10047,7 +10202,7 @@ Use /skills to see it.`, "plain");
|
|
|
10047
10202
|
}
|
|
10048
10203
|
const runLines = cronRuns2.map((r) => {
|
|
10049
10204
|
const dur = r.durationMs ? ` (${(r.durationMs / 1e3).toFixed(1)}s)` : "";
|
|
10050
|
-
return `#${r.jobId} [${r.status}] ${r.startedAt}${dur}`;
|
|
10205
|
+
return `#${r.jobId} [${r.status}] ${formatLocalDateTime(r.startedAt)}${dur}`;
|
|
10051
10206
|
});
|
|
10052
10207
|
await channel.sendText(chatId, runLines.join("\n\n"), "plain");
|
|
10053
10208
|
break;
|
|
@@ -10096,7 +10251,7 @@ async function handleVoice(msg, channel) {
|
|
|
10096
10251
|
const vModel = resolveModel(chatId);
|
|
10097
10252
|
const vVerbose = getVerboseLevel(chatId);
|
|
10098
10253
|
const vToolCb = vVerbose !== "off" ? makeToolActionCallback(chatId, channel, vVerbose) : void 0;
|
|
10099
|
-
const response = await askAgent(chatId, transcript, getCwd(chatId),
|
|
10254
|
+
const response = await askAgent(chatId, transcript, { cwd: getCwd(chatId), model: vModel, permMode: mode, onToolAction: vToolCb });
|
|
10100
10255
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, vModel);
|
|
10101
10256
|
await sendResponse(chatId, channel, response.text);
|
|
10102
10257
|
} catch (err) {
|
|
@@ -10143,7 +10298,7 @@ Summarize this for the user.`;
|
|
|
10143
10298
|
const vMode = getMode(chatId);
|
|
10144
10299
|
const vidVerbose = getVerboseLevel(chatId);
|
|
10145
10300
|
const vidToolCb = vidVerbose !== "off" ? makeToolActionCallback(chatId, channel, vidVerbose) : void 0;
|
|
10146
|
-
const response2 = await askAgent(chatId, prompt2, getCwd(chatId),
|
|
10301
|
+
const response2 = await askAgent(chatId, prompt2, { cwd: getCwd(chatId), model: vidModel, permMode: vMode, onToolAction: vidToolCb });
|
|
10147
10302
|
if (response2.usage) addUsage(chatId, response2.usage.input, response2.usage.output, response2.usage.cacheRead, vidModel);
|
|
10148
10303
|
await sendResponse(chatId, channel, response2.text);
|
|
10149
10304
|
return;
|
|
@@ -10184,7 +10339,7 @@ ${content}
|
|
|
10184
10339
|
const mMode = getMode(chatId);
|
|
10185
10340
|
const mVerbose = getVerboseLevel(chatId);
|
|
10186
10341
|
const mToolCb = mVerbose !== "off" ? makeToolActionCallback(chatId, channel, mVerbose) : void 0;
|
|
10187
|
-
const response = await askAgent(chatId, prompt, getCwd(chatId),
|
|
10342
|
+
const response = await askAgent(chatId, prompt, { cwd: getCwd(chatId), model: mediaModel, permMode: mMode, onToolAction: mToolCb });
|
|
10188
10343
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, mediaModel);
|
|
10189
10344
|
await sendResponse(chatId, channel, response.text);
|
|
10190
10345
|
if (tempFilePath) {
|
|
@@ -10249,7 +10404,7 @@ async function handleText(msg, channel) {
|
|
|
10249
10404
|
const tMode = getMode(chatId);
|
|
10250
10405
|
const tVerbose = getVerboseLevel(chatId);
|
|
10251
10406
|
const tToolCb = tVerbose !== "off" ? makeToolActionCallback(chatId, channel, tVerbose) : void 0;
|
|
10252
|
-
const response = await askAgent(chatId, text, getCwd(chatId),
|
|
10407
|
+
const response = await askAgent(chatId, text, { cwd: getCwd(chatId), model: model2, permMode: tMode, onToolAction: tToolCb });
|
|
10253
10408
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2);
|
|
10254
10409
|
await sendResponse(chatId, channel, response.text);
|
|
10255
10410
|
} catch (err) {
|
|
@@ -10620,7 +10775,7 @@ ${PERM_MODES[chosen]}`,
|
|
|
10620
10775
|
const sMode = getMode(chatId);
|
|
10621
10776
|
const sVerbose = getVerboseLevel(chatId);
|
|
10622
10777
|
const sToolCb = sVerbose !== "off" ? makeToolActionCallback(chatId, channel, sVerbose) : void 0;
|
|
10623
|
-
const response = await askAgent(chatId, skillContent, getCwd(chatId),
|
|
10778
|
+
const response = await askAgent(chatId, skillContent, { cwd: getCwd(chatId), model: skillModel, permMode: sMode, onToolAction: sToolCb });
|
|
10624
10779
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, skillModel);
|
|
10625
10780
|
await sendResponse(chatId, channel, response.text);
|
|
10626
10781
|
}
|
|
@@ -10773,10 +10928,12 @@ var init_router = __esm({
|
|
|
10773
10928
|
init_profile();
|
|
10774
10929
|
init_heartbeat();
|
|
10775
10930
|
init_log();
|
|
10931
|
+
init_format_time();
|
|
10776
10932
|
init_agent();
|
|
10777
10933
|
init_stt();
|
|
10778
10934
|
init_store4();
|
|
10779
10935
|
init_summarize();
|
|
10936
|
+
init_session_log();
|
|
10780
10937
|
init_backends();
|
|
10781
10938
|
init_cron();
|
|
10782
10939
|
init_wizard();
|
|
@@ -12420,7 +12577,9 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
12420
12577
|
lines.push(` ${parts.join(", ")}`);
|
|
12421
12578
|
const fixable = r.checks.filter((c) => c.fix);
|
|
12422
12579
|
if (fixable.length > 0 && !localOpts.fix) {
|
|
12423
|
-
|
|
12580
|
+
for (const f of fixable) {
|
|
12581
|
+
lines.push(muted(` Fix: ${f.fix}`));
|
|
12582
|
+
}
|
|
12424
12583
|
}
|
|
12425
12584
|
}
|
|
12426
12585
|
lines.push("");
|
|
@@ -12723,7 +12882,7 @@ async function memoryHistory(globalOpts, opts) {
|
|
|
12723
12882
|
`;
|
|
12724
12883
|
const lines = ["", divider(`Session History (${sums.length})`), ""];
|
|
12725
12884
|
for (const s of sums) {
|
|
12726
|
-
const date =
|
|
12885
|
+
const date = formatLocalDateTime(s.created_at);
|
|
12727
12886
|
lines.push(` ${date} (${s.message_count} msgs)`);
|
|
12728
12887
|
lines.push(` ${s.summary}`);
|
|
12729
12888
|
lines.push(` Topics: ${muted(s.topics)}`);
|
|
@@ -12738,6 +12897,7 @@ var init_memory = __esm({
|
|
|
12738
12897
|
init_format();
|
|
12739
12898
|
init_paths();
|
|
12740
12899
|
init_resolve_chat();
|
|
12900
|
+
init_format_time();
|
|
12741
12901
|
}
|
|
12742
12902
|
});
|
|
12743
12903
|
|
|
@@ -12752,6 +12912,15 @@ __export(cron_exports2, {
|
|
|
12752
12912
|
cronRuns: () => cronRuns
|
|
12753
12913
|
});
|
|
12754
12914
|
import { existsSync as existsSync24 } from "fs";
|
|
12915
|
+
function parseAndValidateTimeout(raw) {
|
|
12916
|
+
if (!raw) return null;
|
|
12917
|
+
const val = parseInt(raw, 10);
|
|
12918
|
+
if (isNaN(val) || val < TIMEOUT_MIN_SECONDS || val > TIMEOUT_MAX_SECONDS) {
|
|
12919
|
+
outputError("INVALID_TIMEOUT", `Timeout must be between ${TIMEOUT_MIN_SECONDS} and ${TIMEOUT_MAX_SECONDS} seconds (got: ${raw})`);
|
|
12920
|
+
process.exit(1);
|
|
12921
|
+
}
|
|
12922
|
+
return val;
|
|
12923
|
+
}
|
|
12755
12924
|
async function cronList(globalOpts) {
|
|
12756
12925
|
if (!existsSync24(DB_PATH)) {
|
|
12757
12926
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
@@ -12774,6 +12943,7 @@ async function cronList(globalOpts) {
|
|
|
12774
12943
|
lines.push(` ${statusDot(status)} #${j.id} [${status}] ${schedule2}${tz}`);
|
|
12775
12944
|
lines.push(` ${j.description}`);
|
|
12776
12945
|
if (j.backend) lines.push(` Backend: ${j.backend}${j.model ? ` / ${j.model}` : ""}`);
|
|
12946
|
+
if (j.timeout) lines.push(` Timeout: ${j.timeout}s`);
|
|
12777
12947
|
if (j.next_run_at) lines.push(` Next: ${muted(j.next_run_at)}`);
|
|
12778
12948
|
lines.push("");
|
|
12779
12949
|
}
|
|
@@ -12810,7 +12980,7 @@ async function cronHealth(globalOpts) {
|
|
|
12810
12980
|
});
|
|
12811
12981
|
}
|
|
12812
12982
|
async function cronCreate(globalOpts, opts) {
|
|
12813
|
-
const { isDaemonRunning: isDaemonRunning2
|
|
12983
|
+
const { isDaemonRunning: isDaemonRunning2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
12814
12984
|
if (!await isDaemonRunning2()) {
|
|
12815
12985
|
outputError("DAEMON_OFFLINE", "CC-Claw daemon is not running.\n\n Start it with: cc-claw service start");
|
|
12816
12986
|
process.exit(1);
|
|
@@ -12821,10 +12991,9 @@ async function cronCreate(globalOpts, opts) {
|
|
|
12821
12991
|
}
|
|
12822
12992
|
const chatId = resolveChatId(globalOpts);
|
|
12823
12993
|
const { success: successFmt } = await Promise.resolve().then(() => (init_format(), format_exports));
|
|
12994
|
+
const timeout = parseAndValidateTimeout(opts.timeout);
|
|
12824
12995
|
try {
|
|
12825
|
-
const {
|
|
12826
|
-
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
12827
|
-
const db3 = getDb2();
|
|
12996
|
+
const { insertJob: insertJob2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
12828
12997
|
const schedType = opts.cron ? "cron" : opts.at ? "at" : "every";
|
|
12829
12998
|
let everyMs = null;
|
|
12830
12999
|
if (opts.every) {
|
|
@@ -12835,28 +13004,25 @@ async function cronCreate(globalOpts, opts) {
|
|
|
12835
13004
|
everyMs = unit.startsWith("h") ? num * 36e5 : unit.startsWith("m") ? num * 6e4 : num * 1e3;
|
|
12836
13005
|
}
|
|
12837
13006
|
}
|
|
12838
|
-
const
|
|
12839
|
-
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
schedType,
|
|
12843
|
-
opts.cron ?? null,
|
|
12844
|
-
opts.at ?? null,
|
|
13007
|
+
const job = insertJob2({
|
|
13008
|
+
scheduleType: schedType,
|
|
13009
|
+
cron: opts.cron ?? null,
|
|
13010
|
+
atTime: opts.at ?? null,
|
|
12845
13011
|
everyMs,
|
|
12846
|
-
opts.description,
|
|
13012
|
+
description: opts.description,
|
|
12847
13013
|
chatId,
|
|
12848
|
-
opts.backend ?? null,
|
|
12849
|
-
opts.model ?? null,
|
|
12850
|
-
opts.thinking ?? null,
|
|
12851
|
-
|
|
12852
|
-
opts.
|
|
12853
|
-
opts.
|
|
12854
|
-
opts.
|
|
12855
|
-
opts.
|
|
12856
|
-
|
|
12857
|
-
|
|
12858
|
-
output({ id:
|
|
12859
|
-
${successFmt(`Job #${
|
|
13014
|
+
backend: opts.backend ?? null,
|
|
13015
|
+
model: opts.model ?? null,
|
|
13016
|
+
thinking: opts.thinking ?? null,
|
|
13017
|
+
timeout,
|
|
13018
|
+
sessionType: opts.sessionType ?? "isolated",
|
|
13019
|
+
deliveryMode: opts.delivery ?? "announce",
|
|
13020
|
+
channel: opts.channel ?? null,
|
|
13021
|
+
target: opts.target ?? null,
|
|
13022
|
+
timezone: opts.timezone ?? "UTC"
|
|
13023
|
+
});
|
|
13024
|
+
output({ id: job.id, success: true }, () => `
|
|
13025
|
+
${successFmt(`Job #${job.id} created.`)}
|
|
12860
13026
|
`);
|
|
12861
13027
|
} catch (err) {
|
|
12862
13028
|
outputError("CREATE_FAILED", err.message);
|
|
@@ -12923,6 +13089,11 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
12923
13089
|
updates.push("thinking = ?");
|
|
12924
13090
|
values.push(opts.thinking);
|
|
12925
13091
|
}
|
|
13092
|
+
if (opts.timeout) {
|
|
13093
|
+
const timeout = parseAndValidateTimeout(opts.timeout);
|
|
13094
|
+
updates.push("timeout = ?");
|
|
13095
|
+
values.push(timeout);
|
|
13096
|
+
}
|
|
12926
13097
|
if (opts.timezone) {
|
|
12927
13098
|
updates.push("timezone = ?");
|
|
12928
13099
|
values.push(opts.timezone);
|
|
@@ -12974,6 +13145,7 @@ var init_cron2 = __esm({
|
|
|
12974
13145
|
init_format();
|
|
12975
13146
|
init_paths();
|
|
12976
13147
|
init_resolve_chat();
|
|
13148
|
+
init_types2();
|
|
12977
13149
|
}
|
|
12978
13150
|
});
|
|
12979
13151
|
|
|
@@ -15049,7 +15221,7 @@ function registerCronCommands(cmd) {
|
|
|
15049
15221
|
const { cronList: cronList2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
|
|
15050
15222
|
await cronList2(program.opts());
|
|
15051
15223
|
});
|
|
15052
|
-
cmd.command("create").description("Create a scheduled job").requiredOption("--description <text>", "Job description").option("--prompt <text>", "Agent prompt (defaults to description)").option("--cron <expr>", "Cron expression (e.g. '0 9 * * *')").option("--at <iso8601>", "One-shot time").option("--every <interval>", "Repeat interval (e.g. 30m, 1h)").option("--backend <name>", "Backend for this job").option("--model <name>", "Model for this job").option("--thinking <level>", "Thinking level").option("--timezone <tz>", "IANA timezone", "UTC").option("--session-type <type>", "Session type (isolated/main)", "isolated").option("--delivery <mode>", "Delivery mode (announce/webhook/none)", "announce").option("--channel <name>", "Delivery channel").option("--target <id>", "Delivery target").option("--cwd <path>", "Working directory").action(async (opts) => {
|
|
15224
|
+
cmd.command("create").description("Create a scheduled job").requiredOption("--description <text>", "Job description").option("--prompt <text>", "Agent prompt (defaults to description)").option("--cron <expr>", "Cron expression (e.g. '0 9 * * *')").option("--at <iso8601>", "One-shot time").option("--every <interval>", "Repeat interval (e.g. 30m, 1h)").option("--backend <name>", "Backend for this job").option("--model <name>", "Model for this job").option("--thinking <level>", "Thinking level").option("--timeout <seconds>", "Job timeout in seconds (30-3600)").option("--timezone <tz>", "IANA timezone", "UTC").option("--session-type <type>", "Session type (isolated/main)", "isolated").option("--delivery <mode>", "Delivery mode (announce/webhook/none)", "announce").option("--channel <name>", "Delivery channel").option("--target <id>", "Delivery target").option("--cwd <path>", "Working directory").action(async (opts) => {
|
|
15053
15225
|
const { cronCreate: cronCreate2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
|
|
15054
15226
|
await cronCreate2(program.opts(), opts);
|
|
15055
15227
|
});
|
|
@@ -15069,7 +15241,7 @@ function registerCronCommands(cmd) {
|
|
|
15069
15241
|
const { cronAction: cronAction2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
|
|
15070
15242
|
await cronAction2(program.opts(), "run", id);
|
|
15071
15243
|
});
|
|
15072
|
-
cmd.command("edit <id>").description("Edit a job (same flags as create)").option("--description <text>").option("--cron <expr>").option("--at <iso8601>").option("--every <interval>").option("--backend <name>").option("--model <name>").option("--thinking <level>").option("--timezone <tz>").action(async (id, opts) => {
|
|
15244
|
+
cmd.command("edit <id>").description("Edit a job (same flags as create)").option("--description <text>").option("--cron <expr>").option("--at <iso8601>").option("--every <interval>").option("--backend <name>").option("--model <name>").option("--thinking <level>").option("--timeout <seconds>", "Job timeout in seconds (30-3600)").option("--timezone <tz>").action(async (id, opts) => {
|
|
15073
15245
|
const { cronEdit: cronEdit2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
|
|
15074
15246
|
await cronEdit2(program.opts(), id, opts);
|
|
15075
15247
|
});
|
package/package.json
CHANGED