cueclaw 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{app-DIUXV4XR.js → app-LWDIWH7K.js} +3 -3
- package/dist/{chunk-W274JWEK.js → chunk-FAT2VKMJ.js} +9 -6
- package/dist/{chunk-F3EQAFH4.js → chunk-IB6TU7TP.js} +17 -11
- package/dist/cli.js +34 -7
- package/dist/{daemon-R3LU23PR.js → daemon-WOR4GE5C.js} +7 -6
- package/dist/{router-KEZ3YQXC.js → router-ID6RN5AT.js} +1 -1
- package/dist/{telegram-P6DBJ7WZ.js → telegram-EFPHL4HC.js} +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Confirm the plan, and CueClaw runs it continuously in the background as a daemon
|
|
|
38
38
|
- **Multi-channel** — TUI, WhatsApp, or Telegram. All channels share identical capabilities.
|
|
39
39
|
- **Triggers** — Poll scripts, cron schedules, or manual. Runs as a system service with auto-restart.
|
|
40
40
|
- **Parallel DAG execution** — Independent steps run concurrently. Dependencies are respected.
|
|
41
|
-
- **Container isolation** — Agents run in Docker with filesystem isolation and mount allowlists.
|
|
41
|
+
- **Container isolation** (optional) — Agents can run in Docker with filesystem isolation and mount allowlists. Defaults to local mode with PreToolUse hooks for permission control.
|
|
42
42
|
|
|
43
43
|
## Install
|
|
44
44
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TriggerLoop
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FAT2VKMJ.js";
|
|
4
4
|
import {
|
|
5
5
|
getServiceStatus
|
|
6
6
|
} from "./chunk-PZZ6FBGB.js";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-KRNAXOQ4.js";
|
|
11
11
|
import {
|
|
12
12
|
MessageRouter
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-IB6TU7TP.js";
|
|
14
14
|
import {
|
|
15
15
|
askQuestionTool,
|
|
16
16
|
buildPlannerSystemPrompt,
|
|
@@ -1309,7 +1309,7 @@ async function startBotChannels(bridge, config) {
|
|
|
1309
1309
|
async function connectBotChannels(config, router, botChannels) {
|
|
1310
1310
|
if (config.telegram?.enabled && config.telegram.token) {
|
|
1311
1311
|
try {
|
|
1312
|
-
const { TelegramChannel } = await import("./telegram-
|
|
1312
|
+
const { TelegramChannel } = await import("./telegram-EFPHL4HC.js");
|
|
1313
1313
|
const tg = new TelegramChannel(
|
|
1314
1314
|
config.telegram.token,
|
|
1315
1315
|
config.telegram.allowed_users ?? [],
|
|
@@ -9,15 +9,18 @@ import {
|
|
|
9
9
|
import { CronExpressionParser } from "cron-parser";
|
|
10
10
|
|
|
11
11
|
// src/trigger.ts
|
|
12
|
-
import {
|
|
12
|
+
import { execFile } from "child_process";
|
|
13
|
+
import { promisify } from "util";
|
|
14
|
+
var execFileAsync = promisify(execFile);
|
|
13
15
|
var CHECK_SCRIPT_TIMEOUT = 3e4;
|
|
14
|
-
function evaluatePollTrigger(workflow, trigger, db) {
|
|
16
|
+
async function evaluatePollTrigger(workflow, trigger, db) {
|
|
15
17
|
let stdout;
|
|
16
18
|
try {
|
|
17
|
-
|
|
19
|
+
const result = await execFileAsync("sh", ["-c", trigger.check_script], {
|
|
18
20
|
timeout: CHECK_SCRIPT_TIMEOUT,
|
|
19
21
|
encoding: "utf-8"
|
|
20
|
-
})
|
|
22
|
+
});
|
|
23
|
+
stdout = result.stdout.trim();
|
|
21
24
|
} catch (err) {
|
|
22
25
|
logger.error({ workflowId: workflow.id, err }, "Poll check_script failed");
|
|
23
26
|
db.prepare(
|
|
@@ -125,9 +128,9 @@ var TriggerLoop = class {
|
|
|
125
128
|
this.unregisterTrigger(workflow.id);
|
|
126
129
|
const trigger = workflow.trigger;
|
|
127
130
|
if (trigger.type === "poll") {
|
|
128
|
-
const interval = setInterval(() => {
|
|
131
|
+
const interval = setInterval(async () => {
|
|
129
132
|
try {
|
|
130
|
-
const result = evaluatePollTrigger(workflow, trigger, this.db);
|
|
133
|
+
const result = await evaluatePollTrigger(workflow, trigger, this.db);
|
|
131
134
|
if (result) {
|
|
132
135
|
this.executeTrigger(workflow, result.data);
|
|
133
136
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-SEYPA5M2.js";
|
|
13
13
|
import {
|
|
14
14
|
getWorkflow,
|
|
15
|
+
insertWorkflow,
|
|
15
16
|
listWorkflows,
|
|
16
17
|
updateWorkflowPhase
|
|
17
18
|
} from "./chunk-G43R5ASK.js";
|
|
@@ -46,6 +47,12 @@ var MessageRouter = class {
|
|
|
46
47
|
this.cleanupTimer = null;
|
|
47
48
|
}
|
|
48
49
|
}
|
|
50
|
+
/** Disconnect all registered channels */
|
|
51
|
+
async disconnectAll() {
|
|
52
|
+
await Promise.allSettled(
|
|
53
|
+
[...this.channels.values()].map((c) => c.disconnect())
|
|
54
|
+
);
|
|
55
|
+
}
|
|
49
56
|
/** Broadcast a notification to all connected channels (used by MCP handler) */
|
|
50
57
|
broadcastNotification(message) {
|
|
51
58
|
for (const channel of this.channels.values()) {
|
|
@@ -69,8 +76,14 @@ var MessageRouter = class {
|
|
|
69
76
|
}
|
|
70
77
|
if (text.startsWith("/") || text.startsWith("!")) {
|
|
71
78
|
await this.handleCommand(channel, chatJid, text);
|
|
72
|
-
} else if (this.
|
|
73
|
-
|
|
79
|
+
} else if (this.pendingConfirmations.has(chatJid)) {
|
|
80
|
+
const pending = this.pendingConfirmations.get(chatJid);
|
|
81
|
+
if (Date.now() > pending.expiresAt) {
|
|
82
|
+
this.pendingConfirmations.delete(chatJid);
|
|
83
|
+
await channel.sendMessage(chatJid, "Your pending plan has expired. Send a new description to start over.");
|
|
84
|
+
} else {
|
|
85
|
+
await this.handleConfirmation(channel, chatJid, text);
|
|
86
|
+
}
|
|
74
87
|
} else {
|
|
75
88
|
await this.classifyAndRoute(channel, chatJid, text);
|
|
76
89
|
}
|
|
@@ -201,6 +214,7 @@ ${steps}`);
|
|
|
201
214
|
channel.setTyping?.(chatJid, true);
|
|
202
215
|
try {
|
|
203
216
|
const workflow = await generatePlan(text, this.config);
|
|
217
|
+
insertWorkflow(this.db, workflow);
|
|
204
218
|
channel.setTyping?.(chatJid, false);
|
|
205
219
|
this.pendingConfirmations.set(chatJid, {
|
|
206
220
|
workflowId: workflow.id,
|
|
@@ -255,6 +269,7 @@ ${steps}`);
|
|
|
255
269
|
channel.setTyping?.(chatJid, true);
|
|
256
270
|
try {
|
|
257
271
|
const modified = await modifyPlan(pending.workflow, text, this.config);
|
|
272
|
+
insertWorkflow(this.db, modified);
|
|
258
273
|
channel.setTyping?.(chatJid, false);
|
|
259
274
|
this.pendingConfirmations.set(chatJid, {
|
|
260
275
|
workflowId: modified.id,
|
|
@@ -269,15 +284,6 @@ ${steps}`);
|
|
|
269
284
|
}
|
|
270
285
|
}
|
|
271
286
|
}
|
|
272
|
-
hasPendingConfirmation(chatJid) {
|
|
273
|
-
const pending = this.pendingConfirmations.get(chatJid);
|
|
274
|
-
if (!pending) return false;
|
|
275
|
-
if (Date.now() > pending.expiresAt) {
|
|
276
|
-
this.pendingConfirmations.delete(chatJid);
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
return true;
|
|
280
|
-
}
|
|
281
287
|
isRateLimited(chatJid) {
|
|
282
288
|
const now = Date.now();
|
|
283
289
|
const timestamps = this.messageTimestamps.get(chatJid) ?? [];
|
package/dist/cli.js
CHANGED
|
@@ -26,7 +26,10 @@ import {
|
|
|
26
26
|
// src/cli.ts
|
|
27
27
|
import { Command } from "commander";
|
|
28
28
|
import { createInterface } from "readline";
|
|
29
|
-
|
|
29
|
+
import { createRequire } from "module";
|
|
30
|
+
var require2 = createRequire(import.meta.url);
|
|
31
|
+
var { version: pkgVersion } = require2("../package.json");
|
|
32
|
+
var program = new Command().name("cueclaw").description("Orchestrate agent workflows with natural language").version(pkgVersion);
|
|
30
33
|
program.command("info").description("Show loaded config, paths, versions").action(() => {
|
|
31
34
|
try {
|
|
32
35
|
const config = loadConfig();
|
|
@@ -333,9 +336,19 @@ program.command("delete").argument("<workflow-id>", "Workflow ID").description("
|
|
|
333
336
|
}
|
|
334
337
|
});
|
|
335
338
|
var daemonCmd = program.command("daemon").description("Manage background daemon");
|
|
336
|
-
daemonCmd.command("start").option("--detach", "Run in background").description("Start the daemon").action(async () => {
|
|
339
|
+
daemonCmd.command("start").option("--detach", "Run in background").description("Start the daemon").action(async (opts) => {
|
|
340
|
+
if (opts.detach) {
|
|
341
|
+
const { spawn } = await import("child_process");
|
|
342
|
+
const child = spawn(process.execPath, [process.argv[1], "daemon", "start"], {
|
|
343
|
+
detached: true,
|
|
344
|
+
stdio: "ignore"
|
|
345
|
+
});
|
|
346
|
+
child.unref();
|
|
347
|
+
console.log(`Daemon started in background (PID ${child.pid})`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
337
350
|
try {
|
|
338
|
-
const { startDaemon } = await import("./daemon-
|
|
351
|
+
const { startDaemon } = await import("./daemon-WOR4GE5C.js");
|
|
339
352
|
await startDaemon();
|
|
340
353
|
} catch (err) {
|
|
341
354
|
logger.error({ err }, "Daemon failed");
|
|
@@ -357,6 +370,20 @@ daemonCmd.command("stop").description("Stop the daemon").action(async () => {
|
|
|
357
370
|
process.exit(1);
|
|
358
371
|
}
|
|
359
372
|
});
|
|
373
|
+
daemonCmd.command("restart").description("Restart the daemon").action(async () => {
|
|
374
|
+
const { getServiceStatus, stopService } = await import("./service-VTUYSAAZ.js");
|
|
375
|
+
const status = getServiceStatus();
|
|
376
|
+
if (status === "running") {
|
|
377
|
+
const result = stopService();
|
|
378
|
+
if (!result.success) {
|
|
379
|
+
console.log(`Failed to stop daemon: ${result.error}`);
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
382
|
+
console.log("Daemon stopped.");
|
|
383
|
+
}
|
|
384
|
+
const { startDaemon } = await import("./daemon-WOR4GE5C.js");
|
|
385
|
+
await startDaemon();
|
|
386
|
+
});
|
|
360
387
|
daemonCmd.command("install").description("Install system service").action(async () => {
|
|
361
388
|
const { installService } = await import("./service-VTUYSAAZ.js");
|
|
362
389
|
const result = installService();
|
|
@@ -399,7 +426,7 @@ botCmd.command("start").description("Start all configured bot channels").action(
|
|
|
399
426
|
try {
|
|
400
427
|
const config = loadConfig();
|
|
401
428
|
const db = initDb();
|
|
402
|
-
const { MessageRouter } = await import("./router-
|
|
429
|
+
const { MessageRouter } = await import("./router-ID6RN5AT.js");
|
|
403
430
|
const router = new MessageRouter(db, config, process.cwd());
|
|
404
431
|
if (config.whatsapp?.enabled) {
|
|
405
432
|
const { WhatsAppChannel } = await import("./whatsapp-HFMOFSFI.js");
|
|
@@ -413,7 +440,7 @@ botCmd.command("start").description("Start all configured bot channels").action(
|
|
|
413
440
|
logger.info("WhatsApp channel started");
|
|
414
441
|
}
|
|
415
442
|
if (config.telegram?.enabled) {
|
|
416
|
-
const { TelegramChannel } = await import("./telegram-
|
|
443
|
+
const { TelegramChannel } = await import("./telegram-EFPHL4HC.js");
|
|
417
444
|
const tg = new TelegramChannel(
|
|
418
445
|
config.telegram.token,
|
|
419
446
|
config.telegram.allowed_users ?? [],
|
|
@@ -452,7 +479,7 @@ program.command("tui").description("Start interactive TUI").option("--skip-onboa
|
|
|
452
479
|
enableTuiLogging();
|
|
453
480
|
const React = await import("react");
|
|
454
481
|
const { render } = await import("ink");
|
|
455
|
-
const { App } = await import("./app-
|
|
482
|
+
const { App } = await import("./app-LWDIWH7K.js");
|
|
456
483
|
render(React.createElement(App, { cwd: process.cwd(), skipOnboarding: opts.skipOnboarding }));
|
|
457
484
|
} catch (err) {
|
|
458
485
|
logger.error({ err }, "Failed to start TUI");
|
|
@@ -466,7 +493,7 @@ program.option("--skip-onboarding", "Skip first-run onboarding wizard").action(a
|
|
|
466
493
|
enableTuiLogging();
|
|
467
494
|
const React = await import("react");
|
|
468
495
|
const { render } = await import("ink");
|
|
469
|
-
const { App } = await import("./app-
|
|
496
|
+
const { App } = await import("./app-LWDIWH7K.js");
|
|
470
497
|
render(React.createElement(App, { cwd: process.cwd(), skipOnboarding }));
|
|
471
498
|
} catch (err) {
|
|
472
499
|
logger.error({ err }, "Failed to start TUI");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TriggerLoop
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FAT2VKMJ.js";
|
|
4
4
|
import {
|
|
5
5
|
MessageRouter
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IB6TU7TP.js";
|
|
7
7
|
import "./chunk-WE5J7GMR.js";
|
|
8
8
|
import "./chunk-DVQFSFIZ.js";
|
|
9
9
|
import "./chunk-ZCK3IFLC.js";
|
|
@@ -42,7 +42,7 @@ async function startDaemon() {
|
|
|
42
42
|
}
|
|
43
43
|
if (config.telegram?.enabled) {
|
|
44
44
|
try {
|
|
45
|
-
const { TelegramChannel } = await import("./telegram-
|
|
45
|
+
const { TelegramChannel } = await import("./telegram-EFPHL4HC.js");
|
|
46
46
|
const tg = new TelegramChannel(
|
|
47
47
|
config.telegram.token,
|
|
48
48
|
config.telegram.allowed_users ?? [],
|
|
@@ -62,15 +62,16 @@ async function startDaemon() {
|
|
|
62
62
|
triggerLoop.start();
|
|
63
63
|
router.start();
|
|
64
64
|
logger.info("Daemon started");
|
|
65
|
-
const shutdown = () => {
|
|
65
|
+
const shutdown = async () => {
|
|
66
66
|
logger.info("Shutting down daemon...");
|
|
67
67
|
triggerLoop.stop();
|
|
68
68
|
router.stop();
|
|
69
|
+
await router.disconnectAll();
|
|
69
70
|
db.close();
|
|
70
71
|
process.exit(0);
|
|
71
72
|
};
|
|
72
|
-
process.on("SIGTERM", shutdown);
|
|
73
|
-
process.on("SIGINT", shutdown);
|
|
73
|
+
process.on("SIGTERM", () => void shutdown());
|
|
74
|
+
process.on("SIGINT", () => void shutdown());
|
|
74
75
|
}
|
|
75
76
|
async function recoverRunningWorkflows(db, router) {
|
|
76
77
|
const interruptedRuns = db.prepare(
|
|
@@ -78,7 +78,8 @@ var TelegramChannel = class {
|
|
|
78
78
|
ownsJid(jid) {
|
|
79
79
|
return /^-?\d+$/.test(jid);
|
|
80
80
|
}
|
|
81
|
-
async setTyping(jid,
|
|
81
|
+
async setTyping(jid, isTyping) {
|
|
82
|
+
if (!isTyping) return;
|
|
82
83
|
try {
|
|
83
84
|
await this.bot.api.sendChatAction(Number(jid), "typing");
|
|
84
85
|
} catch {
|