@suzuke/agend 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +557 -1
- package/README.zh-TW.md +504 -0
- package/dist/access-path.d.ts +7 -0
- package/dist/access-path.js +12 -0
- package/dist/access-path.js.map +1 -0
- package/dist/approval/approval-server.d.ts +30 -0
- package/dist/approval/approval-server.js +156 -0
- package/dist/approval/approval-server.js.map +1 -0
- package/dist/approval/tmux-prompt-detector.d.ts +34 -0
- package/dist/approval/tmux-prompt-detector.js +264 -0
- package/dist/approval/tmux-prompt-detector.js.map +1 -0
- package/dist/backend/approval-strategy.d.ts +14 -0
- package/dist/backend/approval-strategy.js +2 -0
- package/dist/backend/approval-strategy.js.map +1 -0
- package/dist/backend/claude-code.d.ts +13 -0
- package/dist/backend/claude-code.js +114 -0
- package/dist/backend/claude-code.js.map +1 -0
- package/dist/backend/codex.d.ts +10 -0
- package/dist/backend/codex.js +58 -0
- package/dist/backend/codex.js.map +1 -0
- package/dist/backend/factory.d.ts +2 -0
- package/dist/backend/factory.js +19 -0
- package/dist/backend/factory.js.map +1 -0
- package/dist/backend/gemini-cli.d.ts +10 -0
- package/dist/backend/gemini-cli.js +68 -0
- package/dist/backend/gemini-cli.js.map +1 -0
- package/dist/backend/hook-based-approval.d.ts +20 -0
- package/dist/backend/hook-based-approval.js +41 -0
- package/dist/backend/hook-based-approval.js.map +1 -0
- package/dist/backend/index.d.ts +6 -0
- package/dist/backend/index.js +6 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/opencode.d.ts +10 -0
- package/dist/backend/opencode.js +63 -0
- package/dist/backend/opencode.js.map +1 -0
- package/dist/backend/types.d.ts +26 -0
- package/dist/backend/types.js +2 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/channel/access-manager.d.ts +18 -0
- package/dist/channel/access-manager.js +149 -0
- package/dist/channel/access-manager.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +45 -0
- package/dist/channel/adapters/discord.js +366 -0
- package/dist/channel/adapters/discord.js.map +1 -0
- package/dist/channel/adapters/telegram.d.ts +58 -0
- package/dist/channel/adapters/telegram.js +569 -0
- package/dist/channel/adapters/telegram.js.map +1 -0
- package/dist/channel/attachment-handler.d.ts +15 -0
- package/dist/channel/attachment-handler.js +55 -0
- package/dist/channel/attachment-handler.js.map +1 -0
- package/dist/channel/factory.d.ts +12 -0
- package/dist/channel/factory.js +38 -0
- package/dist/channel/factory.js.map +1 -0
- package/dist/channel/ipc-bridge.d.ts +26 -0
- package/dist/channel/ipc-bridge.js +170 -0
- package/dist/channel/ipc-bridge.js.map +1 -0
- package/dist/channel/mcp-server.d.ts +10 -0
- package/dist/channel/mcp-server.js +196 -0
- package/dist/channel/mcp-server.js.map +1 -0
- package/dist/channel/mcp-tools.d.ts +909 -0
- package/dist/channel/mcp-tools.js +346 -0
- package/dist/channel/mcp-tools.js.map +1 -0
- package/dist/channel/message-bus.d.ts +17 -0
- package/dist/channel/message-bus.js +86 -0
- package/dist/channel/message-bus.js.map +1 -0
- package/dist/channel/message-queue.d.ts +39 -0
- package/dist/channel/message-queue.js +248 -0
- package/dist/channel/message-queue.js.map +1 -0
- package/dist/channel/tool-router.d.ts +6 -0
- package/dist/channel/tool-router.js +69 -0
- package/dist/channel/tool-router.js.map +1 -0
- package/dist/channel/tool-tracker.d.ts +13 -0
- package/dist/channel/tool-tracker.js +58 -0
- package/dist/channel/tool-tracker.js.map +1 -0
- package/dist/channel/types.d.ts +116 -0
- package/dist/channel/types.js +2 -0
- package/dist/channel/types.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +782 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +85 -0
- package/dist/config.js.map +1 -0
- package/dist/container-manager.d.ts +24 -0
- package/dist/container-manager.js +148 -0
- package/dist/container-manager.js.map +1 -0
- package/dist/context-guardian.d.ts +29 -0
- package/dist/context-guardian.js +123 -0
- package/dist/context-guardian.js.map +1 -0
- package/dist/cost-guard.d.ts +21 -0
- package/dist/cost-guard.js +113 -0
- package/dist/cost-guard.js.map +1 -0
- package/dist/daemon-entry.d.ts +1 -0
- package/dist/daemon-entry.js +29 -0
- package/dist/daemon-entry.js.map +1 -0
- package/dist/daemon.d.ts +88 -0
- package/dist/daemon.js +820 -0
- package/dist/daemon.js.map +1 -0
- package/dist/daily-summary.d.ts +13 -0
- package/dist/daily-summary.js +55 -0
- package/dist/daily-summary.js.map +1 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.js +43 -0
- package/dist/db.js.map +1 -0
- package/dist/event-log.d.ts +22 -0
- package/dist/event-log.js +66 -0
- package/dist/event-log.js.map +1 -0
- package/dist/export-import.d.ts +2 -0
- package/dist/export-import.js +110 -0
- package/dist/export-import.js.map +1 -0
- package/dist/fleet-context.d.ts +36 -0
- package/dist/fleet-context.js +4 -0
- package/dist/fleet-context.js.map +1 -0
- package/dist/fleet-manager.d.ts +115 -0
- package/dist/fleet-manager.js +1742 -0
- package/dist/fleet-manager.js.map +1 -0
- package/dist/fleet-system-prompt.d.ts +11 -0
- package/dist/fleet-system-prompt.js +60 -0
- package/dist/fleet-system-prompt.js.map +1 -0
- package/dist/hang-detector.d.ts +16 -0
- package/dist/hang-detector.js +53 -0
- package/dist/hang-detector.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/install-recorder.d.ts +30 -0
- package/dist/install-recorder.js +159 -0
- package/dist/install-recorder.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +63 -0
- package/dist/logger.js.map +1 -0
- package/dist/meeting/orchestrator.d.ts +30 -0
- package/dist/meeting/orchestrator.js +355 -0
- package/dist/meeting/orchestrator.js.map +1 -0
- package/dist/meeting/prompt-builder.d.ts +12 -0
- package/dist/meeting/prompt-builder.js +96 -0
- package/dist/meeting/prompt-builder.js.map +1 -0
- package/dist/meeting/role-assigner.d.ts +2 -0
- package/dist/meeting/role-assigner.js +25 -0
- package/dist/meeting/role-assigner.js.map +1 -0
- package/dist/meeting/types.d.ts +21 -0
- package/dist/meeting/types.js +2 -0
- package/dist/meeting/types.js.map +1 -0
- package/dist/meeting-manager.d.ts +10 -0
- package/dist/meeting-manager.js +38 -0
- package/dist/meeting-manager.js.map +1 -0
- package/dist/memory-layer.d.ts +13 -0
- package/dist/memory-layer.js +44 -0
- package/dist/memory-layer.js.map +1 -0
- package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
- package/dist/plugin/agend/.mcp.json +9 -0
- package/dist/plugin/ccd-channel/.claude-plugin/plugin.json +5 -0
- package/dist/plugin/ccd-channel/.mcp.json +9 -0
- package/dist/process-manager.d.ts +31 -0
- package/dist/process-manager.js +264 -0
- package/dist/process-manager.js.map +1 -0
- package/dist/scheduler/db.d.ts +16 -0
- package/dist/scheduler/db.js +132 -0
- package/dist/scheduler/db.js.map +1 -0
- package/dist/scheduler/db.test.d.ts +1 -0
- package/dist/scheduler/db.test.js +92 -0
- package/dist/scheduler/db.test.js.map +1 -0
- package/dist/scheduler/index.d.ts +4 -0
- package/dist/scheduler/index.js +4 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +25 -0
- package/dist/scheduler/scheduler.js +119 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/scheduler.test.d.ts +1 -0
- package/dist/scheduler/scheduler.test.js +119 -0
- package/dist/scheduler/scheduler.test.js.map +1 -0
- package/dist/scheduler/types.d.ts +47 -0
- package/dist/scheduler/types.js +7 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service-installer.d.ts +14 -0
- package/dist/service-installer.js +91 -0
- package/dist/service-installer.js.map +1 -0
- package/dist/setup-wizard.d.ts +14 -0
- package/dist/setup-wizard.js +517 -0
- package/dist/setup-wizard.js.map +1 -0
- package/dist/stt.d.ts +10 -0
- package/dist/stt.js +33 -0
- package/dist/stt.js.map +1 -0
- package/dist/tmux-manager.d.ts +22 -0
- package/dist/tmux-manager.js +131 -0
- package/dist/tmux-manager.js.map +1 -0
- package/dist/topic-commands.d.ts +22 -0
- package/dist/topic-commands.js +176 -0
- package/dist/topic-commands.js.map +1 -0
- package/dist/transcript-monitor.d.ts +21 -0
- package/dist/transcript-monitor.js +149 -0
- package/dist/transcript-monitor.js.map +1 -0
- package/dist/types.d.ts +153 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/webhook-emitter.d.ts +15 -0
- package/dist/webhook-emitter.js +41 -0
- package/dist/webhook-emitter.js.map +1 -0
- package/package.json +60 -4
- package/templates/launchd.plist.ejs +29 -0
- package/templates/systemd.service.ejs +15 -0
- package/index.js +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
const WORKTREE_DIR = join(homedir(), ".claude-channel-daemon", "tmp");
|
|
5
|
+
export class MeetingManager {
|
|
6
|
+
ctx;
|
|
7
|
+
ephemeralTopicMap = new Map();
|
|
8
|
+
constructor(ctx) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
mkdirSync(WORKTREE_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
/** Get the ephemeral topic ID for an instance (used by fleet-manager for outbound routing) */
|
|
13
|
+
getEphemeralTopicId(instanceName) {
|
|
14
|
+
return this.ephemeralTopicMap.get(instanceName);
|
|
15
|
+
}
|
|
16
|
+
/** Clean up ephemeral instance resources (worktree, topic map). Called on topic deletion. */
|
|
17
|
+
async cleanupEphemeral(name) {
|
|
18
|
+
this.ephemeralTopicMap.delete(name);
|
|
19
|
+
const worktreePath = join(WORKTREE_DIR, `ccd-collab-${name}`);
|
|
20
|
+
if (!existsSync(worktreePath))
|
|
21
|
+
return;
|
|
22
|
+
try {
|
|
23
|
+
const { execFileSync } = await import("child_process");
|
|
24
|
+
const mainRepo = execFileSync("git", ["rev-parse", "--git-common-dir"], { cwd: worktreePath, stdio: "pipe" }).toString().trim();
|
|
25
|
+
const mainRepoDir = dirname(mainRepo);
|
|
26
|
+
execFileSync("git", ["worktree", "remove", "--force", worktreePath], { cwd: mainRepoDir, stdio: "pipe" });
|
|
27
|
+
try {
|
|
28
|
+
execFileSync("git", ["branch", "-D", `meet/${name}`], { cwd: mainRepoDir, stdio: "pipe" });
|
|
29
|
+
}
|
|
30
|
+
catch { /* branch may not exist */ }
|
|
31
|
+
this.ctx.logger.info({ name }, "Cleaned up ephemeral worktree");
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
this.ctx.logger.warn({ name, err }, "Failed to clean up ephemeral worktree");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=meeting-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meeting-manager.js","sourceRoot":"","sources":["../src/meeting-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,wBAAwB,EAAE,KAAK,CAAC,CAAC;AAEtE,MAAM,OAAO,cAAc;IAGL;IAFZ,iBAAiB,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE3D,YAAoB,GAAiB;QAAjB,QAAG,GAAH,GAAG,CAAc;QACnC,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,8FAA8F;IAC9F,mBAAmB,CAAC,YAAoB;QACtC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAED,6FAA6F;IAC7F,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEpC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,OAAO;QAEtC,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YAChI,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YACtC,YAAY,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1G,IAAI,CAAC;gBACH,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC7F,CAAC;YAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,+BAA+B,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,uCAAuC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;CAEF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { MemoryDb } from "./db.js";
|
|
3
|
+
import type { Logger } from "./logger.js";
|
|
4
|
+
export declare class MemoryLayer extends EventEmitter {
|
|
5
|
+
private memoryDir;
|
|
6
|
+
private db;
|
|
7
|
+
private logger;
|
|
8
|
+
private watcher;
|
|
9
|
+
constructor(memoryDir: string, db: MemoryDb, logger: Logger);
|
|
10
|
+
start(): Promise<void>;
|
|
11
|
+
stop(): Promise<void>;
|
|
12
|
+
private backupFile;
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { watch } from "chokidar";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
export class MemoryLayer extends EventEmitter {
|
|
5
|
+
memoryDir;
|
|
6
|
+
db;
|
|
7
|
+
logger;
|
|
8
|
+
watcher = null;
|
|
9
|
+
constructor(memoryDir, db, logger) {
|
|
10
|
+
super();
|
|
11
|
+
this.memoryDir = memoryDir;
|
|
12
|
+
this.db = db;
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
async start() {
|
|
16
|
+
this.logger.info({ dir: this.memoryDir }, "Watching memory directory");
|
|
17
|
+
this.watcher = watch(this.memoryDir, {
|
|
18
|
+
ignoreInitial: false,
|
|
19
|
+
awaitWriteFinish: { stabilityThreshold: 200 },
|
|
20
|
+
});
|
|
21
|
+
this.watcher.on("add", (path) => this.backupFile(path));
|
|
22
|
+
this.watcher.on("change", (path) => this.backupFile(path));
|
|
23
|
+
this.watcher.on("error", (err) => this.logger.error({ err }, "Memory watcher error"));
|
|
24
|
+
}
|
|
25
|
+
async stop() {
|
|
26
|
+
if (this.watcher) {
|
|
27
|
+
await this.watcher.close();
|
|
28
|
+
this.watcher = null;
|
|
29
|
+
}
|
|
30
|
+
this.db.close();
|
|
31
|
+
}
|
|
32
|
+
backupFile(filePath) {
|
|
33
|
+
try {
|
|
34
|
+
const content = readFileSync(filePath, "utf-8");
|
|
35
|
+
this.db.insertBackup(filePath, content, null);
|
|
36
|
+
this.logger.info({ filePath }, "Memory file backed up");
|
|
37
|
+
this.emit("file_changed", filePath);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
this.logger.error({ err, filePath }, "Failed to backup memory file");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=memory-layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-layer.js","sourceRoot":"","sources":["../src/memory-layer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAkB,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIvC,MAAM,OAAO,WAAY,SAAQ,YAAY;IAIjC;IACA;IACA;IALF,OAAO,GAAqB,IAAI,CAAC;IAEzC,YACU,SAAiB,EACjB,EAAY,EACZ,MAAc;QAEtB,KAAK,EAAE,CAAC;QAJA,cAAS,GAAT,SAAS,CAAQ;QACjB,OAAE,GAAF,EAAE,CAAU;QACZ,WAAM,GAAN,MAAM,CAAQ;IAGxB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,2BAA2B,CAAC,CAAC;QAEvE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE;YACnC,aAAa,EAAE,KAAK;YACpB,gBAAgB,EAAE,EAAE,kBAAkB,EAAE,GAAG,EAAE;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAEO,UAAU,CAAC,QAAgB;QACjC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAChD,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,uBAAuB,CAAC,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,8BAA8B,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { DaemonConfig } from "./types.js";
|
|
3
|
+
import type { Logger } from "./logger.js";
|
|
4
|
+
export declare const STATUSLINE_FILE: string;
|
|
5
|
+
export declare class ProcessManager extends EventEmitter {
|
|
6
|
+
private config;
|
|
7
|
+
private logger;
|
|
8
|
+
private term;
|
|
9
|
+
private running;
|
|
10
|
+
private retryCount;
|
|
11
|
+
private shuttingDown;
|
|
12
|
+
private restartTimer;
|
|
13
|
+
private uptimeTimer;
|
|
14
|
+
private sessionId;
|
|
15
|
+
private suppressSessionCapture;
|
|
16
|
+
constructor(config: DaemonConfig, logger: Logger);
|
|
17
|
+
isRunning(): boolean;
|
|
18
|
+
start(): Promise<void>;
|
|
19
|
+
stop(): Promise<void>;
|
|
20
|
+
/** Clear saved session ID so next start creates a fresh session. */
|
|
21
|
+
clearSessionId(): void;
|
|
22
|
+
sendInput(text: string): void;
|
|
23
|
+
private ensureStatusLineScript;
|
|
24
|
+
private ensureSpawnHelper;
|
|
25
|
+
private resolveClaudeBin;
|
|
26
|
+
private spawnChild;
|
|
27
|
+
private scheduleRestart;
|
|
28
|
+
private getBackoffDelay;
|
|
29
|
+
private loadSessionId;
|
|
30
|
+
private saveSessionId;
|
|
31
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import pty from "node-pty";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { execSync, execFileSync } from "node:child_process";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import stripAnsi from "strip-ansi";
|
|
8
|
+
const DATA_DIR = join(homedir(), ".claude-channel-daemon");
|
|
9
|
+
const SESSION_FILE = join(DATA_DIR, "session-id");
|
|
10
|
+
export const STATUSLINE_FILE = join(DATA_DIR, "statusline.json");
|
|
11
|
+
const STATUSLINE_SCRIPT = join(DATA_DIR, "statusline.sh");
|
|
12
|
+
export class ProcessManager extends EventEmitter {
|
|
13
|
+
config;
|
|
14
|
+
logger;
|
|
15
|
+
term = null;
|
|
16
|
+
running = false;
|
|
17
|
+
retryCount = 0;
|
|
18
|
+
shuttingDown = false;
|
|
19
|
+
restartTimer = null;
|
|
20
|
+
uptimeTimer = null;
|
|
21
|
+
sessionId = null;
|
|
22
|
+
suppressSessionCapture = false;
|
|
23
|
+
constructor(config, logger) {
|
|
24
|
+
super();
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.logger = logger;
|
|
27
|
+
this.loadSessionId();
|
|
28
|
+
}
|
|
29
|
+
isRunning() {
|
|
30
|
+
return this.running;
|
|
31
|
+
}
|
|
32
|
+
async start() {
|
|
33
|
+
if (this.running) {
|
|
34
|
+
this.logger.warn("Process already running");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.shuttingDown = false;
|
|
38
|
+
this.suppressSessionCapture = false;
|
|
39
|
+
this.ensureSpawnHelper();
|
|
40
|
+
this.ensureStatusLineScript();
|
|
41
|
+
this.spawnChild();
|
|
42
|
+
}
|
|
43
|
+
async stop() {
|
|
44
|
+
this.shuttingDown = true;
|
|
45
|
+
if (this.restartTimer) {
|
|
46
|
+
clearTimeout(this.restartTimer);
|
|
47
|
+
this.restartTimer = null;
|
|
48
|
+
}
|
|
49
|
+
if (this.uptimeTimer) {
|
|
50
|
+
clearTimeout(this.uptimeTimer);
|
|
51
|
+
this.uptimeTimer = null;
|
|
52
|
+
}
|
|
53
|
+
if (!this.term)
|
|
54
|
+
return;
|
|
55
|
+
// Send /exit to claude for graceful shutdown
|
|
56
|
+
this.term.write("/exit\r");
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
const forceKillTimer = setTimeout(() => {
|
|
59
|
+
try {
|
|
60
|
+
this.term?.kill();
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
}, 5000);
|
|
64
|
+
this.term.onExit(() => {
|
|
65
|
+
clearTimeout(forceKillTimer);
|
|
66
|
+
this.term = null;
|
|
67
|
+
this.running = false;
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/** Clear saved session ID so next start creates a fresh session. */
|
|
73
|
+
clearSessionId() {
|
|
74
|
+
this.sessionId = null;
|
|
75
|
+
this.suppressSessionCapture = true;
|
|
76
|
+
this.saveSessionId();
|
|
77
|
+
this.logger.info("Session ID cleared — next start will create a fresh session");
|
|
78
|
+
}
|
|
79
|
+
sendInput(text) {
|
|
80
|
+
if (!this.term || !this.running) {
|
|
81
|
+
this.logger.warn("Cannot send input: process not running");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.term.write(text + "\r");
|
|
85
|
+
}
|
|
86
|
+
ensureStatusLineScript() {
|
|
87
|
+
// Tee stdin JSON to our file, then pipe to the user's original statusLine command.
|
|
88
|
+
const script = `#!/bin/bash
|
|
89
|
+
INPUT=$(cat)
|
|
90
|
+
echo "$INPUT" > "${STATUSLINE_FILE}"
|
|
91
|
+
if command -v ccline &>/dev/null; then
|
|
92
|
+
echo "$INPUT" | ccline
|
|
93
|
+
else
|
|
94
|
+
echo "ok"
|
|
95
|
+
fi
|
|
96
|
+
`;
|
|
97
|
+
writeFileSync(STATUSLINE_SCRIPT, script, { mode: 0o755 });
|
|
98
|
+
// Write a settings file (not CLI flag) so it doesn't conflict with
|
|
99
|
+
// other --settings injected by tools like cmux
|
|
100
|
+
const settingsFile = join(DATA_DIR, "claude-settings.json");
|
|
101
|
+
const settings = {
|
|
102
|
+
hooks: {
|
|
103
|
+
PreToolUse: [
|
|
104
|
+
{
|
|
105
|
+
matcher: "*",
|
|
106
|
+
hooks: [
|
|
107
|
+
{
|
|
108
|
+
type: "command",
|
|
109
|
+
command: "curl -s -X POST http://127.0.0.1:18321/approve -H 'Content-Type: application/json' -d @- --max-time 130 --connect-timeout 1 || echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"approval server unreachable — denied for safety\"}}'",
|
|
110
|
+
timeout: 135000,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
permissions: {
|
|
117
|
+
allow: [
|
|
118
|
+
"Read", "Edit", "Write", "Glob", "Grep",
|
|
119
|
+
"Bash(*)", "WebFetch", "WebSearch", "Agent", "Skill",
|
|
120
|
+
"mcp__plugin_telegram_telegram__reply",
|
|
121
|
+
"mcp__plugin_telegram_telegram__react",
|
|
122
|
+
"mcp__plugin_telegram_telegram__edit_message",
|
|
123
|
+
],
|
|
124
|
+
deny: [
|
|
125
|
+
"Bash(rm -rf /)", "Bash(rm -rf /*)",
|
|
126
|
+
"Bash(rm -rf ~)", "Bash(rm -rf ~/*)",
|
|
127
|
+
"Bash(git push * --force *)", "Bash(git push --force *)",
|
|
128
|
+
"Bash(git reset --hard *)", "Bash(git clean -fd *)",
|
|
129
|
+
"Bash(git clean -f *)", "Bash(dd *)", "Bash(mkfs *)",
|
|
130
|
+
],
|
|
131
|
+
defaultMode: "default",
|
|
132
|
+
},
|
|
133
|
+
statusLine: {
|
|
134
|
+
type: "command",
|
|
135
|
+
command: STATUSLINE_SCRIPT,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
writeFileSync(settingsFile, JSON.stringify(settings));
|
|
139
|
+
}
|
|
140
|
+
ensureSpawnHelper() {
|
|
141
|
+
// node-pty's spawn-helper loses +x after npm install on macOS
|
|
142
|
+
try {
|
|
143
|
+
const helperPath = join(process.cwd(), "node_modules/node-pty/prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
|
|
144
|
+
if (existsSync(helperPath)) {
|
|
145
|
+
execFileSync("chmod", ["+x", helperPath]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// Best effort — may not be needed on all platforms
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
resolveClaudeBin() {
|
|
153
|
+
try {
|
|
154
|
+
return execSync("which claude", { encoding: "utf8" }).trim();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return "claude";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
spawnChild() {
|
|
161
|
+
const claudeBin = this.resolveClaudeBin();
|
|
162
|
+
const args = [];
|
|
163
|
+
// Channel mode: route Telegram messages as user prompts
|
|
164
|
+
args.push("--channels", `plugin:${this.config.channel_plugin}`);
|
|
165
|
+
// Settings file has: permissions (bypassPermissions), PreToolUse hook (→ Telegram approval), statusLine
|
|
166
|
+
const settingsFile = join(DATA_DIR, "claude-settings.json");
|
|
167
|
+
args.push("--settings", settingsFile);
|
|
168
|
+
// Resume previous session if available
|
|
169
|
+
if (this.sessionId) {
|
|
170
|
+
args.push("--resume", this.sessionId);
|
|
171
|
+
this.logger.info({ sessionId: this.sessionId }, "Resuming previous session");
|
|
172
|
+
}
|
|
173
|
+
this.logger.info({ claudeBin, args: args.map(a => a.length > 50 ? a.slice(0, 50) + "..." : a), cwd: this.config.working_directory }, "Spawning claude via PTY");
|
|
174
|
+
this.term = pty.spawn(claudeBin, args, {
|
|
175
|
+
name: "xterm-256color",
|
|
176
|
+
cols: 220,
|
|
177
|
+
rows: 50,
|
|
178
|
+
cwd: this.config.working_directory,
|
|
179
|
+
env: {
|
|
180
|
+
...process.env,
|
|
181
|
+
TERM: "xterm-256color",
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
this.running = true;
|
|
185
|
+
this.term.onData((data) => {
|
|
186
|
+
const clean = stripAnsi(data);
|
|
187
|
+
if (clean.trim()) {
|
|
188
|
+
this.emit("stdout", clean);
|
|
189
|
+
this.logger.debug({ stdout: clean.trim().slice(0, 200) }, "claude stdout");
|
|
190
|
+
}
|
|
191
|
+
// Handle PTY permission prompts (hard-coded path protection)
|
|
192
|
+
// These only fire for .git/, .claude/, .vscode/, .idea/ writes
|
|
193
|
+
// that bypass acceptEdits. PreToolUse hook already handles tool-level permissions.
|
|
194
|
+
// Claude Code shows: "1.Yes 2.Yes,andallow... 3.No"
|
|
195
|
+
if (clean.includes("1.Yes") && clean.includes("3.No")) {
|
|
196
|
+
this.logger.warn("PTY permission prompt detected — forwarding to Telegram");
|
|
197
|
+
this.emit("permission_prompt", clean);
|
|
198
|
+
}
|
|
199
|
+
// Capture session ID from output (claude prints: claude --resume <uuid>)
|
|
200
|
+
const resumeMatch = clean.match(/--resume\s+([0-9a-f-]{36})/);
|
|
201
|
+
if (resumeMatch && !this.suppressSessionCapture) {
|
|
202
|
+
this.sessionId = resumeMatch[1];
|
|
203
|
+
this.saveSessionId();
|
|
204
|
+
this.logger.info({ sessionId: this.sessionId }, "Captured session ID for resume");
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
this.term.onExit(({ exitCode, signal }) => {
|
|
208
|
+
this.logger.info({ exitCode, signal }, "claude process exited");
|
|
209
|
+
this.term = null;
|
|
210
|
+
this.running = false;
|
|
211
|
+
this.emit("exited", { code: exitCode, signal });
|
|
212
|
+
if (!this.shuttingDown) {
|
|
213
|
+
this.scheduleRestart();
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// Reset retry counter after stable uptime
|
|
217
|
+
this.uptimeTimer = setTimeout(() => {
|
|
218
|
+
this.retryCount = 0;
|
|
219
|
+
this.logger.info("Uptime threshold reached, retry counter reset");
|
|
220
|
+
}, this.config.restart_policy.reset_after * 1000);
|
|
221
|
+
this.emit("started");
|
|
222
|
+
}
|
|
223
|
+
scheduleRestart() {
|
|
224
|
+
if (this.shuttingDown)
|
|
225
|
+
return;
|
|
226
|
+
if (this.retryCount >= this.config.restart_policy.max_retries) {
|
|
227
|
+
this.logger.error("Max retries reached, giving up");
|
|
228
|
+
this.emit("max_retries_reached");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const delay = this.getBackoffDelay(this.retryCount);
|
|
232
|
+
this.retryCount++;
|
|
233
|
+
this.logger.info({ delay, retryCount: this.retryCount }, "Scheduling restart");
|
|
234
|
+
this.restartTimer = setTimeout(() => {
|
|
235
|
+
this.spawnChild();
|
|
236
|
+
}, delay);
|
|
237
|
+
}
|
|
238
|
+
getBackoffDelay(attempt) {
|
|
239
|
+
const base = 1000;
|
|
240
|
+
const max = 60000;
|
|
241
|
+
if (this.config.restart_policy.backoff === "exponential") {
|
|
242
|
+
return Math.min(base * Math.pow(2, attempt), max);
|
|
243
|
+
}
|
|
244
|
+
return Math.min(base * (attempt + 1), max);
|
|
245
|
+
}
|
|
246
|
+
loadSessionId() {
|
|
247
|
+
try {
|
|
248
|
+
if (existsSync(SESSION_FILE)) {
|
|
249
|
+
this.sessionId = readFileSync(SESSION_FILE, "utf-8").trim();
|
|
250
|
+
if (this.sessionId) {
|
|
251
|
+
this.logger.info({ sessionId: this.sessionId }, "Loaded previous session ID");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch { }
|
|
256
|
+
}
|
|
257
|
+
saveSessionId() {
|
|
258
|
+
try {
|
|
259
|
+
writeFileSync(SESSION_FILE, this.sessionId ?? "");
|
|
260
|
+
}
|
|
261
|
+
catch { }
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=process-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Schedule, ScheduleRun, CreateScheduleParams, UpdateScheduleParams } from "./types.js";
|
|
2
|
+
export declare class SchedulerDb {
|
|
3
|
+
private db;
|
|
4
|
+
constructor(dbPath: string);
|
|
5
|
+
private rowToSchedule;
|
|
6
|
+
create(params: CreateScheduleParams, maxSchedules?: number): Schedule;
|
|
7
|
+
get(id: string): Schedule | null;
|
|
8
|
+
list(target?: string): Schedule[];
|
|
9
|
+
update(id: string, params: UpdateScheduleParams): Schedule;
|
|
10
|
+
delete(id: string): void;
|
|
11
|
+
deleteByInstanceOrThread(instanceName: string, threadId: string): number;
|
|
12
|
+
recordRun(scheduleId: string, status: string, detail?: string): void;
|
|
13
|
+
getRuns(scheduleId: string, limit?: number): ScheduleRun[];
|
|
14
|
+
pruneOldRuns(days?: number): void;
|
|
15
|
+
close(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
export class SchedulerDb {
|
|
4
|
+
db;
|
|
5
|
+
constructor(dbPath) {
|
|
6
|
+
this.db = new Database(dbPath);
|
|
7
|
+
this.db.pragma("journal_mode = WAL");
|
|
8
|
+
this.db.pragma("foreign_keys = ON");
|
|
9
|
+
this.db.exec(`
|
|
10
|
+
CREATE TABLE IF NOT EXISTS schedules (
|
|
11
|
+
id TEXT PRIMARY KEY,
|
|
12
|
+
cron TEXT NOT NULL,
|
|
13
|
+
message TEXT NOT NULL,
|
|
14
|
+
source TEXT NOT NULL,
|
|
15
|
+
target TEXT NOT NULL,
|
|
16
|
+
reply_chat_id TEXT NOT NULL,
|
|
17
|
+
reply_thread_id TEXT,
|
|
18
|
+
label TEXT,
|
|
19
|
+
enabled INTEGER DEFAULT 1,
|
|
20
|
+
timezone TEXT DEFAULT 'Asia/Taipei',
|
|
21
|
+
created_at TEXT NOT NULL,
|
|
22
|
+
last_triggered_at TEXT,
|
|
23
|
+
last_status TEXT
|
|
24
|
+
);
|
|
25
|
+
CREATE TABLE IF NOT EXISTS schedule_runs (
|
|
26
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
27
|
+
schedule_id TEXT NOT NULL REFERENCES schedules(id) ON DELETE CASCADE,
|
|
28
|
+
triggered_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
29
|
+
status TEXT NOT NULL,
|
|
30
|
+
detail TEXT
|
|
31
|
+
);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_schedule_runs_schedule_id ON schedule_runs(schedule_id);
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
rowToSchedule(row) {
|
|
36
|
+
return {
|
|
37
|
+
id: row.id,
|
|
38
|
+
cron: row.cron,
|
|
39
|
+
message: row.message,
|
|
40
|
+
source: row.source,
|
|
41
|
+
target: row.target,
|
|
42
|
+
reply_chat_id: row.reply_chat_id,
|
|
43
|
+
reply_thread_id: row.reply_thread_id,
|
|
44
|
+
label: row.label,
|
|
45
|
+
enabled: row.enabled === 1,
|
|
46
|
+
timezone: row.timezone,
|
|
47
|
+
created_at: row.created_at,
|
|
48
|
+
last_triggered_at: row.last_triggered_at,
|
|
49
|
+
last_status: row.last_status,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
create(params, maxSchedules = 100) {
|
|
53
|
+
const count = this.db.prepare("SELECT COUNT(*) as c FROM schedules").get();
|
|
54
|
+
if (count.c >= maxSchedules) {
|
|
55
|
+
throw new Error(`Schedule limit reached (${maxSchedules}). Delete existing schedules first.`);
|
|
56
|
+
}
|
|
57
|
+
const id = randomUUID();
|
|
58
|
+
const now = new Date().toISOString();
|
|
59
|
+
this.db.prepare(`
|
|
60
|
+
INSERT INTO schedules (id, cron, message, source, target, reply_chat_id, reply_thread_id, label, timezone, created_at)
|
|
61
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
62
|
+
`).run(id, params.cron, params.message, params.source, params.target, params.reply_chat_id, params.reply_thread_id, params.label ?? null, params.timezone ?? "Asia/Taipei", now);
|
|
63
|
+
return this.get(id);
|
|
64
|
+
}
|
|
65
|
+
get(id) {
|
|
66
|
+
const row = this.db.prepare("SELECT * FROM schedules WHERE id = ?").get(id);
|
|
67
|
+
return row ? this.rowToSchedule(row) : null;
|
|
68
|
+
}
|
|
69
|
+
list(target) {
|
|
70
|
+
const rows = target
|
|
71
|
+
? this.db.prepare("SELECT * FROM schedules WHERE target = ? ORDER BY created_at").all(target)
|
|
72
|
+
: this.db.prepare("SELECT * FROM schedules ORDER BY created_at").all();
|
|
73
|
+
return rows.map((r) => this.rowToSchedule(r));
|
|
74
|
+
}
|
|
75
|
+
update(id, params) {
|
|
76
|
+
const existing = this.get(id);
|
|
77
|
+
if (!existing)
|
|
78
|
+
throw new Error(`Schedule "${id}" not found`);
|
|
79
|
+
const sets = [];
|
|
80
|
+
const values = [];
|
|
81
|
+
if (params.cron !== undefined) {
|
|
82
|
+
sets.push("cron = ?");
|
|
83
|
+
values.push(params.cron);
|
|
84
|
+
}
|
|
85
|
+
if (params.message !== undefined) {
|
|
86
|
+
sets.push("message = ?");
|
|
87
|
+
values.push(params.message);
|
|
88
|
+
}
|
|
89
|
+
if (params.target !== undefined) {
|
|
90
|
+
sets.push("target = ?");
|
|
91
|
+
values.push(params.target);
|
|
92
|
+
}
|
|
93
|
+
if (params.label !== undefined) {
|
|
94
|
+
sets.push("label = ?");
|
|
95
|
+
values.push(params.label);
|
|
96
|
+
}
|
|
97
|
+
if (params.timezone !== undefined) {
|
|
98
|
+
sets.push("timezone = ?");
|
|
99
|
+
values.push(params.timezone);
|
|
100
|
+
}
|
|
101
|
+
if (params.enabled !== undefined) {
|
|
102
|
+
sets.push("enabled = ?");
|
|
103
|
+
values.push(params.enabled ? 1 : 0);
|
|
104
|
+
}
|
|
105
|
+
if (sets.length > 0) {
|
|
106
|
+
values.push(id);
|
|
107
|
+
this.db.prepare(`UPDATE schedules SET ${sets.join(", ")} WHERE id = ?`).run(...values);
|
|
108
|
+
}
|
|
109
|
+
return this.get(id) ?? existing;
|
|
110
|
+
}
|
|
111
|
+
delete(id) {
|
|
112
|
+
this.db.prepare("DELETE FROM schedules WHERE id = ?").run(id);
|
|
113
|
+
}
|
|
114
|
+
deleteByInstanceOrThread(instanceName, threadId) {
|
|
115
|
+
const result = this.db.prepare("DELETE FROM schedules WHERE target = ? OR reply_thread_id = ?").run(instanceName, threadId);
|
|
116
|
+
return result.changes;
|
|
117
|
+
}
|
|
118
|
+
recordRun(scheduleId, status, detail) {
|
|
119
|
+
this.db.prepare("INSERT INTO schedule_runs (schedule_id, status, detail) VALUES (?, ?, ?)").run(scheduleId, status, detail ?? null);
|
|
120
|
+
this.db.prepare("UPDATE schedules SET last_triggered_at = datetime('now'), last_status = ? WHERE id = ?").run(status, scheduleId);
|
|
121
|
+
}
|
|
122
|
+
getRuns(scheduleId, limit = 50) {
|
|
123
|
+
return this.db.prepare("SELECT * FROM schedule_runs WHERE schedule_id = ? ORDER BY triggered_at DESC, id DESC LIMIT ?").all(scheduleId, limit);
|
|
124
|
+
}
|
|
125
|
+
pruneOldRuns(days = 30) {
|
|
126
|
+
this.db.prepare("DELETE FROM schedule_runs WHERE triggered_at < datetime('now', '-' || ? || ' days')").run(days);
|
|
127
|
+
}
|
|
128
|
+
close() {
|
|
129
|
+
this.db.close();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/scheduler/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|