@openacp/cli 2026.41.1 → 2026.41.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 +1086 -493
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +17 -35
- package/dist/index.js +112 -146
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -833,9 +833,7 @@ Register with \`ctx.registerMiddleware(hook, { priority?, handler })\`. Return \
|
|
|
833
833
|
- \`session:afterDestroy\` \u2014 after session destroyed (sessionId, reason, durationMs, promptCount)
|
|
834
834
|
|
|
835
835
|
### Control
|
|
836
|
-
- \`mode:beforeChange\` \u2014 before mode change (sessionId, fromMode, toMode)
|
|
837
836
|
- \`config:beforeChange\` \u2014 before config change (sessionId, configId, oldValue, newValue)
|
|
838
|
-
- \`model:beforeChange\` \u2014 before model change (sessionId, fromModel, toModel)
|
|
839
837
|
- \`agent:beforeCancel\` \u2014 before agent cancellation (sessionId, reason)
|
|
840
838
|
- \`agent:beforeSwitch\` \u2014 **blocking** before agent switch (sessionId, fromAgent, toAgent). Return null/false to block.
|
|
841
839
|
- \`agent:afterSwitch\` \u2014 **fire-and-forget** after agent switch (sessionId, fromAgent, toAgent, resumed). Observational only.
|
|
@@ -3136,10 +3134,6 @@ var init_history_recorder = __esm({
|
|
|
3136
3134
|
steps.push(step2);
|
|
3137
3135
|
break;
|
|
3138
3136
|
}
|
|
3139
|
-
case "current_mode_update": {
|
|
3140
|
-
steps.push({ type: "mode_change", modeId: event.modeId });
|
|
3141
|
-
break;
|
|
3142
|
-
}
|
|
3143
3137
|
case "config_option_update": {
|
|
3144
3138
|
for (const opt of event.options) {
|
|
3145
3139
|
steps.push({
|
|
@@ -4570,7 +4564,7 @@ var init_cloudflare = __esm({
|
|
|
4570
4564
|
settle(() => reject(new Error("Cloudflare tunnel timed out after 30s")));
|
|
4571
4565
|
}, 3e4);
|
|
4572
4566
|
try {
|
|
4573
|
-
this.child = spawn(binaryPath, args2, { stdio: ["ignore", "pipe", "pipe"] });
|
|
4567
|
+
this.child = spawn(binaryPath, args2, { stdio: ["ignore", "pipe", "pipe"], detached: true });
|
|
4574
4568
|
} catch {
|
|
4575
4569
|
clearTimeout(timeout);
|
|
4576
4570
|
settle(() => reject(new Error(`Failed to start cloudflared at ${binaryPath}`)));
|
|
@@ -4606,11 +4600,16 @@ var init_cloudflare = __esm({
|
|
|
4606
4600
|
});
|
|
4607
4601
|
});
|
|
4608
4602
|
}
|
|
4609
|
-
async stop() {
|
|
4603
|
+
async stop(force = false) {
|
|
4610
4604
|
const child = this.child;
|
|
4611
4605
|
if (!child) return;
|
|
4612
4606
|
this.child = null;
|
|
4613
4607
|
this.exitCallback = null;
|
|
4608
|
+
if (force) {
|
|
4609
|
+
child.kill("SIGKILL");
|
|
4610
|
+
log3.info("Cloudflare tunnel force-killed");
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4614
4613
|
child.kill("SIGTERM");
|
|
4615
4614
|
const exited = await Promise.race([
|
|
4616
4615
|
new Promise((resolve8) => child.on("exit", () => resolve8(true))),
|
|
@@ -4679,7 +4678,7 @@ var init_ngrok = __esm({
|
|
|
4679
4678
|
settle(() => reject(new Error("ngrok tunnel timed out after 30s. Is ngrok installed?")));
|
|
4680
4679
|
}, 3e4);
|
|
4681
4680
|
try {
|
|
4682
|
-
this.child = spawn2("ngrok", args2, { stdio: ["ignore", "pipe", "pipe"] });
|
|
4681
|
+
this.child = spawn2("ngrok", args2, { stdio: ["ignore", "pipe", "pipe"], detached: true });
|
|
4683
4682
|
} catch {
|
|
4684
4683
|
clearTimeout(timeout);
|
|
4685
4684
|
settle(() => reject(new Error(
|
|
@@ -4719,11 +4718,16 @@ var init_ngrok = __esm({
|
|
|
4719
4718
|
});
|
|
4720
4719
|
});
|
|
4721
4720
|
}
|
|
4722
|
-
async stop() {
|
|
4721
|
+
async stop(force = false) {
|
|
4723
4722
|
const child = this.child;
|
|
4724
4723
|
if (!child) return;
|
|
4725
4724
|
this.child = null;
|
|
4726
4725
|
this.exitCallback = null;
|
|
4726
|
+
if (force) {
|
|
4727
|
+
child.kill("SIGKILL");
|
|
4728
|
+
log4.info("ngrok tunnel force-killed");
|
|
4729
|
+
return;
|
|
4730
|
+
}
|
|
4727
4731
|
child.kill("SIGTERM");
|
|
4728
4732
|
const exited = await Promise.race([
|
|
4729
4733
|
new Promise((resolve8) => child.on("exit", () => resolve8(true))),
|
|
@@ -4784,7 +4788,7 @@ var init_bore = __esm({
|
|
|
4784
4788
|
settle(() => reject(new Error("Bore tunnel timed out after 30s. Is bore installed?")));
|
|
4785
4789
|
}, 3e4);
|
|
4786
4790
|
try {
|
|
4787
|
-
this.child = spawn3("bore", args2, { stdio: ["ignore", "pipe", "pipe"] });
|
|
4791
|
+
this.child = spawn3("bore", args2, { stdio: ["ignore", "pipe", "pipe"], detached: true });
|
|
4788
4792
|
} catch {
|
|
4789
4793
|
clearTimeout(timeout);
|
|
4790
4794
|
settle(() => reject(new Error(
|
|
@@ -4824,11 +4828,16 @@ var init_bore = __esm({
|
|
|
4824
4828
|
});
|
|
4825
4829
|
});
|
|
4826
4830
|
}
|
|
4827
|
-
async stop() {
|
|
4831
|
+
async stop(force = false) {
|
|
4828
4832
|
const child = this.child;
|
|
4829
4833
|
if (!child) return;
|
|
4830
4834
|
this.child = null;
|
|
4831
4835
|
this.exitCallback = null;
|
|
4836
|
+
if (force) {
|
|
4837
|
+
child.kill("SIGKILL");
|
|
4838
|
+
log5.info("Bore tunnel force-killed");
|
|
4839
|
+
return;
|
|
4840
|
+
}
|
|
4832
4841
|
child.kill("SIGTERM");
|
|
4833
4842
|
const exited = await Promise.race([
|
|
4834
4843
|
new Promise((resolve8) => child.on("exit", () => resolve8(true))),
|
|
@@ -4894,7 +4903,7 @@ var init_tailscale = __esm({
|
|
|
4894
4903
|
settle(() => reject(new Error("Tailscale funnel timed out after 30s. Is tailscale installed?")));
|
|
4895
4904
|
}, 3e4);
|
|
4896
4905
|
try {
|
|
4897
|
-
this.child = spawn4("tailscale", args2, { stdio: ["ignore", "pipe", "pipe"] });
|
|
4906
|
+
this.child = spawn4("tailscale", args2, { stdio: ["ignore", "pipe", "pipe"], detached: true });
|
|
4898
4907
|
} catch {
|
|
4899
4908
|
clearTimeout(timeout);
|
|
4900
4909
|
settle(() => reject(new Error(
|
|
@@ -4941,11 +4950,16 @@ var init_tailscale = __esm({
|
|
|
4941
4950
|
});
|
|
4942
4951
|
});
|
|
4943
4952
|
}
|
|
4944
|
-
async stop() {
|
|
4953
|
+
async stop(force = false) {
|
|
4945
4954
|
const child = this.child;
|
|
4946
4955
|
if (!child) return;
|
|
4947
4956
|
this.child = null;
|
|
4948
4957
|
this.exitCallback = null;
|
|
4958
|
+
if (force) {
|
|
4959
|
+
child.kill("SIGKILL");
|
|
4960
|
+
log6.info("Tailscale funnel force-killed");
|
|
4961
|
+
return;
|
|
4962
|
+
}
|
|
4949
4963
|
child.kill("SIGTERM");
|
|
4950
4964
|
const exited = await Promise.race([
|
|
4951
4965
|
new Promise((resolve8) => child.on("exit", () => resolve8(true))),
|
|
@@ -5076,6 +5090,7 @@ var init_tunnel_registry = __esm({
|
|
|
5076
5090
|
const entry = await this.add(port, opts, false);
|
|
5077
5091
|
entry.retryCount = retryCount;
|
|
5078
5092
|
} catch (err) {
|
|
5093
|
+
if (this.shuttingDown) return;
|
|
5079
5094
|
log7.error({ port, err: err.message, retry: retryCount }, "Tunnel retry failed");
|
|
5080
5095
|
const failedEntry = {
|
|
5081
5096
|
port,
|
|
@@ -5146,7 +5161,7 @@ var init_tunnel_registry = __esm({
|
|
|
5146
5161
|
for (const [, live] of this.entries) {
|
|
5147
5162
|
if (live.retryTimer) clearTimeout(live.retryTimer);
|
|
5148
5163
|
if (live.process) {
|
|
5149
|
-
stopPromises.push(live.process.stop().catch(() => {
|
|
5164
|
+
stopPromises.push(live.process.stop(true).catch(() => {
|
|
5150
5165
|
}));
|
|
5151
5166
|
}
|
|
5152
5167
|
}
|
|
@@ -6651,6 +6666,7 @@ async function createApiServer(options) {
|
|
|
6651
6666
|
return { port: Number(url.port), host: url.hostname };
|
|
6652
6667
|
} catch (err) {
|
|
6653
6668
|
if (err?.code === "EADDRINUSE" && attempt < maxRetries && port < 65535) {
|
|
6669
|
+
console.log(`[api-server] Port ${port} in use, trying ${port + 1}...`);
|
|
6654
6670
|
port++;
|
|
6655
6671
|
continue;
|
|
6656
6672
|
}
|
|
@@ -6896,7 +6912,7 @@ var init_service = __esm({
|
|
|
6896
6912
|
|
|
6897
6913
|
// src/plugins/api-server/schemas/sessions.ts
|
|
6898
6914
|
import { z } from "zod";
|
|
6899
|
-
var ListSessionsQuerySchema, CreateSessionBodySchema, AdoptSessionBodySchema, PromptBodySchema, PermissionResponseBodySchema, DangerousModeBodySchema, UpdateSessionBodySchema, SessionIdParamSchema;
|
|
6915
|
+
var ListSessionsQuerySchema, CreateSessionBodySchema, AdoptSessionBodySchema, PromptBodySchema, PermissionResponseBodySchema, DangerousModeBodySchema, UpdateSessionBodySchema, SessionIdParamSchema, ConfigIdParamSchema, SetConfigOptionBodySchema, SetClientOverridesBodySchema;
|
|
6900
6916
|
var init_sessions = __esm({
|
|
6901
6917
|
"src/plugins/api-server/schemas/sessions.ts"() {
|
|
6902
6918
|
"use strict";
|
|
@@ -6935,6 +6951,16 @@ var init_sessions = __esm({
|
|
|
6935
6951
|
SessionIdParamSchema = z.object({
|
|
6936
6952
|
sessionId: z.string().min(1)
|
|
6937
6953
|
});
|
|
6954
|
+
ConfigIdParamSchema = z.object({
|
|
6955
|
+
sessionId: z.string().min(1),
|
|
6956
|
+
configId: z.string().min(1)
|
|
6957
|
+
});
|
|
6958
|
+
SetConfigOptionBodySchema = z.object({
|
|
6959
|
+
value: z.string()
|
|
6960
|
+
});
|
|
6961
|
+
SetClientOverridesBodySchema = z.object({
|
|
6962
|
+
bypassPermissions: z.boolean().optional()
|
|
6963
|
+
});
|
|
6938
6964
|
}
|
|
6939
6965
|
});
|
|
6940
6966
|
|
|
@@ -6954,15 +6980,12 @@ async function sessionRoutes(app, deps) {
|
|
|
6954
6980
|
name: s.name ?? null,
|
|
6955
6981
|
workspace: s.workingDirectory,
|
|
6956
6982
|
createdAt: s.createdAt.toISOString(),
|
|
6957
|
-
dangerousMode: s.
|
|
6983
|
+
dangerousMode: s.clientOverrides.bypassPermissions ?? false,
|
|
6958
6984
|
queueDepth: s.queueDepth,
|
|
6959
6985
|
promptRunning: s.promptRunning,
|
|
6960
6986
|
lastActiveAt: deps.core.sessionManager.getSessionRecord(s.id)?.lastActiveAt ?? null,
|
|
6961
6987
|
// ACP state
|
|
6962
|
-
|
|
6963
|
-
currentModel: s.currentModel ?? null,
|
|
6964
|
-
availableModes: s.availableModes?.length ? s.availableModes : void 0,
|
|
6965
|
-
availableModels: s.availableModels?.length ? s.availableModels : void 0,
|
|
6988
|
+
configOptions: s.configOptions?.length ? s.configOptions : void 0,
|
|
6966
6989
|
capabilities: s.agentCapabilities ?? null
|
|
6967
6990
|
}))
|
|
6968
6991
|
};
|
|
@@ -6989,17 +7012,13 @@ async function sessionRoutes(app, deps) {
|
|
|
6989
7012
|
name: session.name ?? null,
|
|
6990
7013
|
workspace: session.workingDirectory,
|
|
6991
7014
|
createdAt: session.createdAt.toISOString(),
|
|
6992
|
-
dangerousMode: session.
|
|
7015
|
+
dangerousMode: session.clientOverrides.bypassPermissions ?? false,
|
|
6993
7016
|
queueDepth: session.queueDepth,
|
|
6994
7017
|
promptRunning: session.promptRunning,
|
|
6995
7018
|
threadId: session.threadId,
|
|
6996
7019
|
channelId: session.channelId,
|
|
6997
7020
|
agentSessionId: session.agentSessionId,
|
|
6998
7021
|
// ACP state
|
|
6999
|
-
currentMode: session.currentMode ?? null,
|
|
7000
|
-
currentModel: session.currentModel ?? null,
|
|
7001
|
-
availableModes: session.availableModes?.length ? session.availableModes : void 0,
|
|
7002
|
-
availableModels: session.availableModels?.length ? session.availableModels : void 0,
|
|
7003
7022
|
configOptions: session.configOptions?.length ? session.configOptions : void 0,
|
|
7004
7023
|
capabilities: session.agentCapabilities ?? null
|
|
7005
7024
|
}
|
|
@@ -7173,9 +7192,9 @@ async function sessionRoutes(app, deps) {
|
|
|
7173
7192
|
changes.voiceMode = body.voiceMode;
|
|
7174
7193
|
}
|
|
7175
7194
|
if (body.dangerousMode !== void 0) {
|
|
7176
|
-
session.
|
|
7195
|
+
session.clientOverrides.bypassPermissions = body.dangerousMode;
|
|
7177
7196
|
await deps.core.sessionManager.patchRecord(sessionId, {
|
|
7178
|
-
|
|
7197
|
+
clientOverrides: session.clientOverrides
|
|
7179
7198
|
});
|
|
7180
7199
|
changes.dangerousMode = body.dangerousMode;
|
|
7181
7200
|
}
|
|
@@ -7196,13 +7215,101 @@ async function sessionRoutes(app, deps) {
|
|
|
7196
7215
|
);
|
|
7197
7216
|
}
|
|
7198
7217
|
const body = DangerousModeBodySchema.parse(request.body);
|
|
7199
|
-
session.
|
|
7218
|
+
session.clientOverrides.bypassPermissions = body.enabled;
|
|
7200
7219
|
await deps.core.sessionManager.patchRecord(sessionId, {
|
|
7201
|
-
|
|
7220
|
+
clientOverrides: session.clientOverrides
|
|
7202
7221
|
});
|
|
7203
7222
|
return { ok: true, dangerousMode: body.enabled };
|
|
7204
7223
|
}
|
|
7205
7224
|
);
|
|
7225
|
+
app.get(
|
|
7226
|
+
"/:sessionId/config",
|
|
7227
|
+
{ preHandler: requireScopes("sessions:read") },
|
|
7228
|
+
async (request) => {
|
|
7229
|
+
const { sessionId: rawId } = SessionIdParamSchema.parse(request.params);
|
|
7230
|
+
const sessionId = decodeURIComponent(rawId);
|
|
7231
|
+
const session = deps.core.sessionManager.getSession(sessionId);
|
|
7232
|
+
if (!session) {
|
|
7233
|
+
throw new NotFoundError(
|
|
7234
|
+
"SESSION_NOT_FOUND",
|
|
7235
|
+
`Session "${sessionId}" not found`
|
|
7236
|
+
);
|
|
7237
|
+
}
|
|
7238
|
+
return {
|
|
7239
|
+
configOptions: session.configOptions,
|
|
7240
|
+
clientOverrides: session.clientOverrides
|
|
7241
|
+
};
|
|
7242
|
+
}
|
|
7243
|
+
);
|
|
7244
|
+
app.put(
|
|
7245
|
+
"/:sessionId/config/:configId",
|
|
7246
|
+
{ preHandler: requireScopes("sessions:write") },
|
|
7247
|
+
async (request) => {
|
|
7248
|
+
const { sessionId: rawId, configId } = ConfigIdParamSchema.parse(request.params);
|
|
7249
|
+
const sessionId = decodeURIComponent(rawId);
|
|
7250
|
+
const session = deps.core.sessionManager.getSession(sessionId);
|
|
7251
|
+
if (!session) {
|
|
7252
|
+
throw new NotFoundError(
|
|
7253
|
+
"SESSION_NOT_FOUND",
|
|
7254
|
+
`Session "${sessionId}" not found`
|
|
7255
|
+
);
|
|
7256
|
+
}
|
|
7257
|
+
const body = SetConfigOptionBodySchema.parse(request.body);
|
|
7258
|
+
const response = await session.agentInstance.setConfigOption(configId, {
|
|
7259
|
+
type: "select",
|
|
7260
|
+
value: body.value
|
|
7261
|
+
});
|
|
7262
|
+
if (response.configOptions) {
|
|
7263
|
+
await session.updateConfigOptions(response.configOptions);
|
|
7264
|
+
}
|
|
7265
|
+
await deps.core.sessionManager.patchRecord(sessionId, {
|
|
7266
|
+
acpState: session.toAcpStateSnapshot()
|
|
7267
|
+
});
|
|
7268
|
+
return {
|
|
7269
|
+
configOptions: session.configOptions,
|
|
7270
|
+
clientOverrides: session.clientOverrides
|
|
7271
|
+
};
|
|
7272
|
+
}
|
|
7273
|
+
);
|
|
7274
|
+
app.get(
|
|
7275
|
+
"/:sessionId/config/overrides",
|
|
7276
|
+
{ preHandler: requireScopes("sessions:read") },
|
|
7277
|
+
async (request) => {
|
|
7278
|
+
const { sessionId: rawId } = SessionIdParamSchema.parse(request.params);
|
|
7279
|
+
const sessionId = decodeURIComponent(rawId);
|
|
7280
|
+
const session = deps.core.sessionManager.getSession(sessionId);
|
|
7281
|
+
if (!session) {
|
|
7282
|
+
throw new NotFoundError(
|
|
7283
|
+
"SESSION_NOT_FOUND",
|
|
7284
|
+
`Session "${sessionId}" not found`
|
|
7285
|
+
);
|
|
7286
|
+
}
|
|
7287
|
+
return { clientOverrides: session.clientOverrides };
|
|
7288
|
+
}
|
|
7289
|
+
);
|
|
7290
|
+
app.put(
|
|
7291
|
+
"/:sessionId/config/overrides",
|
|
7292
|
+
{ preHandler: requireScopes("sessions:write") },
|
|
7293
|
+
async (request) => {
|
|
7294
|
+
const { sessionId: rawId } = SessionIdParamSchema.parse(request.params);
|
|
7295
|
+
const sessionId = decodeURIComponent(rawId);
|
|
7296
|
+
const session = deps.core.sessionManager.getSession(sessionId);
|
|
7297
|
+
if (!session) {
|
|
7298
|
+
throw new NotFoundError(
|
|
7299
|
+
"SESSION_NOT_FOUND",
|
|
7300
|
+
`Session "${sessionId}" not found`
|
|
7301
|
+
);
|
|
7302
|
+
}
|
|
7303
|
+
const body = SetClientOverridesBodySchema.parse(request.body);
|
|
7304
|
+
if (body.bypassPermissions !== void 0) {
|
|
7305
|
+
session.clientOverrides.bypassPermissions = body.bypassPermissions;
|
|
7306
|
+
}
|
|
7307
|
+
await deps.core.sessionManager.patchRecord(sessionId, {
|
|
7308
|
+
clientOverrides: session.clientOverrides
|
|
7309
|
+
});
|
|
7310
|
+
return { clientOverrides: session.clientOverrides };
|
|
7311
|
+
}
|
|
7312
|
+
);
|
|
7206
7313
|
app.post(
|
|
7207
7314
|
"/:sessionId/archive",
|
|
7208
7315
|
{ preHandler: requireScopes("sessions:write") },
|
|
@@ -7349,28 +7456,28 @@ import path21 from "path";
|
|
|
7349
7456
|
import fs17 from "fs";
|
|
7350
7457
|
import os10 from "os";
|
|
7351
7458
|
function createInstanceContext(opts) {
|
|
7352
|
-
const { id, root
|
|
7459
|
+
const { id, root, isGlobal } = opts;
|
|
7353
7460
|
return {
|
|
7354
7461
|
id,
|
|
7355
|
-
root
|
|
7462
|
+
root,
|
|
7356
7463
|
isGlobal,
|
|
7357
7464
|
paths: {
|
|
7358
|
-
config: path21.join(
|
|
7359
|
-
sessions: path21.join(
|
|
7360
|
-
agents: path21.join(
|
|
7361
|
-
registryCache: path21.join(
|
|
7362
|
-
plugins: path21.join(
|
|
7363
|
-
pluginsData: path21.join(
|
|
7364
|
-
pluginRegistry: path21.join(
|
|
7365
|
-
logs: path21.join(
|
|
7366
|
-
pid: path21.join(
|
|
7367
|
-
running: path21.join(
|
|
7368
|
-
apiPort: path21.join(
|
|
7369
|
-
apiSecret: path21.join(
|
|
7370
|
-
bin: path21.join(
|
|
7371
|
-
cache: path21.join(
|
|
7372
|
-
tunnels: path21.join(
|
|
7373
|
-
agentsDir: path21.join(
|
|
7465
|
+
config: path21.join(root, "config.json"),
|
|
7466
|
+
sessions: path21.join(root, "sessions.json"),
|
|
7467
|
+
agents: path21.join(root, "agents.json"),
|
|
7468
|
+
registryCache: path21.join(root, "registry-cache.json"),
|
|
7469
|
+
plugins: path21.join(root, "plugins"),
|
|
7470
|
+
pluginsData: path21.join(root, "plugins", "data"),
|
|
7471
|
+
pluginRegistry: path21.join(root, "plugins.json"),
|
|
7472
|
+
logs: path21.join(root, "logs"),
|
|
7473
|
+
pid: path21.join(root, "openacp.pid"),
|
|
7474
|
+
running: path21.join(root, "running"),
|
|
7475
|
+
apiPort: path21.join(root, "api.port"),
|
|
7476
|
+
apiSecret: path21.join(root, "api-secret"),
|
|
7477
|
+
bin: path21.join(root, "bin"),
|
|
7478
|
+
cache: path21.join(root, "cache"),
|
|
7479
|
+
tunnels: path21.join(root, "tunnels.json"),
|
|
7480
|
+
agentsDir: path21.join(root, "agents")
|
|
7374
7481
|
}
|
|
7375
7482
|
};
|
|
7376
7483
|
}
|
|
@@ -7412,22 +7519,22 @@ __export(config_registry_exports, {
|
|
|
7412
7519
|
});
|
|
7413
7520
|
import * as fs18 from "fs";
|
|
7414
7521
|
import * as path22 from "path";
|
|
7415
|
-
function getFieldDef(
|
|
7416
|
-
return CONFIG_REGISTRY.find((f) => f.path ===
|
|
7522
|
+
function getFieldDef(path65) {
|
|
7523
|
+
return CONFIG_REGISTRY.find((f) => f.path === path65);
|
|
7417
7524
|
}
|
|
7418
7525
|
function getSafeFields() {
|
|
7419
7526
|
return CONFIG_REGISTRY.filter((f) => f.scope === "safe");
|
|
7420
7527
|
}
|
|
7421
|
-
function isHotReloadable(
|
|
7422
|
-
const def = getFieldDef(
|
|
7528
|
+
function isHotReloadable(path65) {
|
|
7529
|
+
const def = getFieldDef(path65);
|
|
7423
7530
|
return def?.hotReload ?? false;
|
|
7424
7531
|
}
|
|
7425
7532
|
function resolveOptions(def, config) {
|
|
7426
7533
|
if (!def.options) return void 0;
|
|
7427
7534
|
return typeof def.options === "function" ? def.options(config) : def.options;
|
|
7428
7535
|
}
|
|
7429
|
-
function getConfigValue(config,
|
|
7430
|
-
const parts =
|
|
7536
|
+
function getConfigValue(config, path65) {
|
|
7537
|
+
const parts = path65.split(".");
|
|
7431
7538
|
let current = config;
|
|
7432
7539
|
for (const part of parts) {
|
|
7433
7540
|
if (current && typeof current === "object" && part in current) {
|
|
@@ -8392,14 +8499,14 @@ async function commandRoutes(app, deps) {
|
|
|
8392
8499
|
if (!deps.commandRegistry) {
|
|
8393
8500
|
return { commands: [] };
|
|
8394
8501
|
}
|
|
8395
|
-
const
|
|
8502
|
+
const commands = deps.commandRegistry.getAll().map((cmd) => ({
|
|
8396
8503
|
name: cmd.name,
|
|
8397
8504
|
description: cmd.description,
|
|
8398
8505
|
usage: cmd.usage ?? null,
|
|
8399
8506
|
category: cmd.category,
|
|
8400
8507
|
pluginName: cmd.pluginName ?? null
|
|
8401
8508
|
}));
|
|
8402
|
-
return { commands
|
|
8509
|
+
return { commands };
|
|
8403
8510
|
});
|
|
8404
8511
|
app.post("/execute", { preHandler: requireScopes("commands:execute") }, async (request, reply) => {
|
|
8405
8512
|
if (!deps.commandRegistry) {
|
|
@@ -8628,7 +8735,7 @@ function createApiServerPlugin() {
|
|
|
8628
8735
|
version: "1.0.0",
|
|
8629
8736
|
description: "REST API + SSE streaming server",
|
|
8630
8737
|
essential: false,
|
|
8631
|
-
permissions: ["services:register", "kernel:access", "events:read"],
|
|
8738
|
+
permissions: ["services:register", "services:use", "kernel:access", "events:read"],
|
|
8632
8739
|
async install(ctx) {
|
|
8633
8740
|
const { settings, legacyConfig, terminal } = ctx;
|
|
8634
8741
|
if (legacyConfig) {
|
|
@@ -8695,6 +8802,11 @@ function createApiServerPlugin() {
|
|
|
8695
8802
|
port: config.port ?? 0,
|
|
8696
8803
|
host: config.host ?? "127.0.0.1"
|
|
8697
8804
|
};
|
|
8805
|
+
console.log(`[api-server] setup() called \u2014 port=${apiConfig.port}, host=${apiConfig.host}, instanceRoot=${instanceRoot}`);
|
|
8806
|
+
log13.info(
|
|
8807
|
+
{ port: apiConfig.port, host: apiConfig.host, instanceRoot },
|
|
8808
|
+
"API server plugin setup \u2014 config loaded"
|
|
8809
|
+
);
|
|
8698
8810
|
portFilePath = path25.join(instanceRoot, "api.port");
|
|
8699
8811
|
const secretFilePath = path25.join(instanceRoot, "api-secret");
|
|
8700
8812
|
const jwtSecretFilePath = path25.join(instanceRoot, "jwt-secret");
|
|
@@ -8791,14 +8903,21 @@ function createApiServerPlugin() {
|
|
|
8791
8903
|
ctx.registerService("api-server", apiService);
|
|
8792
8904
|
cleanupInterval = setInterval(() => tokenStore.cleanup(), 60 * 60 * 1e3);
|
|
8793
8905
|
ctx.on("system:ready", async () => {
|
|
8906
|
+
console.log(`[api-server] system:ready fired \u2014 starting server on ${apiConfig.host}:${apiConfig.port}`);
|
|
8907
|
+
log13.info(
|
|
8908
|
+
{ configPort: apiConfig.port, configHost: apiConfig.host },
|
|
8909
|
+
"API server starting..."
|
|
8910
|
+
);
|
|
8794
8911
|
try {
|
|
8795
8912
|
const addr = await server.start();
|
|
8796
8913
|
actualPort = addr.port;
|
|
8797
8914
|
writePortFile(portFilePath, actualPort);
|
|
8798
8915
|
sseManager.setup();
|
|
8799
8916
|
log13.info(
|
|
8800
|
-
{ host: addr.host, port: addr.port },
|
|
8801
|
-
"API server listening"
|
|
8917
|
+
{ host: addr.host, port: addr.port, portFile: portFilePath },
|
|
8918
|
+
"API server listening on http://%s:%d",
|
|
8919
|
+
addr.host,
|
|
8920
|
+
addr.port
|
|
8802
8921
|
);
|
|
8803
8922
|
if (apiConfig.host !== "127.0.0.1" && apiConfig.host !== "localhost") {
|
|
8804
8923
|
log13.warn(
|
|
@@ -8806,7 +8925,7 @@ function createApiServerPlugin() {
|
|
|
8806
8925
|
);
|
|
8807
8926
|
}
|
|
8808
8927
|
} catch (err) {
|
|
8809
|
-
|
|
8928
|
+
log13.error({ err, configPort: apiConfig.port, configHost: apiConfig.host }, "API server failed to start");
|
|
8810
8929
|
}
|
|
8811
8930
|
});
|
|
8812
8931
|
},
|
|
@@ -9266,7 +9385,7 @@ var init_sse_adapter = __esm({
|
|
|
9266
9385
|
"@openacp/security": "^1.0.0",
|
|
9267
9386
|
"@openacp/notifications": "^1.0.0"
|
|
9268
9387
|
},
|
|
9269
|
-
permissions: ["services:register", "kernel:access", "events:read"],
|
|
9388
|
+
permissions: ["services:register", "services:use", "kernel:access", "events:read"],
|
|
9270
9389
|
async setup(ctx) {
|
|
9271
9390
|
const core = ctx.core;
|
|
9272
9391
|
const apiServer = ctx.getService("api-server");
|
|
@@ -9627,8 +9746,8 @@ function formatToolSummary(name, rawInput, displaySummary) {
|
|
|
9627
9746
|
}
|
|
9628
9747
|
if (lowerName === "grep") {
|
|
9629
9748
|
const pattern = args2.pattern ?? "";
|
|
9630
|
-
const
|
|
9631
|
-
return pattern ? `\u{1F50D} Grep "${pattern}"${
|
|
9749
|
+
const path65 = args2.path ?? "";
|
|
9750
|
+
return pattern ? `\u{1F50D} Grep "${pattern}"${path65 ? ` in ${path65}` : ""}` : `\u{1F527} ${name}`;
|
|
9632
9751
|
}
|
|
9633
9752
|
if (lowerName === "glob") {
|
|
9634
9753
|
const pattern = args2.pattern ?? "";
|
|
@@ -9662,8 +9781,8 @@ function formatToolTitle(name, rawInput, displayTitle) {
|
|
|
9662
9781
|
}
|
|
9663
9782
|
if (lowerName === "grep") {
|
|
9664
9783
|
const pattern = args2.pattern ?? "";
|
|
9665
|
-
const
|
|
9666
|
-
return pattern ? `"${pattern}"${
|
|
9784
|
+
const path65 = args2.path ?? "";
|
|
9785
|
+
return pattern ? `"${pattern}"${path65 ? ` in ${path65}` : ""}` : name;
|
|
9667
9786
|
}
|
|
9668
9787
|
if (lowerName === "glob") {
|
|
9669
9788
|
return String(args2.pattern ?? name);
|
|
@@ -9951,14 +10070,15 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
9951
10070
|
const sessionId = ctx.callbackQuery.data.slice(2);
|
|
9952
10071
|
const session = core.sessionManager.getSession(sessionId);
|
|
9953
10072
|
if (session) {
|
|
9954
|
-
|
|
10073
|
+
const newDangerousMode2 = !session.clientOverrides.bypassPermissions;
|
|
10074
|
+
session.clientOverrides.bypassPermissions = newDangerousMode2;
|
|
9955
10075
|
log14.info(
|
|
9956
|
-
{ sessionId, dangerousMode:
|
|
10076
|
+
{ sessionId, dangerousMode: newDangerousMode2 },
|
|
9957
10077
|
"Dangerous mode toggled via button"
|
|
9958
10078
|
);
|
|
9959
|
-
core.sessionManager.patchRecord(sessionId, {
|
|
10079
|
+
core.sessionManager.patchRecord(sessionId, { clientOverrides: session.clientOverrides }).catch(() => {
|
|
9960
10080
|
});
|
|
9961
|
-
const toastText2 =
|
|
10081
|
+
const toastText2 = newDangerousMode2 ? "\u2620\uFE0F Dangerous mode enabled \u2014 permissions auto-approved" : "\u{1F510} Dangerous mode disabled \u2014 permissions shown normally";
|
|
9962
10082
|
try {
|
|
9963
10083
|
await ctx.answerCallbackQuery({ text: toastText2 });
|
|
9964
10084
|
} catch {
|
|
@@ -9967,7 +10087,7 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
9967
10087
|
await ctx.editMessageReplyMarkup({
|
|
9968
10088
|
reply_markup: buildSessionControlKeyboard(
|
|
9969
10089
|
sessionId,
|
|
9970
|
-
|
|
10090
|
+
newDangerousMode2,
|
|
9971
10091
|
session.voiceMode === "on"
|
|
9972
10092
|
)
|
|
9973
10093
|
});
|
|
@@ -9985,8 +10105,8 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
9985
10105
|
}
|
|
9986
10106
|
return;
|
|
9987
10107
|
}
|
|
9988
|
-
const newDangerousMode = !(record.dangerousMode ?? false);
|
|
9989
|
-
core.sessionManager.patchRecord(sessionId, {
|
|
10108
|
+
const newDangerousMode = !(record.clientOverrides?.bypassPermissions ?? record.dangerousMode ?? false);
|
|
10109
|
+
core.sessionManager.patchRecord(sessionId, { clientOverrides: { bypassPermissions: newDangerousMode } }).catch(() => {
|
|
9990
10110
|
});
|
|
9991
10111
|
log14.info(
|
|
9992
10112
|
{ sessionId, dangerousMode: newDangerousMode },
|
|
@@ -10017,19 +10137,19 @@ async function handleEnableDangerous(ctx, core) {
|
|
|
10017
10137
|
});
|
|
10018
10138
|
return;
|
|
10019
10139
|
}
|
|
10020
|
-
const session = core.
|
|
10140
|
+
const session = await core.getOrResumeSession(
|
|
10021
10141
|
"telegram",
|
|
10022
10142
|
String(threadId)
|
|
10023
10143
|
);
|
|
10024
10144
|
if (session) {
|
|
10025
|
-
if (session.
|
|
10145
|
+
if (session.clientOverrides.bypassPermissions) {
|
|
10026
10146
|
await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", {
|
|
10027
10147
|
parse_mode: "HTML"
|
|
10028
10148
|
});
|
|
10029
10149
|
return;
|
|
10030
10150
|
}
|
|
10031
|
-
session.
|
|
10032
|
-
core.sessionManager.patchRecord(session.id, {
|
|
10151
|
+
session.clientOverrides.bypassPermissions = true;
|
|
10152
|
+
core.sessionManager.patchRecord(session.id, { clientOverrides: session.clientOverrides }).catch(() => {
|
|
10033
10153
|
});
|
|
10034
10154
|
} else {
|
|
10035
10155
|
const record = core.sessionManager.getRecordByThread(
|
|
@@ -10042,13 +10162,13 @@ async function handleEnableDangerous(ctx, core) {
|
|
|
10042
10162
|
});
|
|
10043
10163
|
return;
|
|
10044
10164
|
}
|
|
10045
|
-
if (record.dangerousMode) {
|
|
10165
|
+
if (record.clientOverrides?.bypassPermissions ?? record.dangerousMode) {
|
|
10046
10166
|
await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", {
|
|
10047
10167
|
parse_mode: "HTML"
|
|
10048
10168
|
});
|
|
10049
10169
|
return;
|
|
10050
10170
|
}
|
|
10051
|
-
core.sessionManager.patchRecord(record.sessionId, {
|
|
10171
|
+
core.sessionManager.patchRecord(record.sessionId, { clientOverrides: { bypassPermissions: true } }).catch(() => {
|
|
10052
10172
|
});
|
|
10053
10173
|
}
|
|
10054
10174
|
await ctx.reply(
|
|
@@ -10068,19 +10188,19 @@ async function handleDisableDangerous(ctx, core) {
|
|
|
10068
10188
|
});
|
|
10069
10189
|
return;
|
|
10070
10190
|
}
|
|
10071
|
-
const session = core.
|
|
10191
|
+
const session = await core.getOrResumeSession(
|
|
10072
10192
|
"telegram",
|
|
10073
10193
|
String(threadId)
|
|
10074
10194
|
);
|
|
10075
10195
|
if (session) {
|
|
10076
|
-
if (!session.
|
|
10196
|
+
if (!session.clientOverrides.bypassPermissions) {
|
|
10077
10197
|
await ctx.reply("\u{1F510} Dangerous mode is already disabled.", {
|
|
10078
10198
|
parse_mode: "HTML"
|
|
10079
10199
|
});
|
|
10080
10200
|
return;
|
|
10081
10201
|
}
|
|
10082
|
-
session.
|
|
10083
|
-
core.sessionManager.patchRecord(session.id, {
|
|
10202
|
+
session.clientOverrides.bypassPermissions = false;
|
|
10203
|
+
core.sessionManager.patchRecord(session.id, { clientOverrides: session.clientOverrides }).catch(() => {
|
|
10084
10204
|
});
|
|
10085
10205
|
} else {
|
|
10086
10206
|
const record = core.sessionManager.getRecordByThread(
|
|
@@ -10093,13 +10213,13 @@ async function handleDisableDangerous(ctx, core) {
|
|
|
10093
10213
|
});
|
|
10094
10214
|
return;
|
|
10095
10215
|
}
|
|
10096
|
-
if (!record.dangerousMode) {
|
|
10216
|
+
if (!(record.clientOverrides?.bypassPermissions ?? record.dangerousMode)) {
|
|
10097
10217
|
await ctx.reply("\u{1F510} Dangerous mode is already disabled.", {
|
|
10098
10218
|
parse_mode: "HTML"
|
|
10099
10219
|
});
|
|
10100
10220
|
return;
|
|
10101
10221
|
}
|
|
10102
|
-
core.sessionManager.patchRecord(record.sessionId, {
|
|
10222
|
+
core.sessionManager.patchRecord(record.sessionId, { clientOverrides: { bypassPermissions: false } }).catch(() => {
|
|
10103
10223
|
});
|
|
10104
10224
|
}
|
|
10105
10225
|
await ctx.reply(
|
|
@@ -10149,7 +10269,7 @@ function setupTTSCallbacks(bot, core) {
|
|
|
10149
10269
|
await ctx.editMessageReplyMarkup({
|
|
10150
10270
|
reply_markup: buildSessionControlKeyboard(
|
|
10151
10271
|
sessionId,
|
|
10152
|
-
session.
|
|
10272
|
+
session.clientOverrides.bypassPermissions ?? false,
|
|
10153
10273
|
newMode === "on"
|
|
10154
10274
|
)
|
|
10155
10275
|
});
|
|
@@ -10213,7 +10333,7 @@ async function handleOutputMode(ctx, core) {
|
|
|
10213
10333
|
await ctx.reply("\u26A0\uFE0F This command must be used in a session topic.", { parse_mode: "HTML" });
|
|
10214
10334
|
return;
|
|
10215
10335
|
}
|
|
10216
|
-
const session = core.
|
|
10336
|
+
const session = await core.getOrResumeSession(
|
|
10217
10337
|
"telegram",
|
|
10218
10338
|
String(threadId)
|
|
10219
10339
|
);
|
|
@@ -10522,7 +10642,7 @@ async function handleNewChat(ctx, core, chatId) {
|
|
|
10522
10642
|
);
|
|
10523
10643
|
return;
|
|
10524
10644
|
}
|
|
10525
|
-
const currentSession = core.
|
|
10645
|
+
const currentSession = await core.getOrResumeSession(
|
|
10526
10646
|
"telegram",
|
|
10527
10647
|
String(threadId)
|
|
10528
10648
|
);
|
|
@@ -10802,7 +10922,7 @@ async function handleCancel(ctx, core, assistant) {
|
|
|
10802
10922
|
async function handleStatus(ctx, core) {
|
|
10803
10923
|
const threadId = ctx.message?.message_thread_id;
|
|
10804
10924
|
if (threadId) {
|
|
10805
|
-
const session = core.
|
|
10925
|
+
const session = await core.getOrResumeSession(
|
|
10806
10926
|
"telegram",
|
|
10807
10927
|
String(threadId)
|
|
10808
10928
|
);
|
|
@@ -11188,8 +11308,8 @@ async function handleClear(ctx, assistant) {
|
|
|
11188
11308
|
await ctx.reply(`\u274C Failed to clear: <code>${message}</code>`, { parse_mode: "HTML" });
|
|
11189
11309
|
}
|
|
11190
11310
|
}
|
|
11191
|
-
function buildSkillMessages(
|
|
11192
|
-
const sorted = [...
|
|
11311
|
+
function buildSkillMessages(commands) {
|
|
11312
|
+
const sorted = [...commands].sort((a, b) => a.name.localeCompare(b.name));
|
|
11193
11313
|
const header2 = "\u{1F6E0} <b>Available Skills</b>\n";
|
|
11194
11314
|
const lines = sorted.map((c3) => `<code>/${c3.name}</code>`);
|
|
11195
11315
|
const messages = [];
|
|
@@ -15272,8 +15392,12 @@ var init_send_queue = __esm({
|
|
|
15272
15392
|
const result = await item.fn();
|
|
15273
15393
|
item.resolve(result);
|
|
15274
15394
|
} catch (err) {
|
|
15275
|
-
|
|
15276
|
-
|
|
15395
|
+
if (err instanceof Error && "description" in err && typeof err.description === "string" && err.description.includes("message is not modified")) {
|
|
15396
|
+
item.resolve(void 0);
|
|
15397
|
+
} else {
|
|
15398
|
+
this.config.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
15399
|
+
item.reject(err);
|
|
15400
|
+
}
|
|
15277
15401
|
} finally {
|
|
15278
15402
|
const now = Date.now();
|
|
15279
15403
|
this.lastExec = now;
|
|
@@ -15474,6 +15598,7 @@ var init_streaming = __esm({
|
|
|
15474
15598
|
flushTimer;
|
|
15475
15599
|
flushPromise = Promise.resolve();
|
|
15476
15600
|
lastSentBuffer = "";
|
|
15601
|
+
lastSentHtml = "";
|
|
15477
15602
|
displayTruncated = false;
|
|
15478
15603
|
tracer;
|
|
15479
15604
|
append(text6) {
|
|
@@ -15533,6 +15658,8 @@ var init_streaming = __esm({
|
|
|
15533
15658
|
this.firstFlushPending = false;
|
|
15534
15659
|
}
|
|
15535
15660
|
} else {
|
|
15661
|
+
if (html === this.lastSentHtml) return;
|
|
15662
|
+
this.lastSentHtml = html;
|
|
15536
15663
|
try {
|
|
15537
15664
|
const result = await this.sendQueue.enqueue(
|
|
15538
15665
|
() => this.bot.api.editMessageText(this.chatId, this.messageId, html, {
|
|
@@ -15767,7 +15894,7 @@ var init_skill_command_manager = __esm({
|
|
|
15767
15894
|
this.sessionManager = sessionManager;
|
|
15768
15895
|
}
|
|
15769
15896
|
messages = /* @__PURE__ */ new Map();
|
|
15770
|
-
async send(sessionId, threadId,
|
|
15897
|
+
async send(sessionId, threadId, commands) {
|
|
15771
15898
|
if (!this.messages.has(sessionId)) {
|
|
15772
15899
|
const record = this.sessionManager.getSessionRecord(sessionId);
|
|
15773
15900
|
const platform2 = record?.platform;
|
|
@@ -15775,11 +15902,11 @@ var init_skill_command_manager = __esm({
|
|
|
15775
15902
|
this.messages.set(sessionId, platform2.skillMsgId);
|
|
15776
15903
|
}
|
|
15777
15904
|
}
|
|
15778
|
-
if (
|
|
15905
|
+
if (commands.length === 0) {
|
|
15779
15906
|
await this.cleanup(sessionId);
|
|
15780
15907
|
return;
|
|
15781
15908
|
}
|
|
15782
|
-
const messages = buildSkillMessages(
|
|
15909
|
+
const messages = buildSkillMessages(commands);
|
|
15783
15910
|
const existingMsgId = this.messages.get(sessionId);
|
|
15784
15911
|
if (existingMsgId) {
|
|
15785
15912
|
try {
|
|
@@ -16417,10 +16544,10 @@ var init_adapter2 = __esm({
|
|
|
16417
16544
|
const chatId = ctx.chat.id;
|
|
16418
16545
|
const topicId = ctx.message.message_thread_id;
|
|
16419
16546
|
try {
|
|
16420
|
-
const sessionId = topicId != null ? this.core.
|
|
16547
|
+
const sessionId = topicId != null ? (await this.core.getOrResumeSession(
|
|
16421
16548
|
"telegram",
|
|
16422
16549
|
String(topicId)
|
|
16423
|
-
)?.id ?? null : null;
|
|
16550
|
+
))?.id ?? null : null;
|
|
16424
16551
|
const response = await registry.execute(text6, {
|
|
16425
16552
|
raw: "",
|
|
16426
16553
|
sessionId,
|
|
@@ -16456,10 +16583,10 @@ var init_adapter2 = __esm({
|
|
|
16456
16583
|
const chatId = ctx.chat.id;
|
|
16457
16584
|
const topicId = ctx.callbackQuery.message?.message_thread_id;
|
|
16458
16585
|
try {
|
|
16459
|
-
const sessionId = topicId != null ? this.core.
|
|
16586
|
+
const sessionId = topicId != null ? (await this.core.getOrResumeSession(
|
|
16460
16587
|
"telegram",
|
|
16461
16588
|
String(topicId)
|
|
16462
|
-
)?.id ?? null : null;
|
|
16589
|
+
))?.id ?? null : null;
|
|
16463
16590
|
const response = await registry.execute(command2, {
|
|
16464
16591
|
raw: "",
|
|
16465
16592
|
sessionId,
|
|
@@ -16541,7 +16668,7 @@ var init_adapter2 = __esm({
|
|
|
16541
16668
|
});
|
|
16542
16669
|
return;
|
|
16543
16670
|
}
|
|
16544
|
-
const session = this.core.
|
|
16671
|
+
const session = await this.core.getOrResumeSession(
|
|
16545
16672
|
"telegram",
|
|
16546
16673
|
String(threadId)
|
|
16547
16674
|
);
|
|
@@ -16813,10 +16940,10 @@ ${lines.join("\n")}`;
|
|
|
16813
16940
|
);
|
|
16814
16941
|
return;
|
|
16815
16942
|
}
|
|
16816
|
-
const sessionId = this.core.
|
|
16943
|
+
const sessionId = (await this.core.getOrResumeSession(
|
|
16817
16944
|
"telegram",
|
|
16818
16945
|
String(threadId)
|
|
16819
|
-
)?.id;
|
|
16946
|
+
))?.id;
|
|
16820
16947
|
if (sessionId) {
|
|
16821
16948
|
this.getTracer(sessionId)?.log("telegram", { action: "incoming:message", sessionId, userId: String(ctx.from?.id), text: ctx.message?.text });
|
|
16822
16949
|
await this.draftManager.finalize(sessionId, this.assistantSession?.id);
|
|
@@ -17282,33 +17409,33 @@ Task completed.
|
|
|
17282
17409
|
);
|
|
17283
17410
|
}
|
|
17284
17411
|
}
|
|
17285
|
-
async sendSkillCommands(sessionId,
|
|
17412
|
+
async sendSkillCommands(sessionId, commands) {
|
|
17286
17413
|
if (sessionId === this.assistantSession?.id) return;
|
|
17287
17414
|
const session = this.core.sessionManager.getSession(sessionId);
|
|
17288
17415
|
if (!session) return;
|
|
17289
17416
|
const threadId = Number(session.threadId);
|
|
17290
17417
|
if (!threadId) {
|
|
17291
|
-
this._pendingSkillCommands.set(sessionId,
|
|
17418
|
+
this._pendingSkillCommands.set(sessionId, commands);
|
|
17292
17419
|
return;
|
|
17293
17420
|
}
|
|
17294
|
-
await this.skillManager.send(sessionId, threadId,
|
|
17421
|
+
await this.skillManager.send(sessionId, threadId, commands);
|
|
17295
17422
|
}
|
|
17296
17423
|
/** Flush any skill commands that were queued before threadId was available */
|
|
17297
17424
|
async flushPendingSkillCommands(sessionId) {
|
|
17298
|
-
const
|
|
17299
|
-
if (!
|
|
17425
|
+
const commands = this._pendingSkillCommands.get(sessionId);
|
|
17426
|
+
if (!commands) return;
|
|
17300
17427
|
this._pendingSkillCommands.delete(sessionId);
|
|
17301
17428
|
const session = this.core.sessionManager.getSession(sessionId);
|
|
17302
17429
|
if (!session) return;
|
|
17303
17430
|
const threadId = Number(session.threadId);
|
|
17304
17431
|
if (!threadId) return;
|
|
17305
|
-
await this.skillManager.send(sessionId, threadId,
|
|
17432
|
+
await this.skillManager.send(sessionId, threadId, commands);
|
|
17306
17433
|
}
|
|
17307
|
-
resolveSessionId(threadId) {
|
|
17308
|
-
return this.core.
|
|
17434
|
+
async resolveSessionId(threadId) {
|
|
17435
|
+
return (await this.core.getOrResumeSession(
|
|
17309
17436
|
"telegram",
|
|
17310
17437
|
String(threadId)
|
|
17311
|
-
)?.id;
|
|
17438
|
+
))?.id;
|
|
17312
17439
|
}
|
|
17313
17440
|
async downloadTelegramFile(fileId) {
|
|
17314
17441
|
try {
|
|
@@ -17329,7 +17456,7 @@ Task completed.
|
|
|
17329
17456
|
if (!downloaded) return;
|
|
17330
17457
|
let buffer = downloaded.buffer;
|
|
17331
17458
|
let originalFilePath;
|
|
17332
|
-
const sessionId = this.resolveSessionId(threadId) || "unknown";
|
|
17459
|
+
const sessionId = await this.resolveSessionId(threadId) || "unknown";
|
|
17333
17460
|
if (convertOggToWav) {
|
|
17334
17461
|
const oggAtt = await this.fileService.saveFile(
|
|
17335
17462
|
sessionId,
|
|
@@ -17364,7 +17491,7 @@ Task completed.
|
|
|
17364
17491
|
}
|
|
17365
17492
|
return;
|
|
17366
17493
|
}
|
|
17367
|
-
const sid = this.resolveSessionId(threadId);
|
|
17494
|
+
const sid = await this.resolveSessionId(threadId);
|
|
17368
17495
|
if (sid) await this.draftManager.finalize(sid, this.assistantSession?.id);
|
|
17369
17496
|
this.core.handleMessage({
|
|
17370
17497
|
channelId: "telegram",
|
|
@@ -17893,11 +18020,11 @@ __export(api_client_exports, {
|
|
|
17893
18020
|
import * as fs32 from "fs";
|
|
17894
18021
|
import * as path33 from "path";
|
|
17895
18022
|
import * as os14 from "os";
|
|
17896
|
-
function defaultPortFile(
|
|
17897
|
-
return path33.join(
|
|
18023
|
+
function defaultPortFile(root) {
|
|
18024
|
+
return path33.join(root ?? DEFAULT_ROOT, "api.port");
|
|
17898
18025
|
}
|
|
17899
|
-
function defaultSecretFile(
|
|
17900
|
-
return path33.join(
|
|
18026
|
+
function defaultSecretFile(root) {
|
|
18027
|
+
return path33.join(root ?? DEFAULT_ROOT, "api-secret");
|
|
17901
18028
|
}
|
|
17902
18029
|
function readApiPort(portFilePath, instanceRoot) {
|
|
17903
18030
|
const filePath = portFilePath ?? defaultPortFile(instanceRoot);
|
|
@@ -17987,17 +18114,16 @@ var init_suggest = __esm({
|
|
|
17987
18114
|
import fs33 from "fs";
|
|
17988
18115
|
import path34 from "path";
|
|
17989
18116
|
import os15 from "os";
|
|
17990
|
-
function printInstanceHint(
|
|
18117
|
+
function printInstanceHint(root) {
|
|
17991
18118
|
const globalRoot = getGlobalRoot();
|
|
17992
|
-
const isGlobal =
|
|
17993
|
-
const displayPath =
|
|
18119
|
+
const isGlobal = root === globalRoot;
|
|
18120
|
+
const displayPath = root.replace(os15.homedir(), "~");
|
|
17994
18121
|
const label = isGlobal ? "global" : "local";
|
|
17995
|
-
console.log(`
|
|
18122
|
+
console.log(` Workspace: ${label} \u2014 ${displayPath}`);
|
|
17996
18123
|
if (isGlobal) {
|
|
17997
18124
|
const localRoot = path34.join(process.cwd(), ".openacp");
|
|
17998
18125
|
if (fs33.existsSync(localRoot)) {
|
|
17999
|
-
|
|
18000
|
-
console.log(` \x1B[2mhint: local instance found at ${localDisplay} \u2014 use --local to use it\x1B[0m`);
|
|
18126
|
+
console.log(` \x1B[2mhint: local workspace exists in current directory \u2014 use --local to use it\x1B[0m`);
|
|
18001
18127
|
}
|
|
18002
18128
|
}
|
|
18003
18129
|
}
|
|
@@ -18029,16 +18155,16 @@ import { spawn as spawn5 } from "child_process";
|
|
|
18029
18155
|
import * as fs34 from "fs";
|
|
18030
18156
|
import * as path35 from "path";
|
|
18031
18157
|
import * as os16 from "os";
|
|
18032
|
-
function getPidPath(
|
|
18033
|
-
const base =
|
|
18158
|
+
function getPidPath(root) {
|
|
18159
|
+
const base = root ?? DEFAULT_ROOT2;
|
|
18034
18160
|
return path35.join(base, "openacp.pid");
|
|
18035
18161
|
}
|
|
18036
|
-
function getLogDir(
|
|
18037
|
-
const base =
|
|
18162
|
+
function getLogDir(root) {
|
|
18163
|
+
const base = root ?? DEFAULT_ROOT2;
|
|
18038
18164
|
return path35.join(base, "logs");
|
|
18039
18165
|
}
|
|
18040
|
-
function getRunningMarker(
|
|
18041
|
-
const base =
|
|
18166
|
+
function getRunningMarker(root) {
|
|
18167
|
+
const base = root ?? DEFAULT_ROOT2;
|
|
18042
18168
|
return path35.join(base, "running");
|
|
18043
18169
|
}
|
|
18044
18170
|
function writePidFile(pidPath, pid) {
|
|
@@ -18174,19 +18300,19 @@ async function stopDaemon(pidPath = getPidPath(), instanceRoot) {
|
|
|
18174
18300
|
}
|
|
18175
18301
|
return { stopped: false, pid, error: "Process did not exit after SIGKILL (possible uninterruptible I/O). PID file retained." };
|
|
18176
18302
|
}
|
|
18177
|
-
function markRunning(
|
|
18178
|
-
const marker = getRunningMarker(
|
|
18303
|
+
function markRunning(root) {
|
|
18304
|
+
const marker = getRunningMarker(root);
|
|
18179
18305
|
fs34.mkdirSync(path35.dirname(marker), { recursive: true });
|
|
18180
18306
|
fs34.writeFileSync(marker, "");
|
|
18181
18307
|
}
|
|
18182
|
-
function clearRunning(
|
|
18308
|
+
function clearRunning(root) {
|
|
18183
18309
|
try {
|
|
18184
|
-
fs34.unlinkSync(getRunningMarker(
|
|
18310
|
+
fs34.unlinkSync(getRunningMarker(root));
|
|
18185
18311
|
} catch {
|
|
18186
18312
|
}
|
|
18187
18313
|
}
|
|
18188
|
-
function shouldAutoStart(
|
|
18189
|
-
return fs34.existsSync(getRunningMarker(
|
|
18314
|
+
function shouldAutoStart(root) {
|
|
18315
|
+
return fs34.existsSync(getRunningMarker(root));
|
|
18190
18316
|
}
|
|
18191
18317
|
var DEFAULT_ROOT2;
|
|
18192
18318
|
var init_daemon2 = __esm({
|
|
@@ -18205,7 +18331,7 @@ __export(stop_exports, {
|
|
|
18205
18331
|
import path37 from "path";
|
|
18206
18332
|
import os18 from "os";
|
|
18207
18333
|
async function cmdStop(args2 = [], instanceRoot) {
|
|
18208
|
-
const
|
|
18334
|
+
const root = instanceRoot ?? path37.join(os18.homedir(), ".openacp");
|
|
18209
18335
|
if (wantsHelp(args2)) {
|
|
18210
18336
|
console.log(`
|
|
18211
18337
|
\x1B[1mopenacp stop\x1B[0m \u2014 Stop the background daemon
|
|
@@ -18218,7 +18344,7 @@ Sends a stop signal to the running OpenACP daemon process.
|
|
|
18218
18344
|
return;
|
|
18219
18345
|
}
|
|
18220
18346
|
const { stopDaemon: stopDaemon2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
18221
|
-
const result = await stopDaemon2(getPidPath2(
|
|
18347
|
+
const result = await stopDaemon2(getPidPath2(root), root);
|
|
18222
18348
|
if (result.stopped) {
|
|
18223
18349
|
console.log(`OpenACP daemon stopped (was PID ${result.pid})`);
|
|
18224
18350
|
} else {
|
|
@@ -18600,10 +18726,10 @@ function resolveAgentCommand(cmd) {
|
|
|
18600
18726
|
if (ownDir !== process.cwd()) {
|
|
18601
18727
|
searchRoots.push(ownDir);
|
|
18602
18728
|
}
|
|
18603
|
-
for (const
|
|
18729
|
+
for (const root of searchRoots) {
|
|
18604
18730
|
const packageDirs = [
|
|
18605
|
-
path39.resolve(
|
|
18606
|
-
path39.resolve(
|
|
18731
|
+
path39.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
|
|
18732
|
+
path39.resolve(root, "node_modules", cmd, "dist", "index.js")
|
|
18607
18733
|
];
|
|
18608
18734
|
for (const jsPath of packageDirs) {
|
|
18609
18735
|
if (fs36.existsSync(jsPath)) {
|
|
@@ -18611,8 +18737,8 @@ function resolveAgentCommand(cmd) {
|
|
|
18611
18737
|
}
|
|
18612
18738
|
}
|
|
18613
18739
|
}
|
|
18614
|
-
for (const
|
|
18615
|
-
const localBin = path39.resolve(
|
|
18740
|
+
for (const root of searchRoots) {
|
|
18741
|
+
const localBin = path39.resolve(root, "node_modules", ".bin", cmd);
|
|
18616
18742
|
if (fs36.existsSync(localBin)) {
|
|
18617
18743
|
const content = fs36.readFileSync(localBin, "utf-8");
|
|
18618
18744
|
if (content.startsWith("#!/usr/bin/env node")) {
|
|
@@ -18953,14 +19079,6 @@ ${stderr}`
|
|
|
18953
19079
|
};
|
|
18954
19080
|
break;
|
|
18955
19081
|
}
|
|
18956
|
-
case "current_mode_update": {
|
|
18957
|
-
const cm = update;
|
|
18958
|
-
event = {
|
|
18959
|
-
type: "current_mode_update",
|
|
18960
|
-
modeId: cm.currentModeId
|
|
18961
|
-
};
|
|
18962
|
-
break;
|
|
18963
|
-
}
|
|
18964
19082
|
case "config_option_update": {
|
|
18965
19083
|
const co = update;
|
|
18966
19084
|
event = {
|
|
@@ -18978,10 +19096,10 @@ ${stderr}`
|
|
|
18978
19096
|
break;
|
|
18979
19097
|
}
|
|
18980
19098
|
// NOTE: model_update is NOT a session update type in the ACP SDK schema.
|
|
18981
|
-
// Model changes are applied via
|
|
18982
|
-
//
|
|
18983
|
-
//
|
|
18984
|
-
//
|
|
19099
|
+
// Model changes are applied via setSessionConfigOption() and the response
|
|
19100
|
+
// is synchronous — the SDK does not push a model_update notification to
|
|
19101
|
+
// the client. Therefore AgentEvent "model_update" cannot originate from
|
|
19102
|
+
// sessionUpdate and must be emitted by callers of setConfigOption()
|
|
18985
19103
|
// if they need to propagate the change downstream.
|
|
18986
19104
|
default:
|
|
18987
19105
|
return;
|
|
@@ -19063,9 +19181,6 @@ ${stderr}`
|
|
|
19063
19181
|
};
|
|
19064
19182
|
}
|
|
19065
19183
|
// ── New ACP methods ──────────────────────────────────────────────────
|
|
19066
|
-
async setMode(modeId) {
|
|
19067
|
-
await this.connection.setSessionMode({ sessionId: this.sessionId, modeId });
|
|
19068
|
-
}
|
|
19069
19184
|
async setConfigOption(configId, value) {
|
|
19070
19185
|
return await this.connection.setSessionConfigOption({
|
|
19071
19186
|
sessionId: this.sessionId,
|
|
@@ -19073,12 +19188,6 @@ ${stderr}`
|
|
|
19073
19188
|
...value
|
|
19074
19189
|
});
|
|
19075
19190
|
}
|
|
19076
|
-
async setModel(modelId) {
|
|
19077
|
-
await this.connection.unstable_setSessionModel({
|
|
19078
|
-
sessionId: this.sessionId,
|
|
19079
|
-
modelId
|
|
19080
|
-
});
|
|
19081
|
-
}
|
|
19082
19191
|
async listSessions(cwd, cursor) {
|
|
19083
19192
|
return await this.connection.listSessions({
|
|
19084
19193
|
cwd: cwd ?? null,
|
|
@@ -19376,12 +19485,8 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
19376
19485
|
name;
|
|
19377
19486
|
createdAt = /* @__PURE__ */ new Date();
|
|
19378
19487
|
voiceMode = "off";
|
|
19379
|
-
dangerousMode = false;
|
|
19380
|
-
currentMode;
|
|
19381
|
-
availableModes = [];
|
|
19382
19488
|
configOptions = [];
|
|
19383
|
-
|
|
19384
|
-
availableModels = [];
|
|
19489
|
+
clientOverrides = {};
|
|
19385
19490
|
agentCapabilities;
|
|
19386
19491
|
archiving = false;
|
|
19387
19492
|
promptCount = 0;
|
|
@@ -19675,34 +19780,28 @@ ${result.text}` : result.text;
|
|
|
19675
19780
|
}
|
|
19676
19781
|
}
|
|
19677
19782
|
// --- ACP Mode / Config / Model State ---
|
|
19678
|
-
|
|
19679
|
-
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19683
|
-
|
|
19684
|
-
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
|
|
19688
|
-
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
|
|
19692
|
-
|
|
19783
|
+
setInitialConfigOptions(options) {
|
|
19784
|
+
this.configOptions = options ?? [];
|
|
19785
|
+
}
|
|
19786
|
+
setAgentCapabilities(caps) {
|
|
19787
|
+
this.agentCapabilities = caps;
|
|
19788
|
+
}
|
|
19789
|
+
getConfigOption(id) {
|
|
19790
|
+
return this.configOptions.find((o) => o.id === id);
|
|
19791
|
+
}
|
|
19792
|
+
getConfigByCategory(category) {
|
|
19793
|
+
return this.configOptions.find((o) => o.category === category);
|
|
19794
|
+
}
|
|
19795
|
+
getConfigValue(id) {
|
|
19796
|
+
const option = this.getConfigOption(id);
|
|
19797
|
+
if (!option) return void 0;
|
|
19798
|
+
return String(option.currentValue);
|
|
19693
19799
|
}
|
|
19694
19800
|
/** Set session name explicitly and emit 'named' event */
|
|
19695
19801
|
setName(name) {
|
|
19696
19802
|
this.name = name;
|
|
19697
19803
|
this.emit("named", name);
|
|
19698
19804
|
}
|
|
19699
|
-
async updateMode(modeId) {
|
|
19700
|
-
if (this.middlewareChain) {
|
|
19701
|
-
const result = await this.middlewareChain.execute("mode:beforeChange", { sessionId: this.id, fromMode: this.currentMode, toMode: modeId }, async (p2) => p2);
|
|
19702
|
-
if (!result) return;
|
|
19703
|
-
}
|
|
19704
|
-
this.currentMode = modeId;
|
|
19705
|
-
}
|
|
19706
19805
|
async updateConfigOptions(options) {
|
|
19707
19806
|
if (this.middlewareChain) {
|
|
19708
19807
|
const result = await this.middlewareChain.execute("config:beforeChange", { sessionId: this.id, configId: "options", oldValue: this.configOptions, newValue: options }, async (p2) => p2);
|
|
@@ -19710,21 +19809,10 @@ ${result.text}` : result.text;
|
|
|
19710
19809
|
}
|
|
19711
19810
|
this.configOptions = options;
|
|
19712
19811
|
}
|
|
19713
|
-
async updateModel(modelId) {
|
|
19714
|
-
if (this.middlewareChain) {
|
|
19715
|
-
const result = await this.middlewareChain.execute("model:beforeChange", { sessionId: this.id, fromModel: this.currentModel, toModel: modelId }, async (p2) => p2);
|
|
19716
|
-
if (!result) return;
|
|
19717
|
-
}
|
|
19718
|
-
this.currentModel = modelId;
|
|
19719
|
-
}
|
|
19720
19812
|
/** Snapshot of current ACP state for persistence */
|
|
19721
19813
|
toAcpStateSnapshot() {
|
|
19722
19814
|
return {
|
|
19723
|
-
currentMode: this.currentMode,
|
|
19724
|
-
availableModes: this.availableModes.length > 0 ? this.availableModes : void 0,
|
|
19725
19815
|
configOptions: this.configOptions.length > 0 ? this.configOptions : void 0,
|
|
19726
|
-
currentModel: this.currentModel,
|
|
19727
|
-
availableModels: this.availableModels.length > 0 ? this.availableModels : void 0,
|
|
19728
19816
|
agentCapabilities: this.agentCapabilities
|
|
19729
19817
|
};
|
|
19730
19818
|
}
|
|
@@ -19774,10 +19862,6 @@ ${result.text}` : result.text;
|
|
|
19774
19862
|
this.agentSessionId = newAgent.sessionId;
|
|
19775
19863
|
this.promptCount = 0;
|
|
19776
19864
|
this.agentCapabilities = void 0;
|
|
19777
|
-
this.currentMode = void 0;
|
|
19778
|
-
this.availableModes = [];
|
|
19779
|
-
this.currentModel = void 0;
|
|
19780
|
-
this.availableModels = [];
|
|
19781
19865
|
this.configOptions = [];
|
|
19782
19866
|
this.log.info({ from: this.agentSwitchHistory.at(-1).agentName, to: agentName }, "Agent switched");
|
|
19783
19867
|
}
|
|
@@ -19832,7 +19916,7 @@ var init_session_manager = __esm({
|
|
|
19832
19916
|
createdAt: session.createdAt.toISOString(),
|
|
19833
19917
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19834
19918
|
name: session.name,
|
|
19835
|
-
|
|
19919
|
+
clientOverrides: {},
|
|
19836
19920
|
platform: {}
|
|
19837
19921
|
});
|
|
19838
19922
|
}
|
|
@@ -19964,12 +20048,26 @@ var init_session_manager = __esm({
|
|
|
19964
20048
|
}
|
|
19965
20049
|
});
|
|
19966
20050
|
|
|
20051
|
+
// src/core/utils/bypass-detection.ts
|
|
20052
|
+
function isPermissionBypass(value) {
|
|
20053
|
+
const lower = value.toLowerCase();
|
|
20054
|
+
return BYPASS_KEYWORDS.some((kw) => lower.includes(kw));
|
|
20055
|
+
}
|
|
20056
|
+
var BYPASS_KEYWORDS;
|
|
20057
|
+
var init_bypass_detection = __esm({
|
|
20058
|
+
"src/core/utils/bypass-detection.ts"() {
|
|
20059
|
+
"use strict";
|
|
20060
|
+
BYPASS_KEYWORDS = ["bypass", "dangerous", "skip", "dontask", "dont_ask", "auto_accept"];
|
|
20061
|
+
}
|
|
20062
|
+
});
|
|
20063
|
+
|
|
19967
20064
|
// src/core/sessions/session-bridge.ts
|
|
19968
20065
|
var log29, SessionBridge;
|
|
19969
20066
|
var init_session_bridge = __esm({
|
|
19970
20067
|
"src/core/sessions/session-bridge.ts"() {
|
|
19971
20068
|
"use strict";
|
|
19972
20069
|
init_log();
|
|
20070
|
+
init_bypass_detection();
|
|
19973
20071
|
log29 = createChildLogger({ module: "session-bridge" });
|
|
19974
20072
|
SessionBridge = class {
|
|
19975
20073
|
constructor(session, adapter, deps) {
|
|
@@ -20128,12 +20226,12 @@ var init_session_bridge = __esm({
|
|
|
20128
20226
|
break;
|
|
20129
20227
|
case "image_content": {
|
|
20130
20228
|
if (this.deps.fileService) {
|
|
20131
|
-
const
|
|
20229
|
+
const fs53 = this.deps.fileService;
|
|
20132
20230
|
const sid = this.session.id;
|
|
20133
20231
|
const { data, mimeType } = event;
|
|
20134
20232
|
const buffer = Buffer.from(data, "base64");
|
|
20135
|
-
const ext =
|
|
20136
|
-
|
|
20233
|
+
const ext = fs53.extensionFromMime(mimeType);
|
|
20234
|
+
fs53.saveFile(sid, `agent-image${ext}`, buffer, mimeType).then((att) => {
|
|
20137
20235
|
this.sendMessage(sid, {
|
|
20138
20236
|
type: "attachment",
|
|
20139
20237
|
text: "",
|
|
@@ -20145,12 +20243,12 @@ var init_session_bridge = __esm({
|
|
|
20145
20243
|
}
|
|
20146
20244
|
case "audio_content": {
|
|
20147
20245
|
if (this.deps.fileService) {
|
|
20148
|
-
const
|
|
20246
|
+
const fs53 = this.deps.fileService;
|
|
20149
20247
|
const sid = this.session.id;
|
|
20150
20248
|
const { data, mimeType } = event;
|
|
20151
20249
|
const buffer = Buffer.from(data, "base64");
|
|
20152
|
-
const ext =
|
|
20153
|
-
|
|
20250
|
+
const ext = fs53.extensionFromMime(mimeType);
|
|
20251
|
+
fs53.saveFile(sid, `agent-audio${ext}`, buffer, mimeType).then((att) => {
|
|
20154
20252
|
this.sendMessage(sid, {
|
|
20155
20253
|
type: "attachment",
|
|
20156
20254
|
text: "",
|
|
@@ -20175,24 +20273,12 @@ var init_session_bridge = __esm({
|
|
|
20175
20273
|
outgoing = this.deps.messageTransformer.transform(event);
|
|
20176
20274
|
this.sendMessage(this.session.id, outgoing);
|
|
20177
20275
|
break;
|
|
20178
|
-
case "current_mode_update":
|
|
20179
|
-
this.session.updateMode(event.modeId);
|
|
20180
|
-
this.persistAcpState();
|
|
20181
|
-
outgoing = this.deps.messageTransformer.transform(event);
|
|
20182
|
-
this.sendMessage(this.session.id, outgoing);
|
|
20183
|
-
break;
|
|
20184
20276
|
case "config_option_update":
|
|
20185
20277
|
this.session.updateConfigOptions(event.options);
|
|
20186
20278
|
this.persistAcpState();
|
|
20187
20279
|
outgoing = this.deps.messageTransformer.transform(event);
|
|
20188
20280
|
this.sendMessage(this.session.id, outgoing);
|
|
20189
20281
|
break;
|
|
20190
|
-
case "model_update":
|
|
20191
|
-
this.session.updateModel(event.modelId);
|
|
20192
|
-
this.persistAcpState();
|
|
20193
|
-
outgoing = this.deps.messageTransformer.transform(event);
|
|
20194
|
-
this.sendMessage(this.session.id, outgoing);
|
|
20195
|
-
break;
|
|
20196
20282
|
case "user_message_chunk":
|
|
20197
20283
|
outgoing = this.deps.messageTransformer.transform(event);
|
|
20198
20284
|
this.sendMessage(this.session.id, outgoing);
|
|
@@ -20212,7 +20298,7 @@ var init_session_bridge = __esm({
|
|
|
20212
20298
|
});
|
|
20213
20299
|
return outgoing;
|
|
20214
20300
|
}
|
|
20215
|
-
/** Persist current ACP state (
|
|
20301
|
+
/** Persist current ACP state (configOptions, agentCapabilities) to session store as cache */
|
|
20216
20302
|
persistAcpState() {
|
|
20217
20303
|
this.deps.sessionManager.patchRecord(this.session.id, {
|
|
20218
20304
|
acpState: this.session.toAcpStateSnapshot()
|
|
@@ -20267,12 +20353,17 @@ var init_session_bridge = __esm({
|
|
|
20267
20353
|
return allowOption.id;
|
|
20268
20354
|
}
|
|
20269
20355
|
}
|
|
20270
|
-
|
|
20356
|
+
const modeOption = this.session.getConfigByCategory("mode");
|
|
20357
|
+
const isAgentBypass = modeOption && isPermissionBypass(
|
|
20358
|
+
typeof modeOption.currentValue === "string" ? modeOption.currentValue : ""
|
|
20359
|
+
);
|
|
20360
|
+
const isClientBypass = this.session.clientOverrides.bypassPermissions;
|
|
20361
|
+
if (isAgentBypass || isClientBypass) {
|
|
20271
20362
|
const allowOption = permReq.options.find((o) => o.isAllow);
|
|
20272
20363
|
if (allowOption) {
|
|
20273
20364
|
log29.info(
|
|
20274
|
-
{ sessionId: this.session.id, requestId: permReq.id, optionId: allowOption.id },
|
|
20275
|
-
"
|
|
20365
|
+
{ sessionId: this.session.id, requestId: permReq.id, optionId: allowOption.id, agentBypass: !!isAgentBypass, clientBypass: !!isClientBypass },
|
|
20366
|
+
"Bypass mode: auto-approving permission"
|
|
20276
20367
|
);
|
|
20277
20368
|
if (mw) {
|
|
20278
20369
|
mw.execute("permission:afterResolve", {
|
|
@@ -20596,24 +20687,12 @@ var init_message_transformer = __esm({
|
|
|
20596
20687
|
text: `Session updated: ${event.title ?? ""}`.trim(),
|
|
20597
20688
|
metadata: { title: event.title, updatedAt: event.updatedAt }
|
|
20598
20689
|
};
|
|
20599
|
-
case "current_mode_update":
|
|
20600
|
-
return {
|
|
20601
|
-
type: "mode_change",
|
|
20602
|
-
text: `Mode: ${event.modeId}`,
|
|
20603
|
-
metadata: { modeId: event.modeId }
|
|
20604
|
-
};
|
|
20605
20690
|
case "config_option_update":
|
|
20606
20691
|
return {
|
|
20607
20692
|
type: "config_update",
|
|
20608
20693
|
text: "Config updated",
|
|
20609
20694
|
metadata: { options: event.options }
|
|
20610
20695
|
};
|
|
20611
|
-
case "model_update":
|
|
20612
|
-
return {
|
|
20613
|
-
type: "model_update",
|
|
20614
|
-
text: `Model: ${event.modelId}`,
|
|
20615
|
-
metadata: { modelId: event.modelId }
|
|
20616
|
-
};
|
|
20617
20696
|
case "user_message_chunk":
|
|
20618
20697
|
return {
|
|
20619
20698
|
type: "user_replay",
|
|
@@ -21009,16 +21088,14 @@ var init_session_factory = __esm({
|
|
|
21009
21088
|
}
|
|
21010
21089
|
const resp = agentInstance.initialSessionResponse;
|
|
21011
21090
|
if (resp) {
|
|
21012
|
-
|
|
21013
|
-
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
|
|
21017
|
-
}
|
|
21091
|
+
if (resp.configOptions) {
|
|
21092
|
+
session.setInitialConfigOptions(resp.configOptions);
|
|
21093
|
+
}
|
|
21094
|
+
if (agentInstance.agentCapabilities) {
|
|
21095
|
+
session.setAgentCapabilities(agentInstance.agentCapabilities);
|
|
21096
|
+
}
|
|
21018
21097
|
} else if (agentInstance.agentCapabilities) {
|
|
21019
|
-
session.
|
|
21020
|
-
agentCapabilities: agentInstance.agentCapabilities
|
|
21021
|
-
});
|
|
21098
|
+
session.setAgentCapabilities(agentInstance.agentCapabilities);
|
|
21022
21099
|
}
|
|
21023
21100
|
this.sessionManager.registerSession(session);
|
|
21024
21101
|
this.eventBus.emit("session:created", {
|
|
@@ -21068,18 +21145,21 @@ var init_session_factory = __esm({
|
|
|
21068
21145
|
threadId
|
|
21069
21146
|
});
|
|
21070
21147
|
session.activate();
|
|
21071
|
-
|
|
21148
|
+
if (record.clientOverrides) {
|
|
21149
|
+
session.clientOverrides = record.clientOverrides;
|
|
21150
|
+
} else if (record.dangerousMode) {
|
|
21151
|
+
session.clientOverrides = { bypassPermissions: true };
|
|
21152
|
+
}
|
|
21072
21153
|
if (record.firstAgent) session.firstAgent = record.firstAgent;
|
|
21073
21154
|
if (record.agentSwitchHistory) session.agentSwitchHistory = record.agentSwitchHistory;
|
|
21074
21155
|
if (record.currentPromptCount != null) session.promptCount = record.currentPromptCount;
|
|
21075
21156
|
if (record.acpState) {
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
});
|
|
21157
|
+
if (record.acpState.configOptions) {
|
|
21158
|
+
session.setInitialConfigOptions(record.acpState.configOptions);
|
|
21159
|
+
}
|
|
21160
|
+
if (record.acpState.agentCapabilities) {
|
|
21161
|
+
session.setAgentCapabilities(record.acpState.agentCapabilities);
|
|
21162
|
+
}
|
|
21083
21163
|
}
|
|
21084
21164
|
log32.info({ sessionId: session.id, threadId }, "Lazy resume successful");
|
|
21085
21165
|
return session;
|
|
@@ -22655,6 +22735,7 @@ var init_lifecycle_manager = __esm({
|
|
|
22655
22735
|
} catch (err) {
|
|
22656
22736
|
this._failed.add(plugin2.name);
|
|
22657
22737
|
ctx.cleanup();
|
|
22738
|
+
console.error(`[lifecycle] Plugin ${plugin2.name} setup() FAILED:`, err);
|
|
22658
22739
|
this.getPluginLogger(plugin2.name).error(`setup() failed: ${err}`);
|
|
22659
22740
|
this.eventBus?.emit("plugin:failed", { name: plugin2.name, error: String(err) });
|
|
22660
22741
|
}
|
|
@@ -22951,6 +23032,13 @@ var init_core = __esm({
|
|
|
22951
23032
|
{ channelId: message.channelId, threadId: message.threadId },
|
|
22952
23033
|
"No session found for thread (in-memory miss + lazy resume returned null)"
|
|
22953
23034
|
);
|
|
23035
|
+
const adapter = this.adapters.get(message.channelId);
|
|
23036
|
+
if (adapter) {
|
|
23037
|
+
await adapter.sendMessage(message.threadId, {
|
|
23038
|
+
type: "error",
|
|
23039
|
+
text: "\u26A0\uFE0F No active session in this topic. Use /new to start one."
|
|
23040
|
+
});
|
|
23041
|
+
}
|
|
22954
23042
|
return;
|
|
22955
23043
|
}
|
|
22956
23044
|
this.sessionManager.patchRecord(session.id, {
|
|
@@ -23638,6 +23726,162 @@ var init_switch2 = __esm({
|
|
|
23638
23726
|
}
|
|
23639
23727
|
});
|
|
23640
23728
|
|
|
23729
|
+
// src/core/commands/config.ts
|
|
23730
|
+
function flattenChoices(options) {
|
|
23731
|
+
const result = [];
|
|
23732
|
+
for (const item of options) {
|
|
23733
|
+
if ("group" in item && "options" in item) {
|
|
23734
|
+
result.push(...item.options);
|
|
23735
|
+
} else {
|
|
23736
|
+
result.push(item);
|
|
23737
|
+
}
|
|
23738
|
+
}
|
|
23739
|
+
return result;
|
|
23740
|
+
}
|
|
23741
|
+
function registerCategoryCommand(registry, core, category, commandName, notSupportedMsg) {
|
|
23742
|
+
registry.register({
|
|
23743
|
+
name: commandName,
|
|
23744
|
+
description: `Set ${commandName} for this session`,
|
|
23745
|
+
usage: `[value]`,
|
|
23746
|
+
category: "system",
|
|
23747
|
+
handler: async (args2) => {
|
|
23748
|
+
if (!args2.sessionId) {
|
|
23749
|
+
return { type: "error", message: "\u26A0\uFE0F No active session." };
|
|
23750
|
+
}
|
|
23751
|
+
const session = core.sessionManager.getSession(args2.sessionId);
|
|
23752
|
+
if (!session) {
|
|
23753
|
+
return { type: "error", message: "\u26A0\uFE0F Session not found." };
|
|
23754
|
+
}
|
|
23755
|
+
const configOption = session.getConfigByCategory(category);
|
|
23756
|
+
if (!configOption || configOption.type !== "select") {
|
|
23757
|
+
return { type: "error", message: `\u26A0\uFE0F ${notSupportedMsg}` };
|
|
23758
|
+
}
|
|
23759
|
+
const choices = flattenChoices(configOption.options);
|
|
23760
|
+
const raw = args2.raw.trim();
|
|
23761
|
+
if (!raw) {
|
|
23762
|
+
return {
|
|
23763
|
+
type: "menu",
|
|
23764
|
+
title: configOption.name,
|
|
23765
|
+
options: choices.map((c3) => ({
|
|
23766
|
+
label: c3.value === configOption.currentValue ? `\u2705 ${c3.label}` : c3.label,
|
|
23767
|
+
command: `/${commandName} ${c3.value}`,
|
|
23768
|
+
hint: c3.description
|
|
23769
|
+
}))
|
|
23770
|
+
};
|
|
23771
|
+
}
|
|
23772
|
+
const match = choices.find((c3) => c3.value === raw);
|
|
23773
|
+
if (!match) {
|
|
23774
|
+
const valid = choices.map((c3) => c3.value).join(", ");
|
|
23775
|
+
return { type: "error", message: `\u26A0\uFE0F Invalid value "${raw}". Valid: ${valid}` };
|
|
23776
|
+
}
|
|
23777
|
+
if (session.middlewareChain) {
|
|
23778
|
+
const result = await session.middlewareChain.execute("config:beforeChange", {
|
|
23779
|
+
sessionId: session.id,
|
|
23780
|
+
configId: configOption.id,
|
|
23781
|
+
oldValue: configOption.currentValue,
|
|
23782
|
+
newValue: raw
|
|
23783
|
+
}, async (p2) => p2);
|
|
23784
|
+
if (!result) return { type: "error", message: `Config change blocked by middleware.` };
|
|
23785
|
+
}
|
|
23786
|
+
try {
|
|
23787
|
+
const response = await session.agentInstance.setConfigOption(
|
|
23788
|
+
configOption.id,
|
|
23789
|
+
{ type: "select", value: raw }
|
|
23790
|
+
);
|
|
23791
|
+
if (response.configOptions) {
|
|
23792
|
+
session.configOptions = response.configOptions;
|
|
23793
|
+
}
|
|
23794
|
+
return { type: "text", text: `${configOption.name} set to ${match.label}.` };
|
|
23795
|
+
} catch (err) {
|
|
23796
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
23797
|
+
return { type: "error", message: `\u26A0\uFE0F Failed to set ${commandName}: ${msg}` };
|
|
23798
|
+
}
|
|
23799
|
+
}
|
|
23800
|
+
});
|
|
23801
|
+
}
|
|
23802
|
+
function registerDangerousCommand(registry, core) {
|
|
23803
|
+
registry.register({
|
|
23804
|
+
name: "dangerous",
|
|
23805
|
+
description: "Toggle dangerous mode (bypass permissions)",
|
|
23806
|
+
usage: "[on|off]",
|
|
23807
|
+
category: "system",
|
|
23808
|
+
handler: async (args2) => {
|
|
23809
|
+
if (!args2.sessionId) {
|
|
23810
|
+
return { type: "error", message: "\u26A0\uFE0F No active session." };
|
|
23811
|
+
}
|
|
23812
|
+
const session = core.sessionManager.getSession(args2.sessionId);
|
|
23813
|
+
if (!session) {
|
|
23814
|
+
return { type: "error", message: "\u26A0\uFE0F Session not found." };
|
|
23815
|
+
}
|
|
23816
|
+
const raw = args2.raw.trim().toLowerCase();
|
|
23817
|
+
const modeConfig = session.getConfigByCategory("mode");
|
|
23818
|
+
let bypassValue;
|
|
23819
|
+
let nonBypassDefault;
|
|
23820
|
+
if (modeConfig && modeConfig.type === "select") {
|
|
23821
|
+
const choices = flattenChoices(modeConfig.options);
|
|
23822
|
+
bypassValue = choices.find((c3) => isPermissionBypass(c3.value))?.value;
|
|
23823
|
+
nonBypassDefault = choices.find((c3) => !isPermissionBypass(c3.value))?.value;
|
|
23824
|
+
}
|
|
23825
|
+
const isCurrentlyDangerous = bypassValue ? modeConfig.type === "select" && isPermissionBypass(modeConfig.currentValue) : !!session.clientOverrides.bypassPermissions;
|
|
23826
|
+
if (!raw) {
|
|
23827
|
+
const status = isCurrentlyDangerous ? "on" : "off";
|
|
23828
|
+
const toggleCmd = isCurrentlyDangerous ? "/dangerous off" : "/dangerous on";
|
|
23829
|
+
const toggleLabel = isCurrentlyDangerous ? "Turn off" : "Turn on";
|
|
23830
|
+
return {
|
|
23831
|
+
type: "menu",
|
|
23832
|
+
title: `Dangerous mode: ${status}`,
|
|
23833
|
+
options: [{ label: toggleLabel, command: toggleCmd }]
|
|
23834
|
+
};
|
|
23835
|
+
}
|
|
23836
|
+
if (raw !== "on" && raw !== "off") {
|
|
23837
|
+
return { type: "error", message: "\u26A0\uFE0F Usage: /dangerous [on|off]" };
|
|
23838
|
+
}
|
|
23839
|
+
const wantOn = raw === "on";
|
|
23840
|
+
if (bypassValue && modeConfig) {
|
|
23841
|
+
try {
|
|
23842
|
+
const targetValue = wantOn ? bypassValue : nonBypassDefault;
|
|
23843
|
+
const response = await session.agentInstance.setConfigOption(
|
|
23844
|
+
modeConfig.id,
|
|
23845
|
+
{ type: "select", value: targetValue }
|
|
23846
|
+
);
|
|
23847
|
+
if (response.configOptions) {
|
|
23848
|
+
session.configOptions = response.configOptions;
|
|
23849
|
+
}
|
|
23850
|
+
return {
|
|
23851
|
+
type: "text",
|
|
23852
|
+
text: `Dangerous mode ${wantOn ? "enabled" : "disabled"}.`
|
|
23853
|
+
};
|
|
23854
|
+
} catch (err) {
|
|
23855
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
23856
|
+
return { type: "error", message: `\u26A0\uFE0F Failed: ${msg}` };
|
|
23857
|
+
}
|
|
23858
|
+
}
|
|
23859
|
+
session.clientOverrides.bypassPermissions = wantOn;
|
|
23860
|
+
await core.sessionManager.patchRecord(session.id, {
|
|
23861
|
+
clientOverrides: { ...session.clientOverrides }
|
|
23862
|
+
});
|
|
23863
|
+
return {
|
|
23864
|
+
type: "text",
|
|
23865
|
+
text: `Dangerous mode ${wantOn ? "enabled" : "disabled"} (client-side bypass).`
|
|
23866
|
+
};
|
|
23867
|
+
}
|
|
23868
|
+
});
|
|
23869
|
+
}
|
|
23870
|
+
function registerConfigCommands(registry, _core) {
|
|
23871
|
+
const core = _core;
|
|
23872
|
+
registerCategoryCommand(registry, core, "mode", "mode", "Agent does not support mode selection.");
|
|
23873
|
+
registerCategoryCommand(registry, core, "model", "model", "Agent does not support model selection.");
|
|
23874
|
+
registerCategoryCommand(registry, core, "thought_level", "thought", "Agent does not support thought level.");
|
|
23875
|
+
registerDangerousCommand(registry, core);
|
|
23876
|
+
}
|
|
23877
|
+
var init_config5 = __esm({
|
|
23878
|
+
"src/core/commands/config.ts"() {
|
|
23879
|
+
"use strict";
|
|
23880
|
+
init_bypass_detection();
|
|
23881
|
+
init_bypass_detection();
|
|
23882
|
+
}
|
|
23883
|
+
});
|
|
23884
|
+
|
|
23641
23885
|
// src/core/commands/index.ts
|
|
23642
23886
|
function registerSystemCommands(registry, core) {
|
|
23643
23887
|
registerSessionCommands(registry, core);
|
|
@@ -23646,6 +23890,7 @@ function registerSystemCommands(registry, core) {
|
|
|
23646
23890
|
registerHelpCommand(registry, core);
|
|
23647
23891
|
registerMenuCommand(registry, core);
|
|
23648
23892
|
registerSwitchCommands(registry);
|
|
23893
|
+
registerConfigCommands(registry, core);
|
|
23649
23894
|
}
|
|
23650
23895
|
var init_commands4 = __esm({
|
|
23651
23896
|
"src/core/commands/index.ts"() {
|
|
@@ -23656,6 +23901,7 @@ var init_commands4 = __esm({
|
|
|
23656
23901
|
init_help();
|
|
23657
23902
|
init_menu2();
|
|
23658
23903
|
init_switch2();
|
|
23904
|
+
init_config5();
|
|
23659
23905
|
}
|
|
23660
23906
|
});
|
|
23661
23907
|
|
|
@@ -23681,17 +23927,34 @@ var init_instance_registry = __esm({
|
|
|
23681
23927
|
const parsed = JSON.parse(raw);
|
|
23682
23928
|
if (parsed.version === 1 && parsed.instances) {
|
|
23683
23929
|
this.data = parsed;
|
|
23930
|
+
this.deduplicate();
|
|
23684
23931
|
}
|
|
23685
23932
|
} catch {
|
|
23686
23933
|
}
|
|
23687
23934
|
}
|
|
23935
|
+
/** Remove duplicate entries that point to the same root, keeping the first one */
|
|
23936
|
+
deduplicate() {
|
|
23937
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23938
|
+
const toRemove = [];
|
|
23939
|
+
for (const [id, entry] of Object.entries(this.data.instances)) {
|
|
23940
|
+
if (seen.has(entry.root)) {
|
|
23941
|
+
toRemove.push(id);
|
|
23942
|
+
} else {
|
|
23943
|
+
seen.add(entry.root);
|
|
23944
|
+
}
|
|
23945
|
+
}
|
|
23946
|
+
if (toRemove.length > 0) {
|
|
23947
|
+
for (const id of toRemove) delete this.data.instances[id];
|
|
23948
|
+
this.save();
|
|
23949
|
+
}
|
|
23950
|
+
}
|
|
23688
23951
|
save() {
|
|
23689
23952
|
const dir = path47.dirname(this.registryPath);
|
|
23690
23953
|
fs43.mkdirSync(dir, { recursive: true });
|
|
23691
23954
|
fs43.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
|
|
23692
23955
|
}
|
|
23693
|
-
register(id,
|
|
23694
|
-
this.data.instances[id] = { id, root
|
|
23956
|
+
register(id, root) {
|
|
23957
|
+
this.data.instances[id] = { id, root };
|
|
23695
23958
|
}
|
|
23696
23959
|
remove(id) {
|
|
23697
23960
|
delete this.data.instances[id];
|
|
@@ -23699,8 +23962,8 @@ var init_instance_registry = __esm({
|
|
|
23699
23962
|
get(id) {
|
|
23700
23963
|
return this.data.instances[id];
|
|
23701
23964
|
}
|
|
23702
|
-
getByRoot(
|
|
23703
|
-
return Object.values(this.data.instances).find((e) => e.root ===
|
|
23965
|
+
getByRoot(root) {
|
|
23966
|
+
return Object.values(this.data.instances).find((e) => e.root === root);
|
|
23704
23967
|
}
|
|
23705
23968
|
list() {
|
|
23706
23969
|
return Object.values(this.data.instances);
|
|
@@ -23958,14 +24221,15 @@ var init_setup_agents = __esm({
|
|
|
23958
24221
|
// src/core/setup/setup-workspace.ts
|
|
23959
24222
|
import * as clack4 from "@clack/prompts";
|
|
23960
24223
|
async function setupWorkspace(opts) {
|
|
23961
|
-
const { existing, stepNum, totalSteps } = opts ?? {};
|
|
24224
|
+
const { existing, stepNum, totalSteps, isGlobal } = opts ?? {};
|
|
23962
24225
|
if (stepNum != null && totalSteps != null) {
|
|
23963
24226
|
console.log(step(stepNum, totalSteps, "Workspace"));
|
|
23964
24227
|
}
|
|
24228
|
+
const defaultDir = isGlobal === false ? process.cwd() : "~/openacp-workspace";
|
|
23965
24229
|
const baseDir = guardCancel2(
|
|
23966
24230
|
await clack4.text({
|
|
23967
|
-
message: "Base directory for workspaces:",
|
|
23968
|
-
initialValue: existing ??
|
|
24231
|
+
message: "Base directory for agent workspaces:",
|
|
24232
|
+
initialValue: existing ?? defaultDir,
|
|
23969
24233
|
validate: (val) => (val ?? "").toString().trim().length > 0 ? void 0 : "Path cannot be empty"
|
|
23970
24234
|
})
|
|
23971
24235
|
);
|
|
@@ -24491,9 +24755,81 @@ var init_instance_copy = __esm({
|
|
|
24491
24755
|
}
|
|
24492
24756
|
});
|
|
24493
24757
|
|
|
24758
|
+
// src/core/setup/git-protect.ts
|
|
24759
|
+
import fs46 from "fs";
|
|
24760
|
+
import path51 from "path";
|
|
24761
|
+
function protectLocalInstance(projectDir) {
|
|
24762
|
+
ensureGitignore(projectDir);
|
|
24763
|
+
ensureClaudeMd(projectDir);
|
|
24764
|
+
printSecurityWarning();
|
|
24765
|
+
}
|
|
24766
|
+
function ensureGitignore(projectDir) {
|
|
24767
|
+
const gitignorePath = path51.join(projectDir, ".gitignore");
|
|
24768
|
+
const entry = ".openacp";
|
|
24769
|
+
if (fs46.existsSync(gitignorePath)) {
|
|
24770
|
+
const content = fs46.readFileSync(gitignorePath, "utf-8");
|
|
24771
|
+
const lines = content.split("\n").map((l) => l.trim());
|
|
24772
|
+
if (lines.includes(entry) || lines.includes(".openacp")) {
|
|
24773
|
+
return;
|
|
24774
|
+
}
|
|
24775
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
24776
|
+
fs46.appendFileSync(gitignorePath, `${separator}
|
|
24777
|
+
# OpenACP local workspace (contains secrets)
|
|
24778
|
+
${entry}
|
|
24779
|
+
`);
|
|
24780
|
+
} else {
|
|
24781
|
+
fs46.writeFileSync(gitignorePath, `# OpenACP local workspace (contains secrets)
|
|
24782
|
+
${entry}
|
|
24783
|
+
`);
|
|
24784
|
+
}
|
|
24785
|
+
}
|
|
24786
|
+
function ensureClaudeMd(projectDir) {
|
|
24787
|
+
const claudeMdPath = path51.join(projectDir, "CLAUDE.md");
|
|
24788
|
+
const marker = "## Local OpenACP Workspace";
|
|
24789
|
+
if (fs46.existsSync(claudeMdPath)) {
|
|
24790
|
+
const content = fs46.readFileSync(claudeMdPath, "utf-8");
|
|
24791
|
+
if (content.includes(marker)) {
|
|
24792
|
+
return;
|
|
24793
|
+
}
|
|
24794
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
24795
|
+
fs46.appendFileSync(claudeMdPath, `${separator}
|
|
24796
|
+
## Local OpenACP Workspace
|
|
24797
|
+
|
|
24798
|
+
The \`.openacp/\` directory contains a local OpenACP workspace with secrets (bot tokens, API keys). Do not read, commit, or reference files inside it.
|
|
24799
|
+
`);
|
|
24800
|
+
} else {
|
|
24801
|
+
fs46.writeFileSync(claudeMdPath, `# CLAUDE.md
|
|
24802
|
+
|
|
24803
|
+
## Local OpenACP Workspace
|
|
24804
|
+
|
|
24805
|
+
The \`.openacp/\` directory contains a local OpenACP workspace with secrets (bot tokens, API keys). Do not read, commit, or reference files inside it.
|
|
24806
|
+
`);
|
|
24807
|
+
}
|
|
24808
|
+
}
|
|
24809
|
+
function printSecurityWarning() {
|
|
24810
|
+
const red = "\x1B[1;91m";
|
|
24811
|
+
const yellow = "\x1B[1;33m";
|
|
24812
|
+
const reset = "\x1B[0m";
|
|
24813
|
+
const dim3 = "\x1B[2m";
|
|
24814
|
+
console.log("");
|
|
24815
|
+
console.log(`${red} \u26A0 SECURITY WARNING${reset}`);
|
|
24816
|
+
console.log(`${red} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${reset}`);
|
|
24817
|
+
console.log(`${yellow} .openacp/ contains bot tokens and API secrets.${reset}`);
|
|
24818
|
+
console.log(`${yellow} It has been added to .gitignore automatically.${reset}`);
|
|
24819
|
+
console.log(`${dim3} Verify before committing: git status${reset}`);
|
|
24820
|
+
console.log(`${red} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${reset}`);
|
|
24821
|
+
console.log("");
|
|
24822
|
+
}
|
|
24823
|
+
var init_git_protect = __esm({
|
|
24824
|
+
"src/core/setup/git-protect.ts"() {
|
|
24825
|
+
"use strict";
|
|
24826
|
+
}
|
|
24827
|
+
});
|
|
24828
|
+
|
|
24494
24829
|
// src/core/setup/wizard.ts
|
|
24495
|
-
import * as
|
|
24496
|
-
import * as
|
|
24830
|
+
import * as path52 from "path";
|
|
24831
|
+
import * as fs47 from "fs";
|
|
24832
|
+
import * as os25 from "os";
|
|
24497
24833
|
import * as clack8 from "@clack/prompts";
|
|
24498
24834
|
async function fetchCommunityAdapters() {
|
|
24499
24835
|
try {
|
|
@@ -24522,23 +24858,24 @@ async function runSetup(configManager, opts) {
|
|
|
24522
24858
|
const isGlobal = instanceRoot === getGlobalRoot();
|
|
24523
24859
|
let instanceName = opts?.instanceName;
|
|
24524
24860
|
if (!instanceName) {
|
|
24525
|
-
const defaultName = isGlobal ? "
|
|
24861
|
+
const defaultName = isGlobal ? "Global workspace" : path52.basename(path52.dirname(instanceRoot));
|
|
24862
|
+
const locationHint = isGlobal ? "global (~/.openacp)" : `local (${instanceRoot.replace(/\/.openacp$/, "").replace(os25.homedir(), "~")})`;
|
|
24526
24863
|
const nameResult = await clack8.text({
|
|
24527
|
-
message:
|
|
24528
|
-
|
|
24864
|
+
message: `Name for this workspace (${locationHint})`,
|
|
24865
|
+
initialValue: defaultName,
|
|
24529
24866
|
validate: (v) => !v?.trim() ? "Name cannot be empty" : void 0
|
|
24530
24867
|
});
|
|
24531
24868
|
if (clack8.isCancel(nameResult)) return false;
|
|
24532
24869
|
instanceName = nameResult.trim();
|
|
24533
24870
|
}
|
|
24534
24871
|
const globalRoot = getGlobalRoot();
|
|
24535
|
-
const registryPath =
|
|
24872
|
+
const registryPath = path52.join(globalRoot, "instances.json");
|
|
24536
24873
|
const instanceRegistry = new InstanceRegistry(registryPath);
|
|
24537
24874
|
await instanceRegistry.load();
|
|
24538
24875
|
let didCopy = false;
|
|
24539
24876
|
if (opts?.from) {
|
|
24540
|
-
const fromRoot =
|
|
24541
|
-
if (
|
|
24877
|
+
const fromRoot = path52.join(opts.from, ".openacp");
|
|
24878
|
+
if (fs47.existsSync(path52.join(fromRoot, "config.json"))) {
|
|
24542
24879
|
const inheritableMap = buildInheritableKeysMap();
|
|
24543
24880
|
await copyInstance(fromRoot, instanceRoot, { inheritableKeys: inheritableMap });
|
|
24544
24881
|
didCopy = true;
|
|
@@ -24549,11 +24886,26 @@ async function runSetup(configManager, opts) {
|
|
|
24549
24886
|
}
|
|
24550
24887
|
if (!didCopy) {
|
|
24551
24888
|
const existingInstances = instanceRegistry.list().filter(
|
|
24552
|
-
(e) =>
|
|
24889
|
+
(e) => fs47.existsSync(path52.join(e.root, "config.json")) && e.root !== instanceRoot
|
|
24553
24890
|
);
|
|
24554
24891
|
if (existingInstances.length > 0) {
|
|
24892
|
+
let singleLabel;
|
|
24893
|
+
if (existingInstances.length === 1) {
|
|
24894
|
+
const e = existingInstances[0];
|
|
24895
|
+
let name = e.id;
|
|
24896
|
+
try {
|
|
24897
|
+
const cfg = JSON.parse(fs47.readFileSync(path52.join(e.root, "config.json"), "utf-8"));
|
|
24898
|
+
if (cfg.instanceName) name = cfg.instanceName;
|
|
24899
|
+
} catch {
|
|
24900
|
+
}
|
|
24901
|
+
const isGlobalEntry = e.root === getGlobalRoot();
|
|
24902
|
+
const displayPath = e.root.replace(os25.homedir(), "~");
|
|
24903
|
+
const type = isGlobalEntry ? "global" : "local";
|
|
24904
|
+
singleLabel = `${name} workspace (${type} \u2014 ${displayPath})`;
|
|
24905
|
+
}
|
|
24906
|
+
const confirmMsg = singleLabel ? `Copy config from ${singleLabel}?` : "Copy config from an existing workspace?";
|
|
24555
24907
|
const shouldCopy = await clack8.confirm({
|
|
24556
|
-
message:
|
|
24908
|
+
message: confirmMsg,
|
|
24557
24909
|
initialValue: true
|
|
24558
24910
|
});
|
|
24559
24911
|
if (clack8.isCancel(shouldCopy)) return false;
|
|
@@ -24563,16 +24915,18 @@ async function runSetup(configManager, opts) {
|
|
|
24563
24915
|
sourceRoot = existingInstances[0].root;
|
|
24564
24916
|
} else {
|
|
24565
24917
|
const choice = await clack8.select({
|
|
24566
|
-
message: "Which
|
|
24918
|
+
message: "Which workspace to copy from?",
|
|
24567
24919
|
options: existingInstances.map((e) => {
|
|
24568
24920
|
let name = e.id;
|
|
24569
24921
|
try {
|
|
24570
|
-
const cfg = JSON.parse(
|
|
24922
|
+
const cfg = JSON.parse(fs47.readFileSync(path52.join(e.root, "config.json"), "utf-8"));
|
|
24571
24923
|
if (cfg.instanceName) name = cfg.instanceName;
|
|
24572
24924
|
} catch {
|
|
24573
24925
|
}
|
|
24574
|
-
const
|
|
24575
|
-
|
|
24926
|
+
const isGlobalEntry = e.root === getGlobalRoot();
|
|
24927
|
+
const displayPath = e.root.replace(os25.homedir(), "~");
|
|
24928
|
+
const type = isGlobalEntry ? "global" : "local";
|
|
24929
|
+
return { value: e.root, label: `${name} workspace (${type} \u2014 ${displayPath})` };
|
|
24576
24930
|
})
|
|
24577
24931
|
});
|
|
24578
24932
|
if (clack8.isCancel(choice)) return false;
|
|
@@ -24642,10 +24996,10 @@ async function runSetup(configManager, opts) {
|
|
|
24642
24996
|
if (channelId.startsWith("official:")) {
|
|
24643
24997
|
const npmPackage = channelId.slice("official:".length);
|
|
24644
24998
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
24645
|
-
const pluginsDir =
|
|
24646
|
-
const nodeModulesDir =
|
|
24647
|
-
const installedPath =
|
|
24648
|
-
if (!
|
|
24999
|
+
const pluginsDir = path52.join(instanceRoot, "plugins");
|
|
25000
|
+
const nodeModulesDir = path52.join(pluginsDir, "node_modules");
|
|
25001
|
+
const installedPath = path52.join(nodeModulesDir, npmPackage);
|
|
25002
|
+
if (!fs47.existsSync(installedPath)) {
|
|
24649
25003
|
try {
|
|
24650
25004
|
clack8.log.step(`Installing ${npmPackage}...`);
|
|
24651
25005
|
execFileSync8("npm", ["install", npmPackage, "--prefix", pluginsDir, "--save"], {
|
|
@@ -24658,9 +25012,9 @@ async function runSetup(configManager, opts) {
|
|
|
24658
25012
|
}
|
|
24659
25013
|
}
|
|
24660
25014
|
try {
|
|
24661
|
-
const installedPkgPath =
|
|
24662
|
-
const installedPkg = JSON.parse(
|
|
24663
|
-
const pluginModule = await import(
|
|
25015
|
+
const installedPkgPath = path52.join(nodeModulesDir, npmPackage, "package.json");
|
|
25016
|
+
const installedPkg = JSON.parse(fs47.readFileSync(installedPkgPath, "utf-8"));
|
|
25017
|
+
const pluginModule = await import(path52.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
|
|
24664
25018
|
const plugin2 = pluginModule.default;
|
|
24665
25019
|
if (plugin2?.install) {
|
|
24666
25020
|
const installCtx = createInstallContext2({
|
|
@@ -24690,8 +25044,8 @@ async function runSetup(configManager, opts) {
|
|
|
24690
25044
|
if (channelId.startsWith("community:")) {
|
|
24691
25045
|
const npmPackage = channelId.slice("community:".length);
|
|
24692
25046
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
24693
|
-
const pluginsDir =
|
|
24694
|
-
const nodeModulesDir =
|
|
25047
|
+
const pluginsDir = path52.join(instanceRoot, "plugins");
|
|
25048
|
+
const nodeModulesDir = path52.join(pluginsDir, "node_modules");
|
|
24695
25049
|
try {
|
|
24696
25050
|
execFileSync8("npm", ["install", npmPackage, "--prefix", pluginsDir, "--save"], {
|
|
24697
25051
|
stdio: "inherit",
|
|
@@ -24703,9 +25057,9 @@ async function runSetup(configManager, opts) {
|
|
|
24703
25057
|
}
|
|
24704
25058
|
try {
|
|
24705
25059
|
const { readFileSync: readFileSync18 } = await import("fs");
|
|
24706
|
-
const installedPkgPath =
|
|
25060
|
+
const installedPkgPath = path52.join(nodeModulesDir, npmPackage, "package.json");
|
|
24707
25061
|
const installedPkg = JSON.parse(readFileSync18(installedPkgPath, "utf-8"));
|
|
24708
|
-
const pluginModule = await import(
|
|
25062
|
+
const pluginModule = await import(path52.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
|
|
24709
25063
|
const plugin2 = pluginModule.default;
|
|
24710
25064
|
if (plugin2?.install) {
|
|
24711
25065
|
const installCtx = createInstallContext2({
|
|
@@ -24737,7 +25091,7 @@ async function runSetup(configManager, opts) {
|
|
|
24737
25091
|
const { defaultAgent } = await setupAgents();
|
|
24738
25092
|
await setupIntegrations();
|
|
24739
25093
|
currentStep++;
|
|
24740
|
-
const workspace = await setupWorkspace({ stepNum: currentStep, totalSteps });
|
|
25094
|
+
const workspace = await setupWorkspace({ stepNum: currentStep, totalSteps, isGlobal });
|
|
24741
25095
|
let runMode = "foreground";
|
|
24742
25096
|
let autoStart = false;
|
|
24743
25097
|
if (!opts?.skipRunMode) {
|
|
@@ -24760,7 +25114,7 @@ async function runSetup(configManager, opts) {
|
|
|
24760
25114
|
security,
|
|
24761
25115
|
logging: {
|
|
24762
25116
|
level: "info",
|
|
24763
|
-
logDir:
|
|
25117
|
+
logDir: path52.join(instanceRoot, "logs"),
|
|
24764
25118
|
maxFileSize: "10m",
|
|
24765
25119
|
maxFiles: 7,
|
|
24766
25120
|
sessionLogRetentionDays: 30
|
|
@@ -24806,9 +25160,17 @@ async function runSetup(configManager, opts) {
|
|
|
24806
25160
|
await registerBuiltinPlugins(settingsManager, pluginRegistry);
|
|
24807
25161
|
await pluginRegistry.save();
|
|
24808
25162
|
}
|
|
24809
|
-
const
|
|
24810
|
-
|
|
24811
|
-
|
|
25163
|
+
const existingEntry = instanceRegistry.getByRoot(instanceRoot);
|
|
25164
|
+
if (!existingEntry) {
|
|
25165
|
+
const id = instanceRegistry.uniqueId(generateSlug(instanceName));
|
|
25166
|
+
instanceRegistry.register(id, instanceRoot);
|
|
25167
|
+
await instanceRegistry.save();
|
|
25168
|
+
}
|
|
25169
|
+
const isLocal = instanceRoot !== path52.join(getGlobalRoot());
|
|
25170
|
+
if (isLocal) {
|
|
25171
|
+
const projectDir = path52.dirname(instanceRoot);
|
|
25172
|
+
protectLocalInstance(projectDir);
|
|
25173
|
+
}
|
|
24812
25174
|
clack8.outro(`Config saved to ${configManager.getConfigPath()}`);
|
|
24813
25175
|
if (!opts?.skipRunMode) {
|
|
24814
25176
|
console.log(ok("Starting OpenACP..."));
|
|
@@ -24942,6 +25304,7 @@ var init_wizard = __esm({
|
|
|
24942
25304
|
init_instance_registry();
|
|
24943
25305
|
init_instance_context();
|
|
24944
25306
|
init_instance_copy();
|
|
25307
|
+
init_git_protect();
|
|
24945
25308
|
}
|
|
24946
25309
|
});
|
|
24947
25310
|
|
|
@@ -25092,8 +25455,8 @@ var dev_loader_exports = {};
|
|
|
25092
25455
|
__export(dev_loader_exports, {
|
|
25093
25456
|
DevPluginLoader: () => DevPluginLoader
|
|
25094
25457
|
});
|
|
25095
|
-
import
|
|
25096
|
-
import
|
|
25458
|
+
import fs48 from "fs";
|
|
25459
|
+
import path53 from "path";
|
|
25097
25460
|
var loadCounter, DevPluginLoader;
|
|
25098
25461
|
var init_dev_loader = __esm({
|
|
25099
25462
|
"src/core/plugin/dev-loader.ts"() {
|
|
@@ -25102,15 +25465,15 @@ var init_dev_loader = __esm({
|
|
|
25102
25465
|
DevPluginLoader = class {
|
|
25103
25466
|
pluginPath;
|
|
25104
25467
|
constructor(pluginPath) {
|
|
25105
|
-
this.pluginPath =
|
|
25468
|
+
this.pluginPath = path53.resolve(pluginPath);
|
|
25106
25469
|
}
|
|
25107
25470
|
async load() {
|
|
25108
|
-
const distIndex =
|
|
25109
|
-
const srcIndex =
|
|
25110
|
-
if (!
|
|
25471
|
+
const distIndex = path53.join(this.pluginPath, "dist", "index.js");
|
|
25472
|
+
const srcIndex = path53.join(this.pluginPath, "src", "index.ts");
|
|
25473
|
+
if (!fs48.existsSync(distIndex) && !fs48.existsSync(srcIndex)) {
|
|
25111
25474
|
throw new Error(`Plugin not found at ${this.pluginPath}. Expected dist/index.js or src/index.ts`);
|
|
25112
25475
|
}
|
|
25113
|
-
if (!
|
|
25476
|
+
if (!fs48.existsSync(distIndex)) {
|
|
25114
25477
|
throw new Error(`Built plugin not found at ${distIndex}. Run 'npm run build' first.`);
|
|
25115
25478
|
}
|
|
25116
25479
|
const cacheBuster = `v=${Date.now()}-${++loadCounter}`;
|
|
@@ -25125,7 +25488,7 @@ var init_dev_loader = __esm({
|
|
|
25125
25488
|
return this.pluginPath;
|
|
25126
25489
|
}
|
|
25127
25490
|
getDistPath() {
|
|
25128
|
-
return
|
|
25491
|
+
return path53.join(this.pluginPath, "dist");
|
|
25129
25492
|
}
|
|
25130
25493
|
};
|
|
25131
25494
|
}
|
|
@@ -25137,8 +25500,8 @@ __export(main_exports, {
|
|
|
25137
25500
|
RESTART_EXIT_CODE: () => RESTART_EXIT_CODE,
|
|
25138
25501
|
startServer: () => startServer
|
|
25139
25502
|
});
|
|
25140
|
-
import
|
|
25141
|
-
import
|
|
25503
|
+
import path54 from "path";
|
|
25504
|
+
import fs49 from "fs";
|
|
25142
25505
|
async function startServer(opts) {
|
|
25143
25506
|
const ctx = opts?.instanceContext ?? createInstanceContext({
|
|
25144
25507
|
id: "main",
|
|
@@ -25219,25 +25582,25 @@ async function startServer(opts) {
|
|
|
25219
25582
|
try {
|
|
25220
25583
|
let modulePath;
|
|
25221
25584
|
if (name.startsWith("/") || name.startsWith(".")) {
|
|
25222
|
-
const resolved =
|
|
25223
|
-
const pkgPath =
|
|
25224
|
-
const pkg = JSON.parse(await
|
|
25225
|
-
modulePath =
|
|
25585
|
+
const resolved = path54.resolve(name);
|
|
25586
|
+
const pkgPath = path54.join(resolved, "package.json");
|
|
25587
|
+
const pkg = JSON.parse(await fs49.promises.readFile(pkgPath, "utf-8"));
|
|
25588
|
+
modulePath = path54.join(resolved, pkg.main || "dist/index.js");
|
|
25226
25589
|
} else {
|
|
25227
|
-
const nodeModulesDir =
|
|
25228
|
-
let pkgDir =
|
|
25229
|
-
if (!
|
|
25590
|
+
const nodeModulesDir = path54.join(ctx.paths.plugins, "node_modules");
|
|
25591
|
+
let pkgDir = path54.join(nodeModulesDir, name);
|
|
25592
|
+
if (!fs49.existsSync(path54.join(pkgDir, "package.json"))) {
|
|
25230
25593
|
let found = false;
|
|
25231
|
-
const scopes =
|
|
25594
|
+
const scopes = fs49.existsSync(nodeModulesDir) ? fs49.readdirSync(nodeModulesDir).filter((d) => d.startsWith("@")) : [];
|
|
25232
25595
|
for (const scope of scopes) {
|
|
25233
|
-
const scopeDir =
|
|
25234
|
-
const pkgs =
|
|
25596
|
+
const scopeDir = path54.join(nodeModulesDir, scope);
|
|
25597
|
+
const pkgs = fs49.readdirSync(scopeDir);
|
|
25235
25598
|
for (const pkg2 of pkgs) {
|
|
25236
|
-
const candidateDir =
|
|
25237
|
-
const candidatePkgPath =
|
|
25238
|
-
if (
|
|
25599
|
+
const candidateDir = path54.join(scopeDir, pkg2);
|
|
25600
|
+
const candidatePkgPath = path54.join(candidateDir, "package.json");
|
|
25601
|
+
if (fs49.existsSync(candidatePkgPath)) {
|
|
25239
25602
|
try {
|
|
25240
|
-
const candidatePkg = JSON.parse(
|
|
25603
|
+
const candidatePkg = JSON.parse(fs49.readFileSync(candidatePkgPath, "utf-8"));
|
|
25241
25604
|
const pluginName = candidatePkg.openacp?.pluginName;
|
|
25242
25605
|
if (pluginName === name) {
|
|
25243
25606
|
pkgDir = candidateDir;
|
|
@@ -25251,9 +25614,9 @@ async function startServer(opts) {
|
|
|
25251
25614
|
if (found) break;
|
|
25252
25615
|
}
|
|
25253
25616
|
}
|
|
25254
|
-
const pkgJsonPath =
|
|
25255
|
-
const pkg = JSON.parse(await
|
|
25256
|
-
modulePath =
|
|
25617
|
+
const pkgJsonPath = path54.join(pkgDir, "package.json");
|
|
25618
|
+
const pkg = JSON.parse(await fs49.promises.readFile(pkgJsonPath, "utf-8"));
|
|
25619
|
+
modulePath = path54.join(pkgDir, pkg.main || "dist/index.js");
|
|
25257
25620
|
}
|
|
25258
25621
|
log.debug({ plugin: name, modulePath }, "Loading community plugin");
|
|
25259
25622
|
const mod = await import(modulePath);
|
|
@@ -25284,7 +25647,7 @@ async function startServer(opts) {
|
|
|
25284
25647
|
if (!opts.noWatch) {
|
|
25285
25648
|
const distPath = devLoader.getDistPath();
|
|
25286
25649
|
let reloadTimer = null;
|
|
25287
|
-
|
|
25650
|
+
fs49.watch(distPath, { recursive: true }, (_eventType, filename) => {
|
|
25288
25651
|
if (!filename?.endsWith(".js")) return;
|
|
25289
25652
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
25290
25653
|
reloadTimer = setTimeout(async () => {
|
|
@@ -25362,21 +25725,21 @@ async function startServer(opts) {
|
|
|
25362
25725
|
if (isDaemon) {
|
|
25363
25726
|
const { spawn: spawnChild } = await import("child_process");
|
|
25364
25727
|
const { expandHome: expandHome4 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
25365
|
-
const
|
|
25728
|
+
const fs53 = await import("fs");
|
|
25366
25729
|
const pathMod2 = await import("path");
|
|
25367
25730
|
const cliPath = pathMod2.resolve(process.argv[1]);
|
|
25368
25731
|
const resolvedLogDir = expandHome4(config.logging.logDir);
|
|
25369
|
-
|
|
25732
|
+
fs53.mkdirSync(resolvedLogDir, { recursive: true });
|
|
25370
25733
|
const logFile = pathMod2.join(resolvedLogDir, "openacp.log");
|
|
25371
|
-
const out =
|
|
25372
|
-
const err =
|
|
25734
|
+
const out = fs53.openSync(logFile, "a");
|
|
25735
|
+
const err = fs53.openSync(logFile, "a");
|
|
25373
25736
|
const child = spawnChild(process.execPath, [cliPath, "--daemon-child"], {
|
|
25374
25737
|
detached: true,
|
|
25375
25738
|
stdio: ["ignore", out, err],
|
|
25376
25739
|
env: { ...process.env, OPENACP_SKIP_UPDATE_CHECK: "1" }
|
|
25377
25740
|
});
|
|
25378
|
-
|
|
25379
|
-
|
|
25741
|
+
fs53.closeSync(out);
|
|
25742
|
+
fs53.closeSync(err);
|
|
25380
25743
|
child.unref();
|
|
25381
25744
|
log.info({ newPid: child.pid }, "Respawned daemon for restart");
|
|
25382
25745
|
} else if (!process.env.OPENACP_DEV_LOOP) {
|
|
@@ -25405,7 +25768,7 @@ async function startServer(opts) {
|
|
|
25405
25768
|
await core.start();
|
|
25406
25769
|
try {
|
|
25407
25770
|
const globalRoot = getGlobalRoot();
|
|
25408
|
-
const registryPath =
|
|
25771
|
+
const registryPath = path54.join(globalRoot, "instances.json");
|
|
25409
25772
|
const instanceReg = new InstanceRegistry(registryPath);
|
|
25410
25773
|
await instanceReg.load();
|
|
25411
25774
|
if (!instanceReg.getByRoot(ctx.root)) {
|
|
@@ -25553,10 +25916,10 @@ var restart_exports = {};
|
|
|
25553
25916
|
__export(restart_exports, {
|
|
25554
25917
|
cmdRestart: () => cmdRestart
|
|
25555
25918
|
});
|
|
25556
|
-
import
|
|
25557
|
-
import
|
|
25919
|
+
import path55 from "path";
|
|
25920
|
+
import os26 from "os";
|
|
25558
25921
|
async function cmdRestart(args2 = [], instanceRoot) {
|
|
25559
|
-
const
|
|
25922
|
+
const root = instanceRoot ?? path55.join(os26.homedir(), ".openacp");
|
|
25560
25923
|
if (wantsHelp(args2)) {
|
|
25561
25924
|
console.log(`
|
|
25562
25925
|
\x1B[1mopenacp restart\x1B[0m \u2014 Restart the background daemon
|
|
@@ -25581,8 +25944,8 @@ Stops the running daemon (if any) and starts a new one.
|
|
|
25581
25944
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
25582
25945
|
const { checkAndPromptUpdate: checkAndPromptUpdate2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
25583
25946
|
await checkAndPromptUpdate2();
|
|
25584
|
-
const pidPath = getPidPath2(
|
|
25585
|
-
const stopResult = await stopDaemon2(pidPath,
|
|
25947
|
+
const pidPath = getPidPath2(root);
|
|
25948
|
+
const stopResult = await stopDaemon2(pidPath, root);
|
|
25586
25949
|
if (stopResult.stopped) {
|
|
25587
25950
|
console.log(`Stopped daemon (was PID ${stopResult.pid})`);
|
|
25588
25951
|
}
|
|
@@ -25595,23 +25958,23 @@ Stops the running daemon (if any) and starts a new one.
|
|
|
25595
25958
|
const config = cm.get();
|
|
25596
25959
|
const useForeground = forceForeground || !forceDaemon && config.runMode !== "daemon";
|
|
25597
25960
|
if (useForeground) {
|
|
25598
|
-
markRunning2(
|
|
25599
|
-
printInstanceHint(
|
|
25961
|
+
markRunning2(root);
|
|
25962
|
+
printInstanceHint(root);
|
|
25600
25963
|
console.log("Starting in foreground mode...");
|
|
25601
25964
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
25602
25965
|
const ctx = createInstanceContext({
|
|
25603
25966
|
id: "default",
|
|
25604
|
-
root
|
|
25605
|
-
isGlobal:
|
|
25967
|
+
root,
|
|
25968
|
+
isGlobal: root === getGlobalRoot()
|
|
25606
25969
|
});
|
|
25607
25970
|
await startServer2({ instanceContext: ctx });
|
|
25608
25971
|
} else {
|
|
25609
|
-
const result = startDaemon2(pidPath, config.logging.logDir,
|
|
25972
|
+
const result = startDaemon2(pidPath, config.logging.logDir, root);
|
|
25610
25973
|
if ("error" in result) {
|
|
25611
25974
|
console.error(result.error);
|
|
25612
25975
|
process.exit(1);
|
|
25613
25976
|
}
|
|
25614
|
-
printInstanceHint(
|
|
25977
|
+
printInstanceHint(root);
|
|
25615
25978
|
console.log(`OpenACP daemon started (PID ${result.pid})`);
|
|
25616
25979
|
}
|
|
25617
25980
|
}
|
|
@@ -25631,9 +25994,9 @@ __export(status_exports, {
|
|
|
25631
25994
|
formatInstanceStatus: () => formatInstanceStatus,
|
|
25632
25995
|
readInstanceInfo: () => readInstanceInfo
|
|
25633
25996
|
});
|
|
25634
|
-
import
|
|
25635
|
-
import
|
|
25636
|
-
import
|
|
25997
|
+
import fs50 from "fs";
|
|
25998
|
+
import path56 from "path";
|
|
25999
|
+
import os27 from "os";
|
|
25637
26000
|
async function cmdStatus(args2 = [], instanceRoot) {
|
|
25638
26001
|
if (args2.includes("--all")) {
|
|
25639
26002
|
await showAllInstances();
|
|
@@ -25644,16 +26007,16 @@ async function cmdStatus(args2 = [], instanceRoot) {
|
|
|
25644
26007
|
await showInstanceById(args2[idIdx + 1]);
|
|
25645
26008
|
return;
|
|
25646
26009
|
}
|
|
25647
|
-
const
|
|
25648
|
-
await showSingleInstance(
|
|
26010
|
+
const root = instanceRoot ?? getGlobalRoot();
|
|
26011
|
+
await showSingleInstance(root);
|
|
25649
26012
|
}
|
|
25650
26013
|
async function showAllInstances() {
|
|
25651
|
-
const registryPath =
|
|
26014
|
+
const registryPath = path56.join(getGlobalRoot(), "instances.json");
|
|
25652
26015
|
const registry = new InstanceRegistry(registryPath);
|
|
25653
26016
|
await registry.load();
|
|
25654
26017
|
const instances = registry.list();
|
|
25655
26018
|
if (instances.length === 0) {
|
|
25656
|
-
console.log("No
|
|
26019
|
+
console.log("No workspaces registered.");
|
|
25657
26020
|
return;
|
|
25658
26021
|
}
|
|
25659
26022
|
console.log("");
|
|
@@ -25665,7 +26028,7 @@ async function showAllInstances() {
|
|
|
25665
26028
|
const mode = info.pid ? info.runMode === "daemon" ? "daemon" : "fg" : "\u2014";
|
|
25666
26029
|
const api = info.apiPort ? String(info.apiPort) : "\u2014";
|
|
25667
26030
|
const tunnel = info.tunnelPort ? String(info.tunnelPort) : "\u2014";
|
|
25668
|
-
const dir = entry.root.replace(/\/.openacp$/, "").replace(
|
|
26031
|
+
const dir = entry.root.replace(/\/.openacp$/, "").replace(os27.homedir(), "~");
|
|
25669
26032
|
const channels = info.channels.join(", ") || "\u2014";
|
|
25670
26033
|
const name = info.name ?? entry.id;
|
|
25671
26034
|
console.log(` ${status.padEnd(10)} ${entry.id.padEnd(16)} ${name.padEnd(16)} ${dir.padEnd(20)} ${mode.padEnd(8)} ${channels.padEnd(10)} ${api.padEnd(6)} ${tunnel}`);
|
|
@@ -25673,18 +26036,18 @@ async function showAllInstances() {
|
|
|
25673
26036
|
console.log("");
|
|
25674
26037
|
}
|
|
25675
26038
|
async function showInstanceById(id) {
|
|
25676
|
-
const registryPath =
|
|
26039
|
+
const registryPath = path56.join(getGlobalRoot(), "instances.json");
|
|
25677
26040
|
const registry = new InstanceRegistry(registryPath);
|
|
25678
26041
|
await registry.load();
|
|
25679
26042
|
const entry = registry.get(id);
|
|
25680
26043
|
if (!entry) {
|
|
25681
|
-
console.error(`
|
|
26044
|
+
console.error(`Workspace "${id}" not found.`);
|
|
25682
26045
|
process.exit(1);
|
|
25683
26046
|
}
|
|
25684
26047
|
await showSingleInstance(entry.root);
|
|
25685
26048
|
}
|
|
25686
|
-
async function showSingleInstance(
|
|
25687
|
-
const info = readInstanceInfo(
|
|
26049
|
+
async function showSingleInstance(root) {
|
|
26050
|
+
const info = readInstanceInfo(root);
|
|
25688
26051
|
if (info.pid) {
|
|
25689
26052
|
console.log(`OpenACP is running (PID ${info.pid})`);
|
|
25690
26053
|
if (info.name) console.log(` Name: ${info.name}`);
|
|
@@ -25695,7 +26058,7 @@ async function showSingleInstance(root2) {
|
|
|
25695
26058
|
console.log("OpenACP is not running.");
|
|
25696
26059
|
}
|
|
25697
26060
|
}
|
|
25698
|
-
function readInstanceInfo(
|
|
26061
|
+
function readInstanceInfo(root) {
|
|
25699
26062
|
const result = {
|
|
25700
26063
|
name: null,
|
|
25701
26064
|
pid: null,
|
|
@@ -25705,13 +26068,13 @@ function readInstanceInfo(root2) {
|
|
|
25705
26068
|
channels: []
|
|
25706
26069
|
};
|
|
25707
26070
|
try {
|
|
25708
|
-
const config = JSON.parse(
|
|
26071
|
+
const config = JSON.parse(fs50.readFileSync(path56.join(root, "config.json"), "utf-8"));
|
|
25709
26072
|
result.name = config.instanceName ?? null;
|
|
25710
26073
|
result.runMode = config.runMode ?? null;
|
|
25711
26074
|
} catch {
|
|
25712
26075
|
}
|
|
25713
26076
|
try {
|
|
25714
|
-
const pid = parseInt(
|
|
26077
|
+
const pid = parseInt(fs50.readFileSync(path56.join(root, "openacp.pid"), "utf-8").trim());
|
|
25715
26078
|
if (!isNaN(pid)) {
|
|
25716
26079
|
process.kill(pid, 0);
|
|
25717
26080
|
result.pid = pid;
|
|
@@ -25719,19 +26082,19 @@ function readInstanceInfo(root2) {
|
|
|
25719
26082
|
} catch {
|
|
25720
26083
|
}
|
|
25721
26084
|
try {
|
|
25722
|
-
const port = parseInt(
|
|
26085
|
+
const port = parseInt(fs50.readFileSync(path56.join(root, "api.port"), "utf-8").trim());
|
|
25723
26086
|
if (!isNaN(port)) result.apiPort = port;
|
|
25724
26087
|
} catch {
|
|
25725
26088
|
}
|
|
25726
26089
|
try {
|
|
25727
|
-
const tunnels = JSON.parse(
|
|
26090
|
+
const tunnels = JSON.parse(fs50.readFileSync(path56.join(root, "tunnels.json"), "utf-8"));
|
|
25728
26091
|
const entries = Object.values(tunnels);
|
|
25729
26092
|
const systemEntry = entries.find((t) => t.type === "system");
|
|
25730
26093
|
if (systemEntry?.port) result.tunnelPort = systemEntry.port;
|
|
25731
26094
|
} catch {
|
|
25732
26095
|
}
|
|
25733
26096
|
try {
|
|
25734
|
-
const plugins = JSON.parse(
|
|
26097
|
+
const plugins = JSON.parse(fs50.readFileSync(path56.join(root, "plugins.json"), "utf-8"));
|
|
25735
26098
|
const adapters = ["@openacp/telegram", "@openacp/discord", "@openacp/slack"];
|
|
25736
26099
|
for (const name of adapters) {
|
|
25737
26100
|
if (plugins.installed?.[name] && plugins.installed[name].enabled !== false) {
|
|
@@ -25742,15 +26105,15 @@ function readInstanceInfo(root2) {
|
|
|
25742
26105
|
}
|
|
25743
26106
|
return result;
|
|
25744
26107
|
}
|
|
25745
|
-
function formatInstanceStatus(
|
|
25746
|
-
const info = readInstanceInfo(
|
|
26108
|
+
function formatInstanceStatus(root) {
|
|
26109
|
+
const info = readInstanceInfo(root);
|
|
25747
26110
|
if (!info.pid) return null;
|
|
25748
|
-
const
|
|
25749
|
-
const
|
|
26111
|
+
const isGlobal = root === getGlobalRoot();
|
|
26112
|
+
const displayPath = root.replace(os27.homedir(), "~");
|
|
25750
26113
|
const label = isGlobal ? "global" : "local";
|
|
25751
26114
|
const lines = [];
|
|
25752
26115
|
lines.push(` PID: ${info.pid}`);
|
|
25753
|
-
lines.push(`
|
|
26116
|
+
lines.push(` Workspace: ${info.name ?? "unknown"} (${label} \u2014 ${displayPath})`);
|
|
25754
26117
|
lines.push(` Mode: ${info.runMode ?? "unknown"}`);
|
|
25755
26118
|
if (info.channels.length > 0) lines.push(` Channels: ${info.channels.join(", ")}`);
|
|
25756
26119
|
if (info.apiPort) lines.push(` API: port ${info.apiPort}`);
|
|
@@ -25814,7 +26177,7 @@ var config_editor_exports = {};
|
|
|
25814
26177
|
__export(config_editor_exports, {
|
|
25815
26178
|
runConfigEditor: () => runConfigEditor
|
|
25816
26179
|
});
|
|
25817
|
-
import * as
|
|
26180
|
+
import * as path57 from "path";
|
|
25818
26181
|
import * as clack9 from "@clack/prompts";
|
|
25819
26182
|
async function select8(opts) {
|
|
25820
26183
|
const result = await clack9.select({
|
|
@@ -25974,14 +26337,14 @@ async function editDiscord(_config, _updates) {
|
|
|
25974
26337
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
25975
26338
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
25976
26339
|
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
25977
|
-
const
|
|
25978
|
-
const basePath =
|
|
26340
|
+
const root = getGlobalRoot2();
|
|
26341
|
+
const basePath = path57.join(root, "plugins");
|
|
25979
26342
|
const settingsManager = new SettingsManager2(basePath);
|
|
25980
26343
|
const ctx = createInstallContext2({
|
|
25981
26344
|
pluginName: plugin2.name,
|
|
25982
26345
|
settingsManager,
|
|
25983
26346
|
basePath,
|
|
25984
|
-
instanceRoot:
|
|
26347
|
+
instanceRoot: root
|
|
25985
26348
|
});
|
|
25986
26349
|
await plugin2.configure(ctx);
|
|
25987
26350
|
} else {
|
|
@@ -26438,17 +26801,17 @@ ${c2.cyan}${c2.bold}OpenACP Config Editor${c2.reset}`);
|
|
|
26438
26801
|
async function sendConfigViaApi(port, updates) {
|
|
26439
26802
|
const { apiCall: call } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
26440
26803
|
const paths = flattenToPaths(updates);
|
|
26441
|
-
for (const { path:
|
|
26804
|
+
for (const { path: path65, value } of paths) {
|
|
26442
26805
|
const res = await call(port, "/api/config", {
|
|
26443
26806
|
method: "PATCH",
|
|
26444
26807
|
headers: { "Content-Type": "application/json" },
|
|
26445
|
-
body: JSON.stringify({ path:
|
|
26808
|
+
body: JSON.stringify({ path: path65, value })
|
|
26446
26809
|
});
|
|
26447
26810
|
const data = await res.json();
|
|
26448
26811
|
if (!res.ok) {
|
|
26449
|
-
console.log(warn2(`Failed to update ${
|
|
26812
|
+
console.log(warn2(`Failed to update ${path65}: ${data.error}`));
|
|
26450
26813
|
} else if (data.needsRestart) {
|
|
26451
|
-
console.log(warn2(`${
|
|
26814
|
+
console.log(warn2(`${path65} updated \u2014 restart required`));
|
|
26452
26815
|
}
|
|
26453
26816
|
}
|
|
26454
26817
|
}
|
|
@@ -26551,9 +26914,78 @@ var init_interactive_menu = __esm({
|
|
|
26551
26914
|
}
|
|
26552
26915
|
});
|
|
26553
26916
|
|
|
26917
|
+
// src/cli/instance-prompt.ts
|
|
26918
|
+
var instance_prompt_exports = {};
|
|
26919
|
+
__export(instance_prompt_exports, {
|
|
26920
|
+
promptForInstance: () => promptForInstance
|
|
26921
|
+
});
|
|
26922
|
+
import fs52 from "fs";
|
|
26923
|
+
import path63 from "path";
|
|
26924
|
+
import os31 from "os";
|
|
26925
|
+
async function promptForInstance(opts) {
|
|
26926
|
+
const globalRoot = getGlobalRoot();
|
|
26927
|
+
const globalConfigExists = fs52.existsSync(path63.join(globalRoot, "config.json"));
|
|
26928
|
+
const cwd = process.cwd();
|
|
26929
|
+
const localRoot = path63.join(cwd, ".openacp");
|
|
26930
|
+
if (!globalConfigExists) return globalRoot;
|
|
26931
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
26932
|
+
if (!isTTY) return globalRoot;
|
|
26933
|
+
const registryPath = path63.join(globalRoot, "instances.json");
|
|
26934
|
+
const registry = new InstanceRegistry(registryPath);
|
|
26935
|
+
registry.load();
|
|
26936
|
+
const instances = registry.list().filter((e) => fs52.existsSync(e.root));
|
|
26937
|
+
const instanceOptions = instances.map((e) => {
|
|
26938
|
+
let name = e.id;
|
|
26939
|
+
try {
|
|
26940
|
+
const raw = fs52.readFileSync(path63.join(e.root, "config.json"), "utf-8");
|
|
26941
|
+
const parsed = JSON.parse(raw);
|
|
26942
|
+
if (parsed.instanceName) name = parsed.instanceName;
|
|
26943
|
+
} catch {
|
|
26944
|
+
}
|
|
26945
|
+
const isGlobal = e.root === globalRoot;
|
|
26946
|
+
const displayPath = e.root.replace(os31.homedir(), "~");
|
|
26947
|
+
const type = isGlobal ? "global" : "local";
|
|
26948
|
+
return { value: e.root, label: `${name} workspace (${type} \u2014 ${displayPath})` };
|
|
26949
|
+
});
|
|
26950
|
+
if (instanceOptions.length === 0) {
|
|
26951
|
+
const globalDisplay = globalRoot.replace(os31.homedir(), "~");
|
|
26952
|
+
instanceOptions.push({ value: globalRoot, label: `Global workspace (${globalDisplay})` });
|
|
26953
|
+
}
|
|
26954
|
+
if (instanceOptions.length === 1 && !opts.allowCreate) {
|
|
26955
|
+
return instanceOptions[0].value;
|
|
26956
|
+
}
|
|
26957
|
+
const options = instanceOptions.map((o) => ({
|
|
26958
|
+
value: o.value,
|
|
26959
|
+
label: o.label
|
|
26960
|
+
}));
|
|
26961
|
+
if (opts.allowCreate) {
|
|
26962
|
+
const localDisplay = localRoot.replace(os31.homedir(), "~");
|
|
26963
|
+
options.push({ value: localRoot, label: `New local workspace (${localDisplay})` });
|
|
26964
|
+
}
|
|
26965
|
+
const clack10 = await import("@clack/prompts");
|
|
26966
|
+
const choice = await clack10.select({
|
|
26967
|
+
message: "How would you like to run OpenACP?",
|
|
26968
|
+
options
|
|
26969
|
+
});
|
|
26970
|
+
if (clack10.isCancel(choice)) {
|
|
26971
|
+
process.exit(0);
|
|
26972
|
+
}
|
|
26973
|
+
if (choice === localRoot) {
|
|
26974
|
+
console.log(`\x1B[2mTip: next time use \`openacp --local\`\x1B[0m`);
|
|
26975
|
+
}
|
|
26976
|
+
return choice;
|
|
26977
|
+
}
|
|
26978
|
+
var init_instance_prompt = __esm({
|
|
26979
|
+
"src/cli/instance-prompt.ts"() {
|
|
26980
|
+
"use strict";
|
|
26981
|
+
init_instance_context();
|
|
26982
|
+
init_instance_registry();
|
|
26983
|
+
}
|
|
26984
|
+
});
|
|
26985
|
+
|
|
26554
26986
|
// src/cli.ts
|
|
26555
26987
|
import { setDefaultAutoSelectFamily } from "net";
|
|
26556
|
-
import
|
|
26988
|
+
import path64 from "path";
|
|
26557
26989
|
|
|
26558
26990
|
// src/cli/commands/help.ts
|
|
26559
26991
|
function printHelp() {
|
|
@@ -26633,12 +27065,12 @@ Connect messaging platforms (Telegram, Discord) to 28+ AI coding agents via ACP
|
|
|
26633
27065
|
openacp api health System health check
|
|
26634
27066
|
openacp api restart Restart daemon
|
|
26635
27067
|
|
|
26636
|
-
\x1B[
|
|
26637
|
-
--local Use
|
|
26638
|
-
--global Use
|
|
26639
|
-
--dir <path> Use
|
|
26640
|
-
--from <path> Copy settings from existing
|
|
26641
|
-
--name <name> Set
|
|
27068
|
+
\x1B[1mWorkspace Flags:\x1B[0m
|
|
27069
|
+
--local Use workspace in current directory
|
|
27070
|
+
--global Use global workspace (~/.openacp)
|
|
27071
|
+
--dir <path> Use workspace at specified directory
|
|
27072
|
+
--from <path> Copy settings from existing workspace (on create)
|
|
27073
|
+
--name <name> Set workspace name (on create)
|
|
26642
27074
|
|
|
26643
27075
|
\x1B[2mMore info: https://github.com/Open-ACP/OpenACP\x1B[0m
|
|
26644
27076
|
`);
|
|
@@ -26657,8 +27089,8 @@ import * as fs from "fs";
|
|
|
26657
27089
|
import * as path from "path";
|
|
26658
27090
|
import * as os from "os";
|
|
26659
27091
|
async function cmdInstall(args2, instanceRoot) {
|
|
26660
|
-
const
|
|
26661
|
-
const pluginsDir = path.join(
|
|
27092
|
+
const root = instanceRoot ?? path.join(os.homedir(), ".openacp");
|
|
27093
|
+
const pluginsDir = path.join(root, "plugins");
|
|
26662
27094
|
if (wantsHelp(args2)) {
|
|
26663
27095
|
console.log(`
|
|
26664
27096
|
\x1B[1mopenacp install\x1B[0m \u2014 Install a plugin adapter
|
|
@@ -26698,8 +27130,8 @@ import * as fs2 from "fs";
|
|
|
26698
27130
|
import * as path2 from "path";
|
|
26699
27131
|
import * as os2 from "os";
|
|
26700
27132
|
async function cmdUninstall(args2, instanceRoot) {
|
|
26701
|
-
const
|
|
26702
|
-
const pluginsDir = path2.join(
|
|
27133
|
+
const root = instanceRoot ?? path2.join(os2.homedir(), ".openacp");
|
|
27134
|
+
const pluginsDir = path2.join(root, "plugins");
|
|
26703
27135
|
if (wantsHelp(args2)) {
|
|
26704
27136
|
console.log(`
|
|
26705
27137
|
\x1B[1mopenacp uninstall\x1B[0m \u2014 Remove a plugin adapter
|
|
@@ -26744,11 +27176,11 @@ Shows all plugins registered in the plugin registry.
|
|
|
26744
27176
|
`);
|
|
26745
27177
|
return;
|
|
26746
27178
|
}
|
|
26747
|
-
const
|
|
26748
|
-
const
|
|
27179
|
+
const os32 = await import("os");
|
|
27180
|
+
const path65 = await import("path");
|
|
26749
27181
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
26750
|
-
const
|
|
26751
|
-
const registryPath =
|
|
27182
|
+
const root = instanceRoot ?? path65.join(os32.homedir(), ".openacp");
|
|
27183
|
+
const registryPath = path65.join(root, "plugins.json");
|
|
26752
27184
|
const registry = new PluginRegistry2(registryPath);
|
|
26753
27185
|
await registry.load();
|
|
26754
27186
|
const plugins = registry.list();
|
|
@@ -26859,11 +27291,11 @@ async function cmdPlugin(args2 = [], instanceRoot) {
|
|
|
26859
27291
|
}
|
|
26860
27292
|
}
|
|
26861
27293
|
async function setPluginEnabled(name, enabled, instanceRoot) {
|
|
26862
|
-
const
|
|
26863
|
-
const
|
|
27294
|
+
const os32 = await import("os");
|
|
27295
|
+
const path65 = await import("path");
|
|
26864
27296
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
26865
|
-
const
|
|
26866
|
-
const registryPath =
|
|
27297
|
+
const root = instanceRoot ?? path65.join(os32.homedir(), ".openacp");
|
|
27298
|
+
const registryPath = path65.join(root, "plugins.json");
|
|
26867
27299
|
const registry = new PluginRegistry2(registryPath);
|
|
26868
27300
|
await registry.load();
|
|
26869
27301
|
const entry = registry.get(name);
|
|
@@ -26876,8 +27308,8 @@ async function setPluginEnabled(name, enabled, instanceRoot) {
|
|
|
26876
27308
|
console.log(`Plugin ${name} ${enabled ? "enabled" : "disabled"}. Restart to apply.`);
|
|
26877
27309
|
}
|
|
26878
27310
|
async function configurePlugin(name, instanceRoot) {
|
|
26879
|
-
const
|
|
26880
|
-
const
|
|
27311
|
+
const os32 = await import("os");
|
|
27312
|
+
const path65 = await import("path");
|
|
26881
27313
|
const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
|
|
26882
27314
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
26883
27315
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
@@ -26886,8 +27318,8 @@ async function configurePlugin(name, instanceRoot) {
|
|
|
26886
27318
|
console.error(`Plugin "${name}" not found.`);
|
|
26887
27319
|
process.exit(1);
|
|
26888
27320
|
}
|
|
26889
|
-
const
|
|
26890
|
-
const basePath =
|
|
27321
|
+
const root = instanceRoot ?? path65.join(os32.homedir(), ".openacp");
|
|
27322
|
+
const basePath = path65.join(root, "plugins", "data");
|
|
26891
27323
|
const settingsManager = new SettingsManager2(basePath);
|
|
26892
27324
|
const ctx = createInstallContext2({ pluginName: name, settingsManager, basePath });
|
|
26893
27325
|
if (plugin2.configure) {
|
|
@@ -26899,14 +27331,14 @@ async function configurePlugin(name, instanceRoot) {
|
|
|
26899
27331
|
}
|
|
26900
27332
|
}
|
|
26901
27333
|
async function installPlugin(input2, instanceRoot) {
|
|
26902
|
-
const
|
|
26903
|
-
const
|
|
27334
|
+
const os32 = await import("os");
|
|
27335
|
+
const path65 = await import("path");
|
|
26904
27336
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
26905
27337
|
const { getCurrentVersion: getCurrentVersion2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
26906
27338
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
26907
27339
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
26908
27340
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
26909
|
-
const
|
|
27341
|
+
const root = instanceRoot ?? path65.join(os32.homedir(), ".openacp");
|
|
26910
27342
|
let pkgName;
|
|
26911
27343
|
let pkgVersion;
|
|
26912
27344
|
if (input2.startsWith("@")) {
|
|
@@ -26951,9 +27383,9 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26951
27383
|
console.log(`Installing ${installSpec}...`);
|
|
26952
27384
|
const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
|
|
26953
27385
|
const builtinPlugin = corePlugins2.find((p2) => p2.name === pkgName);
|
|
26954
|
-
const basePath =
|
|
27386
|
+
const basePath = path65.join(root, "plugins", "data");
|
|
26955
27387
|
const settingsManager = new SettingsManager2(basePath);
|
|
26956
|
-
const registryPath =
|
|
27388
|
+
const registryPath = path65.join(root, "plugins.json");
|
|
26957
27389
|
const pluginRegistry = new PluginRegistry2(registryPath);
|
|
26958
27390
|
await pluginRegistry.load();
|
|
26959
27391
|
if (builtinPlugin) {
|
|
@@ -26972,8 +27404,8 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26972
27404
|
console.log(`\u2713 ${builtinPlugin.name} installed! Restart to activate.`);
|
|
26973
27405
|
return;
|
|
26974
27406
|
}
|
|
26975
|
-
const pluginsDir =
|
|
26976
|
-
const nodeModulesDir =
|
|
27407
|
+
const pluginsDir = path65.join(root, "plugins");
|
|
27408
|
+
const nodeModulesDir = path65.join(pluginsDir, "node_modules");
|
|
26977
27409
|
try {
|
|
26978
27410
|
execFileSync8("npm", ["install", installSpec, "--prefix", pluginsDir, "--save"], {
|
|
26979
27411
|
stdio: "inherit",
|
|
@@ -26986,8 +27418,8 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
26986
27418
|
const cliVersion = getCurrentVersion2();
|
|
26987
27419
|
const isLocalPath = pkgName.startsWith("/") || pkgName.startsWith(".");
|
|
26988
27420
|
try {
|
|
26989
|
-
const pluginRoot = isLocalPath ?
|
|
26990
|
-
const installedPkgPath =
|
|
27421
|
+
const pluginRoot = isLocalPath ? path65.resolve(pkgName) : path65.join(nodeModulesDir, pkgName);
|
|
27422
|
+
const installedPkgPath = path65.join(pluginRoot, "package.json");
|
|
26991
27423
|
const { readFileSync: readFileSync18 } = await import("fs");
|
|
26992
27424
|
const installedPkg = JSON.parse(readFileSync18(installedPkgPath, "utf-8"));
|
|
26993
27425
|
const minVersion = installedPkg.engines?.openacp?.replace(/[>=^~\s]/g, "");
|
|
@@ -27000,7 +27432,7 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
27000
27432
|
`);
|
|
27001
27433
|
}
|
|
27002
27434
|
}
|
|
27003
|
-
const pluginModule = await import(
|
|
27435
|
+
const pluginModule = await import(path65.join(pluginRoot, installedPkg.main ?? "dist/index.js"));
|
|
27004
27436
|
const plugin2 = pluginModule.default;
|
|
27005
27437
|
if (plugin2?.install) {
|
|
27006
27438
|
const ctx = createInstallContext2({ pluginName: plugin2.name ?? pkgName, settingsManager, basePath });
|
|
@@ -27027,12 +27459,12 @@ async function installPlugin(input2, instanceRoot) {
|
|
|
27027
27459
|
}
|
|
27028
27460
|
}
|
|
27029
27461
|
async function uninstallPlugin(name, purge, instanceRoot) {
|
|
27030
|
-
const
|
|
27031
|
-
const
|
|
27032
|
-
const
|
|
27462
|
+
const os32 = await import("os");
|
|
27463
|
+
const path65 = await import("path");
|
|
27464
|
+
const fs53 = await import("fs");
|
|
27033
27465
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
27034
|
-
const
|
|
27035
|
-
const registryPath =
|
|
27466
|
+
const root = instanceRoot ?? path65.join(os32.homedir(), ".openacp");
|
|
27467
|
+
const registryPath = path65.join(root, "plugins.json");
|
|
27036
27468
|
const registry = new PluginRegistry2(registryPath);
|
|
27037
27469
|
await registry.load();
|
|
27038
27470
|
const entry = registry.get(name);
|
|
@@ -27050,7 +27482,7 @@ async function uninstallPlugin(name, purge, instanceRoot) {
|
|
|
27050
27482
|
if (plugin2?.uninstall) {
|
|
27051
27483
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
27052
27484
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
27053
|
-
const basePath =
|
|
27485
|
+
const basePath = path65.join(root, "plugins", "data");
|
|
27054
27486
|
const settingsManager = new SettingsManager2(basePath);
|
|
27055
27487
|
const ctx = createInstallContext2({ pluginName: name, settingsManager, basePath });
|
|
27056
27488
|
await plugin2.uninstall(ctx, { purge });
|
|
@@ -27058,8 +27490,8 @@ async function uninstallPlugin(name, purge, instanceRoot) {
|
|
|
27058
27490
|
} catch {
|
|
27059
27491
|
}
|
|
27060
27492
|
if (purge) {
|
|
27061
|
-
const pluginDir =
|
|
27062
|
-
|
|
27493
|
+
const pluginDir = path65.join(root, "plugins", name);
|
|
27494
|
+
fs53.rmSync(pluginDir, { recursive: true, force: true });
|
|
27063
27495
|
}
|
|
27064
27496
|
registry.remove(name);
|
|
27065
27497
|
await registry.save();
|
|
@@ -27087,6 +27519,12 @@ function printApiHelp() {
|
|
|
27087
27519
|
openacp api cancel <id> Cancel a session
|
|
27088
27520
|
openacp api dangerous <id> on|off Toggle dangerous mode
|
|
27089
27521
|
|
|
27522
|
+
\x1B[1mSession Config Commands:\x1B[0m
|
|
27523
|
+
openacp api session-config <id> List all config options
|
|
27524
|
+
openacp api session-config <id> set <opt> <value> Set a config option
|
|
27525
|
+
openacp api session-config <id> overrides Show clientOverrides
|
|
27526
|
+
openacp api session-config <id> dangerous [on|off] Toggle bypassPermissions
|
|
27527
|
+
|
|
27090
27528
|
\x1B[1mTopic Commands:\x1B[0m
|
|
27091
27529
|
openacp api topics [--status s1,s2] List topics
|
|
27092
27530
|
openacp api delete-topic <id> [--force] Delete a topic
|
|
@@ -27298,6 +27736,26 @@ Sends a restart signal to the running daemon.
|
|
|
27298
27736
|
openacp api version
|
|
27299
27737
|
|
|
27300
27738
|
Shows the version of the currently running daemon process.
|
|
27739
|
+
`,
|
|
27740
|
+
"session-config": `
|
|
27741
|
+
\x1B[1mopenacp api session-config\x1B[0m \u2014 Manage session config options
|
|
27742
|
+
|
|
27743
|
+
\x1B[1mUsage:\x1B[0m
|
|
27744
|
+
openacp api session-config <id> List all config options
|
|
27745
|
+
openacp api session-config <id> set <opt> <value> Set a config option
|
|
27746
|
+
openacp api session-config <id> overrides Show clientOverrides
|
|
27747
|
+
openacp api session-config <id> dangerous [on|off] Toggle bypassPermissions
|
|
27748
|
+
|
|
27749
|
+
\x1B[1mArguments:\x1B[0m
|
|
27750
|
+
<id> Session ID
|
|
27751
|
+
<opt> Config option ID (from list)
|
|
27752
|
+
<value> New value for the config option
|
|
27753
|
+
|
|
27754
|
+
\x1B[1mExamples:\x1B[0m
|
|
27755
|
+
openacp api session-config abc123
|
|
27756
|
+
openacp api session-config abc123 set model claude-opus-4-5
|
|
27757
|
+
openacp api session-config abc123 overrides
|
|
27758
|
+
openacp api session-config abc123 dangerous on
|
|
27301
27759
|
`
|
|
27302
27760
|
};
|
|
27303
27761
|
const help = apiSubHelp[subCmd];
|
|
@@ -27627,6 +28085,126 @@ Shows the version of the currently running daemon process.
|
|
|
27627
28085
|
process.exit(1);
|
|
27628
28086
|
}
|
|
27629
28087
|
console.log(`Daemon version: ${data.version}`);
|
|
28088
|
+
} else if (subCmd === "session-config") {
|
|
28089
|
+
const sessionId = args2[2];
|
|
28090
|
+
if (!sessionId) {
|
|
28091
|
+
console.error("Usage: openacp api session-config <session-id> [set <opt> <value> | overrides | dangerous [on|off]]");
|
|
28092
|
+
process.exit(1);
|
|
28093
|
+
}
|
|
28094
|
+
const configSubCmd = args2[3];
|
|
28095
|
+
if (!configSubCmd || configSubCmd === "list") {
|
|
28096
|
+
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config`);
|
|
28097
|
+
const data = await res.json();
|
|
28098
|
+
if (!res.ok) {
|
|
28099
|
+
console.error(`Error: ${data.error}`);
|
|
28100
|
+
process.exit(1);
|
|
28101
|
+
}
|
|
28102
|
+
const configOptions = data.configOptions;
|
|
28103
|
+
const clientOverrides = data.clientOverrides;
|
|
28104
|
+
if (!configOptions || configOptions.length === 0) {
|
|
28105
|
+
console.log("No config options available for this session.");
|
|
28106
|
+
} else {
|
|
28107
|
+
console.log(`Config options for session ${sessionId}:
|
|
28108
|
+
`);
|
|
28109
|
+
for (const opt of configOptions) {
|
|
28110
|
+
const desc = opt.description ? ` ${opt.description}` : "";
|
|
28111
|
+
console.log(` [${opt.id}] ${opt.name} (${opt.type}) current: ${opt.currentValue}${desc}`);
|
|
28112
|
+
if (opt.type === "select") {
|
|
28113
|
+
const options = opt.options;
|
|
28114
|
+
if (options && options.length > 0) {
|
|
28115
|
+
const choices = options.flatMap((o) => {
|
|
28116
|
+
if ("group" in o) {
|
|
28117
|
+
const groupOpts = o.options;
|
|
28118
|
+
return groupOpts?.map((c3) => `${c3.value} (${c3.label})`) ?? [];
|
|
28119
|
+
}
|
|
28120
|
+
return [`${o.value} (${o.label})`];
|
|
28121
|
+
});
|
|
28122
|
+
console.log(` choices: ${choices.join(", ")}`);
|
|
28123
|
+
}
|
|
28124
|
+
}
|
|
28125
|
+
}
|
|
28126
|
+
}
|
|
28127
|
+
if (clientOverrides && Object.keys(clientOverrides).length > 0) {
|
|
28128
|
+
console.log(`
|
|
28129
|
+
Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
28130
|
+
}
|
|
28131
|
+
} else if (configSubCmd === "set") {
|
|
28132
|
+
const configId = args2[4];
|
|
28133
|
+
const value = args2[5];
|
|
28134
|
+
if (!configId || value === void 0) {
|
|
28135
|
+
console.error("Usage: openacp api session-config <session-id> set <config-id> <value>");
|
|
28136
|
+
process.exit(1);
|
|
28137
|
+
}
|
|
28138
|
+
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/${encodeURIComponent(configId)}`, {
|
|
28139
|
+
method: "PUT",
|
|
28140
|
+
headers: { "Content-Type": "application/json" },
|
|
28141
|
+
body: JSON.stringify({ value })
|
|
28142
|
+
});
|
|
28143
|
+
const data = await res.json();
|
|
28144
|
+
if (!res.ok) {
|
|
28145
|
+
console.error(`Error: ${data.error}`);
|
|
28146
|
+
process.exit(1);
|
|
28147
|
+
}
|
|
28148
|
+
console.log(`Config option "${configId}" updated to "${value}"`);
|
|
28149
|
+
const configOptions = data.configOptions;
|
|
28150
|
+
const updated = configOptions?.find((o) => o.id === configId);
|
|
28151
|
+
if (updated) {
|
|
28152
|
+
console.log(` Current value: ${updated.currentValue}`);
|
|
28153
|
+
}
|
|
28154
|
+
} else if (configSubCmd === "overrides") {
|
|
28155
|
+
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`);
|
|
28156
|
+
const data = await res.json();
|
|
28157
|
+
if (!res.ok) {
|
|
28158
|
+
console.error(`Error: ${data.error}`);
|
|
28159
|
+
process.exit(1);
|
|
28160
|
+
}
|
|
28161
|
+
const overrides = data.clientOverrides;
|
|
28162
|
+
if (!overrides || Object.keys(overrides).length === 0) {
|
|
28163
|
+
console.log("No client overrides set.");
|
|
28164
|
+
} else {
|
|
28165
|
+
console.log(`Client overrides for session ${sessionId}:`);
|
|
28166
|
+
for (const [key, val] of Object.entries(overrides)) {
|
|
28167
|
+
console.log(` ${key}: ${val}`);
|
|
28168
|
+
}
|
|
28169
|
+
}
|
|
28170
|
+
} else if (configSubCmd === "dangerous") {
|
|
28171
|
+
const toggle = args2[4];
|
|
28172
|
+
if (toggle && toggle !== "on" && toggle !== "off") {
|
|
28173
|
+
console.error("Usage: openacp api session-config <session-id> dangerous [on|off]");
|
|
28174
|
+
process.exit(1);
|
|
28175
|
+
}
|
|
28176
|
+
if (toggle) {
|
|
28177
|
+
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`, {
|
|
28178
|
+
method: "PUT",
|
|
28179
|
+
headers: { "Content-Type": "application/json" },
|
|
28180
|
+
body: JSON.stringify({ bypassPermissions: toggle === "on" })
|
|
28181
|
+
});
|
|
28182
|
+
const data = await res.json();
|
|
28183
|
+
if (!res.ok) {
|
|
28184
|
+
console.error(`Error: ${data.error}`);
|
|
28185
|
+
process.exit(1);
|
|
28186
|
+
}
|
|
28187
|
+
const state = toggle === "on" ? "enabled" : "disabled";
|
|
28188
|
+
console.log(`bypassPermissions ${state} for session ${sessionId}`);
|
|
28189
|
+
} else {
|
|
28190
|
+
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`);
|
|
28191
|
+
const data = await res.json();
|
|
28192
|
+
if (!res.ok) {
|
|
28193
|
+
console.error(`Error: ${data.error}`);
|
|
28194
|
+
process.exit(1);
|
|
28195
|
+
}
|
|
28196
|
+
const overrides = data.clientOverrides;
|
|
28197
|
+
const bypass = overrides?.bypassPermissions;
|
|
28198
|
+
console.log(`bypassPermissions: ${bypass ?? false}`);
|
|
28199
|
+
}
|
|
28200
|
+
} else {
|
|
28201
|
+
console.error(`Unknown session-config subcommand: ${configSubCmd}`);
|
|
28202
|
+
console.log(" openacp api session-config <id> List config options");
|
|
28203
|
+
console.log(" openacp api session-config <id> set <opt> <value> Set a config option");
|
|
28204
|
+
console.log(" openacp api session-config <id> overrides Show clientOverrides");
|
|
28205
|
+
console.log(" openacp api session-config <id> dangerous [on|off] Toggle bypassPermissions");
|
|
28206
|
+
process.exit(1);
|
|
28207
|
+
}
|
|
27630
28208
|
} else {
|
|
27631
28209
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
27632
28210
|
const apiSubcommands = [
|
|
@@ -27646,7 +28224,8 @@ Shows the version of the currently running daemon process.
|
|
|
27646
28224
|
"adapters",
|
|
27647
28225
|
"tunnel",
|
|
27648
28226
|
"notify",
|
|
27649
|
-
"version"
|
|
28227
|
+
"version",
|
|
28228
|
+
"session-config"
|
|
27650
28229
|
];
|
|
27651
28230
|
const suggestion = suggestMatch2(subCmd ?? "", apiSubcommands);
|
|
27652
28231
|
console.error(`Unknown api command: ${subCmd || "(none)"}
|
|
@@ -27673,7 +28252,7 @@ init_instance_hint();
|
|
|
27673
28252
|
import path36 from "path";
|
|
27674
28253
|
import os17 from "os";
|
|
27675
28254
|
async function cmdStart(args2 = [], instanceRoot) {
|
|
27676
|
-
const
|
|
28255
|
+
const root = instanceRoot ?? path36.join(os17.homedir(), ".openacp");
|
|
27677
28256
|
if (wantsHelp(args2)) {
|
|
27678
28257
|
console.log(`
|
|
27679
28258
|
\x1B[1mopenacp start\x1B[0m \u2014 Start OpenACP as a background daemon
|
|
@@ -27695,16 +28274,16 @@ Requires an existing config \u2014 run 'openacp' first to set up.
|
|
|
27695
28274
|
await checkAndPromptUpdate();
|
|
27696
28275
|
const { startDaemon: startDaemon2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
27697
28276
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
27698
|
-
const cm = new ConfigManager2(path36.join(
|
|
28277
|
+
const cm = new ConfigManager2(path36.join(root, "config.json"));
|
|
27699
28278
|
if (await cm.exists()) {
|
|
27700
28279
|
await cm.load();
|
|
27701
28280
|
const config = cm.get();
|
|
27702
|
-
const result = startDaemon2(getPidPath2(
|
|
28281
|
+
const result = startDaemon2(getPidPath2(root), config.logging.logDir, root);
|
|
27703
28282
|
if ("error" in result) {
|
|
27704
28283
|
console.error(result.error);
|
|
27705
28284
|
process.exit(1);
|
|
27706
28285
|
}
|
|
27707
|
-
printInstanceHint(
|
|
28286
|
+
printInstanceHint(root);
|
|
27708
28287
|
console.log(`OpenACP daemon started (PID ${result.pid})`);
|
|
27709
28288
|
} else {
|
|
27710
28289
|
console.error('No config found. Run "openacp" first to set up.');
|
|
@@ -27854,18 +28433,18 @@ start fresh with the setup wizard. The daemon must be stopped first.
|
|
|
27854
28433
|
`);
|
|
27855
28434
|
return;
|
|
27856
28435
|
}
|
|
27857
|
-
const
|
|
27858
|
-
const
|
|
27859
|
-
const
|
|
28436
|
+
const os32 = await import("os");
|
|
28437
|
+
const path65 = await import("path");
|
|
28438
|
+
const root = instanceRoot ?? path65.join(os32.homedir(), ".openacp");
|
|
27860
28439
|
const { getStatus: getStatus2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
27861
|
-
const status = getStatus2(getPidPath2(
|
|
28440
|
+
const status = getStatus2(getPidPath2(root));
|
|
27862
28441
|
if (status.running) {
|
|
27863
28442
|
console.error("OpenACP is running. Stop it first: openacp stop");
|
|
27864
28443
|
process.exit(1);
|
|
27865
28444
|
}
|
|
27866
28445
|
const clack10 = await import("@clack/prompts");
|
|
27867
28446
|
const yes = await clack10.confirm({
|
|
27868
|
-
message: `This will delete all OpenACP data (${
|
|
28447
|
+
message: `This will delete all OpenACP data (${root}). You will need to set up again. Continue?`,
|
|
27869
28448
|
initialValue: false
|
|
27870
28449
|
});
|
|
27871
28450
|
if (clack10.isCancel(yes) || !yes) {
|
|
@@ -27874,8 +28453,8 @@ start fresh with the setup wizard. The daemon must be stopped first.
|
|
|
27874
28453
|
}
|
|
27875
28454
|
const { uninstallAutoStart: uninstallAutoStart2 } = await Promise.resolve().then(() => (init_autostart(), autostart_exports));
|
|
27876
28455
|
uninstallAutoStart2();
|
|
27877
|
-
const
|
|
27878
|
-
|
|
28456
|
+
const fs53 = await import("fs");
|
|
28457
|
+
fs53.rmSync(root, { recursive: true, force: true });
|
|
27879
28458
|
console.log("Reset complete. Run `openacp` to set up again.");
|
|
27880
28459
|
}
|
|
27881
28460
|
|
|
@@ -28620,16 +29199,16 @@ Tunnel Management:
|
|
|
28620
29199
|
}
|
|
28621
29200
|
|
|
28622
29201
|
// src/cli/commands/onboard.ts
|
|
28623
|
-
import * as
|
|
29202
|
+
import * as path58 from "path";
|
|
28624
29203
|
async function cmdOnboard(instanceRoot) {
|
|
28625
29204
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
28626
29205
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
28627
29206
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
28628
29207
|
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
28629
29208
|
const OPENACP_DIR = instanceRoot ?? getGlobalRoot2();
|
|
28630
|
-
const PLUGINS_DATA_DIR =
|
|
28631
|
-
const REGISTRY_PATH =
|
|
28632
|
-
const cm = new ConfigManager2(
|
|
29209
|
+
const PLUGINS_DATA_DIR = path58.join(OPENACP_DIR, "plugins", "data");
|
|
29210
|
+
const REGISTRY_PATH = path58.join(OPENACP_DIR, "plugins.json");
|
|
29211
|
+
const cm = new ConfigManager2(path58.join(OPENACP_DIR, "config.json"));
|
|
28633
29212
|
const settingsManager = new SettingsManager2(PLUGINS_DATA_DIR);
|
|
28634
29213
|
const pluginRegistry = new PluginRegistry2(REGISTRY_PATH);
|
|
28635
29214
|
await pluginRegistry.load();
|
|
@@ -28646,12 +29225,12 @@ async function cmdOnboard(instanceRoot) {
|
|
|
28646
29225
|
init_version();
|
|
28647
29226
|
init_instance_context();
|
|
28648
29227
|
init_instance_hint();
|
|
28649
|
-
import
|
|
28650
|
-
import
|
|
29228
|
+
import path59 from "path";
|
|
29229
|
+
import os28 from "os";
|
|
28651
29230
|
async function cmdDefault(command2, instanceRoot) {
|
|
28652
|
-
const
|
|
28653
|
-
const pluginsDataDir =
|
|
28654
|
-
const registryPath =
|
|
29231
|
+
const root = instanceRoot ?? path59.join(os28.homedir(), ".openacp");
|
|
29232
|
+
const pluginsDataDir = path59.join(root, "plugins", "data");
|
|
29233
|
+
const registryPath = path59.join(root, "plugins.json");
|
|
28655
29234
|
const forceForeground = command2 === "--foreground";
|
|
28656
29235
|
if (command2 && !command2.startsWith("-")) {
|
|
28657
29236
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
@@ -28683,7 +29262,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
28683
29262
|
}
|
|
28684
29263
|
await checkAndPromptUpdate();
|
|
28685
29264
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
28686
|
-
const configPath =
|
|
29265
|
+
const configPath = path59.join(root, "config.json");
|
|
28687
29266
|
const cm = new ConfigManager2(configPath);
|
|
28688
29267
|
if (!await cm.exists()) {
|
|
28689
29268
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
@@ -28692,44 +29271,44 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
28692
29271
|
const pluginRegistry = new PluginRegistry2(registryPath);
|
|
28693
29272
|
await pluginRegistry.load();
|
|
28694
29273
|
const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
|
|
28695
|
-
const shouldStart = await runSetup2(cm, { settingsManager, pluginRegistry, instanceRoot:
|
|
29274
|
+
const shouldStart = await runSetup2(cm, { settingsManager, pluginRegistry, instanceRoot: root });
|
|
28696
29275
|
if (!shouldStart) process.exit(0);
|
|
28697
29276
|
}
|
|
28698
29277
|
await cm.load();
|
|
28699
29278
|
const config = cm.get();
|
|
28700
29279
|
if (!forceForeground && config.runMode === "daemon") {
|
|
28701
29280
|
const { isProcessRunning: isProcessRunning2, getPidPath: getPidPath2, startDaemon: startDaemon2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
28702
|
-
const pidPath = getPidPath2(
|
|
29281
|
+
const pidPath = getPidPath2(root);
|
|
28703
29282
|
if (isProcessRunning2(pidPath)) {
|
|
28704
|
-
await showAlreadyRunningMenu(
|
|
29283
|
+
await showAlreadyRunningMenu(root);
|
|
28705
29284
|
return;
|
|
28706
29285
|
}
|
|
28707
|
-
const result = startDaemon2(pidPath, config.logging.logDir,
|
|
29286
|
+
const result = startDaemon2(pidPath, config.logging.logDir, root);
|
|
28708
29287
|
if ("error" in result) {
|
|
28709
29288
|
console.error(result.error);
|
|
28710
29289
|
process.exit(1);
|
|
28711
29290
|
}
|
|
28712
|
-
printInstanceHint(
|
|
29291
|
+
printInstanceHint(root);
|
|
28713
29292
|
console.log(`OpenACP daemon started (PID ${result.pid})`);
|
|
28714
29293
|
return;
|
|
28715
29294
|
}
|
|
28716
29295
|
const { markRunning: markRunning2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
28717
|
-
markRunning2(
|
|
28718
|
-
printInstanceHint(
|
|
29296
|
+
markRunning2(root);
|
|
29297
|
+
printInstanceHint(root);
|
|
28719
29298
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
28720
29299
|
const ctx = createInstanceContext({
|
|
28721
29300
|
id: "default",
|
|
28722
|
-
root
|
|
28723
|
-
isGlobal:
|
|
29301
|
+
root,
|
|
29302
|
+
isGlobal: root === getGlobalRoot()
|
|
28724
29303
|
});
|
|
28725
29304
|
await startServer2({ instanceContext: ctx });
|
|
28726
29305
|
}
|
|
28727
|
-
async function showAlreadyRunningMenu(
|
|
29306
|
+
async function showAlreadyRunningMenu(root) {
|
|
28728
29307
|
const { formatInstanceStatus: formatInstanceStatus2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
28729
29308
|
console.log("");
|
|
28730
29309
|
console.log("\x1B[1mOpenACP is already running\x1B[0m");
|
|
28731
29310
|
console.log("");
|
|
28732
|
-
const status = formatInstanceStatus2(
|
|
29311
|
+
const status = formatInstanceStatus2(root);
|
|
28733
29312
|
if (status) {
|
|
28734
29313
|
for (const line of status.lines) {
|
|
28735
29314
|
console.log(line);
|
|
@@ -28743,7 +29322,7 @@ async function showAlreadyRunningMenu(root2) {
|
|
|
28743
29322
|
label: "Restart",
|
|
28744
29323
|
action: async () => {
|
|
28745
29324
|
const { cmdRestart: cmdRestart2 } = await Promise.resolve().then(() => (init_restart(), restart_exports));
|
|
28746
|
-
await cmdRestart2([],
|
|
29325
|
+
await cmdRestart2([], root);
|
|
28747
29326
|
}
|
|
28748
29327
|
},
|
|
28749
29328
|
{
|
|
@@ -28751,7 +29330,7 @@ async function showAlreadyRunningMenu(root2) {
|
|
|
28751
29330
|
label: "Stop",
|
|
28752
29331
|
action: async () => {
|
|
28753
29332
|
const { cmdStop: cmdStop2 } = await Promise.resolve().then(() => (init_stop(), stop_exports));
|
|
28754
|
-
await cmdStop2([],
|
|
29333
|
+
await cmdStop2([], root);
|
|
28755
29334
|
}
|
|
28756
29335
|
},
|
|
28757
29336
|
{
|
|
@@ -28765,7 +29344,7 @@ async function showAlreadyRunningMenu(root2) {
|
|
|
28765
29344
|
label: "Restart in foreground",
|
|
28766
29345
|
action: async () => {
|
|
28767
29346
|
const { cmdRestart: cmdRestart2 } = await Promise.resolve().then(() => (init_restart(), restart_exports));
|
|
28768
|
-
await cmdRestart2(["--foreground"],
|
|
29347
|
+
await cmdRestart2(["--foreground"], root);
|
|
28769
29348
|
}
|
|
28770
29349
|
},
|
|
28771
29350
|
{
|
|
@@ -28773,7 +29352,7 @@ async function showAlreadyRunningMenu(root2) {
|
|
|
28773
29352
|
label: "View logs",
|
|
28774
29353
|
action: async () => {
|
|
28775
29354
|
const { cmdLogs: cmdLogs2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
|
|
28776
|
-
await cmdLogs2([],
|
|
29355
|
+
await cmdLogs2([], root);
|
|
28777
29356
|
}
|
|
28778
29357
|
}
|
|
28779
29358
|
]);
|
|
@@ -28785,8 +29364,8 @@ async function showAlreadyRunningMenu(root2) {
|
|
|
28785
29364
|
|
|
28786
29365
|
// src/cli/commands/dev.ts
|
|
28787
29366
|
init_helpers();
|
|
28788
|
-
import
|
|
28789
|
-
import
|
|
29367
|
+
import fs51 from "fs";
|
|
29368
|
+
import path60 from "path";
|
|
28790
29369
|
async function cmdDev(args2 = []) {
|
|
28791
29370
|
if (wantsHelp(args2)) {
|
|
28792
29371
|
console.log(`
|
|
@@ -28813,13 +29392,13 @@ async function cmdDev(args2 = []) {
|
|
|
28813
29392
|
console.error("Error: missing plugin path. Usage: openacp dev <plugin-path>");
|
|
28814
29393
|
process.exit(1);
|
|
28815
29394
|
}
|
|
28816
|
-
const pluginPath =
|
|
28817
|
-
if (!
|
|
29395
|
+
const pluginPath = path60.resolve(pluginPathArg);
|
|
29396
|
+
if (!fs51.existsSync(pluginPath)) {
|
|
28818
29397
|
console.error(`Error: plugin path does not exist: ${pluginPath}`);
|
|
28819
29398
|
process.exit(1);
|
|
28820
29399
|
}
|
|
28821
|
-
const tsconfigPath =
|
|
28822
|
-
const hasTsconfig =
|
|
29400
|
+
const tsconfigPath = path60.join(pluginPath, "tsconfig.json");
|
|
29401
|
+
const hasTsconfig = fs51.existsSync(tsconfigPath);
|
|
28823
29402
|
if (hasTsconfig) {
|
|
28824
29403
|
console.log("Compiling plugin TypeScript...");
|
|
28825
29404
|
const { execSync: execSync5 } = await import("child_process");
|
|
@@ -28860,10 +29439,10 @@ async function cmdDev(args2 = []) {
|
|
|
28860
29439
|
|
|
28861
29440
|
// src/cli/commands/attach.ts
|
|
28862
29441
|
init_helpers();
|
|
28863
|
-
import
|
|
28864
|
-
import
|
|
29442
|
+
import path61 from "path";
|
|
29443
|
+
import os29 from "os";
|
|
28865
29444
|
async function cmdAttach(args2 = [], instanceRoot) {
|
|
28866
|
-
const
|
|
29445
|
+
const root = instanceRoot ?? path61.join(os29.homedir(), ".openacp");
|
|
28867
29446
|
if (wantsHelp(args2)) {
|
|
28868
29447
|
console.log(`
|
|
28869
29448
|
\x1B[1mopenacp attach\x1B[0m \u2014 Attach to a running daemon
|
|
@@ -28881,7 +29460,7 @@ Press Ctrl+C to detach.
|
|
|
28881
29460
|
return;
|
|
28882
29461
|
}
|
|
28883
29462
|
const { formatInstanceStatus: formatInstanceStatus2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
28884
|
-
const status = formatInstanceStatus2(
|
|
29463
|
+
const status = formatInstanceStatus2(root);
|
|
28885
29464
|
if (!status) {
|
|
28886
29465
|
console.log("OpenACP is not running.");
|
|
28887
29466
|
process.exit(1);
|
|
@@ -28897,15 +29476,15 @@ Press Ctrl+C to detach.
|
|
|
28897
29476
|
console.log("");
|
|
28898
29477
|
const { spawn: spawn8 } = await import("child_process");
|
|
28899
29478
|
const { expandHome: expandHome4 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
28900
|
-
let logDir2 =
|
|
29479
|
+
let logDir2 = path61.join(root, "logs");
|
|
28901
29480
|
try {
|
|
28902
|
-
const configPath =
|
|
29481
|
+
const configPath = path61.join(root, "config.json");
|
|
28903
29482
|
const { readFileSync: readFileSync18 } = await import("fs");
|
|
28904
29483
|
const config = JSON.parse(readFileSync18(configPath, "utf-8"));
|
|
28905
29484
|
if (config.logging?.logDir) logDir2 = expandHome4(config.logging.logDir);
|
|
28906
29485
|
} catch {
|
|
28907
29486
|
}
|
|
28908
|
-
const logFile =
|
|
29487
|
+
const logFile = path61.join(logDir2, "openacp.log");
|
|
28909
29488
|
const tail = spawn8("tail", ["-f", "-n", "50", logFile], { stdio: "inherit" });
|
|
28910
29489
|
tail.on("error", (err) => {
|
|
28911
29490
|
console.error(`Cannot tail log file: ${err.message}`);
|
|
@@ -28916,8 +29495,8 @@ Press Ctrl+C to detach.
|
|
|
28916
29495
|
// src/cli/commands/remote.ts
|
|
28917
29496
|
init_api_client();
|
|
28918
29497
|
init_instance_registry();
|
|
28919
|
-
import
|
|
28920
|
-
import
|
|
29498
|
+
import path62 from "path";
|
|
29499
|
+
import os30 from "os";
|
|
28921
29500
|
import qrcode from "qrcode-terminal";
|
|
28922
29501
|
async function cmdRemote(args2, instanceRoot) {
|
|
28923
29502
|
const role = extractFlag(args2, "--role") ?? "admin";
|
|
@@ -28930,12 +29509,12 @@ async function cmdRemote(args2, instanceRoot) {
|
|
|
28930
29509
|
const scopes = scopesRaw ? scopesRaw.split(",").map((s) => s.trim()) : void 0;
|
|
28931
29510
|
let resolvedInstanceRoot2 = instanceRoot;
|
|
28932
29511
|
if (instanceId) {
|
|
28933
|
-
const registryPath =
|
|
29512
|
+
const registryPath = path62.join(os30.homedir(), ".openacp", "instances.json");
|
|
28934
29513
|
const registry = new InstanceRegistry(registryPath);
|
|
28935
29514
|
await registry.load();
|
|
28936
29515
|
const entry = registry.get(instanceId);
|
|
28937
29516
|
if (!entry) {
|
|
28938
|
-
console.error(`
|
|
29517
|
+
console.error(`Workspace "${instanceId}" not found. Run "openacp status" to see workspaces.`);
|
|
28939
29518
|
process.exit(1);
|
|
28940
29519
|
}
|
|
28941
29520
|
resolvedInstanceRoot2 = entry.root;
|
|
@@ -29105,41 +29684,34 @@ resolvedInstanceRoot = resolveInstanceRoot({
|
|
|
29105
29684
|
global: flags.global,
|
|
29106
29685
|
cwd: process.cwd()
|
|
29107
29686
|
});
|
|
29108
|
-
var
|
|
29109
|
-
var commands = {
|
|
29687
|
+
var noInstanceCommands = {
|
|
29110
29688
|
"--help": async () => printHelp(),
|
|
29111
29689
|
"-h": async () => printHelp(),
|
|
29112
29690
|
"--version": () => cmdVersion(),
|
|
29113
29691
|
"-v": () => cmdVersion(),
|
|
29114
|
-
"install": () => cmdInstall(args, root),
|
|
29115
|
-
"uninstall": () => cmdUninstall(args, root),
|
|
29116
|
-
"plugins": () => cmdPlugins(args, root),
|
|
29117
|
-
"plugin": () => cmdPlugin(args, root),
|
|
29118
|
-
"api": () => cmdApi(args, root),
|
|
29119
|
-
"start": () => cmdStart(args, root),
|
|
29120
|
-
"stop": () => cmdStop(args, root),
|
|
29121
|
-
"restart": () => cmdRestart(args, root),
|
|
29122
|
-
"status": () => cmdStatus(args, root),
|
|
29123
|
-
"logs": () => cmdLogs(args, root),
|
|
29124
|
-
"config": () => cmdConfig(args, root),
|
|
29125
|
-
"reset": () => cmdReset(args, root),
|
|
29126
29692
|
"update": () => cmdUpdate(args),
|
|
29127
29693
|
"adopt": () => cmdAdopt(args),
|
|
29128
29694
|
"integrate": () => cmdIntegrate(args),
|
|
29129
|
-
"
|
|
29130
|
-
|
|
29131
|
-
|
|
29132
|
-
|
|
29133
|
-
|
|
29134
|
-
|
|
29135
|
-
|
|
29136
|
-
|
|
29695
|
+
"dev": () => cmdDev(args)
|
|
29696
|
+
};
|
|
29697
|
+
async function resolveRoot(allowCreate) {
|
|
29698
|
+
if (resolvedInstanceRoot) return resolvedInstanceRoot;
|
|
29699
|
+
const { promptForInstance: promptForInstance2 } = await Promise.resolve().then(() => (init_instance_prompt(), instance_prompt_exports));
|
|
29700
|
+
return promptForInstance2({ allowCreate });
|
|
29701
|
+
}
|
|
29702
|
+
async function main() {
|
|
29703
|
+
const noInstance = command ? noInstanceCommands[command] : void 0;
|
|
29704
|
+
if (noInstance) {
|
|
29705
|
+
await noInstance();
|
|
29706
|
+
return;
|
|
29707
|
+
}
|
|
29708
|
+
if (command === "--daemon-child") {
|
|
29137
29709
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
29138
29710
|
const envRoot = process.env.OPENACP_INSTANCE_ROOT;
|
|
29139
29711
|
if (envRoot) {
|
|
29140
29712
|
const { createInstanceContext: createInstanceContext2, getGlobalRoot: getGlobal } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
29141
29713
|
const { InstanceRegistry: InstanceRegistry2 } = await Promise.resolve().then(() => (init_instance_registry(), instance_registry_exports));
|
|
29142
|
-
const registry = new InstanceRegistry2(
|
|
29714
|
+
const registry = new InstanceRegistry2(path64.join(getGlobal(), "instances.json"));
|
|
29143
29715
|
await registry.load();
|
|
29144
29716
|
const entry = registry.getByRoot(envRoot);
|
|
29145
29717
|
const id = entry?.id ?? "unknown";
|
|
@@ -29152,13 +29724,34 @@ var commands = {
|
|
|
29152
29724
|
} else {
|
|
29153
29725
|
await startServer2();
|
|
29154
29726
|
}
|
|
29727
|
+
return;
|
|
29155
29728
|
}
|
|
29156
|
-
|
|
29157
|
-
|
|
29158
|
-
|
|
29729
|
+
const instanceCommands = {
|
|
29730
|
+
"install": (r) => cmdInstall(args, r),
|
|
29731
|
+
"uninstall": (r) => cmdUninstall(args, r),
|
|
29732
|
+
"plugins": (r) => cmdPlugins(args, r),
|
|
29733
|
+
"plugin": (r) => cmdPlugin(args, r),
|
|
29734
|
+
"api": (r) => cmdApi(args, r),
|
|
29735
|
+
"start": (r) => cmdStart(args, r),
|
|
29736
|
+
"stop": (r) => cmdStop(args, r),
|
|
29737
|
+
"restart": (r) => cmdRestart(args, r),
|
|
29738
|
+
"status": (r) => cmdStatus(args, r),
|
|
29739
|
+
"logs": (r) => cmdLogs(args, r),
|
|
29740
|
+
"config": (r) => cmdConfig(args, r),
|
|
29741
|
+
"reset": (r) => cmdReset(args, r),
|
|
29742
|
+
"doctor": (r) => cmdDoctor(args, r),
|
|
29743
|
+
"agents": (r) => cmdAgents(args, r),
|
|
29744
|
+
"tunnel": (r) => cmdTunnel(args, r),
|
|
29745
|
+
"onboard": (r) => cmdOnboard(r),
|
|
29746
|
+
"attach": (r) => cmdAttach(args, r),
|
|
29747
|
+
"remote": (r) => cmdRemote(args, r)
|
|
29748
|
+
};
|
|
29749
|
+
const handler = command ? instanceCommands[command] : void 0;
|
|
29159
29750
|
if (handler) {
|
|
29160
|
-
await
|
|
29751
|
+
const root = await resolveRoot(false);
|
|
29752
|
+
await handler(root);
|
|
29161
29753
|
} else {
|
|
29754
|
+
const root = await resolveRoot(true);
|
|
29162
29755
|
await cmdDefault(command, root);
|
|
29163
29756
|
}
|
|
29164
29757
|
}
|