@openacp/cli 0.4.11 → 0.5.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 +40 -2
- package/dist/agent-catalog-4IAJ7HEG.js +10 -0
- package/dist/agent-registry-B5YAMA4T.js +8 -0
- package/dist/agent-store-ZBXGOFPH.js +8 -0
- package/dist/chunk-5HGXUCMX.js +83 -0
- package/dist/chunk-5HGXUCMX.js.map +1 -0
- package/dist/{chunk-W7QQA6CW.js → chunk-D73LCTPF.js} +73 -35
- package/dist/chunk-D73LCTPF.js.map +1 -0
- package/dist/{chunk-66RVSUAR.js → chunk-FWN3UIRT.js} +465 -86
- package/dist/chunk-FWN3UIRT.js.map +1 -0
- package/dist/{chunk-3DIPXFZJ.js → chunk-IRGYTNLP.js} +2 -2
- package/dist/{chunk-WYZFGHHI.js → chunk-JRF4G4X7.js} +60 -24
- package/dist/chunk-JRF4G4X7.js.map +1 -0
- package/dist/{chunk-FKOARMAE.js → chunk-LAFKARV3.js} +3 -3
- package/dist/chunk-NAMYZIS5.js +1 -0
- package/dist/{chunk-ZW444AQY.js → chunk-NDR5JCS7.js} +2 -2
- package/dist/chunk-S3DRLJPM.js +422 -0
- package/dist/chunk-S3DRLJPM.js.map +1 -0
- package/dist/chunk-UG6X672R.js +90 -0
- package/dist/chunk-UG6X672R.js.map +1 -0
- package/dist/{chunk-YRJEZD7R.js → chunk-VBEWSWVL.js} +2 -2
- package/dist/chunk-XJJ7LPXP.js +85 -0
- package/dist/chunk-XJJ7LPXP.js.map +1 -0
- package/dist/{chunk-C33LTDZV.js → chunk-Z46LGZ7R.js} +21 -8
- package/dist/chunk-Z46LGZ7R.js.map +1 -0
- package/dist/cli.js +190 -18
- package/dist/cli.js.map +1 -1
- package/dist/{config-XURP6B3S.js → config-PCPIBPUA.js} +2 -2
- package/dist/config-editor-5L7AJ5AF.js +12 -0
- package/dist/{config-registry-OGX4YM2U.js → config-registry-SNKA2EH2.js} +2 -2
- package/dist/{daemon-GWJM2S4A.js → daemon-JZLFRUW6.js} +3 -3
- package/dist/data/registry-snapshot.json +876 -0
- package/dist/doctor-N2HKKUUQ.js +9 -0
- package/dist/doctor-N2HKKUUQ.js.map +1 -0
- package/dist/index.d.ts +137 -17
- package/dist/index.js +19 -10
- package/dist/{main-2QKD2EI2.js → main-37GLOJ7G.js} +18 -15
- package/dist/{main-2QKD2EI2.js.map → main-37GLOJ7G.js.map} +1 -1
- package/dist/{menu-CARRTW2F.js → menu-6RCPBVGQ.js} +2 -4
- package/dist/menu-6RCPBVGQ.js.map +1 -0
- package/dist/{setup-TTOL7XAN.js → setup-QAS3QW3M.js} +4 -3
- package/dist/setup-QAS3QW3M.js.map +1 -0
- package/package.json +10 -2
- package/dist/agent-registry-7HC6D4CH.js +0 -7
- package/dist/chunk-66RVSUAR.js.map +0 -1
- package/dist/chunk-BGKQHQB4.js +0 -276
- package/dist/chunk-BGKQHQB4.js.map +0 -1
- package/dist/chunk-C33LTDZV.js.map +0 -1
- package/dist/chunk-VA2M52CM.js +0 -15
- package/dist/chunk-VA2M52CM.js.map +0 -1
- package/dist/chunk-W7QQA6CW.js.map +0 -1
- package/dist/chunk-WYZFGHHI.js.map +0 -1
- package/dist/config-editor-AALY3URF.js +0 -11
- package/dist/doctor-X477CVZN.js +0 -9
- /package/dist/{agent-registry-7HC6D4CH.js.map → agent-catalog-4IAJ7HEG.js.map} +0 -0
- /package/dist/{config-XURP6B3S.js.map → agent-registry-B5YAMA4T.js.map} +0 -0
- /package/dist/{config-editor-AALY3URF.js.map → agent-store-ZBXGOFPH.js.map} +0 -0
- /package/dist/{chunk-3DIPXFZJ.js.map → chunk-IRGYTNLP.js.map} +0 -0
- /package/dist/{chunk-FKOARMAE.js.map → chunk-LAFKARV3.js.map} +0 -0
- /package/dist/{config-registry-OGX4YM2U.js.map → chunk-NAMYZIS5.js.map} +0 -0
- /package/dist/{chunk-ZW444AQY.js.map → chunk-NDR5JCS7.js.map} +0 -0
- /package/dist/{chunk-YRJEZD7R.js.map → chunk-VBEWSWVL.js.map} +0 -0
- /package/dist/{daemon-GWJM2S4A.js.map → config-PCPIBPUA.js.map} +0 -0
- /package/dist/{doctor-X477CVZN.js.map → config-editor-5L7AJ5AF.js.map} +0 -0
- /package/dist/{menu-CARRTW2F.js.map → config-registry-SNKA2EH2.js.map} +0 -0
- /package/dist/{setup-TTOL7XAN.js.map → daemon-JZLFRUW6.js.map} +0 -0
|
@@ -1,29 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DoctorEngine
|
|
3
|
-
} from "./chunk-3DIPXFZJ.js";
|
|
4
|
-
import {
|
|
5
|
-
getAgentCapabilities
|
|
6
|
-
} from "./chunk-VA2M52CM.js";
|
|
7
1
|
import {
|
|
8
2
|
buildMenuKeyboard,
|
|
9
3
|
buildSkillMessages,
|
|
10
|
-
escapeHtml,
|
|
11
|
-
formatToolCall,
|
|
12
|
-
formatToolUpdate,
|
|
13
|
-
formatUsage,
|
|
14
|
-
handleAgents,
|
|
15
4
|
handleClear,
|
|
16
5
|
handleHelp,
|
|
17
|
-
handleMenu
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
handleMenu
|
|
7
|
+
} from "./chunk-UG6X672R.js";
|
|
8
|
+
import {
|
|
9
|
+
AgentCatalog
|
|
10
|
+
} from "./chunk-S3DRLJPM.js";
|
|
11
|
+
import {
|
|
12
|
+
getAgentCapabilities
|
|
13
|
+
} from "./chunk-XJJ7LPXP.js";
|
|
14
|
+
import {
|
|
15
|
+
DoctorEngine
|
|
16
|
+
} from "./chunk-IRGYTNLP.js";
|
|
21
17
|
import {
|
|
22
18
|
getConfigValue,
|
|
23
19
|
getSafeFields,
|
|
24
20
|
isHotReloadable,
|
|
25
21
|
resolveOptions
|
|
26
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-Z46LGZ7R.js";
|
|
27
23
|
import {
|
|
28
24
|
createChildLogger,
|
|
29
25
|
createSessionLogger
|
|
@@ -72,7 +68,7 @@ var StderrCapture = class {
|
|
|
72
68
|
};
|
|
73
69
|
|
|
74
70
|
// src/core/agent-instance.ts
|
|
75
|
-
import { spawn,
|
|
71
|
+
import { spawn, execFileSync } from "child_process";
|
|
76
72
|
import { Transform } from "stream";
|
|
77
73
|
import fs from "fs";
|
|
78
74
|
import path from "path";
|
|
@@ -123,7 +119,7 @@ function resolveAgentCommand(cmd) {
|
|
|
123
119
|
}
|
|
124
120
|
}
|
|
125
121
|
try {
|
|
126
|
-
const fullPath =
|
|
122
|
+
const fullPath = execFileSync("which", [cmd], { encoding: "utf-8" }).trim();
|
|
127
123
|
if (fullPath) {
|
|
128
124
|
const content = fs.readFileSync(fullPath, "utf-8");
|
|
129
125
|
if (content.startsWith("#!/usr/bin/env node")) {
|
|
@@ -501,31 +497,29 @@ ${stderr}`
|
|
|
501
497
|
|
|
502
498
|
// src/core/agent-manager.ts
|
|
503
499
|
var AgentManager = class {
|
|
504
|
-
constructor(
|
|
505
|
-
this.
|
|
500
|
+
constructor(catalog) {
|
|
501
|
+
this.catalog = catalog;
|
|
506
502
|
}
|
|
507
503
|
getAvailableAgents() {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
env:
|
|
504
|
+
const installed = this.catalog.getInstalledEntries();
|
|
505
|
+
return Object.entries(installed).map(([key, agent]) => ({
|
|
506
|
+
name: key,
|
|
507
|
+
command: agent.command,
|
|
508
|
+
args: agent.args,
|
|
509
|
+
env: agent.env
|
|
514
510
|
}));
|
|
515
511
|
}
|
|
516
512
|
getAgent(name) {
|
|
517
|
-
|
|
518
|
-
if (!cfg) return void 0;
|
|
519
|
-
return { name, ...cfg };
|
|
513
|
+
return this.catalog.resolve(name);
|
|
520
514
|
}
|
|
521
515
|
async spawn(agentName, workingDirectory) {
|
|
522
516
|
const agentDef = this.getAgent(agentName);
|
|
523
|
-
if (!agentDef) throw new Error(`Agent "${agentName}" not
|
|
517
|
+
if (!agentDef) throw new Error(`Agent "${agentName}" is not installed. Run "openacp agents install ${agentName}" to add it.`);
|
|
524
518
|
return AgentInstance.spawn(agentDef, workingDirectory);
|
|
525
519
|
}
|
|
526
520
|
async resume(agentName, workingDirectory, agentSessionId) {
|
|
527
521
|
const agentDef = this.getAgent(agentName);
|
|
528
|
-
if (!agentDef) throw new Error(`Agent "${agentName}" not
|
|
522
|
+
if (!agentDef) throw new Error(`Agent "${agentName}" is not installed. Run "openacp agents install ${agentName}" to add it.`);
|
|
529
523
|
return AgentInstance.resume(agentDef, workingDirectory, agentSessionId);
|
|
530
524
|
}
|
|
531
525
|
};
|
|
@@ -652,28 +646,40 @@ var PromptQueue = class {
|
|
|
652
646
|
};
|
|
653
647
|
|
|
654
648
|
// src/core/permission-gate.ts
|
|
649
|
+
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
655
650
|
var PermissionGate = class {
|
|
656
651
|
request;
|
|
657
652
|
resolveFn;
|
|
658
653
|
rejectFn;
|
|
659
654
|
settled = false;
|
|
655
|
+
timeoutTimer;
|
|
656
|
+
timeoutMs;
|
|
657
|
+
constructor(timeoutMs) {
|
|
658
|
+
this.timeoutMs = timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
659
|
+
}
|
|
660
660
|
setPending(request) {
|
|
661
661
|
this.request = request;
|
|
662
662
|
this.settled = false;
|
|
663
|
+
this.clearTimeout();
|
|
663
664
|
return new Promise((resolve2, reject) => {
|
|
664
665
|
this.resolveFn = resolve2;
|
|
665
666
|
this.rejectFn = reject;
|
|
667
|
+
this.timeoutTimer = setTimeout(() => {
|
|
668
|
+
this.reject("Permission request timed out (no response received)");
|
|
669
|
+
}, this.timeoutMs);
|
|
666
670
|
});
|
|
667
671
|
}
|
|
668
672
|
resolve(optionId) {
|
|
669
673
|
if (this.settled || !this.resolveFn) return;
|
|
670
674
|
this.settled = true;
|
|
675
|
+
this.clearTimeout();
|
|
671
676
|
this.resolveFn(optionId);
|
|
672
677
|
this.cleanup();
|
|
673
678
|
}
|
|
674
679
|
reject(reason) {
|
|
675
680
|
if (this.settled || !this.rejectFn) return;
|
|
676
681
|
this.settled = true;
|
|
682
|
+
this.clearTimeout();
|
|
677
683
|
this.rejectFn(new Error(reason ?? "Permission rejected"));
|
|
678
684
|
this.cleanup();
|
|
679
685
|
}
|
|
@@ -687,6 +693,12 @@ var PermissionGate = class {
|
|
|
687
693
|
get requestId() {
|
|
688
694
|
return this.request?.id;
|
|
689
695
|
}
|
|
696
|
+
clearTimeout() {
|
|
697
|
+
if (this.timeoutTimer) {
|
|
698
|
+
clearTimeout(this.timeoutTimer);
|
|
699
|
+
this.timeoutTimer = void 0;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
690
702
|
cleanup() {
|
|
691
703
|
this.request = void 0;
|
|
692
704
|
this.resolveFn = void 0;
|
|
@@ -1453,6 +1465,7 @@ var JsonFileSessionStore = class {
|
|
|
1453
1465
|
var log5 = createChildLogger({ module: "core" });
|
|
1454
1466
|
var OpenACPCore = class {
|
|
1455
1467
|
configManager;
|
|
1468
|
+
agentCatalog;
|
|
1456
1469
|
agentManager;
|
|
1457
1470
|
sessionManager;
|
|
1458
1471
|
notificationManager;
|
|
@@ -1466,7 +1479,9 @@ var OpenACPCore = class {
|
|
|
1466
1479
|
constructor(configManager) {
|
|
1467
1480
|
this.configManager = configManager;
|
|
1468
1481
|
const config = configManager.get();
|
|
1469
|
-
this.
|
|
1482
|
+
this.agentCatalog = new AgentCatalog();
|
|
1483
|
+
this.agentCatalog.load();
|
|
1484
|
+
this.agentManager = new AgentManager(this.agentCatalog);
|
|
1470
1485
|
const storePath = path3.join(os.homedir(), ".openacp", "sessions.json");
|
|
1471
1486
|
this.sessionStore = new JsonFileSessionStore(
|
|
1472
1487
|
storePath,
|
|
@@ -1494,6 +1509,9 @@ var OpenACPCore = class {
|
|
|
1494
1509
|
this.adapters.set(name, adapter);
|
|
1495
1510
|
}
|
|
1496
1511
|
async start() {
|
|
1512
|
+
this.agentCatalog.refreshRegistryIfStale().catch((err) => {
|
|
1513
|
+
log5.warn({ err }, "Background registry refresh failed");
|
|
1514
|
+
});
|
|
1497
1515
|
for (const adapter of this.adapters.values()) {
|
|
1498
1516
|
await adapter.start();
|
|
1499
1517
|
}
|
|
@@ -1631,8 +1649,9 @@ var OpenACPCore = class {
|
|
|
1631
1649
|
const config = this.configManager.get();
|
|
1632
1650
|
const resolvedAgent = agentName || config.defaultAgent;
|
|
1633
1651
|
log5.info({ channelId, agentName: resolvedAgent }, "New session request");
|
|
1652
|
+
const agentDef = this.agentCatalog.resolve(resolvedAgent);
|
|
1634
1653
|
const resolvedWorkspace = this.configManager.resolveWorkspace(
|
|
1635
|
-
workspacePath ||
|
|
1654
|
+
workspacePath || agentDef?.workingDirectory
|
|
1636
1655
|
);
|
|
1637
1656
|
return this.createSession({
|
|
1638
1657
|
channelId,
|
|
@@ -2128,7 +2147,7 @@ var ApiServer = class {
|
|
|
2128
2147
|
this.sendJson(res, 200, { version: getVersion() });
|
|
2129
2148
|
}
|
|
2130
2149
|
async handleGetEditableConfig(res) {
|
|
2131
|
-
const { getSafeFields: getSafeFields2, resolveOptions: resolveOptions2, getConfigValue: getConfigValue2 } = await import("./config-registry-
|
|
2150
|
+
const { getSafeFields: getSafeFields2, resolveOptions: resolveOptions2, getConfigValue: getConfigValue2 } = await import("./config-registry-SNKA2EH2.js");
|
|
2132
2151
|
const config = this.core.configManager.get();
|
|
2133
2152
|
const safeFields = getSafeFields2();
|
|
2134
2153
|
const fields = safeFields.map((def) => ({
|
|
@@ -2182,7 +2201,7 @@ var ApiServer = class {
|
|
|
2182
2201
|
return;
|
|
2183
2202
|
}
|
|
2184
2203
|
target[lastKey] = value;
|
|
2185
|
-
const { ConfigSchema } = await import("./config-
|
|
2204
|
+
const { ConfigSchema } = await import("./config-PCPIBPUA.js");
|
|
2186
2205
|
const result = ConfigSchema.safeParse(cloned);
|
|
2187
2206
|
if (!result.success) {
|
|
2188
2207
|
this.sendJson(res, 400, {
|
|
@@ -2199,7 +2218,7 @@ var ApiServer = class {
|
|
|
2199
2218
|
}
|
|
2200
2219
|
updateTarget[lastKey] = value;
|
|
2201
2220
|
await this.core.configManager.save(updates, configPath);
|
|
2202
|
-
const { isHotReloadable: isHotReloadable2 } = await import("./config-registry-
|
|
2221
|
+
const { isHotReloadable: isHotReloadable2 } = await import("./config-registry-SNKA2EH2.js");
|
|
2203
2222
|
const needsRestart = !isHotReloadable2(configPath);
|
|
2204
2223
|
this.sendJson(res, 200, {
|
|
2205
2224
|
ok: true,
|
|
@@ -2485,6 +2504,169 @@ function buildDeepLink(chatId, messageId) {
|
|
|
2485
2504
|
// src/adapters/telegram/commands/new-session.ts
|
|
2486
2505
|
import { InlineKeyboard as InlineKeyboard2 } from "grammy";
|
|
2487
2506
|
|
|
2507
|
+
// src/adapters/telegram/formatting.ts
|
|
2508
|
+
function escapeHtml(text) {
|
|
2509
|
+
if (!text) return "";
|
|
2510
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
2511
|
+
}
|
|
2512
|
+
function markdownToTelegramHtml(md) {
|
|
2513
|
+
const codeBlocks = [];
|
|
2514
|
+
const inlineCodes = [];
|
|
2515
|
+
let text = md.replace(/```(\w*)\n?([\s\S]*?)```/g, (_match, lang, code) => {
|
|
2516
|
+
const index = codeBlocks.length;
|
|
2517
|
+
const escapedCode = escapeHtml(code);
|
|
2518
|
+
const langAttr = lang ? ` class="language-${escapeHtml(lang)}"` : "";
|
|
2519
|
+
codeBlocks.push(`<pre><code${langAttr}>${escapedCode}</code></pre>`);
|
|
2520
|
+
return `\0CODE_BLOCK_${index}\0`;
|
|
2521
|
+
});
|
|
2522
|
+
text = text.replace(/`([^`]+)`/g, (_match, code) => {
|
|
2523
|
+
const index = inlineCodes.length;
|
|
2524
|
+
inlineCodes.push(`<code>${escapeHtml(code)}</code>`);
|
|
2525
|
+
return `\0INLINE_CODE_${index}\0`;
|
|
2526
|
+
});
|
|
2527
|
+
text = escapeHtml(text);
|
|
2528
|
+
text = text.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
|
|
2529
|
+
text = text.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<i>$1</i>");
|
|
2530
|
+
text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
2531
|
+
text = text.replace(/\x00CODE_BLOCK_(\d+)\x00/g, (_match, idx) => {
|
|
2532
|
+
return codeBlocks[parseInt(idx, 10)];
|
|
2533
|
+
});
|
|
2534
|
+
text = text.replace(/\x00INLINE_CODE_(\d+)\x00/g, (_match, idx) => {
|
|
2535
|
+
return inlineCodes[parseInt(idx, 10)];
|
|
2536
|
+
});
|
|
2537
|
+
return text;
|
|
2538
|
+
}
|
|
2539
|
+
var STATUS_ICON = {
|
|
2540
|
+
pending: "\u23F3",
|
|
2541
|
+
in_progress: "\u{1F504}",
|
|
2542
|
+
completed: "\u2705",
|
|
2543
|
+
failed: "\u274C"
|
|
2544
|
+
};
|
|
2545
|
+
var KIND_ICON = {
|
|
2546
|
+
read: "\u{1F4D6}",
|
|
2547
|
+
edit: "\u270F\uFE0F",
|
|
2548
|
+
delete: "\u{1F5D1}\uFE0F",
|
|
2549
|
+
execute: "\u25B6\uFE0F",
|
|
2550
|
+
search: "\u{1F50D}",
|
|
2551
|
+
fetch: "\u{1F310}",
|
|
2552
|
+
think: "\u{1F9E0}",
|
|
2553
|
+
move: "\u{1F4E6}",
|
|
2554
|
+
other: "\u{1F6E0}\uFE0F"
|
|
2555
|
+
};
|
|
2556
|
+
function extractContentText(content, depth = 0) {
|
|
2557
|
+
if (!content || depth > 5) return "";
|
|
2558
|
+
if (typeof content === "string") return content;
|
|
2559
|
+
if (Array.isArray(content)) {
|
|
2560
|
+
return content.map((c) => extractContentText(c, depth + 1)).filter(Boolean).join("\n");
|
|
2561
|
+
}
|
|
2562
|
+
if (typeof content === "object" && content !== null) {
|
|
2563
|
+
const c = content;
|
|
2564
|
+
if (c.type === "text" && typeof c.text === "string") return c.text;
|
|
2565
|
+
if (typeof c.text === "string") return c.text;
|
|
2566
|
+
if (typeof c.content === "string") return c.content;
|
|
2567
|
+
if (c.content && typeof c.content === "object") return extractContentText(c.content, depth + 1);
|
|
2568
|
+
if (c.input) return extractContentText(c.input, depth + 1);
|
|
2569
|
+
if (c.output) return extractContentText(c.output, depth + 1);
|
|
2570
|
+
const keys = Object.keys(c).filter((k) => k !== "type");
|
|
2571
|
+
if (keys.length === 0) return "";
|
|
2572
|
+
return JSON.stringify(c, null, 2);
|
|
2573
|
+
}
|
|
2574
|
+
return String(content);
|
|
2575
|
+
}
|
|
2576
|
+
function truncateContent(text, maxLen = 3800) {
|
|
2577
|
+
if (text.length <= maxLen) return text;
|
|
2578
|
+
return text.slice(0, maxLen) + "\n\u2026 (truncated)";
|
|
2579
|
+
}
|
|
2580
|
+
function formatToolCall(tool) {
|
|
2581
|
+
const si = STATUS_ICON[tool.status || ""] || "\u{1F527}";
|
|
2582
|
+
const ki = KIND_ICON[tool.kind || ""] || "\u{1F6E0}\uFE0F";
|
|
2583
|
+
let text = `${si} ${ki} <b>${escapeHtml(tool.name || "Tool")}</b>`;
|
|
2584
|
+
text += formatViewerLinks(tool.viewerLinks, tool.viewerFilePath);
|
|
2585
|
+
if (!tool.viewerLinks) {
|
|
2586
|
+
const details = extractContentText(tool.content);
|
|
2587
|
+
if (details) {
|
|
2588
|
+
text += `
|
|
2589
|
+
<pre>${escapeHtml(truncateContent(details))}</pre>`;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
return text;
|
|
2593
|
+
}
|
|
2594
|
+
function formatToolUpdate(update) {
|
|
2595
|
+
const si = STATUS_ICON[update.status] || "\u{1F527}";
|
|
2596
|
+
const ki = KIND_ICON[update.kind || ""] || "\u{1F6E0}\uFE0F";
|
|
2597
|
+
const name = update.name || "Tool";
|
|
2598
|
+
let text = `${si} ${ki} <b>${escapeHtml(name)}</b>`;
|
|
2599
|
+
text += formatViewerLinks(update.viewerLinks, update.viewerFilePath);
|
|
2600
|
+
if (!update.viewerLinks) {
|
|
2601
|
+
const details = extractContentText(update.content);
|
|
2602
|
+
if (details) {
|
|
2603
|
+
text += `
|
|
2604
|
+
<pre>${escapeHtml(truncateContent(details))}</pre>`;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
return text;
|
|
2608
|
+
}
|
|
2609
|
+
function formatViewerLinks(links, filePath) {
|
|
2610
|
+
if (!links) return "";
|
|
2611
|
+
const fileName = filePath ? filePath.split("/").pop() || filePath : "";
|
|
2612
|
+
let text = "\n";
|
|
2613
|
+
if (links.file) text += `
|
|
2614
|
+
\u{1F4C4} <a href="${escapeHtml(links.file)}">View ${escapeHtml(fileName || "file")}</a>`;
|
|
2615
|
+
if (links.diff) text += `
|
|
2616
|
+
\u{1F4DD} <a href="${escapeHtml(links.diff)}">View diff${fileName ? ` \u2014 ${escapeHtml(fileName)}` : ""}</a>`;
|
|
2617
|
+
return text;
|
|
2618
|
+
}
|
|
2619
|
+
function formatTokens(n) {
|
|
2620
|
+
return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
|
|
2621
|
+
}
|
|
2622
|
+
function progressBar(ratio) {
|
|
2623
|
+
const filled = Math.round(Math.min(ratio, 1) * 10);
|
|
2624
|
+
return "\u2593".repeat(filled) + "\u2591".repeat(10 - filled);
|
|
2625
|
+
}
|
|
2626
|
+
function formatUsage(usage) {
|
|
2627
|
+
const { tokensUsed, contextSize } = usage;
|
|
2628
|
+
if (tokensUsed == null) return "\u{1F4CA} Usage data unavailable";
|
|
2629
|
+
if (contextSize == null) return `\u{1F4CA} ${formatTokens(tokensUsed)} tokens`;
|
|
2630
|
+
const ratio = tokensUsed / contextSize;
|
|
2631
|
+
const pct = Math.round(ratio * 100);
|
|
2632
|
+
const bar = progressBar(ratio);
|
|
2633
|
+
const emoji = pct >= 85 ? "\u26A0\uFE0F" : "\u{1F4CA}";
|
|
2634
|
+
return `${emoji} ${formatTokens(tokensUsed)} / ${formatTokens(contextSize)} tokens
|
|
2635
|
+
${bar} ${pct}%`;
|
|
2636
|
+
}
|
|
2637
|
+
function splitMessage(text, maxLength = 3800) {
|
|
2638
|
+
if (text.length <= maxLength) return [text];
|
|
2639
|
+
const chunks = [];
|
|
2640
|
+
let remaining = text;
|
|
2641
|
+
while (remaining.length > 0) {
|
|
2642
|
+
if (remaining.length <= maxLength) {
|
|
2643
|
+
chunks.push(remaining);
|
|
2644
|
+
break;
|
|
2645
|
+
}
|
|
2646
|
+
const wouldLeaveSmall = remaining.length < maxLength * 1.3;
|
|
2647
|
+
const searchLimit = wouldLeaveSmall ? Math.floor(remaining.length / 2) + 300 : maxLength;
|
|
2648
|
+
let splitAt = remaining.lastIndexOf("\n\n", searchLimit);
|
|
2649
|
+
if (splitAt === -1 || splitAt < searchLimit * 0.2) {
|
|
2650
|
+
splitAt = remaining.lastIndexOf("\n", searchLimit);
|
|
2651
|
+
}
|
|
2652
|
+
if (splitAt === -1 || splitAt < searchLimit * 0.2) {
|
|
2653
|
+
splitAt = searchLimit;
|
|
2654
|
+
}
|
|
2655
|
+
const candidate = remaining.slice(0, splitAt);
|
|
2656
|
+
const fences = candidate.match(/```/g);
|
|
2657
|
+
if (fences && fences.length % 2 !== 0) {
|
|
2658
|
+
const closingFence = remaining.indexOf("```", splitAt);
|
|
2659
|
+
if (closingFence !== -1) {
|
|
2660
|
+
const afterFence = remaining.indexOf("\n", closingFence + 3);
|
|
2661
|
+
splitAt = afterFence !== -1 ? afterFence + 1 : closingFence + 3;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
chunks.push(remaining.slice(0, splitAt));
|
|
2665
|
+
remaining = remaining.slice(splitAt).replace(/^\n+/, "");
|
|
2666
|
+
}
|
|
2667
|
+
return chunks;
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2488
2670
|
// src/adapters/telegram/commands/admin.ts
|
|
2489
2671
|
import { InlineKeyboard } from "grammy";
|
|
2490
2672
|
var log9 = createChildLogger({ module: "telegram-cmd-admin" });
|
|
@@ -2688,37 +2870,12 @@ async function handleNew(ctx, core, chatId, assistant) {
|
|
|
2688
2870
|
return;
|
|
2689
2871
|
}
|
|
2690
2872
|
}
|
|
2691
|
-
|
|
2692
|
-
if (!userId) return;
|
|
2693
|
-
const agents = core.agentManager.getAvailableAgents();
|
|
2694
|
-
const config = core.configManager.get();
|
|
2695
|
-
if (agentName || agents.length === 1) {
|
|
2696
|
-
const selectedAgent = agentName || config.defaultAgent;
|
|
2697
|
-
await startWorkspaceStep(ctx, core, chatId, userId, selectedAgent);
|
|
2698
|
-
return;
|
|
2699
|
-
}
|
|
2700
|
-
const keyboard = new InlineKeyboard2();
|
|
2701
|
-
for (const agent of agents) {
|
|
2702
|
-
const label = agent.name === config.defaultAgent ? `${agent.name} (default)` : agent.name;
|
|
2703
|
-
keyboard.text(label, `m:new:agent:${agent.name}`).row();
|
|
2704
|
-
}
|
|
2705
|
-
keyboard.text("\u274C Cancel", "m:new:cancel");
|
|
2706
|
-
const msg = await ctx.reply(
|
|
2707
|
-
`\u{1F916} <b>Choose an agent:</b>`,
|
|
2708
|
-
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
2709
|
-
);
|
|
2710
|
-
cleanupPending(userId);
|
|
2711
|
-
pendingNewSessions.set(userId, {
|
|
2712
|
-
step: "agent",
|
|
2713
|
-
messageId: msg.message_id,
|
|
2714
|
-
threadId: currentThreadId,
|
|
2715
|
-
timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS)
|
|
2716
|
-
});
|
|
2873
|
+
await showAgentPicker(ctx, core, chatId, agentName);
|
|
2717
2874
|
}
|
|
2718
2875
|
async function startWorkspaceStep(ctx, core, chatId, userId, agentName) {
|
|
2719
2876
|
const config = core.configManager.get();
|
|
2720
2877
|
const baseDir = config.workspace.baseDir;
|
|
2721
|
-
const keyboard = new InlineKeyboard2().text(`\u{1F4C1} Use ${baseDir}`, "m:new:ws:default").row().text("\u270F\uFE0F Enter project path", "m:new:ws:custom")
|
|
2878
|
+
const keyboard = new InlineKeyboard2().text(`\u{1F4C1} Use ${baseDir}`, "m:new:ws:default").row().text("\u270F\uFE0F Enter project path", "m:new:ws:custom");
|
|
2722
2879
|
const text = `\u{1F4C1} <b>Where should ${escapeHtml(agentName)} work?</b>
|
|
2723
2880
|
|
|
2724
2881
|
Enter the path to your project folder \u2014 the agent will read, write, and run code there.
|
|
@@ -2953,30 +3110,35 @@ async function handlePendingWorkspaceInput(ctx, core, chatId, assistantTopicId)
|
|
|
2953
3110
|
return true;
|
|
2954
3111
|
}
|
|
2955
3112
|
async function startInteractiveNewSession(ctx, core, chatId, agentName) {
|
|
3113
|
+
await showAgentPicker(ctx, core, chatId, agentName);
|
|
3114
|
+
}
|
|
3115
|
+
async function showAgentPicker(ctx, core, chatId, agentName) {
|
|
2956
3116
|
const userId = ctx.from?.id;
|
|
2957
3117
|
if (!userId) return;
|
|
2958
|
-
const
|
|
3118
|
+
const installedEntries = core.agentCatalog.getInstalledEntries();
|
|
3119
|
+
const agentKeys = Object.keys(installedEntries);
|
|
2959
3120
|
const config = core.configManager.get();
|
|
2960
|
-
if (agentName ||
|
|
3121
|
+
if (agentName || agentKeys.length === 1) {
|
|
2961
3122
|
const selectedAgent = agentName || config.defaultAgent;
|
|
2962
3123
|
await startWorkspaceStep(ctx, core, chatId, userId, selectedAgent);
|
|
2963
3124
|
return;
|
|
2964
3125
|
}
|
|
2965
3126
|
const keyboard = new InlineKeyboard2();
|
|
2966
|
-
for (const
|
|
2967
|
-
const
|
|
2968
|
-
|
|
3127
|
+
for (const key of agentKeys) {
|
|
3128
|
+
const agent = installedEntries[key];
|
|
3129
|
+
const label = key === config.defaultAgent ? `${agent.name} (default)` : agent.name;
|
|
3130
|
+
keyboard.text(label, `m:new:agent:${key}`).row();
|
|
2969
3131
|
}
|
|
2970
|
-
keyboard.text("\u274C Cancel", "m:new:cancel");
|
|
2971
3132
|
const msg = await ctx.reply(
|
|
2972
3133
|
`\u{1F916} <b>Choose an agent:</b>`,
|
|
2973
3134
|
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
2974
3135
|
);
|
|
2975
3136
|
cleanupPending(userId);
|
|
3137
|
+
const threadId = ctx.message?.message_thread_id ?? ctx.callbackQuery?.message?.message_thread_id;
|
|
2976
3138
|
pendingNewSessions.set(userId, {
|
|
2977
3139
|
step: "agent",
|
|
2978
3140
|
messageId: msg.message_id,
|
|
2979
|
-
threadId
|
|
3141
|
+
threadId,
|
|
2980
3142
|
timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS)
|
|
2981
3143
|
});
|
|
2982
3144
|
}
|
|
@@ -3350,12 +3512,221 @@ function setupSessionCallbacks(bot, core, chatId, systemTopicIds) {
|
|
|
3350
3512
|
});
|
|
3351
3513
|
}
|
|
3352
3514
|
|
|
3353
|
-
// src/adapters/telegram/commands/
|
|
3515
|
+
// src/adapters/telegram/commands/agents.ts
|
|
3354
3516
|
import { InlineKeyboard as InlineKeyboard4 } from "grammy";
|
|
3517
|
+
var AGENTS_PER_PAGE = 6;
|
|
3518
|
+
async function handleAgents(ctx, core, page = 0) {
|
|
3519
|
+
const catalog = core.agentCatalog;
|
|
3520
|
+
const items = catalog.getAvailable();
|
|
3521
|
+
const installed = items.filter((i) => i.installed);
|
|
3522
|
+
const available = items.filter((i) => !i.installed);
|
|
3523
|
+
let text = "<b>\u{1F916} Agents</b>\n\n";
|
|
3524
|
+
if (installed.length > 0) {
|
|
3525
|
+
text += "<b>Installed:</b>\n";
|
|
3526
|
+
for (const item of installed) {
|
|
3527
|
+
text += `\u2705 <b>${escapeHtml(item.name)}</b>`;
|
|
3528
|
+
if (item.description) {
|
|
3529
|
+
text += ` \u2014 <i>${escapeHtml(truncate(item.description, 50))}</i>`;
|
|
3530
|
+
}
|
|
3531
|
+
text += "\n";
|
|
3532
|
+
}
|
|
3533
|
+
text += "\n";
|
|
3534
|
+
}
|
|
3535
|
+
if (available.length > 0) {
|
|
3536
|
+
const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE);
|
|
3537
|
+
const safePage = Math.max(0, Math.min(page, totalPages - 1));
|
|
3538
|
+
const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE);
|
|
3539
|
+
text += `<b>Available to install:</b>`;
|
|
3540
|
+
if (totalPages > 1) {
|
|
3541
|
+
text += ` (${safePage + 1}/${totalPages})`;
|
|
3542
|
+
}
|
|
3543
|
+
text += "\n";
|
|
3544
|
+
for (const item of pageItems) {
|
|
3545
|
+
if (item.available) {
|
|
3546
|
+
text += `\u2B07\uFE0F <b>${escapeHtml(item.name)}</b>`;
|
|
3547
|
+
} else {
|
|
3548
|
+
const deps = item.missingDeps?.join(", ") ?? "requirements not met";
|
|
3549
|
+
text += `\u26A0\uFE0F <b>${escapeHtml(item.name)}</b> <i>(needs: ${escapeHtml(deps)})</i>`;
|
|
3550
|
+
}
|
|
3551
|
+
if (item.description) {
|
|
3552
|
+
text += `
|
|
3553
|
+
<i>${escapeHtml(truncate(item.description, 60))}</i>`;
|
|
3554
|
+
}
|
|
3555
|
+
text += "\n";
|
|
3556
|
+
}
|
|
3557
|
+
const keyboard = new InlineKeyboard4();
|
|
3558
|
+
const installable = pageItems.filter((i) => i.available);
|
|
3559
|
+
for (let i = 0; i < installable.length; i += 2) {
|
|
3560
|
+
const row = installable.slice(i, i + 2);
|
|
3561
|
+
for (const item of row) {
|
|
3562
|
+
keyboard.text(`\u2B07\uFE0F ${item.name}`, `ag:install:${item.key}`);
|
|
3563
|
+
}
|
|
3564
|
+
keyboard.row();
|
|
3565
|
+
}
|
|
3566
|
+
if (totalPages > 1) {
|
|
3567
|
+
if (safePage > 0) {
|
|
3568
|
+
keyboard.text("\u25C0\uFE0F Prev", `ag:page:${safePage - 1}`);
|
|
3569
|
+
}
|
|
3570
|
+
if (safePage < totalPages - 1) {
|
|
3571
|
+
keyboard.text("Next \u25B6\uFE0F", `ag:page:${safePage + 1}`);
|
|
3572
|
+
}
|
|
3573
|
+
keyboard.row();
|
|
3574
|
+
}
|
|
3575
|
+
if (available.some((i) => !i.available)) {
|
|
3576
|
+
text += "\n\u{1F4A1} <i>Agents marked \u26A0\uFE0F need additional setup. Use</i> <code>openacp agents info <name></code> <i>for details.</i>\n";
|
|
3577
|
+
}
|
|
3578
|
+
await ctx.reply(text, { parse_mode: "HTML", reply_markup: keyboard });
|
|
3579
|
+
} else {
|
|
3580
|
+
text += "<i>All agents are already installed!</i>";
|
|
3581
|
+
await ctx.reply(text, { parse_mode: "HTML" });
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
async function handleInstall(ctx, core) {
|
|
3585
|
+
const text = (ctx.message?.text ?? "").trim();
|
|
3586
|
+
const parts = text.split(/\s+/);
|
|
3587
|
+
const nameOrId = parts[1];
|
|
3588
|
+
if (!nameOrId) {
|
|
3589
|
+
await ctx.reply(
|
|
3590
|
+
"\u{1F4E6} <b>Install an agent</b>\n\nUsage: <code>/install <agent-name></code>\nExample: <code>/install gemini</code>\n\nUse /agents to browse available agents.",
|
|
3591
|
+
{ parse_mode: "HTML" }
|
|
3592
|
+
);
|
|
3593
|
+
return;
|
|
3594
|
+
}
|
|
3595
|
+
await installAgentWithProgress(ctx, core, nameOrId);
|
|
3596
|
+
}
|
|
3597
|
+
async function handleAgentCallback(ctx, core) {
|
|
3598
|
+
const data = ctx.callbackQuery?.data ?? "";
|
|
3599
|
+
await ctx.answerCallbackQuery();
|
|
3600
|
+
if (data.startsWith("ag:install:")) {
|
|
3601
|
+
const nameOrId = data.replace("ag:install:", "");
|
|
3602
|
+
await installAgentWithProgress(ctx, core, nameOrId);
|
|
3603
|
+
return;
|
|
3604
|
+
}
|
|
3605
|
+
if (data.startsWith("ag:page:")) {
|
|
3606
|
+
const page = parseInt(data.replace("ag:page:", ""), 10);
|
|
3607
|
+
try {
|
|
3608
|
+
const catalog = core.agentCatalog;
|
|
3609
|
+
const items = catalog.getAvailable();
|
|
3610
|
+
const installed = items.filter((i) => i.installed);
|
|
3611
|
+
const available = items.filter((i) => !i.installed);
|
|
3612
|
+
let text = "<b>\u{1F916} Agents</b>\n\n";
|
|
3613
|
+
if (installed.length > 0) {
|
|
3614
|
+
text += "<b>Installed:</b>\n";
|
|
3615
|
+
for (const item of installed) {
|
|
3616
|
+
text += `\u2705 <b>${escapeHtml(item.name)}</b>`;
|
|
3617
|
+
if (item.description) {
|
|
3618
|
+
text += ` \u2014 <i>${escapeHtml(truncate(item.description, 50))}</i>`;
|
|
3619
|
+
}
|
|
3620
|
+
text += "\n";
|
|
3621
|
+
}
|
|
3622
|
+
text += "\n";
|
|
3623
|
+
}
|
|
3624
|
+
const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE);
|
|
3625
|
+
const safePage = Math.max(0, Math.min(page, totalPages - 1));
|
|
3626
|
+
const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE);
|
|
3627
|
+
text += `<b>Available to install:</b>`;
|
|
3628
|
+
if (totalPages > 1) {
|
|
3629
|
+
text += ` (${safePage + 1}/${totalPages})`;
|
|
3630
|
+
}
|
|
3631
|
+
text += "\n";
|
|
3632
|
+
for (const item of pageItems) {
|
|
3633
|
+
if (item.available) {
|
|
3634
|
+
text += `\u2B07\uFE0F <b>${escapeHtml(item.name)}</b>`;
|
|
3635
|
+
} else {
|
|
3636
|
+
const deps = item.missingDeps?.join(", ") ?? "requirements not met";
|
|
3637
|
+
text += `\u26A0\uFE0F <b>${escapeHtml(item.name)}</b> <i>(needs: ${escapeHtml(deps)})</i>`;
|
|
3638
|
+
}
|
|
3639
|
+
if (item.description) {
|
|
3640
|
+
text += `
|
|
3641
|
+
<i>${escapeHtml(truncate(item.description, 60))}</i>`;
|
|
3642
|
+
}
|
|
3643
|
+
text += "\n";
|
|
3644
|
+
}
|
|
3645
|
+
const keyboard = new InlineKeyboard4();
|
|
3646
|
+
const installable = pageItems.filter((i) => i.available);
|
|
3647
|
+
for (let i = 0; i < installable.length; i += 2) {
|
|
3648
|
+
const row = installable.slice(i, i + 2);
|
|
3649
|
+
for (const item of row) {
|
|
3650
|
+
keyboard.text(`\u2B07\uFE0F ${item.name}`, `ag:install:${item.key}`);
|
|
3651
|
+
}
|
|
3652
|
+
keyboard.row();
|
|
3653
|
+
}
|
|
3654
|
+
if (totalPages > 1) {
|
|
3655
|
+
if (safePage > 0) {
|
|
3656
|
+
keyboard.text("\u25C0\uFE0F Prev", `ag:page:${safePage - 1}`);
|
|
3657
|
+
}
|
|
3658
|
+
if (safePage < totalPages - 1) {
|
|
3659
|
+
keyboard.text("Next \u25B6\uFE0F", `ag:page:${safePage + 1}`);
|
|
3660
|
+
}
|
|
3661
|
+
keyboard.row();
|
|
3662
|
+
}
|
|
3663
|
+
await ctx.editMessageText(text, { parse_mode: "HTML", reply_markup: keyboard });
|
|
3664
|
+
} catch {
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
async function installAgentWithProgress(ctx, core, nameOrId) {
|
|
3669
|
+
const catalog = core.agentCatalog;
|
|
3670
|
+
const msg = await ctx.reply(`\u23F3 Installing <b>${escapeHtml(nameOrId)}</b>...`, { parse_mode: "HTML" });
|
|
3671
|
+
let lastEdit = 0;
|
|
3672
|
+
const EDIT_THROTTLE_MS = 1500;
|
|
3673
|
+
const progress = {
|
|
3674
|
+
onStart(_id, _name) {
|
|
3675
|
+
},
|
|
3676
|
+
async onStep(step) {
|
|
3677
|
+
const now = Date.now();
|
|
3678
|
+
if (now - lastEdit > EDIT_THROTTLE_MS) {
|
|
3679
|
+
lastEdit = now;
|
|
3680
|
+
try {
|
|
3681
|
+
await ctx.api.editMessageText(msg.chat.id, msg.message_id, `\u23F3 <b>${escapeHtml(nameOrId)}</b>: ${escapeHtml(step)}`, { parse_mode: "HTML" });
|
|
3682
|
+
} catch {
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
},
|
|
3686
|
+
async onDownloadProgress(percent) {
|
|
3687
|
+
const now = Date.now();
|
|
3688
|
+
if (now - lastEdit > EDIT_THROTTLE_MS) {
|
|
3689
|
+
lastEdit = now;
|
|
3690
|
+
try {
|
|
3691
|
+
const bar = buildProgressBar(percent);
|
|
3692
|
+
await ctx.api.editMessageText(msg.chat.id, msg.message_id, `\u23F3 <b>${escapeHtml(nameOrId)}</b>
|
|
3693
|
+
Downloading... ${bar} ${percent}%`, { parse_mode: "HTML" });
|
|
3694
|
+
} catch {
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
},
|
|
3698
|
+
async onSuccess(name) {
|
|
3699
|
+
try {
|
|
3700
|
+
const keyboard = new InlineKeyboard4().text(`\u{1F680} Start session with ${name}`, `na:${nameOrId}`);
|
|
3701
|
+
await ctx.api.editMessageText(msg.chat.id, msg.message_id, `\u2705 <b>${escapeHtml(name)}</b> installed!`, { parse_mode: "HTML", reply_markup: keyboard });
|
|
3702
|
+
} catch {
|
|
3703
|
+
}
|
|
3704
|
+
},
|
|
3705
|
+
async onError(error) {
|
|
3706
|
+
try {
|
|
3707
|
+
await ctx.api.editMessageText(msg.chat.id, msg.message_id, `\u274C ${escapeHtml(error)}`, { parse_mode: "HTML" });
|
|
3708
|
+
} catch {
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
};
|
|
3712
|
+
await catalog.install(nameOrId, progress);
|
|
3713
|
+
}
|
|
3714
|
+
function truncate(text, maxLen) {
|
|
3715
|
+
if (text.length <= maxLen) return text;
|
|
3716
|
+
return text.slice(0, maxLen - 1) + "\u2026";
|
|
3717
|
+
}
|
|
3718
|
+
function buildProgressBar(percent) {
|
|
3719
|
+
const filled = Math.round(percent / 10);
|
|
3720
|
+
const empty = 10 - filled;
|
|
3721
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3724
|
+
// src/adapters/telegram/commands/integrate.ts
|
|
3725
|
+
import { InlineKeyboard as InlineKeyboard5 } from "grammy";
|
|
3355
3726
|
async function handleIntegrate(ctx, _core) {
|
|
3356
3727
|
const { listIntegrations } = await import("./integrate-WUPLRJD3.js");
|
|
3357
3728
|
const agents = listIntegrations();
|
|
3358
|
-
const keyboard = new
|
|
3729
|
+
const keyboard = new InlineKeyboard5();
|
|
3359
3730
|
for (const agent of agents) {
|
|
3360
3731
|
keyboard.text(`\u{1F916} ${agent}`, `i:agent:${agent}`).row();
|
|
3361
3732
|
}
|
|
@@ -3367,7 +3738,7 @@ Select an agent to manage its integrations.`,
|
|
|
3367
3738
|
);
|
|
3368
3739
|
}
|
|
3369
3740
|
function buildAgentItemsKeyboard(agentName, items) {
|
|
3370
|
-
const keyboard = new
|
|
3741
|
+
const keyboard = new InlineKeyboard5();
|
|
3371
3742
|
for (const item of items) {
|
|
3372
3743
|
const installed = item.isInstalled();
|
|
3373
3744
|
keyboard.text(
|
|
@@ -3388,7 +3759,7 @@ function setupIntegrateCallbacks(bot, core) {
|
|
|
3388
3759
|
if (data === "i:back") {
|
|
3389
3760
|
const { listIntegrations } = await import("./integrate-WUPLRJD3.js");
|
|
3390
3761
|
const agents = listIntegrations();
|
|
3391
|
-
const keyboard2 = new
|
|
3762
|
+
const keyboard2 = new InlineKeyboard5();
|
|
3392
3763
|
for (const agent of agents) {
|
|
3393
3764
|
keyboard2.text(`\u{1F916} ${agent}`, `i:agent:${agent}`).row();
|
|
3394
3765
|
}
|
|
@@ -3469,12 +3840,12 @@ ${resultText}`,
|
|
|
3469
3840
|
}
|
|
3470
3841
|
|
|
3471
3842
|
// src/adapters/telegram/commands/settings.ts
|
|
3472
|
-
import { InlineKeyboard as
|
|
3843
|
+
import { InlineKeyboard as InlineKeyboard6 } from "grammy";
|
|
3473
3844
|
var log12 = createChildLogger({ module: "telegram-settings" });
|
|
3474
3845
|
function buildSettingsKeyboard(core) {
|
|
3475
3846
|
const config = core.configManager.get();
|
|
3476
3847
|
const fields = getSafeFields();
|
|
3477
|
-
const kb = new
|
|
3848
|
+
const kb = new InlineKeyboard6();
|
|
3478
3849
|
for (const field of fields) {
|
|
3479
3850
|
const value = getConfigValue(config, field.path);
|
|
3480
3851
|
const label = formatFieldLabel(field, value);
|
|
@@ -3545,7 +3916,7 @@ function setupSettingsCallbacks(bot, core, getAssistantSession) {
|
|
|
3545
3916
|
if (!fieldDef) return;
|
|
3546
3917
|
const options = resolveOptions(fieldDef, config) ?? [];
|
|
3547
3918
|
const currentValue = getConfigValue(config, fieldPath);
|
|
3548
|
-
const kb = new
|
|
3919
|
+
const kb = new InlineKeyboard6();
|
|
3549
3920
|
for (const opt of options) {
|
|
3550
3921
|
const marker = opt === String(currentValue) ? " \u2713" : "";
|
|
3551
3922
|
kb.text(`${opt}${marker}`, `s:pick:${fieldPath}:${opt}`).row();
|
|
@@ -3617,7 +3988,7 @@ Tap to change:`, {
|
|
|
3617
3988
|
await ctx.answerCallbackQuery();
|
|
3618
3989
|
} catch {
|
|
3619
3990
|
}
|
|
3620
|
-
const { buildMenuKeyboard: buildMenuKeyboard3 } = await import("./menu-
|
|
3991
|
+
const { buildMenuKeyboard: buildMenuKeyboard3 } = await import("./menu-6RCPBVGQ.js");
|
|
3621
3992
|
try {
|
|
3622
3993
|
await ctx.editMessageText(`<b>OpenACP Menu</b>
|
|
3623
3994
|
Choose an action:`, {
|
|
@@ -3655,7 +4026,7 @@ function buildNestedUpdate(dotPath, value) {
|
|
|
3655
4026
|
}
|
|
3656
4027
|
|
|
3657
4028
|
// src/adapters/telegram/commands/doctor.ts
|
|
3658
|
-
import { InlineKeyboard as
|
|
4029
|
+
import { InlineKeyboard as InlineKeyboard7 } from "grammy";
|
|
3659
4030
|
var log13 = createChildLogger({ module: "telegram-cmd-doctor" });
|
|
3660
4031
|
var pendingFixesStore = /* @__PURE__ */ new Map();
|
|
3661
4032
|
function renderReport(report) {
|
|
@@ -3673,7 +4044,7 @@ function renderReport(report) {
|
|
|
3673
4044
|
lines.push(`<b>Result:</b> ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`);
|
|
3674
4045
|
let keyboard;
|
|
3675
4046
|
if (report.pendingFixes.length > 0) {
|
|
3676
|
-
keyboard = new
|
|
4047
|
+
keyboard = new InlineKeyboard7();
|
|
3677
4048
|
for (let i = 0; i < report.pendingFixes.length; i++) {
|
|
3678
4049
|
const label = `\u{1F527} Fix: ${report.pendingFixes[i].message.slice(0, 30)}`;
|
|
3679
4050
|
keyboard.text(label, `m:doctor:fix:${i}`).row();
|
|
@@ -3768,6 +4139,7 @@ function setupCommands(bot, core, chatId, assistant) {
|
|
|
3768
4139
|
bot.command("status", (ctx) => handleStatus(ctx, core));
|
|
3769
4140
|
bot.command("sessions", (ctx) => handleTopics(ctx, core));
|
|
3770
4141
|
bot.command("agents", (ctx) => handleAgents(ctx, core));
|
|
4142
|
+
bot.command("install", (ctx) => handleInstall(ctx, core));
|
|
3771
4143
|
bot.command("help", (ctx) => handleHelp(ctx));
|
|
3772
4144
|
bot.command("menu", (ctx) => handleMenu(ctx));
|
|
3773
4145
|
bot.command("enable_dangerous", (ctx) => handleEnableDangerous(ctx, core));
|
|
@@ -3783,6 +4155,12 @@ function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSessio
|
|
|
3783
4155
|
setupSessionCallbacks(bot, core, chatId, systemTopicIds);
|
|
3784
4156
|
setupSettingsCallbacks(bot, core, getAssistantSession ?? (() => void 0));
|
|
3785
4157
|
setupDoctorCallbacks(bot);
|
|
4158
|
+
bot.callbackQuery(/^ag:/, (ctx) => handleAgentCallback(ctx, core));
|
|
4159
|
+
bot.callbackQuery(/^na:/, async (ctx) => {
|
|
4160
|
+
const agentKey = ctx.callbackQuery.data.replace("na:", "");
|
|
4161
|
+
await ctx.answerCallbackQuery();
|
|
4162
|
+
await createSessionDirect(ctx, core, chatId, agentKey, core.configManager.get().workspace.baseDir);
|
|
4163
|
+
});
|
|
3786
4164
|
bot.callbackQuery(/^m:/, async (ctx) => {
|
|
3787
4165
|
const data = ctx.callbackQuery.data;
|
|
3788
4166
|
try {
|
|
@@ -3827,6 +4205,7 @@ var STATIC_COMMANDS = [
|
|
|
3827
4205
|
{ command: "status", description: "Show status" },
|
|
3828
4206
|
{ command: "sessions", description: "List all sessions" },
|
|
3829
4207
|
{ command: "agents", description: "List available agents" },
|
|
4208
|
+
{ command: "install", description: "Install a new agent" },
|
|
3830
4209
|
{ command: "help", description: "Help" },
|
|
3831
4210
|
{ command: "menu", description: "Show menu" },
|
|
3832
4211
|
{ command: "enable_dangerous", description: "Auto-approve all permission requests (session only)" },
|
|
@@ -3840,7 +4219,7 @@ var STATIC_COMMANDS = [
|
|
|
3840
4219
|
];
|
|
3841
4220
|
|
|
3842
4221
|
// src/adapters/telegram/permissions.ts
|
|
3843
|
-
import { InlineKeyboard as
|
|
4222
|
+
import { InlineKeyboard as InlineKeyboard8 } from "grammy";
|
|
3844
4223
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3845
4224
|
var log14 = createChildLogger({ module: "telegram-permissions" });
|
|
3846
4225
|
var PermissionHandler = class {
|
|
@@ -3859,7 +4238,7 @@ var PermissionHandler = class {
|
|
|
3859
4238
|
requestId: request.id,
|
|
3860
4239
|
options: request.options.map((o) => ({ id: o.id, isAllow: o.isAllow }))
|
|
3861
4240
|
});
|
|
3862
|
-
const keyboard = new
|
|
4241
|
+
const keyboard = new InlineKeyboard8();
|
|
3863
4242
|
for (const option of request.options) {
|
|
3864
4243
|
const emoji = option.isAllow ? "\u2705" : "\u274C";
|
|
3865
4244
|
keyboard.text(`${emoji} ${option.label}`, `p:${callbackKey}:${option.id}`);
|
|
@@ -4801,7 +5180,7 @@ var TelegramSendQueue = class {
|
|
|
4801
5180
|
|
|
4802
5181
|
// src/adapters/telegram/action-detect.ts
|
|
4803
5182
|
import { nanoid as nanoid3 } from "nanoid";
|
|
4804
|
-
import { InlineKeyboard as
|
|
5183
|
+
import { InlineKeyboard as InlineKeyboard9 } from "grammy";
|
|
4805
5184
|
var CMD_NEW_RE = /\/new(?:\s+([^\s\u0080-\uFFFF]+)(?:\s+([^\s\u0080-\uFFFF]+))?)?/;
|
|
4806
5185
|
var CMD_CANCEL_RE = /\/cancel\b/;
|
|
4807
5186
|
var KW_NEW_RE = /(?:create|new)\s+session/i;
|
|
@@ -4848,7 +5227,7 @@ function removeAction(id) {
|
|
|
4848
5227
|
actionMap.delete(id);
|
|
4849
5228
|
}
|
|
4850
5229
|
function buildActionKeyboard(actionId, action) {
|
|
4851
|
-
const keyboard = new
|
|
5230
|
+
const keyboard = new InlineKeyboard9();
|
|
4852
5231
|
if (action.action === "new_session") {
|
|
4853
5232
|
keyboard.text("\u2705 Create session", `a:${actionId}`);
|
|
4854
5233
|
keyboard.text("\u274C Cancel", `a:dismiss:${actionId}`);
|
|
@@ -5577,7 +5956,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
5577
5956
|
});
|
|
5578
5957
|
return;
|
|
5579
5958
|
}
|
|
5580
|
-
const { getAgentCapabilities: getAgentCapabilities2 } = await import("./agent-registry-
|
|
5959
|
+
const { getAgentCapabilities: getAgentCapabilities2 } = await import("./agent-registry-B5YAMA4T.js");
|
|
5581
5960
|
const caps = getAgentCapabilities2(agentName);
|
|
5582
5961
|
if (!caps.supportsResume || !caps.resumeCommand) {
|
|
5583
5962
|
await ctx.reply("This agent does not support session transfer.", {
|
|
@@ -5953,4 +6332,4 @@ export {
|
|
|
5953
6332
|
TopicManager,
|
|
5954
6333
|
TelegramAdapter
|
|
5955
6334
|
};
|
|
5956
|
-
//# sourceMappingURL=chunk-
|
|
6335
|
+
//# sourceMappingURL=chunk-FWN3UIRT.js.map
|