@emqo/claudebridge 0.5.3 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/discord.js +6 -1
- package/dist/adapters/telegram.js +6 -1
- package/dist/core/i18n.js +2 -0
- package/dist/core/store.d.ts +4 -2
- package/dist/core/store.js +20 -10
- package/dist/ctl.js +22 -6
- package/dist/skills/bridge.js +74 -0
- package/dist/webhook.js +4 -3
- package/package.json +2 -2
package/dist/adapters/discord.js
CHANGED
|
@@ -304,7 +304,12 @@ export class DiscordAdapter {
|
|
|
304
304
|
};
|
|
305
305
|
const lines = recent.map(task => {
|
|
306
306
|
const chain = task.parent_id ? ` (chain #${task.parent_id})` : "";
|
|
307
|
-
|
|
307
|
+
let schedInfo = "";
|
|
308
|
+
if (task.status === "auto" && task.scheduled_at && task.scheduled_at > Date.now()) {
|
|
309
|
+
const mins = Math.ceil((task.scheduled_at - Date.now()) / 60000);
|
|
310
|
+
schedInfo = ` [in ${mins}min]`;
|
|
311
|
+
}
|
|
312
|
+
return `${statusEmoji[task.status] || "[?]"} #${task.id} [${task.status}]${schedInfo} ${task.description.slice(0, 60)}${chain}`;
|
|
308
313
|
});
|
|
309
314
|
const stats = this.store.getAutoTaskStats();
|
|
310
315
|
const summary = stats.map(s => `${s.status}: ${s.count}`).join(" | ");
|
|
@@ -515,7 +515,12 @@ export class TelegramAdapter {
|
|
|
515
515
|
};
|
|
516
516
|
const lines = recent.map(task => {
|
|
517
517
|
const chain = task.parent_id ? ` (chain #${task.parent_id})` : "";
|
|
518
|
-
|
|
518
|
+
let schedInfo = "";
|
|
519
|
+
if (task.status === "auto" && task.scheduled_at && task.scheduled_at > Date.now()) {
|
|
520
|
+
const mins = Math.ceil((task.scheduled_at - Date.now()) / 60000);
|
|
521
|
+
schedInfo = ` [in ${mins}min]`;
|
|
522
|
+
}
|
|
523
|
+
return `${statusEmoji[task.status] || "[?]"} #${task.id} [${task.status}]${schedInfo} ${task.description.slice(0, 60)}${chain}`;
|
|
519
524
|
});
|
|
520
525
|
const stats = this.store.getAutoTaskStats();
|
|
521
526
|
const summary = stats.map(s => `${s.status}: ${s.count}`).join(" | ");
|
package/dist/core/i18n.js
CHANGED
|
@@ -11,6 +11,7 @@ const messages = {
|
|
|
11
11
|
upload_failed: "Upload failed: ",
|
|
12
12
|
reminder_notify: "Reminder: {desc}",
|
|
13
13
|
auto_starting: "Auto task #{id} starting:\n{desc}",
|
|
14
|
+
auto_scheduled: "Auto task #{id} scheduled (executes in {minutes} min):\n{desc}",
|
|
14
15
|
auto_done: "Auto task #{id} done (cost: ${cost}):",
|
|
15
16
|
auto_failed: "Auto task #{id} failed: {err}",
|
|
16
17
|
page_expired: "Page expired. Please resend your question.",
|
|
@@ -34,6 +35,7 @@ const messages = {
|
|
|
34
35
|
upload_failed: "上传失败:",
|
|
35
36
|
reminder_notify: "提醒:{desc}",
|
|
36
37
|
auto_starting: "自动任务 #{id} 开始执行:\n{desc}",
|
|
38
|
+
auto_scheduled: "自动任务 #{id} 已排程({minutes} 分钟后执行):\n{desc}",
|
|
37
39
|
auto_done: "自动任务 #{id} 完成(花费:${cost}):",
|
|
38
40
|
auto_failed: "自动任务 #{id} 失败:{err}",
|
|
39
41
|
page_expired: "页面已过期,请重新发送问题。",
|
package/dist/core/store.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export declare class Store {
|
|
|
30
30
|
}[];
|
|
31
31
|
clearMemories(userId: string): void;
|
|
32
32
|
trimMemories(userId: string, max: number): void;
|
|
33
|
-
addTask(userId: string, platform: string, chatId: string, description: string, remindAt?: number, auto?: boolean, parentId?: number): number;
|
|
33
|
+
addTask(userId: string, platform: string, chatId: string, description: string, remindAt?: number, auto?: boolean, parentId?: number, scheduledAt?: number): number;
|
|
34
34
|
getTasks(userId: string): {
|
|
35
35
|
id: number;
|
|
36
36
|
description: string;
|
|
@@ -60,9 +60,10 @@ export declare class Store {
|
|
|
60
60
|
id: number;
|
|
61
61
|
description: string;
|
|
62
62
|
status: string;
|
|
63
|
+
scheduled_at: number | null;
|
|
63
64
|
created_at: number;
|
|
64
65
|
}[];
|
|
65
|
-
addApprovalTask(userId: string, platform: string, chatId: string, description: string, parentId?: number): number;
|
|
66
|
+
addApprovalTask(userId: string, platform: string, chatId: string, description: string, parentId?: number, scheduledAt?: number): number;
|
|
66
67
|
getPendingApprovals(platform: string): {
|
|
67
68
|
id: number;
|
|
68
69
|
user_id: string;
|
|
@@ -104,6 +105,7 @@ export declare class Store {
|
|
|
104
105
|
description: string;
|
|
105
106
|
status: string;
|
|
106
107
|
parent_id: number | null;
|
|
108
|
+
scheduled_at: number | null;
|
|
107
109
|
created_at: number;
|
|
108
110
|
}[];
|
|
109
111
|
}
|
package/dist/core/store.js
CHANGED
|
@@ -55,7 +55,7 @@ export class Store {
|
|
|
55
55
|
CREATE INDEX IF NOT EXISTS idx_memories_user ON memories(user_id);
|
|
56
56
|
CREATE INDEX IF NOT EXISTS idx_tasks_user ON tasks(user_id, status);
|
|
57
57
|
`);
|
|
58
|
-
// Schema migration: add parent_id and
|
|
58
|
+
// Schema migration: add parent_id, result, and scheduled_at columns
|
|
59
59
|
try {
|
|
60
60
|
this.db.exec("ALTER TABLE tasks ADD COLUMN parent_id INTEGER");
|
|
61
61
|
}
|
|
@@ -64,7 +64,16 @@ export class Store {
|
|
|
64
64
|
this.db.exec("ALTER TABLE tasks ADD COLUMN result TEXT");
|
|
65
65
|
}
|
|
66
66
|
catch { }
|
|
67
|
+
try {
|
|
68
|
+
this.db.exec("ALTER TABLE tasks ADD COLUMN scheduled_at INTEGER");
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
67
71
|
this.db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_id)");
|
|
72
|
+
// Startup recovery: reset orphaned 'running' tasks back to 'auto' so they get re-executed
|
|
73
|
+
const recovered = this.db.prepare("UPDATE tasks SET status = 'auto' WHERE status = 'running'").run();
|
|
74
|
+
if (recovered.changes > 0) {
|
|
75
|
+
console.log(`[store] recovered ${recovered.changes} orphaned running task(s) back to auto queue`);
|
|
76
|
+
}
|
|
68
77
|
}
|
|
69
78
|
// --- sessions ---
|
|
70
79
|
getSession(userId) {
|
|
@@ -130,8 +139,8 @@ export class Store {
|
|
|
130
139
|
this.db.prepare("DELETE FROM memories WHERE user_id = ? AND id NOT IN (SELECT id FROM memories WHERE user_id = ? ORDER BY created_at DESC LIMIT ?)").run(userId, userId, max);
|
|
131
140
|
}
|
|
132
141
|
// --- tasks ---
|
|
133
|
-
addTask(userId, platform, chatId, description, remindAt, auto = false, parentId) {
|
|
134
|
-
const r = this.db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, remind_at, parent_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(userId, platform, chatId, description, auto ? "auto" : "pending", remindAt ?? null, parentId ?? null, Date.now());
|
|
142
|
+
addTask(userId, platform, chatId, description, remindAt, auto = false, parentId, scheduledAt) {
|
|
143
|
+
const r = this.db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, remind_at, parent_id, scheduled_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(userId, platform, chatId, description, auto ? "auto" : "pending", remindAt ?? null, parentId ?? null, scheduledAt ?? null, Date.now());
|
|
135
144
|
return Number(r.lastInsertRowid);
|
|
136
145
|
}
|
|
137
146
|
getTasks(userId) {
|
|
@@ -148,10 +157,11 @@ export class Store {
|
|
|
148
157
|
this.db.prepare("UPDATE tasks SET reminder_sent = 1 WHERE id = ?").run(taskId);
|
|
149
158
|
}
|
|
150
159
|
getNextAutoTask(platform) {
|
|
160
|
+
const now = Date.now();
|
|
151
161
|
if (platform) {
|
|
152
|
-
return this.db.prepare("SELECT id, user_id, platform, chat_id, description FROM tasks WHERE status = 'auto' AND platform = ? ORDER BY created_at ASC LIMIT 1").get(platform) ?? null;
|
|
162
|
+
return this.db.prepare("SELECT id, user_id, platform, chat_id, description FROM tasks WHERE status = 'auto' AND platform = ? AND (scheduled_at IS NULL OR scheduled_at <= ?) ORDER BY created_at ASC LIMIT 1").get(platform, now) ?? null;
|
|
153
163
|
}
|
|
154
|
-
return this.db.prepare("SELECT id, user_id, platform, chat_id, description FROM tasks WHERE status = 'auto' ORDER BY created_at ASC LIMIT 1").get() ?? null;
|
|
164
|
+
return this.db.prepare("SELECT id, user_id, platform, chat_id, description FROM tasks WHERE status = 'auto' AND (scheduled_at IS NULL OR scheduled_at <= ?) ORDER BY created_at ASC LIMIT 1").get(now) ?? null;
|
|
155
165
|
}
|
|
156
166
|
markTaskRunning(taskId) {
|
|
157
167
|
this.db.prepare("UPDATE tasks SET status = 'running' WHERE id = ?").run(taskId);
|
|
@@ -160,11 +170,11 @@ export class Store {
|
|
|
160
170
|
this.db.prepare("UPDATE tasks SET status = ? WHERE id = ?").run(status, taskId);
|
|
161
171
|
}
|
|
162
172
|
getAutoTasks(userId) {
|
|
163
|
-
return this.db.prepare("SELECT id, description, status, created_at FROM tasks WHERE user_id = ? AND status IN ('auto','running') ORDER BY created_at DESC").all(userId);
|
|
173
|
+
return this.db.prepare("SELECT id, description, status, scheduled_at, created_at FROM tasks WHERE user_id = ? AND status IN ('auto','running') ORDER BY created_at DESC").all(userId);
|
|
164
174
|
}
|
|
165
175
|
// --- HITL (Human-in-the-Loop) ---
|
|
166
|
-
addApprovalTask(userId, platform, chatId, description, parentId) {
|
|
167
|
-
const r = this.db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, parent_id, created_at) VALUES (?, ?, ?, ?, 'approval_pending', ?, ?)").run(userId, platform, chatId, description, parentId ?? null, Date.now());
|
|
176
|
+
addApprovalTask(userId, platform, chatId, description, parentId, scheduledAt) {
|
|
177
|
+
const r = this.db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, parent_id, scheduled_at, created_at) VALUES (?, ?, ?, ?, 'approval_pending', ?, ?, ?)").run(userId, platform, chatId, description, parentId ?? null, scheduledAt ?? null, Date.now());
|
|
168
178
|
return Number(r.lastInsertRowid);
|
|
169
179
|
}
|
|
170
180
|
getPendingApprovals(platform) {
|
|
@@ -187,7 +197,7 @@ export class Store {
|
|
|
187
197
|
}
|
|
188
198
|
// --- Parallel ---
|
|
189
199
|
getNextAutoTasks(platform, limit) {
|
|
190
|
-
return this.db.prepare("SELECT id, user_id, platform, chat_id, description, parent_id FROM tasks WHERE status = 'auto' AND platform = ? ORDER BY created_at ASC LIMIT ?").all(platform, limit);
|
|
200
|
+
return this.db.prepare("SELECT id, user_id, platform, chat_id, description, parent_id FROM tasks WHERE status = 'auto' AND platform = ? AND (scheduled_at IS NULL OR scheduled_at <= ?) ORDER BY created_at ASC LIMIT ?").all(platform, Date.now(), limit);
|
|
191
201
|
}
|
|
192
202
|
// --- Observability ---
|
|
193
203
|
getAutoTaskStats(userId) {
|
|
@@ -211,6 +221,6 @@ export class Store {
|
|
|
211
221
|
return result;
|
|
212
222
|
}
|
|
213
223
|
getRecentAutoTasks(platform, limit) {
|
|
214
|
-
return this.db.prepare("SELECT id, user_id, description, status, parent_id, created_at FROM tasks WHERE platform = ? AND status IN ('auto','running','done','failed','approval_pending','cancelled') ORDER BY created_at DESC LIMIT ?").all(platform, limit);
|
|
224
|
+
return this.db.prepare("SELECT id, user_id, description, status, parent_id, scheduled_at, created_at FROM tasks WHERE platform = ? AND status IN ('auto','running','done','failed','approval_pending','cancelled') ORDER BY created_at DESC LIMIT ?").all(platform, limit);
|
|
215
225
|
}
|
|
216
226
|
}
|
package/dist/ctl.js
CHANGED
|
@@ -109,23 +109,39 @@ else if (category === "auto") {
|
|
|
109
109
|
parentId = parseInt(descParts[parentIdx + 1]);
|
|
110
110
|
descParts.splice(parentIdx, 2);
|
|
111
111
|
}
|
|
112
|
+
// Parse optional --delay flag
|
|
113
|
+
let scheduledAt = null;
|
|
114
|
+
const delayIdx = descParts.indexOf("--delay");
|
|
115
|
+
if (delayIdx !== -1 && descParts[delayIdx + 1]) {
|
|
116
|
+
const delayMin = parseInt(descParts[delayIdx + 1]);
|
|
117
|
+
scheduledAt = Date.now() + delayMin * 60000;
|
|
118
|
+
descParts.splice(delayIdx, 2);
|
|
119
|
+
}
|
|
112
120
|
const desc = descParts.join(" ");
|
|
113
|
-
const r = db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, parent_id, created_at) VALUES (?, ?, ?, ?, 'auto', ?, ?)").run(userId, platform, chatId, desc, parentId, Date.now());
|
|
114
|
-
output({ ok: true, id: Number(r.lastInsertRowid), message: "Auto task queued" });
|
|
121
|
+
const r = db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, parent_id, scheduled_at, created_at) VALUES (?, ?, ?, ?, 'auto', ?, ?, ?)").run(userId, platform, chatId, desc, parentId, scheduledAt, Date.now());
|
|
122
|
+
output({ ok: true, id: Number(r.lastInsertRowid), scheduled_at: scheduledAt, message: scheduledAt ? `Auto task scheduled (in ${Math.ceil((scheduledAt - Date.now()) / 60000)} min)` : "Auto task queued" });
|
|
115
123
|
}
|
|
116
124
|
else if (action === "add-approval") {
|
|
117
125
|
const [userId, platform, chatId, ...descParts] = rest;
|
|
118
126
|
if (!userId || !platform || !chatId || !descParts.length)
|
|
119
|
-
fail("Usage: auto add-approval <user_id> <platform> <chat_id> <description> [--parent <id>]");
|
|
127
|
+
fail("Usage: auto add-approval <user_id> <platform> <chat_id> <description> [--parent <id>] [--delay <minutes>]");
|
|
120
128
|
let parentId = null;
|
|
121
129
|
const parentIdx = descParts.indexOf("--parent");
|
|
122
130
|
if (parentIdx !== -1 && descParts[parentIdx + 1]) {
|
|
123
131
|
parentId = parseInt(descParts[parentIdx + 1]);
|
|
124
132
|
descParts.splice(parentIdx, 2);
|
|
125
133
|
}
|
|
134
|
+
// Parse optional --delay flag
|
|
135
|
+
let scheduledAt = null;
|
|
136
|
+
const delayIdx = descParts.indexOf("--delay");
|
|
137
|
+
if (delayIdx !== -1 && descParts[delayIdx + 1]) {
|
|
138
|
+
const delayMin = parseInt(descParts[delayIdx + 1]);
|
|
139
|
+
scheduledAt = Date.now() + delayMin * 60000;
|
|
140
|
+
descParts.splice(delayIdx, 2);
|
|
141
|
+
}
|
|
126
142
|
const desc = descParts.join(" ");
|
|
127
|
-
const r = db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, parent_id, created_at) VALUES (?, ?, ?, ?, 'approval_pending', ?, ?)").run(userId, platform, chatId, desc, parentId, Date.now());
|
|
128
|
-
output({ ok: true, id: Number(r.lastInsertRowid), message: "Auto task queued for approval" });
|
|
143
|
+
const r = db.prepare("INSERT INTO tasks (user_id, platform, chat_id, description, status, parent_id, scheduled_at, created_at) VALUES (?, ?, ?, ?, 'approval_pending', ?, ?, ?)").run(userId, platform, chatId, desc, parentId, scheduledAt, Date.now());
|
|
144
|
+
output({ ok: true, id: Number(r.lastInsertRowid), scheduled_at: scheduledAt, message: scheduledAt ? `Auto task queued for approval (scheduled in ${Math.ceil((scheduledAt - Date.now()) / 60000)} min)` : "Auto task queued for approval" });
|
|
129
145
|
}
|
|
130
146
|
else if (action === "result") {
|
|
131
147
|
const [taskId, ...resultParts] = rest;
|
|
@@ -139,7 +155,7 @@ else if (category === "auto") {
|
|
|
139
155
|
const [userId] = rest;
|
|
140
156
|
if (!userId)
|
|
141
157
|
fail("Usage: auto list <user_id>");
|
|
142
|
-
const rows = db.prepare("SELECT id, description, status, created_at FROM tasks WHERE user_id = ? AND status IN ('auto','running') ORDER BY created_at DESC").all(userId);
|
|
158
|
+
const rows = db.prepare("SELECT id, description, status, scheduled_at, created_at FROM tasks WHERE user_id = ? AND status IN ('auto','running') ORDER BY created_at DESC").all(userId);
|
|
143
159
|
output({ ok: true, tasks: rows });
|
|
144
160
|
}
|
|
145
161
|
else if (action === "cancel") {
|
package/dist/skills/bridge.js
CHANGED
|
@@ -30,6 +30,7 @@ export function generateSkillDoc(ctx) {
|
|
|
30
30
|
``,
|
|
31
31
|
`### 自动任务`,
|
|
32
32
|
`- 创建自动任务: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "任务描述"\``,
|
|
33
|
+
`- 创建定时自动任务: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "任务描述" --delay <分钟数>\``,
|
|
33
34
|
`- 查看自动任务: \`${ctl} auto list ${ctx.userId}\``,
|
|
34
35
|
`- 取消自动任务: \`${ctl} auto cancel <任务ID>\``,
|
|
35
36
|
``,
|
|
@@ -75,6 +76,42 @@ export function generateSkillDoc(ctx) {
|
|
|
75
76
|
` 2. 任务#2: "修复N+1查询" (--parent 1)`,
|
|
76
77
|
` 3. 任务#3: "添加缓存层" (--parent 1)`,
|
|
77
78
|
` 4. 任务#4: "运行基准测试" (--parent 1)`,
|
|
79
|
+
``,
|
|
80
|
+
`### 定时自动任务`,
|
|
81
|
+
`- 用 --delay <分钟数> 安排延迟执行: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "任务描述" --delay 30\``,
|
|
82
|
+
`- 任务创建后不会立即执行,等到延迟时间到达后才进入执行队列`,
|
|
83
|
+
`- 适用场景:需要等待、验证、或时间间隔的任务`,
|
|
84
|
+
`- 可与 --parent 组合使用: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "验证部署" --delay 15 --parent 42\``,
|
|
85
|
+
`- 审批任务也支持延迟: \`${ctl} auto add-approval ${ctx.userId} ${ctx.platform} ${ctx.chatId} "描述" --delay 60\``,
|
|
86
|
+
``,
|
|
87
|
+
`### 自主项目管理模式`,
|
|
88
|
+
`当用户委托你全程管理一个项目时,使用以下模式:`,
|
|
89
|
+
``,
|
|
90
|
+
`**模式1:部署验证**`,
|
|
91
|
+
`- 任务1: "部署代码到staging"`,
|
|
92
|
+
`- 任务2 (--delay 15): "检查staging健康状态:访问/health端点,查看最近日志是否有错误"`,
|
|
93
|
+
`- 任务3 (--delay 30): "如果staging正常则部署到生产环境,否则回滚并报告"`,
|
|
94
|
+
``,
|
|
95
|
+
`**模式2:迭代开发**`,
|
|
96
|
+
`- 任务1: "分析项目,识别所有需要修改的点,保存到记忆"`,
|
|
97
|
+
`- 任务2 (--delay 2): "读取记忆,执行第一批修改,运行测试"`,
|
|
98
|
+
`- 任务3 (--delay 5): "检查测试结果,修复失败用例"`,
|
|
99
|
+
`- 任务4 (--delay 3): "运行完整集成测试,生成报告"`,
|
|
100
|
+
``,
|
|
101
|
+
`**模式3:监控巡检**`,
|
|
102
|
+
`- 任务1: "检查应用状态:CPU、内存、错误率"`,
|
|
103
|
+
`- 任务2 (--delay 60): "再次检查应用状态,与上次对比,如有恶化则创建告警任务"`,
|
|
104
|
+
``,
|
|
105
|
+
`**模式4:数据库迁移**`,
|
|
106
|
+
`- 任务1: "执行数据库迁移脚本"`,
|
|
107
|
+
`- 任务2 (--delay 30): "验证数据完整性:检查行数、约束、索引"`,
|
|
108
|
+
``,
|
|
109
|
+
`**关键原则:**`,
|
|
110
|
+
`- 需要等待验证的步骤必须用 --delay,不要立即执行`,
|
|
111
|
+
`- 每个任务描述必须完整自包含(全新会话执行)`,
|
|
112
|
+
`- 用 memory add 传递上下文,用 --parent 关联链路`,
|
|
113
|
+
`- 用 add-approval 保护破坏性操作(删除、部署、迁移)`,
|
|
114
|
+
`- 任务描述中加入"先用 memory list 读取前序任务结论"确保上下文`,
|
|
78
115
|
].join("\n");
|
|
79
116
|
}
|
|
80
117
|
return [
|
|
@@ -101,6 +138,7 @@ export function generateSkillDoc(ctx) {
|
|
|
101
138
|
``,
|
|
102
139
|
`### Auto Tasks`,
|
|
103
140
|
`- Queue an auto task: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "description"\``,
|
|
141
|
+
`- Schedule a delayed auto task: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "description" --delay <minutes>\``,
|
|
104
142
|
`- List auto tasks: \`${ctl} auto list ${ctx.userId}\``,
|
|
105
143
|
`- Cancel an auto task: \`${ctl} auto cancel <task_id>\``,
|
|
106
144
|
``,
|
|
@@ -146,5 +184,41 @@ export function generateSkillDoc(ctx) {
|
|
|
146
184
|
` 2. Task #2: "Fix N+1 queries" (--parent 1)`,
|
|
147
185
|
` 3. Task #3: "Add caching layer" (--parent 1)`,
|
|
148
186
|
` 4. Task #4: "Run benchmarks" (--parent 1)`,
|
|
187
|
+
``,
|
|
188
|
+
`### Scheduled Auto Tasks`,
|
|
189
|
+
`- Use --delay <minutes> to schedule delayed execution: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "description" --delay 30\``,
|
|
190
|
+
`- The task won't execute immediately -- it enters the queue only after the delay expires`,
|
|
191
|
+
`- Use cases: tasks that need waiting, verification, or time gaps between steps`,
|
|
192
|
+
`- Can combine with --parent: \`${ctl} auto add ${ctx.userId} ${ctx.platform} ${ctx.chatId} "verify deploy" --delay 15 --parent 42\``,
|
|
193
|
+
`- Approval tasks also support delay: \`${ctl} auto add-approval ${ctx.userId} ${ctx.platform} ${ctx.chatId} "desc" --delay 60\``,
|
|
194
|
+
``,
|
|
195
|
+
`### Autonomous Project Management Patterns`,
|
|
196
|
+
`When the user delegates full project management to you, use these patterns:`,
|
|
197
|
+
``,
|
|
198
|
+
`**Pattern 1: Deploy & Verify**`,
|
|
199
|
+
`- Task 1: "Deploy code to staging"`,
|
|
200
|
+
`- Task 2 (--delay 15): "Check staging health: hit /health endpoint, review recent logs for errors"`,
|
|
201
|
+
`- Task 3 (--delay 30): "If staging is healthy, deploy to production. Otherwise rollback and report."`,
|
|
202
|
+
``,
|
|
203
|
+
`**Pattern 2: Iterative Development**`,
|
|
204
|
+
`- Task 1: "Analyze project, identify all changes needed, save findings to memory"`,
|
|
205
|
+
`- Task 2 (--delay 2): "Read memory, execute first batch of changes, run tests"`,
|
|
206
|
+
`- Task 3 (--delay 5): "Check test results, fix any failures"`,
|
|
207
|
+
`- Task 4 (--delay 3): "Run full integration tests, generate report"`,
|
|
208
|
+
``,
|
|
209
|
+
`**Pattern 3: Monitoring / Health Check**`,
|
|
210
|
+
`- Task 1: "Check application status: CPU, memory, error rates"`,
|
|
211
|
+
`- Task 2 (--delay 60): "Re-check application status, compare with previous check, create alert tasks if degraded"`,
|
|
212
|
+
``,
|
|
213
|
+
`**Pattern 4: Database Migration**`,
|
|
214
|
+
`- Task 1: "Run database migration script"`,
|
|
215
|
+
`- Task 2 (--delay 30): "Verify data integrity: check row counts, constraints, indexes"`,
|
|
216
|
+
``,
|
|
217
|
+
`**Key principles:**`,
|
|
218
|
+
`- Steps that need wait/verification MUST use --delay, don't execute immediately`,
|
|
219
|
+
`- Each task description must be self-contained (runs in a fresh session)`,
|
|
220
|
+
`- Use memory add to pass context, use --parent to link chains`,
|
|
221
|
+
`- Use add-approval for destructive operations (delete, deploy, migrate)`,
|
|
222
|
+
`- Include "first run memory list to review prior task conclusions" in descriptions`,
|
|
149
223
|
].join("\n");
|
|
150
224
|
}
|
package/dist/webhook.js
CHANGED
|
@@ -60,13 +60,14 @@ export class WebhookServer {
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
let id;
|
|
63
|
+
const scheduledAt = data.delay_minutes ? Date.now() + data.delay_minutes * 60000 : undefined;
|
|
63
64
|
if (data.approval) {
|
|
64
|
-
id = this.store.addApprovalTask(data.user_id, data.platform, data.chat_id, data.description, data.parent_id);
|
|
65
|
+
id = this.store.addApprovalTask(data.user_id, data.platform, data.chat_id, data.description, data.parent_id, scheduledAt);
|
|
65
66
|
}
|
|
66
67
|
else {
|
|
67
|
-
id = this.store.addTask(data.user_id, data.platform, data.chat_id, data.description, undefined, true, data.parent_id);
|
|
68
|
+
id = this.store.addTask(data.user_id, data.platform, data.chat_id, data.description, undefined, true, data.parent_id, scheduledAt);
|
|
68
69
|
}
|
|
69
|
-
this.json(res, 201, { ok: true, id, status: data.approval ? "approval_pending" : "auto" });
|
|
70
|
+
this.json(res, 201, { ok: true, id, status: data.approval ? "approval_pending" : "auto", scheduled_at: scheduledAt || null });
|
|
70
71
|
}
|
|
71
72
|
catch (e) {
|
|
72
73
|
this.json(res, 400, { error: e.message || "Invalid JSON" });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emqo/claudebridge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Bridge claude CLI to chat platforms (Telegram, Discord) with HITL approval, conditional branching, webhook triggers, parallel execution, and observability",
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "Bridge claude CLI to chat platforms (Telegram, Discord) with scheduled auto-tasks, autonomous project management, HITL approval, conditional branching, webhook triggers, parallel execution, and observability",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claudebridge": "dist/cli.js",
|