@openacp/cli 0.6.10 → 2026.41.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/README.md +34 -16
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +27787 -467
- package/dist/cli.js.map +1 -1
- package/dist/data/registry-snapshot.json +1 -1
- package/dist/index.d.ts +1944 -463
- package/dist/index.js +17365 -102
- package/dist/index.js.map +1 -1
- package/package.json +13 -7
- package/dist/action-detect-P7ZE4NEM.js +0 -16
- package/dist/action-detect-P7ZE4NEM.js.map +0 -1
- package/dist/adapter-ZOANORGM.js +0 -799
- package/dist/adapter-ZOANORGM.js.map +0 -1
- package/dist/admin-6SYB6XCZ.js +0 -23
- package/dist/admin-6SYB6XCZ.js.map +0 -1
- package/dist/agent-catalog-FC3HGDEQ.js +0 -11
- package/dist/agent-catalog-FC3HGDEQ.js.map +0 -1
- package/dist/agent-dependencies-4OWBMZWZ.js +0 -24
- package/dist/agent-dependencies-4OWBMZWZ.js.map +0 -1
- package/dist/agent-registry-WT4NXPYG.js +0 -9
- package/dist/agent-registry-WT4NXPYG.js.map +0 -1
- package/dist/agent-store-VZLFPTZU.js +0 -9
- package/dist/agent-store-VZLFPTZU.js.map +0 -1
- package/dist/agents-QO7DKARJ.js +0 -15
- package/dist/agents-QO7DKARJ.js.map +0 -1
- package/dist/api-client-CFQT5U7D.js +0 -14
- package/dist/api-client-CFQT5U7D.js.map +0 -1
- package/dist/autostart-X33OGMX6.js +0 -23
- package/dist/autostart-X33OGMX6.js.map +0 -1
- package/dist/chunk-2CJ46J3C.js +0 -154
- package/dist/chunk-2CJ46J3C.js.map +0 -1
- package/dist/chunk-2HMQOC7N.js +0 -134
- package/dist/chunk-2HMQOC7N.js.map +0 -1
- package/dist/chunk-33RP6K2O.js +0 -435
- package/dist/chunk-33RP6K2O.js.map +0 -1
- package/dist/chunk-34M4OS5P.js +0 -83
- package/dist/chunk-34M4OS5P.js.map +0 -1
- package/dist/chunk-4CTX774K.js +0 -265
- package/dist/chunk-4CTX774K.js.map +0 -1
- package/dist/chunk-7QJS2XBD.js +0 -92
- package/dist/chunk-7QJS2XBD.js.map +0 -1
- package/dist/chunk-BNLGTZ34.js +0 -122
- package/dist/chunk-BNLGTZ34.js.map +0 -1
- package/dist/chunk-CS3KCJ5D.js +0 -4788
- package/dist/chunk-CS3KCJ5D.js.map +0 -1
- package/dist/chunk-GAK6PIBW.js +0 -224
- package/dist/chunk-GAK6PIBW.js.map +0 -1
- package/dist/chunk-I7WC6E5S.js +0 -71
- package/dist/chunk-I7WC6E5S.js.map +0 -1
- package/dist/chunk-J4SJTKIK.js +0 -203
- package/dist/chunk-J4SJTKIK.js.map +0 -1
- package/dist/chunk-JHYXKVV2.js +0 -183
- package/dist/chunk-JHYXKVV2.js.map +0 -1
- package/dist/chunk-JKBFUAJK.js +0 -282
- package/dist/chunk-JKBFUAJK.js.map +0 -1
- package/dist/chunk-KIRH7TUJ.js +0 -219
- package/dist/chunk-KIRH7TUJ.js.map +0 -1
- package/dist/chunk-LBIKITQT.js +0 -22
- package/dist/chunk-LBIKITQT.js.map +0 -1
- package/dist/chunk-LCRLAV4G.js +0 -1085
- package/dist/chunk-LCRLAV4G.js.map +0 -1
- package/dist/chunk-LGP2YGRL.js +0 -4880
- package/dist/chunk-LGP2YGRL.js.map +0 -1
- package/dist/chunk-MKHUZLII.js +0 -738
- package/dist/chunk-MKHUZLII.js.map +0 -1
- package/dist/chunk-NAMYZIS5.js +0 -1
- package/dist/chunk-NAMYZIS5.js.map +0 -1
- package/dist/chunk-NVPG6JCL.js +0 -724
- package/dist/chunk-NVPG6JCL.js.map +0 -1
- package/dist/chunk-O7CPGUAI.js +0 -298
- package/dist/chunk-O7CPGUAI.js.map +0 -1
- package/dist/chunk-OWP7RZ62.js +0 -697
- package/dist/chunk-OWP7RZ62.js.map +0 -1
- package/dist/chunk-S64CB6J3.js +0 -98
- package/dist/chunk-S64CB6J3.js.map +0 -1
- package/dist/chunk-UKT3G5IA.js +0 -484
- package/dist/chunk-UKT3G5IA.js.map +0 -1
- package/dist/chunk-V5GZQEIY.js +0 -101
- package/dist/chunk-V5GZQEIY.js.map +0 -1
- package/dist/chunk-VOIJ6OY4.js +0 -63
- package/dist/chunk-VOIJ6OY4.js.map +0 -1
- package/dist/chunk-VUNV25KB.js +0 -16
- package/dist/chunk-VUNV25KB.js.map +0 -1
- package/dist/chunk-W3EYKZNQ.js +0 -45
- package/dist/chunk-W3EYKZNQ.js.map +0 -1
- package/dist/chunk-WTZDAYZX.js +0 -172
- package/dist/chunk-WTZDAYZX.js.map +0 -1
- package/dist/chunk-XANPHG7W.js +0 -145
- package/dist/chunk-XANPHG7W.js.map +0 -1
- package/dist/config-6S355X75.js +0 -15
- package/dist/config-6S355X75.js.map +0 -1
- package/dist/config-editor-QQTZMWGD.js +0 -13
- package/dist/config-editor-QQTZMWGD.js.map +0 -1
- package/dist/config-registry-AHYI4MYL.js +0 -18
- package/dist/config-registry-AHYI4MYL.js.map +0 -1
- package/dist/daemon-4CS6HMB5.js +0 -30
- package/dist/daemon-4CS6HMB5.js.map +0 -1
- package/dist/discord-OMC52Y54.js +0 -2239
- package/dist/discord-OMC52Y54.js.map +0 -1
- package/dist/dist-UHQK5CXN.js +0 -21151
- package/dist/dist-UHQK5CXN.js.map +0 -1
- package/dist/doctor-HZZ5BSHB.js +0 -10
- package/dist/doctor-HZZ5BSHB.js.map +0 -1
- package/dist/doctor-OLYBO3V3.js +0 -15
- package/dist/doctor-OLYBO3V3.js.map +0 -1
- package/dist/install-cloudflared-Z7VCGOVG.js +0 -33
- package/dist/install-cloudflared-Z7VCGOVG.js.map +0 -1
- package/dist/install-jq-HUYSQWKR.js +0 -32
- package/dist/install-jq-HUYSQWKR.js.map +0 -1
- package/dist/integrate-PNEHRY2I.js +0 -373
- package/dist/integrate-PNEHRY2I.js.map +0 -1
- package/dist/log-NXABYJTT.js +0 -24
- package/dist/log-NXABYJTT.js.map +0 -1
- package/dist/main-XOZCLFUK.js +0 -238
- package/dist/main-XOZCLFUK.js.map +0 -1
- package/dist/menu-YY5MKHEK.js +0 -16
- package/dist/menu-YY5MKHEK.js.map +0 -1
- package/dist/new-session-FEO4J4VU.js +0 -17
- package/dist/new-session-FEO4J4VU.js.map +0 -1
- package/dist/post-upgrade-CJG5I7M2.js +0 -80
- package/dist/post-upgrade-CJG5I7M2.js.map +0 -1
- package/dist/session-IUSI7P5S.js +0 -20
- package/dist/session-IUSI7P5S.js.map +0 -1
- package/dist/settings-RQPAM4KC.js +0 -14
- package/dist/settings-RQPAM4KC.js.map +0 -1
- package/dist/setup-XHS4OMPM.js +0 -37
- package/dist/setup-XHS4OMPM.js.map +0 -1
- package/dist/suggest-7D6B542M.js +0 -38
- package/dist/suggest-7D6B542M.js.map +0 -1
- package/dist/tunnel-service-CJLUH6SZ.js +0 -1174
- package/dist/tunnel-service-CJLUH6SZ.js.map +0 -1
- package/dist/version-NQZBM5M7.js +0 -16
- package/dist/version-NQZBM5M7.js.map +0 -1
package/dist/chunk-LCRLAV4G.js
DELETED
|
@@ -1,1085 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
commandExists
|
|
3
|
-
} from "./chunk-JKBFUAJK.js";
|
|
4
|
-
import {
|
|
5
|
-
expandHome
|
|
6
|
-
} from "./chunk-33RP6K2O.js";
|
|
7
|
-
|
|
8
|
-
// src/core/setup/wizard.ts
|
|
9
|
-
import * as clack9 from "@clack/prompts";
|
|
10
|
-
|
|
11
|
-
// src/core/setup/types.ts
|
|
12
|
-
var ONBOARD_SECTION_OPTIONS = [
|
|
13
|
-
{ value: "channels", label: "Channels", hint: "Link/update messaging platforms" },
|
|
14
|
-
{ value: "agents", label: "Agents", hint: "Install agents, change default" },
|
|
15
|
-
{ value: "workspace", label: "Workspace", hint: "Set workspace directory" },
|
|
16
|
-
{ value: "runMode", label: "Run mode", hint: "Foreground/daemon, auto-start" },
|
|
17
|
-
{ value: "integrations", label: "Integrations", hint: "Claude CLI session transfer" }
|
|
18
|
-
];
|
|
19
|
-
var CHANNEL_META = {
|
|
20
|
-
telegram: { label: "Telegram", method: "Bot API" },
|
|
21
|
-
discord: { label: "Discord", method: "Bot API" }
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// src/core/setup/helpers.ts
|
|
25
|
-
import * as clack from "@clack/prompts";
|
|
26
|
-
var c = {
|
|
27
|
-
reset: "\x1B[0m",
|
|
28
|
-
bold: "\x1B[1m",
|
|
29
|
-
dim: "\x1B[2m",
|
|
30
|
-
green: "\x1B[32m",
|
|
31
|
-
yellow: "\x1B[33m",
|
|
32
|
-
red: "\x1B[31m",
|
|
33
|
-
cyan: "\x1B[36m",
|
|
34
|
-
white: "\x1B[37m"
|
|
35
|
-
};
|
|
36
|
-
var ok = (msg) => `${c.green}${c.bold}\u2713${c.reset} ${c.green}${msg}${c.reset}`;
|
|
37
|
-
var warn = (msg) => `${c.yellow}\u26A0 ${msg}${c.reset}`;
|
|
38
|
-
var fail = (msg) => `${c.red}\u2717 ${msg}${c.reset}`;
|
|
39
|
-
var step = (n, total, title) => `
|
|
40
|
-
${c.cyan}${c.bold}[${n}/${total}]${c.reset} ${c.bold}${title}${c.reset}
|
|
41
|
-
`;
|
|
42
|
-
var dim = (msg) => `${c.dim}${msg}${c.reset}`;
|
|
43
|
-
function guardCancel(value) {
|
|
44
|
-
if (clack.isCancel(value)) {
|
|
45
|
-
clack.cancel("Setup cancelled.");
|
|
46
|
-
process.exit(0);
|
|
47
|
-
}
|
|
48
|
-
return value;
|
|
49
|
-
}
|
|
50
|
-
function applyGradient(text4) {
|
|
51
|
-
const colors = [135, 99, 63, 33, 39, 44, 44];
|
|
52
|
-
const lines = text4.split("\n");
|
|
53
|
-
return lines.map((line, i) => {
|
|
54
|
-
const colorIdx = Math.min(i, colors.length - 1);
|
|
55
|
-
return `\x1B[38;5;${colors[colorIdx]}m${line}\x1B[0m`;
|
|
56
|
-
}).join("\n");
|
|
57
|
-
}
|
|
58
|
-
var BANNER = `
|
|
59
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
60
|
-
\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
61
|
-
\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
62
|
-
\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u255D
|
|
63
|
-
\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
|
|
64
|
-
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D
|
|
65
|
-
`;
|
|
66
|
-
async function printStartBanner() {
|
|
67
|
-
let version = "0.0.0";
|
|
68
|
-
try {
|
|
69
|
-
const { getCurrentVersion } = await import("./version-NQZBM5M7.js");
|
|
70
|
-
version = getCurrentVersion();
|
|
71
|
-
} catch {
|
|
72
|
-
}
|
|
73
|
-
console.log(applyGradient(BANNER));
|
|
74
|
-
console.log(`${c.dim} AI coding agents, anywhere. v${version}${c.reset}
|
|
75
|
-
`);
|
|
76
|
-
}
|
|
77
|
-
function summarizeConfig(config) {
|
|
78
|
-
const lines = [];
|
|
79
|
-
const channelStatuses = [];
|
|
80
|
-
for (const [id, meta] of Object.entries({
|
|
81
|
-
telegram: "Telegram",
|
|
82
|
-
discord: "Discord"
|
|
83
|
-
})) {
|
|
84
|
-
const ch = config.channels[id];
|
|
85
|
-
if (ch?.enabled) {
|
|
86
|
-
channelStatuses.push(`${meta} (enabled)`);
|
|
87
|
-
} else if (ch && Object.keys(ch).length > 1) {
|
|
88
|
-
channelStatuses.push(`${meta} (disabled)`);
|
|
89
|
-
} else {
|
|
90
|
-
channelStatuses.push(`${meta} (not configured)`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
lines.push(`Channels: ${channelStatuses.join(", ")}`);
|
|
94
|
-
lines.push(`Default agent: ${config.defaultAgent}`);
|
|
95
|
-
lines.push(`Workspace: ${config.workspace.baseDir}`);
|
|
96
|
-
lines.push(`Run mode: ${config.runMode}${config.autoStart ? " (auto-start)" : ""}`);
|
|
97
|
-
return lines.join("\n");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// src/core/setup/setup-telegram.ts
|
|
101
|
-
import * as clack2 from "@clack/prompts";
|
|
102
|
-
|
|
103
|
-
// src/core/setup/validation.ts
|
|
104
|
-
async function validateBotToken(token) {
|
|
105
|
-
try {
|
|
106
|
-
const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);
|
|
107
|
-
const data = await res.json();
|
|
108
|
-
if (data.ok && data.result) {
|
|
109
|
-
return {
|
|
110
|
-
ok: true,
|
|
111
|
-
botName: data.result.first_name,
|
|
112
|
-
botUsername: data.result.username
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
return { ok: false, error: data.description || "Invalid token" };
|
|
116
|
-
} catch (err) {
|
|
117
|
-
return { ok: false, error: err.message };
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function validateChatId(token, chatId) {
|
|
121
|
-
try {
|
|
122
|
-
const res = await fetch(`https://api.telegram.org/bot${token}/getChat`, {
|
|
123
|
-
method: "POST",
|
|
124
|
-
headers: { "Content-Type": "application/json" },
|
|
125
|
-
body: JSON.stringify({ chat_id: chatId })
|
|
126
|
-
});
|
|
127
|
-
const data = await res.json();
|
|
128
|
-
if (!data.ok || !data.result) {
|
|
129
|
-
return { ok: false, error: data.description || "Invalid chat ID" };
|
|
130
|
-
}
|
|
131
|
-
if (data.result.type !== "supergroup") {
|
|
132
|
-
return {
|
|
133
|
-
ok: false,
|
|
134
|
-
error: `Chat is "${data.result.type}", must be a supergroup`
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
ok: true,
|
|
139
|
-
title: data.result.title,
|
|
140
|
-
isForum: data.result.is_forum === true
|
|
141
|
-
};
|
|
142
|
-
} catch (err) {
|
|
143
|
-
return { ok: false, error: err.message };
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
async function validateBotAdmin(token, chatId) {
|
|
147
|
-
try {
|
|
148
|
-
const meRes = await fetch(`https://api.telegram.org/bot${token}/getMe`);
|
|
149
|
-
const meData = await meRes.json();
|
|
150
|
-
if (!meData.ok || !meData.result) {
|
|
151
|
-
return { ok: false, error: "Could not retrieve bot info" };
|
|
152
|
-
}
|
|
153
|
-
const res = await fetch(
|
|
154
|
-
`https://api.telegram.org/bot${token}/getChatMember`,
|
|
155
|
-
{
|
|
156
|
-
method: "POST",
|
|
157
|
-
headers: { "Content-Type": "application/json" },
|
|
158
|
-
body: JSON.stringify({ chat_id: chatId, user_id: meData.result.id })
|
|
159
|
-
}
|
|
160
|
-
);
|
|
161
|
-
const data = await res.json();
|
|
162
|
-
if (!data.ok || !data.result) {
|
|
163
|
-
return {
|
|
164
|
-
ok: false,
|
|
165
|
-
error: data.description || "Could not check bot membership"
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
const { status } = data.result;
|
|
169
|
-
if (status === "administrator" || status === "creator") {
|
|
170
|
-
return { ok: true };
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
ok: false,
|
|
174
|
-
error: `Bot is "${status}" in this group. It must be an admin. Please promote the bot to admin in group settings.`
|
|
175
|
-
};
|
|
176
|
-
} catch (err) {
|
|
177
|
-
return { ok: false, error: err.message };
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
async function validateDiscordToken(token) {
|
|
181
|
-
try {
|
|
182
|
-
const res = await fetch("https://discord.com/api/v10/users/@me", {
|
|
183
|
-
headers: { Authorization: `Bot ${token}` }
|
|
184
|
-
});
|
|
185
|
-
if (res.status === 200) {
|
|
186
|
-
const data = await res.json();
|
|
187
|
-
return { ok: true, username: data.username, id: data.id };
|
|
188
|
-
}
|
|
189
|
-
if (res.status === 401) {
|
|
190
|
-
return { ok: false, error: "Token rejected by Discord (401 Unauthorized)" };
|
|
191
|
-
}
|
|
192
|
-
return { ok: false, error: `Discord API returned ${res.status}` };
|
|
193
|
-
} catch (err) {
|
|
194
|
-
return { ok: false, error: err.message };
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// src/core/setup/setup-telegram.ts
|
|
199
|
-
async function promptManualChatId() {
|
|
200
|
-
const val = guardCancel(
|
|
201
|
-
await clack2.text({
|
|
202
|
-
message: "Supergroup chat ID (e.g. -1001234567890):",
|
|
203
|
-
validate: (val2) => {
|
|
204
|
-
const n = Number((val2 ?? "").toString().trim());
|
|
205
|
-
if (isNaN(n) || !Number.isInteger(n)) return "Chat ID must be an integer";
|
|
206
|
-
return void 0;
|
|
207
|
-
}
|
|
208
|
-
})
|
|
209
|
-
);
|
|
210
|
-
return Number(val.trim());
|
|
211
|
-
}
|
|
212
|
-
async function detectChatId(token) {
|
|
213
|
-
let lastUpdateId = 0;
|
|
214
|
-
try {
|
|
215
|
-
const clearRes = await fetch(
|
|
216
|
-
`https://api.telegram.org/bot${token}/getUpdates?offset=-1`
|
|
217
|
-
);
|
|
218
|
-
const clearData = await clearRes.json();
|
|
219
|
-
if (clearData.ok && clearData.result?.length) {
|
|
220
|
-
lastUpdateId = clearData.result[clearData.result.length - 1].update_id;
|
|
221
|
-
}
|
|
222
|
-
} catch {
|
|
223
|
-
}
|
|
224
|
-
console.log("");
|
|
225
|
-
console.log(` ${c.bold}If you don't have a supergroup yet:${c.reset}`);
|
|
226
|
-
console.log(dim(" 1. Open Telegram \u2192 New Group \u2192 add your bot"));
|
|
227
|
-
console.log(dim(" 2. Group Settings \u2192 convert to Supergroup"));
|
|
228
|
-
console.log(dim(" 3. Enable Topics in group settings"));
|
|
229
|
-
console.log("");
|
|
230
|
-
console.log(` ${c.bold}Then send "hi" in the group.${c.reset}`);
|
|
231
|
-
console.log(
|
|
232
|
-
dim(
|
|
233
|
-
` Listening... press ${c.reset}${c.yellow}m${c.reset}${c.dim} to enter ID manually`
|
|
234
|
-
)
|
|
235
|
-
);
|
|
236
|
-
console.log("");
|
|
237
|
-
const MAX_ATTEMPTS = 120;
|
|
238
|
-
const POLL_INTERVAL = 1e3;
|
|
239
|
-
let cancelled = false;
|
|
240
|
-
const onKeypress = (data) => {
|
|
241
|
-
const key = data.toString();
|
|
242
|
-
if (key === "m" || key === "M") {
|
|
243
|
-
cancelled = true;
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
if (process.stdin.isTTY) {
|
|
247
|
-
process.stdin.setRawMode(true);
|
|
248
|
-
process.stdin.resume();
|
|
249
|
-
process.stdin.on("data", onKeypress);
|
|
250
|
-
}
|
|
251
|
-
const cleanup = () => {
|
|
252
|
-
if (process.stdin.isTTY) {
|
|
253
|
-
process.stdin.removeListener("data", onKeypress);
|
|
254
|
-
process.stdin.setRawMode(false);
|
|
255
|
-
process.stdin.pause();
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
try {
|
|
259
|
-
for (let i = 0; i < MAX_ATTEMPTS; i++) {
|
|
260
|
-
if (cancelled) {
|
|
261
|
-
cleanup();
|
|
262
|
-
return promptManualChatId();
|
|
263
|
-
}
|
|
264
|
-
try {
|
|
265
|
-
const offset = lastUpdateId ? lastUpdateId + 1 : 0;
|
|
266
|
-
const res = await fetch(
|
|
267
|
-
`https://api.telegram.org/bot${token}/getUpdates?offset=${offset}&timeout=1`
|
|
268
|
-
);
|
|
269
|
-
const data = await res.json();
|
|
270
|
-
if (!data.ok || !data.result?.length) {
|
|
271
|
-
await new Promise((r) => setTimeout(r, POLL_INTERVAL));
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
const groups = /* @__PURE__ */ new Map();
|
|
275
|
-
for (const update of data.result) {
|
|
276
|
-
lastUpdateId = update.update_id;
|
|
277
|
-
const chat = update.message?.chat ?? update.my_chat_member?.chat;
|
|
278
|
-
if (chat && (chat.type === "supergroup" || chat.type === "group")) {
|
|
279
|
-
groups.set(chat.id, chat.title ?? String(chat.id));
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (groups.size === 1) {
|
|
283
|
-
const [id, title] = [...groups.entries()][0];
|
|
284
|
-
console.log(
|
|
285
|
-
ok(`Group detected: ${c.bold}${title}${c.reset}${c.green} (${id})`)
|
|
286
|
-
);
|
|
287
|
-
cleanup();
|
|
288
|
-
return id;
|
|
289
|
-
}
|
|
290
|
-
if (groups.size > 1) {
|
|
291
|
-
cleanup();
|
|
292
|
-
const options = [...groups.entries()].map(([id, title]) => ({
|
|
293
|
-
label: `${title} (${id})`,
|
|
294
|
-
value: id
|
|
295
|
-
}));
|
|
296
|
-
return guardCancel(
|
|
297
|
-
await clack2.select({
|
|
298
|
-
message: "Multiple groups found. Pick one:",
|
|
299
|
-
options
|
|
300
|
-
})
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
} catch {
|
|
304
|
-
}
|
|
305
|
-
await new Promise((r) => setTimeout(r, POLL_INTERVAL));
|
|
306
|
-
}
|
|
307
|
-
console.log(warn("Timed out waiting for messages."));
|
|
308
|
-
cleanup();
|
|
309
|
-
return promptManualChatId();
|
|
310
|
-
} catch (err) {
|
|
311
|
-
cleanup();
|
|
312
|
-
throw err;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
async function detectAndValidateChatId(botToken) {
|
|
316
|
-
while (true) {
|
|
317
|
-
const chatId = await detectChatId(botToken);
|
|
318
|
-
const chatResult = await validateChatId(botToken, chatId);
|
|
319
|
-
if (!chatResult.ok) {
|
|
320
|
-
console.log(fail(chatResult.error));
|
|
321
|
-
console.log("");
|
|
322
|
-
console.log(` ${c.bold}How to fix:${c.reset}`);
|
|
323
|
-
console.log(dim(" 1. Make sure the bot is added to the group"));
|
|
324
|
-
console.log(dim(" 2. The group must be a Supergroup (Group Settings \u2192 convert)"));
|
|
325
|
-
console.log(dim(" 3. Send a message in the group after adding the bot"));
|
|
326
|
-
console.log("");
|
|
327
|
-
guardCancel(await clack2.text({ message: "Press Enter to try again..." }));
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
|
-
console.log(
|
|
331
|
-
ok(
|
|
332
|
-
`Group: ${c.bold}${chatResult.title}${c.reset}${c.green}${chatResult.isForum ? " (Topics enabled)" : ""}`
|
|
333
|
-
)
|
|
334
|
-
);
|
|
335
|
-
const adminResult = await validateBotAdmin(botToken, chatId);
|
|
336
|
-
if (!adminResult.ok) {
|
|
337
|
-
console.log(fail(adminResult.error));
|
|
338
|
-
console.log("");
|
|
339
|
-
console.log(` ${c.bold}How to fix:${c.reset}`);
|
|
340
|
-
console.log(dim(" 1. Open the group in Telegram"));
|
|
341
|
-
console.log(dim(" 2. Go to Group Settings \u2192 Administrators"));
|
|
342
|
-
console.log(dim(" 3. Add the bot as an administrator"));
|
|
343
|
-
console.log("");
|
|
344
|
-
guardCancel(await clack2.text({ message: "Press Enter to check again..." }));
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
console.log(ok("Bot has admin privileges"));
|
|
348
|
-
return chatId;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
async function setupTelegram(opts) {
|
|
352
|
-
const { existing, stepNum, totalSteps } = opts ?? {};
|
|
353
|
-
if (stepNum != null && totalSteps != null) {
|
|
354
|
-
console.log(step(stepNum, totalSteps, "Telegram Bot"));
|
|
355
|
-
}
|
|
356
|
-
let botToken = "";
|
|
357
|
-
const existingToken = existing?.botToken;
|
|
358
|
-
while (true) {
|
|
359
|
-
const tokenInput = guardCancel(
|
|
360
|
-
await clack2.text({
|
|
361
|
-
message: existingToken ? "Bot token (from @BotFather) \u2014 leave blank to keep current:" : "Bot token (from @BotFather):",
|
|
362
|
-
...existingToken ? { placeholder: "Leave blank to keep current" } : {},
|
|
363
|
-
validate: (val) => {
|
|
364
|
-
if (existingToken && (val ?? "").toString().trim().length === 0) return void 0;
|
|
365
|
-
if ((val ?? "").toString().trim().length > 0) return void 0;
|
|
366
|
-
return "Token cannot be empty";
|
|
367
|
-
}
|
|
368
|
-
})
|
|
369
|
-
);
|
|
370
|
-
const keptExisting = existingToken && !tokenInput.trim();
|
|
371
|
-
botToken = tokenInput.trim() || existingToken || "";
|
|
372
|
-
if (!botToken) continue;
|
|
373
|
-
if (keptExisting) {
|
|
374
|
-
console.log(ok("Keeping current bot token"));
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
const s = clack2.spinner();
|
|
378
|
-
s.start("Validating token...");
|
|
379
|
-
const result = await validateBotToken(botToken);
|
|
380
|
-
s.stop("Token validated");
|
|
381
|
-
if (result.ok) {
|
|
382
|
-
console.log(ok(`Connected to @${result.botUsername}`));
|
|
383
|
-
break;
|
|
384
|
-
}
|
|
385
|
-
console.log(fail(result.error));
|
|
386
|
-
const action = guardCancel(
|
|
387
|
-
await clack2.select({
|
|
388
|
-
message: "What to do?",
|
|
389
|
-
options: [
|
|
390
|
-
{ label: "Re-enter token", value: "retry" },
|
|
391
|
-
{ label: "Use as-is (skip validation)", value: "skip" }
|
|
392
|
-
]
|
|
393
|
-
})
|
|
394
|
-
);
|
|
395
|
-
if (action === "skip") break;
|
|
396
|
-
}
|
|
397
|
-
let chatId;
|
|
398
|
-
const existingChatId = existing?.chatId;
|
|
399
|
-
if (existingChatId && existingChatId !== 0) {
|
|
400
|
-
const chatIdAction = guardCancel(
|
|
401
|
-
await clack2.select({
|
|
402
|
-
message: `Group chat ID: ${existingChatId}`,
|
|
403
|
-
options: [
|
|
404
|
-
{ value: "keep", label: "Keep current" },
|
|
405
|
-
{ value: "manual", label: "Enter new chat ID" },
|
|
406
|
-
{ value: "detect", label: "Auto-detect from group" }
|
|
407
|
-
],
|
|
408
|
-
initialValue: "keep"
|
|
409
|
-
})
|
|
410
|
-
);
|
|
411
|
-
if (chatIdAction === "keep") {
|
|
412
|
-
chatId = existingChatId;
|
|
413
|
-
console.log(ok("Keeping current group chat ID"));
|
|
414
|
-
} else if (chatIdAction === "manual") {
|
|
415
|
-
chatId = await promptManualChatId();
|
|
416
|
-
const chatResult = await validateChatId(botToken, chatId);
|
|
417
|
-
if (chatResult.ok) {
|
|
418
|
-
console.log(ok(`Group: ${c.bold}${chatResult.title}${c.reset}${c.green}${chatResult.isForum ? " (Topics enabled)" : ""}`));
|
|
419
|
-
} else {
|
|
420
|
-
console.log(fail(chatResult.error));
|
|
421
|
-
}
|
|
422
|
-
} else {
|
|
423
|
-
chatId = await detectAndValidateChatId(botToken);
|
|
424
|
-
}
|
|
425
|
-
} else {
|
|
426
|
-
chatId = await detectAndValidateChatId(botToken);
|
|
427
|
-
}
|
|
428
|
-
return {
|
|
429
|
-
enabled: true,
|
|
430
|
-
botToken,
|
|
431
|
-
chatId,
|
|
432
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
433
|
-
notificationTopicId: existing?.notificationTopicId ?? null,
|
|
434
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
435
|
-
assistantTopicId: existing?.assistantTopicId ?? null
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// src/core/setup/setup-discord.ts
|
|
440
|
-
import * as clack3 from "@clack/prompts";
|
|
441
|
-
async function setupDiscord(opts) {
|
|
442
|
-
const { existing } = opts ?? {};
|
|
443
|
-
console.log("\nDiscord Setup\n");
|
|
444
|
-
console.log(` ${c.bold}Quick setup:${c.reset}`);
|
|
445
|
-
console.log(dim(" 1. Create app at https://discord.com/developers/applications"));
|
|
446
|
-
console.log(dim(" 2. Go to Bot \u2192 Reset Token \u2192 copy it"));
|
|
447
|
-
console.log(dim(" 3. Enable Message Content Intent (Bot \u2192 Privileged Intents)"));
|
|
448
|
-
console.log(dim(" 4. OAuth2 \u2192 URL Generator \u2192 scopes: bot + applications.commands"));
|
|
449
|
-
console.log(dim(" 5. Bot Permissions: Manage Channels, Send Messages, Manage Threads, Attach Files"));
|
|
450
|
-
console.log(dim(" 6. Open generated URL \u2192 invite bot to your server"));
|
|
451
|
-
console.log("");
|
|
452
|
-
console.log(dim(` Detailed guide: https://github.com/Open-ACP/OpenACP/blob/main/docs/guide/discord-setup.md`));
|
|
453
|
-
console.log("");
|
|
454
|
-
let botToken = "";
|
|
455
|
-
const existingToken = existing?.botToken;
|
|
456
|
-
while (true) {
|
|
457
|
-
const tokenInput = guardCancel(
|
|
458
|
-
await clack3.text({
|
|
459
|
-
message: existingToken ? "Bot token (from Discord Developer Portal) \u2014 leave blank to keep current:" : "Bot token (from Discord Developer Portal):",
|
|
460
|
-
...existingToken ? { placeholder: "Leave blank to keep current" } : {},
|
|
461
|
-
validate: (val) => {
|
|
462
|
-
if (existingToken && (val ?? "").toString().trim().length === 0) return void 0;
|
|
463
|
-
if ((val ?? "").toString().trim().length > 0) return void 0;
|
|
464
|
-
return "Token cannot be empty";
|
|
465
|
-
}
|
|
466
|
-
})
|
|
467
|
-
);
|
|
468
|
-
const keptExisting = existingToken && !tokenInput.trim();
|
|
469
|
-
botToken = tokenInput.trim() || existingToken || "";
|
|
470
|
-
if (!botToken) continue;
|
|
471
|
-
if (keptExisting) {
|
|
472
|
-
console.log(ok("Keeping current bot token"));
|
|
473
|
-
break;
|
|
474
|
-
}
|
|
475
|
-
const s = clack3.spinner();
|
|
476
|
-
s.start("Validating token...");
|
|
477
|
-
const result = await validateDiscordToken(botToken);
|
|
478
|
-
s.stop("Token validated");
|
|
479
|
-
if (result.ok) {
|
|
480
|
-
console.log(ok(`Connected as @${result.username} (id: ${result.id})`));
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
console.log(fail(result.error));
|
|
484
|
-
const action = guardCancel(
|
|
485
|
-
await clack3.select({
|
|
486
|
-
message: "What to do?",
|
|
487
|
-
options: [
|
|
488
|
-
{ label: "Re-enter token", value: "retry" },
|
|
489
|
-
{ label: "Use as-is (skip validation)", value: "skip" }
|
|
490
|
-
]
|
|
491
|
-
})
|
|
492
|
-
);
|
|
493
|
-
if (action === "skip") break;
|
|
494
|
-
}
|
|
495
|
-
const guildIdInput = guardCancel(
|
|
496
|
-
await clack3.text({
|
|
497
|
-
message: existing?.guildId ? "Guild (server) ID \u2014 leave blank to keep current:" : "Guild (server) ID:",
|
|
498
|
-
...existing?.guildId ? { placeholder: `Current: ${existing.guildId}` } : {},
|
|
499
|
-
validate: (val) => {
|
|
500
|
-
const trimmed = (val ?? "").toString().trim();
|
|
501
|
-
if (existing?.guildId && !trimmed) return void 0;
|
|
502
|
-
if (!trimmed) return "Guild ID cannot be empty";
|
|
503
|
-
if (!/^\d{17,20}$/.test(trimmed)) return "Guild ID must be a numeric Discord snowflake (17-20 digits)";
|
|
504
|
-
return void 0;
|
|
505
|
-
}
|
|
506
|
-
})
|
|
507
|
-
);
|
|
508
|
-
const guildId = guildIdInput.trim() || existing?.guildId || "";
|
|
509
|
-
return {
|
|
510
|
-
enabled: true,
|
|
511
|
-
botToken,
|
|
512
|
-
guildId: guildId.trim(),
|
|
513
|
-
forumChannelId: existing?.forumChannelId ?? null,
|
|
514
|
-
notificationChannelId: existing?.notificationChannelId ?? null,
|
|
515
|
-
assistantThreadId: existing?.assistantThreadId ?? null
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// src/core/setup/setup-agents.ts
|
|
520
|
-
import { execFileSync } from "child_process";
|
|
521
|
-
import * as clack4 from "@clack/prompts";
|
|
522
|
-
var KNOWN_AGENTS = [
|
|
523
|
-
// claude-agent-acp is bundled as a dependency — no detection needed, but
|
|
524
|
-
// kept here so detectAgents() still returns it for display purposes.
|
|
525
|
-
{ name: "claude", commands: ["claude-agent-acp"] },
|
|
526
|
-
{ name: "codex", commands: ["codex"] }
|
|
527
|
-
];
|
|
528
|
-
async function detectAgents() {
|
|
529
|
-
const found = [];
|
|
530
|
-
for (const agent of KNOWN_AGENTS) {
|
|
531
|
-
const available = [];
|
|
532
|
-
for (const cmd of agent.commands) {
|
|
533
|
-
if (commandExists(cmd)) {
|
|
534
|
-
available.push(cmd);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
if (available.length > 0) {
|
|
538
|
-
found.push({ name: agent.name, command: available[0] });
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
return found;
|
|
542
|
-
}
|
|
543
|
-
async function validateAgentCommand(command) {
|
|
544
|
-
try {
|
|
545
|
-
execFileSync("which", [command], { stdio: "pipe" });
|
|
546
|
-
return true;
|
|
547
|
-
} catch {
|
|
548
|
-
return false;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
async function setupAgents() {
|
|
552
|
-
const { AgentCatalog } = await import("./agent-catalog-FC3HGDEQ.js");
|
|
553
|
-
const { muteLogger, unmuteLogger } = await import("./log-NXABYJTT.js");
|
|
554
|
-
muteLogger();
|
|
555
|
-
const catalog = new AgentCatalog();
|
|
556
|
-
catalog.load();
|
|
557
|
-
const s = clack4.spinner();
|
|
558
|
-
s.start("Checking available agents...");
|
|
559
|
-
await catalog.refreshRegistryIfStale();
|
|
560
|
-
if (!catalog.getInstalledAgent("claude")) {
|
|
561
|
-
const claudeRegistry = catalog.findRegistryAgent("claude-acp");
|
|
562
|
-
if (claudeRegistry) {
|
|
563
|
-
await catalog.install("claude-acp");
|
|
564
|
-
} else {
|
|
565
|
-
const { AgentStore } = await import("./agent-store-VZLFPTZU.js");
|
|
566
|
-
const store = new AgentStore();
|
|
567
|
-
store.load();
|
|
568
|
-
store.addAgent("claude", {
|
|
569
|
-
registryId: "claude-acp",
|
|
570
|
-
name: "Claude Agent",
|
|
571
|
-
version: "bundled",
|
|
572
|
-
distribution: "npx",
|
|
573
|
-
command: "npx",
|
|
574
|
-
args: ["@zed-industries/claude-agent-acp"],
|
|
575
|
-
env: {},
|
|
576
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
577
|
-
binaryPath: null
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
s.stop(ok("Claude Agent ready"));
|
|
582
|
-
unmuteLogger();
|
|
583
|
-
const available = catalog.getAvailable();
|
|
584
|
-
const installed = available.filter((a) => a.installed);
|
|
585
|
-
const installable = available.filter((a) => !a.installed && a.available);
|
|
586
|
-
if (installed.length > 0 || installable.length > 0) {
|
|
587
|
-
const seen = /* @__PURE__ */ new Set();
|
|
588
|
-
const options = [];
|
|
589
|
-
for (const a of installed) {
|
|
590
|
-
const dedupeKey = `${a.key}::${a.name}`;
|
|
591
|
-
if (seen.has(dedupeKey)) continue;
|
|
592
|
-
seen.add(dedupeKey);
|
|
593
|
-
options.push({
|
|
594
|
-
label: `${a.name} (installed)`,
|
|
595
|
-
value: a.key
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
for (const a of installable) {
|
|
599
|
-
const dedupeKey = `${a.key}::${a.name}`;
|
|
600
|
-
if (seen.has(dedupeKey)) continue;
|
|
601
|
-
seen.add(dedupeKey);
|
|
602
|
-
options.push({
|
|
603
|
-
label: `${a.name} (${a.distribution})`,
|
|
604
|
-
value: a.key
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
|
-
const installedKeys = installed.map((a) => a.key);
|
|
608
|
-
const selected = guardCancel(
|
|
609
|
-
await clack4.autocompleteMultiselect({
|
|
610
|
-
message: "Install additional agents? (type to search, Space to select)",
|
|
611
|
-
options,
|
|
612
|
-
initialValues: installedKeys,
|
|
613
|
-
required: false
|
|
614
|
-
})
|
|
615
|
-
);
|
|
616
|
-
for (const key of selected) {
|
|
617
|
-
const regAgent = catalog.findRegistryAgent(key);
|
|
618
|
-
if (regAgent) {
|
|
619
|
-
const installSpinner = clack4.spinner();
|
|
620
|
-
installSpinner.start(`Installing ${regAgent.name}...`);
|
|
621
|
-
muteLogger();
|
|
622
|
-
const result = await catalog.install(key);
|
|
623
|
-
unmuteLogger();
|
|
624
|
-
if (result.ok) {
|
|
625
|
-
installSpinner.stop(ok("done"));
|
|
626
|
-
} else {
|
|
627
|
-
installSpinner.stop(warn(`skipped: ${result.error}`));
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
const installedAgents = Object.keys(catalog.getInstalledEntries());
|
|
633
|
-
let defaultAgent = "claude";
|
|
634
|
-
if (installedAgents.length > 1) {
|
|
635
|
-
defaultAgent = guardCancel(
|
|
636
|
-
await clack4.select({
|
|
637
|
-
message: "Which agent should be the default?",
|
|
638
|
-
options: installedAgents.map((key) => {
|
|
639
|
-
const agent = catalog.getInstalledAgent(key);
|
|
640
|
-
return { label: `${agent.name} (${key})`, value: key };
|
|
641
|
-
}),
|
|
642
|
-
initialValue: "claude"
|
|
643
|
-
})
|
|
644
|
-
);
|
|
645
|
-
}
|
|
646
|
-
console.log(ok(`Default agent: ${c.bold}${defaultAgent}${c.reset}`));
|
|
647
|
-
return { defaultAgent };
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// src/core/setup/setup-workspace.ts
|
|
651
|
-
import * as clack5 from "@clack/prompts";
|
|
652
|
-
async function setupWorkspace(opts) {
|
|
653
|
-
const { existing, stepNum, totalSteps } = opts ?? {};
|
|
654
|
-
if (stepNum != null && totalSteps != null) {
|
|
655
|
-
console.log(step(stepNum, totalSteps, "Workspace"));
|
|
656
|
-
}
|
|
657
|
-
const baseDir = guardCancel(
|
|
658
|
-
await clack5.text({
|
|
659
|
-
message: "Base directory for workspaces:",
|
|
660
|
-
initialValue: existing ?? "~/openacp-workspace",
|
|
661
|
-
validate: (val) => (val ?? "").toString().trim().length > 0 ? void 0 : "Path cannot be empty"
|
|
662
|
-
})
|
|
663
|
-
);
|
|
664
|
-
return { baseDir: baseDir.trim().replace(/^['"]|['"]$/g, "") };
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// src/core/setup/setup-run-mode.ts
|
|
668
|
-
import * as clack6 from "@clack/prompts";
|
|
669
|
-
async function setupRunMode(opts) {
|
|
670
|
-
const { existing, stepNum, totalSteps } = opts ?? {};
|
|
671
|
-
if (stepNum != null && totalSteps != null) {
|
|
672
|
-
console.log(step(stepNum, totalSteps, "Run Mode"));
|
|
673
|
-
}
|
|
674
|
-
if (process.platform === "win32") {
|
|
675
|
-
console.log(dim(" (Daemon mode not available on Windows)"));
|
|
676
|
-
return { runMode: "foreground", autoStart: false };
|
|
677
|
-
}
|
|
678
|
-
const initialValue = existing?.runMode === "daemon" ? "daemon" : "foreground";
|
|
679
|
-
const mode = guardCancel(
|
|
680
|
-
await clack6.select({
|
|
681
|
-
message: "How would you like to run OpenACP?",
|
|
682
|
-
options: [
|
|
683
|
-
{
|
|
684
|
-
label: "Background (daemon)",
|
|
685
|
-
value: "daemon",
|
|
686
|
-
hint: "Runs silently, auto-starts on boot. Manage with: openacp status | stop | logs"
|
|
687
|
-
},
|
|
688
|
-
{
|
|
689
|
-
label: "Foreground (terminal)",
|
|
690
|
-
value: "foreground",
|
|
691
|
-
hint: "Runs in current terminal session. Start with: openacp"
|
|
692
|
-
}
|
|
693
|
-
],
|
|
694
|
-
initialValue
|
|
695
|
-
})
|
|
696
|
-
);
|
|
697
|
-
const wasDaemon = existing?.runMode === "daemon";
|
|
698
|
-
if (mode === "daemon") {
|
|
699
|
-
const { installAutoStart, isAutoStartSupported } = await import("./autostart-X33OGMX6.js");
|
|
700
|
-
const { muteLogger, unmuteLogger } = await import("./log-NXABYJTT.js");
|
|
701
|
-
const autoStart = isAutoStartSupported();
|
|
702
|
-
if (autoStart) {
|
|
703
|
-
muteLogger();
|
|
704
|
-
const result = installAutoStart(expandHome("~/.openacp/logs"));
|
|
705
|
-
unmuteLogger();
|
|
706
|
-
if (result.success) {
|
|
707
|
-
console.log(ok("Auto-start on boot enabled"));
|
|
708
|
-
} else {
|
|
709
|
-
console.log(warn(`Auto-start failed: ${result.error}`));
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
return { runMode: "daemon", autoStart };
|
|
713
|
-
}
|
|
714
|
-
if (wasDaemon) {
|
|
715
|
-
const { muteLogger, unmuteLogger } = await import("./log-NXABYJTT.js");
|
|
716
|
-
muteLogger();
|
|
717
|
-
try {
|
|
718
|
-
const { stopDaemon } = await import("./daemon-4CS6HMB5.js");
|
|
719
|
-
const result = await stopDaemon();
|
|
720
|
-
unmuteLogger();
|
|
721
|
-
if (result.stopped) {
|
|
722
|
-
console.log(ok(`Daemon stopped (was PID ${result.pid})`));
|
|
723
|
-
}
|
|
724
|
-
} catch {
|
|
725
|
-
unmuteLogger();
|
|
726
|
-
}
|
|
727
|
-
muteLogger();
|
|
728
|
-
try {
|
|
729
|
-
const { uninstallAutoStart } = await import("./autostart-X33OGMX6.js");
|
|
730
|
-
uninstallAutoStart();
|
|
731
|
-
unmuteLogger();
|
|
732
|
-
} catch {
|
|
733
|
-
unmuteLogger();
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return { runMode: "foreground", autoStart: false };
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// src/core/setup/setup-integrations.ts
|
|
740
|
-
import * as clack7 from "@clack/prompts";
|
|
741
|
-
async function setupIntegrations(config) {
|
|
742
|
-
const claudeIntegration = config?.integrations?.claude;
|
|
743
|
-
const isInstalled = claudeIntegration?.installed === true;
|
|
744
|
-
const installClaude = guardCancel(
|
|
745
|
-
await clack7.confirm({
|
|
746
|
-
message: isInstalled ? "Claude CLI integration is installed. Reinstall?" : "Install session transfer for Claude? (enables /openacp:handoff in your terminal)",
|
|
747
|
-
initialValue: !isInstalled
|
|
748
|
-
})
|
|
749
|
-
);
|
|
750
|
-
if (installClaude) {
|
|
751
|
-
try {
|
|
752
|
-
const { getIntegration } = await import("./integrate-PNEHRY2I.js");
|
|
753
|
-
const integration = getIntegration("claude");
|
|
754
|
-
if (integration) {
|
|
755
|
-
for (const item of integration.items) {
|
|
756
|
-
const result = await item.install();
|
|
757
|
-
for (const log of result.logs) console.log(` ${log}`);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
console.log("Claude CLI integration installed.\n");
|
|
761
|
-
} catch (err) {
|
|
762
|
-
console.log(`Could not install Claude CLI integration: ${err instanceof Error ? err.message : err}`);
|
|
763
|
-
console.log(" You can install it later with: openacp integrate claude\n");
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
// src/core/setup/setup-channels.ts
|
|
769
|
-
import * as clack8 from "@clack/prompts";
|
|
770
|
-
function getChannelStatuses(config) {
|
|
771
|
-
const statuses = [];
|
|
772
|
-
for (const [id, meta] of Object.entries(CHANNEL_META)) {
|
|
773
|
-
const ch = config.channels[id];
|
|
774
|
-
const enabled = ch?.enabled === true;
|
|
775
|
-
const configured = !!ch && Object.keys(ch).length > 1;
|
|
776
|
-
let hint;
|
|
777
|
-
if (id === "telegram" && ch?.botToken && typeof ch.botToken === "string" && ch.botToken !== "YOUR_BOT_TOKEN_HERE") {
|
|
778
|
-
hint = `Chat ID: ${ch.chatId}`;
|
|
779
|
-
}
|
|
780
|
-
if (id === "discord" && ch?.guildId) {
|
|
781
|
-
hint = `Guild: ${ch.guildId}`;
|
|
782
|
-
}
|
|
783
|
-
statuses.push({ id, label: meta.label, configured, enabled, hint });
|
|
784
|
-
}
|
|
785
|
-
return statuses;
|
|
786
|
-
}
|
|
787
|
-
function noteChannelStatus(config) {
|
|
788
|
-
const statuses = getChannelStatuses(config);
|
|
789
|
-
const lines = statuses.map((s) => {
|
|
790
|
-
const status = s.enabled ? "enabled" : s.configured ? "disabled" : "not configured";
|
|
791
|
-
const hintStr = s.hint ? ` \u2014 ${s.hint}` : "";
|
|
792
|
-
return ` ${s.label}: ${status}${hintStr}`;
|
|
793
|
-
});
|
|
794
|
-
console.log("");
|
|
795
|
-
console.log(`${c.bold} Channel status${c.reset}`);
|
|
796
|
-
for (const line of lines) console.log(line);
|
|
797
|
-
console.log("");
|
|
798
|
-
}
|
|
799
|
-
async function promptConfiguredAction(label) {
|
|
800
|
-
return guardCancel(
|
|
801
|
-
await clack8.select({
|
|
802
|
-
message: `${label} already configured. What do you want to do?`,
|
|
803
|
-
options: [
|
|
804
|
-
{ value: "modify", label: "Modify settings" },
|
|
805
|
-
{ value: "disable", label: "Disable bot" },
|
|
806
|
-
{ value: "delete", label: "Delete config" },
|
|
807
|
-
{ value: "skip", label: "Skip (leave as-is)" }
|
|
808
|
-
],
|
|
809
|
-
initialValue: "modify"
|
|
810
|
-
})
|
|
811
|
-
);
|
|
812
|
-
}
|
|
813
|
-
async function configureChannels(config) {
|
|
814
|
-
const next = structuredClone(config);
|
|
815
|
-
let changed = false;
|
|
816
|
-
noteChannelStatus(next);
|
|
817
|
-
while (true) {
|
|
818
|
-
const statuses = getChannelStatuses(next);
|
|
819
|
-
const options = statuses.map((s) => {
|
|
820
|
-
const status = s.enabled ? "enabled" : s.configured ? "disabled" : "not configured";
|
|
821
|
-
return {
|
|
822
|
-
value: s.id,
|
|
823
|
-
label: `${s.label} (${CHANNEL_META[s.id].method})`,
|
|
824
|
-
hint: status + (s.hint ? ` \xB7 ${s.hint}` : "")
|
|
825
|
-
};
|
|
826
|
-
});
|
|
827
|
-
const choice = guardCancel(
|
|
828
|
-
await clack8.select({
|
|
829
|
-
message: "Select a channel",
|
|
830
|
-
options: [
|
|
831
|
-
...options,
|
|
832
|
-
{ value: "__done__", label: "Finished" }
|
|
833
|
-
]
|
|
834
|
-
})
|
|
835
|
-
);
|
|
836
|
-
if (choice === "__done__") break;
|
|
837
|
-
const channelId = choice;
|
|
838
|
-
const meta = CHANNEL_META[channelId];
|
|
839
|
-
const existing = next.channels[channelId];
|
|
840
|
-
const isConfigured = !!existing && Object.keys(existing).length > 1;
|
|
841
|
-
if (isConfigured) {
|
|
842
|
-
const action = await promptConfiguredAction(meta.label);
|
|
843
|
-
if (action === "skip") continue;
|
|
844
|
-
if (action === "disable") {
|
|
845
|
-
next.channels[channelId].enabled = false;
|
|
846
|
-
changed = true;
|
|
847
|
-
console.log(ok(`${meta.label} disabled`));
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
if (action === "delete") {
|
|
851
|
-
const confirmed = guardCancel(
|
|
852
|
-
await clack8.confirm({
|
|
853
|
-
message: `Delete ${meta.label} config? This cannot be undone.`,
|
|
854
|
-
initialValue: false
|
|
855
|
-
})
|
|
856
|
-
);
|
|
857
|
-
if (confirmed) {
|
|
858
|
-
delete next.channels[channelId];
|
|
859
|
-
changed = true;
|
|
860
|
-
console.log(ok(`${meta.label} config deleted`));
|
|
861
|
-
}
|
|
862
|
-
continue;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
if (channelId === "telegram") {
|
|
866
|
-
const result = await setupTelegram({
|
|
867
|
-
existing: isConfigured ? existing : void 0
|
|
868
|
-
});
|
|
869
|
-
next.channels.telegram = result;
|
|
870
|
-
changed = true;
|
|
871
|
-
} else if (channelId === "discord") {
|
|
872
|
-
const result = await setupDiscord({
|
|
873
|
-
existing: isConfigured ? existing : void 0
|
|
874
|
-
});
|
|
875
|
-
next.channels.discord = result;
|
|
876
|
-
changed = true;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
return { config: next, changed };
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// src/core/setup/wizard.ts
|
|
883
|
-
async function runSetup(configManager, opts) {
|
|
884
|
-
await printStartBanner();
|
|
885
|
-
clack9.intro("Let's set up OpenACP");
|
|
886
|
-
try {
|
|
887
|
-
const channelChoice = guardCancel(
|
|
888
|
-
await clack9.select({
|
|
889
|
-
message: "Which messaging platform do you want to use?",
|
|
890
|
-
options: [
|
|
891
|
-
{ label: "Telegram", value: "telegram" },
|
|
892
|
-
{ label: "Discord", value: "discord" },
|
|
893
|
-
{ label: "Both", value: "both" }
|
|
894
|
-
]
|
|
895
|
-
})
|
|
896
|
-
);
|
|
897
|
-
let telegram;
|
|
898
|
-
let discord;
|
|
899
|
-
const channelSteps = channelChoice === "both" ? 2 : 1;
|
|
900
|
-
const runModeSteps = opts?.skipRunMode ? 0 : 1;
|
|
901
|
-
const totalSteps = channelSteps + 1 + runModeSteps;
|
|
902
|
-
let currentStep = 0;
|
|
903
|
-
if (channelChoice === "telegram" || channelChoice === "both") {
|
|
904
|
-
currentStep++;
|
|
905
|
-
telegram = await setupTelegram({ stepNum: currentStep, totalSteps });
|
|
906
|
-
}
|
|
907
|
-
if (channelChoice === "discord" || channelChoice === "both") {
|
|
908
|
-
currentStep++;
|
|
909
|
-
discord = await setupDiscord();
|
|
910
|
-
}
|
|
911
|
-
const { defaultAgent } = await setupAgents();
|
|
912
|
-
await setupIntegrations();
|
|
913
|
-
currentStep++;
|
|
914
|
-
const workspace = await setupWorkspace({ stepNum: currentStep, totalSteps });
|
|
915
|
-
let runMode = "foreground";
|
|
916
|
-
let autoStart = false;
|
|
917
|
-
if (!opts?.skipRunMode) {
|
|
918
|
-
currentStep++;
|
|
919
|
-
const result = await setupRunMode({ stepNum: currentStep, totalSteps });
|
|
920
|
-
runMode = result.runMode;
|
|
921
|
-
autoStart = result.autoStart;
|
|
922
|
-
}
|
|
923
|
-
const security = {
|
|
924
|
-
allowedUserIds: [],
|
|
925
|
-
maxConcurrentSessions: 20,
|
|
926
|
-
sessionTimeoutMinutes: 60
|
|
927
|
-
};
|
|
928
|
-
const channels = {};
|
|
929
|
-
if (telegram) channels.telegram = telegram;
|
|
930
|
-
if (discord) channels.discord = discord;
|
|
931
|
-
const config = {
|
|
932
|
-
channels,
|
|
933
|
-
agents: {},
|
|
934
|
-
defaultAgent,
|
|
935
|
-
workspace,
|
|
936
|
-
security,
|
|
937
|
-
logging: {
|
|
938
|
-
level: "info",
|
|
939
|
-
logDir: "~/.openacp/logs",
|
|
940
|
-
maxFileSize: "10m",
|
|
941
|
-
maxFiles: 7,
|
|
942
|
-
sessionLogRetentionDays: 30
|
|
943
|
-
},
|
|
944
|
-
runMode,
|
|
945
|
-
autoStart,
|
|
946
|
-
api: {
|
|
947
|
-
port: 21420,
|
|
948
|
-
host: "127.0.0.1"
|
|
949
|
-
},
|
|
950
|
-
sessionStore: { ttlDays: 30 },
|
|
951
|
-
tunnel: {
|
|
952
|
-
enabled: true,
|
|
953
|
-
port: 3100,
|
|
954
|
-
provider: "cloudflare",
|
|
955
|
-
options: {},
|
|
956
|
-
maxUserTunnels: 5,
|
|
957
|
-
storeTtlMinutes: 60,
|
|
958
|
-
auth: { enabled: false }
|
|
959
|
-
},
|
|
960
|
-
usage: {
|
|
961
|
-
enabled: true,
|
|
962
|
-
warningThreshold: 0.8,
|
|
963
|
-
currency: "USD",
|
|
964
|
-
retentionDays: 90
|
|
965
|
-
},
|
|
966
|
-
integrations: {},
|
|
967
|
-
speech: {
|
|
968
|
-
stt: { provider: null, providers: {} },
|
|
969
|
-
tts: { provider: null, providers: {} }
|
|
970
|
-
}
|
|
971
|
-
};
|
|
972
|
-
try {
|
|
973
|
-
await configManager.writeNew(config);
|
|
974
|
-
} catch (writeErr) {
|
|
975
|
-
console.log(
|
|
976
|
-
fail(`Could not save config: ${writeErr.message}`)
|
|
977
|
-
);
|
|
978
|
-
return false;
|
|
979
|
-
}
|
|
980
|
-
clack9.outro(`Config saved to ${configManager.getConfigPath()}`);
|
|
981
|
-
if (!opts?.skipRunMode) {
|
|
982
|
-
console.log(ok("Starting OpenACP..."));
|
|
983
|
-
console.log("");
|
|
984
|
-
}
|
|
985
|
-
return true;
|
|
986
|
-
} catch (err) {
|
|
987
|
-
if (err.name === "ExitPromptError") {
|
|
988
|
-
clack9.cancel("Setup cancelled.");
|
|
989
|
-
return false;
|
|
990
|
-
}
|
|
991
|
-
throw err;
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
async function selectSection(hasSelection) {
|
|
995
|
-
return guardCancel(
|
|
996
|
-
await clack9.select({
|
|
997
|
-
message: "Select sections to configure",
|
|
998
|
-
options: [
|
|
999
|
-
...ONBOARD_SECTION_OPTIONS,
|
|
1000
|
-
{
|
|
1001
|
-
value: "__continue",
|
|
1002
|
-
label: "Continue",
|
|
1003
|
-
hint: hasSelection ? "Done" : "Skip for now"
|
|
1004
|
-
}
|
|
1005
|
-
],
|
|
1006
|
-
initialValue: ONBOARD_SECTION_OPTIONS[0].value
|
|
1007
|
-
})
|
|
1008
|
-
);
|
|
1009
|
-
}
|
|
1010
|
-
async function runReconfigure(configManager) {
|
|
1011
|
-
await printStartBanner();
|
|
1012
|
-
clack9.intro("OpenACP \u2014 Reconfigure");
|
|
1013
|
-
try {
|
|
1014
|
-
await configManager.load();
|
|
1015
|
-
let config = configManager.get();
|
|
1016
|
-
clack9.note(summarizeConfig(config), "Current configuration");
|
|
1017
|
-
let ranSection = false;
|
|
1018
|
-
while (true) {
|
|
1019
|
-
const choice = await selectSection(ranSection);
|
|
1020
|
-
if (choice === "__continue") break;
|
|
1021
|
-
ranSection = true;
|
|
1022
|
-
if (choice === "channels") {
|
|
1023
|
-
const result = await configureChannels(config);
|
|
1024
|
-
if (result.changed) {
|
|
1025
|
-
config = { ...config, channels: result.config.channels };
|
|
1026
|
-
await configManager.writeNew(config);
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
if (choice === "agents") {
|
|
1030
|
-
const { defaultAgent } = await setupAgents();
|
|
1031
|
-
await configManager.save({ defaultAgent });
|
|
1032
|
-
config = configManager.get();
|
|
1033
|
-
}
|
|
1034
|
-
if (choice === "workspace") {
|
|
1035
|
-
const { baseDir } = await setupWorkspace({
|
|
1036
|
-
existing: config.workspace.baseDir
|
|
1037
|
-
});
|
|
1038
|
-
await configManager.save({ workspace: { baseDir } });
|
|
1039
|
-
config = configManager.get();
|
|
1040
|
-
}
|
|
1041
|
-
if (choice === "runMode") {
|
|
1042
|
-
const result = await setupRunMode({
|
|
1043
|
-
existing: { runMode: config.runMode, autoStart: config.autoStart }
|
|
1044
|
-
});
|
|
1045
|
-
await configManager.save({
|
|
1046
|
-
runMode: result.runMode,
|
|
1047
|
-
autoStart: result.autoStart
|
|
1048
|
-
});
|
|
1049
|
-
config = configManager.get();
|
|
1050
|
-
}
|
|
1051
|
-
if (choice === "integrations") {
|
|
1052
|
-
await setupIntegrations(config);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
if (!ranSection) {
|
|
1056
|
-
clack9.outro("No changes made.");
|
|
1057
|
-
return;
|
|
1058
|
-
}
|
|
1059
|
-
clack9.outro(`Config saved to ${configManager.getConfigPath()}`);
|
|
1060
|
-
} catch (err) {
|
|
1061
|
-
if (err.name === "ExitPromptError") {
|
|
1062
|
-
clack9.cancel("Setup cancelled.");
|
|
1063
|
-
return;
|
|
1064
|
-
}
|
|
1065
|
-
throw err;
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
export {
|
|
1070
|
-
printStartBanner,
|
|
1071
|
-
validateBotToken,
|
|
1072
|
-
validateChatId,
|
|
1073
|
-
validateBotAdmin,
|
|
1074
|
-
validateDiscordToken,
|
|
1075
|
-
setupTelegram,
|
|
1076
|
-
setupDiscord,
|
|
1077
|
-
detectAgents,
|
|
1078
|
-
validateAgentCommand,
|
|
1079
|
-
setupAgents,
|
|
1080
|
-
setupWorkspace,
|
|
1081
|
-
setupRunMode,
|
|
1082
|
-
runSetup,
|
|
1083
|
-
runReconfigure
|
|
1084
|
-
};
|
|
1085
|
-
//# sourceMappingURL=chunk-LCRLAV4G.js.map
|