@openacp/cli 0.4.6 → 0.4.8
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 +8 -8
- package/dist/{chunk-IUPHAXGA.js → chunk-6MJLVZXV.js} +3 -3
- package/dist/{chunk-2M4O7AFI.js → chunk-BBPWAWE3.js} +392 -37
- package/dist/chunk-BBPWAWE3.js.map +1 -0
- package/dist/{chunk-3QACY5E3.js → chunk-C6YIUTGR.js} +2 -2
- package/dist/{chunk-2SY7Y2VB.js → chunk-HZD3CGPK.js} +2 -2
- package/dist/{chunk-ARWC4S35.js → chunk-UAUTLC4E.js} +13 -7
- package/dist/{chunk-ARWC4S35.js.map → chunk-UAUTLC4E.js.map} +1 -1
- package/dist/{chunk-WF5XDN4D.js → chunk-ZRFBLD3W.js} +6 -2
- package/dist/chunk-ZRFBLD3W.js.map +1 -0
- package/dist/cli.js +37 -31
- package/dist/cli.js.map +1 -1
- package/dist/{config-J5YQOMDU.js → config-H2DSEHNW.js} +2 -2
- package/dist/config-editor-SKS4LJLT.js +11 -0
- package/dist/{daemon-SLGQGRKO.js → daemon-VF6HJQXD.js} +3 -3
- package/dist/index.d.ts +18 -0
- package/dist/index.js +6 -6
- package/dist/integrate-WUPLRJD3.js +145 -0
- package/dist/integrate-WUPLRJD3.js.map +1 -0
- package/dist/{main-3POGUQPY.js → main-NV7YN3VY.js} +11 -11
- package/dist/{setup-CEDO6VWV.js → setup-FCVL75K6.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-2M4O7AFI.js.map +0 -1
- package/dist/chunk-WF5XDN4D.js.map +0 -1
- package/dist/config-editor-EPOKAEP6.js +0 -11
- package/dist/integrate-HYDSHAF3.js +0 -123
- package/dist/integrate-HYDSHAF3.js.map +0 -1
- /package/dist/{chunk-IUPHAXGA.js.map → chunk-6MJLVZXV.js.map} +0 -0
- /package/dist/{chunk-3QACY5E3.js.map → chunk-C6YIUTGR.js.map} +0 -0
- /package/dist/{chunk-2SY7Y2VB.js.map → chunk-HZD3CGPK.js.map} +0 -0
- /package/dist/{config-J5YQOMDU.js.map → config-H2DSEHNW.js.map} +0 -0
- /package/dist/{config-editor-EPOKAEP6.js.map → config-editor-SKS4LJLT.js.map} +0 -0
- /package/dist/{daemon-SLGQGRKO.js.map → daemon-VF6HJQXD.js.map} +0 -0
- /package/dist/{main-3POGUQPY.js.map → main-NV7YN3VY.js.map} +0 -0
- /package/dist/{setup-CEDO6VWV.js.map → setup-FCVL75K6.js.map} +0 -0
package/README.md
CHANGED
|
@@ -109,24 +109,24 @@ Once OpenACP is running, control it from Telegram:
|
|
|
109
109
|
|
|
110
110
|
Each session gets its own forum topic. The agent streams responses in real time, shows tool calls, and asks for permission when needed.
|
|
111
111
|
|
|
112
|
-
### Session
|
|
112
|
+
### Session Transfer
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
Move sessions between your terminal and Telegram:
|
|
115
115
|
|
|
116
|
-
**
|
|
116
|
+
**Terminal → Telegram:**
|
|
117
117
|
```bash
|
|
118
|
-
# Install
|
|
118
|
+
# Install integration (one-time)
|
|
119
119
|
openacp integrate claude
|
|
120
120
|
|
|
121
|
-
# In Claude CLI, type /openacp:handoff to transfer current session
|
|
121
|
+
# In Claude CLI, type /openacp:handoff to transfer the current session
|
|
122
122
|
# Or manually:
|
|
123
123
|
openacp adopt claude <session_id> --cwd /path/to/project
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
**Telegram →
|
|
127
|
-
Type `/handoff` in any session topic. The bot
|
|
126
|
+
**Telegram → Terminal:**
|
|
127
|
+
Type `/handoff` in any session topic. The bot replies with a command you can paste in your terminal to continue.
|
|
128
128
|
|
|
129
|
-
Sessions are not locked after
|
|
129
|
+
Sessions are not locked after transfer — you can continue from either side.
|
|
130
130
|
|
|
131
131
|
## Roadmap
|
|
132
132
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
validateBotToken,
|
|
3
3
|
validateChatId
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UAUTLC4E.js";
|
|
5
5
|
import {
|
|
6
6
|
expandHome
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZRFBLD3W.js";
|
|
8
8
|
import {
|
|
9
9
|
installAutoStart,
|
|
10
10
|
isAutoStartInstalled,
|
|
@@ -524,4 +524,4 @@ ${c.cyan}${c.bold}OpenACP Config Editor${c.reset}`);
|
|
|
524
524
|
export {
|
|
525
525
|
runConfigEditor
|
|
526
526
|
};
|
|
527
|
-
//# sourceMappingURL=chunk-
|
|
527
|
+
//# sourceMappingURL=chunk-6MJLVZXV.js.map
|
|
@@ -830,6 +830,7 @@ var SessionManager = class {
|
|
|
830
830
|
createdAt: session.createdAt.toISOString(),
|
|
831
831
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
832
832
|
name: session.name,
|
|
833
|
+
dangerousMode: false,
|
|
833
834
|
platform: {}
|
|
834
835
|
});
|
|
835
836
|
}
|
|
@@ -2016,7 +2017,7 @@ var ApiServer = class {
|
|
|
2016
2017
|
return;
|
|
2017
2018
|
}
|
|
2018
2019
|
target[lastKey] = value;
|
|
2019
|
-
const { ConfigSchema } = await import("./config-
|
|
2020
|
+
const { ConfigSchema } = await import("./config-H2DSEHNW.js");
|
|
2020
2021
|
const result = ConfigSchema.safeParse(cloned);
|
|
2021
2022
|
if (!result.success) {
|
|
2022
2023
|
this.sendJson(res, 400, {
|
|
@@ -2418,7 +2419,7 @@ function formatUsage(usage) {
|
|
|
2418
2419
|
return `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens
|
|
2419
2420
|
${bar} ${pct}%`;
|
|
2420
2421
|
}
|
|
2421
|
-
function splitMessage(text, maxLength =
|
|
2422
|
+
function splitMessage(text, maxLength = 3800) {
|
|
2422
2423
|
if (text.length <= maxLength) return [text];
|
|
2423
2424
|
const chunks = [];
|
|
2424
2425
|
let remaining = text;
|
|
@@ -2428,14 +2429,23 @@ function splitMessage(text, maxLength = 4096) {
|
|
|
2428
2429
|
break;
|
|
2429
2430
|
}
|
|
2430
2431
|
let splitAt = remaining.lastIndexOf("\n\n", maxLength);
|
|
2431
|
-
if (splitAt === -1 || splitAt < maxLength * 0.
|
|
2432
|
+
if (splitAt === -1 || splitAt < maxLength * 0.2) {
|
|
2432
2433
|
splitAt = remaining.lastIndexOf("\n", maxLength);
|
|
2433
2434
|
}
|
|
2434
|
-
if (splitAt === -1 || splitAt < maxLength * 0.
|
|
2435
|
+
if (splitAt === -1 || splitAt < maxLength * 0.2) {
|
|
2435
2436
|
splitAt = maxLength;
|
|
2436
2437
|
}
|
|
2438
|
+
const candidate = remaining.slice(0, splitAt);
|
|
2439
|
+
const fences = candidate.match(/```/g);
|
|
2440
|
+
if (fences && fences.length % 2 !== 0) {
|
|
2441
|
+
const closingFence = remaining.indexOf("```", splitAt);
|
|
2442
|
+
if (closingFence !== -1) {
|
|
2443
|
+
const afterFence = remaining.indexOf("\n", closingFence + 3);
|
|
2444
|
+
splitAt = afterFence !== -1 ? afterFence + 1 : closingFence + 3;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2437
2447
|
chunks.push(remaining.slice(0, splitAt));
|
|
2438
|
-
remaining = remaining.slice(splitAt).
|
|
2448
|
+
remaining = remaining.slice(splitAt).replace(/^\n+/, "");
|
|
2439
2449
|
}
|
|
2440
2450
|
return chunks;
|
|
2441
2451
|
}
|
|
@@ -2472,14 +2482,22 @@ var MessageDraft = class {
|
|
|
2472
2482
|
async flush() {
|
|
2473
2483
|
if (!this.buffer) return;
|
|
2474
2484
|
if (this.firstFlushPending) return;
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2485
|
+
let displayBuffer = this.buffer;
|
|
2486
|
+
if (displayBuffer.length > 3800) {
|
|
2487
|
+
let cutAt = displayBuffer.lastIndexOf("\n", 3800);
|
|
2488
|
+
if (cutAt < 800) cutAt = 3800;
|
|
2489
|
+
displayBuffer = displayBuffer.slice(0, cutAt) + "\n\u2026";
|
|
2490
|
+
}
|
|
2491
|
+
let html = markdownToTelegramHtml(displayBuffer);
|
|
2492
|
+
if (!html) return;
|
|
2493
|
+
if (html.length > 4096) {
|
|
2494
|
+
html = html.slice(0, 4090) + "\n\u2026";
|
|
2495
|
+
}
|
|
2478
2496
|
if (!this.messageId) {
|
|
2479
2497
|
this.firstFlushPending = true;
|
|
2480
2498
|
try {
|
|
2481
2499
|
const result = await this.sendQueue.enqueue(
|
|
2482
|
-
() => this.bot.api.sendMessage(this.chatId,
|
|
2500
|
+
() => this.bot.api.sendMessage(this.chatId, html, {
|
|
2483
2501
|
message_thread_id: this.threadId,
|
|
2484
2502
|
parse_mode: "HTML",
|
|
2485
2503
|
disable_notification: true
|
|
@@ -2497,7 +2515,7 @@ var MessageDraft = class {
|
|
|
2497
2515
|
} else {
|
|
2498
2516
|
try {
|
|
2499
2517
|
await this.sendQueue.enqueue(
|
|
2500
|
-
() => this.bot.api.editMessageText(this.chatId, this.messageId,
|
|
2518
|
+
() => this.bot.api.editMessageText(this.chatId, this.messageId, html, {
|
|
2501
2519
|
parse_mode: "HTML"
|
|
2502
2520
|
}),
|
|
2503
2521
|
{ type: "text", key: this.sessionId }
|
|
@@ -2517,21 +2535,20 @@ var MessageDraft = class {
|
|
|
2517
2535
|
if (this.messageId && this.buffer === this.lastSentBuffer) {
|
|
2518
2536
|
return this.messageId;
|
|
2519
2537
|
}
|
|
2520
|
-
const
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
const chunk = chunks[i];
|
|
2538
|
+
const mdChunks = splitMessage(this.buffer);
|
|
2539
|
+
for (let i = 0; i < mdChunks.length; i++) {
|
|
2540
|
+
const html = markdownToTelegramHtml(mdChunks[i]);
|
|
2541
|
+
try {
|
|
2525
2542
|
if (i === 0 && this.messageId) {
|
|
2526
2543
|
await this.sendQueue.enqueue(
|
|
2527
|
-
() => this.bot.api.editMessageText(this.chatId, this.messageId,
|
|
2544
|
+
() => this.bot.api.editMessageText(this.chatId, this.messageId, html, {
|
|
2528
2545
|
parse_mode: "HTML"
|
|
2529
2546
|
}),
|
|
2530
2547
|
{ type: "other" }
|
|
2531
2548
|
);
|
|
2532
2549
|
} else {
|
|
2533
2550
|
const msg = await this.sendQueue.enqueue(
|
|
2534
|
-
() => this.bot.api.sendMessage(this.chatId,
|
|
2551
|
+
() => this.bot.api.sendMessage(this.chatId, html, {
|
|
2535
2552
|
message_thread_id: this.threadId,
|
|
2536
2553
|
parse_mode: "HTML",
|
|
2537
2554
|
disable_notification: true
|
|
@@ -2542,17 +2559,25 @@ var MessageDraft = class {
|
|
|
2542
2559
|
this.messageId = msg.message_id;
|
|
2543
2560
|
}
|
|
2544
2561
|
}
|
|
2545
|
-
}
|
|
2546
|
-
} catch {
|
|
2547
|
-
if (this.buffer !== this.lastSentBuffer) {
|
|
2562
|
+
} catch {
|
|
2548
2563
|
try {
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2564
|
+
if (i === 0 && this.messageId) {
|
|
2565
|
+
await this.sendQueue.enqueue(
|
|
2566
|
+
() => this.bot.api.editMessageText(this.chatId, this.messageId, mdChunks[i].slice(0, 4096)),
|
|
2567
|
+
{ type: "other" }
|
|
2568
|
+
);
|
|
2569
|
+
} else {
|
|
2570
|
+
const msg = await this.sendQueue.enqueue(
|
|
2571
|
+
() => this.bot.api.sendMessage(this.chatId, mdChunks[i].slice(0, 4096), {
|
|
2572
|
+
message_thread_id: this.threadId,
|
|
2573
|
+
disable_notification: true
|
|
2574
|
+
}),
|
|
2575
|
+
{ type: "other" }
|
|
2576
|
+
);
|
|
2577
|
+
if (msg) {
|
|
2578
|
+
this.messageId = msg.message_id;
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2556
2581
|
} catch {
|
|
2557
2582
|
}
|
|
2558
2583
|
}
|
|
@@ -2603,6 +2628,7 @@ function setupCommands(bot, core, chatId, assistant) {
|
|
|
2603
2628
|
bot.command("newchat", (ctx) => handleNewChat(ctx, core, chatId));
|
|
2604
2629
|
bot.command("cancel", (ctx) => handleCancel(ctx, core, assistant));
|
|
2605
2630
|
bot.command("status", (ctx) => handleStatus(ctx, core));
|
|
2631
|
+
bot.command("sessions", (ctx) => handleTopics(ctx, core));
|
|
2606
2632
|
bot.command("agents", (ctx) => handleAgents(ctx, core));
|
|
2607
2633
|
bot.command("help", (ctx) => handleHelp(ctx));
|
|
2608
2634
|
bot.command("menu", (ctx) => handleMenu(ctx));
|
|
@@ -2610,11 +2636,12 @@ function setupCommands(bot, core, chatId, assistant) {
|
|
|
2610
2636
|
bot.command("disable_dangerous", (ctx) => handleDisableDangerous(ctx, core));
|
|
2611
2637
|
bot.command("restart", (ctx) => handleRestart(ctx, core));
|
|
2612
2638
|
bot.command("update", (ctx) => handleUpdate(ctx, core));
|
|
2639
|
+
bot.command("integrate", (ctx) => handleIntegrate(ctx, core));
|
|
2613
2640
|
}
|
|
2614
2641
|
function buildMenuKeyboard() {
|
|
2615
|
-
return new InlineKeyboard().text("\u{1F195} New Session", "m:new").text("\u{1F4AC} New Chat", "m:newchat").row().text("\u26D4 Cancel", "m:cancel").text("\u{1F4CA} Status", "m:status").row().text("\u{1F916} Agents", "m:agents").text("\u2753 Help", "m:help").row().text("\u{1F504} Restart", "m:restart").text("\u2B06\uFE0F Update", "m:update");
|
|
2642
|
+
return new InlineKeyboard().text("\u{1F195} New Session", "m:new").text("\u{1F4AC} New Chat", "m:newchat").row().text("\u26D4 Cancel", "m:cancel").text("\u{1F4CA} Status", "m:status").row().text("\u{1F4CB} Sessions", "m:topics").text("\u{1F916} Agents", "m:agents").row().text("\u{1F517} Integrate", "m:integrate").text("\u2753 Help", "m:help").row().text("\u{1F504} Restart", "m:restart").text("\u2B06\uFE0F Update", "m:update");
|
|
2616
2643
|
}
|
|
2617
|
-
function setupMenuCallbacks(bot, core, chatId) {
|
|
2644
|
+
function setupMenuCallbacks(bot, core, chatId, systemTopicIds) {
|
|
2618
2645
|
bot.callbackQuery(/^m:/, async (ctx) => {
|
|
2619
2646
|
const data = ctx.callbackQuery.data;
|
|
2620
2647
|
try {
|
|
@@ -2646,6 +2673,27 @@ function setupMenuCallbacks(bot, core, chatId) {
|
|
|
2646
2673
|
case "m:update":
|
|
2647
2674
|
await handleUpdate(ctx, core);
|
|
2648
2675
|
break;
|
|
2676
|
+
case "m:integrate":
|
|
2677
|
+
await handleIntegrate(ctx, core);
|
|
2678
|
+
break;
|
|
2679
|
+
case "m:topics":
|
|
2680
|
+
await handleTopics(ctx, core);
|
|
2681
|
+
break;
|
|
2682
|
+
case "m:cleanup:finished":
|
|
2683
|
+
await handleCleanup(ctx, core, chatId, ["finished"]);
|
|
2684
|
+
break;
|
|
2685
|
+
case "m:cleanup:errors":
|
|
2686
|
+
await handleCleanup(ctx, core, chatId, ["error", "cancelled"]);
|
|
2687
|
+
break;
|
|
2688
|
+
case "m:cleanup:all":
|
|
2689
|
+
await handleCleanup(ctx, core, chatId, ["finished", "error", "cancelled"]);
|
|
2690
|
+
break;
|
|
2691
|
+
case "m:cleanup:everything":
|
|
2692
|
+
await handleCleanupEverything(ctx, core, chatId, systemTopicIds);
|
|
2693
|
+
break;
|
|
2694
|
+
case "m:cleanup:everything:confirm":
|
|
2695
|
+
await handleCleanupEverythingConfirmed(ctx, core, chatId, systemTopicIds);
|
|
2696
|
+
break;
|
|
2649
2697
|
}
|
|
2650
2698
|
});
|
|
2651
2699
|
}
|
|
@@ -2870,6 +2918,188 @@ Total sessions: ${sessions.length}`,
|
|
|
2870
2918
|
);
|
|
2871
2919
|
}
|
|
2872
2920
|
}
|
|
2921
|
+
async function handleTopics(ctx, core) {
|
|
2922
|
+
try {
|
|
2923
|
+
const allRecords = core.sessionManager.listRecords();
|
|
2924
|
+
const records = allRecords.filter((r) => {
|
|
2925
|
+
const platform = r.platform;
|
|
2926
|
+
return !!platform?.topicId;
|
|
2927
|
+
});
|
|
2928
|
+
const headlessCount = allRecords.length - records.length;
|
|
2929
|
+
if (records.length === 0) {
|
|
2930
|
+
const extra = headlessCount > 0 ? ` (${headlessCount} headless hidden)` : "";
|
|
2931
|
+
await ctx.reply(`No sessions with topics found.${extra}`, { parse_mode: "HTML" });
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
const statusEmoji = {
|
|
2935
|
+
active: "\u{1F7E2}",
|
|
2936
|
+
initializing: "\u{1F7E1}",
|
|
2937
|
+
finished: "\u2705",
|
|
2938
|
+
error: "\u274C",
|
|
2939
|
+
cancelled: "\u26D4"
|
|
2940
|
+
};
|
|
2941
|
+
const statusOrder = { active: 0, initializing: 1, error: 2, finished: 3, cancelled: 4 };
|
|
2942
|
+
records.sort((a, b) => (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5));
|
|
2943
|
+
const MAX_DISPLAY = 30;
|
|
2944
|
+
const displayed = records.slice(0, MAX_DISPLAY);
|
|
2945
|
+
const lines = displayed.map((r) => {
|
|
2946
|
+
const emoji = statusEmoji[r.status] || "\u26AA";
|
|
2947
|
+
const name = r.name?.trim();
|
|
2948
|
+
const label = name ? escapeHtml(name) : `<i>${escapeHtml(r.agentName)} session</i>`;
|
|
2949
|
+
return `${emoji} ${label} <code>[${r.status}]</code>`;
|
|
2950
|
+
});
|
|
2951
|
+
const header = `<b>Sessions: ${records.length}</b>` + (headlessCount > 0 ? ` (${headlessCount} headless hidden)` : "");
|
|
2952
|
+
const truncated = records.length > MAX_DISPLAY ? `
|
|
2953
|
+
|
|
2954
|
+
<i>...and ${records.length - MAX_DISPLAY} more</i>` : "";
|
|
2955
|
+
const finishedCount = records.filter((r) => r.status === "finished").length;
|
|
2956
|
+
const errorCount = records.filter((r) => r.status === "error" || r.status === "cancelled").length;
|
|
2957
|
+
const activeCount = records.filter((r) => r.status === "active" || r.status === "initializing").length;
|
|
2958
|
+
const keyboard = new InlineKeyboard();
|
|
2959
|
+
if (finishedCount > 0) {
|
|
2960
|
+
keyboard.text(`Cleanup finished (${finishedCount})`, "m:cleanup:finished").row();
|
|
2961
|
+
}
|
|
2962
|
+
if (errorCount > 0) {
|
|
2963
|
+
keyboard.text(`Cleanup errors (${errorCount})`, "m:cleanup:errors").row();
|
|
2964
|
+
}
|
|
2965
|
+
if (finishedCount + errorCount > 0) {
|
|
2966
|
+
keyboard.text(`Cleanup all non-active (${finishedCount + errorCount})`, "m:cleanup:all").row();
|
|
2967
|
+
}
|
|
2968
|
+
keyboard.text(`\u26A0\uFE0F Cleanup ALL (${records.length})`, "m:cleanup:everything").row();
|
|
2969
|
+
keyboard.text("Refresh", "m:topics");
|
|
2970
|
+
await ctx.reply(
|
|
2971
|
+
`${header}
|
|
2972
|
+
|
|
2973
|
+
${lines.join("\n")}${truncated}`,
|
|
2974
|
+
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
2975
|
+
);
|
|
2976
|
+
} catch (err) {
|
|
2977
|
+
log8.error({ err }, "handleTopics error");
|
|
2978
|
+
await ctx.reply("\u274C Failed to list sessions.", { parse_mode: "HTML" }).catch(() => {
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
async function handleCleanup(ctx, core, chatId, statuses) {
|
|
2983
|
+
const allRecords = core.sessionManager.listRecords();
|
|
2984
|
+
const cleanable = allRecords.filter((r) => {
|
|
2985
|
+
const platform = r.platform;
|
|
2986
|
+
return !!platform?.topicId && statuses.includes(r.status);
|
|
2987
|
+
});
|
|
2988
|
+
if (cleanable.length === 0) {
|
|
2989
|
+
await ctx.reply("Nothing to clean up.", { parse_mode: "HTML" });
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2992
|
+
let deleted = 0;
|
|
2993
|
+
let failed = 0;
|
|
2994
|
+
for (const record of cleanable) {
|
|
2995
|
+
try {
|
|
2996
|
+
const topicId = record.platform?.topicId;
|
|
2997
|
+
if (topicId) {
|
|
2998
|
+
try {
|
|
2999
|
+
await ctx.api.deleteForumTopic(chatId, topicId);
|
|
3000
|
+
} catch (err) {
|
|
3001
|
+
log8.warn({ err, sessionId: record.sessionId, topicId }, "Failed to delete forum topic during cleanup");
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
await core.sessionManager.removeRecord(record.sessionId);
|
|
3005
|
+
deleted++;
|
|
3006
|
+
} catch (err) {
|
|
3007
|
+
log8.error({ err, sessionId: record.sessionId }, "Failed to cleanup session");
|
|
3008
|
+
failed++;
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
await ctx.reply(
|
|
3012
|
+
`\u{1F5D1} Cleaned up <b>${deleted}</b> sessions${failed > 0 ? ` (${failed} failed)` : ""}.`,
|
|
3013
|
+
{ parse_mode: "HTML" }
|
|
3014
|
+
);
|
|
3015
|
+
}
|
|
3016
|
+
async function handleCleanupEverything(ctx, core, chatId, systemTopicIds) {
|
|
3017
|
+
const allRecords = core.sessionManager.listRecords();
|
|
3018
|
+
const cleanable = allRecords.filter((r) => {
|
|
3019
|
+
const platform = r.platform;
|
|
3020
|
+
if (!platform?.topicId) return false;
|
|
3021
|
+
if (systemTopicIds && (platform.topicId === systemTopicIds.notificationTopicId || platform.topicId === systemTopicIds.assistantTopicId)) return false;
|
|
3022
|
+
return true;
|
|
3023
|
+
});
|
|
3024
|
+
if (cleanable.length === 0) {
|
|
3025
|
+
await ctx.reply("Nothing to clean up.", { parse_mode: "HTML" });
|
|
3026
|
+
return;
|
|
3027
|
+
}
|
|
3028
|
+
const statusCounts = /* @__PURE__ */ new Map();
|
|
3029
|
+
for (const r of cleanable) {
|
|
3030
|
+
statusCounts.set(r.status, (statusCounts.get(r.status) ?? 0) + 1);
|
|
3031
|
+
}
|
|
3032
|
+
const statusEmoji = {
|
|
3033
|
+
active: "\u{1F7E2}",
|
|
3034
|
+
initializing: "\u{1F7E1}",
|
|
3035
|
+
finished: "\u2705",
|
|
3036
|
+
error: "\u274C",
|
|
3037
|
+
cancelled: "\u26D4"
|
|
3038
|
+
};
|
|
3039
|
+
const breakdown = Array.from(statusCounts.entries()).map(([status, count]) => `${statusEmoji[status] ?? "\u26AA"} ${status}: ${count}`).join("\n");
|
|
3040
|
+
const activeCount = (statusCounts.get("active") ?? 0) + (statusCounts.get("initializing") ?? 0);
|
|
3041
|
+
const activeWarning = activeCount > 0 ? `
|
|
3042
|
+
|
|
3043
|
+
\u26A0\uFE0F <b>${activeCount} active session(s) will be cancelled and their agents stopped!</b>` : "";
|
|
3044
|
+
const keyboard = new InlineKeyboard().text("Yes, delete all", "m:cleanup:everything:confirm").text("Cancel", "m:topics");
|
|
3045
|
+
await ctx.reply(
|
|
3046
|
+
`<b>Delete ${cleanable.length} topics?</b>
|
|
3047
|
+
|
|
3048
|
+
This will:
|
|
3049
|
+
\u2022 Delete all session topics from this group
|
|
3050
|
+
\u2022 Cancel any running agent sessions
|
|
3051
|
+
\u2022 Remove all session records
|
|
3052
|
+
|
|
3053
|
+
<b>Breakdown:</b>
|
|
3054
|
+
${breakdown}${activeWarning}
|
|
3055
|
+
|
|
3056
|
+
<i>Notifications and Assistant topics will NOT be deleted.</i>`,
|
|
3057
|
+
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
3058
|
+
);
|
|
3059
|
+
}
|
|
3060
|
+
async function handleCleanupEverythingConfirmed(ctx, core, chatId, systemTopicIds) {
|
|
3061
|
+
const allRecords = core.sessionManager.listRecords();
|
|
3062
|
+
const cleanable = allRecords.filter((r) => {
|
|
3063
|
+
const platform = r.platform;
|
|
3064
|
+
if (!platform?.topicId) return false;
|
|
3065
|
+
if (systemTopicIds && (platform.topicId === systemTopicIds.notificationTopicId || platform.topicId === systemTopicIds.assistantTopicId)) return false;
|
|
3066
|
+
return true;
|
|
3067
|
+
});
|
|
3068
|
+
if (cleanable.length === 0) {
|
|
3069
|
+
await ctx.reply("Nothing to clean up.", { parse_mode: "HTML" });
|
|
3070
|
+
return;
|
|
3071
|
+
}
|
|
3072
|
+
let deleted = 0;
|
|
3073
|
+
let failed = 0;
|
|
3074
|
+
for (const record of cleanable) {
|
|
3075
|
+
try {
|
|
3076
|
+
if (record.status === "active" || record.status === "initializing") {
|
|
3077
|
+
try {
|
|
3078
|
+
await core.sessionManager.cancelSession(record.sessionId);
|
|
3079
|
+
} catch (err) {
|
|
3080
|
+
log8.warn({ err, sessionId: record.sessionId }, "Failed to cancel session during cleanup");
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
const topicId = record.platform?.topicId;
|
|
3084
|
+
if (topicId) {
|
|
3085
|
+
try {
|
|
3086
|
+
await ctx.api.deleteForumTopic(chatId, topicId);
|
|
3087
|
+
} catch (err) {
|
|
3088
|
+
log8.warn({ err, sessionId: record.sessionId, topicId }, "Failed to delete forum topic during cleanup");
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
await core.sessionManager.removeRecord(record.sessionId);
|
|
3092
|
+
deleted++;
|
|
3093
|
+
} catch (err) {
|
|
3094
|
+
log8.error({ err, sessionId: record.sessionId }, "Failed to cleanup session");
|
|
3095
|
+
failed++;
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
await ctx.reply(
|
|
3099
|
+
`\u{1F5D1} Cleaned up <b>${deleted}</b> sessions${failed > 0 ? ` (${failed} failed)` : ""}.`,
|
|
3100
|
+
{ parse_mode: "HTML" }
|
|
3101
|
+
);
|
|
3102
|
+
}
|
|
2873
3103
|
async function handleAgents(ctx, core) {
|
|
2874
3104
|
const agents = core.agentManager.getAvailableAgents();
|
|
2875
3105
|
const defaultAgent = core.configManager.get().defaultAgent;
|
|
@@ -3126,16 +3356,134 @@ async function executeCancelSession(core, excludeSessionId) {
|
|
|
3126
3356
|
await session.cancel();
|
|
3127
3357
|
return session;
|
|
3128
3358
|
}
|
|
3359
|
+
async function handleIntegrate(ctx, _core) {
|
|
3360
|
+
const { listIntegrations } = await import("./integrate-WUPLRJD3.js");
|
|
3361
|
+
const agents = listIntegrations();
|
|
3362
|
+
const keyboard = new InlineKeyboard();
|
|
3363
|
+
for (const agent of agents) {
|
|
3364
|
+
keyboard.text(`\u{1F916} ${agent}`, `i:agent:${agent}`).row();
|
|
3365
|
+
}
|
|
3366
|
+
await ctx.reply(
|
|
3367
|
+
`<b>\u{1F517} Integrations</b>
|
|
3368
|
+
|
|
3369
|
+
Select an agent to manage its integrations.`,
|
|
3370
|
+
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
3371
|
+
);
|
|
3372
|
+
}
|
|
3373
|
+
function buildAgentItemsKeyboard(agentName, items) {
|
|
3374
|
+
const keyboard = new InlineKeyboard();
|
|
3375
|
+
for (const item of items) {
|
|
3376
|
+
const installed = item.isInstalled();
|
|
3377
|
+
keyboard.text(
|
|
3378
|
+
installed ? `\u2705 ${item.name} \u2014 Uninstall` : `\u{1F4E6} ${item.name} \u2014 Install`,
|
|
3379
|
+
installed ? `i:uninstall:${agentName}:${item.id}` : `i:install:${agentName}:${item.id}`
|
|
3380
|
+
).row();
|
|
3381
|
+
}
|
|
3382
|
+
keyboard.text("\u2190 Back", "i:back").row();
|
|
3383
|
+
return keyboard;
|
|
3384
|
+
}
|
|
3385
|
+
function setupIntegrateCallbacks(bot, core) {
|
|
3386
|
+
bot.callbackQuery(/^i:/, async (ctx) => {
|
|
3387
|
+
const data = ctx.callbackQuery.data;
|
|
3388
|
+
try {
|
|
3389
|
+
await ctx.answerCallbackQuery();
|
|
3390
|
+
} catch {
|
|
3391
|
+
}
|
|
3392
|
+
if (data === "i:back") {
|
|
3393
|
+
const { listIntegrations } = await import("./integrate-WUPLRJD3.js");
|
|
3394
|
+
const agents = listIntegrations();
|
|
3395
|
+
const keyboard2 = new InlineKeyboard();
|
|
3396
|
+
for (const agent of agents) {
|
|
3397
|
+
keyboard2.text(`\u{1F916} ${agent}`, `i:agent:${agent}`).row();
|
|
3398
|
+
}
|
|
3399
|
+
try {
|
|
3400
|
+
await ctx.editMessageText(
|
|
3401
|
+
`<b>\u{1F517} Integrations</b>
|
|
3402
|
+
|
|
3403
|
+
Select an agent to manage its integrations.`,
|
|
3404
|
+
{ parse_mode: "HTML", reply_markup: keyboard2 }
|
|
3405
|
+
);
|
|
3406
|
+
} catch {
|
|
3407
|
+
}
|
|
3408
|
+
return;
|
|
3409
|
+
}
|
|
3410
|
+
const agentMatch = data.match(/^i:agent:(.+)$/);
|
|
3411
|
+
if (agentMatch) {
|
|
3412
|
+
const agentName2 = agentMatch[1];
|
|
3413
|
+
const { getIntegration: getIntegration2 } = await import("./integrate-WUPLRJD3.js");
|
|
3414
|
+
const integration2 = getIntegration2(agentName2);
|
|
3415
|
+
if (!integration2) {
|
|
3416
|
+
await ctx.reply(`\u274C No integration available for '${escapeHtml(agentName2)}'.`, { parse_mode: "HTML" });
|
|
3417
|
+
return;
|
|
3418
|
+
}
|
|
3419
|
+
const keyboard2 = buildAgentItemsKeyboard(agentName2, integration2.items);
|
|
3420
|
+
try {
|
|
3421
|
+
await ctx.editMessageText(
|
|
3422
|
+
`<b>\u{1F517} ${escapeHtml(agentName2)} Integrations</b>
|
|
3423
|
+
|
|
3424
|
+
${integration2.items.map((i) => `\u2022 <b>${escapeHtml(i.name)}</b> \u2014 ${escapeHtml(i.description)}`).join("\n")}`,
|
|
3425
|
+
{ parse_mode: "HTML", reply_markup: keyboard2 }
|
|
3426
|
+
);
|
|
3427
|
+
} catch {
|
|
3428
|
+
await ctx.reply(
|
|
3429
|
+
`<b>\u{1F517} ${escapeHtml(agentName2)} Integrations</b>`,
|
|
3430
|
+
{ parse_mode: "HTML", reply_markup: keyboard2 }
|
|
3431
|
+
);
|
|
3432
|
+
}
|
|
3433
|
+
return;
|
|
3434
|
+
}
|
|
3435
|
+
const actionMatch = data.match(/^i:(install|uninstall):([^:]+):(.+)$/);
|
|
3436
|
+
if (!actionMatch) return;
|
|
3437
|
+
const action = actionMatch[1];
|
|
3438
|
+
const agentName = actionMatch[2];
|
|
3439
|
+
const itemId = actionMatch[3];
|
|
3440
|
+
const { getIntegration } = await import("./integrate-WUPLRJD3.js");
|
|
3441
|
+
const integration = getIntegration(agentName);
|
|
3442
|
+
if (!integration) return;
|
|
3443
|
+
const item = integration.items.find((i) => i.id === itemId);
|
|
3444
|
+
if (!item) return;
|
|
3445
|
+
const result = action === "install" ? await item.install() : await item.uninstall();
|
|
3446
|
+
const installed = action === "install" && result.success;
|
|
3447
|
+
await core.configManager.save({
|
|
3448
|
+
integrations: {
|
|
3449
|
+
[agentName]: {
|
|
3450
|
+
installed,
|
|
3451
|
+
installedAt: installed ? (/* @__PURE__ */ new Date()).toISOString() : void 0
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
});
|
|
3455
|
+
const statusEmoji = result.success ? "\u2705" : "\u274C";
|
|
3456
|
+
const actionLabel = action === "install" ? "installed" : "uninstalled";
|
|
3457
|
+
const logsText = result.logs.map((l) => `<code>${escapeHtml(l)}</code>`).join("\n");
|
|
3458
|
+
const resultText = `${statusEmoji} <b>${escapeHtml(item.name)}</b> ${actionLabel}.
|
|
3459
|
+
|
|
3460
|
+
${logsText}`;
|
|
3461
|
+
const keyboard = buildAgentItemsKeyboard(agentName, integration.items);
|
|
3462
|
+
try {
|
|
3463
|
+
await ctx.editMessageText(
|
|
3464
|
+
`<b>\u{1F517} ${escapeHtml(agentName)} Integrations</b>
|
|
3465
|
+
|
|
3466
|
+
${resultText}`,
|
|
3467
|
+
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
3468
|
+
);
|
|
3469
|
+
} catch {
|
|
3470
|
+
await ctx.reply(resultText, { parse_mode: "HTML" });
|
|
3471
|
+
}
|
|
3472
|
+
});
|
|
3473
|
+
}
|
|
3129
3474
|
var STATIC_COMMANDS = [
|
|
3130
3475
|
{ command: "new", description: "Create new session" },
|
|
3131
3476
|
{ command: "newchat", description: "New chat, same agent & workspace" },
|
|
3132
3477
|
{ command: "cancel", description: "Cancel current session" },
|
|
3133
3478
|
{ command: "status", description: "Show status" },
|
|
3479
|
+
{ command: "sessions", description: "List all sessions" },
|
|
3134
3480
|
{ command: "agents", description: "List available agents" },
|
|
3135
3481
|
{ command: "help", description: "Help" },
|
|
3136
3482
|
{ command: "menu", description: "Show menu" },
|
|
3137
3483
|
{ command: "enable_dangerous", description: "Auto-approve all permission requests (session only)" },
|
|
3138
3484
|
{ command: "disable_dangerous", description: "Restore normal permission prompts (session only)" },
|
|
3485
|
+
{ command: "integrate", description: "Manage agent integrations" },
|
|
3486
|
+
{ command: "handoff", description: "Continue this session in your terminal" },
|
|
3139
3487
|
{ command: "restart", description: "Restart OpenACP" },
|
|
3140
3488
|
{ command: "update", description: "Update to latest version and restart" }
|
|
3141
3489
|
];
|
|
@@ -3942,10 +4290,12 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3942
4290
|
this.telegramConfig.chatId,
|
|
3943
4291
|
() => this.assistantSession?.id
|
|
3944
4292
|
);
|
|
4293
|
+
setupIntegrateCallbacks(this.bot, this.core);
|
|
3945
4294
|
setupMenuCallbacks(
|
|
3946
4295
|
this.bot,
|
|
3947
4296
|
this.core,
|
|
3948
|
-
this.telegramConfig.chatId
|
|
4297
|
+
this.telegramConfig.chatId,
|
|
4298
|
+
{ notificationTopicId: this.notificationTopicId, assistantTopicId: this.assistantTopicId }
|
|
3949
4299
|
);
|
|
3950
4300
|
setupCommands(
|
|
3951
4301
|
this.bot,
|
|
@@ -3967,24 +4317,26 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3967
4317
|
return;
|
|
3968
4318
|
}
|
|
3969
4319
|
const session = this.core.sessionManager.getSessionByThread("telegram", String(threadId));
|
|
3970
|
-
|
|
3971
|
-
|
|
4320
|
+
const record = session ? void 0 : this.core.sessionManager.getRecordByThread("telegram", String(threadId));
|
|
4321
|
+
const agentName = session?.agentName ?? record?.agentName;
|
|
4322
|
+
const agentSessionId = session?.agentSessionId ?? record?.agentSessionId;
|
|
4323
|
+
if (!agentName || !agentSessionId) {
|
|
4324
|
+
await ctx.reply("No session found for this topic.", {
|
|
3972
4325
|
message_thread_id: threadId
|
|
3973
4326
|
});
|
|
3974
4327
|
return;
|
|
3975
4328
|
}
|
|
3976
4329
|
const { getAgentCapabilities: getAgentCapabilities2 } = await import("./agent-registry-7HC6D4CH.js");
|
|
3977
|
-
const caps = getAgentCapabilities2(
|
|
4330
|
+
const caps = getAgentCapabilities2(agentName);
|
|
3978
4331
|
if (!caps.supportsResume || !caps.resumeCommand) {
|
|
3979
|
-
await ctx.reply("This agent does not support
|
|
4332
|
+
await ctx.reply("This agent does not support session transfer.", {
|
|
3980
4333
|
message_thread_id: threadId
|
|
3981
4334
|
});
|
|
3982
4335
|
return;
|
|
3983
4336
|
}
|
|
3984
|
-
const agentSessionId = session.agentSessionId;
|
|
3985
4337
|
const command = caps.resumeCommand(agentSessionId);
|
|
3986
4338
|
await ctx.reply(
|
|
3987
|
-
`
|
|
4339
|
+
`Run this in your terminal to continue the session:
|
|
3988
4340
|
|
|
3989
4341
|
<code>${command}</code>`,
|
|
3990
4342
|
{
|
|
@@ -4006,10 +4358,13 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
4006
4358
|
const agents = this.core.agentManager.getAvailableAgents();
|
|
4007
4359
|
const agentList = agents.map((a) => `${escapeHtml(a.name)}${a.name === config.defaultAgent ? " (default)" : ""}`).join(", ");
|
|
4008
4360
|
const workspace = escapeHtml(config.workspace.baseDir);
|
|
4361
|
+
const allRecords = this.core.sessionManager.listRecords();
|
|
4362
|
+
const activeCount = allRecords.filter((r) => r.status === "active" || r.status === "initializing").length;
|
|
4009
4363
|
const welcomeText = `\u{1F44B} <b>OpenACP Assistant</b> is online.
|
|
4010
4364
|
|
|
4011
4365
|
Available agents: ${agentList}
|
|
4012
4366
|
Workspace: <code>${workspace}</code>
|
|
4367
|
+
Sessions: ${activeCount} active / ${allRecords.length} total
|
|
4013
4368
|
|
|
4014
4369
|
<b>Select an action:</b>`;
|
|
4015
4370
|
await this.bot.api.sendMessage(this.telegramConfig.chatId, welcomeText, {
|
|
@@ -4533,4 +4888,4 @@ export {
|
|
|
4533
4888
|
TopicManager,
|
|
4534
4889
|
TelegramAdapter
|
|
4535
4890
|
};
|
|
4536
|
-
//# sourceMappingURL=chunk-
|
|
4891
|
+
//# sourceMappingURL=chunk-BBPWAWE3.js.map
|