@openacp/cli 2026.402.1 → 2026.402.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1715 -770
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +26 -22
- package/dist/index.js +737 -144
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,284 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/core/utils/log.ts
|
|
13
|
+
var log_exports = {};
|
|
14
|
+
__export(log_exports, {
|
|
15
|
+
cleanupOldSessionLogs: () => cleanupOldSessionLogs,
|
|
16
|
+
closeSessionLogger: () => closeSessionLogger,
|
|
17
|
+
createChildLogger: () => createChildLogger,
|
|
18
|
+
createSessionLogger: () => createSessionLogger,
|
|
19
|
+
initLogger: () => initLogger,
|
|
20
|
+
log: () => log,
|
|
21
|
+
muteLogger: () => muteLogger,
|
|
22
|
+
setLogLevel: () => setLogLevel,
|
|
23
|
+
shutdownLogger: () => shutdownLogger,
|
|
24
|
+
unmuteLogger: () => unmuteLogger
|
|
25
|
+
});
|
|
26
|
+
import pino from "pino";
|
|
27
|
+
import fs from "fs";
|
|
28
|
+
import path from "path";
|
|
29
|
+
import os from "os";
|
|
30
|
+
function expandHome(p2) {
|
|
31
|
+
return p2.startsWith("~") ? path.join(os.homedir(), p2.slice(1)) : p2;
|
|
32
|
+
}
|
|
33
|
+
function wrapVariadic(logger) {
|
|
34
|
+
return {
|
|
35
|
+
info: (...args2) => {
|
|
36
|
+
if (args2.length === 0) return;
|
|
37
|
+
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
38
|
+
logger.info(args2[0], args2.slice(1).join(" "));
|
|
39
|
+
} else {
|
|
40
|
+
logger.info(args2.map(String).join(" "));
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
warn: (...args2) => {
|
|
44
|
+
if (args2.length === 0) return;
|
|
45
|
+
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
46
|
+
logger.warn(args2[0], args2.slice(1).join(" "));
|
|
47
|
+
} else {
|
|
48
|
+
logger.warn(args2.map(String).join(" "));
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
error: (...args2) => {
|
|
52
|
+
if (args2.length === 0) return;
|
|
53
|
+
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
54
|
+
logger.error(args2[0], args2.slice(1).join(" "));
|
|
55
|
+
} else {
|
|
56
|
+
logger.error(args2.map(String).join(" "));
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
debug: (...args2) => {
|
|
60
|
+
if (args2.length === 0) return;
|
|
61
|
+
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
62
|
+
logger.debug(args2[0], args2.slice(1).join(" "));
|
|
63
|
+
} else {
|
|
64
|
+
logger.debug(args2.map(String).join(" "));
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
fatal: (...args2) => {
|
|
68
|
+
if (args2.length === 0) return;
|
|
69
|
+
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
70
|
+
logger.fatal(args2[0], args2.slice(1).join(" "));
|
|
71
|
+
} else {
|
|
72
|
+
logger.fatal(args2.map(String).join(" "));
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
child: (bindings) => logger.child(bindings)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function muteLogger() {
|
|
79
|
+
if (muteCount === 0) {
|
|
80
|
+
savedLevel = rootLogger.level;
|
|
81
|
+
rootLogger.level = "silent";
|
|
82
|
+
}
|
|
83
|
+
muteCount++;
|
|
84
|
+
}
|
|
85
|
+
function unmuteLogger() {
|
|
86
|
+
muteCount--;
|
|
87
|
+
if (muteCount <= 0) {
|
|
88
|
+
muteCount = 0;
|
|
89
|
+
rootLogger.level = savedLevel;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function initLogger(config) {
|
|
93
|
+
if (initialized) return rootLogger;
|
|
94
|
+
const resolvedLogDir = expandHome(config.logDir);
|
|
95
|
+
logDir = resolvedLogDir;
|
|
96
|
+
try {
|
|
97
|
+
fs.mkdirSync(resolvedLogDir, { recursive: true });
|
|
98
|
+
fs.mkdirSync(path.join(resolvedLogDir, "sessions"), { recursive: true });
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(`[WARN] Failed to create log directory ${resolvedLogDir}, falling back to console-only:`, err);
|
|
101
|
+
return rootLogger;
|
|
102
|
+
}
|
|
103
|
+
const transports = pino.transport({
|
|
104
|
+
targets: [
|
|
105
|
+
{
|
|
106
|
+
target: "pino-pretty",
|
|
107
|
+
options: {
|
|
108
|
+
colorize: true,
|
|
109
|
+
translateTime: "SYS:HH:MM:ss",
|
|
110
|
+
ignore: "pid,hostname",
|
|
111
|
+
singleLine: true,
|
|
112
|
+
destination: 2
|
|
113
|
+
},
|
|
114
|
+
level: config.level
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
target: "pino-roll",
|
|
118
|
+
options: {
|
|
119
|
+
file: path.join(resolvedLogDir, "openacp.log"),
|
|
120
|
+
size: config.maxFileSize,
|
|
121
|
+
limit: { count: config.maxFiles }
|
|
122
|
+
},
|
|
123
|
+
level: config.level
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
});
|
|
127
|
+
currentTransport = transports;
|
|
128
|
+
rootLogger = pino({ level: config.level }, transports);
|
|
129
|
+
initialized = true;
|
|
130
|
+
Object.assign(log, wrapVariadic(rootLogger));
|
|
131
|
+
return rootLogger;
|
|
132
|
+
}
|
|
133
|
+
function setLogLevel(level) {
|
|
134
|
+
rootLogger.level = level;
|
|
135
|
+
}
|
|
136
|
+
function createChildLogger(context) {
|
|
137
|
+
return new Proxy({}, {
|
|
138
|
+
get(_target, prop, receiver) {
|
|
139
|
+
const child = rootLogger.child(context);
|
|
140
|
+
const value = Reflect.get(child, prop, receiver);
|
|
141
|
+
return typeof value === "function" ? value.bind(child) : value;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function createSessionLogger(sessionId, parentLogger) {
|
|
146
|
+
const sessionLogDir = logDir ? path.join(logDir, "sessions") : void 0;
|
|
147
|
+
if (!sessionLogDir) {
|
|
148
|
+
return parentLogger.child({ sessionId });
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const sessionLogPath = path.join(sessionLogDir, `${sessionId}.log`);
|
|
152
|
+
const dest = pino.destination(sessionLogPath);
|
|
153
|
+
const sessionFileLogger = pino({ level: parentLogger.level }, dest).child({ sessionId });
|
|
154
|
+
const combinedChild = parentLogger.child({ sessionId });
|
|
155
|
+
const originalInfo = combinedChild.info.bind(combinedChild);
|
|
156
|
+
const originalWarn = combinedChild.warn.bind(combinedChild);
|
|
157
|
+
const originalError = combinedChild.error.bind(combinedChild);
|
|
158
|
+
const originalDebug = combinedChild.debug.bind(combinedChild);
|
|
159
|
+
const originalFatal = combinedChild.fatal.bind(combinedChild);
|
|
160
|
+
combinedChild.info = ((objOrMsg, ...rest) => {
|
|
161
|
+
sessionFileLogger.info(objOrMsg, ...rest);
|
|
162
|
+
return originalInfo(objOrMsg, ...rest);
|
|
163
|
+
});
|
|
164
|
+
combinedChild.warn = ((objOrMsg, ...rest) => {
|
|
165
|
+
sessionFileLogger.warn(objOrMsg, ...rest);
|
|
166
|
+
return originalWarn(objOrMsg, ...rest);
|
|
167
|
+
});
|
|
168
|
+
combinedChild.error = ((objOrMsg, ...rest) => {
|
|
169
|
+
sessionFileLogger.error(objOrMsg, ...rest);
|
|
170
|
+
return originalError(objOrMsg, ...rest);
|
|
171
|
+
});
|
|
172
|
+
combinedChild.debug = ((objOrMsg, ...rest) => {
|
|
173
|
+
sessionFileLogger.debug(objOrMsg, ...rest);
|
|
174
|
+
return originalDebug(objOrMsg, ...rest);
|
|
175
|
+
});
|
|
176
|
+
combinedChild.fatal = ((objOrMsg, ...rest) => {
|
|
177
|
+
sessionFileLogger.fatal(objOrMsg, ...rest);
|
|
178
|
+
return originalFatal(objOrMsg, ...rest);
|
|
179
|
+
});
|
|
180
|
+
combinedChild.__sessionDest = dest;
|
|
181
|
+
return combinedChild;
|
|
182
|
+
} catch (err) {
|
|
183
|
+
parentLogger.warn({ sessionId, err }, "Failed to create session log file, using combined log only");
|
|
184
|
+
return parentLogger.child({ sessionId });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function closeSessionLogger(logger) {
|
|
188
|
+
const dest = logger.__sessionDest;
|
|
189
|
+
if (dest && typeof dest.destroy === "function") {
|
|
190
|
+
dest.destroy();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function shutdownLogger() {
|
|
194
|
+
if (!initialized) return;
|
|
195
|
+
const transport = currentTransport;
|
|
196
|
+
rootLogger = pino({ level: "debug" });
|
|
197
|
+
Object.assign(log, wrapVariadic(rootLogger));
|
|
198
|
+
currentTransport = void 0;
|
|
199
|
+
logDir = void 0;
|
|
200
|
+
initialized = false;
|
|
201
|
+
if (transport) {
|
|
202
|
+
await new Promise((resolve8) => {
|
|
203
|
+
const timeout = setTimeout(resolve8, 3e3);
|
|
204
|
+
transport.on("close", () => {
|
|
205
|
+
clearTimeout(timeout);
|
|
206
|
+
resolve8();
|
|
207
|
+
});
|
|
208
|
+
transport.end();
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async function cleanupOldSessionLogs(retentionDays) {
|
|
213
|
+
if (!logDir) return;
|
|
214
|
+
const sessionsDir = path.join(logDir, "sessions");
|
|
215
|
+
try {
|
|
216
|
+
const files = await fs.promises.readdir(sessionsDir);
|
|
217
|
+
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
218
|
+
for (const file of files) {
|
|
219
|
+
try {
|
|
220
|
+
const filePath = path.join(sessionsDir, file);
|
|
221
|
+
const stat = await fs.promises.stat(filePath);
|
|
222
|
+
if (stat.mtimeMs < cutoff) {
|
|
223
|
+
await fs.promises.unlink(filePath);
|
|
224
|
+
rootLogger.debug({ file }, "Deleted old session log");
|
|
225
|
+
}
|
|
226
|
+
} catch (err) {
|
|
227
|
+
rootLogger.warn({ file, err }, "Failed to delete old session log");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
var rootLogger, initialized, logDir, currentTransport, log, muteCount, savedLevel;
|
|
234
|
+
var init_log = __esm({
|
|
235
|
+
"src/core/utils/log.ts"() {
|
|
236
|
+
"use strict";
|
|
237
|
+
rootLogger = pino({
|
|
238
|
+
level: "debug",
|
|
239
|
+
transport: { target: "pino-pretty", options: { colorize: true, translateTime: "SYS:standard", destination: 2 } }
|
|
240
|
+
});
|
|
241
|
+
initialized = false;
|
|
242
|
+
log = wrapVariadic(rootLogger);
|
|
243
|
+
muteCount = 0;
|
|
244
|
+
savedLevel = "info";
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// src/cli/output.ts
|
|
249
|
+
function isJsonMode(args2) {
|
|
250
|
+
return args2.includes("--json");
|
|
251
|
+
}
|
|
252
|
+
function jsonSuccess(data) {
|
|
253
|
+
console.log(JSON.stringify({ success: true, data }));
|
|
254
|
+
process.exit(0);
|
|
255
|
+
}
|
|
256
|
+
function jsonError(code, message) {
|
|
257
|
+
console.log(JSON.stringify({ success: false, error: { code, message } }));
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
async function muteForJson() {
|
|
261
|
+
try {
|
|
262
|
+
const { muteLogger: muteLogger2 } = await Promise.resolve().then(() => (init_log(), log_exports));
|
|
263
|
+
muteLogger2();
|
|
264
|
+
} catch {
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
var ErrorCodes;
|
|
268
|
+
var init_output = __esm({
|
|
269
|
+
"src/cli/output.ts"() {
|
|
270
|
+
"use strict";
|
|
271
|
+
ErrorCodes = {
|
|
272
|
+
DAEMON_NOT_RUNNING: "DAEMON_NOT_RUNNING",
|
|
273
|
+
INSTANCE_NOT_FOUND: "INSTANCE_NOT_FOUND",
|
|
274
|
+
PLUGIN_NOT_FOUND: "PLUGIN_NOT_FOUND",
|
|
275
|
+
AGENT_NOT_FOUND: "AGENT_NOT_FOUND",
|
|
276
|
+
CONFIG_INVALID: "CONFIG_INVALID",
|
|
277
|
+
CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND",
|
|
278
|
+
SETUP_FAILED: "SETUP_FAILED",
|
|
279
|
+
API_ERROR: "API_ERROR",
|
|
280
|
+
TUNNEL_ERROR: "TUNNEL_ERROR",
|
|
281
|
+
INSTALL_FAILED: "INSTALL_FAILED",
|
|
282
|
+
UNINSTALL_FAILED: "UNINSTALL_FAILED",
|
|
283
|
+
MISSING_ARGUMENT: "MISSING_ARGUMENT",
|
|
284
|
+
UNKNOWN_COMMAND: "UNKNOWN_COMMAND",
|
|
285
|
+
UNKNOWN_ERROR: "UNKNOWN_ERROR"
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
12
290
|
// src/cli/version.ts
|
|
13
291
|
var version_exports = {};
|
|
14
292
|
__export(version_exports, {
|
|
@@ -139,8 +417,8 @@ var plugin_registry_exports = {};
|
|
|
139
417
|
__export(plugin_registry_exports, {
|
|
140
418
|
PluginRegistry: () => PluginRegistry
|
|
141
419
|
});
|
|
142
|
-
import
|
|
143
|
-
import
|
|
420
|
+
import fs4 from "fs";
|
|
421
|
+
import path4 from "path";
|
|
144
422
|
var PluginRegistry;
|
|
145
423
|
var init_plugin_registry = __esm({
|
|
146
424
|
"src/core/plugin/plugin-registry.ts"() {
|
|
@@ -183,7 +461,7 @@ var init_plugin_registry = __esm({
|
|
|
183
461
|
}
|
|
184
462
|
async load() {
|
|
185
463
|
try {
|
|
186
|
-
const content =
|
|
464
|
+
const content = fs4.readFileSync(this.registryPath, "utf-8");
|
|
187
465
|
const parsed = JSON.parse(content);
|
|
188
466
|
if (parsed && typeof parsed.installed === "object") {
|
|
189
467
|
this.data = parsed;
|
|
@@ -193,9 +471,9 @@ var init_plugin_registry = __esm({
|
|
|
193
471
|
}
|
|
194
472
|
}
|
|
195
473
|
async save() {
|
|
196
|
-
const dir =
|
|
197
|
-
|
|
198
|
-
|
|
474
|
+
const dir = path4.dirname(this.registryPath);
|
|
475
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
476
|
+
fs4.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
|
|
199
477
|
}
|
|
200
478
|
};
|
|
201
479
|
}
|
|
@@ -254,14 +532,31 @@ __export(plugin_search_exports, {
|
|
|
254
532
|
cmdPluginSearch: () => cmdPluginSearch
|
|
255
533
|
});
|
|
256
534
|
async function cmdPluginSearch(args2) {
|
|
257
|
-
const
|
|
535
|
+
const json = isJsonMode(args2);
|
|
536
|
+
if (json) await muteForJson();
|
|
537
|
+
const query = args2.filter((a) => a !== "--json").join(" ").trim();
|
|
258
538
|
if (!query) {
|
|
539
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Search query is required");
|
|
259
540
|
console.error("Usage: openacp plugin search <query>");
|
|
260
541
|
process.exit(1);
|
|
261
542
|
}
|
|
262
543
|
const client = new RegistryClient();
|
|
263
544
|
try {
|
|
264
545
|
const results = await client.search(query);
|
|
546
|
+
if (json) {
|
|
547
|
+
jsonSuccess({
|
|
548
|
+
results: results.map((p2) => ({
|
|
549
|
+
name: p2.name,
|
|
550
|
+
displayName: p2.displayName ?? p2.name,
|
|
551
|
+
version: p2.version,
|
|
552
|
+
description: p2.description,
|
|
553
|
+
npm: p2.npm,
|
|
554
|
+
category: p2.category,
|
|
555
|
+
verified: p2.verified ?? false,
|
|
556
|
+
featured: p2.featured ?? false
|
|
557
|
+
}))
|
|
558
|
+
});
|
|
559
|
+
}
|
|
265
560
|
if (results.length === 0) {
|
|
266
561
|
console.log(`No plugins found matching "${query}"`);
|
|
267
562
|
return;
|
|
@@ -279,6 +574,7 @@ Found ${results.length} plugin${results.length > 1 ? "s" : ""} matching "${query
|
|
|
279
574
|
console.log();
|
|
280
575
|
}
|
|
281
576
|
} catch (err) {
|
|
577
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `Failed to search registry: ${err}`);
|
|
282
578
|
console.error(`Failed to search registry: ${err}`);
|
|
283
579
|
process.exit(1);
|
|
284
580
|
}
|
|
@@ -287,6 +583,7 @@ var init_plugin_search = __esm({
|
|
|
287
583
|
"src/cli/commands/plugin-search.ts"() {
|
|
288
584
|
"use strict";
|
|
289
585
|
init_registry_client();
|
|
586
|
+
init_output();
|
|
290
587
|
}
|
|
291
588
|
});
|
|
292
589
|
|
|
@@ -1234,8 +1531,8 @@ __export(plugin_create_exports, {
|
|
|
1234
1531
|
cmdPluginCreate: () => cmdPluginCreate
|
|
1235
1532
|
});
|
|
1236
1533
|
import * as p from "@clack/prompts";
|
|
1237
|
-
import
|
|
1238
|
-
import
|
|
1534
|
+
import fs5 from "fs";
|
|
1535
|
+
import path5 from "path";
|
|
1239
1536
|
async function cmdPluginCreate() {
|
|
1240
1537
|
p.intro("Create a new OpenACP plugin");
|
|
1241
1538
|
const result = await p.group(
|
|
@@ -1278,14 +1575,14 @@ async function cmdPluginCreate() {
|
|
|
1278
1575
|
);
|
|
1279
1576
|
const pluginName = result.name.trim();
|
|
1280
1577
|
const dirName = pluginName.replace(/^@[^/]+\//, "");
|
|
1281
|
-
const targetDir =
|
|
1282
|
-
if (
|
|
1578
|
+
const targetDir = path5.resolve(process.cwd(), dirName);
|
|
1579
|
+
if (fs5.existsSync(targetDir)) {
|
|
1283
1580
|
p.cancel(`Directory "${dirName}" already exists.`);
|
|
1284
1581
|
process.exit(1);
|
|
1285
1582
|
}
|
|
1286
1583
|
const spinner4 = p.spinner();
|
|
1287
1584
|
spinner4.start("Scaffolding plugin...");
|
|
1288
|
-
|
|
1585
|
+
fs5.mkdirSync(path5.join(targetDir, "src", "__tests__"), { recursive: true });
|
|
1289
1586
|
const params = {
|
|
1290
1587
|
pluginName,
|
|
1291
1588
|
description: result.description || "",
|
|
@@ -1302,11 +1599,11 @@ async function cmdPluginCreate() {
|
|
|
1302
1599
|
{ relativePath: "README.md", content: generateReadme(params) },
|
|
1303
1600
|
{ relativePath: "CLAUDE.md", content: generateClaudeMd(params) },
|
|
1304
1601
|
{ relativePath: "PLUGIN_GUIDE.md", content: generatePluginGuide(params) },
|
|
1305
|
-
{ relativePath:
|
|
1306
|
-
{ relativePath:
|
|
1602
|
+
{ relativePath: path5.join("src", "index.ts"), content: generatePluginSource(params) },
|
|
1603
|
+
{ relativePath: path5.join("src", "__tests__", "index.test.ts"), content: generatePluginTest(params) }
|
|
1307
1604
|
];
|
|
1308
1605
|
for (const file of files) {
|
|
1309
|
-
|
|
1606
|
+
fs5.writeFileSync(path5.join(targetDir, file.relativePath), file.content);
|
|
1310
1607
|
}
|
|
1311
1608
|
spinner4.stop("Plugin scaffolded!");
|
|
1312
1609
|
p.note(
|
|
@@ -1478,9 +1775,9 @@ var read_text_file_exports = {};
|
|
|
1478
1775
|
__export(read_text_file_exports, {
|
|
1479
1776
|
readTextFileWithRange: () => readTextFileWithRange
|
|
1480
1777
|
});
|
|
1481
|
-
import
|
|
1778
|
+
import fs6 from "fs";
|
|
1482
1779
|
async function readTextFileWithRange(filePath, options) {
|
|
1483
|
-
const content = await
|
|
1780
|
+
const content = await fs6.promises.readFile(filePath, "utf-8");
|
|
1484
1781
|
if (!options?.line && !options?.limit) return content;
|
|
1485
1782
|
const lines = content.split("\n");
|
|
1486
1783
|
const start = Math.max(0, (options.line ?? 1) - 1);
|
|
@@ -1494,8 +1791,8 @@ var init_read_text_file = __esm({
|
|
|
1494
1791
|
});
|
|
1495
1792
|
|
|
1496
1793
|
// src/plugins/file-service/file-service.ts
|
|
1497
|
-
import
|
|
1498
|
-
import
|
|
1794
|
+
import fs7 from "fs";
|
|
1795
|
+
import path6 from "path";
|
|
1499
1796
|
import { OggOpusDecoder } from "ogg-opus-decoder";
|
|
1500
1797
|
import wav from "node-wav";
|
|
1501
1798
|
function classifyMime(mimeType) {
|
|
@@ -1551,14 +1848,14 @@ var init_file_service = __esm({
|
|
|
1551
1848
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
1552
1849
|
let removed = 0;
|
|
1553
1850
|
try {
|
|
1554
|
-
const entries = await
|
|
1851
|
+
const entries = await fs7.promises.readdir(this.baseDir, { withFileTypes: true });
|
|
1555
1852
|
for (const entry of entries) {
|
|
1556
1853
|
if (!entry.isDirectory()) continue;
|
|
1557
|
-
const dirPath =
|
|
1854
|
+
const dirPath = path6.join(this.baseDir, entry.name);
|
|
1558
1855
|
try {
|
|
1559
|
-
const stat = await
|
|
1856
|
+
const stat = await fs7.promises.stat(dirPath);
|
|
1560
1857
|
if (stat.mtimeMs < cutoff) {
|
|
1561
|
-
await
|
|
1858
|
+
await fs7.promises.rm(dirPath, { recursive: true, force: true });
|
|
1562
1859
|
removed++;
|
|
1563
1860
|
}
|
|
1564
1861
|
} catch {
|
|
@@ -1569,11 +1866,11 @@ var init_file_service = __esm({
|
|
|
1569
1866
|
return removed;
|
|
1570
1867
|
}
|
|
1571
1868
|
async saveFile(sessionId, fileName, data, mimeType) {
|
|
1572
|
-
const sessionDir =
|
|
1573
|
-
await
|
|
1869
|
+
const sessionDir = path6.join(this.baseDir, sessionId);
|
|
1870
|
+
await fs7.promises.mkdir(sessionDir, { recursive: true });
|
|
1574
1871
|
const safeName = `${Date.now()}-${fileName.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
1575
|
-
const filePath =
|
|
1576
|
-
await
|
|
1872
|
+
const filePath = path6.join(sessionDir, safeName);
|
|
1873
|
+
await fs7.promises.writeFile(filePath, data);
|
|
1577
1874
|
return {
|
|
1578
1875
|
type: classifyMime(mimeType),
|
|
1579
1876
|
filePath,
|
|
@@ -1584,14 +1881,14 @@ var init_file_service = __esm({
|
|
|
1584
1881
|
}
|
|
1585
1882
|
async resolveFile(filePath) {
|
|
1586
1883
|
try {
|
|
1587
|
-
const stat = await
|
|
1884
|
+
const stat = await fs7.promises.stat(filePath);
|
|
1588
1885
|
if (!stat.isFile()) return null;
|
|
1589
|
-
const ext =
|
|
1886
|
+
const ext = path6.extname(filePath).toLowerCase();
|
|
1590
1887
|
const mimeType = EXT_TO_MIME[ext] || "application/octet-stream";
|
|
1591
1888
|
return {
|
|
1592
1889
|
type: classifyMime(mimeType),
|
|
1593
1890
|
filePath,
|
|
1594
|
-
fileName:
|
|
1891
|
+
fileName: path6.basename(filePath),
|
|
1595
1892
|
mimeType,
|
|
1596
1893
|
size: stat.size
|
|
1597
1894
|
};
|
|
@@ -1638,8 +1935,8 @@ var file_service_exports = {};
|
|
|
1638
1935
|
__export(file_service_exports, {
|
|
1639
1936
|
default: () => file_service_default
|
|
1640
1937
|
});
|
|
1641
|
-
import
|
|
1642
|
-
import
|
|
1938
|
+
import path7 from "path";
|
|
1939
|
+
import os4 from "os";
|
|
1643
1940
|
function createFileServicePlugin() {
|
|
1644
1941
|
return {
|
|
1645
1942
|
name: "@openacp/file-service",
|
|
@@ -1649,7 +1946,7 @@ function createFileServicePlugin() {
|
|
|
1649
1946
|
permissions: ["services:register"],
|
|
1650
1947
|
async install(ctx) {
|
|
1651
1948
|
const { settings, legacyConfig, terminal } = ctx;
|
|
1652
|
-
const defaultFilesDir =
|
|
1949
|
+
const defaultFilesDir = path7.join(ctx.instanceRoot ?? path7.join(os4.homedir(), ".openacp"), "files");
|
|
1653
1950
|
if (legacyConfig) {
|
|
1654
1951
|
const filesCfg = legacyConfig.files;
|
|
1655
1952
|
if (filesCfg) {
|
|
@@ -1668,7 +1965,7 @@ function createFileServicePlugin() {
|
|
|
1668
1965
|
async configure(ctx) {
|
|
1669
1966
|
const { terminal, settings } = ctx;
|
|
1670
1967
|
const current = await settings.getAll();
|
|
1671
|
-
const defaultFilesDir =
|
|
1968
|
+
const defaultFilesDir = path7.join(ctx.instanceRoot ?? path7.join(os4.homedir(), ".openacp"), "files");
|
|
1672
1969
|
const val = await terminal.text({
|
|
1673
1970
|
message: "File storage directory:",
|
|
1674
1971
|
defaultValue: current.baseDir ?? defaultFilesDir
|
|
@@ -1684,7 +1981,7 @@ function createFileServicePlugin() {
|
|
|
1684
1981
|
},
|
|
1685
1982
|
async setup(ctx) {
|
|
1686
1983
|
const config = ctx.pluginConfig;
|
|
1687
|
-
const baseDir = config.baseDir ??
|
|
1984
|
+
const baseDir = config.baseDir ?? path7.join(ctx.instanceRoot, "files");
|
|
1688
1985
|
const retentionDays = config.retentionDays ?? 30;
|
|
1689
1986
|
const service = new FileService(baseDir);
|
|
1690
1987
|
ctx.registerService("file-service", service);
|
|
@@ -1706,8 +2003,8 @@ var init_file_service2 = __esm({
|
|
|
1706
2003
|
});
|
|
1707
2004
|
|
|
1708
2005
|
// src/plugins/context/context-cache.ts
|
|
1709
|
-
import * as
|
|
1710
|
-
import * as
|
|
2006
|
+
import * as fs8 from "fs";
|
|
2007
|
+
import * as path8 from "path";
|
|
1711
2008
|
import * as crypto from "crypto";
|
|
1712
2009
|
var DEFAULT_TTL_MS, ContextCache;
|
|
1713
2010
|
var init_context_cache = __esm({
|
|
@@ -1718,37 +2015,37 @@ var init_context_cache = __esm({
|
|
|
1718
2015
|
constructor(cacheDir, ttlMs = DEFAULT_TTL_MS) {
|
|
1719
2016
|
this.cacheDir = cacheDir;
|
|
1720
2017
|
this.ttlMs = ttlMs;
|
|
1721
|
-
|
|
2018
|
+
fs8.mkdirSync(cacheDir, { recursive: true });
|
|
1722
2019
|
}
|
|
1723
2020
|
keyHash(repoPath, queryKey) {
|
|
1724
2021
|
return crypto.createHash("sha256").update(`${repoPath}:${queryKey}`).digest("hex").slice(0, 16);
|
|
1725
2022
|
}
|
|
1726
2023
|
filePath(repoPath, queryKey) {
|
|
1727
|
-
return
|
|
2024
|
+
return path8.join(this.cacheDir, `${this.keyHash(repoPath, queryKey)}.json`);
|
|
1728
2025
|
}
|
|
1729
2026
|
get(repoPath, queryKey) {
|
|
1730
2027
|
const fp = this.filePath(repoPath, queryKey);
|
|
1731
2028
|
try {
|
|
1732
|
-
const stat =
|
|
2029
|
+
const stat = fs8.statSync(fp);
|
|
1733
2030
|
if (Date.now() - stat.mtimeMs > this.ttlMs) {
|
|
1734
|
-
|
|
2031
|
+
fs8.unlinkSync(fp);
|
|
1735
2032
|
return null;
|
|
1736
2033
|
}
|
|
1737
|
-
return JSON.parse(
|
|
2034
|
+
return JSON.parse(fs8.readFileSync(fp, "utf-8"));
|
|
1738
2035
|
} catch {
|
|
1739
2036
|
return null;
|
|
1740
2037
|
}
|
|
1741
2038
|
}
|
|
1742
2039
|
set(repoPath, queryKey, result) {
|
|
1743
|
-
|
|
2040
|
+
fs8.writeFileSync(this.filePath(repoPath, queryKey), JSON.stringify(result));
|
|
1744
2041
|
}
|
|
1745
2042
|
};
|
|
1746
2043
|
}
|
|
1747
2044
|
});
|
|
1748
2045
|
|
|
1749
2046
|
// src/plugins/context/context-manager.ts
|
|
1750
|
-
import * as
|
|
1751
|
-
import * as
|
|
2047
|
+
import * as os5 from "os";
|
|
2048
|
+
import * as path9 from "path";
|
|
1752
2049
|
var ContextManager;
|
|
1753
2050
|
var init_context_manager = __esm({
|
|
1754
2051
|
"src/plugins/context/context-manager.ts"() {
|
|
@@ -1759,7 +2056,7 @@ var init_context_manager = __esm({
|
|
|
1759
2056
|
cache;
|
|
1760
2057
|
historyStore;
|
|
1761
2058
|
constructor(cachePath) {
|
|
1762
|
-
this.cache = new ContextCache(cachePath ??
|
|
2059
|
+
this.cache = new ContextCache(cachePath ?? path9.join(os5.homedir(), ".openacp", "cache", "entire"));
|
|
1763
2060
|
}
|
|
1764
2061
|
setHistoryStore(store) {
|
|
1765
2062
|
this.historyStore = store;
|
|
@@ -3189,8 +3486,8 @@ var init_history_recorder = __esm({
|
|
|
3189
3486
|
});
|
|
3190
3487
|
|
|
3191
3488
|
// src/plugins/context/history/history-store.ts
|
|
3192
|
-
import
|
|
3193
|
-
import
|
|
3489
|
+
import fs9 from "fs";
|
|
3490
|
+
import path10 from "path";
|
|
3194
3491
|
var HistoryStore;
|
|
3195
3492
|
var init_history_store = __esm({
|
|
3196
3493
|
"src/plugins/context/history/history-store.ts"() {
|
|
@@ -3200,14 +3497,14 @@ var init_history_store = __esm({
|
|
|
3200
3497
|
this.dir = dir;
|
|
3201
3498
|
}
|
|
3202
3499
|
async write(history) {
|
|
3203
|
-
await
|
|
3500
|
+
await fs9.promises.mkdir(this.dir, { recursive: true });
|
|
3204
3501
|
const filePath = this.filePath(history.sessionId);
|
|
3205
|
-
await
|
|
3502
|
+
await fs9.promises.writeFile(filePath, JSON.stringify(history, null, 2));
|
|
3206
3503
|
}
|
|
3207
3504
|
async read(sessionId) {
|
|
3208
3505
|
const filePath = this.filePath(sessionId);
|
|
3209
3506
|
try {
|
|
3210
|
-
const raw = await
|
|
3507
|
+
const raw = await fs9.promises.readFile(filePath, "utf-8");
|
|
3211
3508
|
return JSON.parse(raw);
|
|
3212
3509
|
} catch {
|
|
3213
3510
|
return null;
|
|
@@ -3215,7 +3512,7 @@ var init_history_store = __esm({
|
|
|
3215
3512
|
}
|
|
3216
3513
|
async exists(sessionId) {
|
|
3217
3514
|
try {
|
|
3218
|
-
await
|
|
3515
|
+
await fs9.promises.access(this.filePath(sessionId));
|
|
3219
3516
|
return true;
|
|
3220
3517
|
} catch {
|
|
3221
3518
|
return false;
|
|
@@ -3223,7 +3520,7 @@ var init_history_store = __esm({
|
|
|
3223
3520
|
}
|
|
3224
3521
|
async list() {
|
|
3225
3522
|
try {
|
|
3226
|
-
const files = await
|
|
3523
|
+
const files = await fs9.promises.readdir(this.dir);
|
|
3227
3524
|
return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
|
|
3228
3525
|
} catch {
|
|
3229
3526
|
return [];
|
|
@@ -3231,13 +3528,13 @@ var init_history_store = __esm({
|
|
|
3231
3528
|
}
|
|
3232
3529
|
async delete(sessionId) {
|
|
3233
3530
|
try {
|
|
3234
|
-
await
|
|
3531
|
+
await fs9.promises.unlink(this.filePath(sessionId));
|
|
3235
3532
|
} catch {
|
|
3236
3533
|
}
|
|
3237
3534
|
}
|
|
3238
3535
|
filePath(sessionId) {
|
|
3239
|
-
const basename2 =
|
|
3240
|
-
const resolved =
|
|
3536
|
+
const basename2 = path10.basename(sessionId);
|
|
3537
|
+
const resolved = path10.join(this.dir, `${basename2}.json`);
|
|
3241
3538
|
if (!resolved.startsWith(this.dir)) {
|
|
3242
3539
|
throw new Error(`Invalid session ID: ${sessionId}`);
|
|
3243
3540
|
}
|
|
@@ -3252,7 +3549,7 @@ var context_exports = {};
|
|
|
3252
3549
|
__export(context_exports, {
|
|
3253
3550
|
default: () => context_default
|
|
3254
3551
|
});
|
|
3255
|
-
import * as
|
|
3552
|
+
import * as path11 from "path";
|
|
3256
3553
|
var contextPlugin, context_default;
|
|
3257
3554
|
var init_context = __esm({
|
|
3258
3555
|
"src/plugins/context/index.ts"() {
|
|
@@ -3293,12 +3590,12 @@ var init_context = __esm({
|
|
|
3293
3590
|
}
|
|
3294
3591
|
},
|
|
3295
3592
|
async setup(ctx) {
|
|
3296
|
-
const historyDir =
|
|
3593
|
+
const historyDir = path11.join(ctx.instanceRoot, "history");
|
|
3297
3594
|
const store = new HistoryStore(historyDir);
|
|
3298
3595
|
const recorder = new HistoryRecorder(store);
|
|
3299
3596
|
const sessionManager = ctx.sessions;
|
|
3300
3597
|
const getRecords = () => sessionManager.listRecords();
|
|
3301
|
-
const cachePath =
|
|
3598
|
+
const cachePath = path11.join(ctx.instanceRoot, "cache", "entire");
|
|
3302
3599
|
const manager = new ContextManager(cachePath);
|
|
3303
3600
|
manager.register(new HistoryProvider(store, getRecords));
|
|
3304
3601
|
manager.register(new EntireProvider());
|
|
@@ -3499,16 +3796,16 @@ __export(plugin_installer_exports, {
|
|
|
3499
3796
|
});
|
|
3500
3797
|
import { exec } from "child_process";
|
|
3501
3798
|
import { promisify } from "util";
|
|
3502
|
-
import * as
|
|
3503
|
-
import * as
|
|
3504
|
-
import * as
|
|
3799
|
+
import * as fs10 from "fs/promises";
|
|
3800
|
+
import * as os6 from "os";
|
|
3801
|
+
import * as path12 from "path";
|
|
3505
3802
|
import { pathToFileURL } from "url";
|
|
3506
3803
|
async function importFromDir(packageName, dir) {
|
|
3507
|
-
const pkgDir =
|
|
3508
|
-
const pkgJsonPath =
|
|
3804
|
+
const pkgDir = path12.join(dir, "node_modules", ...packageName.split("/"));
|
|
3805
|
+
const pkgJsonPath = path12.join(pkgDir, "package.json");
|
|
3509
3806
|
let pkgJson;
|
|
3510
3807
|
try {
|
|
3511
|
-
pkgJson = JSON.parse(await
|
|
3808
|
+
pkgJson = JSON.parse(await fs10.readFile(pkgJsonPath, "utf-8"));
|
|
3512
3809
|
} catch (err) {
|
|
3513
3810
|
throw new Error(`Cannot read package.json for "${packageName}" at ${pkgJsonPath}: ${err.message}`);
|
|
3514
3811
|
}
|
|
@@ -3521,9 +3818,9 @@ async function importFromDir(packageName, dir) {
|
|
|
3521
3818
|
} else {
|
|
3522
3819
|
entry = pkgJson.main ?? "index.js";
|
|
3523
3820
|
}
|
|
3524
|
-
const entryPath =
|
|
3821
|
+
const entryPath = path12.join(pkgDir, entry);
|
|
3525
3822
|
try {
|
|
3526
|
-
await
|
|
3823
|
+
await fs10.access(entryPath);
|
|
3527
3824
|
} catch {
|
|
3528
3825
|
throw new Error(`Entry point "${entry}" not found for "${packageName}" at ${entryPath}`);
|
|
3529
3826
|
}
|
|
@@ -3533,7 +3830,7 @@ async function installNpmPlugin(packageName, pluginsDir) {
|
|
|
3533
3830
|
if (!VALID_NPM_NAME.test(packageName)) {
|
|
3534
3831
|
throw new Error(`Invalid package name: "${packageName}". Must be a valid npm package name.`);
|
|
3535
3832
|
}
|
|
3536
|
-
const dir = pluginsDir ??
|
|
3833
|
+
const dir = pluginsDir ?? path12.join(os6.homedir(), ".openacp", "plugins");
|
|
3537
3834
|
try {
|
|
3538
3835
|
return await importFromDir(packageName, dir);
|
|
3539
3836
|
} catch {
|
|
@@ -3557,7 +3854,7 @@ var speech_exports = {};
|
|
|
3557
3854
|
__export(speech_exports, {
|
|
3558
3855
|
default: () => speech_default
|
|
3559
3856
|
});
|
|
3560
|
-
import
|
|
3857
|
+
import path13 from "path";
|
|
3561
3858
|
var EDGE_TTS_PLUGIN, speechPlugin, speech_default;
|
|
3562
3859
|
var init_speech = __esm({
|
|
3563
3860
|
"src/plugins/speech/index.ts"() {
|
|
@@ -3575,7 +3872,7 @@ var init_speech = __esm({
|
|
|
3575
3872
|
inheritableKeys: ["tts"],
|
|
3576
3873
|
async install(ctx) {
|
|
3577
3874
|
const { terminal, settings, legacyConfig } = ctx;
|
|
3578
|
-
const pluginsDir = ctx.instanceRoot ?
|
|
3875
|
+
const pluginsDir = ctx.instanceRoot ? path13.join(ctx.instanceRoot, "plugins") : void 0;
|
|
3579
3876
|
if (legacyConfig) {
|
|
3580
3877
|
const speechCfg = legacyConfig.speech;
|
|
3581
3878
|
if (speechCfg) {
|
|
@@ -3678,7 +3975,7 @@ var init_speech = __esm({
|
|
|
3678
3975
|
}
|
|
3679
3976
|
},
|
|
3680
3977
|
async setup(ctx) {
|
|
3681
|
-
const pluginsDir = ctx.instanceRoot ?
|
|
3978
|
+
const pluginsDir = ctx.instanceRoot ? path13.join(ctx.instanceRoot, "plugins") : void 0;
|
|
3682
3979
|
const config = ctx.pluginConfig;
|
|
3683
3980
|
const groqApiKey = config.groqApiKey;
|
|
3684
3981
|
const sttProvider = groqApiKey ? "groq" : null;
|
|
@@ -3805,301 +4102,65 @@ var init_notification = __esm({
|
|
|
3805
4102
|
for (const adapter of this.adapters.values()) {
|
|
3806
4103
|
try {
|
|
3807
4104
|
await adapter.sendNotification(notification);
|
|
3808
|
-
} catch {
|
|
3809
|
-
}
|
|
3810
|
-
}
|
|
3811
|
-
}
|
|
3812
|
-
};
|
|
3813
|
-
}
|
|
3814
|
-
});
|
|
3815
|
-
|
|
3816
|
-
// src/plugins/notifications/index.ts
|
|
3817
|
-
var notifications_exports = {};
|
|
3818
|
-
__export(notifications_exports, {
|
|
3819
|
-
default: () => notifications_default
|
|
3820
|
-
});
|
|
3821
|
-
function createNotificationsPlugin() {
|
|
3822
|
-
return {
|
|
3823
|
-
name: "@openacp/notifications",
|
|
3824
|
-
version: "1.0.0",
|
|
3825
|
-
description: "Cross-session notification routing",
|
|
3826
|
-
essential: false,
|
|
3827
|
-
pluginDependencies: { "@openacp/security": "^1.0.0" },
|
|
3828
|
-
permissions: ["services:register", "kernel:access"],
|
|
3829
|
-
async install(ctx) {
|
|
3830
|
-
const { settings, terminal } = ctx;
|
|
3831
|
-
await settings.setAll({ enabled: true });
|
|
3832
|
-
terminal.log.success("Notifications defaults saved");
|
|
3833
|
-
},
|
|
3834
|
-
async configure(ctx) {
|
|
3835
|
-
const { terminal, settings } = ctx;
|
|
3836
|
-
const current = await settings.getAll();
|
|
3837
|
-
const toggle = await terminal.confirm({
|
|
3838
|
-
message: `Notifications are ${current.enabled !== false ? "enabled" : "disabled"}. Toggle?`,
|
|
3839
|
-
initialValue: false
|
|
3840
|
-
});
|
|
3841
|
-
if (toggle) {
|
|
3842
|
-
const newState = current.enabled === false;
|
|
3843
|
-
await settings.set("enabled", newState);
|
|
3844
|
-
terminal.log.success(`Notifications ${newState ? "enabled" : "disabled"}`);
|
|
3845
|
-
}
|
|
3846
|
-
},
|
|
3847
|
-
async uninstall(ctx, opts) {
|
|
3848
|
-
if (opts.purge) {
|
|
3849
|
-
await ctx.settings.clear();
|
|
3850
|
-
ctx.terminal.log.success("Notifications settings cleared");
|
|
3851
|
-
}
|
|
3852
|
-
},
|
|
3853
|
-
async setup(ctx) {
|
|
3854
|
-
const core = ctx.core;
|
|
3855
|
-
const manager = new NotificationManager(core.adapters);
|
|
3856
|
-
ctx.registerService("notifications", manager);
|
|
3857
|
-
ctx.log.info("Notifications service ready");
|
|
3858
|
-
}
|
|
3859
|
-
};
|
|
3860
|
-
}
|
|
3861
|
-
var notifications_default;
|
|
3862
|
-
var init_notifications = __esm({
|
|
3863
|
-
"src/plugins/notifications/index.ts"() {
|
|
3864
|
-
"use strict";
|
|
3865
|
-
init_notification();
|
|
3866
|
-
notifications_default = createNotificationsPlugin();
|
|
3867
|
-
}
|
|
3868
|
-
});
|
|
3869
|
-
|
|
3870
|
-
// src/core/utils/log.ts
|
|
3871
|
-
var log_exports = {};
|
|
3872
|
-
__export(log_exports, {
|
|
3873
|
-
cleanupOldSessionLogs: () => cleanupOldSessionLogs,
|
|
3874
|
-
closeSessionLogger: () => closeSessionLogger,
|
|
3875
|
-
createChildLogger: () => createChildLogger,
|
|
3876
|
-
createSessionLogger: () => createSessionLogger,
|
|
3877
|
-
initLogger: () => initLogger,
|
|
3878
|
-
log: () => log,
|
|
3879
|
-
muteLogger: () => muteLogger,
|
|
3880
|
-
setLogLevel: () => setLogLevel,
|
|
3881
|
-
shutdownLogger: () => shutdownLogger,
|
|
3882
|
-
unmuteLogger: () => unmuteLogger
|
|
3883
|
-
});
|
|
3884
|
-
import pino from "pino";
|
|
3885
|
-
import fs10 from "fs";
|
|
3886
|
-
import path13 from "path";
|
|
3887
|
-
import os6 from "os";
|
|
3888
|
-
function expandHome(p2) {
|
|
3889
|
-
return p2.startsWith("~") ? path13.join(os6.homedir(), p2.slice(1)) : p2;
|
|
3890
|
-
}
|
|
3891
|
-
function wrapVariadic(logger) {
|
|
3892
|
-
return {
|
|
3893
|
-
info: (...args2) => {
|
|
3894
|
-
if (args2.length === 0) return;
|
|
3895
|
-
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
3896
|
-
logger.info(args2[0], args2.slice(1).join(" "));
|
|
3897
|
-
} else {
|
|
3898
|
-
logger.info(args2.map(String).join(" "));
|
|
3899
|
-
}
|
|
3900
|
-
},
|
|
3901
|
-
warn: (...args2) => {
|
|
3902
|
-
if (args2.length === 0) return;
|
|
3903
|
-
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
3904
|
-
logger.warn(args2[0], args2.slice(1).join(" "));
|
|
3905
|
-
} else {
|
|
3906
|
-
logger.warn(args2.map(String).join(" "));
|
|
3907
|
-
}
|
|
3908
|
-
},
|
|
3909
|
-
error: (...args2) => {
|
|
3910
|
-
if (args2.length === 0) return;
|
|
3911
|
-
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
3912
|
-
logger.error(args2[0], args2.slice(1).join(" "));
|
|
3913
|
-
} else {
|
|
3914
|
-
logger.error(args2.map(String).join(" "));
|
|
3915
|
-
}
|
|
3916
|
-
},
|
|
3917
|
-
debug: (...args2) => {
|
|
3918
|
-
if (args2.length === 0) return;
|
|
3919
|
-
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
3920
|
-
logger.debug(args2[0], args2.slice(1).join(" "));
|
|
3921
|
-
} else {
|
|
3922
|
-
logger.debug(args2.map(String).join(" "));
|
|
3923
|
-
}
|
|
3924
|
-
},
|
|
3925
|
-
fatal: (...args2) => {
|
|
3926
|
-
if (args2.length === 0) return;
|
|
3927
|
-
if (typeof args2[0] === "object" && args2[0] !== null && !(args2[0] instanceof Error)) {
|
|
3928
|
-
logger.fatal(args2[0], args2.slice(1).join(" "));
|
|
3929
|
-
} else {
|
|
3930
|
-
logger.fatal(args2.map(String).join(" "));
|
|
3931
|
-
}
|
|
3932
|
-
},
|
|
3933
|
-
child: (bindings) => logger.child(bindings)
|
|
3934
|
-
};
|
|
3935
|
-
}
|
|
3936
|
-
function muteLogger() {
|
|
3937
|
-
if (muteCount === 0) {
|
|
3938
|
-
savedLevel = rootLogger.level;
|
|
3939
|
-
rootLogger.level = "silent";
|
|
3940
|
-
}
|
|
3941
|
-
muteCount++;
|
|
3942
|
-
}
|
|
3943
|
-
function unmuteLogger() {
|
|
3944
|
-
muteCount--;
|
|
3945
|
-
if (muteCount <= 0) {
|
|
3946
|
-
muteCount = 0;
|
|
3947
|
-
rootLogger.level = savedLevel;
|
|
3948
|
-
}
|
|
3949
|
-
}
|
|
3950
|
-
function initLogger(config) {
|
|
3951
|
-
if (initialized) return rootLogger;
|
|
3952
|
-
const resolvedLogDir = expandHome(config.logDir);
|
|
3953
|
-
logDir = resolvedLogDir;
|
|
3954
|
-
try {
|
|
3955
|
-
fs10.mkdirSync(resolvedLogDir, { recursive: true });
|
|
3956
|
-
fs10.mkdirSync(path13.join(resolvedLogDir, "sessions"), { recursive: true });
|
|
3957
|
-
} catch (err) {
|
|
3958
|
-
console.error(`[WARN] Failed to create log directory ${resolvedLogDir}, falling back to console-only:`, err);
|
|
3959
|
-
return rootLogger;
|
|
3960
|
-
}
|
|
3961
|
-
const transports = pino.transport({
|
|
3962
|
-
targets: [
|
|
3963
|
-
{
|
|
3964
|
-
target: "pino-pretty",
|
|
3965
|
-
options: {
|
|
3966
|
-
colorize: true,
|
|
3967
|
-
translateTime: "SYS:HH:MM:ss",
|
|
3968
|
-
ignore: "pid,hostname",
|
|
3969
|
-
singleLine: true,
|
|
3970
|
-
destination: 2
|
|
3971
|
-
},
|
|
3972
|
-
level: config.level
|
|
3973
|
-
},
|
|
3974
|
-
{
|
|
3975
|
-
target: "pino-roll",
|
|
3976
|
-
options: {
|
|
3977
|
-
file: path13.join(resolvedLogDir, "openacp.log"),
|
|
3978
|
-
size: config.maxFileSize,
|
|
3979
|
-
limit: { count: config.maxFiles }
|
|
3980
|
-
},
|
|
3981
|
-
level: config.level
|
|
3982
|
-
}
|
|
3983
|
-
]
|
|
3984
|
-
});
|
|
3985
|
-
currentTransport = transports;
|
|
3986
|
-
rootLogger = pino({ level: config.level }, transports);
|
|
3987
|
-
initialized = true;
|
|
3988
|
-
Object.assign(log, wrapVariadic(rootLogger));
|
|
3989
|
-
return rootLogger;
|
|
3990
|
-
}
|
|
3991
|
-
function setLogLevel(level) {
|
|
3992
|
-
rootLogger.level = level;
|
|
3993
|
-
}
|
|
3994
|
-
function createChildLogger(context) {
|
|
3995
|
-
return new Proxy({}, {
|
|
3996
|
-
get(_target, prop, receiver) {
|
|
3997
|
-
const child = rootLogger.child(context);
|
|
3998
|
-
const value = Reflect.get(child, prop, receiver);
|
|
3999
|
-
return typeof value === "function" ? value.bind(child) : value;
|
|
4000
|
-
}
|
|
4001
|
-
});
|
|
4002
|
-
}
|
|
4003
|
-
function createSessionLogger(sessionId, parentLogger) {
|
|
4004
|
-
const sessionLogDir = logDir ? path13.join(logDir, "sessions") : void 0;
|
|
4005
|
-
if (!sessionLogDir) {
|
|
4006
|
-
return parentLogger.child({ sessionId });
|
|
4007
|
-
}
|
|
4008
|
-
try {
|
|
4009
|
-
const sessionLogPath = path13.join(sessionLogDir, `${sessionId}.log`);
|
|
4010
|
-
const dest = pino.destination(sessionLogPath);
|
|
4011
|
-
const sessionFileLogger = pino({ level: parentLogger.level }, dest).child({ sessionId });
|
|
4012
|
-
const combinedChild = parentLogger.child({ sessionId });
|
|
4013
|
-
const originalInfo = combinedChild.info.bind(combinedChild);
|
|
4014
|
-
const originalWarn = combinedChild.warn.bind(combinedChild);
|
|
4015
|
-
const originalError = combinedChild.error.bind(combinedChild);
|
|
4016
|
-
const originalDebug = combinedChild.debug.bind(combinedChild);
|
|
4017
|
-
const originalFatal = combinedChild.fatal.bind(combinedChild);
|
|
4018
|
-
combinedChild.info = ((objOrMsg, ...rest) => {
|
|
4019
|
-
sessionFileLogger.info(objOrMsg, ...rest);
|
|
4020
|
-
return originalInfo(objOrMsg, ...rest);
|
|
4021
|
-
});
|
|
4022
|
-
combinedChild.warn = ((objOrMsg, ...rest) => {
|
|
4023
|
-
sessionFileLogger.warn(objOrMsg, ...rest);
|
|
4024
|
-
return originalWarn(objOrMsg, ...rest);
|
|
4025
|
-
});
|
|
4026
|
-
combinedChild.error = ((objOrMsg, ...rest) => {
|
|
4027
|
-
sessionFileLogger.error(objOrMsg, ...rest);
|
|
4028
|
-
return originalError(objOrMsg, ...rest);
|
|
4029
|
-
});
|
|
4030
|
-
combinedChild.debug = ((objOrMsg, ...rest) => {
|
|
4031
|
-
sessionFileLogger.debug(objOrMsg, ...rest);
|
|
4032
|
-
return originalDebug(objOrMsg, ...rest);
|
|
4033
|
-
});
|
|
4034
|
-
combinedChild.fatal = ((objOrMsg, ...rest) => {
|
|
4035
|
-
sessionFileLogger.fatal(objOrMsg, ...rest);
|
|
4036
|
-
return originalFatal(objOrMsg, ...rest);
|
|
4037
|
-
});
|
|
4038
|
-
combinedChild.__sessionDest = dest;
|
|
4039
|
-
return combinedChild;
|
|
4040
|
-
} catch (err) {
|
|
4041
|
-
parentLogger.warn({ sessionId, err }, "Failed to create session log file, using combined log only");
|
|
4042
|
-
return parentLogger.child({ sessionId });
|
|
4043
|
-
}
|
|
4044
|
-
}
|
|
4045
|
-
function closeSessionLogger(logger) {
|
|
4046
|
-
const dest = logger.__sessionDest;
|
|
4047
|
-
if (dest && typeof dest.destroy === "function") {
|
|
4048
|
-
dest.destroy();
|
|
4105
|
+
} catch {
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
};
|
|
4049
4110
|
}
|
|
4050
|
-
}
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4111
|
+
});
|
|
4112
|
+
|
|
4113
|
+
// src/plugins/notifications/index.ts
|
|
4114
|
+
var notifications_exports = {};
|
|
4115
|
+
__export(notifications_exports, {
|
|
4116
|
+
default: () => notifications_default
|
|
4117
|
+
});
|
|
4118
|
+
function createNotificationsPlugin() {
|
|
4119
|
+
return {
|
|
4120
|
+
name: "@openacp/notifications",
|
|
4121
|
+
version: "1.0.0",
|
|
4122
|
+
description: "Cross-session notification routing",
|
|
4123
|
+
essential: false,
|
|
4124
|
+
pluginDependencies: { "@openacp/security": "^1.0.0" },
|
|
4125
|
+
permissions: ["services:register", "kernel:access"],
|
|
4126
|
+
async install(ctx) {
|
|
4127
|
+
const { settings, terminal } = ctx;
|
|
4128
|
+
await settings.setAll({ enabled: true });
|
|
4129
|
+
terminal.log.success("Notifications defaults saved");
|
|
4130
|
+
},
|
|
4131
|
+
async configure(ctx) {
|
|
4132
|
+
const { terminal, settings } = ctx;
|
|
4133
|
+
const current = await settings.getAll();
|
|
4134
|
+
const toggle = await terminal.confirm({
|
|
4135
|
+
message: `Notifications are ${current.enabled !== false ? "enabled" : "disabled"}. Toggle?`,
|
|
4136
|
+
initialValue: false
|
|
4065
4137
|
});
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
}
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
for (const file of files) {
|
|
4077
|
-
try {
|
|
4078
|
-
const filePath = path13.join(sessionsDir, file);
|
|
4079
|
-
const stat = await fs10.promises.stat(filePath);
|
|
4080
|
-
if (stat.mtimeMs < cutoff) {
|
|
4081
|
-
await fs10.promises.unlink(filePath);
|
|
4082
|
-
rootLogger.debug({ file }, "Deleted old session log");
|
|
4083
|
-
}
|
|
4084
|
-
} catch (err) {
|
|
4085
|
-
rootLogger.warn({ file, err }, "Failed to delete old session log");
|
|
4138
|
+
if (toggle) {
|
|
4139
|
+
const newState = current.enabled === false;
|
|
4140
|
+
await settings.set("enabled", newState);
|
|
4141
|
+
terminal.log.success(`Notifications ${newState ? "enabled" : "disabled"}`);
|
|
4142
|
+
}
|
|
4143
|
+
},
|
|
4144
|
+
async uninstall(ctx, opts) {
|
|
4145
|
+
if (opts.purge) {
|
|
4146
|
+
await ctx.settings.clear();
|
|
4147
|
+
ctx.terminal.log.success("Notifications settings cleared");
|
|
4086
4148
|
}
|
|
4149
|
+
},
|
|
4150
|
+
async setup(ctx) {
|
|
4151
|
+
const core = ctx.core;
|
|
4152
|
+
const manager = new NotificationManager(core.adapters);
|
|
4153
|
+
ctx.registerService("notifications", manager);
|
|
4154
|
+
ctx.log.info("Notifications service ready");
|
|
4087
4155
|
}
|
|
4088
|
-
}
|
|
4089
|
-
}
|
|
4156
|
+
};
|
|
4090
4157
|
}
|
|
4091
|
-
var
|
|
4092
|
-
var
|
|
4093
|
-
"src/
|
|
4158
|
+
var notifications_default;
|
|
4159
|
+
var init_notifications = __esm({
|
|
4160
|
+
"src/plugins/notifications/index.ts"() {
|
|
4094
4161
|
"use strict";
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
transport: { target: "pino-pretty", options: { colorize: true, translateTime: "SYS:standard", destination: 2 } }
|
|
4098
|
-
});
|
|
4099
|
-
initialized = false;
|
|
4100
|
-
log = wrapVariadic(rootLogger);
|
|
4101
|
-
muteCount = 0;
|
|
4102
|
-
savedLevel = "info";
|
|
4162
|
+
init_notification();
|
|
4163
|
+
notifications_default = createNotificationsPlugin();
|
|
4103
4164
|
}
|
|
4104
4165
|
});
|
|
4105
4166
|
|
|
@@ -9738,6 +9799,14 @@ var init_validators = __esm({
|
|
|
9738
9799
|
});
|
|
9739
9800
|
|
|
9740
9801
|
// src/plugins/telegram/topics.ts
|
|
9802
|
+
var topics_exports2 = {};
|
|
9803
|
+
__export(topics_exports2, {
|
|
9804
|
+
buildDeepLink: () => buildDeepLink,
|
|
9805
|
+
createSessionTopic: () => createSessionTopic,
|
|
9806
|
+
deleteSessionTopic: () => deleteSessionTopic,
|
|
9807
|
+
ensureTopics: () => ensureTopics,
|
|
9808
|
+
renameSessionTopic: () => renameSessionTopic
|
|
9809
|
+
});
|
|
9741
9810
|
async function ensureTopics(bot, chatId, config, saveConfig) {
|
|
9742
9811
|
let notificationTopicId = config.notificationTopicId;
|
|
9743
9812
|
let assistantTopicId = config.assistantTopicId;
|
|
@@ -10452,76 +10521,328 @@ function setupVerbosityCallbacks(bot, core) {
|
|
|
10452
10521
|
"channels.telegram.outputMode"
|
|
10453
10522
|
);
|
|
10454
10523
|
try {
|
|
10455
|
-
await ctx.answerCallbackQuery({
|
|
10456
|
-
text: `${OUTPUT_MODE_LABELS[level]} Output mode: ${level}`
|
|
10457
|
-
});
|
|
10524
|
+
await ctx.answerCallbackQuery({
|
|
10525
|
+
text: `${OUTPUT_MODE_LABELS[level]} Output mode: ${level}`
|
|
10526
|
+
});
|
|
10527
|
+
} catch {
|
|
10528
|
+
}
|
|
10529
|
+
});
|
|
10530
|
+
}
|
|
10531
|
+
async function handleUpdate(ctx, core) {
|
|
10532
|
+
if (!core.requestRestart) {
|
|
10533
|
+
await ctx.reply(
|
|
10534
|
+
"\u26A0\uFE0F Update is not available (no restart handler registered).",
|
|
10535
|
+
{ parse_mode: "HTML" }
|
|
10536
|
+
);
|
|
10537
|
+
return;
|
|
10538
|
+
}
|
|
10539
|
+
const { getCurrentVersion: getCurrentVersion2, getLatestVersion: getLatestVersion2, compareVersions: compareVersions2, runUpdate: runUpdate2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
10540
|
+
const current = getCurrentVersion2();
|
|
10541
|
+
const statusMsg = await ctx.reply(
|
|
10542
|
+
`\u{1F50D} Checking for updates... (current: v${escapeHtml4(current)})`,
|
|
10543
|
+
{ parse_mode: "HTML" }
|
|
10544
|
+
);
|
|
10545
|
+
const latest = await getLatestVersion2();
|
|
10546
|
+
if (!latest) {
|
|
10547
|
+
await ctx.api.editMessageText(
|
|
10548
|
+
ctx.chat.id,
|
|
10549
|
+
statusMsg.message_id,
|
|
10550
|
+
"\u274C Could not check for updates.",
|
|
10551
|
+
{ parse_mode: "HTML" }
|
|
10552
|
+
);
|
|
10553
|
+
return;
|
|
10554
|
+
}
|
|
10555
|
+
if (compareVersions2(current, latest) >= 0) {
|
|
10556
|
+
await ctx.api.editMessageText(
|
|
10557
|
+
ctx.chat.id,
|
|
10558
|
+
statusMsg.message_id,
|
|
10559
|
+
`\u2705 Already up to date (v${escapeHtml4(current)}).`,
|
|
10560
|
+
{ parse_mode: "HTML" }
|
|
10561
|
+
);
|
|
10562
|
+
return;
|
|
10563
|
+
}
|
|
10564
|
+
await ctx.api.editMessageText(
|
|
10565
|
+
ctx.chat.id,
|
|
10566
|
+
statusMsg.message_id,
|
|
10567
|
+
`\u2B07\uFE0F Updating v${escapeHtml4(current)} \u2192 v${escapeHtml4(latest)}...`,
|
|
10568
|
+
{ parse_mode: "HTML" }
|
|
10569
|
+
);
|
|
10570
|
+
const ok3 = await runUpdate2();
|
|
10571
|
+
if (!ok3) {
|
|
10572
|
+
await ctx.api.editMessageText(
|
|
10573
|
+
ctx.chat.id,
|
|
10574
|
+
statusMsg.message_id,
|
|
10575
|
+
"\u274C Update failed. Try manually: <code>npm install -g @openacp/cli@latest</code>",
|
|
10576
|
+
{ parse_mode: "HTML" }
|
|
10577
|
+
);
|
|
10578
|
+
return;
|
|
10579
|
+
}
|
|
10580
|
+
await ctx.api.editMessageText(
|
|
10581
|
+
ctx.chat.id,
|
|
10582
|
+
statusMsg.message_id,
|
|
10583
|
+
`\u2705 Updated to v${escapeHtml4(latest)}. Restarting...`,
|
|
10584
|
+
{ parse_mode: "HTML" }
|
|
10585
|
+
);
|
|
10586
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
10587
|
+
await core.requestRestart();
|
|
10588
|
+
}
|
|
10589
|
+
async function handleRestart(ctx, core) {
|
|
10590
|
+
if (!core.requestRestart) {
|
|
10591
|
+
await ctx.reply(
|
|
10592
|
+
"\u26A0\uFE0F Restart is not available (no restart handler registered).",
|
|
10593
|
+
{ parse_mode: "HTML" }
|
|
10594
|
+
);
|
|
10595
|
+
return;
|
|
10596
|
+
}
|
|
10597
|
+
await ctx.reply(
|
|
10598
|
+
"\u{1F504} <b>Restarting OpenACP...</b>\nRebuilding and restarting. Be back shortly.",
|
|
10599
|
+
{ parse_mode: "HTML" }
|
|
10600
|
+
);
|
|
10601
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
10602
|
+
await core.requestRestart();
|
|
10603
|
+
}
|
|
10604
|
+
var log13, OUTPUT_MODE_LABELS;
|
|
10605
|
+
var init_admin = __esm({
|
|
10606
|
+
"src/plugins/telegram/commands/admin.ts"() {
|
|
10607
|
+
"use strict";
|
|
10608
|
+
init_bypass_detection();
|
|
10609
|
+
init_formatting();
|
|
10610
|
+
init_log();
|
|
10611
|
+
log13 = createChildLogger({ module: "telegram-cmd-admin" });
|
|
10612
|
+
OUTPUT_MODE_LABELS = {
|
|
10613
|
+
low: "\u{1F507} Low",
|
|
10614
|
+
medium: "\u{1F4CA} Medium",
|
|
10615
|
+
high: "\u{1F50D} High"
|
|
10616
|
+
};
|
|
10617
|
+
}
|
|
10618
|
+
});
|
|
10619
|
+
|
|
10620
|
+
// src/plugins/telegram/commands/new-session.ts
|
|
10621
|
+
import { InlineKeyboard as InlineKeyboard2 } from "grammy";
|
|
10622
|
+
function botFromCtx(ctx) {
|
|
10623
|
+
return { api: ctx.api };
|
|
10624
|
+
}
|
|
10625
|
+
async function createSessionDirect(ctx, core, chatId, agentName, workspace, onControlMessage) {
|
|
10626
|
+
log14.info({ userId: ctx.from?.id, agentName, workspace }, "New session command (direct)");
|
|
10627
|
+
let threadId;
|
|
10628
|
+
try {
|
|
10629
|
+
const topicName = `\u{1F504} New Session`;
|
|
10630
|
+
threadId = await createSessionTopic(botFromCtx(ctx), chatId, topicName);
|
|
10631
|
+
await ctx.api.sendMessage(chatId, `\u23F3 Setting up session, please wait...`, {
|
|
10632
|
+
message_thread_id: threadId,
|
|
10633
|
+
parse_mode: "HTML"
|
|
10634
|
+
});
|
|
10635
|
+
const session = await core.handleNewSession("telegram", agentName, workspace);
|
|
10636
|
+
session.threadId = String(threadId);
|
|
10637
|
+
await core.sessionManager.patchRecord(session.id, { platform: { topicId: threadId } });
|
|
10638
|
+
const finalName = `\u{1F504} ${session.agentName} \u2014 New Session`;
|
|
10639
|
+
try {
|
|
10640
|
+
await ctx.api.editForumTopic(chatId, threadId, { name: finalName });
|
|
10641
|
+
} catch {
|
|
10642
|
+
}
|
|
10643
|
+
const controlMsg = await ctx.api.sendMessage(
|
|
10644
|
+
chatId,
|
|
10645
|
+
buildSessionStatusText(session, `\u2705 <b>Session started</b>`),
|
|
10646
|
+
{
|
|
10647
|
+
message_thread_id: threadId,
|
|
10648
|
+
parse_mode: "HTML",
|
|
10649
|
+
reply_markup: buildSessionControlKeyboard(session.id, false, false)
|
|
10650
|
+
}
|
|
10651
|
+
);
|
|
10652
|
+
onControlMessage?.(session.id, controlMsg.message_id);
|
|
10653
|
+
return threadId ?? null;
|
|
10654
|
+
} catch (err) {
|
|
10655
|
+
log14.error({ err }, "Session creation failed");
|
|
10656
|
+
if (threadId) {
|
|
10657
|
+
try {
|
|
10658
|
+
await ctx.api.deleteForumTopic(chatId, threadId);
|
|
10659
|
+
} catch {
|
|
10660
|
+
}
|
|
10661
|
+
}
|
|
10662
|
+
const message = err instanceof Error ? err.message : typeof err === "object" ? JSON.stringify(err) : String(err);
|
|
10663
|
+
await ctx.reply(`\u274C ${escapeHtml4(message)}`, { parse_mode: "HTML" });
|
|
10664
|
+
return null;
|
|
10665
|
+
}
|
|
10666
|
+
}
|
|
10667
|
+
function cacheWorkspace(agentKey, workspace) {
|
|
10668
|
+
const now = Date.now();
|
|
10669
|
+
if (workspaceCache.size > WS_CACHE_MAX) {
|
|
10670
|
+
for (const [id2, entry] of workspaceCache) {
|
|
10671
|
+
if (now - entry.ts > 5 * 6e4 || workspaceCache.size > WS_CACHE_MAX) {
|
|
10672
|
+
workspaceCache.delete(id2);
|
|
10673
|
+
}
|
|
10674
|
+
}
|
|
10675
|
+
}
|
|
10676
|
+
const id = nextWsId++;
|
|
10677
|
+
workspaceCache.set(id, { agentKey, workspace, ts: now });
|
|
10678
|
+
return id;
|
|
10679
|
+
}
|
|
10680
|
+
function shortenPath2(ws) {
|
|
10681
|
+
const home = process.env.HOME || "";
|
|
10682
|
+
return home && ws.startsWith(home) ? "~" + ws.slice(home.length) : ws;
|
|
10683
|
+
}
|
|
10684
|
+
async function showAgentPicker(ctx, core, chatId) {
|
|
10685
|
+
const catalog = core.agentCatalog;
|
|
10686
|
+
const installed = catalog.getAvailable().filter((i) => i.installed);
|
|
10687
|
+
if (installed.length === 0) {
|
|
10688
|
+
await ctx.reply("No agents installed. Use /install to add one.", { parse_mode: "HTML" }).catch(() => {
|
|
10689
|
+
});
|
|
10690
|
+
return;
|
|
10691
|
+
}
|
|
10692
|
+
if (installed.length === 1) {
|
|
10693
|
+
await showWorkspacePicker(ctx, core, chatId, installed[0].key, true);
|
|
10694
|
+
return;
|
|
10695
|
+
}
|
|
10696
|
+
const kb = new InlineKeyboard2();
|
|
10697
|
+
for (let i = 0; i < installed.length; i += 2) {
|
|
10698
|
+
const row = installed.slice(i, i + 2);
|
|
10699
|
+
for (const agent of row) {
|
|
10700
|
+
kb.text(agent.name, `ns:agent:${agent.key}`);
|
|
10701
|
+
}
|
|
10702
|
+
kb.row();
|
|
10703
|
+
}
|
|
10704
|
+
await ctx.reply("<b>\u{1F195} New Session</b>\nSelect an agent:", {
|
|
10705
|
+
parse_mode: "HTML",
|
|
10706
|
+
reply_markup: kb
|
|
10707
|
+
}).catch(() => {
|
|
10708
|
+
});
|
|
10709
|
+
}
|
|
10710
|
+
async function showWorkspacePicker(ctx, core, chatId, agentKey, newMessage = false) {
|
|
10711
|
+
const records = core.sessionManager.listRecords();
|
|
10712
|
+
const recentWorkspaces = [...new Set(records.map((r) => r.workingDir).filter(Boolean))].slice(0, 5);
|
|
10713
|
+
const config = core.configManager.get();
|
|
10714
|
+
const baseDir = config.workspace.baseDir;
|
|
10715
|
+
const resolvedBaseDir = core.configManager.resolveWorkspace(baseDir);
|
|
10716
|
+
const hasBaseDir = recentWorkspaces.some((ws) => ws === baseDir || ws === resolvedBaseDir);
|
|
10717
|
+
const workspaces = hasBaseDir ? recentWorkspaces : [resolvedBaseDir, ...recentWorkspaces].slice(0, 5);
|
|
10718
|
+
const kb = new InlineKeyboard2();
|
|
10719
|
+
for (const ws of workspaces) {
|
|
10720
|
+
const id = cacheWorkspace(agentKey, ws);
|
|
10721
|
+
kb.text(`\u{1F4C1} ${shortenPath2(ws)}`, `ns:ws:${id}`).row();
|
|
10722
|
+
}
|
|
10723
|
+
kb.text("\u{1F4C1} Custom path...", `ns:custom:${agentKey}`).row();
|
|
10724
|
+
const agentLabel = escapeHtml4(agentKey);
|
|
10725
|
+
const text6 = `<b>\u{1F195} New Session</b>
|
|
10726
|
+
Agent: <code>${agentLabel}</code>
|
|
10727
|
+
|
|
10728
|
+
Select workspace:`;
|
|
10729
|
+
const opts = { parse_mode: "HTML", reply_markup: kb };
|
|
10730
|
+
if (newMessage) {
|
|
10731
|
+
await ctx.reply(text6, opts).catch(() => {
|
|
10732
|
+
});
|
|
10733
|
+
} else {
|
|
10734
|
+
try {
|
|
10735
|
+
await ctx.editMessageText(text6, opts);
|
|
10736
|
+
} catch {
|
|
10737
|
+
await ctx.reply(text6, opts).catch(() => {
|
|
10738
|
+
});
|
|
10739
|
+
}
|
|
10740
|
+
}
|
|
10741
|
+
}
|
|
10742
|
+
function setupNewSessionCallbacks(bot, core, chatId, getAssistantSession) {
|
|
10743
|
+
bot.callbackQuery("ns:start", async (ctx) => {
|
|
10744
|
+
try {
|
|
10745
|
+
await ctx.answerCallbackQuery();
|
|
10746
|
+
} catch {
|
|
10747
|
+
}
|
|
10748
|
+
await showAgentPicker(ctx, core, chatId);
|
|
10749
|
+
});
|
|
10750
|
+
bot.callbackQuery(/^ns:agent:/, async (ctx) => {
|
|
10751
|
+
const agentKey = ctx.callbackQuery.data.replace("ns:agent:", "");
|
|
10752
|
+
try {
|
|
10753
|
+
await ctx.answerCallbackQuery();
|
|
10754
|
+
} catch {
|
|
10755
|
+
}
|
|
10756
|
+
await showWorkspacePicker(ctx, core, chatId, agentKey);
|
|
10757
|
+
});
|
|
10758
|
+
bot.callbackQuery(/^ns:ws:/, async (ctx) => {
|
|
10759
|
+
const id = parseInt(ctx.callbackQuery.data.replace("ns:ws:", ""), 10);
|
|
10760
|
+
try {
|
|
10761
|
+
await ctx.answerCallbackQuery();
|
|
10762
|
+
} catch {
|
|
10763
|
+
}
|
|
10764
|
+
const entry = workspaceCache.get(id);
|
|
10765
|
+
if (!entry) {
|
|
10766
|
+
try {
|
|
10767
|
+
await ctx.editMessageText("\u26A0\uFE0F Session expired. Please try again via /menu.");
|
|
10768
|
+
} catch {
|
|
10769
|
+
}
|
|
10770
|
+
return;
|
|
10771
|
+
}
|
|
10772
|
+
workspaceCache.delete(id);
|
|
10773
|
+
try {
|
|
10774
|
+
await ctx.editMessageText(
|
|
10775
|
+
`<b>\u{1F195} New Session</b>
|
|
10776
|
+
Agent: <code>${escapeHtml4(entry.agentKey)}</code>
|
|
10777
|
+
Workspace: <code>${escapeHtml4(shortenPath2(entry.workspace))}</code>
|
|
10778
|
+
|
|
10779
|
+
\u23F3 Creating session...`,
|
|
10780
|
+
{ parse_mode: "HTML" }
|
|
10781
|
+
);
|
|
10458
10782
|
} catch {
|
|
10459
10783
|
}
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
log13 = createChildLogger({ module: "telegram-cmd-admin" });
|
|
10470
|
-
OUTPUT_MODE_LABELS = {
|
|
10471
|
-
low: "\u{1F507} Low",
|
|
10472
|
-
medium: "\u{1F4CA} Medium",
|
|
10473
|
-
high: "\u{1F50D} High"
|
|
10474
|
-
};
|
|
10475
|
-
}
|
|
10476
|
-
});
|
|
10784
|
+
const threadId = await createSessionDirect(ctx, core, chatId, entry.agentKey, entry.workspace);
|
|
10785
|
+
if (threadId) {
|
|
10786
|
+
const { buildDeepLink: buildDeepLink2 } = await Promise.resolve().then(() => (init_topics2(), topics_exports2));
|
|
10787
|
+
const link = buildDeepLink2(chatId, threadId);
|
|
10788
|
+
try {
|
|
10789
|
+
await ctx.editMessageText(
|
|
10790
|
+
`<b>\u2705 Session created</b>
|
|
10791
|
+
Agent: <code>${escapeHtml4(entry.agentKey)}</code>
|
|
10792
|
+
Workspace: <code>${escapeHtml4(shortenPath2(entry.workspace))}</code>
|
|
10477
10793
|
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
}
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10794
|
+
<a href="${link}">Open session \u2192</a>`,
|
|
10795
|
+
{ parse_mode: "HTML" }
|
|
10796
|
+
);
|
|
10797
|
+
} catch {
|
|
10798
|
+
}
|
|
10799
|
+
} else {
|
|
10800
|
+
try {
|
|
10801
|
+
await ctx.editMessageText(
|
|
10802
|
+
`<b>\u274C Session creation failed</b>
|
|
10803
|
+
Agent: <code>${escapeHtml4(entry.agentKey)}</code>
|
|
10804
|
+
Workspace: <code>${escapeHtml4(shortenPath2(entry.workspace))}</code>
|
|
10805
|
+
|
|
10806
|
+
Try again with /new or /menu`,
|
|
10807
|
+
{ parse_mode: "HTML" }
|
|
10808
|
+
);
|
|
10809
|
+
} catch {
|
|
10810
|
+
}
|
|
10811
|
+
}
|
|
10812
|
+
});
|
|
10813
|
+
bot.callbackQuery(/^ns:custom:/, async (ctx) => {
|
|
10814
|
+
const agentKey = ctx.callbackQuery.data.replace("ns:custom:", "");
|
|
10496
10815
|
try {
|
|
10497
|
-
await ctx.
|
|
10816
|
+
await ctx.answerCallbackQuery();
|
|
10498
10817
|
} catch {
|
|
10499
10818
|
}
|
|
10500
|
-
const
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10819
|
+
const assistant = getAssistantSession?.();
|
|
10820
|
+
if (assistant) {
|
|
10821
|
+
try {
|
|
10822
|
+
await ctx.editMessageText(
|
|
10823
|
+
`<b>\u{1F195} New Session</b>
|
|
10824
|
+
Agent: <code>${escapeHtml4(agentKey)}</code>
|
|
10825
|
+
|
|
10826
|
+
\u{1F4AC} Type your workspace path in the chat below.`,
|
|
10827
|
+
{ parse_mode: "HTML" }
|
|
10828
|
+
);
|
|
10829
|
+
} catch {
|
|
10507
10830
|
}
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
log14.error({ err }, "Session creation failed");
|
|
10513
|
-
if (threadId) {
|
|
10831
|
+
await assistant.enqueuePrompt(
|
|
10832
|
+
`User wants to create a new session with agent "${agentKey}". Ask them for the workspace (project directory) path, then create the session.`
|
|
10833
|
+
);
|
|
10834
|
+
} else {
|
|
10514
10835
|
try {
|
|
10515
|
-
await ctx.
|
|
10836
|
+
await ctx.editMessageText(
|
|
10837
|
+
`Usage: <code>/new ${escapeHtml4(agentKey)} <workspace-path></code>`,
|
|
10838
|
+
{ parse_mode: "HTML" }
|
|
10839
|
+
);
|
|
10516
10840
|
} catch {
|
|
10517
10841
|
}
|
|
10518
10842
|
}
|
|
10519
|
-
|
|
10520
|
-
await ctx.reply(`\u274C ${escapeHtml4(message)}`, { parse_mode: "HTML" });
|
|
10521
|
-
return null;
|
|
10522
|
-
}
|
|
10843
|
+
});
|
|
10523
10844
|
}
|
|
10524
|
-
var log14;
|
|
10845
|
+
var log14, WS_CACHE_MAX, workspaceCache, nextWsId;
|
|
10525
10846
|
var init_new_session = __esm({
|
|
10526
10847
|
"src/plugins/telegram/commands/new-session.ts"() {
|
|
10527
10848
|
"use strict";
|
|
@@ -10530,11 +10851,74 @@ var init_new_session = __esm({
|
|
|
10530
10851
|
init_log();
|
|
10531
10852
|
init_admin();
|
|
10532
10853
|
log14 = createChildLogger({ module: "telegram-cmd-new-session" });
|
|
10854
|
+
WS_CACHE_MAX = 50;
|
|
10855
|
+
workspaceCache = /* @__PURE__ */ new Map();
|
|
10856
|
+
nextWsId = 0;
|
|
10533
10857
|
}
|
|
10534
10858
|
});
|
|
10535
10859
|
|
|
10536
10860
|
// src/plugins/telegram/commands/session.ts
|
|
10537
|
-
import { InlineKeyboard as
|
|
10861
|
+
import { InlineKeyboard as InlineKeyboard3 } from "grammy";
|
|
10862
|
+
async function handleTopics(ctx, core) {
|
|
10863
|
+
try {
|
|
10864
|
+
const allRecords = core.sessionManager.listRecords();
|
|
10865
|
+
const records = allRecords.filter((r) => {
|
|
10866
|
+
const platform2 = r.platform;
|
|
10867
|
+
return !!platform2?.topicId;
|
|
10868
|
+
});
|
|
10869
|
+
const headlessCount = allRecords.length - records.length;
|
|
10870
|
+
if (records.length === 0) {
|
|
10871
|
+
const extra = headlessCount > 0 ? ` (${headlessCount} headless hidden)` : "";
|
|
10872
|
+
await ctx.reply(`No sessions with topics found.${extra}`, { parse_mode: "HTML" });
|
|
10873
|
+
return;
|
|
10874
|
+
}
|
|
10875
|
+
const statusEmoji = {
|
|
10876
|
+
active: "\u{1F7E2}",
|
|
10877
|
+
initializing: "\u{1F7E1}",
|
|
10878
|
+
finished: "\u2705",
|
|
10879
|
+
error: "\u274C",
|
|
10880
|
+
cancelled: "\u26D4"
|
|
10881
|
+
};
|
|
10882
|
+
const statusOrder = { active: 0, initializing: 1, error: 2, finished: 3, cancelled: 4 };
|
|
10883
|
+
records.sort((a, b) => (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5));
|
|
10884
|
+
const MAX_DISPLAY = 30;
|
|
10885
|
+
const displayed = records.slice(0, MAX_DISPLAY);
|
|
10886
|
+
const lines = displayed.map((r) => {
|
|
10887
|
+
const emoji = statusEmoji[r.status] || "\u26AA";
|
|
10888
|
+
const name = r.name?.trim();
|
|
10889
|
+
const label = name ? escapeHtml4(name) : `<i>${escapeHtml4(r.agentName)} session</i>`;
|
|
10890
|
+
return `${emoji} ${label} <code>[${r.status}]</code>`;
|
|
10891
|
+
});
|
|
10892
|
+
const header2 = `<b>Sessions: ${records.length}</b>` + (headlessCount > 0 ? ` (${headlessCount} headless hidden)` : "");
|
|
10893
|
+
const truncated = records.length > MAX_DISPLAY ? `
|
|
10894
|
+
|
|
10895
|
+
<i>...and ${records.length - MAX_DISPLAY} more</i>` : "";
|
|
10896
|
+
const finishedCount = allRecords.filter((r) => r.status === "finished").length;
|
|
10897
|
+
const errorCount = allRecords.filter((r) => r.status === "error" || r.status === "cancelled").length;
|
|
10898
|
+
const keyboard = new InlineKeyboard3();
|
|
10899
|
+
if (finishedCount > 0) {
|
|
10900
|
+
keyboard.text(`Cleanup finished (${finishedCount})`, "m:cleanup:finished").row();
|
|
10901
|
+
}
|
|
10902
|
+
if (errorCount > 0) {
|
|
10903
|
+
keyboard.text(`Cleanup errors (${errorCount})`, "m:cleanup:errors").row();
|
|
10904
|
+
}
|
|
10905
|
+
if (finishedCount + errorCount > 0) {
|
|
10906
|
+
keyboard.text(`Cleanup all non-active (${finishedCount + errorCount})`, "m:cleanup:all").row();
|
|
10907
|
+
}
|
|
10908
|
+
keyboard.text(`\u26A0\uFE0F Cleanup ALL (${allRecords.length})`, "m:cleanup:everything").row();
|
|
10909
|
+
keyboard.text("Refresh", "m:topics");
|
|
10910
|
+
await ctx.reply(
|
|
10911
|
+
`${header2}
|
|
10912
|
+
|
|
10913
|
+
${lines.join("\n")}${truncated}`,
|
|
10914
|
+
{ parse_mode: "HTML", reply_markup: keyboard }
|
|
10915
|
+
);
|
|
10916
|
+
} catch (err) {
|
|
10917
|
+
log15.error({ err }, "handleTopics error");
|
|
10918
|
+
await ctx.reply("\u274C Failed to list sessions.", { parse_mode: "HTML" }).catch(() => {
|
|
10919
|
+
});
|
|
10920
|
+
}
|
|
10921
|
+
}
|
|
10538
10922
|
async function handleCleanup(ctx, core, chatId, statuses) {
|
|
10539
10923
|
const allRecords = core.sessionManager.listRecords();
|
|
10540
10924
|
const cleanable = allRecords.filter((r) => statuses.includes(r.status));
|
|
@@ -10593,7 +10977,7 @@ async function handleCleanupEverything(ctx, core, chatId, systemTopicIds) {
|
|
|
10593
10977
|
const activeWarning = activeCount > 0 ? `
|
|
10594
10978
|
|
|
10595
10979
|
\u26A0\uFE0F <b>${activeCount} active session(s) will be cancelled and their agents stopped!</b>` : "";
|
|
10596
|
-
const keyboard = new
|
|
10980
|
+
const keyboard = new InlineKeyboard3().text("Yes, delete all", "m:cleanup:everything:confirm").text("Cancel", "m:topics");
|
|
10597
10981
|
await ctx.reply(
|
|
10598
10982
|
`<b>Delete ${cleanable.length} topics?</b>
|
|
10599
10983
|
|
|
@@ -10676,6 +11060,13 @@ function setupSessionCallbacks(bot, core, chatId, systemTopicIds) {
|
|
|
10676
11060
|
break;
|
|
10677
11061
|
}
|
|
10678
11062
|
});
|
|
11063
|
+
bot.callbackQuery("m:topics", async (ctx) => {
|
|
11064
|
+
try {
|
|
11065
|
+
await ctx.answerCallbackQuery();
|
|
11066
|
+
} catch {
|
|
11067
|
+
}
|
|
11068
|
+
await handleTopics(ctx, core);
|
|
11069
|
+
});
|
|
10679
11070
|
}
|
|
10680
11071
|
async function handleArchiveConfirm(ctx, core, chatId) {
|
|
10681
11072
|
const data = ctx.callbackQuery?.data;
|
|
@@ -11087,7 +11478,73 @@ var init_integrate = __esm({
|
|
|
11087
11478
|
});
|
|
11088
11479
|
|
|
11089
11480
|
// src/plugins/telegram/commands/agents.ts
|
|
11090
|
-
import { InlineKeyboard as
|
|
11481
|
+
import { InlineKeyboard as InlineKeyboard4 } from "grammy";
|
|
11482
|
+
async function handleAgents(ctx, core, page = 0) {
|
|
11483
|
+
const catalog = core.agentCatalog;
|
|
11484
|
+
const items = catalog.getAvailable();
|
|
11485
|
+
const installed = items.filter((i) => i.installed);
|
|
11486
|
+
const available = items.filter((i) => !i.installed);
|
|
11487
|
+
let text6 = "<b>\u{1F916} Agents</b>\n\n";
|
|
11488
|
+
if (installed.length > 0) {
|
|
11489
|
+
text6 += "<b>Installed:</b>\n";
|
|
11490
|
+
for (const item of installed) {
|
|
11491
|
+
text6 += `\u2705 <b>${escapeHtml4(item.name)}</b>`;
|
|
11492
|
+
if (item.description) {
|
|
11493
|
+
text6 += ` \u2014 <i>${escapeHtml4(truncate(item.description, 50))}</i>`;
|
|
11494
|
+
}
|
|
11495
|
+
text6 += "\n";
|
|
11496
|
+
}
|
|
11497
|
+
text6 += "\n";
|
|
11498
|
+
}
|
|
11499
|
+
if (available.length > 0) {
|
|
11500
|
+
const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE);
|
|
11501
|
+
const safePage = Math.max(0, Math.min(page, totalPages - 1));
|
|
11502
|
+
const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE);
|
|
11503
|
+
text6 += `<b>Available to install:</b>`;
|
|
11504
|
+
if (totalPages > 1) {
|
|
11505
|
+
text6 += ` (${safePage + 1}/${totalPages})`;
|
|
11506
|
+
}
|
|
11507
|
+
text6 += "\n";
|
|
11508
|
+
for (const item of pageItems) {
|
|
11509
|
+
if (item.available) {
|
|
11510
|
+
text6 += `\u2B07\uFE0F <b>${escapeHtml4(item.name)}</b>`;
|
|
11511
|
+
} else {
|
|
11512
|
+
const deps = item.missingDeps?.join(", ") ?? "requirements not met";
|
|
11513
|
+
text6 += `\u26A0\uFE0F <b>${escapeHtml4(item.name)}</b> <i>(needs: ${escapeHtml4(deps)})</i>`;
|
|
11514
|
+
}
|
|
11515
|
+
if (item.description) {
|
|
11516
|
+
text6 += `
|
|
11517
|
+
<i>${escapeHtml4(truncate(item.description, 60))}</i>`;
|
|
11518
|
+
}
|
|
11519
|
+
text6 += "\n";
|
|
11520
|
+
}
|
|
11521
|
+
const keyboard = new InlineKeyboard4();
|
|
11522
|
+
const installable = pageItems.filter((i) => i.available);
|
|
11523
|
+
for (let i = 0; i < installable.length; i += 2) {
|
|
11524
|
+
const row = installable.slice(i, i + 2);
|
|
11525
|
+
for (const item of row) {
|
|
11526
|
+
keyboard.text(`\u2B07\uFE0F ${item.name}`, `ag:install:${item.key}`);
|
|
11527
|
+
}
|
|
11528
|
+
keyboard.row();
|
|
11529
|
+
}
|
|
11530
|
+
if (totalPages > 1) {
|
|
11531
|
+
if (safePage > 0) {
|
|
11532
|
+
keyboard.text("\u25C0\uFE0F Prev", `ag:page:${safePage - 1}`);
|
|
11533
|
+
}
|
|
11534
|
+
if (safePage < totalPages - 1) {
|
|
11535
|
+
keyboard.text("Next \u25B6\uFE0F", `ag:page:${safePage + 1}`);
|
|
11536
|
+
}
|
|
11537
|
+
keyboard.row();
|
|
11538
|
+
}
|
|
11539
|
+
if (available.some((i) => !i.available)) {
|
|
11540
|
+
text6 += "\n\u{1F4A1} <i>Agents marked \u26A0\uFE0F need additional setup. Use</i> <code>openacp agents info <name></code> <i>for details.</i>\n";
|
|
11541
|
+
}
|
|
11542
|
+
await ctx.reply(text6, { parse_mode: "HTML", reply_markup: keyboard });
|
|
11543
|
+
} else {
|
|
11544
|
+
text6 += "<i>All agents are already installed!</i>";
|
|
11545
|
+
await ctx.reply(text6, { parse_mode: "HTML" });
|
|
11546
|
+
}
|
|
11547
|
+
}
|
|
11091
11548
|
async function handleAgentCallback(ctx, core) {
|
|
11092
11549
|
const data = ctx.callbackQuery?.data ?? "";
|
|
11093
11550
|
await ctx.answerCallbackQuery();
|
|
@@ -11136,7 +11593,7 @@ async function handleAgentCallback(ctx, core) {
|
|
|
11136
11593
|
}
|
|
11137
11594
|
text6 += "\n";
|
|
11138
11595
|
}
|
|
11139
|
-
const keyboard = new
|
|
11596
|
+
const keyboard = new InlineKeyboard4();
|
|
11140
11597
|
const installable = pageItems.filter((i) => i.available);
|
|
11141
11598
|
for (let i = 0; i < installable.length; i += 2) {
|
|
11142
11599
|
const row = installable.slice(i, i + 2);
|
|
@@ -11191,7 +11648,7 @@ Downloading... ${bar} ${percent}%`, { parse_mode: "HTML" });
|
|
|
11191
11648
|
},
|
|
11192
11649
|
async onSuccess(name) {
|
|
11193
11650
|
try {
|
|
11194
|
-
const keyboard = new
|
|
11651
|
+
const keyboard = new InlineKeyboard4().text(`\u{1F680} Start session with ${name}`, `na:${nameOrId}`);
|
|
11195
11652
|
await ctx.api.editMessageText(msg.chat.id, msg.message_id, `\u2705 <b>${escapeHtml4(name)}</b> installed!`, { parse_mode: "HTML", reply_markup: keyboard });
|
|
11196
11653
|
} catch {
|
|
11197
11654
|
}
|
|
@@ -11309,13 +11766,13 @@ __export(menu_exports, {
|
|
|
11309
11766
|
handleHelp: () => handleHelp,
|
|
11310
11767
|
handleMenu: () => handleMenu
|
|
11311
11768
|
});
|
|
11312
|
-
import { InlineKeyboard as
|
|
11769
|
+
import { InlineKeyboard as InlineKeyboard5 } from "grammy";
|
|
11313
11770
|
function buildMenuKeyboard(menuRegistry) {
|
|
11314
11771
|
if (!menuRegistry) {
|
|
11315
|
-
return new
|
|
11772
|
+
return new InlineKeyboard5().text("\u{1F195} New Session", "m:core:new").text("\u{1F4CB} Sessions", "m:core:sessions").row().text("\u{1F4CA} Status", "m:core:status").text("\u{1F916} Agents", "m:core:agents").row().text("\u2753 Help", "m:core:help");
|
|
11316
11773
|
}
|
|
11317
11774
|
const items = menuRegistry.getItems();
|
|
11318
|
-
const kb = new
|
|
11775
|
+
const kb = new InlineKeyboard5();
|
|
11319
11776
|
let currentGroup;
|
|
11320
11777
|
let rowCount = 0;
|
|
11321
11778
|
for (const item of items) {
|
|
@@ -11333,11 +11790,11 @@ function buildMenuKeyboard(menuRegistry) {
|
|
|
11333
11790
|
}
|
|
11334
11791
|
return kb;
|
|
11335
11792
|
}
|
|
11336
|
-
async function handleMenu(ctx) {
|
|
11793
|
+
async function handleMenu(ctx, menuRegistry) {
|
|
11337
11794
|
await ctx.reply(`<b>OpenACP Menu</b>
|
|
11338
11795
|
Choose an action:`, {
|
|
11339
11796
|
parse_mode: "HTML",
|
|
11340
|
-
reply_markup: buildMenuKeyboard()
|
|
11797
|
+
reply_markup: buildMenuKeyboard(menuRegistry)
|
|
11341
11798
|
});
|
|
11342
11799
|
}
|
|
11343
11800
|
async function handleHelp(ctx) {
|
|
@@ -11354,7 +11811,7 @@ Each session gets its own topic \u2014 chat there to work with the agent.
|
|
|
11354
11811
|
/status \u2014 Show session or system status
|
|
11355
11812
|
/sessions \u2014 List all sessions
|
|
11356
11813
|
/agents \u2014 Browse & install agents
|
|
11357
|
-
/install
|
|
11814
|
+
/install <name> \u2014 Install an agent
|
|
11358
11815
|
|
|
11359
11816
|
\u2699\uFE0F <b>System</b>
|
|
11360
11817
|
/restart \u2014 Restart OpenACP
|
|
@@ -11418,11 +11875,11 @@ var init_menu = __esm({
|
|
|
11418
11875
|
});
|
|
11419
11876
|
|
|
11420
11877
|
// src/plugins/telegram/commands/settings.ts
|
|
11421
|
-
import { InlineKeyboard as
|
|
11878
|
+
import { InlineKeyboard as InlineKeyboard6 } from "grammy";
|
|
11422
11879
|
function buildSettingsKeyboard(core) {
|
|
11423
11880
|
const config = core.configManager.get();
|
|
11424
11881
|
const fields = getSafeFields();
|
|
11425
|
-
const kb = new
|
|
11882
|
+
const kb = new InlineKeyboard6();
|
|
11426
11883
|
for (const field of fields) {
|
|
11427
11884
|
const value = getConfigValue(config, field.path);
|
|
11428
11885
|
const label = formatFieldLabel(field, value);
|
|
@@ -11454,6 +11911,14 @@ function formatFieldLabel(field, value) {
|
|
|
11454
11911
|
const displayValue = value === null || value === void 0 ? "Not set" : String(value);
|
|
11455
11912
|
return `${icon} ${field.displayName}: ${displayValue}`;
|
|
11456
11913
|
}
|
|
11914
|
+
async function handleSettings(ctx, core) {
|
|
11915
|
+
const kb = buildSettingsKeyboard(core);
|
|
11916
|
+
await ctx.reply(`<b>\u2699\uFE0F Settings</b>
|
|
11917
|
+
Tap to change:`, {
|
|
11918
|
+
parse_mode: "HTML",
|
|
11919
|
+
reply_markup: kb
|
|
11920
|
+
});
|
|
11921
|
+
}
|
|
11457
11922
|
function setupSettingsCallbacks(bot, core, getAssistantSession) {
|
|
11458
11923
|
bot.callbackQuery(/^s:toggle:/, async (ctx) => {
|
|
11459
11924
|
const fieldPath = ctx.callbackQuery.data.replace("s:toggle:", "");
|
|
@@ -11487,7 +11952,7 @@ function setupSettingsCallbacks(bot, core, getAssistantSession) {
|
|
|
11487
11952
|
if (!fieldDef) return;
|
|
11488
11953
|
const options = resolveOptions(fieldDef, config) ?? [];
|
|
11489
11954
|
const currentValue = getConfigValue(config, fieldPath);
|
|
11490
|
-
const kb = new
|
|
11955
|
+
const kb = new InlineKeyboard6();
|
|
11491
11956
|
for (const opt of options) {
|
|
11492
11957
|
const marker = opt === String(currentValue) ? " \u2713" : "";
|
|
11493
11958
|
kb.text(`${opt}${marker}`, `s:pick:${fieldPath}:${opt}`).row();
|
|
@@ -11581,11 +12046,12 @@ Tap to change:`, {
|
|
|
11581
12046
|
} catch {
|
|
11582
12047
|
}
|
|
11583
12048
|
const { buildMenuKeyboard: buildMenuKeyboard2 } = await Promise.resolve().then(() => (init_menu(), menu_exports));
|
|
12049
|
+
const menuRegistry = core.lifecycleManager?.serviceRegistry?.get("menu-registry");
|
|
11584
12050
|
try {
|
|
11585
12051
|
await ctx.editMessageText(`<b>OpenACP Menu</b>
|
|
11586
12052
|
Choose an action:`, {
|
|
11587
12053
|
parse_mode: "HTML",
|
|
11588
|
-
reply_markup: buildMenuKeyboard2()
|
|
12054
|
+
reply_markup: buildMenuKeyboard2(menuRegistry)
|
|
11589
12055
|
});
|
|
11590
12056
|
} catch {
|
|
11591
12057
|
}
|
|
@@ -12335,7 +12801,7 @@ var init_doctor = __esm({
|
|
|
12335
12801
|
});
|
|
12336
12802
|
|
|
12337
12803
|
// src/plugins/telegram/commands/doctor.ts
|
|
12338
|
-
import { InlineKeyboard as
|
|
12804
|
+
import { InlineKeyboard as InlineKeyboard7 } from "grammy";
|
|
12339
12805
|
function renderReport(report) {
|
|
12340
12806
|
const icons = { pass: "\u2705", warn: "\u26A0\uFE0F", fail: "\u274C" };
|
|
12341
12807
|
const lines = ["\u{1FA7A} <b>OpenACP Doctor</b>\n"];
|
|
@@ -12351,7 +12817,7 @@ function renderReport(report) {
|
|
|
12351
12817
|
lines.push(`<b>Result:</b> ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`);
|
|
12352
12818
|
let keyboard;
|
|
12353
12819
|
if (report.pendingFixes.length > 0) {
|
|
12354
|
-
keyboard = new
|
|
12820
|
+
keyboard = new InlineKeyboard7();
|
|
12355
12821
|
for (let i = 0; i < report.pendingFixes.length; i++) {
|
|
12356
12822
|
const label = `\u{1F527} Fix: ${report.pendingFixes[i].message.slice(0, 30)}`;
|
|
12357
12823
|
keyboard.text(label, `m:doctor:fix:${i}`).row();
|
|
@@ -12449,7 +12915,7 @@ var init_doctor2 = __esm({
|
|
|
12449
12915
|
});
|
|
12450
12916
|
|
|
12451
12917
|
// src/plugins/telegram/commands/tunnel.ts
|
|
12452
|
-
import { InlineKeyboard as
|
|
12918
|
+
import { InlineKeyboard as InlineKeyboard8 } from "grammy";
|
|
12453
12919
|
function setupTunnelCallbacks(bot, core) {
|
|
12454
12920
|
bot.callbackQuery(/^tn:/, async (ctx) => {
|
|
12455
12921
|
const data = ctx.callbackQuery.data;
|
|
@@ -12476,7 +12942,7 @@ function setupTunnelCallbacks(bot, core) {
|
|
|
12476
12942
|
if (remaining2.length === 0) {
|
|
12477
12943
|
await ctx.editMessageText("\u{1F50C} All tunnels stopped.", { parse_mode: "HTML" });
|
|
12478
12944
|
} else {
|
|
12479
|
-
const kb = new
|
|
12945
|
+
const kb = new InlineKeyboard8();
|
|
12480
12946
|
for (const e of remaining2) {
|
|
12481
12947
|
kb.text(`\u{1F50C} Stop ${e.port}${e.label ? ` (${e.label})` : ""}`, `tn:stop:${e.port}`).row();
|
|
12482
12948
|
}
|
|
@@ -12513,7 +12979,7 @@ var init_tunnel4 = __esm({
|
|
|
12513
12979
|
});
|
|
12514
12980
|
|
|
12515
12981
|
// src/plugins/telegram/commands/switch.ts
|
|
12516
|
-
import { InlineKeyboard as
|
|
12982
|
+
import { InlineKeyboard as InlineKeyboard9 } from "grammy";
|
|
12517
12983
|
async function executeSwitchAgent(ctx, core, sessionId, agentName) {
|
|
12518
12984
|
try {
|
|
12519
12985
|
const { resumed } = await core.switchSessionAgent(sessionId, agentName);
|
|
@@ -12540,7 +13006,7 @@ function setupSwitchCallbacks(bot, core) {
|
|
|
12540
13006
|
return;
|
|
12541
13007
|
}
|
|
12542
13008
|
if (session.promptRunning) {
|
|
12543
|
-
const keyboard = new
|
|
13009
|
+
const keyboard = new InlineKeyboard9();
|
|
12544
13010
|
keyboard.text("Yes, switch now", `swc:${agentName}`).text("Cancel", "swc:cancel");
|
|
12545
13011
|
await ctx.reply(
|
|
12546
13012
|
`A prompt is currently running. Switching will interrupt it.
|
|
@@ -12580,10 +13046,35 @@ var init_switch = __esm({
|
|
|
12580
13046
|
}
|
|
12581
13047
|
});
|
|
12582
13048
|
|
|
13049
|
+
// src/plugins/telegram/commands/telegram-overrides.ts
|
|
13050
|
+
var TELEGRAM_OVERRIDES;
|
|
13051
|
+
var init_telegram_overrides = __esm({
|
|
13052
|
+
"src/plugins/telegram/commands/telegram-overrides.ts"() {
|
|
13053
|
+
"use strict";
|
|
13054
|
+
init_agents2();
|
|
13055
|
+
init_session();
|
|
13056
|
+
init_doctor2();
|
|
13057
|
+
init_admin();
|
|
13058
|
+
init_menu();
|
|
13059
|
+
TELEGRAM_OVERRIDES = {
|
|
13060
|
+
agents: (ctx, core) => handleAgents(ctx, core),
|
|
13061
|
+
sessions: (ctx, core) => handleTopics(ctx, core),
|
|
13062
|
+
doctor: (ctx) => handleDoctor(ctx),
|
|
13063
|
+
update: (ctx, core) => handleUpdate(ctx, core),
|
|
13064
|
+
restart: (ctx, core) => handleRestart(ctx, core),
|
|
13065
|
+
help: (ctx) => handleHelp(ctx),
|
|
13066
|
+
menu: (ctx, core) => {
|
|
13067
|
+
const menuRegistry = core.lifecycleManager?.serviceRegistry?.get("menu-registry");
|
|
13068
|
+
return handleMenu(ctx, menuRegistry);
|
|
13069
|
+
}
|
|
13070
|
+
};
|
|
13071
|
+
}
|
|
13072
|
+
});
|
|
13073
|
+
|
|
12583
13074
|
// src/plugins/telegram/commands/integrate.ts
|
|
12584
|
-
import { InlineKeyboard as
|
|
13075
|
+
import { InlineKeyboard as InlineKeyboard10 } from "grammy";
|
|
12585
13076
|
function buildAgentItemsKeyboard(agentName, items) {
|
|
12586
|
-
const keyboard = new
|
|
13077
|
+
const keyboard = new InlineKeyboard10();
|
|
12587
13078
|
for (const item of items) {
|
|
12588
13079
|
const installed = item.isInstalled();
|
|
12589
13080
|
keyboard.text(
|
|
@@ -12604,7 +13095,7 @@ function setupIntegrateCallbacks(bot, core) {
|
|
|
12604
13095
|
if (data === "i:back") {
|
|
12605
13096
|
const { listIntegrations: listIntegrations2 } = await Promise.resolve().then(() => (init_integrate(), integrate_exports));
|
|
12606
13097
|
const agents = listIntegrations2();
|
|
12607
|
-
const keyboard2 = new
|
|
13098
|
+
const keyboard2 = new InlineKeyboard10();
|
|
12608
13099
|
for (const agent of agents) {
|
|
12609
13100
|
keyboard2.text(`\u{1F916} ${agent}`, `i:agent:${agent}`).row();
|
|
12610
13101
|
}
|
|
@@ -12697,16 +13188,19 @@ __export(assistant_exports, {
|
|
|
12697
13188
|
redirectToAssistant: () => redirectToAssistant
|
|
12698
13189
|
});
|
|
12699
13190
|
function buildWelcomeMessage(ctx) {
|
|
12700
|
-
const { activeCount, errorCount, totalCount, agents, defaultAgent } = ctx;
|
|
13191
|
+
const { activeCount, errorCount, totalCount, agents, defaultAgent, workspace } = ctx;
|
|
12701
13192
|
const agentList = agents.map((a) => `${a}${a === defaultAgent ? " (default)" : ""}`).join(", ");
|
|
12702
13193
|
if (totalCount === 0) {
|
|
12703
13194
|
return `\u{1F44B} <b>OpenACP is ready!</b>
|
|
12704
13195
|
|
|
13196
|
+
\u{1F4C2} ${workspace}
|
|
13197
|
+
|
|
12705
13198
|
No sessions yet. Tap \u{1F195} New Session to start, or ask me anything!`;
|
|
12706
13199
|
}
|
|
12707
13200
|
if (errorCount > 0) {
|
|
12708
13201
|
return `\u{1F44B} <b>OpenACP is ready!</b>
|
|
12709
13202
|
|
|
13203
|
+
\u{1F4C2} ${workspace}
|
|
12710
13204
|
\u{1F4CA} ${activeCount} active, ${errorCount} errors / ${totalCount} total
|
|
12711
13205
|
\u26A0\uFE0F ${errorCount} session${errorCount > 1 ? "s have" : " has"} errors \u2014 ask me to check if you'd like.
|
|
12712
13206
|
|
|
@@ -12714,6 +13208,7 @@ Agents: ${agentList}`;
|
|
|
12714
13208
|
}
|
|
12715
13209
|
return `\u{1F44B} <b>OpenACP is ready!</b>
|
|
12716
13210
|
|
|
13211
|
+
\u{1F4C2} ${workspace}
|
|
12717
13212
|
\u{1F4CA} ${activeCount} active / ${totalCount} total
|
|
12718
13213
|
Agents: ${agentList}`;
|
|
12719
13214
|
}
|
|
@@ -12748,6 +13243,7 @@ function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSessio
|
|
|
12748
13243
|
core.configManager.get().workspace.baseDir
|
|
12749
13244
|
);
|
|
12750
13245
|
});
|
|
13246
|
+
setupNewSessionCallbacks(bot, core, chatId, getAssistantSession);
|
|
12751
13247
|
bot.callbackQuery(/^ar:/, (ctx) => handleArchiveConfirm(ctx, core, chatId));
|
|
12752
13248
|
bot.callbackQuery(/^m:/, async (ctx) => {
|
|
12753
13249
|
const itemId = ctx.callbackQuery.data.replace("m:", "");
|
|
@@ -12763,6 +13259,17 @@ function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSessio
|
|
|
12763
13259
|
const registry = core.lifecycleManager?.serviceRegistry?.get("command-registry");
|
|
12764
13260
|
switch (item.action.type) {
|
|
12765
13261
|
case "command": {
|
|
13262
|
+
const cmdName = item.action.command.replace(/^\//, "").split(" ")[0];
|
|
13263
|
+
const telegramOverride = TELEGRAM_OVERRIDES[cmdName];
|
|
13264
|
+
if (telegramOverride) {
|
|
13265
|
+
try {
|
|
13266
|
+
await telegramOverride(ctx, core);
|
|
13267
|
+
} catch (err) {
|
|
13268
|
+
await ctx.reply(`\u26A0\uFE0F Command failed: ${String(err)}`).catch(() => {
|
|
13269
|
+
});
|
|
13270
|
+
}
|
|
13271
|
+
break;
|
|
13272
|
+
}
|
|
12766
13273
|
if (!registry) return;
|
|
12767
13274
|
const response = await registry.execute(item.action.command, {
|
|
12768
13275
|
raw: "",
|
|
@@ -12785,16 +13292,16 @@ function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSessio
|
|
|
12785
13292
|
${lines}`, { parse_mode: "HTML" }).catch(() => {
|
|
12786
13293
|
});
|
|
12787
13294
|
} else if (response.type === "menu") {
|
|
12788
|
-
const { InlineKeyboard:
|
|
12789
|
-
const kb = new
|
|
13295
|
+
const { InlineKeyboard: InlineKeyboard12 } = await import("grammy");
|
|
13296
|
+
const kb = new InlineKeyboard12();
|
|
12790
13297
|
for (const opt of response.options) {
|
|
12791
13298
|
kb.text(opt.label, `c/${opt.command}`).row();
|
|
12792
13299
|
}
|
|
12793
13300
|
await ctx.reply(response.title, { parse_mode: "HTML", reply_markup: kb }).catch(() => {
|
|
12794
13301
|
});
|
|
12795
13302
|
} else if (response.type === "confirm") {
|
|
12796
|
-
const { InlineKeyboard:
|
|
12797
|
-
const kb = new
|
|
13303
|
+
const { InlineKeyboard: InlineKeyboard12 } = await import("grammy");
|
|
13304
|
+
const kb = new InlineKeyboard12().text("\u2705 Yes", `c/${response.onYes}`).text("\u274C No", `c/${response.onNo}`);
|
|
12798
13305
|
await ctx.reply(response.question, { reply_markup: kb }).catch(() => {
|
|
12799
13306
|
});
|
|
12800
13307
|
}
|
|
@@ -12802,6 +13309,10 @@ ${lines}`, { parse_mode: "HTML" }).catch(() => {
|
|
|
12802
13309
|
break;
|
|
12803
13310
|
}
|
|
12804
13311
|
case "delegate": {
|
|
13312
|
+
if (itemId === "core:new") {
|
|
13313
|
+
await showAgentPicker(ctx, core, chatId);
|
|
13314
|
+
break;
|
|
13315
|
+
}
|
|
12805
13316
|
const assistant = core.assistantManager?.get("telegram");
|
|
12806
13317
|
if (assistant) {
|
|
12807
13318
|
if (topicId && systemTopicIds && topicId !== systemTopicIds.assistantTopicId) {
|
|
@@ -12817,8 +13328,13 @@ ${lines}`, { parse_mode: "HTML" }).catch(() => {
|
|
|
12817
13328
|
}
|
|
12818
13329
|
break;
|
|
12819
13330
|
}
|
|
12820
|
-
case "callback":
|
|
13331
|
+
case "callback": {
|
|
13332
|
+
const cbData = item.action.callbackData;
|
|
13333
|
+
if (cbData === "s:settings") {
|
|
13334
|
+
await handleSettings(ctx, core);
|
|
13335
|
+
}
|
|
12821
13336
|
break;
|
|
13337
|
+
}
|
|
12822
13338
|
}
|
|
12823
13339
|
});
|
|
12824
13340
|
}
|
|
@@ -12834,8 +13350,10 @@ var init_commands3 = __esm({
|
|
|
12834
13350
|
init_doctor2();
|
|
12835
13351
|
init_tunnel4();
|
|
12836
13352
|
init_switch();
|
|
13353
|
+
init_telegram_overrides();
|
|
12837
13354
|
init_menu();
|
|
12838
13355
|
init_menu();
|
|
13356
|
+
init_telegram_overrides();
|
|
12839
13357
|
init_new_session();
|
|
12840
13358
|
init_session();
|
|
12841
13359
|
init_admin();
|
|
@@ -12877,7 +13395,7 @@ var init_commands3 = __esm({
|
|
|
12877
13395
|
});
|
|
12878
13396
|
|
|
12879
13397
|
// src/plugins/telegram/permissions.ts
|
|
12880
|
-
import { InlineKeyboard as
|
|
13398
|
+
import { InlineKeyboard as InlineKeyboard11 } from "grammy";
|
|
12881
13399
|
import { nanoid as nanoid2 } from "nanoid";
|
|
12882
13400
|
var log21, PermissionHandler;
|
|
12883
13401
|
var init_permissions = __esm({
|
|
@@ -12903,7 +13421,7 @@ var init_permissions = __esm({
|
|
|
12903
13421
|
requestId: request.id,
|
|
12904
13422
|
options: request.options.map((o) => ({ id: o.id, isAllow: o.isAllow }))
|
|
12905
13423
|
});
|
|
12906
|
-
const keyboard = new
|
|
13424
|
+
const keyboard = new InlineKeyboard11();
|
|
12907
13425
|
for (const option of request.options) {
|
|
12908
13426
|
const emoji = option.isAllow ? "\u2705" : "\u274C";
|
|
12909
13427
|
keyboard.text(`${emoji} ${option.label}`, `p:${callbackKey}:${option.id}`);
|
|
@@ -14545,6 +15063,7 @@ var init_adapter2 = __esm({
|
|
|
14545
15063
|
init_log();
|
|
14546
15064
|
init_topics2();
|
|
14547
15065
|
init_commands3();
|
|
15066
|
+
init_telegram_overrides();
|
|
14548
15067
|
init_admin();
|
|
14549
15068
|
init_permissions();
|
|
14550
15069
|
init_assistant();
|
|
@@ -14757,6 +15276,15 @@ var init_adapter2 = __esm({
|
|
|
14757
15276
|
const commandName = atIdx === -1 ? rawCommand : rawCommand.slice(0, atIdx);
|
|
14758
15277
|
const def = registry.get(commandName);
|
|
14759
15278
|
if (!def) return next();
|
|
15279
|
+
const telegramOverride = TELEGRAM_OVERRIDES[commandName];
|
|
15280
|
+
if (telegramOverride) {
|
|
15281
|
+
try {
|
|
15282
|
+
await telegramOverride(ctx, this.core);
|
|
15283
|
+
} catch (err) {
|
|
15284
|
+
await ctx.reply(`\u26A0\uFE0F Command failed: ${String(err)}`);
|
|
15285
|
+
}
|
|
15286
|
+
return;
|
|
15287
|
+
}
|
|
14760
15288
|
const chatId = ctx.chat.id;
|
|
14761
15289
|
const topicId = ctx.message.message_thread_id;
|
|
14762
15290
|
try {
|
|
@@ -14862,7 +15390,16 @@ var init_adapter2 = __esm({
|
|
|
14862
15390
|
if (!assistant) return void 0;
|
|
14863
15391
|
return {
|
|
14864
15392
|
topicId: this.assistantTopicId,
|
|
14865
|
-
enqueuePrompt: (p2) =>
|
|
15393
|
+
enqueuePrompt: (p2) => {
|
|
15394
|
+
const pending = this.core.assistantManager?.consumePendingSystemPrompt("telegram");
|
|
15395
|
+
const text6 = pending ? `${pending}
|
|
15396
|
+
|
|
15397
|
+
---
|
|
15398
|
+
|
|
15399
|
+
User message:
|
|
15400
|
+
${p2}` : p2;
|
|
15401
|
+
return assistant.enqueuePrompt(text6);
|
|
15402
|
+
}
|
|
14866
15403
|
};
|
|
14867
15404
|
},
|
|
14868
15405
|
(sessionId, msgId) => {
|
|
@@ -14923,7 +15460,8 @@ var init_adapter2 = __esm({
|
|
|
14923
15460
|
errorCount: allRecords.filter((r) => r.status === "error").length,
|
|
14924
15461
|
totalCount: allRecords.length,
|
|
14925
15462
|
agents: agents.map((a) => a.name),
|
|
14926
|
-
defaultAgent: config.defaultAgent
|
|
15463
|
+
defaultAgent: config.defaultAgent,
|
|
15464
|
+
workspace: this.core.configManager.resolveWorkspace()
|
|
14927
15465
|
});
|
|
14928
15466
|
await this.bot.api.sendMessage(this.telegramConfig.chatId, welcomeText, {
|
|
14929
15467
|
message_thread_id: this.assistantTopicId,
|
|
@@ -16505,8 +17043,10 @@ __export(stop_exports, {
|
|
|
16505
17043
|
import path36 from "path";
|
|
16506
17044
|
import os17 from "os";
|
|
16507
17045
|
async function cmdStop(args2 = [], instanceRoot) {
|
|
17046
|
+
const json = isJsonMode(args2);
|
|
17047
|
+
if (json) await muteForJson();
|
|
16508
17048
|
const root = instanceRoot ?? path36.join(os17.homedir(), ".openacp");
|
|
16509
|
-
if (wantsHelp(args2)) {
|
|
17049
|
+
if (!json && wantsHelp(args2)) {
|
|
16510
17050
|
console.log(`
|
|
16511
17051
|
\x1B[1mopenacp stop\x1B[0m \u2014 Stop the background daemon
|
|
16512
17052
|
|
|
@@ -16514,14 +17054,20 @@ async function cmdStop(args2 = [], instanceRoot) {
|
|
|
16514
17054
|
openacp stop
|
|
16515
17055
|
|
|
16516
17056
|
Sends a stop signal to the running OpenACP daemon process.
|
|
17057
|
+
|
|
17058
|
+
\x1B[1mOptions:\x1B[0m
|
|
17059
|
+
--json Output result as JSON
|
|
17060
|
+
-h, --help Show this help message
|
|
16517
17061
|
`);
|
|
16518
17062
|
return;
|
|
16519
17063
|
}
|
|
16520
17064
|
const { stopDaemon: stopDaemon2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
16521
17065
|
const result = await stopDaemon2(getPidPath2(root), root);
|
|
16522
17066
|
if (result.stopped) {
|
|
17067
|
+
if (json) jsonSuccess({ stopped: true, pid: result.pid });
|
|
16523
17068
|
console.log(`OpenACP daemon stopped (was PID ${result.pid})`);
|
|
16524
17069
|
} else {
|
|
17070
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, result.error ?? "Daemon is not running.");
|
|
16525
17071
|
console.error(result.error);
|
|
16526
17072
|
process.exit(1);
|
|
16527
17073
|
}
|
|
@@ -16530,6 +17076,80 @@ var init_stop = __esm({
|
|
|
16530
17076
|
"src/cli/commands/stop.ts"() {
|
|
16531
17077
|
"use strict";
|
|
16532
17078
|
init_helpers();
|
|
17079
|
+
init_output();
|
|
17080
|
+
}
|
|
17081
|
+
});
|
|
17082
|
+
|
|
17083
|
+
// src/core/instance/instance-registry.ts
|
|
17084
|
+
var instance_registry_exports = {};
|
|
17085
|
+
__export(instance_registry_exports, {
|
|
17086
|
+
InstanceRegistry: () => InstanceRegistry
|
|
17087
|
+
});
|
|
17088
|
+
import fs34 from "fs";
|
|
17089
|
+
import path37 from "path";
|
|
17090
|
+
var InstanceRegistry;
|
|
17091
|
+
var init_instance_registry = __esm({
|
|
17092
|
+
"src/core/instance/instance-registry.ts"() {
|
|
17093
|
+
"use strict";
|
|
17094
|
+
InstanceRegistry = class {
|
|
17095
|
+
constructor(registryPath) {
|
|
17096
|
+
this.registryPath = registryPath;
|
|
17097
|
+
}
|
|
17098
|
+
data = { version: 1, instances: {} };
|
|
17099
|
+
load() {
|
|
17100
|
+
try {
|
|
17101
|
+
const raw = fs34.readFileSync(this.registryPath, "utf-8");
|
|
17102
|
+
const parsed = JSON.parse(raw);
|
|
17103
|
+
if (parsed.version === 1 && parsed.instances) {
|
|
17104
|
+
this.data = parsed;
|
|
17105
|
+
this.deduplicate();
|
|
17106
|
+
}
|
|
17107
|
+
} catch {
|
|
17108
|
+
}
|
|
17109
|
+
}
|
|
17110
|
+
/** Remove duplicate entries that point to the same root, keeping the first one */
|
|
17111
|
+
deduplicate() {
|
|
17112
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17113
|
+
const toRemove = [];
|
|
17114
|
+
for (const [id, entry] of Object.entries(this.data.instances)) {
|
|
17115
|
+
if (seen.has(entry.root)) {
|
|
17116
|
+
toRemove.push(id);
|
|
17117
|
+
} else {
|
|
17118
|
+
seen.add(entry.root);
|
|
17119
|
+
}
|
|
17120
|
+
}
|
|
17121
|
+
if (toRemove.length > 0) {
|
|
17122
|
+
for (const id of toRemove) delete this.data.instances[id];
|
|
17123
|
+
this.save();
|
|
17124
|
+
}
|
|
17125
|
+
}
|
|
17126
|
+
save() {
|
|
17127
|
+
const dir = path37.dirname(this.registryPath);
|
|
17128
|
+
fs34.mkdirSync(dir, { recursive: true });
|
|
17129
|
+
fs34.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
|
|
17130
|
+
}
|
|
17131
|
+
register(id, root) {
|
|
17132
|
+
this.data.instances[id] = { id, root };
|
|
17133
|
+
}
|
|
17134
|
+
remove(id) {
|
|
17135
|
+
delete this.data.instances[id];
|
|
17136
|
+
}
|
|
17137
|
+
get(id) {
|
|
17138
|
+
return this.data.instances[id];
|
|
17139
|
+
}
|
|
17140
|
+
getByRoot(root) {
|
|
17141
|
+
return Object.values(this.data.instances).find((e) => e.root === root);
|
|
17142
|
+
}
|
|
17143
|
+
list() {
|
|
17144
|
+
return Object.values(this.data.instances);
|
|
17145
|
+
}
|
|
17146
|
+
uniqueId(baseId) {
|
|
17147
|
+
if (!this.data.instances[baseId]) return baseId;
|
|
17148
|
+
let n = 2;
|
|
17149
|
+
while (this.data.instances[`${baseId}-${n}`]) n++;
|
|
17150
|
+
return `${baseId}-${n}`;
|
|
17151
|
+
}
|
|
17152
|
+
};
|
|
16533
17153
|
}
|
|
16534
17154
|
});
|
|
16535
17155
|
|
|
@@ -16839,8 +17459,8 @@ var init_mcp_manager = __esm({
|
|
|
16839
17459
|
});
|
|
16840
17460
|
|
|
16841
17461
|
// src/core/utils/debug-tracer.ts
|
|
16842
|
-
import
|
|
16843
|
-
import
|
|
17462
|
+
import fs35 from "fs";
|
|
17463
|
+
import path38 from "path";
|
|
16844
17464
|
function createDebugTracer(sessionId, workingDirectory) {
|
|
16845
17465
|
if (!DEBUG_ENABLED) return null;
|
|
16846
17466
|
return new DebugTracer(sessionId, workingDirectory);
|
|
@@ -16854,17 +17474,17 @@ var init_debug_tracer = __esm({
|
|
|
16854
17474
|
constructor(sessionId, workingDirectory) {
|
|
16855
17475
|
this.sessionId = sessionId;
|
|
16856
17476
|
this.workingDirectory = workingDirectory;
|
|
16857
|
-
this.logDir =
|
|
17477
|
+
this.logDir = path38.join(workingDirectory, ".log");
|
|
16858
17478
|
}
|
|
16859
17479
|
dirCreated = false;
|
|
16860
17480
|
logDir;
|
|
16861
17481
|
log(layer, data) {
|
|
16862
17482
|
try {
|
|
16863
17483
|
if (!this.dirCreated) {
|
|
16864
|
-
|
|
17484
|
+
fs35.mkdirSync(this.logDir, { recursive: true });
|
|
16865
17485
|
this.dirCreated = true;
|
|
16866
17486
|
}
|
|
16867
|
-
const filePath =
|
|
17487
|
+
const filePath = path38.join(this.logDir, `${this.sessionId}_${layer}.jsonl`);
|
|
16868
17488
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
16869
17489
|
const line = JSON.stringify({ ts: Date.now(), ...data }, (_key, value) => {
|
|
16870
17490
|
if (typeof value === "object" && value !== null) {
|
|
@@ -16873,7 +17493,7 @@ var init_debug_tracer = __esm({
|
|
|
16873
17493
|
}
|
|
16874
17494
|
return value;
|
|
16875
17495
|
}) + "\n";
|
|
16876
|
-
|
|
17496
|
+
fs35.appendFileSync(filePath, line);
|
|
16877
17497
|
} catch {
|
|
16878
17498
|
}
|
|
16879
17499
|
}
|
|
@@ -16887,17 +17507,17 @@ var init_debug_tracer = __esm({
|
|
|
16887
17507
|
// src/core/agents/agent-instance.ts
|
|
16888
17508
|
import { spawn as spawn7, execFileSync as execFileSync5 } from "child_process";
|
|
16889
17509
|
import { Transform } from "stream";
|
|
16890
|
-
import
|
|
16891
|
-
import
|
|
17510
|
+
import fs36 from "fs";
|
|
17511
|
+
import path39 from "path";
|
|
16892
17512
|
import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
16893
17513
|
import { PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
|
|
16894
17514
|
function findPackageRoot(startDir) {
|
|
16895
17515
|
let dir = startDir;
|
|
16896
|
-
while (dir !==
|
|
16897
|
-
if (
|
|
17516
|
+
while (dir !== path39.dirname(dir)) {
|
|
17517
|
+
if (fs36.existsSync(path39.join(dir, "package.json"))) {
|
|
16898
17518
|
return dir;
|
|
16899
17519
|
}
|
|
16900
|
-
dir =
|
|
17520
|
+
dir = path39.dirname(dir);
|
|
16901
17521
|
}
|
|
16902
17522
|
return startDir;
|
|
16903
17523
|
}
|
|
@@ -16909,26 +17529,26 @@ function resolveAgentCommand(cmd) {
|
|
|
16909
17529
|
}
|
|
16910
17530
|
for (const root of searchRoots) {
|
|
16911
17531
|
const packageDirs = [
|
|
16912
|
-
|
|
16913
|
-
|
|
17532
|
+
path39.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
|
|
17533
|
+
path39.resolve(root, "node_modules", cmd, "dist", "index.js")
|
|
16914
17534
|
];
|
|
16915
17535
|
for (const jsPath of packageDirs) {
|
|
16916
|
-
if (
|
|
17536
|
+
if (fs36.existsSync(jsPath)) {
|
|
16917
17537
|
return { command: process.execPath, args: [jsPath] };
|
|
16918
17538
|
}
|
|
16919
17539
|
}
|
|
16920
17540
|
}
|
|
16921
17541
|
for (const root of searchRoots) {
|
|
16922
|
-
const localBin =
|
|
16923
|
-
if (
|
|
16924
|
-
const content =
|
|
17542
|
+
const localBin = path39.resolve(root, "node_modules", ".bin", cmd);
|
|
17543
|
+
if (fs36.existsSync(localBin)) {
|
|
17544
|
+
const content = fs36.readFileSync(localBin, "utf-8");
|
|
16925
17545
|
if (content.startsWith("#!/usr/bin/env node")) {
|
|
16926
17546
|
return { command: process.execPath, args: [localBin] };
|
|
16927
17547
|
}
|
|
16928
17548
|
const match = content.match(/"([^"]+\.js)"/);
|
|
16929
17549
|
if (match) {
|
|
16930
|
-
const target =
|
|
16931
|
-
if (
|
|
17550
|
+
const target = path39.resolve(path39.dirname(localBin), match[1]);
|
|
17551
|
+
if (fs36.existsSync(target)) {
|
|
16932
17552
|
return { command: process.execPath, args: [target] };
|
|
16933
17553
|
}
|
|
16934
17554
|
}
|
|
@@ -16937,7 +17557,7 @@ function resolveAgentCommand(cmd) {
|
|
|
16937
17557
|
try {
|
|
16938
17558
|
const fullPath = execFileSync5("which", [cmd], { encoding: "utf-8" }).trim();
|
|
16939
17559
|
if (fullPath) {
|
|
16940
|
-
const content =
|
|
17560
|
+
const content = fs36.readFileSync(fullPath, "utf-8");
|
|
16941
17561
|
if (content.startsWith("#!/usr/bin/env node")) {
|
|
16942
17562
|
return { command: process.execPath, args: [fullPath] };
|
|
16943
17563
|
}
|
|
@@ -17328,8 +17948,8 @@ ${stderr}`
|
|
|
17328
17948
|
writePath = result.path;
|
|
17329
17949
|
writeContent = result.content;
|
|
17330
17950
|
}
|
|
17331
|
-
await
|
|
17332
|
-
await
|
|
17951
|
+
await fs36.promises.mkdir(path39.dirname(writePath), { recursive: true });
|
|
17952
|
+
await fs36.promises.writeFile(writePath, writeContent, "utf-8");
|
|
17333
17953
|
return {};
|
|
17334
17954
|
},
|
|
17335
17955
|
// ── Terminal operations (delegated to TerminalManager) ─────────────
|
|
@@ -17404,10 +18024,10 @@ ${stderr}`
|
|
|
17404
18024
|
for (const att of attachments ?? []) {
|
|
17405
18025
|
const tooLarge = att.size > 10 * 1024 * 1024;
|
|
17406
18026
|
if (att.type === "image" && this.promptCapabilities?.image && !tooLarge && SUPPORTED_IMAGE_MIMES.has(att.mimeType)) {
|
|
17407
|
-
const data = await
|
|
18027
|
+
const data = await fs36.promises.readFile(att.filePath);
|
|
17408
18028
|
contentBlocks.push({ type: "image", data: data.toString("base64"), mimeType: att.mimeType });
|
|
17409
18029
|
} else if (att.type === "audio" && this.promptCapabilities?.audio && !tooLarge) {
|
|
17410
|
-
const data = await
|
|
18030
|
+
const data = await fs36.promises.readFile(att.filePath);
|
|
17411
18031
|
contentBlocks.push({ type: "audio", data: data.toString("base64"), mimeType: att.mimeType });
|
|
17412
18032
|
} else {
|
|
17413
18033
|
if ((att.type === "image" || att.type === "audio") && !tooLarge) {
|
|
@@ -17631,7 +18251,7 @@ var init_permission_gate = __esm({
|
|
|
17631
18251
|
|
|
17632
18252
|
// src/core/sessions/session.ts
|
|
17633
18253
|
import { nanoid as nanoid3 } from "nanoid";
|
|
17634
|
-
import * as
|
|
18254
|
+
import * as fs37 from "fs";
|
|
17635
18255
|
var moduleLog, TTS_PROMPT_INSTRUCTION, TTS_BLOCK_REGEX, TTS_MAX_LENGTH, TTS_TIMEOUT_MS, VALID_TRANSITIONS, Session;
|
|
17636
18256
|
var init_session2 = __esm({
|
|
17637
18257
|
"src/core/sessions/session.ts"() {
|
|
@@ -17862,7 +18482,7 @@ ${text6}`;
|
|
|
17862
18482
|
try {
|
|
17863
18483
|
const audioPath = att.originalFilePath || att.filePath;
|
|
17864
18484
|
const audioMime = att.originalFilePath ? "audio/ogg" : att.mimeType;
|
|
17865
|
-
const audioBuffer = await
|
|
18485
|
+
const audioBuffer = await fs37.promises.readFile(audioPath);
|
|
17866
18486
|
const result = await this.speechService.transcribe(audioBuffer, audioMime);
|
|
17867
18487
|
this.log.info({ provider: "stt", duration: result.duration }, "Voice transcribed");
|
|
17868
18488
|
this.emit("agent_event", {
|
|
@@ -18939,8 +19559,8 @@ var init_message_transformer = __esm({
|
|
|
18939
19559
|
});
|
|
18940
19560
|
|
|
18941
19561
|
// src/core/sessions/session-store.ts
|
|
18942
|
-
import
|
|
18943
|
-
import
|
|
19562
|
+
import fs38 from "fs";
|
|
19563
|
+
import path40 from "path";
|
|
18944
19564
|
var log29, DEBOUNCE_MS2, JsonFileSessionStore;
|
|
18945
19565
|
var init_session_store = __esm({
|
|
18946
19566
|
"src/core/sessions/session-store.ts"() {
|
|
@@ -19016,9 +19636,9 @@ var init_session_store = __esm({
|
|
|
19016
19636
|
version: 1,
|
|
19017
19637
|
sessions: Object.fromEntries(this.records)
|
|
19018
19638
|
};
|
|
19019
|
-
const dir =
|
|
19020
|
-
if (!
|
|
19021
|
-
|
|
19639
|
+
const dir = path40.dirname(this.filePath);
|
|
19640
|
+
if (!fs38.existsSync(dir)) fs38.mkdirSync(dir, { recursive: true });
|
|
19641
|
+
fs38.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
|
|
19022
19642
|
}
|
|
19023
19643
|
destroy() {
|
|
19024
19644
|
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
@@ -19031,10 +19651,10 @@ var init_session_store = __esm({
|
|
|
19031
19651
|
}
|
|
19032
19652
|
}
|
|
19033
19653
|
load() {
|
|
19034
|
-
if (!
|
|
19654
|
+
if (!fs38.existsSync(this.filePath)) return;
|
|
19035
19655
|
try {
|
|
19036
19656
|
const raw = JSON.parse(
|
|
19037
|
-
|
|
19657
|
+
fs38.readFileSync(this.filePath, "utf-8")
|
|
19038
19658
|
);
|
|
19039
19659
|
if (raw.version !== 1) {
|
|
19040
19660
|
log29.warn(
|
|
@@ -19050,7 +19670,7 @@ var init_session_store = __esm({
|
|
|
19050
19670
|
} catch (err) {
|
|
19051
19671
|
log29.error({ err }, "Failed to load session store, backing up corrupt file");
|
|
19052
19672
|
try {
|
|
19053
|
-
|
|
19673
|
+
fs38.renameSync(this.filePath, `${this.filePath}.bak`);
|
|
19054
19674
|
} catch {
|
|
19055
19675
|
}
|
|
19056
19676
|
}
|
|
@@ -19590,8 +20210,8 @@ var agent_store_exports = {};
|
|
|
19590
20210
|
__export(agent_store_exports, {
|
|
19591
20211
|
AgentStore: () => AgentStore
|
|
19592
20212
|
});
|
|
19593
|
-
import * as
|
|
19594
|
-
import * as
|
|
20213
|
+
import * as fs39 from "fs";
|
|
20214
|
+
import * as path41 from "path";
|
|
19595
20215
|
import * as os18 from "os";
|
|
19596
20216
|
import { z as z7 } from "zod";
|
|
19597
20217
|
var log32, InstalledAgentSchema, AgentStoreSchema, AgentStore;
|
|
@@ -19620,15 +20240,15 @@ var init_agent_store = __esm({
|
|
|
19620
20240
|
data = { version: 1, installed: {} };
|
|
19621
20241
|
filePath;
|
|
19622
20242
|
constructor(filePath) {
|
|
19623
|
-
this.filePath = filePath ??
|
|
20243
|
+
this.filePath = filePath ?? path41.join(os18.homedir(), ".openacp", "agents.json");
|
|
19624
20244
|
}
|
|
19625
20245
|
load() {
|
|
19626
|
-
if (!
|
|
20246
|
+
if (!fs39.existsSync(this.filePath)) {
|
|
19627
20247
|
this.data = { version: 1, installed: {} };
|
|
19628
20248
|
return;
|
|
19629
20249
|
}
|
|
19630
20250
|
try {
|
|
19631
|
-
const raw = JSON.parse(
|
|
20251
|
+
const raw = JSON.parse(fs39.readFileSync(this.filePath, "utf-8"));
|
|
19632
20252
|
const result = AgentStoreSchema.safeParse(raw);
|
|
19633
20253
|
if (result.success) {
|
|
19634
20254
|
this.data = result.data;
|
|
@@ -19642,7 +20262,7 @@ var init_agent_store = __esm({
|
|
|
19642
20262
|
}
|
|
19643
20263
|
}
|
|
19644
20264
|
exists() {
|
|
19645
|
-
return
|
|
20265
|
+
return fs39.existsSync(this.filePath);
|
|
19646
20266
|
}
|
|
19647
20267
|
getInstalled() {
|
|
19648
20268
|
return this.data.installed;
|
|
@@ -19662,18 +20282,18 @@ var init_agent_store = __esm({
|
|
|
19662
20282
|
return key in this.data.installed;
|
|
19663
20283
|
}
|
|
19664
20284
|
save() {
|
|
19665
|
-
|
|
20285
|
+
fs39.mkdirSync(path41.dirname(this.filePath), { recursive: true });
|
|
19666
20286
|
const tmpPath = this.filePath + ".tmp";
|
|
19667
|
-
|
|
19668
|
-
|
|
20287
|
+
fs39.writeFileSync(tmpPath, JSON.stringify(this.data, null, 2));
|
|
20288
|
+
fs39.renameSync(tmpPath, this.filePath);
|
|
19669
20289
|
}
|
|
19670
20290
|
};
|
|
19671
20291
|
}
|
|
19672
20292
|
});
|
|
19673
20293
|
|
|
19674
20294
|
// src/core/agents/agent-installer.ts
|
|
19675
|
-
import * as
|
|
19676
|
-
import * as
|
|
20295
|
+
import * as fs40 from "fs";
|
|
20296
|
+
import * as path42 from "path";
|
|
19677
20297
|
import * as os19 from "os";
|
|
19678
20298
|
function getPlatformKey() {
|
|
19679
20299
|
const platform2 = PLATFORM_MAP[process.platform] ?? process.platform;
|
|
@@ -19725,7 +20345,7 @@ function buildInstalledAgent(registryId, name, version, dist, binaryPath) {
|
|
|
19725
20345
|
binaryPath: null
|
|
19726
20346
|
};
|
|
19727
20347
|
}
|
|
19728
|
-
const absCmd =
|
|
20348
|
+
const absCmd = path42.resolve(binaryPath, dist.cmd);
|
|
19729
20349
|
return {
|
|
19730
20350
|
registryId,
|
|
19731
20351
|
name,
|
|
@@ -19798,8 +20418,8 @@ Install it with: pip install uv`;
|
|
|
19798
20418
|
return { ok: true, agentKey, setupSteps: setup?.setupSteps };
|
|
19799
20419
|
}
|
|
19800
20420
|
async function downloadAndExtract(agentId, archiveUrl, progress, agentsDir) {
|
|
19801
|
-
const destDir =
|
|
19802
|
-
|
|
20421
|
+
const destDir = path42.join(agentsDir ?? DEFAULT_AGENTS_DIR, agentId);
|
|
20422
|
+
fs40.mkdirSync(destDir, { recursive: true });
|
|
19803
20423
|
await progress?.onStep("Downloading...");
|
|
19804
20424
|
log33.info({ agentId, url: archiveUrl }, "Downloading agent binary");
|
|
19805
20425
|
const response = await fetch(archiveUrl);
|
|
@@ -19837,52 +20457,52 @@ async function readResponseWithProgress(response, contentLength, progress) {
|
|
|
19837
20457
|
return Buffer.concat(chunks);
|
|
19838
20458
|
}
|
|
19839
20459
|
function validateExtractedPaths(destDir) {
|
|
19840
|
-
const realDest =
|
|
19841
|
-
const entries =
|
|
20460
|
+
const realDest = fs40.realpathSync(destDir);
|
|
20461
|
+
const entries = fs40.readdirSync(destDir, { recursive: true, withFileTypes: true });
|
|
19842
20462
|
for (const entry of entries) {
|
|
19843
20463
|
const dirent = entry;
|
|
19844
20464
|
const parentPath = dirent.parentPath ?? dirent.path ?? destDir;
|
|
19845
|
-
const fullPath =
|
|
20465
|
+
const fullPath = path42.join(parentPath, entry.name);
|
|
19846
20466
|
let realPath;
|
|
19847
20467
|
try {
|
|
19848
|
-
realPath =
|
|
20468
|
+
realPath = fs40.realpathSync(fullPath);
|
|
19849
20469
|
} catch {
|
|
19850
|
-
const linkTarget =
|
|
19851
|
-
realPath =
|
|
20470
|
+
const linkTarget = fs40.readlinkSync(fullPath);
|
|
20471
|
+
realPath = path42.resolve(path42.dirname(fullPath), linkTarget);
|
|
19852
20472
|
}
|
|
19853
|
-
if (!realPath.startsWith(realDest +
|
|
19854
|
-
|
|
20473
|
+
if (!realPath.startsWith(realDest + path42.sep) && realPath !== realDest) {
|
|
20474
|
+
fs40.rmSync(destDir, { recursive: true, force: true });
|
|
19855
20475
|
throw new Error(`Archive contains unsafe path: ${entry.name}`);
|
|
19856
20476
|
}
|
|
19857
20477
|
}
|
|
19858
20478
|
}
|
|
19859
20479
|
async function extractTarGz(buffer, destDir) {
|
|
19860
20480
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
19861
|
-
const tmpFile =
|
|
19862
|
-
|
|
20481
|
+
const tmpFile = path42.join(destDir, "_archive.tar.gz");
|
|
20482
|
+
fs40.writeFileSync(tmpFile, buffer);
|
|
19863
20483
|
try {
|
|
19864
20484
|
execFileSync8("tar", ["xzf", tmpFile, "-C", destDir], { stdio: "pipe" });
|
|
19865
20485
|
} finally {
|
|
19866
|
-
|
|
20486
|
+
fs40.unlinkSync(tmpFile);
|
|
19867
20487
|
}
|
|
19868
20488
|
validateExtractedPaths(destDir);
|
|
19869
20489
|
}
|
|
19870
20490
|
async function extractZip(buffer, destDir) {
|
|
19871
20491
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
19872
|
-
const tmpFile =
|
|
19873
|
-
|
|
20492
|
+
const tmpFile = path42.join(destDir, "_archive.zip");
|
|
20493
|
+
fs40.writeFileSync(tmpFile, buffer);
|
|
19874
20494
|
try {
|
|
19875
20495
|
execFileSync8("unzip", ["-o", tmpFile, "-d", destDir], { stdio: "pipe" });
|
|
19876
20496
|
} finally {
|
|
19877
|
-
|
|
20497
|
+
fs40.unlinkSync(tmpFile);
|
|
19878
20498
|
}
|
|
19879
20499
|
validateExtractedPaths(destDir);
|
|
19880
20500
|
}
|
|
19881
20501
|
async function uninstallAgent(agentKey, store) {
|
|
19882
20502
|
const agent = store.getAgent(agentKey);
|
|
19883
20503
|
if (!agent) return;
|
|
19884
|
-
if (agent.binaryPath &&
|
|
19885
|
-
|
|
20504
|
+
if (agent.binaryPath && fs40.existsSync(agent.binaryPath)) {
|
|
20505
|
+
fs40.rmSync(agent.binaryPath, { recursive: true, force: true });
|
|
19886
20506
|
log33.info({ agentKey, binaryPath: agent.binaryPath }, "Deleted agent binary");
|
|
19887
20507
|
}
|
|
19888
20508
|
store.removeAgent(agentKey);
|
|
@@ -19894,7 +20514,7 @@ var init_agent_installer = __esm({
|
|
|
19894
20514
|
init_log();
|
|
19895
20515
|
init_agent_dependencies();
|
|
19896
20516
|
log33 = createChildLogger({ module: "agent-installer" });
|
|
19897
|
-
DEFAULT_AGENTS_DIR =
|
|
20517
|
+
DEFAULT_AGENTS_DIR = path42.join(os19.homedir(), ".openacp", "agents");
|
|
19898
20518
|
ARCH_MAP = {
|
|
19899
20519
|
arm64: "aarch64",
|
|
19900
20520
|
x64: "x86_64"
|
|
@@ -19912,8 +20532,8 @@ var agent_catalog_exports = {};
|
|
|
19912
20532
|
__export(agent_catalog_exports, {
|
|
19913
20533
|
AgentCatalog: () => AgentCatalog
|
|
19914
20534
|
});
|
|
19915
|
-
import * as
|
|
19916
|
-
import * as
|
|
20535
|
+
import * as fs41 from "fs";
|
|
20536
|
+
import * as path43 from "path";
|
|
19917
20537
|
import * as os20 from "os";
|
|
19918
20538
|
var log34, REGISTRY_URL2, DEFAULT_TTL_HOURS, AgentCatalog;
|
|
19919
20539
|
var init_agent_catalog = __esm({
|
|
@@ -19933,7 +20553,7 @@ var init_agent_catalog = __esm({
|
|
|
19933
20553
|
agentsDir;
|
|
19934
20554
|
constructor(store, cachePath, agentsDir) {
|
|
19935
20555
|
this.store = store ?? new AgentStore();
|
|
19936
|
-
this.cachePath = cachePath ??
|
|
20556
|
+
this.cachePath = cachePath ?? path43.join(os20.homedir(), ".openacp", "registry-cache.json");
|
|
19937
20557
|
this.agentsDir = agentsDir;
|
|
19938
20558
|
}
|
|
19939
20559
|
load() {
|
|
@@ -19954,8 +20574,8 @@ var init_agent_catalog = __esm({
|
|
|
19954
20574
|
ttlHours: DEFAULT_TTL_HOURS,
|
|
19955
20575
|
data
|
|
19956
20576
|
};
|
|
19957
|
-
|
|
19958
|
-
|
|
20577
|
+
fs41.mkdirSync(path43.dirname(this.cachePath), { recursive: true });
|
|
20578
|
+
fs41.writeFileSync(this.cachePath, JSON.stringify(cache, null, 2));
|
|
19959
20579
|
log34.info({ count: this.registryAgents.length }, "Registry updated");
|
|
19960
20580
|
} catch (err) {
|
|
19961
20581
|
log34.warn({ err }, "Failed to fetch registry, using cached data");
|
|
@@ -20115,9 +20735,9 @@ var init_agent_catalog = __esm({
|
|
|
20115
20735
|
}
|
|
20116
20736
|
}
|
|
20117
20737
|
isCacheStale() {
|
|
20118
|
-
if (!
|
|
20738
|
+
if (!fs41.existsSync(this.cachePath)) return true;
|
|
20119
20739
|
try {
|
|
20120
|
-
const raw = JSON.parse(
|
|
20740
|
+
const raw = JSON.parse(fs41.readFileSync(this.cachePath, "utf-8"));
|
|
20121
20741
|
const fetchedAt = new Date(raw.fetchedAt).getTime();
|
|
20122
20742
|
const ttlMs = (raw.ttlHours ?? DEFAULT_TTL_HOURS) * 60 * 60 * 1e3;
|
|
20123
20743
|
return Date.now() - fetchedAt > ttlMs;
|
|
@@ -20126,9 +20746,9 @@ var init_agent_catalog = __esm({
|
|
|
20126
20746
|
}
|
|
20127
20747
|
}
|
|
20128
20748
|
loadRegistryFromCacheOrSnapshot() {
|
|
20129
|
-
if (
|
|
20749
|
+
if (fs41.existsSync(this.cachePath)) {
|
|
20130
20750
|
try {
|
|
20131
|
-
const raw = JSON.parse(
|
|
20751
|
+
const raw = JSON.parse(fs41.readFileSync(this.cachePath, "utf-8"));
|
|
20132
20752
|
if (raw.data?.agents) {
|
|
20133
20753
|
this.registryAgents = raw.data.agents;
|
|
20134
20754
|
log34.debug({ count: this.registryAgents.length }, "Loaded registry from cache");
|
|
@@ -20140,13 +20760,13 @@ var init_agent_catalog = __esm({
|
|
|
20140
20760
|
}
|
|
20141
20761
|
try {
|
|
20142
20762
|
const candidates = [
|
|
20143
|
-
|
|
20144
|
-
|
|
20145
|
-
|
|
20763
|
+
path43.join(import.meta.dirname, "data", "registry-snapshot.json"),
|
|
20764
|
+
path43.join(import.meta.dirname, "..", "data", "registry-snapshot.json"),
|
|
20765
|
+
path43.join(import.meta.dirname, "..", "..", "data", "registry-snapshot.json")
|
|
20146
20766
|
];
|
|
20147
20767
|
for (const candidate of candidates) {
|
|
20148
|
-
if (
|
|
20149
|
-
const raw = JSON.parse(
|
|
20768
|
+
if (fs41.existsSync(candidate)) {
|
|
20769
|
+
const raw = JSON.parse(fs41.readFileSync(candidate, "utf-8"));
|
|
20150
20770
|
this.registryAgents = raw.agents ?? [];
|
|
20151
20771
|
log34.debug({ count: this.registryAgents.length }, "Loaded registry from bundled snapshot");
|
|
20152
20772
|
return;
|
|
@@ -20439,8 +21059,8 @@ var init_error_tracker = __esm({
|
|
|
20439
21059
|
});
|
|
20440
21060
|
|
|
20441
21061
|
// src/core/plugin/plugin-storage.ts
|
|
20442
|
-
import
|
|
20443
|
-
import
|
|
21062
|
+
import fs42 from "fs";
|
|
21063
|
+
import path44 from "path";
|
|
20444
21064
|
var PluginStorageImpl;
|
|
20445
21065
|
var init_plugin_storage = __esm({
|
|
20446
21066
|
"src/core/plugin/plugin-storage.ts"() {
|
|
@@ -20450,20 +21070,20 @@ var init_plugin_storage = __esm({
|
|
|
20450
21070
|
dataDir;
|
|
20451
21071
|
writeChain = Promise.resolve();
|
|
20452
21072
|
constructor(baseDir) {
|
|
20453
|
-
this.dataDir =
|
|
20454
|
-
this.kvPath =
|
|
20455
|
-
|
|
21073
|
+
this.dataDir = path44.join(baseDir, "data");
|
|
21074
|
+
this.kvPath = path44.join(baseDir, "kv.json");
|
|
21075
|
+
fs42.mkdirSync(baseDir, { recursive: true });
|
|
20456
21076
|
}
|
|
20457
21077
|
readKv() {
|
|
20458
21078
|
try {
|
|
20459
|
-
const raw =
|
|
21079
|
+
const raw = fs42.readFileSync(this.kvPath, "utf-8");
|
|
20460
21080
|
return JSON.parse(raw);
|
|
20461
21081
|
} catch {
|
|
20462
21082
|
return {};
|
|
20463
21083
|
}
|
|
20464
21084
|
}
|
|
20465
21085
|
writeKv(data) {
|
|
20466
|
-
|
|
21086
|
+
fs42.writeFileSync(this.kvPath, JSON.stringify(data), "utf-8");
|
|
20467
21087
|
}
|
|
20468
21088
|
async get(key) {
|
|
20469
21089
|
const data = this.readKv();
|
|
@@ -20489,7 +21109,7 @@ var init_plugin_storage = __esm({
|
|
|
20489
21109
|
return Object.keys(this.readKv());
|
|
20490
21110
|
}
|
|
20491
21111
|
getDataDir() {
|
|
20492
|
-
|
|
21112
|
+
fs42.mkdirSync(this.dataDir, { recursive: true });
|
|
20493
21113
|
return this.dataDir;
|
|
20494
21114
|
}
|
|
20495
21115
|
};
|
|
@@ -20497,7 +21117,7 @@ var init_plugin_storage = __esm({
|
|
|
20497
21117
|
});
|
|
20498
21118
|
|
|
20499
21119
|
// src/core/plugin/plugin-context.ts
|
|
20500
|
-
import
|
|
21120
|
+
import path45 from "path";
|
|
20501
21121
|
import os21 from "os";
|
|
20502
21122
|
function requirePermission(permissions, required, action) {
|
|
20503
21123
|
if (!permissions.includes(required)) {
|
|
@@ -20517,7 +21137,7 @@ function createPluginContext(opts) {
|
|
|
20517
21137
|
config,
|
|
20518
21138
|
core
|
|
20519
21139
|
} = opts;
|
|
20520
|
-
const instanceRoot = opts.instanceRoot ??
|
|
21140
|
+
const instanceRoot = opts.instanceRoot ?? path45.join(os21.homedir(), ".openacp");
|
|
20521
21141
|
const registeredListeners = [];
|
|
20522
21142
|
const registeredCommands = [];
|
|
20523
21143
|
const noopLog = {
|
|
@@ -21105,8 +21725,8 @@ var init_assistant_manager = __esm({
|
|
|
21105
21725
|
this.registry = registry;
|
|
21106
21726
|
}
|
|
21107
21727
|
sessions = /* @__PURE__ */ new Map();
|
|
21108
|
-
readyState = /* @__PURE__ */ new Map();
|
|
21109
21728
|
respawning = /* @__PURE__ */ new Set();
|
|
21729
|
+
pendingSystemPrompts = /* @__PURE__ */ new Map();
|
|
21110
21730
|
async spawn(channelId, threadId) {
|
|
21111
21731
|
const session = await this.core.createSession({
|
|
21112
21732
|
channelId,
|
|
@@ -21118,17 +21738,22 @@ var init_assistant_manager = __esm({
|
|
|
21118
21738
|
session.threadId = threadId;
|
|
21119
21739
|
this.sessions.set(channelId, session);
|
|
21120
21740
|
const systemPrompt = this.registry.buildSystemPrompt(channelId);
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
}).catch((err) => {
|
|
21124
|
-
log37.warn({ err, channelId }, "Assistant system prompt failed");
|
|
21125
|
-
});
|
|
21126
|
-
this.readyState.set(channelId, ready);
|
|
21741
|
+
this.pendingSystemPrompts.set(channelId, systemPrompt);
|
|
21742
|
+
log37.info({ sessionId: session.id, channelId }, "Assistant spawned (system prompt deferred)");
|
|
21127
21743
|
return session;
|
|
21128
21744
|
}
|
|
21129
21745
|
get(channelId) {
|
|
21130
21746
|
return this.sessions.get(channelId) ?? null;
|
|
21131
21747
|
}
|
|
21748
|
+
/**
|
|
21749
|
+
* Consume and return any pending system prompt for a channel.
|
|
21750
|
+
* Should be prepended to the first real user message.
|
|
21751
|
+
*/
|
|
21752
|
+
consumePendingSystemPrompt(channelId) {
|
|
21753
|
+
const prompt = this.pendingSystemPrompts.get(channelId);
|
|
21754
|
+
if (prompt) this.pendingSystemPrompts.delete(channelId);
|
|
21755
|
+
return prompt;
|
|
21756
|
+
}
|
|
21132
21757
|
isAssistant(sessionId) {
|
|
21133
21758
|
for (const s of this.sessions.values()) {
|
|
21134
21759
|
if (s.id === sessionId) return true;
|
|
@@ -21148,9 +21773,6 @@ var init_assistant_manager = __esm({
|
|
|
21148
21773
|
this.respawning.delete(channelId);
|
|
21149
21774
|
}
|
|
21150
21775
|
}
|
|
21151
|
-
async waitReady(channelId) {
|
|
21152
|
-
await this.readyState.get(channelId);
|
|
21153
|
-
}
|
|
21154
21776
|
};
|
|
21155
21777
|
}
|
|
21156
21778
|
});
|
|
@@ -21358,7 +21980,7 @@ var init_core_items = __esm({
|
|
|
21358
21980
|
});
|
|
21359
21981
|
|
|
21360
21982
|
// src/core/core.ts
|
|
21361
|
-
import
|
|
21983
|
+
import path46 from "path";
|
|
21362
21984
|
import os22 from "os";
|
|
21363
21985
|
var log38, OpenACPCore;
|
|
21364
21986
|
var init_core = __esm({
|
|
@@ -21438,7 +22060,7 @@ var init_core = __esm({
|
|
|
21438
22060
|
);
|
|
21439
22061
|
this.agentCatalog.load();
|
|
21440
22062
|
this.agentManager = new AgentManager(this.agentCatalog);
|
|
21441
|
-
const storePath = ctx?.paths.sessions ??
|
|
22063
|
+
const storePath = ctx?.paths.sessions ?? path46.join(os22.homedir(), ".openacp", "sessions.json");
|
|
21442
22064
|
this.sessionStore = new JsonFileSessionStore(
|
|
21443
22065
|
storePath,
|
|
21444
22066
|
config.sessionStore.ttlDays
|
|
@@ -21462,7 +22084,7 @@ var init_core = __esm({
|
|
|
21462
22084
|
sessions: this.sessionManager,
|
|
21463
22085
|
config: this.configManager,
|
|
21464
22086
|
core: this,
|
|
21465
|
-
storagePath: ctx?.paths.pluginsData ??
|
|
22087
|
+
storagePath: ctx?.paths.pluginsData ?? path46.join(os22.homedir(), ".openacp", "plugins", "data"),
|
|
21466
22088
|
instanceRoot: ctx?.root,
|
|
21467
22089
|
log: createChildLogger({ module: "plugin" })
|
|
21468
22090
|
});
|
|
@@ -21509,7 +22131,7 @@ var init_core = __esm({
|
|
|
21509
22131
|
);
|
|
21510
22132
|
registerCoreMenuItems(this.menuRegistry);
|
|
21511
22133
|
if (ctx?.root) {
|
|
21512
|
-
this.assistantRegistry.setInstanceRoot(
|
|
22134
|
+
this.assistantRegistry.setInstanceRoot(path46.dirname(ctx.root));
|
|
21513
22135
|
}
|
|
21514
22136
|
this.assistantRegistry.register(createSessionsSection(this));
|
|
21515
22137
|
this.assistantRegistry.register(createAgentsSection(this));
|
|
@@ -21635,7 +22257,19 @@ var init_core = __esm({
|
|
|
21635
22257
|
this.sessionManager.patchRecord(session.id, {
|
|
21636
22258
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21637
22259
|
});
|
|
21638
|
-
|
|
22260
|
+
let text6 = message.text;
|
|
22261
|
+
if (this.assistantManager?.isAssistant(session.id)) {
|
|
22262
|
+
const pending = this.assistantManager.consumePendingSystemPrompt(message.channelId);
|
|
22263
|
+
if (pending) {
|
|
22264
|
+
text6 = `${pending}
|
|
22265
|
+
|
|
22266
|
+
---
|
|
22267
|
+
|
|
22268
|
+
User message:
|
|
22269
|
+
${text6}`;
|
|
22270
|
+
}
|
|
22271
|
+
}
|
|
22272
|
+
await session.enqueuePrompt(text6, message.attachments);
|
|
21639
22273
|
}
|
|
21640
22274
|
// --- Unified Session Creation Pipeline ---
|
|
21641
22275
|
async createSession(params) {
|
|
@@ -22775,79 +23409,6 @@ var init_commands4 = __esm({
|
|
|
22775
23409
|
}
|
|
22776
23410
|
});
|
|
22777
23411
|
|
|
22778
|
-
// src/core/instance/instance-registry.ts
|
|
22779
|
-
var instance_registry_exports = {};
|
|
22780
|
-
__export(instance_registry_exports, {
|
|
22781
|
-
InstanceRegistry: () => InstanceRegistry
|
|
22782
|
-
});
|
|
22783
|
-
import fs42 from "fs";
|
|
22784
|
-
import path46 from "path";
|
|
22785
|
-
var InstanceRegistry;
|
|
22786
|
-
var init_instance_registry = __esm({
|
|
22787
|
-
"src/core/instance/instance-registry.ts"() {
|
|
22788
|
-
"use strict";
|
|
22789
|
-
InstanceRegistry = class {
|
|
22790
|
-
constructor(registryPath) {
|
|
22791
|
-
this.registryPath = registryPath;
|
|
22792
|
-
}
|
|
22793
|
-
data = { version: 1, instances: {} };
|
|
22794
|
-
load() {
|
|
22795
|
-
try {
|
|
22796
|
-
const raw = fs42.readFileSync(this.registryPath, "utf-8");
|
|
22797
|
-
const parsed = JSON.parse(raw);
|
|
22798
|
-
if (parsed.version === 1 && parsed.instances) {
|
|
22799
|
-
this.data = parsed;
|
|
22800
|
-
this.deduplicate();
|
|
22801
|
-
}
|
|
22802
|
-
} catch {
|
|
22803
|
-
}
|
|
22804
|
-
}
|
|
22805
|
-
/** Remove duplicate entries that point to the same root, keeping the first one */
|
|
22806
|
-
deduplicate() {
|
|
22807
|
-
const seen = /* @__PURE__ */ new Set();
|
|
22808
|
-
const toRemove = [];
|
|
22809
|
-
for (const [id, entry] of Object.entries(this.data.instances)) {
|
|
22810
|
-
if (seen.has(entry.root)) {
|
|
22811
|
-
toRemove.push(id);
|
|
22812
|
-
} else {
|
|
22813
|
-
seen.add(entry.root);
|
|
22814
|
-
}
|
|
22815
|
-
}
|
|
22816
|
-
if (toRemove.length > 0) {
|
|
22817
|
-
for (const id of toRemove) delete this.data.instances[id];
|
|
22818
|
-
this.save();
|
|
22819
|
-
}
|
|
22820
|
-
}
|
|
22821
|
-
save() {
|
|
22822
|
-
const dir = path46.dirname(this.registryPath);
|
|
22823
|
-
fs42.mkdirSync(dir, { recursive: true });
|
|
22824
|
-
fs42.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
|
|
22825
|
-
}
|
|
22826
|
-
register(id, root) {
|
|
22827
|
-
this.data.instances[id] = { id, root };
|
|
22828
|
-
}
|
|
22829
|
-
remove(id) {
|
|
22830
|
-
delete this.data.instances[id];
|
|
22831
|
-
}
|
|
22832
|
-
get(id) {
|
|
22833
|
-
return this.data.instances[id];
|
|
22834
|
-
}
|
|
22835
|
-
getByRoot(root) {
|
|
22836
|
-
return Object.values(this.data.instances).find((e) => e.root === root);
|
|
22837
|
-
}
|
|
22838
|
-
list() {
|
|
22839
|
-
return Object.values(this.data.instances);
|
|
22840
|
-
}
|
|
22841
|
-
uniqueId(baseId) {
|
|
22842
|
-
if (!this.data.instances[baseId]) return baseId;
|
|
22843
|
-
let n = 2;
|
|
22844
|
-
while (this.data.instances[`${baseId}-${n}`]) n++;
|
|
22845
|
-
return `${baseId}-${n}`;
|
|
22846
|
-
}
|
|
22847
|
-
};
|
|
22848
|
-
}
|
|
22849
|
-
});
|
|
22850
|
-
|
|
22851
23412
|
// src/core/setup/types.ts
|
|
22852
23413
|
var ONBOARD_SECTION_OPTIONS, CHANNEL_META;
|
|
22853
23414
|
var init_types = __esm({
|
|
@@ -23701,6 +24262,7 @@ import * as path51 from "path";
|
|
|
23701
24262
|
import * as fs46 from "fs";
|
|
23702
24263
|
import * as os24 from "os";
|
|
23703
24264
|
import * as clack8 from "@clack/prompts";
|
|
24265
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
23704
24266
|
async function fetchCommunityAdapters() {
|
|
23705
24267
|
try {
|
|
23706
24268
|
const client = new RegistryClient();
|
|
@@ -24069,7 +24631,7 @@ async function runSetup(configManager, opts) {
|
|
|
24069
24631
|
}
|
|
24070
24632
|
const existingEntry = instanceRegistry.getByRoot(instanceRoot);
|
|
24071
24633
|
if (!existingEntry) {
|
|
24072
|
-
const id =
|
|
24634
|
+
const id = randomUUID2();
|
|
24073
24635
|
instanceRegistry.register(id, instanceRoot);
|
|
24074
24636
|
await instanceRegistry.save();
|
|
24075
24637
|
}
|
|
@@ -24408,13 +24970,17 @@ __export(main_exports, {
|
|
|
24408
24970
|
startServer: () => startServer
|
|
24409
24971
|
});
|
|
24410
24972
|
import path53 from "path";
|
|
24973
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
24411
24974
|
import fs48 from "fs";
|
|
24412
24975
|
async function startServer(opts) {
|
|
24413
|
-
const
|
|
24414
|
-
|
|
24415
|
-
|
|
24416
|
-
|
|
24417
|
-
|
|
24976
|
+
const globalRoot = getGlobalRoot();
|
|
24977
|
+
if (!opts?.instanceContext) {
|
|
24978
|
+
const reg = new InstanceRegistry(path53.join(globalRoot, "instances.json"));
|
|
24979
|
+
reg.load();
|
|
24980
|
+
const entry = reg.getByRoot(globalRoot);
|
|
24981
|
+
opts = { ...opts, instanceContext: createInstanceContext({ id: entry?.id ?? randomUUID3(), root: globalRoot, isGlobal: true }) };
|
|
24982
|
+
}
|
|
24983
|
+
const ctx = opts.instanceContext;
|
|
24418
24984
|
if (process.argv.includes("--daemon-child")) {
|
|
24419
24985
|
const { writePidFile: writePidFile2, readPidFile: readPidFile2, shouldAutoStart: shouldAutoStart2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
24420
24986
|
console.error(`[startup] Daemon child starting (pid=${process.pid}, root=${ctx.root}, env.OPENACP_INSTANCE_ROOT=${process.env.OPENACP_INSTANCE_ROOT ?? "unset"})`);
|
|
@@ -24689,8 +25255,8 @@ async function startServer(opts) {
|
|
|
24689
25255
|
});
|
|
24690
25256
|
await core.start();
|
|
24691
25257
|
try {
|
|
24692
|
-
const
|
|
24693
|
-
const registryPath = path53.join(
|
|
25258
|
+
const globalRoot2 = getGlobalRoot();
|
|
25259
|
+
const registryPath = path53.join(globalRoot2, "instances.json");
|
|
24694
25260
|
const instanceReg = new InstanceRegistry(registryPath);
|
|
24695
25261
|
await instanceReg.load();
|
|
24696
25262
|
if (!instanceReg.getByRoot(ctx.root)) {
|
|
@@ -24855,9 +25421,12 @@ __export(restart_exports, {
|
|
|
24855
25421
|
});
|
|
24856
25422
|
import path54 from "path";
|
|
24857
25423
|
import os25 from "os";
|
|
25424
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
24858
25425
|
async function cmdRestart(args2 = [], instanceRoot) {
|
|
25426
|
+
const json = isJsonMode(args2);
|
|
25427
|
+
if (json) await muteForJson();
|
|
24859
25428
|
const root = instanceRoot ?? path54.join(os25.homedir(), ".openacp");
|
|
24860
|
-
if (wantsHelp(args2)) {
|
|
25429
|
+
if (!json && wantsHelp(args2)) {
|
|
24861
25430
|
console.log(`
|
|
24862
25431
|
\x1B[1mopenacp restart\x1B[0m \u2014 Restart the background daemon
|
|
24863
25432
|
|
|
@@ -24868,6 +25437,10 @@ async function cmdRestart(args2 = [], instanceRoot) {
|
|
|
24868
25437
|
|
|
24869
25438
|
Stops the running daemon (if any) and starts a new one.
|
|
24870
25439
|
|
|
25440
|
+
\x1B[1mOptions:\x1B[0m
|
|
25441
|
+
--json Output result as JSON
|
|
25442
|
+
-h, --help Show this help message
|
|
25443
|
+
|
|
24871
25444
|
\x1B[1mSee also:\x1B[0m
|
|
24872
25445
|
openacp start Start the daemon
|
|
24873
25446
|
openacp stop Stop the daemon
|
|
@@ -24888,19 +25461,23 @@ Stops the running daemon (if any) and starts a new one.
|
|
|
24888
25461
|
}
|
|
24889
25462
|
const cm = new ConfigManager2();
|
|
24890
25463
|
if (!await cm.exists()) {
|
|
25464
|
+
if (json) jsonError(ErrorCodes.CONFIG_NOT_FOUND, 'No config found. Run "openacp" first to set up.');
|
|
24891
25465
|
console.error('No config found. Run "openacp" first to set up.');
|
|
24892
25466
|
process.exit(1);
|
|
24893
25467
|
}
|
|
24894
25468
|
await cm.load();
|
|
24895
25469
|
const config = cm.get();
|
|
24896
|
-
const useForeground = forceForeground || !forceDaemon && config.runMode !== "daemon";
|
|
25470
|
+
const useForeground = json ? false : forceForeground || !forceDaemon && config.runMode !== "daemon";
|
|
24897
25471
|
if (useForeground) {
|
|
24898
25472
|
markRunning2(root);
|
|
24899
25473
|
printInstanceHint(root);
|
|
24900
25474
|
console.log("Starting in foreground mode...");
|
|
24901
25475
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
25476
|
+
const reg = new InstanceRegistry(path54.join(getGlobalRoot(), "instances.json"));
|
|
25477
|
+
reg.load();
|
|
25478
|
+
const existingEntry = reg.getByRoot(root);
|
|
24902
25479
|
const ctx = createInstanceContext({
|
|
24903
|
-
id:
|
|
25480
|
+
id: existingEntry?.id ?? randomUUID4(),
|
|
24904
25481
|
root,
|
|
24905
25482
|
isGlobal: root === getGlobalRoot()
|
|
24906
25483
|
});
|
|
@@ -24908,9 +25485,11 @@ Stops the running daemon (if any) and starts a new one.
|
|
|
24908
25485
|
} else {
|
|
24909
25486
|
const result = startDaemon2(pidPath, config.logging.logDir, root);
|
|
24910
25487
|
if ("error" in result) {
|
|
25488
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, result.error);
|
|
24911
25489
|
console.error(result.error);
|
|
24912
25490
|
process.exit(1);
|
|
24913
25491
|
}
|
|
25492
|
+
if (json) jsonSuccess({ pid: result.pid, instanceId: path54.basename(root), dir: root });
|
|
24914
25493
|
printInstanceHint(root);
|
|
24915
25494
|
console.log(`OpenACP daemon started (PID ${result.pid})`);
|
|
24916
25495
|
}
|
|
@@ -24919,8 +25498,10 @@ var init_restart = __esm({
|
|
|
24919
25498
|
"src/cli/commands/restart.ts"() {
|
|
24920
25499
|
"use strict";
|
|
24921
25500
|
init_helpers();
|
|
25501
|
+
init_output();
|
|
24922
25502
|
init_instance_hint();
|
|
24923
25503
|
init_instance_context();
|
|
25504
|
+
init_instance_registry();
|
|
24924
25505
|
}
|
|
24925
25506
|
});
|
|
24926
25507
|
|
|
@@ -24935,23 +25516,43 @@ import fs49 from "fs";
|
|
|
24935
25516
|
import path55 from "path";
|
|
24936
25517
|
import os26 from "os";
|
|
24937
25518
|
async function cmdStatus(args2 = [], instanceRoot) {
|
|
25519
|
+
const json = isJsonMode(args2);
|
|
25520
|
+
if (json) await muteForJson();
|
|
24938
25521
|
if (args2.includes("--all")) {
|
|
24939
|
-
await showAllInstances();
|
|
25522
|
+
await showAllInstances(json);
|
|
24940
25523
|
return;
|
|
24941
25524
|
}
|
|
24942
25525
|
const idIdx = args2.indexOf("--id");
|
|
24943
25526
|
if (idIdx !== -1 && args2[idIdx + 1]) {
|
|
24944
|
-
await showInstanceById(args2[idIdx + 1]);
|
|
25527
|
+
await showInstanceById(args2[idIdx + 1], json);
|
|
24945
25528
|
return;
|
|
24946
25529
|
}
|
|
24947
25530
|
const root = instanceRoot ?? getGlobalRoot();
|
|
24948
|
-
await showSingleInstance(root);
|
|
25531
|
+
await showSingleInstance(root, json);
|
|
24949
25532
|
}
|
|
24950
|
-
async function showAllInstances() {
|
|
25533
|
+
async function showAllInstances(json = false) {
|
|
24951
25534
|
const registryPath = path55.join(getGlobalRoot(), "instances.json");
|
|
24952
25535
|
const registry = new InstanceRegistry(registryPath);
|
|
24953
25536
|
await registry.load();
|
|
24954
25537
|
const instances = registry.list();
|
|
25538
|
+
if (json) {
|
|
25539
|
+
jsonSuccess({
|
|
25540
|
+
instances: instances.map((entry) => {
|
|
25541
|
+
const info = readInstanceInfo(entry.root);
|
|
25542
|
+
return {
|
|
25543
|
+
id: entry.id,
|
|
25544
|
+
name: info.name,
|
|
25545
|
+
status: info.pid ? "online" : "offline",
|
|
25546
|
+
pid: info.pid,
|
|
25547
|
+
dir: entry.root,
|
|
25548
|
+
mode: info.runMode,
|
|
25549
|
+
channels: info.channels,
|
|
25550
|
+
apiPort: info.apiPort,
|
|
25551
|
+
tunnelPort: info.tunnelPort
|
|
25552
|
+
};
|
|
25553
|
+
})
|
|
25554
|
+
});
|
|
25555
|
+
}
|
|
24955
25556
|
if (instances.length === 0) {
|
|
24956
25557
|
console.log("No workspaces registered.");
|
|
24957
25558
|
return;
|
|
@@ -24972,19 +25573,33 @@ async function showAllInstances() {
|
|
|
24972
25573
|
}
|
|
24973
25574
|
console.log("");
|
|
24974
25575
|
}
|
|
24975
|
-
async function showInstanceById(id) {
|
|
25576
|
+
async function showInstanceById(id, json = false) {
|
|
24976
25577
|
const registryPath = path55.join(getGlobalRoot(), "instances.json");
|
|
24977
25578
|
const registry = new InstanceRegistry(registryPath);
|
|
24978
25579
|
await registry.load();
|
|
24979
25580
|
const entry = registry.get(id);
|
|
24980
25581
|
if (!entry) {
|
|
25582
|
+
if (json) jsonError(ErrorCodes.INSTANCE_NOT_FOUND, `Workspace "${id}" not found.`);
|
|
24981
25583
|
console.error(`Workspace "${id}" not found.`);
|
|
24982
25584
|
process.exit(1);
|
|
24983
25585
|
}
|
|
24984
|
-
await showSingleInstance(entry.root);
|
|
25586
|
+
await showSingleInstance(entry.root, json);
|
|
24985
25587
|
}
|
|
24986
|
-
async function showSingleInstance(root) {
|
|
25588
|
+
async function showSingleInstance(root, json = false) {
|
|
24987
25589
|
const info = readInstanceInfo(root);
|
|
25590
|
+
if (json) {
|
|
25591
|
+
jsonSuccess({
|
|
25592
|
+
id: path55.basename(root),
|
|
25593
|
+
name: info.name,
|
|
25594
|
+
status: info.pid ? "online" : "offline",
|
|
25595
|
+
pid: info.pid,
|
|
25596
|
+
dir: root,
|
|
25597
|
+
mode: info.runMode,
|
|
25598
|
+
channels: info.channels,
|
|
25599
|
+
apiPort: info.apiPort,
|
|
25600
|
+
tunnelPort: info.tunnelPort
|
|
25601
|
+
});
|
|
25602
|
+
}
|
|
24988
25603
|
if (info.pid) {
|
|
24989
25604
|
console.log(`OpenACP is running (PID ${info.pid})`);
|
|
24990
25605
|
if (info.name) console.log(` Name: ${info.name}`);
|
|
@@ -25062,6 +25677,7 @@ var init_status = __esm({
|
|
|
25062
25677
|
"use strict";
|
|
25063
25678
|
init_instance_registry();
|
|
25064
25679
|
init_instance_context();
|
|
25680
|
+
init_output();
|
|
25065
25681
|
}
|
|
25066
25682
|
});
|
|
25067
25683
|
|
|
@@ -25936,21 +26552,21 @@ Connect messaging platforms (Telegram, Discord) to 28+ AI coding agents via ACP
|
|
|
25936
26552
|
|
|
25937
26553
|
\x1B[1mServer:\x1B[0m
|
|
25938
26554
|
openacp Start (mode from config)
|
|
25939
|
-
openacp start Start as background daemon
|
|
25940
|
-
openacp stop Stop background daemon
|
|
25941
|
-
openacp restart Restart (same mode)
|
|
26555
|
+
openacp start Start as background daemon \x1B[2m[--json]\x1B[0m
|
|
26556
|
+
openacp stop Stop background daemon \x1B[2m[--json]\x1B[0m
|
|
26557
|
+
openacp restart Restart (same mode) \x1B[2m[--json]\x1B[0m
|
|
25942
26558
|
openacp restart --foreground Restart in foreground mode
|
|
25943
26559
|
openacp restart --daemon Restart as background daemon
|
|
25944
26560
|
openacp attach Attach to running daemon
|
|
25945
|
-
openacp status Show daemon status
|
|
26561
|
+
openacp status Show daemon status \x1B[2m[--json]\x1B[0m
|
|
25946
26562
|
openacp logs Tail daemon log file
|
|
25947
26563
|
openacp --foreground Force foreground mode
|
|
25948
26564
|
|
|
25949
26565
|
\x1B[1mAgent Management:\x1B[0m
|
|
25950
|
-
openacp agents Browse all agents (installed + available)
|
|
25951
|
-
openacp agents install <name> Install an agent from the ACP Registry
|
|
25952
|
-
openacp agents uninstall <name> Remove an installed agent
|
|
25953
|
-
openacp agents info <name> Show details, dependencies & setup guide
|
|
26566
|
+
openacp agents Browse all agents (installed + available) \x1B[2m[--json]\x1B[0m
|
|
26567
|
+
openacp agents install <name> Install an agent from the ACP Registry \x1B[2m[--json]\x1B[0m
|
|
26568
|
+
openacp agents uninstall <name> Remove an installed agent \x1B[2m[--json]\x1B[0m
|
|
26569
|
+
openacp agents info <name> Show details, dependencies & setup guide \x1B[2m[--json]\x1B[0m
|
|
25954
26570
|
openacp agents run <name> [-- args] Run agent CLI directly (login, config...)
|
|
25955
26571
|
openacp agents refresh Force-refresh agent list from registry
|
|
25956
26572
|
|
|
@@ -25961,17 +26577,17 @@ Connect messaging platforms (Telegram, Discord) to 28+ AI coding agents via ACP
|
|
|
25961
26577
|
|
|
25962
26578
|
\x1B[1mConfiguration:\x1B[0m
|
|
25963
26579
|
openacp config Interactive config editor
|
|
25964
|
-
openacp config set <key> <value> Set a config value
|
|
26580
|
+
openacp config set <key> <value> Set a config value \x1B[2m[--json]\x1B[0m
|
|
25965
26581
|
openacp onboard Re-run onboarding setup wizard
|
|
25966
26582
|
openacp reset Re-run setup wizard
|
|
25967
26583
|
openacp update Update to latest version
|
|
25968
|
-
openacp doctor Run system diagnostics
|
|
26584
|
+
openacp doctor Run system diagnostics \x1B[2m[--json]\x1B[0m
|
|
25969
26585
|
openacp doctor --dry-run Check only, don't fix
|
|
25970
26586
|
|
|
25971
26587
|
\x1B[1mPlugins:\x1B[0m
|
|
25972
|
-
openacp install <package> Install adapter plugin
|
|
25973
|
-
openacp uninstall <package> Remove adapter
|
|
25974
|
-
openacp plugins List installed plugins
|
|
26588
|
+
openacp install <package> Install adapter plugin \x1B[2m[--json]\x1B[0m
|
|
26589
|
+
openacp uninstall <package> Remove adapter \x1B[2m[--json]\x1B[0m
|
|
26590
|
+
openacp plugins List installed plugins \x1B[2m[--json]\x1B[0m
|
|
25975
26591
|
openacp plugin create Scaffold a new plugin project
|
|
25976
26592
|
|
|
25977
26593
|
\x1B[1mDevelopment:\x1B[0m
|
|
@@ -25982,25 +26598,25 @@ Connect messaging platforms (Telegram, Discord) to 28+ AI coding agents via ACP
|
|
|
25982
26598
|
\x1B[1mSession Transfer:\x1B[0m
|
|
25983
26599
|
openacp integrate <agent> Install handoff integration
|
|
25984
26600
|
openacp integrate <agent> --uninstall
|
|
25985
|
-
openacp adopt <agent> <id> Adopt an external session
|
|
26601
|
+
openacp adopt <agent> <id> Adopt an external session \x1B[2m[--json]\x1B[0m
|
|
25986
26602
|
|
|
25987
26603
|
\x1B[1mTunnels:\x1B[0m
|
|
25988
|
-
openacp tunnel add <port> [--label name] Create tunnel to local port
|
|
25989
|
-
openacp tunnel list List active tunnels
|
|
25990
|
-
openacp tunnel stop <port> Stop a tunnel
|
|
25991
|
-
openacp tunnel stop-all Stop all user tunnels
|
|
26604
|
+
openacp tunnel add <port> [--label name] Create tunnel to local port \x1B[2m[--json]\x1B[0m
|
|
26605
|
+
openacp tunnel list List active tunnels \x1B[2m[--json]\x1B[0m
|
|
26606
|
+
openacp tunnel stop <port> Stop a tunnel \x1B[2m[--json]\x1B[0m
|
|
26607
|
+
openacp tunnel stop-all Stop all user tunnels \x1B[2m[--json]\x1B[0m
|
|
25992
26608
|
|
|
25993
26609
|
\x1B[1mDaemon API:\x1B[0m \x1B[2m(requires running daemon)\x1B[0m
|
|
25994
|
-
openacp api status Active sessions
|
|
25995
|
-
openacp api session <id> Session details
|
|
25996
|
-
openacp api new [agent] [workspace] Create session
|
|
25997
|
-
openacp api send <id> <prompt> Send prompt
|
|
25998
|
-
openacp api cancel <id> Cancel session
|
|
25999
|
-
openacp api bypass <id> on|off Toggle bypass permissions
|
|
26000
|
-
openacp api topics [--status ...] List topics
|
|
26001
|
-
openacp api cleanup [--status ...] Cleanup old topics
|
|
26002
|
-
openacp api health System health check
|
|
26003
|
-
openacp api restart Restart daemon
|
|
26610
|
+
openacp api status Active sessions \x1B[2m[--json]\x1B[0m
|
|
26611
|
+
openacp api session <id> Session details \x1B[2m[--json]\x1B[0m
|
|
26612
|
+
openacp api new [agent] [workspace] Create session \x1B[2m[--json]\x1B[0m
|
|
26613
|
+
openacp api send <id> <prompt> Send prompt \x1B[2m[--json]\x1B[0m
|
|
26614
|
+
openacp api cancel <id> Cancel session \x1B[2m[--json]\x1B[0m
|
|
26615
|
+
openacp api bypass <id> on|off Toggle bypass permissions \x1B[2m[--json]\x1B[0m
|
|
26616
|
+
openacp api topics [--status ...] List topics \x1B[2m[--json]\x1B[0m
|
|
26617
|
+
openacp api cleanup [--status ...] Cleanup old topics \x1B[2m[--json]\x1B[0m
|
|
26618
|
+
openacp api health System health check \x1B[2m[--json]\x1B[0m
|
|
26619
|
+
openacp api restart Restart daemon \x1B[2m[--json]\x1B[0m
|
|
26004
26620
|
|
|
26005
26621
|
\x1B[1mWorkspace Flags:\x1B[0m
|
|
26006
26622
|
--local Use workspace in current directory
|
|
@@ -26009,26 +26625,42 @@ Connect messaging platforms (Telegram, Discord) to 28+ AI coding agents via ACP
|
|
|
26009
26625
|
--from <path> Copy settings from existing workspace (on create)
|
|
26010
26626
|
--name <name> Set workspace name (on create)
|
|
26011
26627
|
|
|
26628
|
+
\x1B[1mOutput Flags:\x1B[0m
|
|
26629
|
+
--json Output result as JSON (single-line, stdout)
|
|
26630
|
+
Commands marked \x1B[2m[--json]\x1B[0m support machine-readable output.
|
|
26631
|
+
Success: { "success": true, "data": { ... } }
|
|
26632
|
+
Error: { "success": false, "error": { "code": "...", "message": "..." } }
|
|
26633
|
+
|
|
26012
26634
|
\x1B[2mMore info: https://github.com/Open-ACP/OpenACP\x1B[0m
|
|
26013
26635
|
`);
|
|
26014
26636
|
}
|
|
26015
26637
|
|
|
26016
26638
|
// src/cli/commands/version.ts
|
|
26017
|
-
|
|
26639
|
+
init_output();
|
|
26640
|
+
async function cmdVersion(args2 = []) {
|
|
26641
|
+
const json = isJsonMode(args2);
|
|
26642
|
+
if (json) await muteForJson();
|
|
26018
26643
|
const { getCurrentVersion: getCurrentVersion2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
26019
|
-
|
|
26644
|
+
const version = getCurrentVersion2();
|
|
26645
|
+
if (json) {
|
|
26646
|
+
jsonSuccess({ version });
|
|
26647
|
+
}
|
|
26648
|
+
console.log(`openacp v${version}`);
|
|
26020
26649
|
}
|
|
26021
26650
|
|
|
26022
26651
|
// src/cli/commands/install.ts
|
|
26023
26652
|
init_helpers();
|
|
26653
|
+
init_output();
|
|
26024
26654
|
import { execSync } from "child_process";
|
|
26025
|
-
import * as
|
|
26026
|
-
import * as
|
|
26027
|
-
import * as
|
|
26655
|
+
import * as fs2 from "fs";
|
|
26656
|
+
import * as path2 from "path";
|
|
26657
|
+
import * as os2 from "os";
|
|
26028
26658
|
async function cmdInstall(args2, instanceRoot) {
|
|
26029
|
-
const
|
|
26030
|
-
|
|
26031
|
-
|
|
26659
|
+
const json = isJsonMode(args2);
|
|
26660
|
+
if (json) await muteForJson();
|
|
26661
|
+
const root = instanceRoot ?? path2.join(os2.homedir(), ".openacp");
|
|
26662
|
+
const pluginsDir = path2.join(root, "plugins");
|
|
26663
|
+
if (!json && wantsHelp(args2)) {
|
|
26032
26664
|
console.log(`
|
|
26033
26665
|
\x1B[1mopenacp install\x1B[0m \u2014 Install a plugin adapter
|
|
26034
26666
|
|
|
@@ -26040,36 +26672,50 @@ async function cmdInstall(args2, instanceRoot) {
|
|
|
26040
26672
|
|
|
26041
26673
|
Installs the plugin to ~/.openacp/plugins/.
|
|
26042
26674
|
|
|
26675
|
+
\x1B[1mOptions:\x1B[0m
|
|
26676
|
+
--json Output result as JSON
|
|
26677
|
+
-h, --help Show this help message
|
|
26678
|
+
|
|
26043
26679
|
\x1B[1mExamples:\x1B[0m
|
|
26044
26680
|
openacp install @openacp/adapter-discord
|
|
26045
26681
|
`);
|
|
26046
26682
|
return;
|
|
26047
26683
|
}
|
|
26048
|
-
const pkg = args2[0];
|
|
26684
|
+
const pkg = args2.filter((a) => a !== "--json")[0];
|
|
26049
26685
|
if (!pkg) {
|
|
26686
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Package name is required");
|
|
26050
26687
|
console.error("Usage: openacp install <package>");
|
|
26051
26688
|
process.exit(1);
|
|
26052
26689
|
}
|
|
26053
|
-
|
|
26054
|
-
const pkgPath =
|
|
26055
|
-
if (!
|
|
26056
|
-
|
|
26690
|
+
fs2.mkdirSync(pluginsDir, { recursive: true });
|
|
26691
|
+
const pkgPath = path2.join(pluginsDir, "package.json");
|
|
26692
|
+
if (!fs2.existsSync(pkgPath)) {
|
|
26693
|
+
fs2.writeFileSync(pkgPath, JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2));
|
|
26694
|
+
}
|
|
26695
|
+
if (!json) console.log(`Installing ${pkg}...`);
|
|
26696
|
+
try {
|
|
26697
|
+
execSync(`npm install ${pkg} --prefix "${pluginsDir}"`, { stdio: json ? "pipe" : "inherit" });
|
|
26698
|
+
} catch (err) {
|
|
26699
|
+
if (json) jsonError(ErrorCodes.INSTALL_FAILED, `Failed to install ${pkg}`);
|
|
26700
|
+
process.exit(1);
|
|
26057
26701
|
}
|
|
26058
|
-
|
|
26059
|
-
execSync(`npm install ${pkg} --prefix "${pluginsDir}"`, { stdio: "inherit" });
|
|
26702
|
+
if (json) jsonSuccess({ plugin: pkg, installed: true });
|
|
26060
26703
|
console.log(`Plugin ${pkg} installed successfully.`);
|
|
26061
26704
|
}
|
|
26062
26705
|
|
|
26063
26706
|
// src/cli/commands/uninstall.ts
|
|
26064
26707
|
init_helpers();
|
|
26708
|
+
init_output();
|
|
26065
26709
|
import { execSync as execSync2 } from "child_process";
|
|
26066
|
-
import * as
|
|
26067
|
-
import * as
|
|
26068
|
-
import * as
|
|
26710
|
+
import * as fs3 from "fs";
|
|
26711
|
+
import * as path3 from "path";
|
|
26712
|
+
import * as os3 from "os";
|
|
26069
26713
|
async function cmdUninstall(args2, instanceRoot) {
|
|
26070
|
-
const
|
|
26071
|
-
|
|
26072
|
-
|
|
26714
|
+
const json = isJsonMode(args2);
|
|
26715
|
+
if (json) await muteForJson();
|
|
26716
|
+
const root = instanceRoot ?? path3.join(os3.homedir(), ".openacp");
|
|
26717
|
+
const pluginsDir = path3.join(root, "plugins");
|
|
26718
|
+
if (!json && wantsHelp(args2)) {
|
|
26073
26719
|
console.log(`
|
|
26074
26720
|
\x1B[1mopenacp uninstall\x1B[0m \u2014 Remove a plugin adapter
|
|
26075
26721
|
|
|
@@ -26079,36 +26725,54 @@ async function cmdUninstall(args2, instanceRoot) {
|
|
|
26079
26725
|
\x1B[1mArguments:\x1B[0m
|
|
26080
26726
|
<package> npm package name to remove
|
|
26081
26727
|
|
|
26728
|
+
\x1B[1mOptions:\x1B[0m
|
|
26729
|
+
--json Output result as JSON
|
|
26730
|
+
-h, --help Show this help message
|
|
26731
|
+
|
|
26082
26732
|
\x1B[1mExamples:\x1B[0m
|
|
26083
26733
|
openacp uninstall @openacp/adapter-discord
|
|
26084
26734
|
`);
|
|
26085
26735
|
return;
|
|
26086
26736
|
}
|
|
26087
|
-
const pkg = args2[0];
|
|
26737
|
+
const pkg = args2.filter((a) => a !== "--json")[0];
|
|
26088
26738
|
if (!pkg) {
|
|
26739
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Package name is required");
|
|
26089
26740
|
console.error("Usage: openacp uninstall <package>");
|
|
26090
26741
|
process.exit(1);
|
|
26091
26742
|
}
|
|
26092
|
-
|
|
26093
|
-
const pkgPath =
|
|
26094
|
-
if (!
|
|
26095
|
-
|
|
26743
|
+
fs3.mkdirSync(pluginsDir, { recursive: true });
|
|
26744
|
+
const pkgPath = path3.join(pluginsDir, "package.json");
|
|
26745
|
+
if (!fs3.existsSync(pkgPath)) {
|
|
26746
|
+
fs3.writeFileSync(pkgPath, JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2));
|
|
26096
26747
|
}
|
|
26097
|
-
console.log(`Uninstalling ${pkg}...`);
|
|
26098
|
-
|
|
26748
|
+
if (!json) console.log(`Uninstalling ${pkg}...`);
|
|
26749
|
+
try {
|
|
26750
|
+
execSync2(`npm uninstall ${pkg} --prefix "${pluginsDir}"`, { stdio: json ? "pipe" : "inherit" });
|
|
26751
|
+
} catch (err) {
|
|
26752
|
+
if (json) jsonError(ErrorCodes.UNINSTALL_FAILED, `Failed to uninstall ${pkg}`);
|
|
26753
|
+
process.exit(1);
|
|
26754
|
+
}
|
|
26755
|
+
if (json) jsonSuccess({ plugin: pkg, uninstalled: true });
|
|
26099
26756
|
console.log(`Plugin ${pkg} uninstalled.`);
|
|
26100
26757
|
}
|
|
26101
26758
|
|
|
26102
26759
|
// src/cli/commands/plugins.ts
|
|
26103
26760
|
init_helpers();
|
|
26761
|
+
init_output();
|
|
26104
26762
|
async function cmdPlugins(args2 = [], instanceRoot) {
|
|
26105
|
-
|
|
26763
|
+
const json = isJsonMode(args2);
|
|
26764
|
+
if (json) await muteForJson();
|
|
26765
|
+
if (!json && wantsHelp(args2)) {
|
|
26106
26766
|
console.log(`
|
|
26107
26767
|
\x1B[1mopenacp plugins\x1B[0m \u2014 List installed plugins
|
|
26108
26768
|
|
|
26109
26769
|
\x1B[1mUsage:\x1B[0m
|
|
26110
26770
|
openacp plugins
|
|
26111
26771
|
|
|
26772
|
+
\x1B[1mOptions:\x1B[0m
|
|
26773
|
+
--json Output result as JSON
|
|
26774
|
+
-h, --help Show this help message
|
|
26775
|
+
|
|
26112
26776
|
Shows all plugins registered in the plugin registry.
|
|
26113
26777
|
`);
|
|
26114
26778
|
return;
|
|
@@ -26121,6 +26785,19 @@ Shows all plugins registered in the plugin registry.
|
|
|
26121
26785
|
const registry = new PluginRegistry2(registryPath);
|
|
26122
26786
|
await registry.load();
|
|
26123
26787
|
const plugins = registry.list();
|
|
26788
|
+
if (json) {
|
|
26789
|
+
const pluginList = [];
|
|
26790
|
+
for (const [name, entry] of plugins) {
|
|
26791
|
+
pluginList.push({
|
|
26792
|
+
name,
|
|
26793
|
+
version: entry.version,
|
|
26794
|
+
enabled: entry.enabled !== false,
|
|
26795
|
+
source: entry.source ?? "unknown",
|
|
26796
|
+
description: entry.description ?? ""
|
|
26797
|
+
});
|
|
26798
|
+
}
|
|
26799
|
+
jsonSuccess({ plugins: pluginList });
|
|
26800
|
+
}
|
|
26124
26801
|
if (plugins.size === 0) {
|
|
26125
26802
|
console.log("No plugins installed.");
|
|
26126
26803
|
} else {
|
|
@@ -26150,6 +26827,10 @@ async function cmdPlugin(args2 = [], instanceRoot) {
|
|
|
26150
26827
|
openacp plugin configure <name> Run interactive configuration
|
|
26151
26828
|
openacp plugin create Scaffold a new plugin project
|
|
26152
26829
|
|
|
26830
|
+
\x1B[1mOptions:\x1B[0m
|
|
26831
|
+
--json Output result as JSON
|
|
26832
|
+
-h, --help Show this help message
|
|
26833
|
+
|
|
26153
26834
|
\x1B[1mExamples:\x1B[0m
|
|
26154
26835
|
openacp plugin list
|
|
26155
26836
|
openacp plugin search telegram
|
|
@@ -26164,7 +26845,7 @@ async function cmdPlugin(args2 = [], instanceRoot) {
|
|
|
26164
26845
|
}
|
|
26165
26846
|
switch (subcommand) {
|
|
26166
26847
|
case "list":
|
|
26167
|
-
return cmdPlugins([], instanceRoot);
|
|
26848
|
+
return cmdPlugins(isJsonMode(args2) ? ["--json"] : [], instanceRoot);
|
|
26168
26849
|
case "search": {
|
|
26169
26850
|
const { cmdPluginSearch: cmdPluginSearch2 } = await Promise.resolve().then(() => (init_plugin_search(), plugin_search_exports));
|
|
26170
26851
|
await cmdPluginSearch2(args2.slice(1));
|
|
@@ -26174,39 +26855,43 @@ async function cmdPlugin(args2 = [], instanceRoot) {
|
|
|
26174
26855
|
case "install": {
|
|
26175
26856
|
const pkg = args2[1];
|
|
26176
26857
|
if (!pkg) {
|
|
26858
|
+
if (isJsonMode(args2)) jsonError(ErrorCodes.MISSING_ARGUMENT, "Package name is required");
|
|
26177
26859
|
console.error("Error: missing package name. Usage: openacp plugin add <package>");
|
|
26178
26860
|
process.exit(1);
|
|
26179
26861
|
}
|
|
26180
|
-
await installPlugin(pkg, instanceRoot);
|
|
26862
|
+
await installPlugin(pkg, instanceRoot, isJsonMode(args2));
|
|
26181
26863
|
return;
|
|
26182
26864
|
}
|
|
26183
26865
|
case "remove":
|
|
26184
26866
|
case "uninstall": {
|
|
26185
26867
|
const pkg = args2[1];
|
|
26186
26868
|
if (!pkg) {
|
|
26869
|
+
if (isJsonMode(args2)) jsonError(ErrorCodes.MISSING_ARGUMENT, "Package name is required");
|
|
26187
26870
|
console.error("Error: missing package name. Usage: openacp plugin remove <package> [--purge]");
|
|
26188
26871
|
process.exit(1);
|
|
26189
26872
|
}
|
|
26190
26873
|
const purge = args2.includes("--purge");
|
|
26191
|
-
await uninstallPlugin(pkg, purge, instanceRoot);
|
|
26874
|
+
await uninstallPlugin(pkg, purge, instanceRoot, isJsonMode(args2));
|
|
26192
26875
|
return;
|
|
26193
26876
|
}
|
|
26194
26877
|
case "enable": {
|
|
26195
26878
|
const name = args2[1];
|
|
26196
26879
|
if (!name) {
|
|
26880
|
+
if (isJsonMode(args2)) jsonError(ErrorCodes.MISSING_ARGUMENT, "Plugin name is required");
|
|
26197
26881
|
console.error("Error: missing plugin name. Usage: openacp plugin enable <name>");
|
|
26198
26882
|
process.exit(1);
|
|
26199
26883
|
}
|
|
26200
|
-
await setPluginEnabled(name, true, instanceRoot);
|
|
26884
|
+
await setPluginEnabled(name, true, instanceRoot, isJsonMode(args2));
|
|
26201
26885
|
return;
|
|
26202
26886
|
}
|
|
26203
26887
|
case "disable": {
|
|
26204
26888
|
const name = args2[1];
|
|
26205
26889
|
if (!name) {
|
|
26890
|
+
if (isJsonMode(args2)) jsonError(ErrorCodes.MISSING_ARGUMENT, "Plugin name is required");
|
|
26206
26891
|
console.error("Error: missing plugin name. Usage: openacp plugin disable <name>");
|
|
26207
26892
|
process.exit(1);
|
|
26208
26893
|
}
|
|
26209
|
-
await setPluginEnabled(name, false, instanceRoot);
|
|
26894
|
+
await setPluginEnabled(name, false, instanceRoot, isJsonMode(args2));
|
|
26210
26895
|
return;
|
|
26211
26896
|
}
|
|
26212
26897
|
case "configure": {
|
|
@@ -26229,7 +26914,8 @@ async function cmdPlugin(args2 = [], instanceRoot) {
|
|
|
26229
26914
|
process.exit(1);
|
|
26230
26915
|
}
|
|
26231
26916
|
}
|
|
26232
|
-
async function setPluginEnabled(name, enabled, instanceRoot) {
|
|
26917
|
+
async function setPluginEnabled(name, enabled, instanceRoot, json = false) {
|
|
26918
|
+
if (json) await muteForJson();
|
|
26233
26919
|
const os31 = await import("os");
|
|
26234
26920
|
const path65 = await import("path");
|
|
26235
26921
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
@@ -26239,11 +26925,13 @@ async function setPluginEnabled(name, enabled, instanceRoot) {
|
|
|
26239
26925
|
await registry.load();
|
|
26240
26926
|
const entry = registry.get(name);
|
|
26241
26927
|
if (!entry) {
|
|
26928
|
+
if (json) jsonError(ErrorCodes.PLUGIN_NOT_FOUND, `Plugin "${name}" not found.`);
|
|
26242
26929
|
console.error(`Plugin "${name}" not found. Run "openacp plugin list" to see installed plugins.`);
|
|
26243
26930
|
process.exit(1);
|
|
26244
26931
|
}
|
|
26245
26932
|
registry.setEnabled(name, enabled);
|
|
26246
26933
|
await registry.save();
|
|
26934
|
+
if (json) jsonSuccess({ plugin: name, enabled });
|
|
26247
26935
|
console.log(`Plugin ${name} ${enabled ? "enabled" : "disabled"}. Restart to apply.`);
|
|
26248
26936
|
}
|
|
26249
26937
|
async function configurePlugin(name, instanceRoot) {
|
|
@@ -26269,7 +26957,8 @@ async function configurePlugin(name, instanceRoot) {
|
|
|
26269
26957
|
console.log(`Plugin ${name} has no configure or install hook.`);
|
|
26270
26958
|
}
|
|
26271
26959
|
}
|
|
26272
|
-
async function installPlugin(input2, instanceRoot) {
|
|
26960
|
+
async function installPlugin(input2, instanceRoot, json = false) {
|
|
26961
|
+
if (json) await muteForJson();
|
|
26273
26962
|
const os31 = await import("os");
|
|
26274
26963
|
const path65 = await import("path");
|
|
26275
26964
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
@@ -26310,16 +26999,16 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26310
26999
|
const registry = await client.getRegistry();
|
|
26311
27000
|
registryPlugin = registry.plugins.find((p2) => p2.name === pkgName || p2.npm === pkgName);
|
|
26312
27001
|
if (registryPlugin) {
|
|
26313
|
-
console.log(`Resolved from registry: ${pkgName} \u2192 ${registryPlugin.npm}`);
|
|
27002
|
+
if (!json) console.log(`Resolved from registry: ${pkgName} \u2192 ${registryPlugin.npm}`);
|
|
26314
27003
|
pkgName = registryPlugin.npm;
|
|
26315
|
-
if (!registryPlugin.verified) {
|
|
27004
|
+
if (!json && !registryPlugin.verified) {
|
|
26316
27005
|
console.log("\u26A0\uFE0F This plugin is not verified by the OpenACP team.");
|
|
26317
27006
|
}
|
|
26318
27007
|
}
|
|
26319
27008
|
} catch {
|
|
26320
27009
|
}
|
|
26321
27010
|
const installSpec = pkgVersion ? `${pkgName}@${pkgVersion}` : pkgName;
|
|
26322
|
-
console.log(`Installing ${installSpec}...`);
|
|
27011
|
+
if (!json) console.log(`Installing ${installSpec}...`);
|
|
26323
27012
|
const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
|
|
26324
27013
|
const builtinPlugin = corePlugins2.find((p2) => p2.name === pkgName);
|
|
26325
27014
|
const basePath = path65.join(root, "plugins", "data");
|
|
@@ -26340,6 +27029,7 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26340
27029
|
description: builtinPlugin.description
|
|
26341
27030
|
});
|
|
26342
27031
|
await pluginRegistry.save();
|
|
27032
|
+
if (json) jsonSuccess({ plugin: builtinPlugin.name, version: builtinPlugin.version, installed: true });
|
|
26343
27033
|
console.log(`\u2713 ${builtinPlugin.name} installed! Restart to activate.`);
|
|
26344
27034
|
return;
|
|
26345
27035
|
}
|
|
@@ -26347,10 +27037,11 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26347
27037
|
const nodeModulesDir = path65.join(pluginsDir, "node_modules");
|
|
26348
27038
|
try {
|
|
26349
27039
|
execFileSync8("npm", ["install", installSpec, "--prefix", pluginsDir, "--save"], {
|
|
26350
|
-
stdio: "inherit",
|
|
27040
|
+
stdio: json ? "pipe" : "inherit",
|
|
26351
27041
|
timeout: 6e4
|
|
26352
27042
|
});
|
|
26353
27043
|
} catch {
|
|
27044
|
+
if (json) jsonError(ErrorCodes.INSTALL_FAILED, `Failed to install ${installSpec}`);
|
|
26354
27045
|
console.error(`Failed to install ${installSpec}. Check the package name and try again.`);
|
|
26355
27046
|
process.exit(1);
|
|
26356
27047
|
}
|
|
@@ -26365,10 +27056,12 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26365
27056
|
if (minVersion) {
|
|
26366
27057
|
const { compareVersions: compareVersions2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
26367
27058
|
if (compareVersions2(cliVersion, minVersion) < 0) {
|
|
26368
|
-
|
|
27059
|
+
if (!json) {
|
|
27060
|
+
console.log(`
|
|
26369
27061
|
\u26A0\uFE0F This plugin requires OpenACP >= ${minVersion}. You have ${cliVersion}.`);
|
|
26370
|
-
|
|
27062
|
+
console.log(` Run 'openacp update' to get the latest version.
|
|
26371
27063
|
`);
|
|
27064
|
+
}
|
|
26372
27065
|
}
|
|
26373
27066
|
}
|
|
26374
27067
|
const pluginModule = await import(path65.join(pluginRoot, installedPkg.main ?? "dist/index.js"));
|
|
@@ -26385,6 +27078,7 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26385
27078
|
description: plugin2?.description ?? installedPkg.description
|
|
26386
27079
|
});
|
|
26387
27080
|
await pluginRegistry.save();
|
|
27081
|
+
if (json) jsonSuccess({ plugin: plugin2?.name ?? pkgName, version: installedPkg.version, installed: true });
|
|
26388
27082
|
console.log(`\u2713 ${plugin2?.name ?? pkgName} installed! Restart to activate.`);
|
|
26389
27083
|
} catch (err) {
|
|
26390
27084
|
pluginRegistry.register(pkgName, {
|
|
@@ -26394,10 +27088,12 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26394
27088
|
settingsPath: settingsManager.getSettingsPath(pkgName)
|
|
26395
27089
|
});
|
|
26396
27090
|
await pluginRegistry.save();
|
|
27091
|
+
if (json) jsonSuccess({ plugin: pkgName, version: pkgVersion ?? "unknown", installed: true });
|
|
26397
27092
|
console.log(`\u2713 ${pkgName} installed (npm only). Restart to activate.`);
|
|
26398
27093
|
}
|
|
26399
27094
|
}
|
|
26400
|
-
async function uninstallPlugin(name, purge, instanceRoot) {
|
|
27095
|
+
async function uninstallPlugin(name, purge, instanceRoot, json = false) {
|
|
27096
|
+
if (json) await muteForJson();
|
|
26401
27097
|
const os31 = await import("os");
|
|
26402
27098
|
const path65 = await import("path");
|
|
26403
27099
|
const fs53 = await import("fs");
|
|
@@ -26408,10 +27104,12 @@ async function uninstallPlugin(name, purge, instanceRoot) {
|
|
|
26408
27104
|
await registry.load();
|
|
26409
27105
|
const entry = registry.get(name);
|
|
26410
27106
|
if (!entry) {
|
|
27107
|
+
if (json) jsonError(ErrorCodes.PLUGIN_NOT_FOUND, `Plugin "${name}" not installed.`);
|
|
26411
27108
|
console.error(`Plugin "${name}" not installed.`);
|
|
26412
27109
|
process.exit(1);
|
|
26413
27110
|
}
|
|
26414
27111
|
if (entry.source === "builtin") {
|
|
27112
|
+
if (json) jsonError(ErrorCodes.UNINSTALL_FAILED, `Cannot uninstall built-in plugin "${name}". Use "openacp plugin disable ${name}" instead.`);
|
|
26415
27113
|
console.error(`Cannot uninstall built-in plugin. Use "openacp plugin disable ${name}" instead.`);
|
|
26416
27114
|
process.exit(1);
|
|
26417
27115
|
}
|
|
@@ -26434,12 +27132,14 @@ async function uninstallPlugin(name, purge, instanceRoot) {
|
|
|
26434
27132
|
}
|
|
26435
27133
|
registry.remove(name);
|
|
26436
27134
|
await registry.save();
|
|
27135
|
+
if (json) jsonSuccess({ plugin: name, uninstalled: true });
|
|
26437
27136
|
console.log(`Plugin ${name} uninstalled${purge ? " (purged)" : ""}.`);
|
|
26438
27137
|
}
|
|
26439
27138
|
|
|
26440
27139
|
// src/cli/commands/api.ts
|
|
26441
27140
|
init_api_client();
|
|
26442
27141
|
init_helpers();
|
|
27142
|
+
init_output();
|
|
26443
27143
|
function printApiHelp() {
|
|
26444
27144
|
console.log(`
|
|
26445
27145
|
\x1B[1mopenacp api\x1B[0m \u2014 Interact with the running OpenACP daemon
|
|
@@ -26481,6 +27181,7 @@ function printApiHelp() {
|
|
|
26481
27181
|
openacp api version Show daemon version
|
|
26482
27182
|
|
|
26483
27183
|
\x1B[1mOptions:\x1B[0m
|
|
27184
|
+
--json Output result as JSON
|
|
26484
27185
|
-h, --help Show this help message
|
|
26485
27186
|
`);
|
|
26486
27187
|
}
|
|
@@ -26705,8 +27406,11 @@ Shows the version of the currently running daemon process.
|
|
|
26705
27406
|
printApiHelp();
|
|
26706
27407
|
return;
|
|
26707
27408
|
}
|
|
27409
|
+
const json = isJsonMode(args2);
|
|
27410
|
+
if (json) await muteForJson();
|
|
26708
27411
|
const port = readApiPort(void 0, instanceRoot);
|
|
26709
27412
|
if (port === null) {
|
|
27413
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, "OpenACP is not running.");
|
|
26710
27414
|
console.error("OpenACP is not running. Start with `openacp start`");
|
|
26711
27415
|
process.exit(1);
|
|
26712
27416
|
}
|
|
@@ -26729,9 +27433,11 @@ Shows the version of the currently running daemon process.
|
|
|
26729
27433
|
});
|
|
26730
27434
|
const data = await res.json();
|
|
26731
27435
|
if (!res.ok) {
|
|
27436
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26732
27437
|
console.error(`Error: ${data.error}`);
|
|
26733
27438
|
process.exit(1);
|
|
26734
27439
|
}
|
|
27440
|
+
if (json) jsonSuccess(data);
|
|
26735
27441
|
console.log("Session created");
|
|
26736
27442
|
console.log(` ID : ${data.sessionId}`);
|
|
26737
27443
|
console.log(` Agent : ${data.agent}`);
|
|
@@ -26742,6 +27448,7 @@ Shows the version of the currently running daemon process.
|
|
|
26742
27448
|
} else if (subCmd === "cancel") {
|
|
26743
27449
|
const sessionId = args2[1];
|
|
26744
27450
|
if (!sessionId) {
|
|
27451
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Session ID is required");
|
|
26745
27452
|
console.error("Usage: openacp api cancel <session-id>");
|
|
26746
27453
|
process.exit(1);
|
|
26747
27454
|
}
|
|
@@ -26750,13 +27457,16 @@ Shows the version of the currently running daemon process.
|
|
|
26750
27457
|
});
|
|
26751
27458
|
const data = await res.json();
|
|
26752
27459
|
if (!res.ok) {
|
|
27460
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26753
27461
|
console.error(`Error: ${data.error}`);
|
|
26754
27462
|
process.exit(1);
|
|
26755
27463
|
}
|
|
27464
|
+
if (json) jsonSuccess({ cancelled: true, sessionId });
|
|
26756
27465
|
console.log(`Session ${sessionId} cancelled`);
|
|
26757
27466
|
} else if (subCmd === "status") {
|
|
26758
27467
|
const res = await call("/api/sessions");
|
|
26759
27468
|
const data = await res.json();
|
|
27469
|
+
if (json) jsonSuccess(data);
|
|
26760
27470
|
if (data.sessions.length === 0) {
|
|
26761
27471
|
console.log("No active sessions.");
|
|
26762
27472
|
} else {
|
|
@@ -26770,6 +27480,7 @@ Shows the version of the currently running daemon process.
|
|
|
26770
27480
|
} else if (subCmd === "agents") {
|
|
26771
27481
|
const res = await call("/api/agents");
|
|
26772
27482
|
const data = await res.json();
|
|
27483
|
+
if (json) jsonSuccess(data);
|
|
26773
27484
|
console.log("Available agents:");
|
|
26774
27485
|
for (const a of data.agents) {
|
|
26775
27486
|
const isDefault = a.name === data.default ? " (default)" : "";
|
|
@@ -26781,6 +27492,7 @@ Shows the version of the currently running daemon process.
|
|
|
26781
27492
|
const query = statusParam ? `?status=${encodeURIComponent(statusParam)}` : "";
|
|
26782
27493
|
const res = await call(`/api/topics${query}`);
|
|
26783
27494
|
const data = await res.json();
|
|
27495
|
+
if (json) jsonSuccess(data);
|
|
26784
27496
|
if (data.topics.length === 0) {
|
|
26785
27497
|
console.log("No topics found.");
|
|
26786
27498
|
} else {
|
|
@@ -26795,6 +27507,7 @@ Shows the version of the currently running daemon process.
|
|
|
26795
27507
|
} else if (subCmd === "delete-topic") {
|
|
26796
27508
|
const sessionId = args2[1];
|
|
26797
27509
|
if (!sessionId) {
|
|
27510
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Session ID is required");
|
|
26798
27511
|
console.error("Usage: openacp api delete-topic <session-id> [--force]");
|
|
26799
27512
|
process.exit(1);
|
|
26800
27513
|
}
|
|
@@ -26804,13 +27517,16 @@ Shows the version of the currently running daemon process.
|
|
|
26804
27517
|
const data = await res.json();
|
|
26805
27518
|
if (res.status === 409) {
|
|
26806
27519
|
const session = data.session;
|
|
27520
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `Session "${sessionId}" is active (${session?.status}). Use --force to delete.`);
|
|
26807
27521
|
console.error(`Session "${sessionId}" is active (${session?.status}). Use --force to delete.`);
|
|
26808
27522
|
process.exit(1);
|
|
26809
27523
|
}
|
|
26810
27524
|
if (!res.ok) {
|
|
27525
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26811
27526
|
console.error(`Error: ${data.error}`);
|
|
26812
27527
|
process.exit(1);
|
|
26813
27528
|
}
|
|
27529
|
+
if (json) jsonSuccess(data);
|
|
26814
27530
|
const topicLabel = data.topicId ? `Topic #${data.topicId}` : "headless session";
|
|
26815
27531
|
console.log(`${topicLabel} deleted (session ${sessionId})`);
|
|
26816
27532
|
} else if (subCmd === "cleanup") {
|
|
@@ -26824,6 +27540,7 @@ Shows the version of the currently running daemon process.
|
|
|
26824
27540
|
body: JSON.stringify(body)
|
|
26825
27541
|
});
|
|
26826
27542
|
const data = await res.json();
|
|
27543
|
+
if (json) jsonSuccess(data);
|
|
26827
27544
|
if (data.deleted.length === 0 && data.failed.length === 0) {
|
|
26828
27545
|
console.log("Nothing to clean up.");
|
|
26829
27546
|
} else {
|
|
@@ -26835,11 +27552,13 @@ Shows the version of the currently running daemon process.
|
|
|
26835
27552
|
} else if (subCmd === "send") {
|
|
26836
27553
|
const sessionId = args2[1];
|
|
26837
27554
|
if (!sessionId) {
|
|
27555
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Session ID is required");
|
|
26838
27556
|
console.error("Usage: openacp api send <session-id> <prompt>");
|
|
26839
27557
|
process.exit(1);
|
|
26840
27558
|
}
|
|
26841
27559
|
const prompt = args2.slice(2).join(" ");
|
|
26842
27560
|
if (!prompt) {
|
|
27561
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Prompt is required");
|
|
26843
27562
|
console.error("Usage: openacp api send <session-id> <prompt>");
|
|
26844
27563
|
process.exit(1);
|
|
26845
27564
|
}
|
|
@@ -26850,22 +27569,27 @@ Shows the version of the currently running daemon process.
|
|
|
26850
27569
|
});
|
|
26851
27570
|
const data = await res.json();
|
|
26852
27571
|
if (!res.ok) {
|
|
27572
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26853
27573
|
console.error(`Error: ${data.error}`);
|
|
26854
27574
|
process.exit(1);
|
|
26855
27575
|
}
|
|
27576
|
+
if (json) jsonSuccess(data);
|
|
26856
27577
|
console.log(`Prompt sent to session ${sessionId} (queue depth: ${data.queueDepth})`);
|
|
26857
27578
|
} else if (subCmd === "session") {
|
|
26858
27579
|
const sessionId = args2[1];
|
|
26859
27580
|
if (!sessionId) {
|
|
27581
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Session ID is required");
|
|
26860
27582
|
console.error("Usage: openacp api session <session-id>");
|
|
26861
27583
|
process.exit(1);
|
|
26862
27584
|
}
|
|
26863
27585
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}`);
|
|
26864
27586
|
const data = await res.json();
|
|
26865
27587
|
if (!res.ok) {
|
|
27588
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26866
27589
|
console.error(`Error: ${data.error}`);
|
|
26867
27590
|
process.exit(1);
|
|
26868
27591
|
}
|
|
27592
|
+
if (json) jsonSuccess(data);
|
|
26869
27593
|
const s = data.session ?? data;
|
|
26870
27594
|
console.log(`Session details:`);
|
|
26871
27595
|
console.log(` ID : ${s.id}`);
|
|
@@ -26882,11 +27606,13 @@ Shows the version of the currently running daemon process.
|
|
|
26882
27606
|
} else if (subCmd === "dangerous" || subCmd === "bypass") {
|
|
26883
27607
|
const sessionId = args2[1];
|
|
26884
27608
|
if (!sessionId) {
|
|
27609
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Session ID is required");
|
|
26885
27610
|
console.error("Usage: openacp api bypass <session-id> [on|off]");
|
|
26886
27611
|
process.exit(1);
|
|
26887
27612
|
}
|
|
26888
27613
|
const toggle = args2[2];
|
|
26889
27614
|
if (!toggle || toggle !== "on" && toggle !== "off") {
|
|
27615
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Toggle value (on|off) is required");
|
|
26890
27616
|
console.error("Usage: openacp api bypass <session-id> [on|off]");
|
|
26891
27617
|
process.exit(1);
|
|
26892
27618
|
}
|
|
@@ -26897,18 +27623,22 @@ Shows the version of the currently running daemon process.
|
|
|
26897
27623
|
});
|
|
26898
27624
|
const data = await res.json();
|
|
26899
27625
|
if (!res.ok) {
|
|
27626
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26900
27627
|
console.error(`Error: ${data.error}`);
|
|
26901
27628
|
process.exit(1);
|
|
26902
27629
|
}
|
|
27630
|
+
if (json) jsonSuccess(data);
|
|
26903
27631
|
const state = toggle === "on" ? "enabled" : "disabled";
|
|
26904
27632
|
console.log(`Bypass permissions ${state} for session ${sessionId}`);
|
|
26905
27633
|
} else if (subCmd === "health") {
|
|
26906
27634
|
const res = await call("/api/health");
|
|
26907
27635
|
const data = await res.json();
|
|
26908
27636
|
if (!res.ok) {
|
|
27637
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26909
27638
|
console.error(`Error: ${data.error}`);
|
|
26910
27639
|
process.exit(1);
|
|
26911
27640
|
}
|
|
27641
|
+
if (json) jsonSuccess(data);
|
|
26912
27642
|
const uptimeMs = typeof data.uptime === "number" ? data.uptime : 0;
|
|
26913
27643
|
const uptimeSeconds = Math.floor(uptimeMs / 1e3);
|
|
26914
27644
|
const hours = Math.floor(uptimeSeconds / 3600);
|
|
@@ -26930,9 +27660,11 @@ Shows the version of the currently running daemon process.
|
|
|
26930
27660
|
const res = await call("/api/restart", { method: "POST" });
|
|
26931
27661
|
const data = await res.json();
|
|
26932
27662
|
if (!res.ok) {
|
|
27663
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26933
27664
|
console.error(`Error: ${data.error}`);
|
|
26934
27665
|
process.exit(1);
|
|
26935
27666
|
}
|
|
27667
|
+
if (json) jsonSuccess({ restarted: true });
|
|
26936
27668
|
console.log("Restart signal sent. OpenACP is restarting...");
|
|
26937
27669
|
} else if (subCmd === "config") {
|
|
26938
27670
|
console.warn('\u26A0\uFE0F Deprecated: use "openacp config" or "openacp config set" instead.');
|
|
@@ -26941,14 +27673,17 @@ Shows the version of the currently running daemon process.
|
|
|
26941
27673
|
const res = await call("/api/config");
|
|
26942
27674
|
const data = await res.json();
|
|
26943
27675
|
if (!res.ok) {
|
|
27676
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26944
27677
|
console.error(`Error: ${data.error}`);
|
|
26945
27678
|
process.exit(1);
|
|
26946
27679
|
}
|
|
27680
|
+
if (json) jsonSuccess(data);
|
|
26947
27681
|
console.log(JSON.stringify(data.config, null, 2));
|
|
26948
27682
|
} else if (subSubCmd === "set") {
|
|
26949
27683
|
const configPath = args2[2];
|
|
26950
27684
|
const configValue = args2[3];
|
|
26951
27685
|
if (!configPath || configValue === void 0) {
|
|
27686
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Config path and value are required");
|
|
26952
27687
|
console.error("Usage: openacp api config set <path> <value>");
|
|
26953
27688
|
process.exit(1);
|
|
26954
27689
|
}
|
|
@@ -26964,14 +27699,17 @@ Shows the version of the currently running daemon process.
|
|
|
26964
27699
|
});
|
|
26965
27700
|
const data = await res.json();
|
|
26966
27701
|
if (!res.ok) {
|
|
27702
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26967
27703
|
console.error(`Error: ${data.error}`);
|
|
26968
27704
|
process.exit(1);
|
|
26969
27705
|
}
|
|
27706
|
+
if (json) jsonSuccess(data);
|
|
26970
27707
|
console.log(`Config updated: ${configPath} = ${JSON.stringify(value)}`);
|
|
26971
27708
|
if (data.needsRestart) {
|
|
26972
27709
|
console.log("Note: restart required for this change to take effect.");
|
|
26973
27710
|
}
|
|
26974
27711
|
} else {
|
|
27712
|
+
if (json) jsonError(ErrorCodes.UNKNOWN_COMMAND, `Unknown config subcommand: ${subSubCmd}`);
|
|
26975
27713
|
console.error(`Unknown config subcommand: ${subSubCmd}`);
|
|
26976
27714
|
console.log(" openacp api config Show runtime config");
|
|
26977
27715
|
console.log(" openacp api config set <key> <value> Update config value");
|
|
@@ -26981,9 +27719,11 @@ Shows the version of the currently running daemon process.
|
|
|
26981
27719
|
const res = await call("/api/adapters");
|
|
26982
27720
|
const data = await res.json();
|
|
26983
27721
|
if (!res.ok) {
|
|
27722
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26984
27723
|
console.error(`Error: ${data.error}`);
|
|
26985
27724
|
process.exit(1);
|
|
26986
27725
|
}
|
|
27726
|
+
if (json) jsonSuccess(data);
|
|
26987
27727
|
console.log("Registered adapters:");
|
|
26988
27728
|
for (const a of data.adapters) {
|
|
26989
27729
|
console.log(` ${a.name} (${a.type})`);
|
|
@@ -26992,9 +27732,11 @@ Shows the version of the currently running daemon process.
|
|
|
26992
27732
|
const res = await call("/api/tunnel");
|
|
26993
27733
|
const data = await res.json();
|
|
26994
27734
|
if (!res.ok) {
|
|
27735
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
26995
27736
|
console.error(`Error: ${data.error}`);
|
|
26996
27737
|
process.exit(1);
|
|
26997
27738
|
}
|
|
27739
|
+
if (json) jsonSuccess(data);
|
|
26998
27740
|
if (data.enabled) {
|
|
26999
27741
|
console.log(`Tunnel provider : ${data.provider}`);
|
|
27000
27742
|
console.log(`Tunnel URL : ${data.url}`);
|
|
@@ -27004,6 +27746,7 @@ Shows the version of the currently running daemon process.
|
|
|
27004
27746
|
} else if (subCmd === "notify") {
|
|
27005
27747
|
const message = args2.slice(1).join(" ");
|
|
27006
27748
|
if (!message) {
|
|
27749
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Message is required");
|
|
27007
27750
|
console.error("Usage: openacp api notify <message>");
|
|
27008
27751
|
process.exit(1);
|
|
27009
27752
|
}
|
|
@@ -27014,21 +27757,26 @@ Shows the version of the currently running daemon process.
|
|
|
27014
27757
|
});
|
|
27015
27758
|
const data = await res.json();
|
|
27016
27759
|
if (!res.ok) {
|
|
27760
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27017
27761
|
console.error(`Error: ${data.error}`);
|
|
27018
27762
|
process.exit(1);
|
|
27019
27763
|
}
|
|
27764
|
+
if (json) jsonSuccess({ sent: true });
|
|
27020
27765
|
console.log("Notification sent to all channels.");
|
|
27021
27766
|
} else if (subCmd === "version") {
|
|
27022
27767
|
const res = await call("/api/version");
|
|
27023
27768
|
const data = await res.json();
|
|
27024
27769
|
if (!res.ok) {
|
|
27770
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27025
27771
|
console.error(`Error: ${data.error}`);
|
|
27026
27772
|
process.exit(1);
|
|
27027
27773
|
}
|
|
27774
|
+
if (json) jsonSuccess(data);
|
|
27028
27775
|
console.log(`Daemon version: ${data.version}`);
|
|
27029
27776
|
} else if (subCmd === "session-config") {
|
|
27030
27777
|
const sessionId = args2[1];
|
|
27031
27778
|
if (!sessionId) {
|
|
27779
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Session ID is required");
|
|
27032
27780
|
console.error("Usage: openacp api session-config <session-id> [set <opt> <value> | overrides | dangerous [on|off]]");
|
|
27033
27781
|
process.exit(1);
|
|
27034
27782
|
}
|
|
@@ -27037,9 +27785,11 @@ Shows the version of the currently running daemon process.
|
|
|
27037
27785
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config`);
|
|
27038
27786
|
const data = await res.json();
|
|
27039
27787
|
if (!res.ok) {
|
|
27788
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27040
27789
|
console.error(`Error: ${data.error}`);
|
|
27041
27790
|
process.exit(1);
|
|
27042
27791
|
}
|
|
27792
|
+
if (json) jsonSuccess(data);
|
|
27043
27793
|
const configOptions = data.configOptions;
|
|
27044
27794
|
const clientOverrides = data.clientOverrides;
|
|
27045
27795
|
if (!configOptions || configOptions.length === 0) {
|
|
@@ -27073,6 +27823,7 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27073
27823
|
const configId = args2[3];
|
|
27074
27824
|
const value = args2[4];
|
|
27075
27825
|
if (!configId || value === void 0) {
|
|
27826
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Config ID and value are required");
|
|
27076
27827
|
console.error("Usage: openacp api session-config <session-id> set <config-id> <value>");
|
|
27077
27828
|
process.exit(1);
|
|
27078
27829
|
}
|
|
@@ -27083,9 +27834,11 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27083
27834
|
});
|
|
27084
27835
|
const data = await res.json();
|
|
27085
27836
|
if (!res.ok) {
|
|
27837
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27086
27838
|
console.error(`Error: ${data.error}`);
|
|
27087
27839
|
process.exit(1);
|
|
27088
27840
|
}
|
|
27841
|
+
if (json) jsonSuccess(data);
|
|
27089
27842
|
console.log(`Config option "${configId}" updated to "${value}"`);
|
|
27090
27843
|
const configOptions = data.configOptions;
|
|
27091
27844
|
const updated = configOptions?.find((o) => o.id === configId);
|
|
@@ -27096,9 +27849,11 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27096
27849
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`);
|
|
27097
27850
|
const data = await res.json();
|
|
27098
27851
|
if (!res.ok) {
|
|
27852
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27099
27853
|
console.error(`Error: ${data.error}`);
|
|
27100
27854
|
process.exit(1);
|
|
27101
27855
|
}
|
|
27856
|
+
if (json) jsonSuccess(data);
|
|
27102
27857
|
const overrides = data.clientOverrides;
|
|
27103
27858
|
if (!overrides || Object.keys(overrides).length === 0) {
|
|
27104
27859
|
console.log("No client overrides set.");
|
|
@@ -27111,6 +27866,7 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27111
27866
|
} else if (configSubCmd === "dangerous") {
|
|
27112
27867
|
const toggle = args2[3];
|
|
27113
27868
|
if (toggle && toggle !== "on" && toggle !== "off") {
|
|
27869
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Toggle value must be on or off");
|
|
27114
27870
|
console.error("Usage: openacp api session-config <session-id> dangerous [on|off]");
|
|
27115
27871
|
process.exit(1);
|
|
27116
27872
|
}
|
|
@@ -27122,23 +27878,28 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27122
27878
|
});
|
|
27123
27879
|
const data = await res.json();
|
|
27124
27880
|
if (!res.ok) {
|
|
27881
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27125
27882
|
console.error(`Error: ${data.error}`);
|
|
27126
27883
|
process.exit(1);
|
|
27127
27884
|
}
|
|
27885
|
+
if (json) jsonSuccess(data);
|
|
27128
27886
|
const state = toggle === "on" ? "enabled" : "disabled";
|
|
27129
27887
|
console.log(`bypassPermissions ${state} for session ${sessionId}`);
|
|
27130
27888
|
} else {
|
|
27131
27889
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`);
|
|
27132
27890
|
const data = await res.json();
|
|
27133
27891
|
if (!res.ok) {
|
|
27892
|
+
if (json) jsonError(ErrorCodes.API_ERROR, String(data.error ?? "API request failed"));
|
|
27134
27893
|
console.error(`Error: ${data.error}`);
|
|
27135
27894
|
process.exit(1);
|
|
27136
27895
|
}
|
|
27896
|
+
if (json) jsonSuccess(data);
|
|
27137
27897
|
const overrides = data.clientOverrides;
|
|
27138
27898
|
const bypass = overrides?.bypassPermissions;
|
|
27139
27899
|
console.log(`bypassPermissions: ${bypass ?? false}`);
|
|
27140
27900
|
}
|
|
27141
27901
|
} else {
|
|
27902
|
+
if (json) jsonError(ErrorCodes.UNKNOWN_COMMAND, `Unknown session-config subcommand: ${configSubCmd}`);
|
|
27142
27903
|
console.error(`Unknown session-config subcommand: ${configSubCmd}`);
|
|
27143
27904
|
console.log(" openacp api session-config <id> List config options");
|
|
27144
27905
|
console.log(" openacp api session-config <id> set <opt> <value> Set a config option");
|
|
@@ -27170,6 +27931,7 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27170
27931
|
"session-config"
|
|
27171
27932
|
];
|
|
27172
27933
|
const suggestion = suggestMatch2(subCmd ?? "", apiSubcommands);
|
|
27934
|
+
if (json) jsonError(ErrorCodes.UNKNOWN_COMMAND, `Unknown api command: ${subCmd || "(none)"}`);
|
|
27173
27935
|
console.error(`Unknown api command: ${subCmd || "(none)"}
|
|
27174
27936
|
`);
|
|
27175
27937
|
if (suggestion) console.error(`Did you mean: ${suggestion}?
|
|
@@ -27178,11 +27940,14 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27178
27940
|
process.exit(1);
|
|
27179
27941
|
}
|
|
27180
27942
|
} catch (err) {
|
|
27943
|
+
if (err instanceof Error && err.message.startsWith("process.exit")) throw err;
|
|
27181
27944
|
if (err instanceof TypeError && err.cause?.code === "ECONNREFUSED") {
|
|
27945
|
+
if (json) jsonError(ErrorCodes.API_ERROR, "OpenACP is not running (stale port file)");
|
|
27182
27946
|
console.error("OpenACP is not running (stale port file)");
|
|
27183
27947
|
removeStalePortFile(void 0, instanceRoot);
|
|
27184
27948
|
process.exit(1);
|
|
27185
27949
|
}
|
|
27950
|
+
if (json) jsonError(ErrorCodes.API_ERROR, err.message);
|
|
27186
27951
|
throw err;
|
|
27187
27952
|
}
|
|
27188
27953
|
}
|
|
@@ -27190,12 +27955,15 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
27190
27955
|
// src/cli/commands/start.ts
|
|
27191
27956
|
init_version();
|
|
27192
27957
|
init_helpers();
|
|
27958
|
+
init_output();
|
|
27193
27959
|
init_instance_hint();
|
|
27194
27960
|
import path35 from "path";
|
|
27195
27961
|
import os16 from "os";
|
|
27196
27962
|
async function cmdStart(args2 = [], instanceRoot) {
|
|
27963
|
+
const json = isJsonMode(args2);
|
|
27964
|
+
if (json) await muteForJson();
|
|
27197
27965
|
const root = instanceRoot ?? path35.join(os16.homedir(), ".openacp");
|
|
27198
|
-
if (wantsHelp(args2)) {
|
|
27966
|
+
if (!json && wantsHelp(args2)) {
|
|
27199
27967
|
console.log(`
|
|
27200
27968
|
\x1B[1mopenacp start\x1B[0m \u2014 Start OpenACP as a background daemon
|
|
27201
27969
|
|
|
@@ -27205,6 +27973,10 @@ async function cmdStart(args2 = [], instanceRoot) {
|
|
|
27205
27973
|
Starts the server as a background process (daemon mode).
|
|
27206
27974
|
Requires an existing config \u2014 run 'openacp' first to set up.
|
|
27207
27975
|
|
|
27976
|
+
\x1B[1mOptions:\x1B[0m
|
|
27977
|
+
--json Output result as JSON
|
|
27978
|
+
-h, --help Show this help message
|
|
27979
|
+
|
|
27208
27980
|
\x1B[1mSee also:\x1B[0m
|
|
27209
27981
|
openacp stop Stop the daemon
|
|
27210
27982
|
openacp restart Restart the daemon
|
|
@@ -27222,12 +27994,15 @@ Requires an existing config \u2014 run 'openacp' first to set up.
|
|
|
27222
27994
|
const config = cm.get();
|
|
27223
27995
|
const result = startDaemon2(getPidPath2(root), config.logging.logDir, root);
|
|
27224
27996
|
if ("error" in result) {
|
|
27997
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, result.error);
|
|
27225
27998
|
console.error(result.error);
|
|
27226
27999
|
process.exit(1);
|
|
27227
28000
|
}
|
|
28001
|
+
if (json) jsonSuccess({ pid: result.pid, instanceId: path35.basename(root), dir: root });
|
|
27228
28002
|
printInstanceHint(root);
|
|
27229
28003
|
console.log(`OpenACP daemon started (PID ${result.pid})`);
|
|
27230
28004
|
} else {
|
|
28005
|
+
if (json) jsonError(ErrorCodes.CONFIG_NOT_FOUND, 'No config found. Run "openacp" first to set up.');
|
|
27231
28006
|
console.error('No config found. Run "openacp" first to set up.');
|
|
27232
28007
|
process.exit(1);
|
|
27233
28008
|
}
|
|
@@ -27242,6 +28017,7 @@ init_logs();
|
|
|
27242
28017
|
// src/cli/commands/config.ts
|
|
27243
28018
|
init_api_client();
|
|
27244
28019
|
init_helpers();
|
|
28020
|
+
init_output();
|
|
27245
28021
|
import * as pathMod from "path";
|
|
27246
28022
|
async function cmdConfig(args2 = [], instanceRoot) {
|
|
27247
28023
|
const subCmd = args2[0];
|
|
@@ -27257,6 +28033,7 @@ async function cmdConfig(args2 = [], instanceRoot) {
|
|
|
27257
28033
|
<value> New value (JSON-parsed if possible, otherwise string)
|
|
27258
28034
|
|
|
27259
28035
|
\x1B[1mOptions:\x1B[0m
|
|
28036
|
+
--json Output result as JSON
|
|
27260
28037
|
-h, --help Show this help message
|
|
27261
28038
|
|
|
27262
28039
|
Works with both running and stopped daemon. When running, uses
|
|
@@ -27278,6 +28055,7 @@ the API for live updates. When stopped, edits config file directly.
|
|
|
27278
28055
|
openacp config set <key> <value> Set a config value directly
|
|
27279
28056
|
|
|
27280
28057
|
\x1B[1mOptions:\x1B[0m
|
|
28058
|
+
--json Output result as JSON
|
|
27281
28059
|
-h, --help Show this help message
|
|
27282
28060
|
|
|
27283
28061
|
Works with both running and stopped daemon. When running, uses
|
|
@@ -27292,9 +28070,12 @@ the API for live updates. When stopped, edits config file directly.
|
|
|
27292
28070
|
return;
|
|
27293
28071
|
}
|
|
27294
28072
|
if (subCmd === "set") {
|
|
28073
|
+
const json = isJsonMode(args2);
|
|
28074
|
+
if (json) await muteForJson();
|
|
27295
28075
|
const configPath = args2[1];
|
|
27296
28076
|
const configValue = args2[2];
|
|
27297
28077
|
if (!configPath || configValue === void 0) {
|
|
28078
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Missing required arguments: <path> and <value>");
|
|
27298
28079
|
console.error("Usage: openacp config set <path> <value>");
|
|
27299
28080
|
process.exit(1);
|
|
27300
28081
|
}
|
|
@@ -27302,6 +28083,7 @@ the API for live updates. When stopped, edits config file directly.
|
|
|
27302
28083
|
const topLevelKey = configPath.split(".")[0];
|
|
27303
28084
|
const validConfigKeys = Object.keys(ConfigSchema2.shape);
|
|
27304
28085
|
if (!validConfigKeys.includes(topLevelKey)) {
|
|
28086
|
+
if (json) jsonError(ErrorCodes.CONFIG_INVALID, `Unknown config key: ${topLevelKey}`);
|
|
27305
28087
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
27306
28088
|
const suggestion = suggestMatch2(topLevelKey, validConfigKeys);
|
|
27307
28089
|
console.error(`Unknown config key: ${topLevelKey}`);
|
|
@@ -27322,9 +28104,11 @@ the API for live updates. When stopped, edits config file directly.
|
|
|
27322
28104
|
}, instanceRoot);
|
|
27323
28105
|
const data = await res.json();
|
|
27324
28106
|
if (!res.ok) {
|
|
28107
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `${data.error}`);
|
|
27325
28108
|
console.error(`Error: ${data.error}`);
|
|
27326
28109
|
process.exit(1);
|
|
27327
28110
|
}
|
|
28111
|
+
if (json) jsonSuccess({ path: configPath, value, needsRestart: data.needsRestart ?? false });
|
|
27328
28112
|
console.log(`Config updated: ${configPath} = ${JSON.stringify(value)}`);
|
|
27329
28113
|
if (data.needsRestart) {
|
|
27330
28114
|
console.log("Note: restart required for this change to take effect.");
|
|
@@ -27333,12 +28117,14 @@ the API for live updates. When stopped, edits config file directly.
|
|
|
27333
28117
|
const { ConfigManager: ConfigManager3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
27334
28118
|
const cm2 = new ConfigManager3(instanceRoot ? pathMod.join(instanceRoot, "config.json") : void 0);
|
|
27335
28119
|
if (!await cm2.exists()) {
|
|
28120
|
+
if (json) jsonError(ErrorCodes.CONFIG_NOT_FOUND, 'No config found. Run "openacp" first to set up.');
|
|
27336
28121
|
console.error('No config found. Run "openacp" first to set up.');
|
|
27337
28122
|
process.exit(1);
|
|
27338
28123
|
}
|
|
27339
28124
|
await cm2.load();
|
|
27340
28125
|
const updates = buildNestedUpdateFromPath(configPath, value);
|
|
27341
28126
|
await cm2.save(updates);
|
|
28127
|
+
if (json) jsonSuccess({ path: configPath, value, needsRestart: false });
|
|
27342
28128
|
console.log(`Config updated: ${configPath} = ${JSON.stringify(value)}`);
|
|
27343
28129
|
}
|
|
27344
28130
|
return;
|
|
@@ -27439,6 +28225,7 @@ installs it globally if an update is available.
|
|
|
27439
28225
|
// src/cli/commands/adopt.ts
|
|
27440
28226
|
init_api_client();
|
|
27441
28227
|
init_helpers();
|
|
28228
|
+
init_output();
|
|
27442
28229
|
async function cmdAdopt(args2) {
|
|
27443
28230
|
if (wantsHelp(args2)) {
|
|
27444
28231
|
console.log(`
|
|
@@ -27454,6 +28241,7 @@ async function cmdAdopt(args2) {
|
|
|
27454
28241
|
\x1B[1mOptions:\x1B[0m
|
|
27455
28242
|
--cwd <path> Working directory for the session (default: current dir)
|
|
27456
28243
|
--channel <name> Target channel adapter (e.g. telegram, discord). Default: first registered
|
|
28244
|
+
--json Output result as JSON
|
|
27457
28245
|
-h, --help Show this help message
|
|
27458
28246
|
|
|
27459
28247
|
Transfers an existing agent session into OpenACP so it appears
|
|
@@ -27466,9 +28254,23 @@ as a messaging thread. Requires a running daemon.
|
|
|
27466
28254
|
`);
|
|
27467
28255
|
return;
|
|
27468
28256
|
}
|
|
27469
|
-
const
|
|
27470
|
-
|
|
28257
|
+
const json = isJsonMode(args2);
|
|
28258
|
+
if (json) await muteForJson();
|
|
28259
|
+
const skipFlags = /* @__PURE__ */ new Set(["--json", "-h", "--help"]);
|
|
28260
|
+
const skipWithValue = /* @__PURE__ */ new Set(["--cwd", "--channel"]);
|
|
28261
|
+
const positional = [];
|
|
28262
|
+
for (let i = 0; i < args2.length; i++) {
|
|
28263
|
+
if (skipWithValue.has(args2[i])) {
|
|
28264
|
+
i++;
|
|
28265
|
+
continue;
|
|
28266
|
+
}
|
|
28267
|
+
if (skipFlags.has(args2[i])) continue;
|
|
28268
|
+
positional.push(args2[i]);
|
|
28269
|
+
}
|
|
28270
|
+
const agent = positional[0];
|
|
28271
|
+
const sessionId = positional[1];
|
|
27471
28272
|
if (!agent || !sessionId) {
|
|
28273
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Missing required arguments: <agent> and <session_id>");
|
|
27472
28274
|
console.log("Usage: openacp adopt <agent> <session_id> [--cwd <path>] [--channel <name>]");
|
|
27473
28275
|
console.log("Example: openacp adopt claude abc123-def456 --cwd /path/to/project");
|
|
27474
28276
|
process.exit(1);
|
|
@@ -27479,6 +28281,7 @@ as a messaging thread. Requires a running daemon.
|
|
|
27479
28281
|
const channel = channelIdx !== -1 && args2[channelIdx + 1] ? args2[channelIdx + 1] : void 0;
|
|
27480
28282
|
const port = readApiPort();
|
|
27481
28283
|
if (!port) {
|
|
28284
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, "OpenACP is not running. Start it with: openacp start");
|
|
27482
28285
|
console.log("OpenACP is not running. Start it with: openacp start");
|
|
27483
28286
|
process.exit(1);
|
|
27484
28287
|
}
|
|
@@ -27491,6 +28294,7 @@ as a messaging thread. Requires a running daemon.
|
|
|
27491
28294
|
});
|
|
27492
28295
|
const data = await res.json();
|
|
27493
28296
|
if (data.ok) {
|
|
28297
|
+
if (json) jsonSuccess({ sessionId: data.sessionId, threadId: data.threadId, agent, status: data.status ?? "new" });
|
|
27494
28298
|
if (data.status === "existing") {
|
|
27495
28299
|
console.log(`Session already active. Topic pinged.`);
|
|
27496
28300
|
} else {
|
|
@@ -27499,10 +28303,13 @@ as a messaging thread. Requires a running daemon.
|
|
|
27499
28303
|
console.log(` Session ID: ${data.sessionId}`);
|
|
27500
28304
|
console.log(` Thread ID: ${data.threadId}`);
|
|
27501
28305
|
} else {
|
|
28306
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `${data.message || data.error || "Unknown error"}`);
|
|
27502
28307
|
console.log(`Error: ${data.message || data.error}`);
|
|
27503
28308
|
process.exit(1);
|
|
27504
28309
|
}
|
|
27505
28310
|
} catch (err) {
|
|
28311
|
+
if (err instanceof Error && err.message.startsWith("process.exit")) throw err;
|
|
28312
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `Failed to connect to OpenACP: ${err instanceof Error ? err.message : err}`);
|
|
27506
28313
|
console.log(`Failed to connect to OpenACP: ${err instanceof Error ? err.message : err}`);
|
|
27507
28314
|
process.exit(1);
|
|
27508
28315
|
}
|
|
@@ -27581,8 +28388,11 @@ a "Handoff" slash command to Claude Code.
|
|
|
27581
28388
|
|
|
27582
28389
|
// src/cli/commands/doctor.ts
|
|
27583
28390
|
init_helpers();
|
|
28391
|
+
init_output();
|
|
27584
28392
|
async function cmdDoctor(args2, instanceRoot) {
|
|
27585
|
-
|
|
28393
|
+
const json = isJsonMode(args2);
|
|
28394
|
+
if (json) await muteForJson();
|
|
28395
|
+
if (!json && wantsHelp(args2)) {
|
|
27586
28396
|
console.log(`
|
|
27587
28397
|
\x1B[1mopenacp doctor\x1B[0m \u2014 Run system diagnostics
|
|
27588
28398
|
|
|
@@ -27591,6 +28401,7 @@ async function cmdDoctor(args2, instanceRoot) {
|
|
|
27591
28401
|
|
|
27592
28402
|
\x1B[1mOptions:\x1B[0m
|
|
27593
28403
|
--dry-run Check only, don't apply any fixes
|
|
28404
|
+
--json Output result as JSON
|
|
27594
28405
|
-h, --help Show this help message
|
|
27595
28406
|
|
|
27596
28407
|
Checks your OpenACP installation for common issues including
|
|
@@ -27599,11 +28410,11 @@ Fixable issues can be auto-repaired when not using --dry-run.
|
|
|
27599
28410
|
`);
|
|
27600
28411
|
return;
|
|
27601
28412
|
}
|
|
27602
|
-
const knownFlags = ["--dry-run"];
|
|
28413
|
+
const knownFlags = ["--dry-run", "--json"];
|
|
27603
28414
|
const unknownFlags = args2.filter(
|
|
27604
28415
|
(a) => a.startsWith("--") && !knownFlags.includes(a)
|
|
27605
28416
|
);
|
|
27606
|
-
if (unknownFlags.length > 0) {
|
|
28417
|
+
if (!json && unknownFlags.length > 0) {
|
|
27607
28418
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
27608
28419
|
for (const flag of unknownFlags) {
|
|
27609
28420
|
const suggestion = suggestMatch2(flag, knownFlags);
|
|
@@ -27612,11 +28423,24 @@ Fixable issues can be auto-repaired when not using --dry-run.
|
|
|
27612
28423
|
}
|
|
27613
28424
|
process.exit(1);
|
|
27614
28425
|
}
|
|
27615
|
-
const dryRun = args2.includes("--dry-run");
|
|
28426
|
+
const dryRun = args2.includes("--dry-run") || json;
|
|
27616
28427
|
const { DoctorEngine: DoctorEngine2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
27617
28428
|
const engine = new DoctorEngine2({ dryRun, dataDir: instanceRoot });
|
|
27618
|
-
console.log("\n\u{1FA7A} OpenACP Doctor\n");
|
|
28429
|
+
if (!json) console.log("\n\u{1FA7A} OpenACP Doctor\n");
|
|
27619
28430
|
const report = await engine.runAll();
|
|
28431
|
+
if (json) {
|
|
28432
|
+
jsonSuccess({
|
|
28433
|
+
categories: report.categories.map((c3) => ({
|
|
28434
|
+
name: c3.name,
|
|
28435
|
+
results: c3.results.map((r) => ({ status: r.status, message: r.message }))
|
|
28436
|
+
})),
|
|
28437
|
+
summary: {
|
|
28438
|
+
passed: report.summary.passed,
|
|
28439
|
+
warnings: report.summary.warnings,
|
|
28440
|
+
failed: report.summary.failed
|
|
28441
|
+
}
|
|
28442
|
+
});
|
|
28443
|
+
}
|
|
27620
28444
|
const icons = { pass: "\x1B[32m\u2705\x1B[0m", warn: "\x1B[33m\u26A0\uFE0F\x1B[0m", fail: "\x1B[31m\u274C\x1B[0m" };
|
|
27621
28445
|
for (const category of report.categories) {
|
|
27622
28446
|
console.log(`\x1B[1m\x1B[36m${category.name}\x1B[0m`);
|
|
@@ -27659,6 +28483,7 @@ Fixable issues can be auto-repaired when not using --dry-run.
|
|
|
27659
28483
|
|
|
27660
28484
|
// src/cli/commands/agents.ts
|
|
27661
28485
|
init_helpers();
|
|
28486
|
+
init_output();
|
|
27662
28487
|
async function createCatalog(instanceRoot) {
|
|
27663
28488
|
const { AgentCatalog: AgentCatalog2 } = await Promise.resolve().then(() => (init_agent_catalog(), agent_catalog_exports));
|
|
27664
28489
|
if (instanceRoot) {
|
|
@@ -27684,6 +28509,7 @@ async function cmdAgents(args2, instanceRoot) {
|
|
|
27684
28509
|
openacp agents refresh Force-refresh agent list from registry
|
|
27685
28510
|
|
|
27686
28511
|
\x1B[1mOptions:\x1B[0m
|
|
28512
|
+
--json Output result as JSON
|
|
27687
28513
|
-h, --help Show this help message
|
|
27688
28514
|
|
|
27689
28515
|
\x1B[1mExamples:\x1B[0m
|
|
@@ -27695,11 +28521,12 @@ async function cmdAgents(args2, instanceRoot) {
|
|
|
27695
28521
|
`);
|
|
27696
28522
|
return;
|
|
27697
28523
|
}
|
|
28524
|
+
const positional = args2.slice(1).find((a) => !a.startsWith("-"));
|
|
27698
28525
|
switch (subcommand) {
|
|
27699
28526
|
case "install":
|
|
27700
|
-
return agentsInstall(
|
|
28527
|
+
return agentsInstall(positional, args2.includes("--force"), wantsHelp(args2), instanceRoot, isJsonMode(args2));
|
|
27701
28528
|
case "uninstall":
|
|
27702
|
-
return agentsUninstall(
|
|
28529
|
+
return agentsUninstall(positional, wantsHelp(args2), instanceRoot, isJsonMode(args2));
|
|
27703
28530
|
case "refresh":
|
|
27704
28531
|
if (wantsHelp(args2)) {
|
|
27705
28532
|
console.log(`
|
|
@@ -27715,7 +28542,7 @@ bypassing the normal staleness check.
|
|
|
27715
28542
|
}
|
|
27716
28543
|
return agentsRefresh(instanceRoot);
|
|
27717
28544
|
case "info":
|
|
27718
|
-
return agentsInfo(
|
|
28545
|
+
return agentsInfo(positional, wantsHelp(args2), instanceRoot, isJsonMode(args2));
|
|
27719
28546
|
case "run":
|
|
27720
28547
|
return agentsRun(args2[1], args2.slice(2), wantsHelp(args2), instanceRoot);
|
|
27721
28548
|
case "list":
|
|
@@ -27734,22 +28561,24 @@ Run 'openacp agents' to see available agents.`);
|
|
|
27734
28561
|
}
|
|
27735
28562
|
}
|
|
27736
28563
|
async function agentsList(instanceRoot, json = false) {
|
|
28564
|
+
if (json) await muteForJson();
|
|
27737
28565
|
const catalog = await createCatalog(instanceRoot);
|
|
27738
28566
|
catalog.load();
|
|
27739
28567
|
await catalog.refreshRegistryIfStale();
|
|
27740
28568
|
const items = catalog.getAvailable();
|
|
27741
28569
|
if (json) {
|
|
27742
|
-
|
|
27743
|
-
|
|
27744
|
-
|
|
27745
|
-
|
|
27746
|
-
|
|
27747
|
-
|
|
27748
|
-
|
|
27749
|
-
|
|
27750
|
-
|
|
27751
|
-
|
|
27752
|
-
|
|
28570
|
+
jsonSuccess({
|
|
28571
|
+
agents: items.map((item) => ({
|
|
28572
|
+
key: item.key,
|
|
28573
|
+
name: item.name,
|
|
28574
|
+
version: item.version,
|
|
28575
|
+
distribution: item.distribution,
|
|
28576
|
+
description: item.description ?? "",
|
|
28577
|
+
installed: item.installed,
|
|
28578
|
+
available: item.available ?? true,
|
|
28579
|
+
missingDeps: item.missingDeps ?? []
|
|
28580
|
+
}))
|
|
28581
|
+
});
|
|
27753
28582
|
}
|
|
27754
28583
|
const installed = items.filter((i) => i.installed);
|
|
27755
28584
|
const available = items.filter((i) => !i.installed);
|
|
@@ -27786,8 +28615,9 @@ async function agentsList(instanceRoot, json = false) {
|
|
|
27786
28615
|
);
|
|
27787
28616
|
console.log("");
|
|
27788
28617
|
}
|
|
27789
|
-
async function agentsInstall(nameOrId, force, help = false, instanceRoot) {
|
|
27790
|
-
if (
|
|
28618
|
+
async function agentsInstall(nameOrId, force, help = false, instanceRoot, json = false) {
|
|
28619
|
+
if (json) await muteForJson();
|
|
28620
|
+
if (!json && (help || !nameOrId)) {
|
|
27791
28621
|
console.log(`
|
|
27792
28622
|
\x1B[1mopenacp agents install\x1B[0m \u2014 Install an agent from the ACP Registry
|
|
27793
28623
|
|
|
@@ -27799,6 +28629,7 @@ async function agentsInstall(nameOrId, force, help = false, instanceRoot) {
|
|
|
27799
28629
|
|
|
27800
28630
|
\x1B[1mOptions:\x1B[0m
|
|
27801
28631
|
--force Reinstall even if already installed
|
|
28632
|
+
--json Output result as JSON
|
|
27802
28633
|
-h, --help Show this help message
|
|
27803
28634
|
|
|
27804
28635
|
\x1B[1mExamples:\x1B[0m
|
|
@@ -27809,10 +28640,25 @@ Run 'openacp agents' to see available agents.
|
|
|
27809
28640
|
`);
|
|
27810
28641
|
return;
|
|
27811
28642
|
}
|
|
28643
|
+
if (!nameOrId) {
|
|
28644
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Agent name is required");
|
|
28645
|
+
return;
|
|
28646
|
+
}
|
|
27812
28647
|
const catalog = await createCatalog(instanceRoot);
|
|
27813
28648
|
catalog.load();
|
|
27814
28649
|
await catalog.refreshRegistryIfStale();
|
|
27815
|
-
const progress = {
|
|
28650
|
+
const progress = json ? {
|
|
28651
|
+
onStart() {
|
|
28652
|
+
},
|
|
28653
|
+
onStep() {
|
|
28654
|
+
},
|
|
28655
|
+
onDownloadProgress() {
|
|
28656
|
+
},
|
|
28657
|
+
onSuccess() {
|
|
28658
|
+
},
|
|
28659
|
+
onError() {
|
|
28660
|
+
}
|
|
28661
|
+
} : {
|
|
27816
28662
|
onStart(_id, name) {
|
|
27817
28663
|
process.stdout.write(`
|
|
27818
28664
|
\u23F3 Installing ${name}...
|
|
@@ -27842,6 +28688,7 @@ Run 'openacp agents' to see available agents.
|
|
|
27842
28688
|
};
|
|
27843
28689
|
const result = await catalog.install(nameOrId, progress, force);
|
|
27844
28690
|
if (!result.ok) {
|
|
28691
|
+
if (json) jsonError(ErrorCodes.INSTALL_FAILED, result.error ?? "Installation failed");
|
|
27845
28692
|
if (result.error?.includes("not found")) {
|
|
27846
28693
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
27847
28694
|
const allKeys = catalog.getAvailable().map((a) => a.key);
|
|
@@ -27850,6 +28697,10 @@ Run 'openacp agents' to see available agents.
|
|
|
27850
28697
|
}
|
|
27851
28698
|
process.exit(1);
|
|
27852
28699
|
}
|
|
28700
|
+
if (json) {
|
|
28701
|
+
const installed = catalog.getInstalledAgent(result.agentKey);
|
|
28702
|
+
jsonSuccess({ key: result.agentKey, version: installed?.version ?? "unknown", installed: true });
|
|
28703
|
+
}
|
|
27853
28704
|
const { getAgentCapabilities: getAgentCapabilities2 } = await Promise.resolve().then(() => (init_agent_dependencies(), agent_dependencies_exports));
|
|
27854
28705
|
const caps = getAgentCapabilities2(result.agentKey);
|
|
27855
28706
|
if (caps.integration) {
|
|
@@ -27871,8 +28722,9 @@ Run 'openacp agents' to see available agents.
|
|
|
27871
28722
|
`);
|
|
27872
28723
|
}
|
|
27873
28724
|
}
|
|
27874
|
-
async function agentsUninstall(name, help = false, instanceRoot) {
|
|
27875
|
-
if (
|
|
28725
|
+
async function agentsUninstall(name, help = false, instanceRoot, json = false) {
|
|
28726
|
+
if (json) await muteForJson();
|
|
28727
|
+
if (!json && (help || !name)) {
|
|
27876
28728
|
console.log(`
|
|
27877
28729
|
\x1B[1mopenacp agents uninstall\x1B[0m \u2014 Remove an installed agent
|
|
27878
28730
|
|
|
@@ -27882,11 +28734,19 @@ async function agentsUninstall(name, help = false, instanceRoot) {
|
|
|
27882
28734
|
\x1B[1mArguments:\x1B[0m
|
|
27883
28735
|
<name> Agent name to remove
|
|
27884
28736
|
|
|
28737
|
+
\x1B[1mOptions:\x1B[0m
|
|
28738
|
+
--json Output result as JSON
|
|
28739
|
+
-h, --help Show this help message
|
|
28740
|
+
|
|
27885
28741
|
\x1B[1mExamples:\x1B[0m
|
|
27886
28742
|
openacp agents uninstall gemini
|
|
27887
28743
|
`);
|
|
27888
28744
|
return;
|
|
27889
28745
|
}
|
|
28746
|
+
if (!name) {
|
|
28747
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Agent name is required");
|
|
28748
|
+
return;
|
|
28749
|
+
}
|
|
27890
28750
|
const catalog = await createCatalog(instanceRoot);
|
|
27891
28751
|
catalog.load();
|
|
27892
28752
|
const result = await catalog.uninstall(name);
|
|
@@ -27898,10 +28758,12 @@ async function agentsUninstall(name, help = false, instanceRoot) {
|
|
|
27898
28758
|
await uninstallIntegration2(name, caps.integration);
|
|
27899
28759
|
console.log(` \x1B[32m\u2713\x1B[0m Handoff integration removed for ${name}`);
|
|
27900
28760
|
}
|
|
28761
|
+
if (json) jsonSuccess({ key: name, uninstalled: true });
|
|
27901
28762
|
console.log(`
|
|
27902
28763
|
\x1B[32m\u2713 ${name} removed.\x1B[0m
|
|
27903
28764
|
`);
|
|
27904
28765
|
} else {
|
|
28766
|
+
if (json) jsonError(ErrorCodes.UNINSTALL_FAILED, result.error ?? "Uninstall failed");
|
|
27905
28767
|
console.log(`
|
|
27906
28768
|
\x1B[31m\u2717 ${result.error}\x1B[0m`);
|
|
27907
28769
|
if (result.error?.includes("not installed")) {
|
|
@@ -27920,8 +28782,9 @@ async function agentsRefresh(instanceRoot) {
|
|
|
27920
28782
|
await catalog.fetchRegistry();
|
|
27921
28783
|
console.log(" \x1B[32m\u2713 Agent list updated.\x1B[0m\n");
|
|
27922
28784
|
}
|
|
27923
|
-
async function agentsInfo(nameOrId, help = false, instanceRoot) {
|
|
27924
|
-
if (
|
|
28785
|
+
async function agentsInfo(nameOrId, help = false, instanceRoot, json = false) {
|
|
28786
|
+
if (json) await muteForJson();
|
|
28787
|
+
if (!json && (help || !nameOrId)) {
|
|
27925
28788
|
console.log(`
|
|
27926
28789
|
\x1B[1mopenacp agents info\x1B[0m \u2014 Show agent details, dependencies & setup guide
|
|
27927
28790
|
|
|
@@ -27934,17 +28797,37 @@ async function agentsInfo(nameOrId, help = false, instanceRoot) {
|
|
|
27934
28797
|
Shows version, distribution type, command, setup steps, and
|
|
27935
28798
|
whether the agent is installed or available from the registry.
|
|
27936
28799
|
|
|
28800
|
+
\x1B[1mOptions:\x1B[0m
|
|
28801
|
+
--json Output result as JSON
|
|
28802
|
+
-h, --help Show this help message
|
|
28803
|
+
|
|
27937
28804
|
\x1B[1mExamples:\x1B[0m
|
|
27938
28805
|
openacp agents info claude
|
|
27939
28806
|
openacp agents info cursor
|
|
27940
28807
|
`);
|
|
27941
28808
|
return;
|
|
27942
28809
|
}
|
|
28810
|
+
if (!nameOrId) {
|
|
28811
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Agent name is required");
|
|
28812
|
+
return;
|
|
28813
|
+
}
|
|
27943
28814
|
const catalog = await createCatalog(instanceRoot);
|
|
27944
28815
|
catalog.load();
|
|
27945
28816
|
const { getAgentSetup: getAgentSetup2 } = await Promise.resolve().then(() => (init_agent_dependencies(), agent_dependencies_exports));
|
|
27946
28817
|
const installed = catalog.getInstalledAgent(nameOrId);
|
|
27947
28818
|
if (installed) {
|
|
28819
|
+
if (json) {
|
|
28820
|
+
jsonSuccess({
|
|
28821
|
+
key: installed.registryId ?? nameOrId,
|
|
28822
|
+
name: installed.name,
|
|
28823
|
+
version: installed.version,
|
|
28824
|
+
distribution: installed.distribution,
|
|
28825
|
+
installed: true,
|
|
28826
|
+
command: installed.command,
|
|
28827
|
+
binaryPath: installed.binaryPath ?? null,
|
|
28828
|
+
registryId: installed.registryId ?? null
|
|
28829
|
+
});
|
|
28830
|
+
}
|
|
27948
28831
|
console.log(`
|
|
27949
28832
|
\x1B[1m${installed.name}\x1B[0m`);
|
|
27950
28833
|
console.log(` Version: ${installed.version}`);
|
|
@@ -27967,6 +28850,15 @@ whether the agent is installed or available from the registry.
|
|
|
27967
28850
|
}
|
|
27968
28851
|
const regAgent = catalog.findRegistryAgent(nameOrId);
|
|
27969
28852
|
if (regAgent) {
|
|
28853
|
+
if (json) {
|
|
28854
|
+
jsonSuccess({
|
|
28855
|
+
key: regAgent.id,
|
|
28856
|
+
name: regAgent.name,
|
|
28857
|
+
version: regAgent.version,
|
|
28858
|
+
description: regAgent.description ?? "",
|
|
28859
|
+
installed: false
|
|
28860
|
+
});
|
|
28861
|
+
}
|
|
27970
28862
|
const availability = catalog.checkAvailability(nameOrId);
|
|
27971
28863
|
console.log(`
|
|
27972
28864
|
\x1B[1m${regAgent.name}\x1B[0m \x1B[2m(not installed)\x1B[0m`);
|
|
@@ -27989,6 +28881,7 @@ whether the agent is installed or available from the registry.
|
|
|
27989
28881
|
`);
|
|
27990
28882
|
return;
|
|
27991
28883
|
}
|
|
28884
|
+
if (json) jsonError(ErrorCodes.AGENT_NOT_FOUND, `"${nameOrId}" not found.`);
|
|
27992
28885
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
27993
28886
|
const allKeys = catalog.getAvailable().map((a) => a.key);
|
|
27994
28887
|
const suggestion = suggestMatch2(nameOrId, allKeys);
|
|
@@ -28070,10 +28963,14 @@ ACP-specific flags are automatically stripped.
|
|
|
28070
28963
|
|
|
28071
28964
|
// src/cli/commands/tunnel.ts
|
|
28072
28965
|
init_api_client();
|
|
28966
|
+
init_output();
|
|
28073
28967
|
async function cmdTunnel(args2, instanceRoot) {
|
|
28968
|
+
const json = isJsonMode(args2);
|
|
28969
|
+
if (json) await muteForJson();
|
|
28074
28970
|
const subCmd = args2[0];
|
|
28075
28971
|
const port = readApiPort(void 0, instanceRoot);
|
|
28076
28972
|
if (port === null) {
|
|
28973
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, "OpenACP is not running.");
|
|
28077
28974
|
console.error("OpenACP is not running. Start with `openacp start`");
|
|
28078
28975
|
process.exit(1);
|
|
28079
28976
|
}
|
|
@@ -28082,6 +28979,7 @@ async function cmdTunnel(args2, instanceRoot) {
|
|
|
28082
28979
|
if (subCmd === "add") {
|
|
28083
28980
|
const tunnelPort = args2[1];
|
|
28084
28981
|
if (!tunnelPort) {
|
|
28982
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Port is required");
|
|
28085
28983
|
console.error("Usage: openacp tunnel add <port> [--label name] [--session id]");
|
|
28086
28984
|
process.exit(1);
|
|
28087
28985
|
}
|
|
@@ -28099,13 +28997,25 @@ async function cmdTunnel(args2, instanceRoot) {
|
|
|
28099
28997
|
});
|
|
28100
28998
|
const data = await res.json();
|
|
28101
28999
|
if (!res.ok) {
|
|
29000
|
+
if (json) jsonError(ErrorCodes.TUNNEL_ERROR, String(data.error));
|
|
28102
29001
|
console.error(`Error: ${data.error}`);
|
|
28103
29002
|
process.exit(1);
|
|
28104
29003
|
}
|
|
29004
|
+
if (json) jsonSuccess({ port: data.port, publicUrl: data.publicUrl });
|
|
28105
29005
|
console.log(`Tunnel active: port ${data.port} \u2192 ${data.publicUrl}`);
|
|
28106
29006
|
} else if (subCmd === "list") {
|
|
28107
29007
|
const res = await call("/api/tunnel/list");
|
|
28108
29008
|
const data = await res.json();
|
|
29009
|
+
if (json) {
|
|
29010
|
+
jsonSuccess({
|
|
29011
|
+
tunnels: data.map((t) => ({
|
|
29012
|
+
port: t.port,
|
|
29013
|
+
label: t.label ?? null,
|
|
29014
|
+
publicUrl: t.publicUrl ?? null,
|
|
29015
|
+
status: t.status ?? "unknown"
|
|
29016
|
+
}))
|
|
29017
|
+
});
|
|
29018
|
+
}
|
|
28109
29019
|
if (data.length === 0) {
|
|
28110
29020
|
console.log("No active tunnels.");
|
|
28111
29021
|
return;
|
|
@@ -28120,23 +29030,28 @@ async function cmdTunnel(args2, instanceRoot) {
|
|
|
28120
29030
|
} else if (subCmd === "stop") {
|
|
28121
29031
|
const tunnelPort = args2[1];
|
|
28122
29032
|
if (!tunnelPort) {
|
|
29033
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "Port is required");
|
|
28123
29034
|
console.error("Usage: openacp tunnel stop <port>");
|
|
28124
29035
|
process.exit(1);
|
|
28125
29036
|
}
|
|
28126
29037
|
const res = await call(`/api/tunnel/${tunnelPort}`, { method: "DELETE" });
|
|
28127
29038
|
if (!res.ok) {
|
|
28128
29039
|
const data = await res.json();
|
|
29040
|
+
if (json) jsonError(ErrorCodes.TUNNEL_ERROR, String(data.error));
|
|
28129
29041
|
console.error(`Error: ${data.error}`);
|
|
28130
29042
|
process.exit(1);
|
|
28131
29043
|
}
|
|
29044
|
+
if (json) jsonSuccess({ port: parseInt(tunnelPort, 10), stopped: true });
|
|
28132
29045
|
console.log(`Tunnel stopped: port ${tunnelPort}`);
|
|
28133
29046
|
} else if (subCmd === "stop-all") {
|
|
28134
29047
|
const res = await call("/api/tunnel", { method: "DELETE" });
|
|
28135
29048
|
if (!res.ok) {
|
|
28136
29049
|
const data = await res.json();
|
|
29050
|
+
if (json) jsonError(ErrorCodes.TUNNEL_ERROR, String(data.error));
|
|
28137
29051
|
console.error(`Error: ${data.error}`);
|
|
28138
29052
|
process.exit(1);
|
|
28139
29053
|
}
|
|
29054
|
+
if (json) jsonSuccess({ stopped: true });
|
|
28140
29055
|
console.log("All user tunnels stopped.");
|
|
28141
29056
|
} else {
|
|
28142
29057
|
console.log(`
|
|
@@ -28145,10 +29060,16 @@ Tunnel Management:
|
|
|
28145
29060
|
openacp tunnel list
|
|
28146
29061
|
openacp tunnel stop <port>
|
|
28147
29062
|
openacp tunnel stop-all
|
|
29063
|
+
|
|
29064
|
+
Options:
|
|
29065
|
+
--json Output result as JSON
|
|
28148
29066
|
`);
|
|
28149
29067
|
}
|
|
28150
29068
|
} catch (err) {
|
|
28151
|
-
|
|
29069
|
+
const msg = err.message;
|
|
29070
|
+
if (msg?.startsWith("process.exit")) throw err;
|
|
29071
|
+
if (json) jsonError(ErrorCodes.TUNNEL_ERROR, msg);
|
|
29072
|
+
console.error(`Failed to connect to daemon: ${msg}`);
|
|
28152
29073
|
process.exit(1);
|
|
28153
29074
|
}
|
|
28154
29075
|
}
|
|
@@ -28179,9 +29100,11 @@ async function cmdOnboard(instanceRoot) {
|
|
|
28179
29100
|
// src/cli/commands/default.ts
|
|
28180
29101
|
init_version();
|
|
28181
29102
|
init_instance_context();
|
|
29103
|
+
init_instance_registry();
|
|
28182
29104
|
init_instance_hint();
|
|
28183
29105
|
import path58 from "path";
|
|
28184
29106
|
import os27 from "os";
|
|
29107
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
28185
29108
|
async function cmdDefault(command2, instanceRoot) {
|
|
28186
29109
|
const root = instanceRoot ?? path58.join(os27.homedir(), ".openacp");
|
|
28187
29110
|
const pluginsDataDir = path58.join(root, "plugins", "data");
|
|
@@ -28251,8 +29174,11 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
28251
29174
|
markRunning2(root);
|
|
28252
29175
|
printInstanceHint(root);
|
|
28253
29176
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
29177
|
+
const reg = new InstanceRegistry(path58.join(getGlobalRoot(), "instances.json"));
|
|
29178
|
+
reg.load();
|
|
29179
|
+
const existingEntry = reg.getByRoot(root);
|
|
28254
29180
|
const ctx = createInstanceContext({
|
|
28255
|
-
id:
|
|
29181
|
+
id: existingEntry?.id ?? randomUUID5(),
|
|
28256
29182
|
root,
|
|
28257
29183
|
isGlobal: root === getGlobalRoot()
|
|
28258
29184
|
});
|
|
@@ -28450,10 +29376,13 @@ Press Ctrl+C to detach.
|
|
|
28450
29376
|
// src/cli/commands/remote.ts
|
|
28451
29377
|
init_api_client();
|
|
28452
29378
|
init_instance_registry();
|
|
29379
|
+
init_output();
|
|
28453
29380
|
import path61 from "path";
|
|
28454
29381
|
import os29 from "os";
|
|
28455
29382
|
import qrcode from "qrcode-terminal";
|
|
28456
29383
|
async function cmdRemote(args2, instanceRoot) {
|
|
29384
|
+
const json = isJsonMode(args2);
|
|
29385
|
+
if (json) await muteForJson();
|
|
28457
29386
|
const role = extractFlag(args2, "--role") ?? "admin";
|
|
28458
29387
|
const expire = extractFlag(args2, "--expire") ?? "24h";
|
|
28459
29388
|
const scopesRaw = extractFlag(args2, "--scopes");
|
|
@@ -28469,6 +29398,7 @@ async function cmdRemote(args2, instanceRoot) {
|
|
|
28469
29398
|
await registry.load();
|
|
28470
29399
|
const entry = registry.get(instanceId);
|
|
28471
29400
|
if (!entry) {
|
|
29401
|
+
if (json) jsonError(ErrorCodes.INSTANCE_NOT_FOUND, `Workspace "${instanceId}" not found. Run "openacp status" to see workspaces.`);
|
|
28472
29402
|
console.error(`Workspace "${instanceId}" not found. Run "openacp status" to see workspaces.`);
|
|
28473
29403
|
process.exit(1);
|
|
28474
29404
|
}
|
|
@@ -28476,21 +29406,26 @@ async function cmdRemote(args2, instanceRoot) {
|
|
|
28476
29406
|
}
|
|
28477
29407
|
const port = readApiPort(void 0, resolvedInstanceRoot2);
|
|
28478
29408
|
if (port === null) {
|
|
29409
|
+
if (json) jsonError(ErrorCodes.DAEMON_NOT_RUNNING, "OpenACP is not running. Start with `openacp start`");
|
|
28479
29410
|
console.error("OpenACP is not running. Start with `openacp start`");
|
|
28480
29411
|
process.exit(1);
|
|
28481
29412
|
}
|
|
28482
29413
|
try {
|
|
28483
29414
|
const healthRes = await apiCall(port, "/api/v1/system/health", void 0, resolvedInstanceRoot2);
|
|
28484
29415
|
if (!healthRes.ok) {
|
|
29416
|
+
if (json) jsonError(ErrorCodes.API_ERROR, "API server is not responding. Try restarting with `openacp restart`");
|
|
28485
29417
|
console.error("API server is not responding. Try restarting with `openacp restart`");
|
|
28486
29418
|
process.exit(1);
|
|
28487
29419
|
}
|
|
28488
|
-
} catch {
|
|
29420
|
+
} catch (err) {
|
|
29421
|
+
if (err instanceof Error && err.message.startsWith("process.exit")) throw err;
|
|
29422
|
+
if (json) jsonError(ErrorCodes.API_ERROR, "Cannot connect to API server. Is OpenACP running?");
|
|
28489
29423
|
console.error("Cannot connect to API server. Is OpenACP running?");
|
|
28490
29424
|
process.exit(1);
|
|
28491
29425
|
}
|
|
28492
29426
|
const secret = readApiSecret(void 0, resolvedInstanceRoot2);
|
|
28493
29427
|
if (!secret) {
|
|
29428
|
+
if (json) jsonError(ErrorCodes.API_ERROR, "Cannot read API secret. Make sure OpenACP is running with the API server enabled.");
|
|
28494
29429
|
console.error("Cannot read API secret. Make sure OpenACP is running with the API server enabled.");
|
|
28495
29430
|
process.exit(1);
|
|
28496
29431
|
}
|
|
@@ -28512,11 +29447,14 @@ async function cmdRemote(args2, instanceRoot) {
|
|
|
28512
29447
|
}, resolvedInstanceRoot2);
|
|
28513
29448
|
if (!res.ok) {
|
|
28514
29449
|
const err = await res.json();
|
|
29450
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `Failed to generate code: ${err.error ?? err.message ?? "Unknown error"}`);
|
|
28515
29451
|
console.error(`Failed to generate code: ${err.error ?? err.message ?? "Unknown error"}`);
|
|
28516
29452
|
process.exit(1);
|
|
28517
29453
|
}
|
|
28518
29454
|
codeData = await res.json();
|
|
28519
29455
|
} catch (err) {
|
|
29456
|
+
if (err instanceof Error && err.message.startsWith("process.exit")) throw err;
|
|
29457
|
+
if (json) jsonError(ErrorCodes.API_ERROR, `Failed to generate code: ${err.message}`);
|
|
28520
29458
|
console.error(`Failed to generate code: ${err.message}`);
|
|
28521
29459
|
process.exit(1);
|
|
28522
29460
|
}
|
|
@@ -28538,6 +29476,19 @@ async function cmdRemote(args2, instanceRoot) {
|
|
|
28538
29476
|
const tunnelLink = tunnelUrl ? `${tunnelUrl}?code=${code}` : null;
|
|
28539
29477
|
const appLink = tunnelUrl ? `openacp://connect?host=${new URL(tunnelUrl).host}&code=${code}` : null;
|
|
28540
29478
|
const expireDisplay = expiresAt;
|
|
29479
|
+
if (json) {
|
|
29480
|
+
jsonSuccess({
|
|
29481
|
+
code,
|
|
29482
|
+
name: tokenName,
|
|
29483
|
+
role,
|
|
29484
|
+
expiresAt,
|
|
29485
|
+
urls: {
|
|
29486
|
+
local: localUrl,
|
|
29487
|
+
tunnel: tunnelLink ?? void 0,
|
|
29488
|
+
app: appLink ?? void 0
|
|
29489
|
+
}
|
|
29490
|
+
});
|
|
29491
|
+
}
|
|
28541
29492
|
const W = 64;
|
|
28542
29493
|
const line = "\u2500".repeat(W - 4);
|
|
28543
29494
|
console.log("");
|
|
@@ -28578,6 +29529,7 @@ function extractFlag(args2, flag) {
|
|
|
28578
29529
|
}
|
|
28579
29530
|
|
|
28580
29531
|
// src/cli/commands/setup.ts
|
|
29532
|
+
init_output();
|
|
28581
29533
|
import * as fs51 from "fs";
|
|
28582
29534
|
import * as path62 from "path";
|
|
28583
29535
|
function parseFlag(args2, flag) {
|
|
@@ -28588,29 +29540,21 @@ async function cmdSetup(args2, instanceRoot) {
|
|
|
28588
29540
|
const workspace = parseFlag(args2, "--workspace");
|
|
28589
29541
|
const agentRaw = parseFlag(args2, "--agent");
|
|
28590
29542
|
const json = args2.includes("--json");
|
|
29543
|
+
if (json) await muteForJson();
|
|
28591
29544
|
if (!workspace) {
|
|
28592
|
-
if (json)
|
|
28593
|
-
|
|
28594
|
-
} else {
|
|
28595
|
-
console.error(" Error: --workspace <path> is required");
|
|
28596
|
-
}
|
|
29545
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "--workspace is required");
|
|
29546
|
+
console.error(" Error: --workspace <path> is required");
|
|
28597
29547
|
process.exit(1);
|
|
28598
29548
|
}
|
|
28599
29549
|
if (!agentRaw) {
|
|
28600
|
-
if (json)
|
|
28601
|
-
|
|
28602
|
-
} else {
|
|
28603
|
-
console.error(" Error: --agent <name> is required");
|
|
28604
|
-
}
|
|
29550
|
+
if (json) jsonError(ErrorCodes.MISSING_ARGUMENT, "--agent is required");
|
|
29551
|
+
console.error(" Error: --agent <name> is required");
|
|
28605
29552
|
process.exit(1);
|
|
28606
29553
|
}
|
|
28607
29554
|
const rawRunMode = parseFlag(args2, "--run-mode") ?? "daemon";
|
|
28608
29555
|
if (rawRunMode !== "daemon" && rawRunMode !== "foreground") {
|
|
28609
|
-
if (json)
|
|
28610
|
-
|
|
28611
|
-
} else {
|
|
28612
|
-
console.error(` Error: --run-mode must be 'daemon' or 'foreground'`);
|
|
28613
|
-
}
|
|
29556
|
+
if (json) jsonError(ErrorCodes.CONFIG_INVALID, `--run-mode must be 'daemon' or 'foreground'`);
|
|
29557
|
+
console.error(` Error: --run-mode must be 'daemon' or 'foreground'`);
|
|
28614
29558
|
process.exit(1);
|
|
28615
29559
|
}
|
|
28616
29560
|
const runMode = rawRunMode;
|
|
@@ -28639,7 +29583,7 @@ async function cmdSetup(args2, instanceRoot) {
|
|
|
28639
29583
|
fs51.mkdirSync(instanceRoot, { recursive: true });
|
|
28640
29584
|
fs51.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
28641
29585
|
if (json) {
|
|
28642
|
-
|
|
29586
|
+
jsonSuccess({ configPath });
|
|
28643
29587
|
} else {
|
|
28644
29588
|
console.log(`
|
|
28645
29589
|
\x1B[32m\u2713 Setup complete.\x1B[0m Config written to ${configPath}
|
|
@@ -28698,8 +29642,8 @@ resolvedInstanceRoot = resolveInstanceRoot({
|
|
|
28698
29642
|
var noInstanceCommands = {
|
|
28699
29643
|
"--help": async () => printHelp(),
|
|
28700
29644
|
"-h": async () => printHelp(),
|
|
28701
|
-
"--version": () => cmdVersion(),
|
|
28702
|
-
"-v": () => cmdVersion(),
|
|
29645
|
+
"--version": () => cmdVersion(args),
|
|
29646
|
+
"-v": () => cmdVersion(args),
|
|
28703
29647
|
"update": () => cmdUpdate(args),
|
|
28704
29648
|
"adopt": () => cmdAdopt(args),
|
|
28705
29649
|
"integrate": () => cmdIntegrate(args),
|
|
@@ -28725,7 +29669,8 @@ async function main() {
|
|
|
28725
29669
|
const registry = new InstanceRegistry2(path64.join(getGlobal(), "instances.json"));
|
|
28726
29670
|
await registry.load();
|
|
28727
29671
|
const entry = registry.getByRoot(envRoot);
|
|
28728
|
-
const
|
|
29672
|
+
const { randomUUID: randomUUID6 } = await import("crypto");
|
|
29673
|
+
const id = entry?.id ?? randomUUID6();
|
|
28729
29674
|
const ctx = createInstanceContext2({
|
|
28730
29675
|
id,
|
|
28731
29676
|
root: envRoot,
|