@openacp/cli 2026.402.5 → 2026.403.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/README.md +25 -8
- package/dist/{channel-DzDoNxa7.d.ts → channel-BL33p1ZP.d.ts} +1 -1
- package/dist/cli.js +1263 -854
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1459 -1438
- package/dist/index.js +14843 -14224
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1634,21 +1634,23 @@ var init_security_guard = __esm({
|
|
|
1634
1634
|
"src/plugins/security/security-guard.ts"() {
|
|
1635
1635
|
"use strict";
|
|
1636
1636
|
SecurityGuard = class {
|
|
1637
|
-
constructor(
|
|
1638
|
-
this.
|
|
1637
|
+
constructor(getSecurityConfig, sessionManager) {
|
|
1638
|
+
this.getSecurityConfig = getSecurityConfig;
|
|
1639
1639
|
this.sessionManager = sessionManager;
|
|
1640
1640
|
}
|
|
1641
|
-
checkAccess(message) {
|
|
1642
|
-
const config = this.
|
|
1643
|
-
|
|
1641
|
+
async checkAccess(message) {
|
|
1642
|
+
const config = await this.getSecurityConfig();
|
|
1643
|
+
const allowedIds = config.allowedUserIds ?? [];
|
|
1644
|
+
const maxSessions = config.maxConcurrentSessions ?? 20;
|
|
1645
|
+
if (allowedIds.length > 0) {
|
|
1644
1646
|
const userId = String(message.userId);
|
|
1645
|
-
if (!
|
|
1647
|
+
if (!allowedIds.includes(userId)) {
|
|
1646
1648
|
return { allowed: false, reason: "Unauthorized user" };
|
|
1647
1649
|
}
|
|
1648
1650
|
}
|
|
1649
1651
|
const active = this.sessionManager.listSessions().filter((s) => s.status === "active" || s.status === "initializing");
|
|
1650
|
-
if (active.length >=
|
|
1651
|
-
return { allowed: false, reason: `Session limit reached (${
|
|
1652
|
+
if (active.length >= maxSessions) {
|
|
1653
|
+
return { allowed: false, reason: `Session limit reached (${maxSessions})` };
|
|
1652
1654
|
}
|
|
1653
1655
|
return { allowed: true };
|
|
1654
1656
|
}
|
|
@@ -1668,7 +1670,7 @@ function createSecurityPlugin() {
|
|
|
1668
1670
|
description: "User access control and session limits",
|
|
1669
1671
|
essential: false,
|
|
1670
1672
|
permissions: ["services:register", "middleware:register", "kernel:access", "commands:register"],
|
|
1671
|
-
inheritableKeys: ["
|
|
1673
|
+
inheritableKeys: ["allowedUserIds", "maxConcurrentSessions", "sessionTimeoutMinutes"],
|
|
1672
1674
|
async install(ctx) {
|
|
1673
1675
|
const { settings, legacyConfig, terminal } = ctx;
|
|
1674
1676
|
if (legacyConfig) {
|
|
@@ -1745,10 +1747,28 @@ function createSecurityPlugin() {
|
|
|
1745
1747
|
},
|
|
1746
1748
|
async setup(ctx) {
|
|
1747
1749
|
const core = ctx.core;
|
|
1748
|
-
const
|
|
1750
|
+
const settingsManager = core.lifecycleManager?.settingsManager;
|
|
1751
|
+
const pluginName = ctx.pluginName;
|
|
1752
|
+
const getSecurityConfig = async () => {
|
|
1753
|
+
if (settingsManager) {
|
|
1754
|
+
const settings = await settingsManager.loadSettings(pluginName);
|
|
1755
|
+
if (Object.keys(settings).length > 0) {
|
|
1756
|
+
return {
|
|
1757
|
+
allowedUserIds: settings.allowedUserIds ?? [],
|
|
1758
|
+
maxConcurrentSessions: settings.maxConcurrentSessions ?? 20
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
const cfg = ctx.pluginConfig;
|
|
1763
|
+
return {
|
|
1764
|
+
allowedUserIds: cfg.allowedUserIds ?? [],
|
|
1765
|
+
maxConcurrentSessions: cfg.maxConcurrentSessions ?? 20
|
|
1766
|
+
};
|
|
1767
|
+
};
|
|
1768
|
+
const guard = new SecurityGuard(getSecurityConfig, core.sessionManager);
|
|
1749
1769
|
ctx.registerMiddleware("message:incoming", {
|
|
1750
1770
|
handler: async (payload, next) => {
|
|
1751
|
-
const access2 = guard.checkAccess(payload);
|
|
1771
|
+
const access2 = await guard.checkAccess(payload);
|
|
1752
1772
|
if (!access2.allowed) {
|
|
1753
1773
|
ctx.log.info(`Access denied: ${access2.reason}`);
|
|
1754
1774
|
return null;
|
|
@@ -3869,7 +3889,7 @@ var init_speech = __esm({
|
|
|
3869
3889
|
essential: false,
|
|
3870
3890
|
optionalPluginDependencies: { "@openacp/file-service": "^1.0.0" },
|
|
3871
3891
|
permissions: ["services:register", "commands:register", "kernel:access"],
|
|
3872
|
-
inheritableKeys: ["
|
|
3892
|
+
inheritableKeys: ["ttsProvider", "ttsVoice"],
|
|
3873
3893
|
async install(ctx) {
|
|
3874
3894
|
const { terminal, settings, legacyConfig } = ctx;
|
|
3875
3895
|
const pluginsDir = ctx.instanceRoot ? path13.join(ctx.instanceRoot, "plugins") : void 0;
|
|
@@ -6826,6 +6846,289 @@ var init_token_store = __esm({
|
|
|
6826
6846
|
}
|
|
6827
6847
|
});
|
|
6828
6848
|
|
|
6849
|
+
// src/core/instance/instance-context.ts
|
|
6850
|
+
var instance_context_exports = {};
|
|
6851
|
+
__export(instance_context_exports, {
|
|
6852
|
+
createInstanceContext: () => createInstanceContext,
|
|
6853
|
+
generateSlug: () => generateSlug,
|
|
6854
|
+
getGlobalRoot: () => getGlobalRoot,
|
|
6855
|
+
resolveInstanceRoot: () => resolveInstanceRoot
|
|
6856
|
+
});
|
|
6857
|
+
import path21 from "path";
|
|
6858
|
+
import fs17 from "fs";
|
|
6859
|
+
import os10 from "os";
|
|
6860
|
+
function createInstanceContext(opts) {
|
|
6861
|
+
const { id, root, isGlobal } = opts;
|
|
6862
|
+
return {
|
|
6863
|
+
id,
|
|
6864
|
+
root,
|
|
6865
|
+
isGlobal,
|
|
6866
|
+
paths: {
|
|
6867
|
+
config: path21.join(root, "config.json"),
|
|
6868
|
+
sessions: path21.join(root, "sessions.json"),
|
|
6869
|
+
agents: path21.join(root, "agents.json"),
|
|
6870
|
+
registryCache: path21.join(root, "registry-cache.json"),
|
|
6871
|
+
plugins: path21.join(root, "plugins"),
|
|
6872
|
+
pluginsData: path21.join(root, "plugins", "data"),
|
|
6873
|
+
pluginRegistry: path21.join(root, "plugins.json"),
|
|
6874
|
+
logs: path21.join(root, "logs"),
|
|
6875
|
+
pid: path21.join(root, "openacp.pid"),
|
|
6876
|
+
running: path21.join(root, "running"),
|
|
6877
|
+
apiPort: path21.join(root, "api.port"),
|
|
6878
|
+
apiSecret: path21.join(root, "api-secret"),
|
|
6879
|
+
bin: path21.join(root, "bin"),
|
|
6880
|
+
cache: path21.join(root, "cache"),
|
|
6881
|
+
tunnels: path21.join(root, "tunnels.json"),
|
|
6882
|
+
agentsDir: path21.join(root, "agents")
|
|
6883
|
+
}
|
|
6884
|
+
};
|
|
6885
|
+
}
|
|
6886
|
+
function generateSlug(name) {
|
|
6887
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
6888
|
+
return slug || "openacp";
|
|
6889
|
+
}
|
|
6890
|
+
function expandHome2(p2) {
|
|
6891
|
+
if (p2.startsWith("~")) return path21.join(os10.homedir(), p2.slice(1));
|
|
6892
|
+
return p2;
|
|
6893
|
+
}
|
|
6894
|
+
function resolveInstanceRoot(opts) {
|
|
6895
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
6896
|
+
if (opts.dir) return path21.join(expandHome2(opts.dir), ".openacp");
|
|
6897
|
+
if (opts.local) return path21.join(cwd, ".openacp");
|
|
6898
|
+
if (opts.global) return path21.join(os10.homedir(), ".openacp");
|
|
6899
|
+
const localRoot = path21.join(cwd, ".openacp");
|
|
6900
|
+
if (fs17.existsSync(localRoot)) return localRoot;
|
|
6901
|
+
if (process.env.OPENACP_INSTANCE_ROOT) return process.env.OPENACP_INSTANCE_ROOT;
|
|
6902
|
+
return null;
|
|
6903
|
+
}
|
|
6904
|
+
function getGlobalRoot() {
|
|
6905
|
+
return path21.join(os10.homedir(), ".openacp");
|
|
6906
|
+
}
|
|
6907
|
+
var init_instance_context = __esm({
|
|
6908
|
+
"src/core/instance/instance-context.ts"() {
|
|
6909
|
+
"use strict";
|
|
6910
|
+
}
|
|
6911
|
+
});
|
|
6912
|
+
|
|
6913
|
+
// src/core/config/config-registry.ts
|
|
6914
|
+
var config_registry_exports = {};
|
|
6915
|
+
__export(config_registry_exports, {
|
|
6916
|
+
CONFIG_REGISTRY: () => CONFIG_REGISTRY,
|
|
6917
|
+
ConfigValidationError: () => ConfigValidationError,
|
|
6918
|
+
getConfigValue: () => getConfigValue,
|
|
6919
|
+
getFieldDef: () => getFieldDef,
|
|
6920
|
+
getFieldValueAsync: () => getFieldValueAsync,
|
|
6921
|
+
getSafeFields: () => getSafeFields,
|
|
6922
|
+
isHotReloadable: () => isHotReloadable,
|
|
6923
|
+
resolveOptions: () => resolveOptions,
|
|
6924
|
+
setFieldValueAsync: () => setFieldValueAsync
|
|
6925
|
+
});
|
|
6926
|
+
import * as fs18 from "fs";
|
|
6927
|
+
import * as path22 from "path";
|
|
6928
|
+
function getFieldDef(path69) {
|
|
6929
|
+
return CONFIG_REGISTRY.find((f) => f.path === path69);
|
|
6930
|
+
}
|
|
6931
|
+
function getSafeFields() {
|
|
6932
|
+
return CONFIG_REGISTRY.filter((f) => f.scope === "safe");
|
|
6933
|
+
}
|
|
6934
|
+
function isHotReloadable(path69) {
|
|
6935
|
+
const def = getFieldDef(path69);
|
|
6936
|
+
return def?.hotReload ?? false;
|
|
6937
|
+
}
|
|
6938
|
+
function resolveOptions(def, config) {
|
|
6939
|
+
if (!def.options) return void 0;
|
|
6940
|
+
return typeof def.options === "function" ? def.options(config) : def.options;
|
|
6941
|
+
}
|
|
6942
|
+
function getConfigValue(config, path69) {
|
|
6943
|
+
const parts = path69.split(".");
|
|
6944
|
+
let current = config;
|
|
6945
|
+
for (const part of parts) {
|
|
6946
|
+
if (current && typeof current === "object" && part in current) {
|
|
6947
|
+
current = current[part];
|
|
6948
|
+
} else {
|
|
6949
|
+
return void 0;
|
|
6950
|
+
}
|
|
6951
|
+
}
|
|
6952
|
+
return current;
|
|
6953
|
+
}
|
|
6954
|
+
async function getFieldValueAsync(field, configManager, settingsManager) {
|
|
6955
|
+
if (field.plugin && settingsManager) {
|
|
6956
|
+
const settings = await settingsManager.loadSettings(field.plugin.name);
|
|
6957
|
+
return settings[field.plugin.key];
|
|
6958
|
+
}
|
|
6959
|
+
return getConfigValue(configManager.get(), field.path);
|
|
6960
|
+
}
|
|
6961
|
+
function validateFieldValue(field, value) {
|
|
6962
|
+
switch (field.type) {
|
|
6963
|
+
case "number":
|
|
6964
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
6965
|
+
throw new ConfigValidationError(`"${field.path}" expects a number, got ${typeof value}`);
|
|
6966
|
+
}
|
|
6967
|
+
break;
|
|
6968
|
+
case "toggle":
|
|
6969
|
+
if (typeof value !== "boolean") {
|
|
6970
|
+
throw new ConfigValidationError(`"${field.path}" expects a boolean, got ${typeof value}`);
|
|
6971
|
+
}
|
|
6972
|
+
break;
|
|
6973
|
+
case "string":
|
|
6974
|
+
if (typeof value !== "string") {
|
|
6975
|
+
throw new ConfigValidationError(`"${field.path}" expects a string, got ${typeof value}`);
|
|
6976
|
+
}
|
|
6977
|
+
break;
|
|
6978
|
+
case "select": {
|
|
6979
|
+
if (typeof value !== "string") {
|
|
6980
|
+
throw new ConfigValidationError(`"${field.path}" expects a string, got ${typeof value}`);
|
|
6981
|
+
}
|
|
6982
|
+
break;
|
|
6983
|
+
}
|
|
6984
|
+
}
|
|
6985
|
+
}
|
|
6986
|
+
async function setFieldValueAsync(field, value, configManager, settingsManager) {
|
|
6987
|
+
validateFieldValue(field, value);
|
|
6988
|
+
if (field.plugin && settingsManager) {
|
|
6989
|
+
await settingsManager.updatePluginSettings(field.plugin.name, {
|
|
6990
|
+
[field.plugin.key]: value
|
|
6991
|
+
});
|
|
6992
|
+
if (configManager.emit) {
|
|
6993
|
+
configManager.emit("config:changed", { path: field.path, value, oldValue: void 0 });
|
|
6994
|
+
}
|
|
6995
|
+
return { needsRestart: !field.hotReload };
|
|
6996
|
+
}
|
|
6997
|
+
await configManager.setPath(field.path, value);
|
|
6998
|
+
return { needsRestart: !field.hotReload };
|
|
6999
|
+
}
|
|
7000
|
+
var CONFIG_REGISTRY, ConfigValidationError;
|
|
7001
|
+
var init_config_registry = __esm({
|
|
7002
|
+
"src/core/config/config-registry.ts"() {
|
|
7003
|
+
"use strict";
|
|
7004
|
+
init_instance_context();
|
|
7005
|
+
CONFIG_REGISTRY = [
|
|
7006
|
+
{
|
|
7007
|
+
path: "defaultAgent",
|
|
7008
|
+
displayName: "Default Agent",
|
|
7009
|
+
group: "agent",
|
|
7010
|
+
type: "select",
|
|
7011
|
+
options: (config) => {
|
|
7012
|
+
try {
|
|
7013
|
+
const agentsPath = path22.join(getGlobalRoot(), "agents.json");
|
|
7014
|
+
if (fs18.existsSync(agentsPath)) {
|
|
7015
|
+
const data = JSON.parse(fs18.readFileSync(agentsPath, "utf-8"));
|
|
7016
|
+
return Object.keys(data.installed ?? {});
|
|
7017
|
+
}
|
|
7018
|
+
} catch {
|
|
7019
|
+
}
|
|
7020
|
+
return Object.keys(config.agents ?? {});
|
|
7021
|
+
},
|
|
7022
|
+
scope: "safe",
|
|
7023
|
+
hotReload: true
|
|
7024
|
+
},
|
|
7025
|
+
{
|
|
7026
|
+
path: "channels.telegram.outputMode",
|
|
7027
|
+
displayName: "Telegram Output Mode",
|
|
7028
|
+
group: "display",
|
|
7029
|
+
type: "select",
|
|
7030
|
+
options: ["low", "medium", "high"],
|
|
7031
|
+
scope: "safe",
|
|
7032
|
+
hotReload: true
|
|
7033
|
+
},
|
|
7034
|
+
{
|
|
7035
|
+
path: "channels.discord.outputMode",
|
|
7036
|
+
displayName: "Discord Output Mode",
|
|
7037
|
+
group: "display",
|
|
7038
|
+
type: "select",
|
|
7039
|
+
options: ["low", "medium", "high"],
|
|
7040
|
+
scope: "safe",
|
|
7041
|
+
hotReload: true
|
|
7042
|
+
},
|
|
7043
|
+
{
|
|
7044
|
+
path: "logging.level",
|
|
7045
|
+
displayName: "Log Level",
|
|
7046
|
+
group: "logging",
|
|
7047
|
+
type: "select",
|
|
7048
|
+
options: ["silent", "debug", "info", "warn", "error", "fatal"],
|
|
7049
|
+
scope: "safe",
|
|
7050
|
+
hotReload: true
|
|
7051
|
+
},
|
|
7052
|
+
{
|
|
7053
|
+
path: "tunnel.enabled",
|
|
7054
|
+
displayName: "Tunnel",
|
|
7055
|
+
group: "tunnel",
|
|
7056
|
+
type: "toggle",
|
|
7057
|
+
scope: "safe",
|
|
7058
|
+
hotReload: false,
|
|
7059
|
+
plugin: { name: "@openacp/tunnel", key: "enabled" }
|
|
7060
|
+
},
|
|
7061
|
+
{
|
|
7062
|
+
path: "security.maxConcurrentSessions",
|
|
7063
|
+
displayName: "Max Concurrent Sessions",
|
|
7064
|
+
group: "security",
|
|
7065
|
+
type: "number",
|
|
7066
|
+
scope: "safe",
|
|
7067
|
+
hotReload: true,
|
|
7068
|
+
plugin: { name: "@openacp/security", key: "maxConcurrentSessions" }
|
|
7069
|
+
},
|
|
7070
|
+
{
|
|
7071
|
+
path: "security.sessionTimeoutMinutes",
|
|
7072
|
+
displayName: "Session Timeout (min)",
|
|
7073
|
+
group: "security",
|
|
7074
|
+
type: "number",
|
|
7075
|
+
scope: "safe",
|
|
7076
|
+
hotReload: true,
|
|
7077
|
+
plugin: { name: "@openacp/security", key: "sessionTimeoutMinutes" }
|
|
7078
|
+
},
|
|
7079
|
+
{
|
|
7080
|
+
path: "workspace.baseDir",
|
|
7081
|
+
displayName: "Workspace Directory",
|
|
7082
|
+
group: "workspace",
|
|
7083
|
+
type: "string",
|
|
7084
|
+
scope: "safe",
|
|
7085
|
+
hotReload: true
|
|
7086
|
+
},
|
|
7087
|
+
{
|
|
7088
|
+
path: "sessionStore.ttlDays",
|
|
7089
|
+
displayName: "Session Store TTL (days)",
|
|
7090
|
+
group: "storage",
|
|
7091
|
+
type: "number",
|
|
7092
|
+
scope: "safe",
|
|
7093
|
+
hotReload: true
|
|
7094
|
+
},
|
|
7095
|
+
{
|
|
7096
|
+
path: "speech.stt.provider",
|
|
7097
|
+
displayName: "Speech to Text",
|
|
7098
|
+
group: "speech",
|
|
7099
|
+
type: "select",
|
|
7100
|
+
options: ["groq"],
|
|
7101
|
+
scope: "safe",
|
|
7102
|
+
hotReload: true,
|
|
7103
|
+
plugin: { name: "@openacp/speech", key: "sttProvider" }
|
|
7104
|
+
},
|
|
7105
|
+
{
|
|
7106
|
+
path: "speech.stt.apiKey",
|
|
7107
|
+
displayName: "STT API Key",
|
|
7108
|
+
group: "speech",
|
|
7109
|
+
type: "string",
|
|
7110
|
+
scope: "sensitive",
|
|
7111
|
+
hotReload: true,
|
|
7112
|
+
plugin: { name: "@openacp/speech", key: "groqApiKey" }
|
|
7113
|
+
},
|
|
7114
|
+
{
|
|
7115
|
+
path: "agentSwitch.labelHistory",
|
|
7116
|
+
displayName: "Label Agent in History",
|
|
7117
|
+
group: "agent",
|
|
7118
|
+
type: "toggle",
|
|
7119
|
+
scope: "safe",
|
|
7120
|
+
hotReload: true
|
|
7121
|
+
}
|
|
7122
|
+
];
|
|
7123
|
+
ConfigValidationError = class extends Error {
|
|
7124
|
+
constructor(message) {
|
|
7125
|
+
super(message);
|
|
7126
|
+
this.name = "ConfigValidationError";
|
|
7127
|
+
}
|
|
7128
|
+
};
|
|
7129
|
+
}
|
|
7130
|
+
});
|
|
7131
|
+
|
|
6829
7132
|
// src/plugins/api-server/middleware/error-handler.ts
|
|
6830
7133
|
var error_handler_exports = {};
|
|
6831
7134
|
__export(error_handler_exports, {
|
|
@@ -6848,6 +7151,16 @@ function globalErrorHandler(error, _request, reply) {
|
|
|
6848
7151
|
});
|
|
6849
7152
|
return;
|
|
6850
7153
|
}
|
|
7154
|
+
if (error instanceof ConfigValidationError) {
|
|
7155
|
+
reply.status(400).send({
|
|
7156
|
+
error: {
|
|
7157
|
+
code: "VALIDATION_ERROR",
|
|
7158
|
+
message: error.message,
|
|
7159
|
+
statusCode: 400
|
|
7160
|
+
}
|
|
7161
|
+
});
|
|
7162
|
+
return;
|
|
7163
|
+
}
|
|
6851
7164
|
if (error instanceof BadRequestError) {
|
|
6852
7165
|
reply.status(400).send({
|
|
6853
7166
|
error: {
|
|
@@ -6900,6 +7213,7 @@ var NotFoundError, BadRequestError, ServiceUnavailableError, AuthError;
|
|
|
6900
7213
|
var init_error_handler = __esm({
|
|
6901
7214
|
"src/plugins/api-server/middleware/error-handler.ts"() {
|
|
6902
7215
|
"use strict";
|
|
7216
|
+
init_config_registry();
|
|
6903
7217
|
NotFoundError = class extends Error {
|
|
6904
7218
|
constructor(code, message) {
|
|
6905
7219
|
super(message);
|
|
@@ -7204,7 +7518,7 @@ var init_sse_manager = __esm({
|
|
|
7204
7518
|
handleRequest(req, res) {
|
|
7205
7519
|
const parsedUrl = new URL(req.url || "", "http://localhost");
|
|
7206
7520
|
const sessionFilter = parsedUrl.searchParams.get("sessionId");
|
|
7207
|
-
console.log(`[sse]
|
|
7521
|
+
console.log(`[sse] +connection total=${this.sseConnections.size + 1}`);
|
|
7208
7522
|
const origin = req.headers.origin;
|
|
7209
7523
|
const corsHeaders = {
|
|
7210
7524
|
"Content-Type": "text/event-stream",
|
|
@@ -7226,7 +7540,7 @@ var init_sse_manager = __esm({
|
|
|
7226
7540
|
const cleanup = () => {
|
|
7227
7541
|
this.sseConnections.delete(res);
|
|
7228
7542
|
this.sseCleanupHandlers.delete(res);
|
|
7229
|
-
console.log(`[sse] connection
|
|
7543
|
+
console.log(`[sse] -connection remaining=${this.sseConnections.size}`);
|
|
7230
7544
|
};
|
|
7231
7545
|
this.sseCleanupHandlers.set(res, cleanup);
|
|
7232
7546
|
req.on("close", cleanup);
|
|
@@ -7286,8 +7600,8 @@ var static_server_exports = {};
|
|
|
7286
7600
|
__export(static_server_exports, {
|
|
7287
7601
|
StaticServer: () => StaticServer
|
|
7288
7602
|
});
|
|
7289
|
-
import * as
|
|
7290
|
-
import * as
|
|
7603
|
+
import * as fs19 from "fs";
|
|
7604
|
+
import * as path23 from "path";
|
|
7291
7605
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7292
7606
|
var MIME_TYPES, StaticServer;
|
|
7293
7607
|
var init_static_server = __esm({
|
|
@@ -7311,16 +7625,16 @@ var init_static_server = __esm({
|
|
|
7311
7625
|
this.uiDir = uiDir;
|
|
7312
7626
|
if (!this.uiDir) {
|
|
7313
7627
|
const __filename = fileURLToPath2(import.meta.url);
|
|
7314
|
-
const candidate =
|
|
7315
|
-
if (
|
|
7628
|
+
const candidate = path23.resolve(path23.dirname(__filename), "../../ui/dist");
|
|
7629
|
+
if (fs19.existsSync(path23.join(candidate, "index.html"))) {
|
|
7316
7630
|
this.uiDir = candidate;
|
|
7317
7631
|
}
|
|
7318
7632
|
if (!this.uiDir) {
|
|
7319
|
-
const publishCandidate =
|
|
7320
|
-
|
|
7633
|
+
const publishCandidate = path23.resolve(
|
|
7634
|
+
path23.dirname(__filename),
|
|
7321
7635
|
"../ui"
|
|
7322
7636
|
);
|
|
7323
|
-
if (
|
|
7637
|
+
if (fs19.existsSync(path23.join(publishCandidate, "index.html"))) {
|
|
7324
7638
|
this.uiDir = publishCandidate;
|
|
7325
7639
|
}
|
|
7326
7640
|
}
|
|
@@ -7332,12 +7646,12 @@ var init_static_server = __esm({
|
|
|
7332
7646
|
serve(req, res) {
|
|
7333
7647
|
if (!this.uiDir) return false;
|
|
7334
7648
|
const urlPath = (req.url || "/").split("?")[0];
|
|
7335
|
-
const safePath =
|
|
7336
|
-
const filePath =
|
|
7337
|
-
if (!filePath.startsWith(this.uiDir +
|
|
7649
|
+
const safePath = path23.normalize(urlPath);
|
|
7650
|
+
const filePath = path23.join(this.uiDir, safePath);
|
|
7651
|
+
if (!filePath.startsWith(this.uiDir + path23.sep) && filePath !== this.uiDir)
|
|
7338
7652
|
return false;
|
|
7339
|
-
if (
|
|
7340
|
-
const ext =
|
|
7653
|
+
if (fs19.existsSync(filePath) && fs19.statSync(filePath).isFile()) {
|
|
7654
|
+
const ext = path23.extname(filePath);
|
|
7341
7655
|
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
7342
7656
|
const isHashed = /\.[a-zA-Z0-9]{8,}\.(js|css)$/.test(filePath);
|
|
7343
7657
|
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
|
|
@@ -7345,16 +7659,16 @@ var init_static_server = __esm({
|
|
|
7345
7659
|
"Content-Type": contentType,
|
|
7346
7660
|
"Cache-Control": cacheControl
|
|
7347
7661
|
});
|
|
7348
|
-
|
|
7662
|
+
fs19.createReadStream(filePath).pipe(res);
|
|
7349
7663
|
return true;
|
|
7350
7664
|
}
|
|
7351
|
-
const indexPath =
|
|
7352
|
-
if (
|
|
7665
|
+
const indexPath = path23.join(this.uiDir, "index.html");
|
|
7666
|
+
if (fs19.existsSync(indexPath)) {
|
|
7353
7667
|
res.writeHead(200, {
|
|
7354
7668
|
"Content-Type": "text/html; charset=utf-8",
|
|
7355
7669
|
"Cache-Control": "no-cache"
|
|
7356
7670
|
});
|
|
7357
|
-
|
|
7671
|
+
fs19.createReadStream(indexPath).pipe(res);
|
|
7358
7672
|
return true;
|
|
7359
7673
|
}
|
|
7360
7674
|
return false;
|
|
@@ -7906,240 +8220,17 @@ var init_config = __esm({
|
|
|
7906
8220
|
}
|
|
7907
8221
|
});
|
|
7908
8222
|
|
|
7909
|
-
// src/core/
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
import path22 from "path";
|
|
7918
|
-
import fs18 from "fs";
|
|
7919
|
-
import os10 from "os";
|
|
7920
|
-
function createInstanceContext(opts) {
|
|
7921
|
-
const { id, root, isGlobal } = opts;
|
|
7922
|
-
return {
|
|
7923
|
-
id,
|
|
7924
|
-
root,
|
|
7925
|
-
isGlobal,
|
|
7926
|
-
paths: {
|
|
7927
|
-
config: path22.join(root, "config.json"),
|
|
7928
|
-
sessions: path22.join(root, "sessions.json"),
|
|
7929
|
-
agents: path22.join(root, "agents.json"),
|
|
7930
|
-
registryCache: path22.join(root, "registry-cache.json"),
|
|
7931
|
-
plugins: path22.join(root, "plugins"),
|
|
7932
|
-
pluginsData: path22.join(root, "plugins", "data"),
|
|
7933
|
-
pluginRegistry: path22.join(root, "plugins.json"),
|
|
7934
|
-
logs: path22.join(root, "logs"),
|
|
7935
|
-
pid: path22.join(root, "openacp.pid"),
|
|
7936
|
-
running: path22.join(root, "running"),
|
|
7937
|
-
apiPort: path22.join(root, "api.port"),
|
|
7938
|
-
apiSecret: path22.join(root, "api-secret"),
|
|
7939
|
-
bin: path22.join(root, "bin"),
|
|
7940
|
-
cache: path22.join(root, "cache"),
|
|
7941
|
-
tunnels: path22.join(root, "tunnels.json"),
|
|
7942
|
-
agentsDir: path22.join(root, "agents")
|
|
8223
|
+
// src/core/config/config-migrations.ts
|
|
8224
|
+
import * as fs20 from "fs";
|
|
8225
|
+
import * as path24 from "path";
|
|
8226
|
+
function applyMigrations(raw, migrationList = migrations, ctx) {
|
|
8227
|
+
let changed = false;
|
|
8228
|
+
for (const migration of migrationList) {
|
|
8229
|
+
if (migration.apply(raw, ctx)) {
|
|
8230
|
+
changed = true;
|
|
7943
8231
|
}
|
|
7944
|
-
}
|
|
7945
|
-
}
|
|
7946
|
-
function generateSlug(name) {
|
|
7947
|
-
const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
7948
|
-
return slug || "openacp";
|
|
7949
|
-
}
|
|
7950
|
-
function expandHome2(p2) {
|
|
7951
|
-
if (p2.startsWith("~")) return path22.join(os10.homedir(), p2.slice(1));
|
|
7952
|
-
return p2;
|
|
7953
|
-
}
|
|
7954
|
-
function resolveInstanceRoot(opts) {
|
|
7955
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
7956
|
-
if (opts.dir) return path22.join(expandHome2(opts.dir), ".openacp");
|
|
7957
|
-
if (opts.local) return path22.join(cwd, ".openacp");
|
|
7958
|
-
if (opts.global) return path22.join(os10.homedir(), ".openacp");
|
|
7959
|
-
const localRoot = path22.join(cwd, ".openacp");
|
|
7960
|
-
if (fs18.existsSync(localRoot)) return localRoot;
|
|
7961
|
-
if (process.env.OPENACP_INSTANCE_ROOT) return process.env.OPENACP_INSTANCE_ROOT;
|
|
7962
|
-
return null;
|
|
7963
|
-
}
|
|
7964
|
-
function getGlobalRoot() {
|
|
7965
|
-
return path22.join(os10.homedir(), ".openacp");
|
|
7966
|
-
}
|
|
7967
|
-
var init_instance_context = __esm({
|
|
7968
|
-
"src/core/instance/instance-context.ts"() {
|
|
7969
|
-
"use strict";
|
|
7970
|
-
}
|
|
7971
|
-
});
|
|
7972
|
-
|
|
7973
|
-
// src/core/config/config-registry.ts
|
|
7974
|
-
var config_registry_exports = {};
|
|
7975
|
-
__export(config_registry_exports, {
|
|
7976
|
-
CONFIG_REGISTRY: () => CONFIG_REGISTRY,
|
|
7977
|
-
getConfigValue: () => getConfigValue,
|
|
7978
|
-
getFieldDef: () => getFieldDef,
|
|
7979
|
-
getSafeFields: () => getSafeFields,
|
|
7980
|
-
isHotReloadable: () => isHotReloadable,
|
|
7981
|
-
resolveOptions: () => resolveOptions
|
|
7982
|
-
});
|
|
7983
|
-
import * as fs19 from "fs";
|
|
7984
|
-
import * as path23 from "path";
|
|
7985
|
-
function getFieldDef(path67) {
|
|
7986
|
-
return CONFIG_REGISTRY.find((f) => f.path === path67);
|
|
7987
|
-
}
|
|
7988
|
-
function getSafeFields() {
|
|
7989
|
-
return CONFIG_REGISTRY.filter((f) => f.scope === "safe");
|
|
7990
|
-
}
|
|
7991
|
-
function isHotReloadable(path67) {
|
|
7992
|
-
const def = getFieldDef(path67);
|
|
7993
|
-
return def?.hotReload ?? false;
|
|
7994
|
-
}
|
|
7995
|
-
function resolveOptions(def, config) {
|
|
7996
|
-
if (!def.options) return void 0;
|
|
7997
|
-
return typeof def.options === "function" ? def.options(config) : def.options;
|
|
7998
|
-
}
|
|
7999
|
-
function getConfigValue(config, path67) {
|
|
8000
|
-
const parts = path67.split(".");
|
|
8001
|
-
let current = config;
|
|
8002
|
-
for (const part of parts) {
|
|
8003
|
-
if (current && typeof current === "object" && part in current) {
|
|
8004
|
-
current = current[part];
|
|
8005
|
-
} else {
|
|
8006
|
-
return void 0;
|
|
8007
|
-
}
|
|
8008
|
-
}
|
|
8009
|
-
return current;
|
|
8010
|
-
}
|
|
8011
|
-
var CONFIG_REGISTRY;
|
|
8012
|
-
var init_config_registry = __esm({
|
|
8013
|
-
"src/core/config/config-registry.ts"() {
|
|
8014
|
-
"use strict";
|
|
8015
|
-
init_instance_context();
|
|
8016
|
-
CONFIG_REGISTRY = [
|
|
8017
|
-
{
|
|
8018
|
-
path: "defaultAgent",
|
|
8019
|
-
displayName: "Default Agent",
|
|
8020
|
-
group: "agent",
|
|
8021
|
-
type: "select",
|
|
8022
|
-
options: (config) => {
|
|
8023
|
-
try {
|
|
8024
|
-
const agentsPath = path23.join(getGlobalRoot(), "agents.json");
|
|
8025
|
-
if (fs19.existsSync(agentsPath)) {
|
|
8026
|
-
const data = JSON.parse(fs19.readFileSync(agentsPath, "utf-8"));
|
|
8027
|
-
return Object.keys(data.installed ?? {});
|
|
8028
|
-
}
|
|
8029
|
-
} catch {
|
|
8030
|
-
}
|
|
8031
|
-
return Object.keys(config.agents ?? {});
|
|
8032
|
-
},
|
|
8033
|
-
scope: "safe",
|
|
8034
|
-
hotReload: true
|
|
8035
|
-
},
|
|
8036
|
-
{
|
|
8037
|
-
path: "channels.telegram.outputMode",
|
|
8038
|
-
displayName: "Telegram Output Mode",
|
|
8039
|
-
group: "display",
|
|
8040
|
-
type: "select",
|
|
8041
|
-
options: ["low", "medium", "high"],
|
|
8042
|
-
scope: "safe",
|
|
8043
|
-
hotReload: true
|
|
8044
|
-
},
|
|
8045
|
-
{
|
|
8046
|
-
path: "channels.discord.outputMode",
|
|
8047
|
-
displayName: "Discord Output Mode",
|
|
8048
|
-
group: "display",
|
|
8049
|
-
type: "select",
|
|
8050
|
-
options: ["low", "medium", "high"],
|
|
8051
|
-
scope: "safe",
|
|
8052
|
-
hotReload: true
|
|
8053
|
-
},
|
|
8054
|
-
{
|
|
8055
|
-
path: "logging.level",
|
|
8056
|
-
displayName: "Log Level",
|
|
8057
|
-
group: "logging",
|
|
8058
|
-
type: "select",
|
|
8059
|
-
options: ["silent", "debug", "info", "warn", "error", "fatal"],
|
|
8060
|
-
scope: "safe",
|
|
8061
|
-
hotReload: true
|
|
8062
|
-
},
|
|
8063
|
-
{
|
|
8064
|
-
path: "tunnel.enabled",
|
|
8065
|
-
displayName: "Tunnel",
|
|
8066
|
-
group: "tunnel",
|
|
8067
|
-
type: "toggle",
|
|
8068
|
-
scope: "safe",
|
|
8069
|
-
hotReload: false
|
|
8070
|
-
},
|
|
8071
|
-
{
|
|
8072
|
-
path: "security.maxConcurrentSessions",
|
|
8073
|
-
displayName: "Max Concurrent Sessions",
|
|
8074
|
-
group: "security",
|
|
8075
|
-
type: "number",
|
|
8076
|
-
scope: "safe",
|
|
8077
|
-
hotReload: true
|
|
8078
|
-
},
|
|
8079
|
-
{
|
|
8080
|
-
path: "security.sessionTimeoutMinutes",
|
|
8081
|
-
displayName: "Session Timeout (min)",
|
|
8082
|
-
group: "security",
|
|
8083
|
-
type: "number",
|
|
8084
|
-
scope: "safe",
|
|
8085
|
-
hotReload: true
|
|
8086
|
-
},
|
|
8087
|
-
{
|
|
8088
|
-
path: "workspace.baseDir",
|
|
8089
|
-
displayName: "Workspace Directory",
|
|
8090
|
-
group: "workspace",
|
|
8091
|
-
type: "string",
|
|
8092
|
-
scope: "safe",
|
|
8093
|
-
hotReload: true
|
|
8094
|
-
},
|
|
8095
|
-
{
|
|
8096
|
-
path: "sessionStore.ttlDays",
|
|
8097
|
-
displayName: "Session Store TTL (days)",
|
|
8098
|
-
group: "storage",
|
|
8099
|
-
type: "number",
|
|
8100
|
-
scope: "safe",
|
|
8101
|
-
hotReload: true
|
|
8102
|
-
},
|
|
8103
|
-
{
|
|
8104
|
-
path: "speech.stt.provider",
|
|
8105
|
-
displayName: "Speech to Text",
|
|
8106
|
-
group: "speech",
|
|
8107
|
-
type: "select",
|
|
8108
|
-
options: ["groq"],
|
|
8109
|
-
scope: "safe",
|
|
8110
|
-
hotReload: true
|
|
8111
|
-
},
|
|
8112
|
-
{
|
|
8113
|
-
path: "speech.stt.apiKey",
|
|
8114
|
-
displayName: "STT API Key",
|
|
8115
|
-
group: "speech",
|
|
8116
|
-
type: "string",
|
|
8117
|
-
scope: "sensitive",
|
|
8118
|
-
hotReload: true
|
|
8119
|
-
},
|
|
8120
|
-
{
|
|
8121
|
-
path: "agentSwitch.labelHistory",
|
|
8122
|
-
displayName: "Label Agent in History",
|
|
8123
|
-
group: "agent",
|
|
8124
|
-
type: "toggle",
|
|
8125
|
-
scope: "safe",
|
|
8126
|
-
hotReload: true
|
|
8127
|
-
}
|
|
8128
|
-
];
|
|
8129
|
-
}
|
|
8130
|
-
});
|
|
8131
|
-
|
|
8132
|
-
// src/core/config/config-migrations.ts
|
|
8133
|
-
import * as fs20 from "fs";
|
|
8134
|
-
import * as path24 from "path";
|
|
8135
|
-
function applyMigrations(raw, migrationList = migrations, ctx) {
|
|
8136
|
-
let changed = false;
|
|
8137
|
-
for (const migration of migrationList) {
|
|
8138
|
-
if (migration.apply(raw, ctx)) {
|
|
8139
|
-
changed = true;
|
|
8140
|
-
}
|
|
8141
|
-
}
|
|
8142
|
-
return { changed };
|
|
8232
|
+
}
|
|
8233
|
+
return { changed };
|
|
8143
8234
|
}
|
|
8144
8235
|
var log11, migrations;
|
|
8145
8236
|
var init_config_migrations = __esm({
|
|
@@ -8533,6 +8624,26 @@ var init_config2 = __esm({
|
|
|
8533
8624
|
fs21.mkdirSync(dir, { recursive: true });
|
|
8534
8625
|
fs21.writeFileSync(this.configPath, JSON.stringify(config, null, 2));
|
|
8535
8626
|
}
|
|
8627
|
+
async applyEnvToPluginSettings(settingsManager) {
|
|
8628
|
+
const pluginOverrides = [
|
|
8629
|
+
{ envVar: "OPENACP_TUNNEL_ENABLED", pluginName: "@openacp/tunnel", key: "enabled", transform: (v) => v === "true" },
|
|
8630
|
+
{ envVar: "OPENACP_TUNNEL_PORT", pluginName: "@openacp/tunnel", key: "port", transform: (v) => Number(v) },
|
|
8631
|
+
{ envVar: "OPENACP_TUNNEL_PROVIDER", pluginName: "@openacp/tunnel", key: "provider" },
|
|
8632
|
+
{ envVar: "OPENACP_API_PORT", pluginName: "@openacp/api-server", key: "port", transform: (v) => Number(v) },
|
|
8633
|
+
{ envVar: "OPENACP_SPEECH_STT_PROVIDER", pluginName: "@openacp/speech", key: "sttProvider" },
|
|
8634
|
+
{ envVar: "OPENACP_SPEECH_GROQ_API_KEY", pluginName: "@openacp/speech", key: "groqApiKey" },
|
|
8635
|
+
{ envVar: "OPENACP_TELEGRAM_BOT_TOKEN", pluginName: "@openacp/telegram", key: "botToken" },
|
|
8636
|
+
{ envVar: "OPENACP_TELEGRAM_CHAT_ID", pluginName: "@openacp/telegram", key: "chatId", transform: (v) => Number(v) }
|
|
8637
|
+
];
|
|
8638
|
+
for (const { envVar, pluginName, key, transform } of pluginOverrides) {
|
|
8639
|
+
const value = process.env[envVar];
|
|
8640
|
+
if (value !== void 0) {
|
|
8641
|
+
const resolved = transform ? transform(value) : value;
|
|
8642
|
+
await settingsManager.updatePluginSettings(pluginName, { [key]: resolved });
|
|
8643
|
+
log12.debug({ envVar, pluginName, key }, "Env var override applied to plugin settings");
|
|
8644
|
+
}
|
|
8645
|
+
}
|
|
8646
|
+
}
|
|
8536
8647
|
applyEnvOverrides(raw) {
|
|
8537
8648
|
const overrides = [
|
|
8538
8649
|
["OPENACP_TELEGRAM_BOT_TOKEN", ["channels", "telegram", "botToken"]],
|
|
@@ -8645,18 +8756,19 @@ function redactDeep(obj) {
|
|
|
8645
8756
|
}
|
|
8646
8757
|
async function configRoutes(app, deps) {
|
|
8647
8758
|
app.get("/editable", { preHandler: requireScopes("config:read") }, async () => {
|
|
8648
|
-
const { getSafeFields: getSafeFields2, resolveOptions: resolveOptions2,
|
|
8759
|
+
const { getSafeFields: getSafeFields2, resolveOptions: resolveOptions2, getFieldValueAsync: getFieldValueAsync2 } = await Promise.resolve().then(() => (init_config_registry(), config_registry_exports));
|
|
8649
8760
|
const config = deps.core.configManager.get();
|
|
8761
|
+
const settingsManager = deps.core.settingsManager;
|
|
8650
8762
|
const safeFields = getSafeFields2();
|
|
8651
|
-
const fields = safeFields.map((def) => ({
|
|
8763
|
+
const fields = await Promise.all(safeFields.map(async (def) => ({
|
|
8652
8764
|
path: def.path,
|
|
8653
8765
|
displayName: def.displayName,
|
|
8654
8766
|
group: def.group,
|
|
8655
8767
|
type: def.type,
|
|
8656
8768
|
options: resolveOptions2(def, config),
|
|
8657
|
-
value:
|
|
8769
|
+
value: await getFieldValueAsync2(def, deps.core.configManager, settingsManager),
|
|
8658
8770
|
hotReload: def.hotReload
|
|
8659
|
-
}));
|
|
8771
|
+
})));
|
|
8660
8772
|
return { fields };
|
|
8661
8773
|
});
|
|
8662
8774
|
app.get("/schema", { preHandler: requireScopes("config:read") }, async () => {
|
|
@@ -8676,16 +8788,20 @@ async function configRoutes(app, deps) {
|
|
|
8676
8788
|
if (configPath.split(".").some((p2) => BLOCKED_KEYS.has(p2))) {
|
|
8677
8789
|
return reply.status(400).send({ error: "Invalid config path" });
|
|
8678
8790
|
}
|
|
8679
|
-
const { getFieldDef: getFieldDef2 } = await Promise.resolve().then(() => (init_config_registry(), config_registry_exports));
|
|
8791
|
+
const { getFieldDef: getFieldDef2, setFieldValueAsync: setFieldValueAsync2 } = await Promise.resolve().then(() => (init_config_registry(), config_registry_exports));
|
|
8680
8792
|
const fieldDef = getFieldDef2(configPath);
|
|
8681
8793
|
if (!fieldDef || fieldDef.scope !== "safe") {
|
|
8682
8794
|
return reply.status(403).send({
|
|
8683
8795
|
error: "This config field cannot be modified via the API"
|
|
8684
8796
|
});
|
|
8685
8797
|
}
|
|
8686
|
-
|
|
8687
|
-
const {
|
|
8688
|
-
|
|
8798
|
+
const settingsManager = deps.core.settingsManager;
|
|
8799
|
+
const { needsRestart } = await setFieldValueAsync2(
|
|
8800
|
+
fieldDef,
|
|
8801
|
+
value,
|
|
8802
|
+
deps.core.configManager,
|
|
8803
|
+
settingsManager
|
|
8804
|
+
);
|
|
8689
8805
|
return {
|
|
8690
8806
|
ok: true,
|
|
8691
8807
|
needsRestart,
|
|
@@ -9196,13 +9312,152 @@ var init_workspace = __esm({
|
|
|
9196
9312
|
}
|
|
9197
9313
|
});
|
|
9198
9314
|
|
|
9315
|
+
// src/plugins/api-server/routes/plugins.ts
|
|
9316
|
+
var plugins_exports = {};
|
|
9317
|
+
__export(plugins_exports, {
|
|
9318
|
+
pluginRoutes: () => pluginRoutes
|
|
9319
|
+
});
|
|
9320
|
+
import path26 from "path";
|
|
9321
|
+
import os12 from "os";
|
|
9322
|
+
async function pluginRoutes(app, deps) {
|
|
9323
|
+
const { lifecycleManager } = deps;
|
|
9324
|
+
const admin = [requireScopes("system:admin")];
|
|
9325
|
+
app.get("/", { preHandler: admin }, async () => {
|
|
9326
|
+
if (!lifecycleManager?.registry) return { plugins: [] };
|
|
9327
|
+
const registry = lifecycleManager.registry;
|
|
9328
|
+
const loadedSet = new Set(lifecycleManager.loadedPlugins);
|
|
9329
|
+
const failedSet = new Set(lifecycleManager.failedPlugins);
|
|
9330
|
+
const loadOrderMap = new Map(lifecycleManager.plugins.map((p2) => [p2.name, p2]));
|
|
9331
|
+
const coreMap = new Map(corePlugins.map((p2) => [p2.name, p2]));
|
|
9332
|
+
const plugins = Array.from(registry.list().entries()).map(([name, entry]) => {
|
|
9333
|
+
const def = loadOrderMap.get(name) ?? coreMap.get(name);
|
|
9334
|
+
return {
|
|
9335
|
+
name,
|
|
9336
|
+
version: entry.version,
|
|
9337
|
+
description: entry.description,
|
|
9338
|
+
source: entry.source,
|
|
9339
|
+
enabled: entry.enabled,
|
|
9340
|
+
loaded: loadedSet.has(name),
|
|
9341
|
+
failed: failedSet.has(name),
|
|
9342
|
+
essential: def?.essential ?? false,
|
|
9343
|
+
hasConfigure: typeof def?.configure === "function"
|
|
9344
|
+
};
|
|
9345
|
+
});
|
|
9346
|
+
return { plugins };
|
|
9347
|
+
});
|
|
9348
|
+
app.get("/marketplace", { preHandler: admin }, async (_req, reply) => {
|
|
9349
|
+
try {
|
|
9350
|
+
const data = await registryClient.getRegistry();
|
|
9351
|
+
const installedNames = new Set(
|
|
9352
|
+
lifecycleManager?.registry ? Array.from(lifecycleManager.registry.list().keys()) : []
|
|
9353
|
+
);
|
|
9354
|
+
const plugins = data.plugins.map((p2) => ({
|
|
9355
|
+
...p2,
|
|
9356
|
+
installed: installedNames.has(p2.name) || installedNames.has(p2.npm)
|
|
9357
|
+
}));
|
|
9358
|
+
return { plugins, categories: data.categories };
|
|
9359
|
+
} catch {
|
|
9360
|
+
return reply.status(503).send({ error: "Marketplace unavailable" });
|
|
9361
|
+
}
|
|
9362
|
+
});
|
|
9363
|
+
app.post("/:name/enable", { preHandler: admin }, async (req, reply) => {
|
|
9364
|
+
if (!lifecycleManager?.registry) {
|
|
9365
|
+
return reply.status(503).send({ error: "Plugin manager unavailable" });
|
|
9366
|
+
}
|
|
9367
|
+
const name = req.params.name;
|
|
9368
|
+
const registry = lifecycleManager.registry;
|
|
9369
|
+
const entry = registry.get(name);
|
|
9370
|
+
if (!entry) {
|
|
9371
|
+
return reply.status(404).send({ error: `Plugin "${name}" not found` });
|
|
9372
|
+
}
|
|
9373
|
+
if (lifecycleManager.loadedPlugins.includes(name)) {
|
|
9374
|
+
registry.setEnabled(name, true);
|
|
9375
|
+
await registry.save();
|
|
9376
|
+
return { ok: true };
|
|
9377
|
+
}
|
|
9378
|
+
let pluginDef = lifecycleManager.plugins.find((p2) => p2.name === name);
|
|
9379
|
+
if (!pluginDef) {
|
|
9380
|
+
if (entry.source === "builtin") {
|
|
9381
|
+
pluginDef = corePlugins.find((p2) => p2.name === name);
|
|
9382
|
+
} else {
|
|
9383
|
+
const { importFromDir: importFromDir2 } = await Promise.resolve().then(() => (init_plugin_installer(), plugin_installer_exports));
|
|
9384
|
+
const instanceRoot = lifecycleManager.instanceRoot ?? path26.join(os12.homedir(), ".openacp");
|
|
9385
|
+
const pluginsDir = path26.join(instanceRoot, "plugins");
|
|
9386
|
+
try {
|
|
9387
|
+
const mod = await importFromDir2(name, pluginsDir);
|
|
9388
|
+
pluginDef = mod.default ?? mod;
|
|
9389
|
+
} catch {
|
|
9390
|
+
return reply.status(500).send({ error: "Plugin module could not be loaded. Try restarting the server." });
|
|
9391
|
+
}
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
if (!pluginDef) {
|
|
9395
|
+
return reply.status(500).send({ error: `Plugin definition not found for "${name}"` });
|
|
9396
|
+
}
|
|
9397
|
+
registry.setEnabled(name, true);
|
|
9398
|
+
await registry.save();
|
|
9399
|
+
await lifecycleManager.boot([pluginDef]);
|
|
9400
|
+
if (lifecycleManager.failedPlugins.includes(name)) {
|
|
9401
|
+
return reply.status(500).send({ error: `Plugin "${name}" failed to start` });
|
|
9402
|
+
}
|
|
9403
|
+
return { ok: true };
|
|
9404
|
+
});
|
|
9405
|
+
app.post("/:name/disable", { preHandler: admin }, async (req, reply) => {
|
|
9406
|
+
if (!lifecycleManager?.registry) {
|
|
9407
|
+
return reply.status(503).send({ error: "Plugin manager unavailable" });
|
|
9408
|
+
}
|
|
9409
|
+
const name = req.params.name;
|
|
9410
|
+
const registry = lifecycleManager.registry;
|
|
9411
|
+
const entry = registry.get(name);
|
|
9412
|
+
if (!entry) {
|
|
9413
|
+
return reply.status(404).send({ error: `Plugin "${name}" not found` });
|
|
9414
|
+
}
|
|
9415
|
+
const def = lifecycleManager.plugins.find((p2) => p2.name === name) ?? corePlugins.find((p2) => p2.name === name);
|
|
9416
|
+
if (def?.essential) {
|
|
9417
|
+
return reply.status(409).send({ error: "Essential plugins cannot be disabled" });
|
|
9418
|
+
}
|
|
9419
|
+
await lifecycleManager.unloadPlugin(name);
|
|
9420
|
+
registry.setEnabled(name, false);
|
|
9421
|
+
await registry.save();
|
|
9422
|
+
return { ok: true };
|
|
9423
|
+
});
|
|
9424
|
+
app.delete("/:name", { preHandler: admin }, async (req, reply) => {
|
|
9425
|
+
if (!lifecycleManager?.registry) {
|
|
9426
|
+
return reply.status(503).send({ error: "Plugin manager unavailable" });
|
|
9427
|
+
}
|
|
9428
|
+
const name = req.params.name;
|
|
9429
|
+
const registry = lifecycleManager.registry;
|
|
9430
|
+
const entry = registry.get(name);
|
|
9431
|
+
if (!entry) {
|
|
9432
|
+
return reply.status(404).send({ error: `Plugin "${name}" not found` });
|
|
9433
|
+
}
|
|
9434
|
+
if (entry.source === "builtin") {
|
|
9435
|
+
return reply.status(400).send({ error: "Builtin plugins cannot be uninstalled. Use disable instead." });
|
|
9436
|
+
}
|
|
9437
|
+
await lifecycleManager.unloadPlugin(name);
|
|
9438
|
+
registry.remove(name);
|
|
9439
|
+
await registry.save();
|
|
9440
|
+
return { ok: true };
|
|
9441
|
+
});
|
|
9442
|
+
}
|
|
9443
|
+
var registryClient;
|
|
9444
|
+
var init_plugins = __esm({
|
|
9445
|
+
"src/plugins/api-server/routes/plugins.ts"() {
|
|
9446
|
+
"use strict";
|
|
9447
|
+
init_auth();
|
|
9448
|
+
init_core_plugins();
|
|
9449
|
+
init_registry_client();
|
|
9450
|
+
registryClient = new RegistryClient();
|
|
9451
|
+
}
|
|
9452
|
+
});
|
|
9453
|
+
|
|
9199
9454
|
// src/core/instance/instance-registry.ts
|
|
9200
9455
|
var instance_registry_exports = {};
|
|
9201
9456
|
__export(instance_registry_exports, {
|
|
9202
9457
|
InstanceRegistry: () => InstanceRegistry
|
|
9203
9458
|
});
|
|
9204
9459
|
import fs22 from "fs";
|
|
9205
|
-
import
|
|
9460
|
+
import path27 from "path";
|
|
9206
9461
|
var InstanceRegistry;
|
|
9207
9462
|
var init_instance_registry = __esm({
|
|
9208
9463
|
"src/core/instance/instance-registry.ts"() {
|
|
@@ -9240,7 +9495,7 @@ var init_instance_registry = __esm({
|
|
|
9240
9495
|
}
|
|
9241
9496
|
}
|
|
9242
9497
|
save() {
|
|
9243
|
-
const dir =
|
|
9498
|
+
const dir = path27.dirname(this.registryPath);
|
|
9244
9499
|
fs22.mkdirSync(dir, { recursive: true });
|
|
9245
9500
|
fs22.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
|
|
9246
9501
|
}
|
|
@@ -9276,13 +9531,13 @@ __export(api_server_exports, {
|
|
|
9276
9531
|
});
|
|
9277
9532
|
import * as fs23 from "fs";
|
|
9278
9533
|
import * as crypto2 from "crypto";
|
|
9279
|
-
import * as
|
|
9534
|
+
import * as path28 from "path";
|
|
9280
9535
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9281
9536
|
function getVersion() {
|
|
9282
9537
|
if (cachedVersion) return cachedVersion;
|
|
9283
9538
|
try {
|
|
9284
9539
|
const __filename = fileURLToPath3(import.meta.url);
|
|
9285
|
-
const pkgPath =
|
|
9540
|
+
const pkgPath = path28.resolve(path28.dirname(__filename), "../../../package.json");
|
|
9286
9541
|
const pkg = JSON.parse(fs23.readFileSync(pkgPath, "utf-8"));
|
|
9287
9542
|
cachedVersion = pkg.version ?? "0.0.0-dev";
|
|
9288
9543
|
} catch {
|
|
@@ -9291,7 +9546,7 @@ function getVersion() {
|
|
|
9291
9546
|
return cachedVersion;
|
|
9292
9547
|
}
|
|
9293
9548
|
function loadOrCreateSecret(secretFilePath) {
|
|
9294
|
-
const dir =
|
|
9549
|
+
const dir = path28.dirname(secretFilePath);
|
|
9295
9550
|
fs23.mkdirSync(dir, { recursive: true });
|
|
9296
9551
|
try {
|
|
9297
9552
|
const existing = fs23.readFileSync(secretFilePath, "utf-8").trim();
|
|
@@ -9317,7 +9572,7 @@ function loadOrCreateSecret(secretFilePath) {
|
|
|
9317
9572
|
return secret;
|
|
9318
9573
|
}
|
|
9319
9574
|
function writePortFile(portFilePath, port) {
|
|
9320
|
-
const dir =
|
|
9575
|
+
const dir = path28.dirname(portFilePath);
|
|
9321
9576
|
fs23.mkdirSync(dir, { recursive: true });
|
|
9322
9577
|
fs23.writeFileSync(portFilePath, String(port));
|
|
9323
9578
|
}
|
|
@@ -9409,10 +9664,10 @@ function createApiServerPlugin() {
|
|
|
9409
9664
|
{ port: apiConfig.port, host: apiConfig.host, instanceRoot },
|
|
9410
9665
|
"API server plugin setup \u2014 config loaded"
|
|
9411
9666
|
);
|
|
9412
|
-
portFilePath =
|
|
9413
|
-
const secretFilePath =
|
|
9414
|
-
const jwtSecretFilePath =
|
|
9415
|
-
const tokensFilePath =
|
|
9667
|
+
portFilePath = path28.join(instanceRoot, "api.port");
|
|
9668
|
+
const secretFilePath = path28.join(instanceRoot, "api-secret");
|
|
9669
|
+
const jwtSecretFilePath = path28.join(instanceRoot, "jwt-secret");
|
|
9670
|
+
const tokensFilePath = path28.join(instanceRoot, "tokens.json");
|
|
9416
9671
|
const startedAt = Date.now();
|
|
9417
9672
|
const secret = loadOrCreateSecret(secretFilePath);
|
|
9418
9673
|
const jwtSecret = loadOrCreateSecret(jwtSecretFilePath);
|
|
@@ -9435,6 +9690,7 @@ function createApiServerPlugin() {
|
|
|
9435
9690
|
const { commandRoutes: commandRoutes2 } = await Promise.resolve().then(() => (init_commands2(), commands_exports));
|
|
9436
9691
|
const { authRoutes: authRoutes2 } = await Promise.resolve().then(() => (init_auth3(), auth_exports3));
|
|
9437
9692
|
const { workspaceRoute: workspaceRoute2 } = await Promise.resolve().then(() => (init_workspace(), workspace_exports));
|
|
9693
|
+
const { pluginRoutes: pluginRoutes2 } = await Promise.resolve().then(() => (init_plugins(), plugins_exports));
|
|
9438
9694
|
server = await createApiServer2({
|
|
9439
9695
|
port: apiConfig.port,
|
|
9440
9696
|
host: apiConfig.host,
|
|
@@ -9453,7 +9709,8 @@ function createApiServerPlugin() {
|
|
|
9453
9709
|
getVersion,
|
|
9454
9710
|
commandRegistry,
|
|
9455
9711
|
authPreHandler: routeAuthPreHandler,
|
|
9456
|
-
contextManager
|
|
9712
|
+
contextManager,
|
|
9713
|
+
lifecycleManager: core.lifecycleManager
|
|
9457
9714
|
};
|
|
9458
9715
|
server.registerPlugin("/api/v1/sessions", async (app) => sessionRoutes2(app, deps));
|
|
9459
9716
|
server.registerPlugin("/api/v1/agents", async (app) => agentRoutes2(app, deps));
|
|
@@ -9464,16 +9721,17 @@ function createApiServerPlugin() {
|
|
|
9464
9721
|
server.registerPlugin("/api/v1/notify", async (app) => notifyRoutes2(app, deps));
|
|
9465
9722
|
server.registerPlugin("/api/v1/commands", async (app) => commandRoutes2(app, deps));
|
|
9466
9723
|
server.registerPlugin("/api/v1/auth", async (app) => authRoutes2(app, { tokenStore, getJwtSecret: () => jwtSecret }));
|
|
9724
|
+
server.registerPlugin("/api/v1/plugins", async (app) => pluginRoutes2(app, deps));
|
|
9467
9725
|
const { InstanceRegistry: InstanceRegistry2 } = await Promise.resolve().then(() => (init_instance_registry(), instance_registry_exports));
|
|
9468
9726
|
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
9469
9727
|
const globalRoot = getGlobalRoot2();
|
|
9470
|
-
const instanceReg = new InstanceRegistry2(
|
|
9728
|
+
const instanceReg = new InstanceRegistry2(path28.join(globalRoot, "instances.json"));
|
|
9471
9729
|
instanceReg.load();
|
|
9472
9730
|
const instanceEntry = instanceReg.getByRoot(instanceRoot);
|
|
9473
9731
|
const workspaceId = instanceEntry?.id ?? "main";
|
|
9474
9732
|
const appConfig = core.configManager.get();
|
|
9475
9733
|
const workspaceName = appConfig.instanceName ?? "Main";
|
|
9476
|
-
const workspaceDir =
|
|
9734
|
+
const workspaceDir = path28.dirname(instanceRoot);
|
|
9477
9735
|
server.registerPlugin("/api/v1", async (app) => {
|
|
9478
9736
|
await app.register(workspaceRoute2, {
|
|
9479
9737
|
id: workspaceId,
|
|
@@ -10408,8 +10666,8 @@ function formatToolSummary(name, rawInput, displaySummary) {
|
|
|
10408
10666
|
}
|
|
10409
10667
|
if (lowerName === "grep") {
|
|
10410
10668
|
const pattern = args2.pattern ?? "";
|
|
10411
|
-
const
|
|
10412
|
-
return pattern ? `\u{1F50D} Grep "${pattern}"${
|
|
10669
|
+
const path69 = args2.path ?? "";
|
|
10670
|
+
return pattern ? `\u{1F50D} Grep "${pattern}"${path69 ? ` in ${path69}` : ""}` : `\u{1F527} ${name}`;
|
|
10413
10671
|
}
|
|
10414
10672
|
if (lowerName === "glob") {
|
|
10415
10673
|
const pattern = args2.pattern ?? "";
|
|
@@ -10445,8 +10703,8 @@ function formatToolTitle(name, rawInput, displayTitle) {
|
|
|
10445
10703
|
}
|
|
10446
10704
|
if (lowerName === "grep") {
|
|
10447
10705
|
const pattern = args2.pattern ?? "";
|
|
10448
|
-
const
|
|
10449
|
-
return pattern ? `"${pattern}"${
|
|
10706
|
+
const path69 = args2.path ?? "";
|
|
10707
|
+
return pattern ? `"${pattern}"${path69 ? ` in ${path69}` : ""}` : name;
|
|
10450
10708
|
}
|
|
10451
10709
|
if (lowerName === "glob") {
|
|
10452
10710
|
return String(args2.pattern ?? name);
|
|
@@ -12254,12 +12512,11 @@ var init_menu = __esm({
|
|
|
12254
12512
|
|
|
12255
12513
|
// src/plugins/telegram/commands/settings.ts
|
|
12256
12514
|
import { InlineKeyboard as InlineKeyboard6 } from "grammy";
|
|
12257
|
-
function buildSettingsKeyboard(core) {
|
|
12258
|
-
const config = core.configManager.get();
|
|
12515
|
+
async function buildSettingsKeyboard(core) {
|
|
12259
12516
|
const fields = getSafeFields();
|
|
12260
12517
|
const kb = new InlineKeyboard6();
|
|
12261
12518
|
for (const field of fields) {
|
|
12262
|
-
const value =
|
|
12519
|
+
const value = await getFieldValueAsync(field, core.configManager, core.settingsManager);
|
|
12263
12520
|
const label = formatFieldLabel(field, value);
|
|
12264
12521
|
if (field.type === "toggle") {
|
|
12265
12522
|
kb.text(`${label}`, `s:toggle:${field.path}`).row();
|
|
@@ -12290,7 +12547,7 @@ function formatFieldLabel(field, value) {
|
|
|
12290
12547
|
return `${icon} ${field.displayName}: ${displayValue}`;
|
|
12291
12548
|
}
|
|
12292
12549
|
async function handleSettings(ctx, core) {
|
|
12293
|
-
const kb = buildSettingsKeyboard(core);
|
|
12550
|
+
const kb = await buildSettingsKeyboard(core);
|
|
12294
12551
|
await ctx.reply(`<b>\u2699\uFE0F Settings</b>
|
|
12295
12552
|
Tap to change:`, {
|
|
12296
12553
|
parse_mode: "HTML",
|
|
@@ -12300,19 +12557,20 @@ Tap to change:`, {
|
|
|
12300
12557
|
function setupSettingsCallbacks(bot, core, getAssistantSession) {
|
|
12301
12558
|
bot.callbackQuery(/^s:toggle:/, async (ctx) => {
|
|
12302
12559
|
const fieldPath = ctx.callbackQuery.data.replace("s:toggle:", "");
|
|
12303
|
-
const
|
|
12304
|
-
|
|
12560
|
+
const fieldDef = getSafeFields().find((f) => f.path === fieldPath);
|
|
12561
|
+
if (!fieldDef) return;
|
|
12562
|
+
const settingsManager = core.settingsManager;
|
|
12563
|
+
const currentValue = await getFieldValueAsync(fieldDef, core.configManager, settingsManager);
|
|
12305
12564
|
const newValue = !currentValue;
|
|
12306
12565
|
try {
|
|
12307
|
-
|
|
12308
|
-
await core.configManager.save(updates, fieldPath);
|
|
12566
|
+
await setFieldValueAsync(fieldDef, newValue, core.configManager, settingsManager);
|
|
12309
12567
|
const toast = isHotReloadable(fieldPath) ? `\u2705 ${fieldPath} = ${newValue}` : `\u2705 ${fieldPath} = ${newValue} (restart needed)`;
|
|
12310
12568
|
try {
|
|
12311
12569
|
await ctx.answerCallbackQuery({ text: toast });
|
|
12312
12570
|
} catch {
|
|
12313
12571
|
}
|
|
12314
12572
|
try {
|
|
12315
|
-
await ctx.editMessageReplyMarkup({ reply_markup: buildSettingsKeyboard(core) });
|
|
12573
|
+
await ctx.editMessageReplyMarkup({ reply_markup: await buildSettingsKeyboard(core) });
|
|
12316
12574
|
} catch {
|
|
12317
12575
|
}
|
|
12318
12576
|
} catch (err) {
|
|
@@ -12329,7 +12587,7 @@ function setupSettingsCallbacks(bot, core, getAssistantSession) {
|
|
|
12329
12587
|
const fieldDef = getSafeFields().find((f) => f.path === fieldPath);
|
|
12330
12588
|
if (!fieldDef) return;
|
|
12331
12589
|
const options = resolveOptions(fieldDef, config) ?? [];
|
|
12332
|
-
const currentValue =
|
|
12590
|
+
const currentValue = await getFieldValueAsync(fieldDef, core.configManager, core.settingsManager);
|
|
12333
12591
|
const kb = new InlineKeyboard6();
|
|
12334
12592
|
for (const opt of options) {
|
|
12335
12593
|
const marker = opt === String(currentValue) ? " \u2713" : "";
|
|
@@ -12353,11 +12611,21 @@ Select a value:`, {
|
|
|
12353
12611
|
const parts = ctx.callbackQuery.data.replace("s:pick:", "").split(":");
|
|
12354
12612
|
const fieldPath = parts.slice(0, -1).join(":");
|
|
12355
12613
|
const newValue = parts[parts.length - 1];
|
|
12614
|
+
const fieldDef = getSafeFields().find((f) => f.path === fieldPath);
|
|
12615
|
+
if (!fieldDef) return;
|
|
12356
12616
|
try {
|
|
12357
12617
|
if (fieldPath === "speech.stt.provider") {
|
|
12358
|
-
const
|
|
12359
|
-
|
|
12360
|
-
if (
|
|
12618
|
+
const sm = core.settingsManager;
|
|
12619
|
+
let hasApiKey = false;
|
|
12620
|
+
if (sm) {
|
|
12621
|
+
const speechSettings = await sm.loadSettings("@openacp/speech");
|
|
12622
|
+
hasApiKey = !!speechSettings.groqApiKey;
|
|
12623
|
+
} else {
|
|
12624
|
+
const config = core.configManager.get();
|
|
12625
|
+
const providerConfig = config.speech?.stt?.providers?.[newValue];
|
|
12626
|
+
hasApiKey = !!providerConfig?.apiKey;
|
|
12627
|
+
}
|
|
12628
|
+
if (!hasApiKey) {
|
|
12361
12629
|
const assistant = getAssistantSession();
|
|
12362
12630
|
if (assistant) {
|
|
12363
12631
|
try {
|
|
@@ -12375,8 +12643,7 @@ Select a value:`, {
|
|
|
12375
12643
|
return;
|
|
12376
12644
|
}
|
|
12377
12645
|
}
|
|
12378
|
-
|
|
12379
|
-
await core.configManager.save(updates, fieldPath);
|
|
12646
|
+
await setFieldValueAsync(fieldDef, newValue, core.configManager, core.settingsManager);
|
|
12380
12647
|
try {
|
|
12381
12648
|
await ctx.answerCallbackQuery({ text: `\u2705 ${fieldPath} = ${newValue}` });
|
|
12382
12649
|
} catch {
|
|
@@ -12385,7 +12652,7 @@ Select a value:`, {
|
|
|
12385
12652
|
await ctx.editMessageText(`<b>\u2699\uFE0F Settings</b>
|
|
12386
12653
|
Tap to change:`, {
|
|
12387
12654
|
parse_mode: "HTML",
|
|
12388
|
-
reply_markup: buildSettingsKeyboard(core)
|
|
12655
|
+
reply_markup: await buildSettingsKeyboard(core)
|
|
12389
12656
|
});
|
|
12390
12657
|
} catch {
|
|
12391
12658
|
}
|
|
@@ -12399,10 +12666,9 @@ Tap to change:`, {
|
|
|
12399
12666
|
});
|
|
12400
12667
|
bot.callbackQuery(/^s:input:/, async (ctx) => {
|
|
12401
12668
|
const fieldPath = ctx.callbackQuery.data.replace("s:input:", "");
|
|
12402
|
-
const config = core.configManager.get();
|
|
12403
12669
|
const fieldDef = getSafeFields().find((f) => f.path === fieldPath);
|
|
12404
12670
|
if (!fieldDef) return;
|
|
12405
|
-
const currentValue =
|
|
12671
|
+
const currentValue = await getFieldValueAsync(fieldDef, core.configManager, core.settingsManager);
|
|
12406
12672
|
const assistant = getAssistantSession();
|
|
12407
12673
|
if (!assistant) {
|
|
12408
12674
|
try {
|
|
@@ -12443,23 +12709,12 @@ Choose an action:`, {
|
|
|
12443
12709
|
await ctx.editMessageText(`<b>\u2699\uFE0F Settings</b>
|
|
12444
12710
|
Tap to change:`, {
|
|
12445
12711
|
parse_mode: "HTML",
|
|
12446
|
-
reply_markup: buildSettingsKeyboard(core)
|
|
12712
|
+
reply_markup: await buildSettingsKeyboard(core)
|
|
12447
12713
|
});
|
|
12448
12714
|
} catch {
|
|
12449
12715
|
}
|
|
12450
12716
|
});
|
|
12451
12717
|
}
|
|
12452
|
-
function buildNestedUpdate(dotPath, value) {
|
|
12453
|
-
const parts = dotPath.split(".");
|
|
12454
|
-
const result = {};
|
|
12455
|
-
let target = result;
|
|
12456
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
12457
|
-
target[parts[i]] = {};
|
|
12458
|
-
target = target[parts[i]];
|
|
12459
|
-
}
|
|
12460
|
-
target[parts[parts.length - 1]] = value;
|
|
12461
|
-
return result;
|
|
12462
|
-
}
|
|
12463
12718
|
var log18;
|
|
12464
12719
|
var init_settings = __esm({
|
|
12465
12720
|
"src/plugins/telegram/commands/settings.ts"() {
|
|
@@ -12534,7 +12789,7 @@ var init_config4 = __esm({
|
|
|
12534
12789
|
// src/core/doctor/checks/agents.ts
|
|
12535
12790
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
12536
12791
|
import * as fs25 from "fs";
|
|
12537
|
-
import * as
|
|
12792
|
+
import * as path29 from "path";
|
|
12538
12793
|
function commandExists2(cmd) {
|
|
12539
12794
|
try {
|
|
12540
12795
|
execFileSync3("which", [cmd], { stdio: "pipe" });
|
|
@@ -12543,9 +12798,9 @@ function commandExists2(cmd) {
|
|
|
12543
12798
|
}
|
|
12544
12799
|
let dir = process.cwd();
|
|
12545
12800
|
while (true) {
|
|
12546
|
-
const binPath =
|
|
12801
|
+
const binPath = path29.join(dir, "node_modules", ".bin", cmd);
|
|
12547
12802
|
if (fs25.existsSync(binPath)) return true;
|
|
12548
|
-
const parent =
|
|
12803
|
+
const parent = path29.dirname(dir);
|
|
12549
12804
|
if (parent === dir) break;
|
|
12550
12805
|
dir = parent;
|
|
12551
12806
|
}
|
|
@@ -12592,7 +12847,115 @@ var init_agents3 = __esm({
|
|
|
12592
12847
|
}
|
|
12593
12848
|
});
|
|
12594
12849
|
|
|
12850
|
+
// src/core/plugin/settings-manager.ts
|
|
12851
|
+
var settings_manager_exports = {};
|
|
12852
|
+
__export(settings_manager_exports, {
|
|
12853
|
+
SettingsManager: () => SettingsManager
|
|
12854
|
+
});
|
|
12855
|
+
import fs26 from "fs";
|
|
12856
|
+
import path30 from "path";
|
|
12857
|
+
var SettingsManager, SettingsAPIImpl;
|
|
12858
|
+
var init_settings_manager = __esm({
|
|
12859
|
+
"src/core/plugin/settings-manager.ts"() {
|
|
12860
|
+
"use strict";
|
|
12861
|
+
SettingsManager = class {
|
|
12862
|
+
constructor(basePath) {
|
|
12863
|
+
this.basePath = basePath;
|
|
12864
|
+
}
|
|
12865
|
+
getBasePath() {
|
|
12866
|
+
return this.basePath;
|
|
12867
|
+
}
|
|
12868
|
+
createAPI(pluginName) {
|
|
12869
|
+
const settingsPath = this.getSettingsPath(pluginName);
|
|
12870
|
+
return new SettingsAPIImpl(settingsPath);
|
|
12871
|
+
}
|
|
12872
|
+
async loadSettings(pluginName) {
|
|
12873
|
+
const settingsPath = this.getSettingsPath(pluginName);
|
|
12874
|
+
try {
|
|
12875
|
+
const content = fs26.readFileSync(settingsPath, "utf-8");
|
|
12876
|
+
return JSON.parse(content);
|
|
12877
|
+
} catch {
|
|
12878
|
+
return {};
|
|
12879
|
+
}
|
|
12880
|
+
}
|
|
12881
|
+
validateSettings(_pluginName, settings, schema) {
|
|
12882
|
+
if (!schema) return { valid: true };
|
|
12883
|
+
const result = schema.safeParse(settings);
|
|
12884
|
+
if (result.success) return { valid: true };
|
|
12885
|
+
return {
|
|
12886
|
+
valid: false,
|
|
12887
|
+
errors: result.error.errors.map(
|
|
12888
|
+
(e) => `${e.path.join(".")}: ${e.message}`
|
|
12889
|
+
)
|
|
12890
|
+
};
|
|
12891
|
+
}
|
|
12892
|
+
getSettingsPath(pluginName) {
|
|
12893
|
+
return path30.join(this.basePath, pluginName, "settings.json");
|
|
12894
|
+
}
|
|
12895
|
+
async getPluginSettings(pluginName) {
|
|
12896
|
+
return this.loadSettings(pluginName);
|
|
12897
|
+
}
|
|
12898
|
+
async updatePluginSettings(pluginName, updates) {
|
|
12899
|
+
const api = this.createAPI(pluginName);
|
|
12900
|
+
const current = await api.getAll();
|
|
12901
|
+
await api.setAll({ ...current, ...updates });
|
|
12902
|
+
}
|
|
12903
|
+
};
|
|
12904
|
+
SettingsAPIImpl = class {
|
|
12905
|
+
constructor(settingsPath) {
|
|
12906
|
+
this.settingsPath = settingsPath;
|
|
12907
|
+
}
|
|
12908
|
+
cache = null;
|
|
12909
|
+
readFile() {
|
|
12910
|
+
if (this.cache !== null) return this.cache;
|
|
12911
|
+
try {
|
|
12912
|
+
const content = fs26.readFileSync(this.settingsPath, "utf-8");
|
|
12913
|
+
this.cache = JSON.parse(content);
|
|
12914
|
+
return this.cache;
|
|
12915
|
+
} catch {
|
|
12916
|
+
this.cache = {};
|
|
12917
|
+
return this.cache;
|
|
12918
|
+
}
|
|
12919
|
+
}
|
|
12920
|
+
writeFile(data) {
|
|
12921
|
+
const dir = path30.dirname(this.settingsPath);
|
|
12922
|
+
fs26.mkdirSync(dir, { recursive: true });
|
|
12923
|
+
fs26.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2));
|
|
12924
|
+
this.cache = data;
|
|
12925
|
+
}
|
|
12926
|
+
async get(key) {
|
|
12927
|
+
const data = this.readFile();
|
|
12928
|
+
return data[key];
|
|
12929
|
+
}
|
|
12930
|
+
async set(key, value) {
|
|
12931
|
+
const data = this.readFile();
|
|
12932
|
+
data[key] = value;
|
|
12933
|
+
this.writeFile(data);
|
|
12934
|
+
}
|
|
12935
|
+
async getAll() {
|
|
12936
|
+
return { ...this.readFile() };
|
|
12937
|
+
}
|
|
12938
|
+
async setAll(settings) {
|
|
12939
|
+
this.writeFile({ ...settings });
|
|
12940
|
+
}
|
|
12941
|
+
async delete(key) {
|
|
12942
|
+
const data = this.readFile();
|
|
12943
|
+
delete data[key];
|
|
12944
|
+
this.writeFile(data);
|
|
12945
|
+
}
|
|
12946
|
+
async clear() {
|
|
12947
|
+
this.writeFile({});
|
|
12948
|
+
}
|
|
12949
|
+
async has(key) {
|
|
12950
|
+
const data = this.readFile();
|
|
12951
|
+
return key in data;
|
|
12952
|
+
}
|
|
12953
|
+
};
|
|
12954
|
+
}
|
|
12955
|
+
});
|
|
12956
|
+
|
|
12595
12957
|
// src/core/doctor/checks/telegram.ts
|
|
12958
|
+
import * as path31 from "path";
|
|
12596
12959
|
var BOT_TOKEN_REGEX, telegramCheck;
|
|
12597
12960
|
var init_telegram = __esm({
|
|
12598
12961
|
"src/core/doctor/checks/telegram.ts"() {
|
|
@@ -12607,13 +12970,16 @@ var init_telegram = __esm({
|
|
|
12607
12970
|
results.push({ status: "fail", message: "Cannot check Telegram \u2014 config not loaded" });
|
|
12608
12971
|
return results;
|
|
12609
12972
|
}
|
|
12610
|
-
const
|
|
12611
|
-
|
|
12612
|
-
|
|
12973
|
+
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
12974
|
+
const sm = new SettingsManager2(path31.join(ctx.pluginsDir, "data"));
|
|
12975
|
+
const ps = await sm.loadSettings("@openacp/telegram");
|
|
12976
|
+
const legacyCh = ctx.config.channels.telegram;
|
|
12977
|
+
const botToken = ps.botToken ?? legacyCh?.botToken;
|
|
12978
|
+
const chatId = ps.chatId ?? legacyCh?.chatId;
|
|
12979
|
+
if (!botToken && !chatId) {
|
|
12980
|
+
results.push({ status: "pass", message: "Telegram not configured (skipped)" });
|
|
12613
12981
|
return results;
|
|
12614
12982
|
}
|
|
12615
|
-
const botToken = tgConfig.botToken;
|
|
12616
|
-
const chatId = tgConfig.chatId;
|
|
12617
12983
|
if (!botToken || !BOT_TOKEN_REGEX.test(botToken)) {
|
|
12618
12984
|
results.push({ status: "fail", message: "Bot token format invalid" });
|
|
12619
12985
|
return results;
|
|
@@ -12689,7 +13055,7 @@ var init_telegram = __esm({
|
|
|
12689
13055
|
});
|
|
12690
13056
|
|
|
12691
13057
|
// src/core/doctor/checks/storage.ts
|
|
12692
|
-
import * as
|
|
13058
|
+
import * as fs27 from "fs";
|
|
12693
13059
|
var storageCheck;
|
|
12694
13060
|
var init_storage = __esm({
|
|
12695
13061
|
"src/core/doctor/checks/storage.ts"() {
|
|
@@ -12699,28 +13065,28 @@ var init_storage = __esm({
|
|
|
12699
13065
|
order: 4,
|
|
12700
13066
|
async run(ctx) {
|
|
12701
13067
|
const results = [];
|
|
12702
|
-
if (!
|
|
13068
|
+
if (!fs27.existsSync(ctx.dataDir)) {
|
|
12703
13069
|
results.push({
|
|
12704
13070
|
status: "fail",
|
|
12705
13071
|
message: "Data directory ~/.openacp does not exist",
|
|
12706
13072
|
fixable: true,
|
|
12707
13073
|
fixRisk: "safe",
|
|
12708
13074
|
fix: async () => {
|
|
12709
|
-
|
|
13075
|
+
fs27.mkdirSync(ctx.dataDir, { recursive: true });
|
|
12710
13076
|
return { success: true, message: "created directory" };
|
|
12711
13077
|
}
|
|
12712
13078
|
});
|
|
12713
13079
|
} else {
|
|
12714
13080
|
try {
|
|
12715
|
-
|
|
13081
|
+
fs27.accessSync(ctx.dataDir, fs27.constants.W_OK);
|
|
12716
13082
|
results.push({ status: "pass", message: "Data directory exists and writable" });
|
|
12717
13083
|
} catch {
|
|
12718
13084
|
results.push({ status: "fail", message: "Data directory not writable" });
|
|
12719
13085
|
}
|
|
12720
13086
|
}
|
|
12721
|
-
if (
|
|
13087
|
+
if (fs27.existsSync(ctx.sessionsPath)) {
|
|
12722
13088
|
try {
|
|
12723
|
-
const content =
|
|
13089
|
+
const content = fs27.readFileSync(ctx.sessionsPath, "utf-8");
|
|
12724
13090
|
const data = JSON.parse(content);
|
|
12725
13091
|
if (typeof data === "object" && data !== null && "sessions" in data) {
|
|
12726
13092
|
results.push({ status: "pass", message: "Sessions file valid" });
|
|
@@ -12731,7 +13097,7 @@ var init_storage = __esm({
|
|
|
12731
13097
|
fixable: true,
|
|
12732
13098
|
fixRisk: "risky",
|
|
12733
13099
|
fix: async () => {
|
|
12734
|
-
|
|
13100
|
+
fs27.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));
|
|
12735
13101
|
return { success: true, message: "reset sessions file" };
|
|
12736
13102
|
}
|
|
12737
13103
|
});
|
|
@@ -12743,7 +13109,7 @@ var init_storage = __esm({
|
|
|
12743
13109
|
fixable: true,
|
|
12744
13110
|
fixRisk: "risky",
|
|
12745
13111
|
fix: async () => {
|
|
12746
|
-
|
|
13112
|
+
fs27.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));
|
|
12747
13113
|
return { success: true, message: "reset sessions file" };
|
|
12748
13114
|
}
|
|
12749
13115
|
});
|
|
@@ -12751,20 +13117,20 @@ var init_storage = __esm({
|
|
|
12751
13117
|
} else {
|
|
12752
13118
|
results.push({ status: "pass", message: "Sessions file not present yet (created on first session)" });
|
|
12753
13119
|
}
|
|
12754
|
-
if (!
|
|
13120
|
+
if (!fs27.existsSync(ctx.logsDir)) {
|
|
12755
13121
|
results.push({
|
|
12756
13122
|
status: "warn",
|
|
12757
13123
|
message: "Log directory does not exist",
|
|
12758
13124
|
fixable: true,
|
|
12759
13125
|
fixRisk: "safe",
|
|
12760
13126
|
fix: async () => {
|
|
12761
|
-
|
|
13127
|
+
fs27.mkdirSync(ctx.logsDir, { recursive: true });
|
|
12762
13128
|
return { success: true, message: "created log directory" };
|
|
12763
13129
|
}
|
|
12764
13130
|
});
|
|
12765
13131
|
} else {
|
|
12766
13132
|
try {
|
|
12767
|
-
|
|
13133
|
+
fs27.accessSync(ctx.logsDir, fs27.constants.W_OK);
|
|
12768
13134
|
results.push({ status: "pass", message: "Log directory exists and writable" });
|
|
12769
13135
|
} catch {
|
|
12770
13136
|
results.push({ status: "fail", message: "Log directory not writable" });
|
|
@@ -12777,7 +13143,7 @@ var init_storage = __esm({
|
|
|
12777
13143
|
});
|
|
12778
13144
|
|
|
12779
13145
|
// src/core/doctor/checks/workspace.ts
|
|
12780
|
-
import * as
|
|
13146
|
+
import * as fs28 from "fs";
|
|
12781
13147
|
var workspaceCheck;
|
|
12782
13148
|
var init_workspace2 = __esm({
|
|
12783
13149
|
"src/core/doctor/checks/workspace.ts"() {
|
|
@@ -12793,20 +13159,20 @@ var init_workspace2 = __esm({
|
|
|
12793
13159
|
return results;
|
|
12794
13160
|
}
|
|
12795
13161
|
const baseDir = expandHome3(ctx.config.workspace.baseDir);
|
|
12796
|
-
if (!
|
|
13162
|
+
if (!fs28.existsSync(baseDir)) {
|
|
12797
13163
|
results.push({
|
|
12798
13164
|
status: "warn",
|
|
12799
13165
|
message: `Workspace directory does not exist: ${baseDir}`,
|
|
12800
13166
|
fixable: true,
|
|
12801
13167
|
fixRisk: "safe",
|
|
12802
13168
|
fix: async () => {
|
|
12803
|
-
|
|
13169
|
+
fs28.mkdirSync(baseDir, { recursive: true });
|
|
12804
13170
|
return { success: true, message: "created directory" };
|
|
12805
13171
|
}
|
|
12806
13172
|
});
|
|
12807
13173
|
} else {
|
|
12808
13174
|
try {
|
|
12809
|
-
|
|
13175
|
+
fs28.accessSync(baseDir, fs28.constants.W_OK);
|
|
12810
13176
|
results.push({ status: "pass", message: `Workspace directory exists: ${baseDir}` });
|
|
12811
13177
|
} catch {
|
|
12812
13178
|
results.push({ status: "fail", message: `Workspace directory not writable: ${baseDir}` });
|
|
@@ -12819,10 +13185,10 @@ var init_workspace2 = __esm({
|
|
|
12819
13185
|
});
|
|
12820
13186
|
|
|
12821
13187
|
// src/core/doctor/checks/plugins.ts
|
|
12822
|
-
import * as
|
|
12823
|
-
import * as
|
|
13188
|
+
import * as fs29 from "fs";
|
|
13189
|
+
import * as path32 from "path";
|
|
12824
13190
|
var pluginsCheck;
|
|
12825
|
-
var
|
|
13191
|
+
var init_plugins2 = __esm({
|
|
12826
13192
|
"src/core/doctor/checks/plugins.ts"() {
|
|
12827
13193
|
"use strict";
|
|
12828
13194
|
pluginsCheck = {
|
|
@@ -12830,16 +13196,16 @@ var init_plugins = __esm({
|
|
|
12830
13196
|
order: 6,
|
|
12831
13197
|
async run(ctx) {
|
|
12832
13198
|
const results = [];
|
|
12833
|
-
if (!
|
|
13199
|
+
if (!fs29.existsSync(ctx.pluginsDir)) {
|
|
12834
13200
|
results.push({
|
|
12835
13201
|
status: "warn",
|
|
12836
13202
|
message: "Plugins directory does not exist",
|
|
12837
13203
|
fixable: true,
|
|
12838
13204
|
fixRisk: "safe",
|
|
12839
13205
|
fix: async () => {
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
|
|
13206
|
+
fs29.mkdirSync(ctx.pluginsDir, { recursive: true });
|
|
13207
|
+
fs29.writeFileSync(
|
|
13208
|
+
path32.join(ctx.pluginsDir, "package.json"),
|
|
12843
13209
|
JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
|
|
12844
13210
|
);
|
|
12845
13211
|
return { success: true, message: "initialized plugins directory" };
|
|
@@ -12848,15 +13214,15 @@ var init_plugins = __esm({
|
|
|
12848
13214
|
return results;
|
|
12849
13215
|
}
|
|
12850
13216
|
results.push({ status: "pass", message: "Plugins directory exists" });
|
|
12851
|
-
const pkgPath =
|
|
12852
|
-
if (!
|
|
13217
|
+
const pkgPath = path32.join(ctx.pluginsDir, "package.json");
|
|
13218
|
+
if (!fs29.existsSync(pkgPath)) {
|
|
12853
13219
|
results.push({
|
|
12854
13220
|
status: "warn",
|
|
12855
13221
|
message: "Plugins package.json missing",
|
|
12856
13222
|
fixable: true,
|
|
12857
13223
|
fixRisk: "safe",
|
|
12858
13224
|
fix: async () => {
|
|
12859
|
-
|
|
13225
|
+
fs29.writeFileSync(
|
|
12860
13226
|
pkgPath,
|
|
12861
13227
|
JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
|
|
12862
13228
|
);
|
|
@@ -12866,7 +13232,7 @@ var init_plugins = __esm({
|
|
|
12866
13232
|
return results;
|
|
12867
13233
|
}
|
|
12868
13234
|
try {
|
|
12869
|
-
const pkg = JSON.parse(
|
|
13235
|
+
const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf-8"));
|
|
12870
13236
|
const deps = pkg.dependencies || {};
|
|
12871
13237
|
const count = Object.keys(deps).length;
|
|
12872
13238
|
results.push({ status: "pass", message: `Plugins package.json valid (${count} plugins)` });
|
|
@@ -12877,7 +13243,7 @@ var init_plugins = __esm({
|
|
|
12877
13243
|
fixable: true,
|
|
12878
13244
|
fixRisk: "risky",
|
|
12879
13245
|
fix: async () => {
|
|
12880
|
-
|
|
13246
|
+
fs29.writeFileSync(
|
|
12881
13247
|
pkgPath,
|
|
12882
13248
|
JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
|
|
12883
13249
|
);
|
|
@@ -12892,7 +13258,7 @@ var init_plugins = __esm({
|
|
|
12892
13258
|
});
|
|
12893
13259
|
|
|
12894
13260
|
// src/core/doctor/checks/daemon.ts
|
|
12895
|
-
import * as
|
|
13261
|
+
import * as fs30 from "fs";
|
|
12896
13262
|
import * as net from "net";
|
|
12897
13263
|
function isProcessAlive(pid) {
|
|
12898
13264
|
try {
|
|
@@ -12922,8 +13288,8 @@ var init_daemon = __esm({
|
|
|
12922
13288
|
order: 7,
|
|
12923
13289
|
async run(ctx) {
|
|
12924
13290
|
const results = [];
|
|
12925
|
-
if (
|
|
12926
|
-
const content =
|
|
13291
|
+
if (fs30.existsSync(ctx.pidPath)) {
|
|
13292
|
+
const content = fs30.readFileSync(ctx.pidPath, "utf-8").trim();
|
|
12927
13293
|
const pid = parseInt(content, 10);
|
|
12928
13294
|
if (isNaN(pid)) {
|
|
12929
13295
|
results.push({
|
|
@@ -12932,7 +13298,7 @@ var init_daemon = __esm({
|
|
|
12932
13298
|
fixable: true,
|
|
12933
13299
|
fixRisk: "safe",
|
|
12934
13300
|
fix: async () => {
|
|
12935
|
-
|
|
13301
|
+
fs30.unlinkSync(ctx.pidPath);
|
|
12936
13302
|
return { success: true, message: "removed invalid PID file" };
|
|
12937
13303
|
}
|
|
12938
13304
|
});
|
|
@@ -12943,7 +13309,7 @@ var init_daemon = __esm({
|
|
|
12943
13309
|
fixable: true,
|
|
12944
13310
|
fixRisk: "safe",
|
|
12945
13311
|
fix: async () => {
|
|
12946
|
-
|
|
13312
|
+
fs30.unlinkSync(ctx.pidPath);
|
|
12947
13313
|
return { success: true, message: "removed stale PID file" };
|
|
12948
13314
|
}
|
|
12949
13315
|
});
|
|
@@ -12951,8 +13317,8 @@ var init_daemon = __esm({
|
|
|
12951
13317
|
results.push({ status: "pass", message: `Daemon running (PID ${pid})` });
|
|
12952
13318
|
}
|
|
12953
13319
|
}
|
|
12954
|
-
if (
|
|
12955
|
-
const content =
|
|
13320
|
+
if (fs30.existsSync(ctx.portFilePath)) {
|
|
13321
|
+
const content = fs30.readFileSync(ctx.portFilePath, "utf-8").trim();
|
|
12956
13322
|
const port = parseInt(content, 10);
|
|
12957
13323
|
if (isNaN(port)) {
|
|
12958
13324
|
results.push({
|
|
@@ -12961,7 +13327,7 @@ var init_daemon = __esm({
|
|
|
12961
13327
|
fixable: true,
|
|
12962
13328
|
fixRisk: "safe",
|
|
12963
13329
|
fix: async () => {
|
|
12964
|
-
|
|
13330
|
+
fs30.unlinkSync(ctx.portFilePath);
|
|
12965
13331
|
return { success: true, message: "removed invalid port file" };
|
|
12966
13332
|
}
|
|
12967
13333
|
});
|
|
@@ -12973,8 +13339,8 @@ var init_daemon = __esm({
|
|
|
12973
13339
|
const apiPort = ctx.config.api.port;
|
|
12974
13340
|
const inUse = await checkPortInUse(apiPort);
|
|
12975
13341
|
if (inUse) {
|
|
12976
|
-
if (
|
|
12977
|
-
const pid = parseInt(
|
|
13342
|
+
if (fs30.existsSync(ctx.pidPath)) {
|
|
13343
|
+
const pid = parseInt(fs30.readFileSync(ctx.pidPath, "utf-8").trim(), 10);
|
|
12978
13344
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
12979
13345
|
results.push({ status: "pass", message: `API port ${apiPort} in use by OpenACP daemon` });
|
|
12980
13346
|
} else {
|
|
@@ -12994,9 +13360,9 @@ var init_daemon = __esm({
|
|
|
12994
13360
|
});
|
|
12995
13361
|
|
|
12996
13362
|
// src/core/doctor/checks/tunnel.ts
|
|
12997
|
-
import * as
|
|
12998
|
-
import * as
|
|
12999
|
-
import * as
|
|
13363
|
+
import * as fs31 from "fs";
|
|
13364
|
+
import * as path33 from "path";
|
|
13365
|
+
import * as os13 from "os";
|
|
13000
13366
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
13001
13367
|
var tunnelCheck;
|
|
13002
13368
|
var init_tunnel3 = __esm({
|
|
@@ -13018,10 +13384,10 @@ var init_tunnel3 = __esm({
|
|
|
13018
13384
|
const provider = ctx.config.tunnel.provider;
|
|
13019
13385
|
results.push({ status: "pass", message: `Tunnel provider: ${provider}` });
|
|
13020
13386
|
if (provider === "cloudflare") {
|
|
13021
|
-
const binName =
|
|
13022
|
-
const binPath =
|
|
13387
|
+
const binName = os13.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
13388
|
+
const binPath = path33.join(ctx.dataDir, "bin", binName);
|
|
13023
13389
|
let found = false;
|
|
13024
|
-
if (
|
|
13390
|
+
if (fs31.existsSync(binPath)) {
|
|
13025
13391
|
found = true;
|
|
13026
13392
|
} else {
|
|
13027
13393
|
try {
|
|
@@ -13067,8 +13433,8 @@ var doctor_exports = {};
|
|
|
13067
13433
|
__export(doctor_exports, {
|
|
13068
13434
|
DoctorEngine: () => DoctorEngine
|
|
13069
13435
|
});
|
|
13070
|
-
import * as
|
|
13071
|
-
import * as
|
|
13436
|
+
import * as fs32 from "fs";
|
|
13437
|
+
import * as path34 from "path";
|
|
13072
13438
|
var ALL_CHECKS, CHECK_TIMEOUT_MS, DoctorEngine;
|
|
13073
13439
|
var init_doctor = __esm({
|
|
13074
13440
|
"src/core/doctor/index.ts"() {
|
|
@@ -13080,7 +13446,7 @@ var init_doctor = __esm({
|
|
|
13080
13446
|
init_telegram();
|
|
13081
13447
|
init_storage();
|
|
13082
13448
|
init_workspace2();
|
|
13083
|
-
|
|
13449
|
+
init_plugins2();
|
|
13084
13450
|
init_daemon();
|
|
13085
13451
|
init_tunnel3();
|
|
13086
13452
|
ALL_CHECKS = [
|
|
@@ -13150,27 +13516,27 @@ var init_doctor = __esm({
|
|
|
13150
13516
|
}
|
|
13151
13517
|
async buildContext() {
|
|
13152
13518
|
const dataDir = this.dataDir;
|
|
13153
|
-
const configPath = process.env.OPENACP_CONFIG_PATH ||
|
|
13519
|
+
const configPath = process.env.OPENACP_CONFIG_PATH || path34.join(dataDir, "config.json");
|
|
13154
13520
|
let config = null;
|
|
13155
13521
|
let rawConfig = null;
|
|
13156
13522
|
try {
|
|
13157
|
-
const content =
|
|
13523
|
+
const content = fs32.readFileSync(configPath, "utf-8");
|
|
13158
13524
|
rawConfig = JSON.parse(content);
|
|
13159
13525
|
const cm = new ConfigManager(configPath);
|
|
13160
13526
|
await cm.load();
|
|
13161
13527
|
config = cm.get();
|
|
13162
13528
|
} catch {
|
|
13163
13529
|
}
|
|
13164
|
-
const logsDir = config ? expandHome3(config.logging.logDir) :
|
|
13530
|
+
const logsDir = config ? expandHome3(config.logging.logDir) : path34.join(dataDir, "logs");
|
|
13165
13531
|
return {
|
|
13166
13532
|
config,
|
|
13167
13533
|
rawConfig,
|
|
13168
13534
|
configPath,
|
|
13169
13535
|
dataDir,
|
|
13170
|
-
sessionsPath:
|
|
13171
|
-
pidPath:
|
|
13172
|
-
portFilePath:
|
|
13173
|
-
pluginsDir:
|
|
13536
|
+
sessionsPath: path34.join(dataDir, "sessions.json"),
|
|
13537
|
+
pidPath: path34.join(dataDir, "openacp.pid"),
|
|
13538
|
+
portFilePath: path34.join(dataDir, "api.port"),
|
|
13539
|
+
pluginsDir: path34.join(dataDir, "plugins"),
|
|
13174
13540
|
logsDir
|
|
13175
13541
|
};
|
|
13176
13542
|
}
|
|
@@ -16907,113 +17273,6 @@ var init_core_plugins = __esm({
|
|
|
16907
17273
|
}
|
|
16908
17274
|
});
|
|
16909
17275
|
|
|
16910
|
-
// src/core/plugin/settings-manager.ts
|
|
16911
|
-
var settings_manager_exports = {};
|
|
16912
|
-
__export(settings_manager_exports, {
|
|
16913
|
-
SettingsManager: () => SettingsManager
|
|
16914
|
-
});
|
|
16915
|
-
import fs32 from "fs";
|
|
16916
|
-
import path32 from "path";
|
|
16917
|
-
var SettingsManager, SettingsAPIImpl;
|
|
16918
|
-
var init_settings_manager = __esm({
|
|
16919
|
-
"src/core/plugin/settings-manager.ts"() {
|
|
16920
|
-
"use strict";
|
|
16921
|
-
SettingsManager = class {
|
|
16922
|
-
constructor(basePath) {
|
|
16923
|
-
this.basePath = basePath;
|
|
16924
|
-
}
|
|
16925
|
-
getBasePath() {
|
|
16926
|
-
return this.basePath;
|
|
16927
|
-
}
|
|
16928
|
-
createAPI(pluginName) {
|
|
16929
|
-
const settingsPath = this.getSettingsPath(pluginName);
|
|
16930
|
-
return new SettingsAPIImpl(settingsPath);
|
|
16931
|
-
}
|
|
16932
|
-
async loadSettings(pluginName) {
|
|
16933
|
-
const settingsPath = this.getSettingsPath(pluginName);
|
|
16934
|
-
try {
|
|
16935
|
-
const content = fs32.readFileSync(settingsPath, "utf-8");
|
|
16936
|
-
return JSON.parse(content);
|
|
16937
|
-
} catch {
|
|
16938
|
-
return {};
|
|
16939
|
-
}
|
|
16940
|
-
}
|
|
16941
|
-
validateSettings(_pluginName, settings, schema) {
|
|
16942
|
-
if (!schema) return { valid: true };
|
|
16943
|
-
const result = schema.safeParse(settings);
|
|
16944
|
-
if (result.success) return { valid: true };
|
|
16945
|
-
return {
|
|
16946
|
-
valid: false,
|
|
16947
|
-
errors: result.error.errors.map(
|
|
16948
|
-
(e) => `${e.path.join(".")}: ${e.message}`
|
|
16949
|
-
)
|
|
16950
|
-
};
|
|
16951
|
-
}
|
|
16952
|
-
getSettingsPath(pluginName) {
|
|
16953
|
-
return path32.join(this.basePath, pluginName, "settings.json");
|
|
16954
|
-
}
|
|
16955
|
-
async getPluginSettings(pluginName) {
|
|
16956
|
-
return this.loadSettings(pluginName);
|
|
16957
|
-
}
|
|
16958
|
-
async updatePluginSettings(pluginName, updates) {
|
|
16959
|
-
const api = this.createAPI(pluginName);
|
|
16960
|
-
const current = await api.getAll();
|
|
16961
|
-
await api.setAll({ ...current, ...updates });
|
|
16962
|
-
}
|
|
16963
|
-
};
|
|
16964
|
-
SettingsAPIImpl = class {
|
|
16965
|
-
constructor(settingsPath) {
|
|
16966
|
-
this.settingsPath = settingsPath;
|
|
16967
|
-
}
|
|
16968
|
-
cache = null;
|
|
16969
|
-
readFile() {
|
|
16970
|
-
if (this.cache !== null) return this.cache;
|
|
16971
|
-
try {
|
|
16972
|
-
const content = fs32.readFileSync(this.settingsPath, "utf-8");
|
|
16973
|
-
this.cache = JSON.parse(content);
|
|
16974
|
-
return this.cache;
|
|
16975
|
-
} catch {
|
|
16976
|
-
this.cache = {};
|
|
16977
|
-
return this.cache;
|
|
16978
|
-
}
|
|
16979
|
-
}
|
|
16980
|
-
writeFile(data) {
|
|
16981
|
-
const dir = path32.dirname(this.settingsPath);
|
|
16982
|
-
fs32.mkdirSync(dir, { recursive: true });
|
|
16983
|
-
fs32.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2));
|
|
16984
|
-
this.cache = data;
|
|
16985
|
-
}
|
|
16986
|
-
async get(key) {
|
|
16987
|
-
const data = this.readFile();
|
|
16988
|
-
return data[key];
|
|
16989
|
-
}
|
|
16990
|
-
async set(key, value) {
|
|
16991
|
-
const data = this.readFile();
|
|
16992
|
-
data[key] = value;
|
|
16993
|
-
this.writeFile(data);
|
|
16994
|
-
}
|
|
16995
|
-
async getAll() {
|
|
16996
|
-
return { ...this.readFile() };
|
|
16997
|
-
}
|
|
16998
|
-
async setAll(settings) {
|
|
16999
|
-
this.writeFile({ ...settings });
|
|
17000
|
-
}
|
|
17001
|
-
async delete(key) {
|
|
17002
|
-
const data = this.readFile();
|
|
17003
|
-
delete data[key];
|
|
17004
|
-
this.writeFile(data);
|
|
17005
|
-
}
|
|
17006
|
-
async clear() {
|
|
17007
|
-
this.writeFile({});
|
|
17008
|
-
}
|
|
17009
|
-
async has(key) {
|
|
17010
|
-
const data = this.readFile();
|
|
17011
|
-
return key in data;
|
|
17012
|
-
}
|
|
17013
|
-
};
|
|
17014
|
-
}
|
|
17015
|
-
});
|
|
17016
|
-
|
|
17017
17276
|
// src/core/plugin/terminal-io.ts
|
|
17018
17277
|
import * as clack from "@clack/prompts";
|
|
17019
17278
|
function isCancel(value) {
|
|
@@ -17077,10 +17336,10 @@ var install_context_exports = {};
|
|
|
17077
17336
|
__export(install_context_exports, {
|
|
17078
17337
|
createInstallContext: () => createInstallContext
|
|
17079
17338
|
});
|
|
17080
|
-
import
|
|
17339
|
+
import path35 from "path";
|
|
17081
17340
|
function createInstallContext(opts) {
|
|
17082
17341
|
const { pluginName, settingsManager, basePath, legacyConfig, instanceRoot } = opts;
|
|
17083
|
-
const dataDir =
|
|
17342
|
+
const dataDir = path35.join(basePath, pluginName, "data");
|
|
17084
17343
|
return {
|
|
17085
17344
|
pluginName,
|
|
17086
17345
|
terminal: createTerminalIO(),
|
|
@@ -17108,13 +17367,13 @@ __export(api_client_exports, {
|
|
|
17108
17367
|
removeStalePortFile: () => removeStalePortFile
|
|
17109
17368
|
});
|
|
17110
17369
|
import * as fs33 from "fs";
|
|
17111
|
-
import * as
|
|
17112
|
-
import * as
|
|
17370
|
+
import * as path36 from "path";
|
|
17371
|
+
import * as os14 from "os";
|
|
17113
17372
|
function defaultPortFile(root) {
|
|
17114
|
-
return
|
|
17373
|
+
return path36.join(root ?? DEFAULT_ROOT, "api.port");
|
|
17115
17374
|
}
|
|
17116
17375
|
function defaultSecretFile(root) {
|
|
17117
|
-
return
|
|
17376
|
+
return path36.join(root ?? DEFAULT_ROOT, "api-secret");
|
|
17118
17377
|
}
|
|
17119
17378
|
function readApiPort(portFilePath, instanceRoot) {
|
|
17120
17379
|
const filePath = portFilePath ?? defaultPortFile(instanceRoot);
|
|
@@ -17154,7 +17413,7 @@ var DEFAULT_ROOT;
|
|
|
17154
17413
|
var init_api_client = __esm({
|
|
17155
17414
|
"src/cli/api-client.ts"() {
|
|
17156
17415
|
"use strict";
|
|
17157
|
-
DEFAULT_ROOT =
|
|
17416
|
+
DEFAULT_ROOT = path36.join(os14.homedir(), ".openacp");
|
|
17158
17417
|
}
|
|
17159
17418
|
});
|
|
17160
17419
|
|
|
@@ -17202,16 +17461,16 @@ var init_suggest = __esm({
|
|
|
17202
17461
|
|
|
17203
17462
|
// src/cli/instance-hint.ts
|
|
17204
17463
|
import fs34 from "fs";
|
|
17205
|
-
import
|
|
17206
|
-
import
|
|
17464
|
+
import path37 from "path";
|
|
17465
|
+
import os15 from "os";
|
|
17207
17466
|
function printInstanceHint(root) {
|
|
17208
17467
|
const globalRoot = getGlobalRoot();
|
|
17209
17468
|
const isGlobal = root === globalRoot;
|
|
17210
|
-
const displayPath = root.replace(
|
|
17469
|
+
const displayPath = root.replace(os15.homedir(), "~");
|
|
17211
17470
|
const label = isGlobal ? "global" : "local";
|
|
17212
17471
|
console.log(` Workspace: ${label} \u2014 ${displayPath}`);
|
|
17213
17472
|
if (isGlobal) {
|
|
17214
|
-
const localRoot =
|
|
17473
|
+
const localRoot = path37.join(process.cwd(), ".openacp");
|
|
17215
17474
|
if (fs34.existsSync(localRoot)) {
|
|
17216
17475
|
console.log(` \x1B[2mhint: local workspace exists in current directory \u2014 use --local to use it\x1B[0m`);
|
|
17217
17476
|
}
|
|
@@ -17243,22 +17502,22 @@ __export(daemon_exports, {
|
|
|
17243
17502
|
});
|
|
17244
17503
|
import { spawn as spawn6 } from "child_process";
|
|
17245
17504
|
import * as fs35 from "fs";
|
|
17246
|
-
import * as
|
|
17247
|
-
import * as
|
|
17505
|
+
import * as path38 from "path";
|
|
17506
|
+
import * as os16 from "os";
|
|
17248
17507
|
function getPidPath(root) {
|
|
17249
17508
|
const base = root ?? DEFAULT_ROOT2;
|
|
17250
|
-
return
|
|
17509
|
+
return path38.join(base, "openacp.pid");
|
|
17251
17510
|
}
|
|
17252
17511
|
function getLogDir(root) {
|
|
17253
17512
|
const base = root ?? DEFAULT_ROOT2;
|
|
17254
|
-
return
|
|
17513
|
+
return path38.join(base, "logs");
|
|
17255
17514
|
}
|
|
17256
17515
|
function getRunningMarker(root) {
|
|
17257
17516
|
const base = root ?? DEFAULT_ROOT2;
|
|
17258
|
-
return
|
|
17517
|
+
return path38.join(base, "running");
|
|
17259
17518
|
}
|
|
17260
17519
|
function writePidFile(pidPath, pid) {
|
|
17261
|
-
const dir =
|
|
17520
|
+
const dir = path38.dirname(pidPath);
|
|
17262
17521
|
fs35.mkdirSync(dir, { recursive: true });
|
|
17263
17522
|
fs35.writeFileSync(pidPath, String(pid));
|
|
17264
17523
|
}
|
|
@@ -17307,8 +17566,8 @@ function startDaemon(pidPath = getPidPath(), logDir2, instanceRoot) {
|
|
|
17307
17566
|
}
|
|
17308
17567
|
const resolvedLogDir = logDir2 ? expandHome3(logDir2) : getLogDir(instanceRoot);
|
|
17309
17568
|
fs35.mkdirSync(resolvedLogDir, { recursive: true });
|
|
17310
|
-
const logFile =
|
|
17311
|
-
const cliPath =
|
|
17569
|
+
const logFile = path38.join(resolvedLogDir, "openacp.log");
|
|
17570
|
+
const cliPath = path38.resolve(process.argv[1]);
|
|
17312
17571
|
const nodePath = process.execPath;
|
|
17313
17572
|
const out = fs35.openSync(logFile, "a");
|
|
17314
17573
|
const err = fs35.openSync(logFile, "a");
|
|
@@ -17392,7 +17651,7 @@ async function stopDaemon(pidPath = getPidPath(), instanceRoot) {
|
|
|
17392
17651
|
}
|
|
17393
17652
|
function markRunning(root) {
|
|
17394
17653
|
const marker = getRunningMarker(root);
|
|
17395
|
-
fs35.mkdirSync(
|
|
17654
|
+
fs35.mkdirSync(path38.dirname(marker), { recursive: true });
|
|
17396
17655
|
fs35.writeFileSync(marker, "");
|
|
17397
17656
|
}
|
|
17398
17657
|
function clearRunning(root) {
|
|
@@ -17409,7 +17668,7 @@ var init_daemon2 = __esm({
|
|
|
17409
17668
|
"src/cli/daemon.ts"() {
|
|
17410
17669
|
"use strict";
|
|
17411
17670
|
init_config2();
|
|
17412
|
-
DEFAULT_ROOT2 =
|
|
17671
|
+
DEFAULT_ROOT2 = path38.join(os16.homedir(), ".openacp");
|
|
17413
17672
|
}
|
|
17414
17673
|
});
|
|
17415
17674
|
|
|
@@ -17418,12 +17677,12 @@ var stop_exports = {};
|
|
|
17418
17677
|
__export(stop_exports, {
|
|
17419
17678
|
cmdStop: () => cmdStop
|
|
17420
17679
|
});
|
|
17421
|
-
import
|
|
17422
|
-
import
|
|
17680
|
+
import path40 from "path";
|
|
17681
|
+
import os18 from "os";
|
|
17423
17682
|
async function cmdStop(args2 = [], instanceRoot) {
|
|
17424
17683
|
const json = isJsonMode(args2);
|
|
17425
17684
|
if (json) await muteForJson();
|
|
17426
|
-
const root = instanceRoot ??
|
|
17685
|
+
const root = instanceRoot ?? path40.join(os18.homedir(), ".openacp");
|
|
17427
17686
|
if (!json && wantsHelp(args2)) {
|
|
17428
17687
|
console.log(`
|
|
17429
17688
|
\x1B[1mopenacp stop\x1B[0m \u2014 Stop the background daemon
|
|
@@ -17765,7 +18024,7 @@ var init_mcp_manager = __esm({
|
|
|
17765
18024
|
|
|
17766
18025
|
// src/core/utils/debug-tracer.ts
|
|
17767
18026
|
import fs37 from "fs";
|
|
17768
|
-
import
|
|
18027
|
+
import path41 from "path";
|
|
17769
18028
|
function createDebugTracer(sessionId, workingDirectory) {
|
|
17770
18029
|
if (!DEBUG_ENABLED) return null;
|
|
17771
18030
|
return new DebugTracer(sessionId, workingDirectory);
|
|
@@ -17779,7 +18038,7 @@ var init_debug_tracer = __esm({
|
|
|
17779
18038
|
constructor(sessionId, workingDirectory) {
|
|
17780
18039
|
this.sessionId = sessionId;
|
|
17781
18040
|
this.workingDirectory = workingDirectory;
|
|
17782
|
-
this.logDir =
|
|
18041
|
+
this.logDir = path41.join(workingDirectory, ".log");
|
|
17783
18042
|
}
|
|
17784
18043
|
dirCreated = false;
|
|
17785
18044
|
logDir;
|
|
@@ -17789,7 +18048,7 @@ var init_debug_tracer = __esm({
|
|
|
17789
18048
|
fs37.mkdirSync(this.logDir, { recursive: true });
|
|
17790
18049
|
this.dirCreated = true;
|
|
17791
18050
|
}
|
|
17792
|
-
const filePath =
|
|
18051
|
+
const filePath = path41.join(this.logDir, `${this.sessionId}_${layer}.jsonl`);
|
|
17793
18052
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
17794
18053
|
const line = JSON.stringify({ ts: Date.now(), ...data }, (_key, value) => {
|
|
17795
18054
|
if (typeof value === "object" && value !== null) {
|
|
@@ -17813,16 +18072,16 @@ var init_debug_tracer = __esm({
|
|
|
17813
18072
|
import { spawn as spawn8, execFileSync as execFileSync5 } from "child_process";
|
|
17814
18073
|
import { Transform } from "stream";
|
|
17815
18074
|
import fs38 from "fs";
|
|
17816
|
-
import
|
|
18075
|
+
import path42 from "path";
|
|
17817
18076
|
import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
17818
18077
|
import { PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
|
|
17819
18078
|
function findPackageRoot(startDir) {
|
|
17820
18079
|
let dir = startDir;
|
|
17821
|
-
while (dir !==
|
|
17822
|
-
if (fs38.existsSync(
|
|
18080
|
+
while (dir !== path42.dirname(dir)) {
|
|
18081
|
+
if (fs38.existsSync(path42.join(dir, "package.json"))) {
|
|
17823
18082
|
return dir;
|
|
17824
18083
|
}
|
|
17825
|
-
dir =
|
|
18084
|
+
dir = path42.dirname(dir);
|
|
17826
18085
|
}
|
|
17827
18086
|
return startDir;
|
|
17828
18087
|
}
|
|
@@ -17834,8 +18093,8 @@ function resolveAgentCommand(cmd) {
|
|
|
17834
18093
|
}
|
|
17835
18094
|
for (const root of searchRoots) {
|
|
17836
18095
|
const packageDirs = [
|
|
17837
|
-
|
|
17838
|
-
|
|
18096
|
+
path42.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
|
|
18097
|
+
path42.resolve(root, "node_modules", cmd, "dist", "index.js")
|
|
17839
18098
|
];
|
|
17840
18099
|
for (const jsPath of packageDirs) {
|
|
17841
18100
|
if (fs38.existsSync(jsPath)) {
|
|
@@ -17844,7 +18103,7 @@ function resolveAgentCommand(cmd) {
|
|
|
17844
18103
|
}
|
|
17845
18104
|
}
|
|
17846
18105
|
for (const root of searchRoots) {
|
|
17847
|
-
const localBin =
|
|
18106
|
+
const localBin = path42.resolve(root, "node_modules", ".bin", cmd);
|
|
17848
18107
|
if (fs38.existsSync(localBin)) {
|
|
17849
18108
|
const content = fs38.readFileSync(localBin, "utf-8");
|
|
17850
18109
|
if (content.startsWith("#!/usr/bin/env node")) {
|
|
@@ -17852,7 +18111,7 @@ function resolveAgentCommand(cmd) {
|
|
|
17852
18111
|
}
|
|
17853
18112
|
const match = content.match(/"([^"]+\.js)"/);
|
|
17854
18113
|
if (match) {
|
|
17855
|
-
const target =
|
|
18114
|
+
const target = path42.resolve(path42.dirname(localBin), match[1]);
|
|
17856
18115
|
if (fs38.existsSync(target)) {
|
|
17857
18116
|
return { command: process.execPath, args: [target] };
|
|
17858
18117
|
}
|
|
@@ -18253,7 +18512,7 @@ ${stderr}`
|
|
|
18253
18512
|
writePath = result.path;
|
|
18254
18513
|
writeContent = result.content;
|
|
18255
18514
|
}
|
|
18256
|
-
await fs38.promises.mkdir(
|
|
18515
|
+
await fs38.promises.mkdir(path42.dirname(writePath), { recursive: true });
|
|
18257
18516
|
await fs38.promises.writeFile(writePath, writeContent, "utf-8");
|
|
18258
18517
|
return {};
|
|
18259
18518
|
},
|
|
@@ -19865,7 +20124,7 @@ var init_message_transformer = __esm({
|
|
|
19865
20124
|
|
|
19866
20125
|
// src/core/sessions/session-store.ts
|
|
19867
20126
|
import fs40 from "fs";
|
|
19868
|
-
import
|
|
20127
|
+
import path43 from "path";
|
|
19869
20128
|
var log30, DEBOUNCE_MS2, JsonFileSessionStore;
|
|
19870
20129
|
var init_session_store = __esm({
|
|
19871
20130
|
"src/core/sessions/session-store.ts"() {
|
|
@@ -19941,7 +20200,7 @@ var init_session_store = __esm({
|
|
|
19941
20200
|
version: 1,
|
|
19942
20201
|
sessions: Object.fromEntries(this.records)
|
|
19943
20202
|
};
|
|
19944
|
-
const dir =
|
|
20203
|
+
const dir = path43.dirname(this.filePath);
|
|
19945
20204
|
if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
|
|
19946
20205
|
fs40.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
|
|
19947
20206
|
}
|
|
@@ -20516,8 +20775,8 @@ __export(agent_store_exports, {
|
|
|
20516
20775
|
AgentStore: () => AgentStore
|
|
20517
20776
|
});
|
|
20518
20777
|
import * as fs41 from "fs";
|
|
20519
|
-
import * as
|
|
20520
|
-
import * as
|
|
20778
|
+
import * as path44 from "path";
|
|
20779
|
+
import * as os19 from "os";
|
|
20521
20780
|
import { z as z7 } from "zod";
|
|
20522
20781
|
var log33, InstalledAgentSchema, AgentStoreSchema, AgentStore;
|
|
20523
20782
|
var init_agent_store = __esm({
|
|
@@ -20545,7 +20804,7 @@ var init_agent_store = __esm({
|
|
|
20545
20804
|
data = { version: 1, installed: {} };
|
|
20546
20805
|
filePath;
|
|
20547
20806
|
constructor(filePath) {
|
|
20548
|
-
this.filePath = filePath ??
|
|
20807
|
+
this.filePath = filePath ?? path44.join(os19.homedir(), ".openacp", "agents.json");
|
|
20549
20808
|
}
|
|
20550
20809
|
load() {
|
|
20551
20810
|
if (!fs41.existsSync(this.filePath)) {
|
|
@@ -20587,7 +20846,7 @@ var init_agent_store = __esm({
|
|
|
20587
20846
|
return key in this.data.installed;
|
|
20588
20847
|
}
|
|
20589
20848
|
save() {
|
|
20590
|
-
fs41.mkdirSync(
|
|
20849
|
+
fs41.mkdirSync(path44.dirname(this.filePath), { recursive: true });
|
|
20591
20850
|
const tmpPath = this.filePath + ".tmp";
|
|
20592
20851
|
fs41.writeFileSync(tmpPath, JSON.stringify(this.data, null, 2));
|
|
20593
20852
|
fs41.renameSync(tmpPath, this.filePath);
|
|
@@ -20598,8 +20857,8 @@ var init_agent_store = __esm({
|
|
|
20598
20857
|
|
|
20599
20858
|
// src/core/agents/agent-installer.ts
|
|
20600
20859
|
import * as fs42 from "fs";
|
|
20601
|
-
import * as
|
|
20602
|
-
import * as
|
|
20860
|
+
import * as path45 from "path";
|
|
20861
|
+
import * as os20 from "os";
|
|
20603
20862
|
function getPlatformKey() {
|
|
20604
20863
|
const platform2 = PLATFORM_MAP[process.platform] ?? process.platform;
|
|
20605
20864
|
const arch = ARCH_MAP[process.arch] ?? process.arch;
|
|
@@ -20650,7 +20909,7 @@ function buildInstalledAgent(registryId, name, version, dist, binaryPath) {
|
|
|
20650
20909
|
binaryPath: null
|
|
20651
20910
|
};
|
|
20652
20911
|
}
|
|
20653
|
-
const absCmd =
|
|
20912
|
+
const absCmd = path45.resolve(binaryPath, dist.cmd);
|
|
20654
20913
|
return {
|
|
20655
20914
|
registryId,
|
|
20656
20915
|
name,
|
|
@@ -20723,7 +20982,7 @@ Install it with: pip install uv`;
|
|
|
20723
20982
|
return { ok: true, agentKey, setupSteps: setup?.setupSteps };
|
|
20724
20983
|
}
|
|
20725
20984
|
async function downloadAndExtract(agentId, archiveUrl, progress, agentsDir) {
|
|
20726
|
-
const destDir =
|
|
20985
|
+
const destDir = path45.join(agentsDir ?? DEFAULT_AGENTS_DIR, agentId);
|
|
20727
20986
|
fs42.mkdirSync(destDir, { recursive: true });
|
|
20728
20987
|
await progress?.onStep("Downloading...");
|
|
20729
20988
|
log34.info({ agentId, url: archiveUrl }, "Downloading agent binary");
|
|
@@ -20767,15 +21026,15 @@ function validateExtractedPaths(destDir) {
|
|
|
20767
21026
|
for (const entry of entries) {
|
|
20768
21027
|
const dirent = entry;
|
|
20769
21028
|
const parentPath = dirent.parentPath ?? dirent.path ?? destDir;
|
|
20770
|
-
const fullPath =
|
|
21029
|
+
const fullPath = path45.join(parentPath, entry.name);
|
|
20771
21030
|
let realPath;
|
|
20772
21031
|
try {
|
|
20773
21032
|
realPath = fs42.realpathSync(fullPath);
|
|
20774
21033
|
} catch {
|
|
20775
21034
|
const linkTarget = fs42.readlinkSync(fullPath);
|
|
20776
|
-
realPath =
|
|
21035
|
+
realPath = path45.resolve(path45.dirname(fullPath), linkTarget);
|
|
20777
21036
|
}
|
|
20778
|
-
if (!realPath.startsWith(realDest +
|
|
21037
|
+
if (!realPath.startsWith(realDest + path45.sep) && realPath !== realDest) {
|
|
20779
21038
|
fs42.rmSync(destDir, { recursive: true, force: true });
|
|
20780
21039
|
throw new Error(`Archive contains unsafe path: ${entry.name}`);
|
|
20781
21040
|
}
|
|
@@ -20783,7 +21042,7 @@ function validateExtractedPaths(destDir) {
|
|
|
20783
21042
|
}
|
|
20784
21043
|
async function extractTarGz(buffer, destDir) {
|
|
20785
21044
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
20786
|
-
const tmpFile =
|
|
21045
|
+
const tmpFile = path45.join(destDir, "_archive.tar.gz");
|
|
20787
21046
|
fs42.writeFileSync(tmpFile, buffer);
|
|
20788
21047
|
try {
|
|
20789
21048
|
execFileSync8("tar", ["xzf", tmpFile, "-C", destDir], { stdio: "pipe" });
|
|
@@ -20794,7 +21053,7 @@ async function extractTarGz(buffer, destDir) {
|
|
|
20794
21053
|
}
|
|
20795
21054
|
async function extractZip(buffer, destDir) {
|
|
20796
21055
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
20797
|
-
const tmpFile =
|
|
21056
|
+
const tmpFile = path45.join(destDir, "_archive.zip");
|
|
20798
21057
|
fs42.writeFileSync(tmpFile, buffer);
|
|
20799
21058
|
try {
|
|
20800
21059
|
execFileSync8("unzip", ["-o", tmpFile, "-d", destDir], { stdio: "pipe" });
|
|
@@ -20819,7 +21078,7 @@ var init_agent_installer = __esm({
|
|
|
20819
21078
|
init_log();
|
|
20820
21079
|
init_agent_dependencies();
|
|
20821
21080
|
log34 = createChildLogger({ module: "agent-installer" });
|
|
20822
|
-
DEFAULT_AGENTS_DIR =
|
|
21081
|
+
DEFAULT_AGENTS_DIR = path45.join(os20.homedir(), ".openacp", "agents");
|
|
20823
21082
|
ARCH_MAP = {
|
|
20824
21083
|
arm64: "aarch64",
|
|
20825
21084
|
x64: "x86_64"
|
|
@@ -20838,8 +21097,8 @@ __export(agent_catalog_exports, {
|
|
|
20838
21097
|
AgentCatalog: () => AgentCatalog
|
|
20839
21098
|
});
|
|
20840
21099
|
import * as fs43 from "fs";
|
|
20841
|
-
import * as
|
|
20842
|
-
import * as
|
|
21100
|
+
import * as path46 from "path";
|
|
21101
|
+
import * as os21 from "os";
|
|
20843
21102
|
var log35, REGISTRY_URL2, DEFAULT_TTL_HOURS, AgentCatalog;
|
|
20844
21103
|
var init_agent_catalog = __esm({
|
|
20845
21104
|
"src/core/agents/agent-catalog.ts"() {
|
|
@@ -20858,7 +21117,7 @@ var init_agent_catalog = __esm({
|
|
|
20858
21117
|
agentsDir;
|
|
20859
21118
|
constructor(store, cachePath, agentsDir) {
|
|
20860
21119
|
this.store = store ?? new AgentStore();
|
|
20861
|
-
this.cachePath = cachePath ??
|
|
21120
|
+
this.cachePath = cachePath ?? path46.join(os21.homedir(), ".openacp", "registry-cache.json");
|
|
20862
21121
|
this.agentsDir = agentsDir;
|
|
20863
21122
|
}
|
|
20864
21123
|
load() {
|
|
@@ -20879,7 +21138,7 @@ var init_agent_catalog = __esm({
|
|
|
20879
21138
|
ttlHours: DEFAULT_TTL_HOURS,
|
|
20880
21139
|
data
|
|
20881
21140
|
};
|
|
20882
|
-
fs43.mkdirSync(
|
|
21141
|
+
fs43.mkdirSync(path46.dirname(this.cachePath), { recursive: true });
|
|
20883
21142
|
fs43.writeFileSync(this.cachePath, JSON.stringify(cache, null, 2));
|
|
20884
21143
|
log35.info({ count: this.registryAgents.length }, "Registry updated");
|
|
20885
21144
|
} catch (err) {
|
|
@@ -21065,9 +21324,9 @@ var init_agent_catalog = __esm({
|
|
|
21065
21324
|
}
|
|
21066
21325
|
try {
|
|
21067
21326
|
const candidates = [
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21327
|
+
path46.join(import.meta.dirname, "data", "registry-snapshot.json"),
|
|
21328
|
+
path46.join(import.meta.dirname, "..", "data", "registry-snapshot.json"),
|
|
21329
|
+
path46.join(import.meta.dirname, "..", "..", "data", "registry-snapshot.json")
|
|
21071
21330
|
];
|
|
21072
21331
|
for (const candidate of candidates) {
|
|
21073
21332
|
if (fs43.existsSync(candidate)) {
|
|
@@ -21365,7 +21624,7 @@ var init_error_tracker = __esm({
|
|
|
21365
21624
|
|
|
21366
21625
|
// src/core/plugin/plugin-storage.ts
|
|
21367
21626
|
import fs44 from "fs";
|
|
21368
|
-
import
|
|
21627
|
+
import path47 from "path";
|
|
21369
21628
|
var PluginStorageImpl;
|
|
21370
21629
|
var init_plugin_storage = __esm({
|
|
21371
21630
|
"src/core/plugin/plugin-storage.ts"() {
|
|
@@ -21375,8 +21634,8 @@ var init_plugin_storage = __esm({
|
|
|
21375
21634
|
dataDir;
|
|
21376
21635
|
writeChain = Promise.resolve();
|
|
21377
21636
|
constructor(baseDir) {
|
|
21378
|
-
this.dataDir =
|
|
21379
|
-
this.kvPath =
|
|
21637
|
+
this.dataDir = path47.join(baseDir, "data");
|
|
21638
|
+
this.kvPath = path47.join(baseDir, "kv.json");
|
|
21380
21639
|
fs44.mkdirSync(baseDir, { recursive: true });
|
|
21381
21640
|
}
|
|
21382
21641
|
readKv() {
|
|
@@ -21422,8 +21681,8 @@ var init_plugin_storage = __esm({
|
|
|
21422
21681
|
});
|
|
21423
21682
|
|
|
21424
21683
|
// src/core/plugin/plugin-context.ts
|
|
21425
|
-
import
|
|
21426
|
-
import
|
|
21684
|
+
import path48 from "path";
|
|
21685
|
+
import os22 from "os";
|
|
21427
21686
|
function requirePermission(permissions, required, action) {
|
|
21428
21687
|
if (!permissions.includes(required)) {
|
|
21429
21688
|
throw new Error(`Plugin does not have '${required}' permission required for ${action}`);
|
|
@@ -21442,7 +21701,7 @@ function createPluginContext(opts) {
|
|
|
21442
21701
|
config,
|
|
21443
21702
|
core
|
|
21444
21703
|
} = opts;
|
|
21445
|
-
const instanceRoot = opts.instanceRoot ??
|
|
21704
|
+
const instanceRoot = opts.instanceRoot ?? path48.join(os22.homedir(), ".openacp");
|
|
21446
21705
|
const registeredListeners = [];
|
|
21447
21706
|
const registeredCommands = [];
|
|
21448
21707
|
const noopLog = {
|
|
@@ -21665,7 +21924,7 @@ var init_lifecycle_manager = __esm({
|
|
|
21665
21924
|
log;
|
|
21666
21925
|
settingsManager;
|
|
21667
21926
|
pluginRegistry;
|
|
21668
|
-
|
|
21927
|
+
_instanceRoot;
|
|
21669
21928
|
contexts = /* @__PURE__ */ new Map();
|
|
21670
21929
|
loadOrder = [];
|
|
21671
21930
|
_loaded = /* @__PURE__ */ new Set();
|
|
@@ -21679,6 +21938,14 @@ var init_lifecycle_manager = __esm({
|
|
|
21679
21938
|
get registry() {
|
|
21680
21939
|
return this.pluginRegistry;
|
|
21681
21940
|
}
|
|
21941
|
+
/** Plugin definitions currently in load order (loaded + failed). */
|
|
21942
|
+
get plugins() {
|
|
21943
|
+
return [...this.loadOrder];
|
|
21944
|
+
}
|
|
21945
|
+
/** Root directory of this OpenACP instance (e.g. ~/.openacp). */
|
|
21946
|
+
get instanceRoot() {
|
|
21947
|
+
return this._instanceRoot;
|
|
21948
|
+
}
|
|
21682
21949
|
constructor(opts) {
|
|
21683
21950
|
this.serviceRegistry = opts?.serviceRegistry ?? new ServiceRegistry();
|
|
21684
21951
|
this.middlewareChain = opts?.middlewareChain ?? new MiddlewareChain();
|
|
@@ -21698,7 +21965,7 @@ var init_lifecycle_manager = __esm({
|
|
|
21698
21965
|
this.log = opts?.log;
|
|
21699
21966
|
this.settingsManager = opts?.settingsManager;
|
|
21700
21967
|
this.pluginRegistry = opts?.pluginRegistry;
|
|
21701
|
-
this.
|
|
21968
|
+
this._instanceRoot = opts?.instanceRoot;
|
|
21702
21969
|
}
|
|
21703
21970
|
getPluginLogger(pluginName) {
|
|
21704
21971
|
if (this.log && typeof this.log.child === "function") {
|
|
@@ -21809,7 +22076,7 @@ var init_lifecycle_manager = __esm({
|
|
|
21809
22076
|
config: this.config,
|
|
21810
22077
|
core: this.core,
|
|
21811
22078
|
log: this.log,
|
|
21812
|
-
instanceRoot: this.
|
|
22079
|
+
instanceRoot: this._instanceRoot
|
|
21813
22080
|
});
|
|
21814
22081
|
try {
|
|
21815
22082
|
await withTimeout(plugin2.setup(ctx), SETUP_TIMEOUT_MS, `${plugin2.name}.setup()`);
|
|
@@ -22285,8 +22552,8 @@ var init_core_items = __esm({
|
|
|
22285
22552
|
});
|
|
22286
22553
|
|
|
22287
22554
|
// src/core/core.ts
|
|
22288
|
-
import
|
|
22289
|
-
import
|
|
22555
|
+
import path49 from "path";
|
|
22556
|
+
import os23 from "os";
|
|
22290
22557
|
var log39, OpenACPCore;
|
|
22291
22558
|
var init_core = __esm({
|
|
22292
22559
|
"src/core/core.ts"() {
|
|
@@ -22354,6 +22621,9 @@ var init_core = __esm({
|
|
|
22354
22621
|
get contextManager() {
|
|
22355
22622
|
return this.getService("context");
|
|
22356
22623
|
}
|
|
22624
|
+
get settingsManager() {
|
|
22625
|
+
return this.lifecycleManager.settingsManager;
|
|
22626
|
+
}
|
|
22357
22627
|
constructor(configManager, ctx) {
|
|
22358
22628
|
this.configManager = configManager;
|
|
22359
22629
|
this.instanceContext = ctx;
|
|
@@ -22365,7 +22635,7 @@ var init_core = __esm({
|
|
|
22365
22635
|
);
|
|
22366
22636
|
this.agentCatalog.load();
|
|
22367
22637
|
this.agentManager = new AgentManager(this.agentCatalog);
|
|
22368
|
-
const storePath = ctx?.paths.sessions ??
|
|
22638
|
+
const storePath = ctx?.paths.sessions ?? path49.join(os23.homedir(), ".openacp", "sessions.json");
|
|
22369
22639
|
this.sessionStore = new JsonFileSessionStore(
|
|
22370
22640
|
storePath,
|
|
22371
22641
|
config.sessionStore.ttlDays
|
|
@@ -22389,7 +22659,7 @@ var init_core = __esm({
|
|
|
22389
22659
|
sessions: this.sessionManager,
|
|
22390
22660
|
config: this.configManager,
|
|
22391
22661
|
core: this,
|
|
22392
|
-
storagePath: ctx?.paths.pluginsData ??
|
|
22662
|
+
storagePath: ctx?.paths.pluginsData ?? path49.join(os23.homedir(), ".openacp", "plugins", "data"),
|
|
22393
22663
|
instanceRoot: ctx?.root,
|
|
22394
22664
|
log: createChildLogger({ module: "plugin" })
|
|
22395
22665
|
});
|
|
@@ -22421,22 +22691,36 @@ var init_core = __esm({
|
|
|
22421
22691
|
log39.info({ level: value }, "Log level changed at runtime");
|
|
22422
22692
|
}
|
|
22423
22693
|
if (configPath.startsWith("speech.")) {
|
|
22424
|
-
const speechSvc = this.
|
|
22694
|
+
const speechSvc = this.lifecycleManager.serviceRegistry.get("speech");
|
|
22425
22695
|
if (speechSvc) {
|
|
22426
|
-
const
|
|
22427
|
-
|
|
22428
|
-
|
|
22429
|
-
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
22696
|
+
const settingsMgr = this.settingsManager;
|
|
22697
|
+
if (settingsMgr) {
|
|
22698
|
+
const pluginCfg = await settingsMgr.loadSettings("@openacp/speech");
|
|
22699
|
+
const groqApiKey = pluginCfg.groqApiKey;
|
|
22700
|
+
const sttProviders = {};
|
|
22701
|
+
if (groqApiKey) {
|
|
22702
|
+
sttProviders.groq = { apiKey: groqApiKey };
|
|
22703
|
+
}
|
|
22704
|
+
const newSpeechConfig = {
|
|
22705
|
+
stt: {
|
|
22706
|
+
provider: groqApiKey ? "groq" : null,
|
|
22707
|
+
providers: sttProviders
|
|
22708
|
+
},
|
|
22709
|
+
tts: {
|
|
22710
|
+
provider: pluginCfg.ttsProvider ?? null,
|
|
22711
|
+
providers: {}
|
|
22712
|
+
}
|
|
22713
|
+
};
|
|
22714
|
+
speechSvc.refreshProviders(newSpeechConfig);
|
|
22715
|
+
log39.info("Speech service config updated at runtime (from plugin settings)");
|
|
22716
|
+
}
|
|
22433
22717
|
}
|
|
22434
22718
|
}
|
|
22435
22719
|
}
|
|
22436
22720
|
);
|
|
22437
22721
|
registerCoreMenuItems(this.menuRegistry);
|
|
22438
22722
|
if (ctx?.root) {
|
|
22439
|
-
this.assistantRegistry.setInstanceRoot(
|
|
22723
|
+
this.assistantRegistry.setInstanceRoot(path49.dirname(ctx.root));
|
|
22440
22724
|
}
|
|
22441
22725
|
this.assistantRegistry.register(createSessionsSection(this));
|
|
22442
22726
|
this.assistantRegistry.register(createAgentsSection(this));
|
|
@@ -22530,7 +22814,7 @@ var init_core = __esm({
|
|
|
22530
22814
|
if (!result) return;
|
|
22531
22815
|
message = result;
|
|
22532
22816
|
}
|
|
22533
|
-
const access2 = this.securityGuard.checkAccess(message);
|
|
22817
|
+
const access2 = await this.securityGuard.checkAccess(message);
|
|
22534
22818
|
if (!access2.allowed) {
|
|
22535
22819
|
log39.warn({ userId: message.userId, reason: access2.reason }, "Access denied");
|
|
22536
22820
|
if (access2.reason.includes("Session limit")) {
|
|
@@ -23762,21 +24046,25 @@ async function printStartBanner() {
|
|
|
23762
24046
|
console.log(`${c.dim} AI coding agents, anywhere. v${version}${c.reset}
|
|
23763
24047
|
`);
|
|
23764
24048
|
}
|
|
23765
|
-
function summarizeConfig(config) {
|
|
24049
|
+
async function summarizeConfig(config, settingsManager) {
|
|
23766
24050
|
const lines = [];
|
|
24051
|
+
const channelDefs = [
|
|
24052
|
+
{ id: "telegram", label: "Telegram", pluginName: "@openacp/telegram", keys: ["botToken", "chatId"] },
|
|
24053
|
+
{ id: "discord", label: "Discord", pluginName: "@openacp/adapter-discord", keys: ["guildId", "token"] }
|
|
24054
|
+
];
|
|
23767
24055
|
const channelStatuses = [];
|
|
23768
|
-
for (const
|
|
23769
|
-
|
|
23770
|
-
|
|
23771
|
-
|
|
23772
|
-
|
|
23773
|
-
|
|
23774
|
-
|
|
23775
|
-
|
|
23776
|
-
|
|
23777
|
-
|
|
23778
|
-
channelStatuses.push(`${meta} (not configured)`);
|
|
24056
|
+
for (const def of channelDefs) {
|
|
24057
|
+
const legacyCh = config.channels[def.id];
|
|
24058
|
+
let configured = !!legacyCh && Object.keys(legacyCh).length > 1;
|
|
24059
|
+
let enabled = legacyCh?.enabled === true;
|
|
24060
|
+
if (settingsManager) {
|
|
24061
|
+
const ps = await settingsManager.loadSettings(def.pluginName);
|
|
24062
|
+
if (def.keys.some((k) => ps[k])) {
|
|
24063
|
+
configured = true;
|
|
24064
|
+
enabled = ps.enabled !== false;
|
|
24065
|
+
}
|
|
23779
24066
|
}
|
|
24067
|
+
channelStatuses.push(`${def.label} (${enabled ? "enabled" : configured ? "disabled" : "not configured"})`);
|
|
23780
24068
|
}
|
|
23781
24069
|
lines.push(`Channels: ${channelStatuses.join(", ")}`);
|
|
23782
24070
|
lines.push(`Default agent: ${config.defaultAgent}`);
|
|
@@ -23853,9 +24141,8 @@ async function setupAgents() {
|
|
|
23853
24141
|
await catalog.refreshRegistryIfStale();
|
|
23854
24142
|
if (!catalog.getInstalledAgent("claude")) {
|
|
23855
24143
|
const claudeRegistry = catalog.findRegistryAgent("claude-acp");
|
|
23856
|
-
|
|
23857
|
-
|
|
23858
|
-
} else {
|
|
24144
|
+
const installed2 = claudeRegistry ? await catalog.install("claude-acp") : null;
|
|
24145
|
+
if (!installed2?.ok) {
|
|
23859
24146
|
const { AgentStore: AgentStore2 } = await Promise.resolve().then(() => (init_agent_store(), agent_store_exports));
|
|
23860
24147
|
const store = new AgentStore2();
|
|
23861
24148
|
store.load();
|
|
@@ -23993,8 +24280,8 @@ __export(autostart_exports, {
|
|
|
23993
24280
|
});
|
|
23994
24281
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
23995
24282
|
import * as fs45 from "fs";
|
|
23996
|
-
import * as
|
|
23997
|
-
import * as
|
|
24283
|
+
import * as path50 from "path";
|
|
24284
|
+
import * as os24 from "os";
|
|
23998
24285
|
function isAutoStartSupported() {
|
|
23999
24286
|
return process.platform === "darwin" || process.platform === "linux";
|
|
24000
24287
|
}
|
|
@@ -24006,7 +24293,7 @@ function escapeSystemdValue(str) {
|
|
|
24006
24293
|
return `"${escaped}"`;
|
|
24007
24294
|
}
|
|
24008
24295
|
function generateLaunchdPlist(nodePath, cliPath, logDir2) {
|
|
24009
|
-
const logFile =
|
|
24296
|
+
const logFile = path50.join(logDir2, "openacp.log");
|
|
24010
24297
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
24011
24298
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
24012
24299
|
<plist version="1.0">
|
|
@@ -24051,12 +24338,12 @@ function installAutoStart(logDir2) {
|
|
|
24051
24338
|
return { success: false, error: "Auto-start not supported on this platform" };
|
|
24052
24339
|
}
|
|
24053
24340
|
const nodePath = process.execPath;
|
|
24054
|
-
const cliPath =
|
|
24055
|
-
const resolvedLogDir = logDir2.startsWith("~") ?
|
|
24341
|
+
const cliPath = path50.resolve(process.argv[1]);
|
|
24342
|
+
const resolvedLogDir = logDir2.startsWith("~") ? path50.join(os24.homedir(), logDir2.slice(1)) : logDir2;
|
|
24056
24343
|
try {
|
|
24057
24344
|
if (process.platform === "darwin") {
|
|
24058
24345
|
const plist = generateLaunchdPlist(nodePath, cliPath, resolvedLogDir);
|
|
24059
|
-
const dir =
|
|
24346
|
+
const dir = path50.dirname(LAUNCHD_PLIST_PATH);
|
|
24060
24347
|
fs45.mkdirSync(dir, { recursive: true });
|
|
24061
24348
|
fs45.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
24062
24349
|
execFileSync7("launchctl", ["load", LAUNCHD_PLIST_PATH], { stdio: "pipe" });
|
|
@@ -24065,7 +24352,7 @@ function installAutoStart(logDir2) {
|
|
|
24065
24352
|
}
|
|
24066
24353
|
if (process.platform === "linux") {
|
|
24067
24354
|
const unit = generateSystemdUnit(nodePath, cliPath);
|
|
24068
|
-
const dir =
|
|
24355
|
+
const dir = path50.dirname(SYSTEMD_SERVICE_PATH);
|
|
24069
24356
|
fs45.mkdirSync(dir, { recursive: true });
|
|
24070
24357
|
fs45.writeFileSync(SYSTEMD_SERVICE_PATH, unit);
|
|
24071
24358
|
execFileSync7("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
|
|
@@ -24131,8 +24418,8 @@ var init_autostart = __esm({
|
|
|
24131
24418
|
init_log();
|
|
24132
24419
|
log40 = createChildLogger({ module: "autostart" });
|
|
24133
24420
|
LAUNCHD_LABEL = "com.openacp.daemon";
|
|
24134
|
-
LAUNCHD_PLIST_PATH =
|
|
24135
|
-
SYSTEMD_SERVICE_PATH =
|
|
24421
|
+
LAUNCHD_PLIST_PATH = path50.join(os24.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
24422
|
+
SYSTEMD_SERVICE_PATH = path50.join(os24.homedir(), ".config", "systemd", "user", "openacp.service");
|
|
24136
24423
|
}
|
|
24137
24424
|
});
|
|
24138
24425
|
|
|
@@ -24251,27 +24538,44 @@ var init_setup_integrations = __esm({
|
|
|
24251
24538
|
});
|
|
24252
24539
|
|
|
24253
24540
|
// src/core/setup/setup-channels.ts
|
|
24254
|
-
import * as
|
|
24541
|
+
import * as path51 from "path";
|
|
24255
24542
|
import * as clack7 from "@clack/prompts";
|
|
24256
|
-
function getChannelStatuses(config) {
|
|
24543
|
+
async function getChannelStatuses(config, settingsManager) {
|
|
24257
24544
|
const statuses = [];
|
|
24258
24545
|
for (const [id, meta] of Object.entries(CHANNEL_META)) {
|
|
24259
24546
|
const ch = config.channels[id];
|
|
24260
|
-
|
|
24261
|
-
|
|
24547
|
+
let configured = !!ch && Object.keys(ch).length > 1;
|
|
24548
|
+
let enabled = ch?.enabled === true;
|
|
24262
24549
|
let hint;
|
|
24263
|
-
if (
|
|
24264
|
-
|
|
24550
|
+
if (settingsManager && id === "telegram") {
|
|
24551
|
+
const ps = await settingsManager.loadSettings("@openacp/telegram");
|
|
24552
|
+
if (ps.botToken && ps.chatId) {
|
|
24553
|
+
configured = true;
|
|
24554
|
+
enabled = ps.enabled !== false;
|
|
24555
|
+
hint = `Chat ID: ${ps.chatId}`;
|
|
24556
|
+
}
|
|
24557
|
+
} else if (settingsManager && id === "discord") {
|
|
24558
|
+
const ps = await settingsManager.loadSettings("@openacp/adapter-discord");
|
|
24559
|
+
if (ps.guildId || ps.token) {
|
|
24560
|
+
configured = true;
|
|
24561
|
+
enabled = ps.enabled !== false;
|
|
24562
|
+
hint = ps.guildId ? `Guild: ${ps.guildId}` : void 0;
|
|
24563
|
+
}
|
|
24265
24564
|
}
|
|
24266
|
-
if (
|
|
24267
|
-
|
|
24565
|
+
if (!hint) {
|
|
24566
|
+
if (id === "telegram" && ch?.botToken && typeof ch.botToken === "string" && ch.botToken !== "YOUR_BOT_TOKEN_HERE") {
|
|
24567
|
+
hint = `Chat ID: ${ch.chatId}`;
|
|
24568
|
+
}
|
|
24569
|
+
if (id === "discord" && ch?.guildId) {
|
|
24570
|
+
hint = `Guild: ${ch.guildId}`;
|
|
24571
|
+
}
|
|
24268
24572
|
}
|
|
24269
24573
|
statuses.push({ id, label: meta.label, configured, enabled, hint });
|
|
24270
24574
|
}
|
|
24271
24575
|
return statuses;
|
|
24272
24576
|
}
|
|
24273
|
-
function noteChannelStatus(config) {
|
|
24274
|
-
const statuses = getChannelStatuses(config);
|
|
24577
|
+
async function noteChannelStatus(config, settingsManager) {
|
|
24578
|
+
const statuses = await getChannelStatuses(config, settingsManager);
|
|
24275
24579
|
const lines = statuses.map((s) => {
|
|
24276
24580
|
const status = s.enabled ? "enabled" : s.configured ? "disabled" : "not configured";
|
|
24277
24581
|
const hintStr = s.hint ? ` \u2014 ${s.hint}` : "";
|
|
@@ -24296,7 +24600,7 @@ async function promptConfiguredAction(label) {
|
|
|
24296
24600
|
})
|
|
24297
24601
|
);
|
|
24298
24602
|
}
|
|
24299
|
-
async function configureViaPlugin(channelId) {
|
|
24603
|
+
async function configureViaPlugin(channelId, settingsManager) {
|
|
24300
24604
|
const pluginMap = {
|
|
24301
24605
|
telegram: { importPath: "../../plugins/telegram/index.js", name: "@openacp/telegram" }
|
|
24302
24606
|
};
|
|
@@ -24315,24 +24619,27 @@ async function configureViaPlugin(channelId) {
|
|
|
24315
24619
|
}
|
|
24316
24620
|
}
|
|
24317
24621
|
if (plugin2?.configure) {
|
|
24318
|
-
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
24319
24622
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
24320
|
-
|
|
24321
|
-
|
|
24623
|
+
let sm = settingsManager;
|
|
24624
|
+
if (!sm) {
|
|
24625
|
+
const { SettingsManager: SM } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
24626
|
+
const basePath = path51.join(getGlobalRoot(), "plugins", "data");
|
|
24627
|
+
sm = new SM(basePath);
|
|
24628
|
+
}
|
|
24322
24629
|
const ctx = createInstallContext2({
|
|
24323
24630
|
pluginName: plugin2.name,
|
|
24324
|
-
settingsManager,
|
|
24325
|
-
basePath
|
|
24631
|
+
settingsManager: sm,
|
|
24632
|
+
basePath: sm.getBasePath()
|
|
24326
24633
|
});
|
|
24327
24634
|
await plugin2.configure(ctx);
|
|
24328
24635
|
}
|
|
24329
24636
|
}
|
|
24330
|
-
async function configureChannels(config) {
|
|
24637
|
+
async function configureChannels(config, settingsManager) {
|
|
24331
24638
|
const next = structuredClone(config);
|
|
24332
24639
|
let changed = false;
|
|
24333
|
-
noteChannelStatus(next);
|
|
24640
|
+
await noteChannelStatus(next, settingsManager);
|
|
24334
24641
|
while (true) {
|
|
24335
|
-
const statuses = getChannelStatuses(next);
|
|
24642
|
+
const statuses = await getChannelStatuses(next, settingsManager);
|
|
24336
24643
|
const options = statuses.map((s) => {
|
|
24337
24644
|
const status = s.enabled ? "enabled" : s.configured ? "disabled" : "not configured";
|
|
24338
24645
|
return {
|
|
@@ -24353,8 +24660,8 @@ async function configureChannels(config) {
|
|
|
24353
24660
|
if (choice === "__done__") break;
|
|
24354
24661
|
const channelId = choice;
|
|
24355
24662
|
const meta = CHANNEL_META[channelId];
|
|
24356
|
-
const
|
|
24357
|
-
const isConfigured =
|
|
24663
|
+
const statuses2 = await getChannelStatuses(next, settingsManager);
|
|
24664
|
+
const isConfigured = statuses2.find((s) => s.id === channelId)?.configured ?? false;
|
|
24358
24665
|
if (isConfigured) {
|
|
24359
24666
|
const action = await promptConfiguredAction(meta.label);
|
|
24360
24667
|
if (action === "skip") continue;
|
|
@@ -24379,7 +24686,7 @@ async function configureChannels(config) {
|
|
|
24379
24686
|
continue;
|
|
24380
24687
|
}
|
|
24381
24688
|
}
|
|
24382
|
-
await configureViaPlugin(channelId);
|
|
24689
|
+
await configureViaPlugin(channelId, settingsManager);
|
|
24383
24690
|
changed = true;
|
|
24384
24691
|
}
|
|
24385
24692
|
return { config: next, changed };
|
|
@@ -24399,55 +24706,70 @@ __export(instance_copy_exports, {
|
|
|
24399
24706
|
copyInstance: () => copyInstance
|
|
24400
24707
|
});
|
|
24401
24708
|
import fs46 from "fs";
|
|
24402
|
-
import
|
|
24709
|
+
import path52 from "path";
|
|
24403
24710
|
async function copyInstance(src, dst, opts) {
|
|
24404
24711
|
const { inheritableKeys = {}, onProgress } = opts;
|
|
24405
24712
|
fs46.mkdirSync(dst, { recursive: true });
|
|
24406
|
-
const configSrc =
|
|
24713
|
+
const configSrc = path52.join(src, "config.json");
|
|
24407
24714
|
if (fs46.existsSync(configSrc)) {
|
|
24408
24715
|
onProgress?.("Configuration", "start");
|
|
24409
24716
|
const config = JSON.parse(fs46.readFileSync(configSrc, "utf-8"));
|
|
24410
24717
|
delete config.instanceName;
|
|
24411
|
-
|
|
24412
|
-
|
|
24413
|
-
|
|
24718
|
+
delete config.security;
|
|
24719
|
+
delete config.tunnel;
|
|
24720
|
+
delete config.api;
|
|
24721
|
+
delete config.speech;
|
|
24722
|
+
delete config.usage;
|
|
24723
|
+
if (config.channels && typeof config.channels === "object") {
|
|
24724
|
+
const CORE_CHANNEL_KEYS = /* @__PURE__ */ new Set(["enabled", "outputMode", "adapter", "displayVerbosity"]);
|
|
24725
|
+
for (const ch of Object.values(config.channels)) {
|
|
24726
|
+
if (ch && typeof ch === "object") {
|
|
24727
|
+
for (const key of Object.keys(ch)) {
|
|
24728
|
+
if (!CORE_CHANNEL_KEYS.has(key)) {
|
|
24729
|
+
delete ch[key];
|
|
24730
|
+
}
|
|
24731
|
+
}
|
|
24732
|
+
}
|
|
24733
|
+
}
|
|
24734
|
+
}
|
|
24735
|
+
fs46.writeFileSync(path52.join(dst, "config.json"), JSON.stringify(config, null, 2));
|
|
24414
24736
|
onProgress?.("Configuration", "done");
|
|
24415
24737
|
}
|
|
24416
|
-
const pluginsSrc =
|
|
24738
|
+
const pluginsSrc = path52.join(src, "plugins.json");
|
|
24417
24739
|
if (fs46.existsSync(pluginsSrc)) {
|
|
24418
24740
|
onProgress?.("Plugin list", "start");
|
|
24419
|
-
fs46.copyFileSync(pluginsSrc,
|
|
24741
|
+
fs46.copyFileSync(pluginsSrc, path52.join(dst, "plugins.json"));
|
|
24420
24742
|
onProgress?.("Plugin list", "done");
|
|
24421
24743
|
}
|
|
24422
|
-
const pluginsDir =
|
|
24744
|
+
const pluginsDir = path52.join(src, "plugins");
|
|
24423
24745
|
if (fs46.existsSync(pluginsDir)) {
|
|
24424
24746
|
onProgress?.("Plugins", "start");
|
|
24425
|
-
const dstPlugins =
|
|
24747
|
+
const dstPlugins = path52.join(dst, "plugins");
|
|
24426
24748
|
fs46.mkdirSync(dstPlugins, { recursive: true });
|
|
24427
|
-
const pkgJson =
|
|
24428
|
-
if (fs46.existsSync(pkgJson)) fs46.copyFileSync(pkgJson,
|
|
24429
|
-
const nodeModules =
|
|
24430
|
-
if (fs46.existsSync(nodeModules)) fs46.cpSync(nodeModules,
|
|
24749
|
+
const pkgJson = path52.join(pluginsDir, "package.json");
|
|
24750
|
+
if (fs46.existsSync(pkgJson)) fs46.copyFileSync(pkgJson, path52.join(dstPlugins, "package.json"));
|
|
24751
|
+
const nodeModules = path52.join(pluginsDir, "node_modules");
|
|
24752
|
+
if (fs46.existsSync(nodeModules)) fs46.cpSync(nodeModules, path52.join(dstPlugins, "node_modules"), { recursive: true });
|
|
24431
24753
|
onProgress?.("Plugins", "done");
|
|
24432
24754
|
}
|
|
24433
|
-
const agentsJson =
|
|
24755
|
+
const agentsJson = path52.join(src, "agents.json");
|
|
24434
24756
|
if (fs46.existsSync(agentsJson)) {
|
|
24435
24757
|
onProgress?.("Agents", "start");
|
|
24436
|
-
fs46.copyFileSync(agentsJson,
|
|
24437
|
-
const agentsDir =
|
|
24438
|
-
if (fs46.existsSync(agentsDir)) fs46.cpSync(agentsDir,
|
|
24758
|
+
fs46.copyFileSync(agentsJson, path52.join(dst, "agents.json"));
|
|
24759
|
+
const agentsDir = path52.join(src, "agents");
|
|
24760
|
+
if (fs46.existsSync(agentsDir)) fs46.cpSync(agentsDir, path52.join(dst, "agents"), { recursive: true });
|
|
24439
24761
|
onProgress?.("Agents", "done");
|
|
24440
24762
|
}
|
|
24441
|
-
const binDir =
|
|
24763
|
+
const binDir = path52.join(src, "bin");
|
|
24442
24764
|
if (fs46.existsSync(binDir)) {
|
|
24443
24765
|
onProgress?.("Tools", "start");
|
|
24444
|
-
fs46.cpSync(binDir,
|
|
24766
|
+
fs46.cpSync(binDir, path52.join(dst, "bin"), { recursive: true });
|
|
24445
24767
|
onProgress?.("Tools", "done");
|
|
24446
24768
|
}
|
|
24447
|
-
const pluginDataSrc =
|
|
24769
|
+
const pluginDataSrc = path52.join(src, "plugins", "data");
|
|
24448
24770
|
if (fs46.existsSync(pluginDataSrc)) {
|
|
24449
24771
|
onProgress?.("Preferences", "start");
|
|
24450
|
-
copyPluginSettings(pluginDataSrc,
|
|
24772
|
+
copyPluginSettings(pluginDataSrc, path52.join(dst, "plugins", "data"), inheritableKeys);
|
|
24451
24773
|
onProgress?.("Preferences", "done");
|
|
24452
24774
|
}
|
|
24453
24775
|
}
|
|
@@ -24462,10 +24784,10 @@ function copyPluginSettings(srcData, dstData, inheritableKeys) {
|
|
|
24462
24784
|
if (key in settings) filtered[key] = settings[key];
|
|
24463
24785
|
}
|
|
24464
24786
|
if (Object.keys(filtered).length > 0) {
|
|
24465
|
-
const relative =
|
|
24466
|
-
const dstDir =
|
|
24787
|
+
const relative = path52.relative(srcData, path52.dirname(settingsPath));
|
|
24788
|
+
const dstDir = path52.join(dstData, relative);
|
|
24467
24789
|
fs46.mkdirSync(dstDir, { recursive: true });
|
|
24468
|
-
fs46.writeFileSync(
|
|
24790
|
+
fs46.writeFileSync(path52.join(dstDir, "settings.json"), JSON.stringify(filtered, null, 2));
|
|
24469
24791
|
}
|
|
24470
24792
|
} catch {
|
|
24471
24793
|
}
|
|
@@ -24476,15 +24798,15 @@ function walkPluginDirs(base, cb) {
|
|
|
24476
24798
|
for (const entry of fs46.readdirSync(base, { withFileTypes: true })) {
|
|
24477
24799
|
if (!entry.isDirectory()) continue;
|
|
24478
24800
|
if (entry.name.startsWith("@")) {
|
|
24479
|
-
const scopeDir =
|
|
24801
|
+
const scopeDir = path52.join(base, entry.name);
|
|
24480
24802
|
for (const sub of fs46.readdirSync(scopeDir, { withFileTypes: true })) {
|
|
24481
24803
|
if (!sub.isDirectory()) continue;
|
|
24482
24804
|
const pluginName = `${entry.name}/${sub.name}`;
|
|
24483
|
-
const settingsPath =
|
|
24805
|
+
const settingsPath = path52.join(scopeDir, sub.name, "settings.json");
|
|
24484
24806
|
if (fs46.existsSync(settingsPath)) cb(pluginName, settingsPath);
|
|
24485
24807
|
}
|
|
24486
24808
|
} else {
|
|
24487
|
-
const settingsPath =
|
|
24809
|
+
const settingsPath = path52.join(base, entry.name, "settings.json");
|
|
24488
24810
|
if (fs46.existsSync(settingsPath)) cb(entry.name, settingsPath);
|
|
24489
24811
|
}
|
|
24490
24812
|
}
|
|
@@ -24497,14 +24819,14 @@ var init_instance_copy = __esm({
|
|
|
24497
24819
|
|
|
24498
24820
|
// src/core/setup/git-protect.ts
|
|
24499
24821
|
import fs47 from "fs";
|
|
24500
|
-
import
|
|
24822
|
+
import path53 from "path";
|
|
24501
24823
|
function protectLocalInstance(projectDir) {
|
|
24502
24824
|
ensureGitignore(projectDir);
|
|
24503
24825
|
ensureClaudeMd(projectDir);
|
|
24504
24826
|
printSecurityWarning();
|
|
24505
24827
|
}
|
|
24506
24828
|
function ensureGitignore(projectDir) {
|
|
24507
|
-
const gitignorePath =
|
|
24829
|
+
const gitignorePath = path53.join(projectDir, ".gitignore");
|
|
24508
24830
|
const entry = ".openacp";
|
|
24509
24831
|
if (fs47.existsSync(gitignorePath)) {
|
|
24510
24832
|
const content = fs47.readFileSync(gitignorePath, "utf-8");
|
|
@@ -24524,7 +24846,7 @@ ${entry}
|
|
|
24524
24846
|
}
|
|
24525
24847
|
}
|
|
24526
24848
|
function ensureClaudeMd(projectDir) {
|
|
24527
|
-
const claudeMdPath =
|
|
24849
|
+
const claudeMdPath = path53.join(projectDir, "CLAUDE.md");
|
|
24528
24850
|
const marker = "## Local OpenACP Workspace";
|
|
24529
24851
|
if (fs47.existsSync(claudeMdPath)) {
|
|
24530
24852
|
const content = fs47.readFileSync(claudeMdPath, "utf-8");
|
|
@@ -24567,9 +24889,9 @@ var init_git_protect = __esm({
|
|
|
24567
24889
|
});
|
|
24568
24890
|
|
|
24569
24891
|
// src/core/setup/wizard.ts
|
|
24570
|
-
import * as
|
|
24892
|
+
import * as path54 from "path";
|
|
24571
24893
|
import * as fs48 from "fs";
|
|
24572
|
-
import * as
|
|
24894
|
+
import * as os25 from "os";
|
|
24573
24895
|
import * as clack8 from "@clack/prompts";
|
|
24574
24896
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
24575
24897
|
async function fetchCommunityAdapters() {
|
|
@@ -24591,7 +24913,7 @@ function checkDesktopAppInstalled() {
|
|
|
24591
24913
|
const platform2 = process.platform;
|
|
24592
24914
|
if (platform2 === "darwin") {
|
|
24593
24915
|
candidates.push("/Applications/OpenACP.app");
|
|
24594
|
-
candidates.push(`${
|
|
24916
|
+
candidates.push(`${os25.homedir()}/Applications/OpenACP.app`);
|
|
24595
24917
|
} else if (platform2 === "win32") {
|
|
24596
24918
|
const localAppData = process.env["LOCALAPPDATA"] ?? "";
|
|
24597
24919
|
candidates.push(`${localAppData}\\Programs\\OpenACP\\OpenACP.exe`);
|
|
@@ -24599,7 +24921,7 @@ function checkDesktopAppInstalled() {
|
|
|
24599
24921
|
} else {
|
|
24600
24922
|
candidates.push("/usr/bin/openacp-desktop");
|
|
24601
24923
|
candidates.push("/usr/local/bin/openacp-desktop");
|
|
24602
|
-
candidates.push(`${
|
|
24924
|
+
candidates.push(`${os25.homedir()}/.local/bin/openacp-desktop`);
|
|
24603
24925
|
}
|
|
24604
24926
|
return candidates.some((p2) => fs48.existsSync(p2));
|
|
24605
24927
|
}
|
|
@@ -24616,8 +24938,8 @@ async function runSetup(configManager, opts) {
|
|
|
24616
24938
|
const isGlobal = instanceRoot === getGlobalRoot();
|
|
24617
24939
|
let instanceName = opts?.instanceName;
|
|
24618
24940
|
if (!instanceName) {
|
|
24619
|
-
const defaultName = isGlobal ? "Global workspace" :
|
|
24620
|
-
const locationHint = isGlobal ? "global (~/.openacp)" : `local (${instanceRoot.replace(/\/.openacp$/, "").replace(
|
|
24941
|
+
const defaultName = isGlobal ? "Global workspace" : path54.basename(path54.dirname(instanceRoot));
|
|
24942
|
+
const locationHint = isGlobal ? "global (~/.openacp)" : `local (${instanceRoot.replace(/\/.openacp$/, "").replace(os25.homedir(), "~")})`;
|
|
24621
24943
|
const nameResult = await clack8.text({
|
|
24622
24944
|
message: `Name for this workspace (${locationHint})`,
|
|
24623
24945
|
initialValue: defaultName,
|
|
@@ -24627,13 +24949,13 @@ async function runSetup(configManager, opts) {
|
|
|
24627
24949
|
instanceName = nameResult.trim();
|
|
24628
24950
|
}
|
|
24629
24951
|
const globalRoot = getGlobalRoot();
|
|
24630
|
-
const registryPath =
|
|
24952
|
+
const registryPath = path54.join(globalRoot, "instances.json");
|
|
24631
24953
|
const instanceRegistry = new InstanceRegistry(registryPath);
|
|
24632
24954
|
await instanceRegistry.load();
|
|
24633
24955
|
let didCopy = false;
|
|
24634
24956
|
if (opts?.from) {
|
|
24635
|
-
const fromRoot =
|
|
24636
|
-
if (fs48.existsSync(
|
|
24957
|
+
const fromRoot = path54.join(opts.from, ".openacp");
|
|
24958
|
+
if (fs48.existsSync(path54.join(fromRoot, "config.json"))) {
|
|
24637
24959
|
const inheritableMap = buildInheritableKeysMap();
|
|
24638
24960
|
await copyInstance(fromRoot, instanceRoot, { inheritableKeys: inheritableMap });
|
|
24639
24961
|
didCopy = true;
|
|
@@ -24644,7 +24966,7 @@ async function runSetup(configManager, opts) {
|
|
|
24644
24966
|
}
|
|
24645
24967
|
if (!didCopy) {
|
|
24646
24968
|
const existingInstances = instanceRegistry.list().filter(
|
|
24647
|
-
(e) => fs48.existsSync(
|
|
24969
|
+
(e) => fs48.existsSync(path54.join(e.root, "config.json")) && e.root !== instanceRoot
|
|
24648
24970
|
);
|
|
24649
24971
|
if (existingInstances.length > 0) {
|
|
24650
24972
|
let singleLabel;
|
|
@@ -24652,12 +24974,12 @@ async function runSetup(configManager, opts) {
|
|
|
24652
24974
|
const e = existingInstances[0];
|
|
24653
24975
|
let name = e.id;
|
|
24654
24976
|
try {
|
|
24655
|
-
const cfg = JSON.parse(fs48.readFileSync(
|
|
24977
|
+
const cfg = JSON.parse(fs48.readFileSync(path54.join(e.root, "config.json"), "utf-8"));
|
|
24656
24978
|
if (cfg.instanceName) name = cfg.instanceName;
|
|
24657
24979
|
} catch {
|
|
24658
24980
|
}
|
|
24659
24981
|
const isGlobalEntry = e.root === getGlobalRoot();
|
|
24660
|
-
const displayPath = e.root.replace(
|
|
24982
|
+
const displayPath = e.root.replace(os25.homedir(), "~");
|
|
24661
24983
|
const type = isGlobalEntry ? "global" : "local";
|
|
24662
24984
|
singleLabel = `${name} workspace (${type} \u2014 ${displayPath})`;
|
|
24663
24985
|
}
|
|
@@ -24677,12 +24999,12 @@ async function runSetup(configManager, opts) {
|
|
|
24677
24999
|
options: existingInstances.map((e) => {
|
|
24678
25000
|
let name = e.id;
|
|
24679
25001
|
try {
|
|
24680
|
-
const cfg = JSON.parse(fs48.readFileSync(
|
|
25002
|
+
const cfg = JSON.parse(fs48.readFileSync(path54.join(e.root, "config.json"), "utf-8"));
|
|
24681
25003
|
if (cfg.instanceName) name = cfg.instanceName;
|
|
24682
25004
|
} catch {
|
|
24683
25005
|
}
|
|
24684
25006
|
const isGlobalEntry = e.root === getGlobalRoot();
|
|
24685
|
-
const displayPath = e.root.replace(
|
|
25007
|
+
const displayPath = e.root.replace(os25.homedir(), "~");
|
|
24686
25008
|
const type = isGlobalEntry ? "global" : "local";
|
|
24687
25009
|
return { value: e.root, label: `${name} workspace (${type} \u2014 ${displayPath})` };
|
|
24688
25010
|
})
|
|
@@ -24774,9 +25096,9 @@ async function runSetup(configManager, opts) {
|
|
|
24774
25096
|
if (channelId.startsWith("official:")) {
|
|
24775
25097
|
const npmPackage = channelId.slice("official:".length);
|
|
24776
25098
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
24777
|
-
const pluginsDir =
|
|
24778
|
-
const nodeModulesDir =
|
|
24779
|
-
const installedPath =
|
|
25099
|
+
const pluginsDir = path54.join(instanceRoot, "plugins");
|
|
25100
|
+
const nodeModulesDir = path54.join(pluginsDir, "node_modules");
|
|
25101
|
+
const installedPath = path54.join(nodeModulesDir, npmPackage);
|
|
24780
25102
|
if (!fs48.existsSync(installedPath)) {
|
|
24781
25103
|
try {
|
|
24782
25104
|
clack8.log.step(`Installing ${npmPackage}...`);
|
|
@@ -24790,9 +25112,9 @@ async function runSetup(configManager, opts) {
|
|
|
24790
25112
|
}
|
|
24791
25113
|
}
|
|
24792
25114
|
try {
|
|
24793
|
-
const installedPkgPath =
|
|
25115
|
+
const installedPkgPath = path54.join(nodeModulesDir, npmPackage, "package.json");
|
|
24794
25116
|
const installedPkg = JSON.parse(fs48.readFileSync(installedPkgPath, "utf-8"));
|
|
24795
|
-
const pluginModule = await import(
|
|
25117
|
+
const pluginModule = await import(path54.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
|
|
24796
25118
|
const plugin2 = pluginModule.default;
|
|
24797
25119
|
if (plugin2?.install) {
|
|
24798
25120
|
const installCtx = createInstallContext2({
|
|
@@ -24822,8 +25144,8 @@ async function runSetup(configManager, opts) {
|
|
|
24822
25144
|
if (channelId.startsWith("community:")) {
|
|
24823
25145
|
const npmPackage = channelId.slice("community:".length);
|
|
24824
25146
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
24825
|
-
const pluginsDir =
|
|
24826
|
-
const nodeModulesDir =
|
|
25147
|
+
const pluginsDir = path54.join(instanceRoot, "plugins");
|
|
25148
|
+
const nodeModulesDir = path54.join(pluginsDir, "node_modules");
|
|
24827
25149
|
try {
|
|
24828
25150
|
execFileSync8("npm", ["install", npmPackage, "--prefix", pluginsDir, "--save"], {
|
|
24829
25151
|
stdio: "inherit",
|
|
@@ -24835,9 +25157,9 @@ async function runSetup(configManager, opts) {
|
|
|
24835
25157
|
}
|
|
24836
25158
|
try {
|
|
24837
25159
|
const { readFileSync: readFileSync19 } = await import("fs");
|
|
24838
|
-
const installedPkgPath =
|
|
25160
|
+
const installedPkgPath = path54.join(nodeModulesDir, npmPackage, "package.json");
|
|
24839
25161
|
const installedPkg = JSON.parse(readFileSync19(installedPkgPath, "utf-8"));
|
|
24840
|
-
const pluginModule = await import(
|
|
25162
|
+
const pluginModule = await import(path54.join(nodeModulesDir, npmPackage, installedPkg.main ?? "dist/index.js"));
|
|
24841
25163
|
const plugin2 = pluginModule.default;
|
|
24842
25164
|
if (plugin2?.install) {
|
|
24843
25165
|
const installCtx = createInstallContext2({
|
|
@@ -24892,7 +25214,7 @@ async function runSetup(configManager, opts) {
|
|
|
24892
25214
|
security,
|
|
24893
25215
|
logging: {
|
|
24894
25216
|
level: "info",
|
|
24895
|
-
logDir:
|
|
25217
|
+
logDir: path54.join(instanceRoot, "logs"),
|
|
24896
25218
|
maxFileSize: "10m",
|
|
24897
25219
|
maxFiles: 7,
|
|
24898
25220
|
sessionLogRetentionDays: 30
|
|
@@ -24944,9 +25266,9 @@ async function runSetup(configManager, opts) {
|
|
|
24944
25266
|
instanceRegistry.register(id, instanceRoot);
|
|
24945
25267
|
await instanceRegistry.save();
|
|
24946
25268
|
}
|
|
24947
|
-
const isLocal = instanceRoot !==
|
|
25269
|
+
const isLocal = instanceRoot !== path54.join(getGlobalRoot());
|
|
24948
25270
|
if (isLocal) {
|
|
24949
|
-
const projectDir =
|
|
25271
|
+
const projectDir = path54.dirname(instanceRoot);
|
|
24950
25272
|
protectLocalInstance(projectDir);
|
|
24951
25273
|
}
|
|
24952
25274
|
clack8.outro(`Config saved to ${configManager.getConfigPath()}`);
|
|
@@ -25010,20 +25332,20 @@ async function selectSection(hasSelection) {
|
|
|
25010
25332
|
})
|
|
25011
25333
|
);
|
|
25012
25334
|
}
|
|
25013
|
-
async function runReconfigure(configManager) {
|
|
25335
|
+
async function runReconfigure(configManager, settingsManager) {
|
|
25014
25336
|
await printStartBanner();
|
|
25015
25337
|
clack8.intro("OpenACP \u2014 Reconfigure");
|
|
25016
25338
|
try {
|
|
25017
25339
|
await configManager.load();
|
|
25018
25340
|
let config = configManager.get();
|
|
25019
|
-
clack8.note(summarizeConfig(config), "Current configuration");
|
|
25341
|
+
clack8.note(await summarizeConfig(config, settingsManager), "Current configuration");
|
|
25020
25342
|
let ranSection = false;
|
|
25021
25343
|
while (true) {
|
|
25022
25344
|
const choice = await selectSection(ranSection);
|
|
25023
25345
|
if (choice === "__continue") break;
|
|
25024
25346
|
ranSection = true;
|
|
25025
25347
|
if (choice === "channels") {
|
|
25026
|
-
const result = await configureChannels(config);
|
|
25348
|
+
const result = await configureChannels(config, settingsManager);
|
|
25027
25349
|
if (result.changed) {
|
|
25028
25350
|
config = { ...config, channels: result.config.channels };
|
|
25029
25351
|
await configManager.writeNew(config);
|
|
@@ -25234,7 +25556,7 @@ __export(dev_loader_exports, {
|
|
|
25234
25556
|
DevPluginLoader: () => DevPluginLoader
|
|
25235
25557
|
});
|
|
25236
25558
|
import fs49 from "fs";
|
|
25237
|
-
import
|
|
25559
|
+
import path55 from "path";
|
|
25238
25560
|
var loadCounter, DevPluginLoader;
|
|
25239
25561
|
var init_dev_loader = __esm({
|
|
25240
25562
|
"src/core/plugin/dev-loader.ts"() {
|
|
@@ -25243,11 +25565,11 @@ var init_dev_loader = __esm({
|
|
|
25243
25565
|
DevPluginLoader = class {
|
|
25244
25566
|
pluginPath;
|
|
25245
25567
|
constructor(pluginPath) {
|
|
25246
|
-
this.pluginPath =
|
|
25568
|
+
this.pluginPath = path55.resolve(pluginPath);
|
|
25247
25569
|
}
|
|
25248
25570
|
async load() {
|
|
25249
|
-
const distIndex =
|
|
25250
|
-
const srcIndex =
|
|
25571
|
+
const distIndex = path55.join(this.pluginPath, "dist", "index.js");
|
|
25572
|
+
const srcIndex = path55.join(this.pluginPath, "src", "index.ts");
|
|
25251
25573
|
if (!fs49.existsSync(distIndex) && !fs49.existsSync(srcIndex)) {
|
|
25252
25574
|
throw new Error(`Plugin not found at ${this.pluginPath}. Expected dist/index.js or src/index.ts`);
|
|
25253
25575
|
}
|
|
@@ -25266,7 +25588,7 @@ var init_dev_loader = __esm({
|
|
|
25266
25588
|
return this.pluginPath;
|
|
25267
25589
|
}
|
|
25268
25590
|
getDistPath() {
|
|
25269
|
-
return
|
|
25591
|
+
return path55.join(this.pluginPath, "dist");
|
|
25270
25592
|
}
|
|
25271
25593
|
};
|
|
25272
25594
|
}
|
|
@@ -25278,13 +25600,13 @@ __export(main_exports, {
|
|
|
25278
25600
|
RESTART_EXIT_CODE: () => RESTART_EXIT_CODE,
|
|
25279
25601
|
startServer: () => startServer
|
|
25280
25602
|
});
|
|
25281
|
-
import
|
|
25603
|
+
import path56 from "path";
|
|
25282
25604
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
25283
25605
|
import fs50 from "fs";
|
|
25284
25606
|
async function startServer(opts) {
|
|
25285
25607
|
const globalRoot = getGlobalRoot();
|
|
25286
25608
|
if (!opts?.instanceContext) {
|
|
25287
|
-
const reg = new InstanceRegistry(
|
|
25609
|
+
const reg = new InstanceRegistry(path56.join(globalRoot, "instances.json"));
|
|
25288
25610
|
reg.load();
|
|
25289
25611
|
const entry = reg.getByRoot(globalRoot);
|
|
25290
25612
|
opts = { ...opts, instanceContext: createInstanceContext({ id: entry?.id ?? randomUUID3(), root: globalRoot, isGlobal: true }) };
|
|
@@ -25325,6 +25647,7 @@ async function startServer(opts) {
|
|
|
25325
25647
|
const config = configManager.get();
|
|
25326
25648
|
initLogger(config.logging);
|
|
25327
25649
|
log.debug({ configPath: configManager.getConfigPath() }, "Config loaded");
|
|
25650
|
+
await configManager.applyEnvToPluginSettings(settingsManager);
|
|
25328
25651
|
if (pluginRegistry.list().size === 0) {
|
|
25329
25652
|
await autoRegisterBuiltinPlugins(settingsManager, pluginRegistry, configManager);
|
|
25330
25653
|
}
|
|
@@ -25368,22 +25691,22 @@ async function startServer(opts) {
|
|
|
25368
25691
|
try {
|
|
25369
25692
|
let modulePath;
|
|
25370
25693
|
if (name.startsWith("/") || name.startsWith(".")) {
|
|
25371
|
-
const resolved =
|
|
25372
|
-
const pkgPath =
|
|
25694
|
+
const resolved = path56.resolve(name);
|
|
25695
|
+
const pkgPath = path56.join(resolved, "package.json");
|
|
25373
25696
|
const pkg = JSON.parse(await fs50.promises.readFile(pkgPath, "utf-8"));
|
|
25374
|
-
modulePath =
|
|
25697
|
+
modulePath = path56.join(resolved, pkg.main || "dist/index.js");
|
|
25375
25698
|
} else {
|
|
25376
|
-
const nodeModulesDir =
|
|
25377
|
-
let pkgDir =
|
|
25378
|
-
if (!fs50.existsSync(
|
|
25699
|
+
const nodeModulesDir = path56.join(ctx.paths.plugins, "node_modules");
|
|
25700
|
+
let pkgDir = path56.join(nodeModulesDir, name);
|
|
25701
|
+
if (!fs50.existsSync(path56.join(pkgDir, "package.json"))) {
|
|
25379
25702
|
let found = false;
|
|
25380
25703
|
const scopes = fs50.existsSync(nodeModulesDir) ? fs50.readdirSync(nodeModulesDir).filter((d) => d.startsWith("@")) : [];
|
|
25381
25704
|
for (const scope of scopes) {
|
|
25382
|
-
const scopeDir =
|
|
25705
|
+
const scopeDir = path56.join(nodeModulesDir, scope);
|
|
25383
25706
|
const pkgs = fs50.readdirSync(scopeDir);
|
|
25384
25707
|
for (const pkg2 of pkgs) {
|
|
25385
|
-
const candidateDir =
|
|
25386
|
-
const candidatePkgPath =
|
|
25708
|
+
const candidateDir = path56.join(scopeDir, pkg2);
|
|
25709
|
+
const candidatePkgPath = path56.join(candidateDir, "package.json");
|
|
25387
25710
|
if (fs50.existsSync(candidatePkgPath)) {
|
|
25388
25711
|
try {
|
|
25389
25712
|
const candidatePkg = JSON.parse(fs50.readFileSync(candidatePkgPath, "utf-8"));
|
|
@@ -25400,9 +25723,9 @@ async function startServer(opts) {
|
|
|
25400
25723
|
if (found) break;
|
|
25401
25724
|
}
|
|
25402
25725
|
}
|
|
25403
|
-
const pkgJsonPath =
|
|
25726
|
+
const pkgJsonPath = path56.join(pkgDir, "package.json");
|
|
25404
25727
|
const pkg = JSON.parse(await fs50.promises.readFile(pkgJsonPath, "utf-8"));
|
|
25405
|
-
modulePath =
|
|
25728
|
+
modulePath = path56.join(pkgDir, pkg.main || "dist/index.js");
|
|
25406
25729
|
}
|
|
25407
25730
|
log.debug({ plugin: name, modulePath }, "Loading community plugin");
|
|
25408
25731
|
const mod = await import(modulePath);
|
|
@@ -25565,7 +25888,7 @@ async function startServer(opts) {
|
|
|
25565
25888
|
await core.start();
|
|
25566
25889
|
try {
|
|
25567
25890
|
const globalRoot2 = getGlobalRoot();
|
|
25568
|
-
const registryPath =
|
|
25891
|
+
const registryPath = path56.join(globalRoot2, "instances.json");
|
|
25569
25892
|
const instanceReg = new InstanceRegistry(registryPath);
|
|
25570
25893
|
await instanceReg.load();
|
|
25571
25894
|
if (!instanceReg.getByRoot(ctx.root)) {
|
|
@@ -25728,13 +26051,13 @@ var restart_exports = {};
|
|
|
25728
26051
|
__export(restart_exports, {
|
|
25729
26052
|
cmdRestart: () => cmdRestart
|
|
25730
26053
|
});
|
|
25731
|
-
import
|
|
25732
|
-
import
|
|
26054
|
+
import path57 from "path";
|
|
26055
|
+
import os26 from "os";
|
|
25733
26056
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
25734
26057
|
async function cmdRestart(args2 = [], instanceRoot) {
|
|
25735
26058
|
const json = isJsonMode(args2);
|
|
25736
26059
|
if (json) await muteForJson();
|
|
25737
|
-
const root = instanceRoot ??
|
|
26060
|
+
const root = instanceRoot ?? path57.join(os26.homedir(), ".openacp");
|
|
25738
26061
|
if (!json && wantsHelp(args2)) {
|
|
25739
26062
|
console.log(`
|
|
25740
26063
|
\x1B[1mopenacp restart\x1B[0m \u2014 Restart the background daemon
|
|
@@ -25782,7 +26105,7 @@ Stops the running daemon (if any) and starts a new one.
|
|
|
25782
26105
|
printInstanceHint(root);
|
|
25783
26106
|
console.log("Starting in foreground mode...");
|
|
25784
26107
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
25785
|
-
const reg = new InstanceRegistry(
|
|
26108
|
+
const reg = new InstanceRegistry(path57.join(getGlobalRoot(), "instances.json"));
|
|
25786
26109
|
reg.load();
|
|
25787
26110
|
const existingEntry = reg.getByRoot(root);
|
|
25788
26111
|
const ctx = createInstanceContext({
|
|
@@ -25798,7 +26121,7 @@ Stops the running daemon (if any) and starts a new one.
|
|
|
25798
26121
|
console.error(result.error);
|
|
25799
26122
|
process.exit(1);
|
|
25800
26123
|
}
|
|
25801
|
-
if (json) jsonSuccess({ pid: result.pid, instanceId:
|
|
26124
|
+
if (json) jsonSuccess({ pid: result.pid, instanceId: path57.basename(root), dir: root });
|
|
25802
26125
|
printInstanceHint(root);
|
|
25803
26126
|
console.log(`OpenACP daemon started (PID ${result.pid})`);
|
|
25804
26127
|
}
|
|
@@ -25822,8 +26145,8 @@ __export(status_exports, {
|
|
|
25822
26145
|
readInstanceInfo: () => readInstanceInfo
|
|
25823
26146
|
});
|
|
25824
26147
|
import fs51 from "fs";
|
|
25825
|
-
import
|
|
25826
|
-
import
|
|
26148
|
+
import path58 from "path";
|
|
26149
|
+
import os27 from "os";
|
|
25827
26150
|
async function cmdStatus(args2 = [], instanceRoot) {
|
|
25828
26151
|
const json = isJsonMode(args2);
|
|
25829
26152
|
if (json) await muteForJson();
|
|
@@ -25840,7 +26163,7 @@ async function cmdStatus(args2 = [], instanceRoot) {
|
|
|
25840
26163
|
await showSingleInstance(root, json);
|
|
25841
26164
|
}
|
|
25842
26165
|
async function showAllInstances(json = false) {
|
|
25843
|
-
const registryPath =
|
|
26166
|
+
const registryPath = path58.join(getGlobalRoot(), "instances.json");
|
|
25844
26167
|
const registry = new InstanceRegistry(registryPath);
|
|
25845
26168
|
await registry.load();
|
|
25846
26169
|
const instances = registry.list();
|
|
@@ -25875,7 +26198,7 @@ async function showAllInstances(json = false) {
|
|
|
25875
26198
|
const mode = info.pid ? info.runMode === "daemon" ? "daemon" : "fg" : "\u2014";
|
|
25876
26199
|
const api = info.apiPort ? String(info.apiPort) : "\u2014";
|
|
25877
26200
|
const tunnel = info.tunnelPort ? String(info.tunnelPort) : "\u2014";
|
|
25878
|
-
const dir = entry.root.replace(/\/.openacp$/, "").replace(
|
|
26201
|
+
const dir = entry.root.replace(/\/.openacp$/, "").replace(os27.homedir(), "~");
|
|
25879
26202
|
const channels = info.channels.join(", ") || "\u2014";
|
|
25880
26203
|
const name = info.name ?? entry.id;
|
|
25881
26204
|
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}`);
|
|
@@ -25883,7 +26206,7 @@ async function showAllInstances(json = false) {
|
|
|
25883
26206
|
console.log("");
|
|
25884
26207
|
}
|
|
25885
26208
|
async function showInstanceById(id, json = false) {
|
|
25886
|
-
const registryPath =
|
|
26209
|
+
const registryPath = path58.join(getGlobalRoot(), "instances.json");
|
|
25887
26210
|
const registry = new InstanceRegistry(registryPath);
|
|
25888
26211
|
await registry.load();
|
|
25889
26212
|
const entry = registry.get(id);
|
|
@@ -25898,7 +26221,7 @@ async function showSingleInstance(root, json = false) {
|
|
|
25898
26221
|
const info = readInstanceInfo(root);
|
|
25899
26222
|
if (json) {
|
|
25900
26223
|
jsonSuccess({
|
|
25901
|
-
id:
|
|
26224
|
+
id: path58.basename(root),
|
|
25902
26225
|
name: info.name,
|
|
25903
26226
|
status: info.pid ? "online" : "offline",
|
|
25904
26227
|
pid: info.pid,
|
|
@@ -25929,13 +26252,13 @@ function readInstanceInfo(root) {
|
|
|
25929
26252
|
channels: []
|
|
25930
26253
|
};
|
|
25931
26254
|
try {
|
|
25932
|
-
const config = JSON.parse(fs51.readFileSync(
|
|
26255
|
+
const config = JSON.parse(fs51.readFileSync(path58.join(root, "config.json"), "utf-8"));
|
|
25933
26256
|
result.name = config.instanceName ?? null;
|
|
25934
26257
|
result.runMode = config.runMode ?? null;
|
|
25935
26258
|
} catch {
|
|
25936
26259
|
}
|
|
25937
26260
|
try {
|
|
25938
|
-
const pid = parseInt(fs51.readFileSync(
|
|
26261
|
+
const pid = parseInt(fs51.readFileSync(path58.join(root, "openacp.pid"), "utf-8").trim());
|
|
25939
26262
|
if (!isNaN(pid)) {
|
|
25940
26263
|
process.kill(pid, 0);
|
|
25941
26264
|
result.pid = pid;
|
|
@@ -25943,19 +26266,19 @@ function readInstanceInfo(root) {
|
|
|
25943
26266
|
} catch {
|
|
25944
26267
|
}
|
|
25945
26268
|
try {
|
|
25946
|
-
const port = parseInt(fs51.readFileSync(
|
|
26269
|
+
const port = parseInt(fs51.readFileSync(path58.join(root, "api.port"), "utf-8").trim());
|
|
25947
26270
|
if (!isNaN(port)) result.apiPort = port;
|
|
25948
26271
|
} catch {
|
|
25949
26272
|
}
|
|
25950
26273
|
try {
|
|
25951
|
-
const tunnels = JSON.parse(fs51.readFileSync(
|
|
26274
|
+
const tunnels = JSON.parse(fs51.readFileSync(path58.join(root, "tunnels.json"), "utf-8"));
|
|
25952
26275
|
const entries = Object.values(tunnels);
|
|
25953
26276
|
const systemEntry = entries.find((t) => t.type === "system");
|
|
25954
26277
|
if (systemEntry?.port) result.tunnelPort = systemEntry.port;
|
|
25955
26278
|
} catch {
|
|
25956
26279
|
}
|
|
25957
26280
|
try {
|
|
25958
|
-
const plugins = JSON.parse(fs51.readFileSync(
|
|
26281
|
+
const plugins = JSON.parse(fs51.readFileSync(path58.join(root, "plugins.json"), "utf-8"));
|
|
25959
26282
|
const adapters = ["@openacp/telegram", "@openacp/discord", "@openacp/slack"];
|
|
25960
26283
|
for (const name of adapters) {
|
|
25961
26284
|
if (plugins.installed?.[name] && plugins.installed[name].enabled !== false) {
|
|
@@ -25970,7 +26293,7 @@ function formatInstanceStatus(root) {
|
|
|
25970
26293
|
const info = readInstanceInfo(root);
|
|
25971
26294
|
if (!info.pid) return null;
|
|
25972
26295
|
const isGlobal = root === getGlobalRoot();
|
|
25973
|
-
const displayPath = root.replace(
|
|
26296
|
+
const displayPath = root.replace(os27.homedir(), "~");
|
|
25974
26297
|
const label = isGlobal ? "global" : "local";
|
|
25975
26298
|
const lines = [];
|
|
25976
26299
|
lines.push(` PID: ${info.pid}`);
|
|
@@ -26039,7 +26362,7 @@ var config_editor_exports = {};
|
|
|
26039
26362
|
__export(config_editor_exports, {
|
|
26040
26363
|
runConfigEditor: () => runConfigEditor
|
|
26041
26364
|
});
|
|
26042
|
-
import * as
|
|
26365
|
+
import * as path59 from "path";
|
|
26043
26366
|
import * as clack9 from "@clack/prompts";
|
|
26044
26367
|
async function select8(opts) {
|
|
26045
26368
|
const result = await clack9.select({
|
|
@@ -26070,11 +26393,19 @@ async function input(opts) {
|
|
|
26070
26393
|
}
|
|
26071
26394
|
return result;
|
|
26072
26395
|
}
|
|
26073
|
-
async function editTelegram(config, updates) {
|
|
26396
|
+
async function editTelegram(config, updates, settingsManager) {
|
|
26074
26397
|
const tg = config.channels?.telegram ?? {};
|
|
26075
|
-
|
|
26076
|
-
|
|
26077
|
-
|
|
26398
|
+
let currentToken = tg.botToken ?? "";
|
|
26399
|
+
let currentChatId = tg.chatId ?? 0;
|
|
26400
|
+
let currentEnabled = tg.enabled ?? false;
|
|
26401
|
+
if (settingsManager) {
|
|
26402
|
+
const ps = await settingsManager.loadSettings("@openacp/telegram");
|
|
26403
|
+
if (Object.keys(ps).length > 0) {
|
|
26404
|
+
currentToken = ps.botToken ?? currentToken;
|
|
26405
|
+
currentChatId = ps.chatId ?? currentChatId;
|
|
26406
|
+
currentEnabled = ps.enabled ?? currentEnabled;
|
|
26407
|
+
}
|
|
26408
|
+
}
|
|
26078
26409
|
console.log(header("Telegram"));
|
|
26079
26410
|
console.log(` Enabled : ${currentEnabled ? ok2("yes") : dim2("no")}`);
|
|
26080
26411
|
const tokenDisplay = currentToken.length > 12 ? currentToken.slice(0, 6) + "..." + currentToken.slice(-6) : currentToken || dim2("(not set)");
|
|
@@ -26089,7 +26420,11 @@ async function editTelegram(config, updates) {
|
|
|
26089
26420
|
return updates.channels.telegram;
|
|
26090
26421
|
};
|
|
26091
26422
|
while (true) {
|
|
26092
|
-
const isEnabled = (() => {
|
|
26423
|
+
const isEnabled = await (async () => {
|
|
26424
|
+
if (settingsManager) {
|
|
26425
|
+
const ps = await settingsManager.loadSettings("@openacp/telegram");
|
|
26426
|
+
if ("enabled" in ps) return ps.enabled;
|
|
26427
|
+
}
|
|
26093
26428
|
const ch = updates.channels;
|
|
26094
26429
|
const tgUp = ch?.telegram;
|
|
26095
26430
|
if (tgUp && "enabled" in tgUp) return tgUp.enabled;
|
|
@@ -26106,8 +26441,12 @@ async function editTelegram(config, updates) {
|
|
|
26106
26441
|
});
|
|
26107
26442
|
if (choice === "back") break;
|
|
26108
26443
|
if (choice === "toggle") {
|
|
26109
|
-
|
|
26110
|
-
|
|
26444
|
+
if (settingsManager) {
|
|
26445
|
+
await settingsManager.updatePluginSettings("@openacp/telegram", { enabled: !isEnabled });
|
|
26446
|
+
} else {
|
|
26447
|
+
const tgUp = ensureTelegramUpdates();
|
|
26448
|
+
tgUp.enabled = !isEnabled;
|
|
26449
|
+
}
|
|
26111
26450
|
console.log(!isEnabled ? ok2("Telegram enabled") : ok2("Telegram disabled"));
|
|
26112
26451
|
}
|
|
26113
26452
|
if (choice === "token") {
|
|
@@ -26127,9 +26466,13 @@ async function editTelegram(config, updates) {
|
|
|
26127
26466
|
} catch {
|
|
26128
26467
|
console.log(warn2("Telegram validator not available \u2014 skipping validation"));
|
|
26129
26468
|
}
|
|
26130
|
-
|
|
26131
|
-
|
|
26132
|
-
|
|
26469
|
+
if (settingsManager) {
|
|
26470
|
+
await settingsManager.updatePluginSettings("@openacp/telegram", { botToken: token.trim(), enabled: true });
|
|
26471
|
+
} else {
|
|
26472
|
+
const tgUp = ensureTelegramUpdates();
|
|
26473
|
+
tgUp.botToken = token.trim();
|
|
26474
|
+
tgUp.enabled = true;
|
|
26475
|
+
}
|
|
26133
26476
|
}
|
|
26134
26477
|
if (choice === "chatid") {
|
|
26135
26478
|
const chatIdStr = await input({
|
|
@@ -26144,8 +26487,8 @@ async function editTelegram(config, updates) {
|
|
|
26144
26487
|
const chatId = Number(chatIdStr.trim());
|
|
26145
26488
|
const tokenForValidation = (() => {
|
|
26146
26489
|
const ch = updates.channels;
|
|
26147
|
-
const
|
|
26148
|
-
if (typeof
|
|
26490
|
+
const tgUp = ch?.telegram;
|
|
26491
|
+
if (typeof tgUp?.botToken === "string") return tgUp.botToken;
|
|
26149
26492
|
return currentToken;
|
|
26150
26493
|
})();
|
|
26151
26494
|
try {
|
|
@@ -26159,8 +26502,12 @@ async function editTelegram(config, updates) {
|
|
|
26159
26502
|
} catch {
|
|
26160
26503
|
console.log(warn2("Telegram validator not available \u2014 skipping validation"));
|
|
26161
26504
|
}
|
|
26162
|
-
|
|
26163
|
-
|
|
26505
|
+
if (settingsManager) {
|
|
26506
|
+
await settingsManager.updatePluginSettings("@openacp/telegram", { chatId });
|
|
26507
|
+
} else {
|
|
26508
|
+
const tgUp = ensureTelegramUpdates();
|
|
26509
|
+
tgUp.chatId = chatId;
|
|
26510
|
+
}
|
|
26164
26511
|
}
|
|
26165
26512
|
}
|
|
26166
26513
|
}
|
|
@@ -26200,7 +26547,7 @@ async function editDiscord(_config, _updates) {
|
|
|
26200
26547
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
26201
26548
|
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
26202
26549
|
const root = getGlobalRoot2();
|
|
26203
|
-
const basePath =
|
|
26550
|
+
const basePath = path59.join(root, "plugins", "data");
|
|
26204
26551
|
const settingsManager = new SettingsManager2(basePath);
|
|
26205
26552
|
const ctx = createInstallContext2({
|
|
26206
26553
|
pluginName: plugin2.name,
|
|
@@ -26213,12 +26560,18 @@ async function editDiscord(_config, _updates) {
|
|
|
26213
26560
|
console.log(warn2("This plugin does not have a configure() method yet."));
|
|
26214
26561
|
}
|
|
26215
26562
|
}
|
|
26216
|
-
async function editChannels(config, updates) {
|
|
26217
|
-
|
|
26218
|
-
|
|
26563
|
+
async function editChannels(config, updates, settingsManager) {
|
|
26564
|
+
let tgConfigured = !!config.channels?.telegram;
|
|
26565
|
+
let dcConfigured = !!config.channels?.discord;
|
|
26566
|
+
if (settingsManager) {
|
|
26567
|
+
const tgPs = await settingsManager.loadSettings("@openacp/telegram");
|
|
26568
|
+
if (tgPs.botToken && tgPs.chatId) tgConfigured = true;
|
|
26569
|
+
const dcPs = await settingsManager.loadSettings("@openacp/adapter-discord");
|
|
26570
|
+
if (dcPs.guildId || dcPs.token) dcConfigured = true;
|
|
26571
|
+
}
|
|
26219
26572
|
console.log(header("Channels"));
|
|
26220
|
-
console.log(` Telegram : ${
|
|
26221
|
-
console.log(` Discord : ${
|
|
26573
|
+
console.log(` Telegram : ${tgConfigured ? ok2("configured") : dim2("not configured")}`);
|
|
26574
|
+
console.log(` Discord : ${dcConfigured ? ok2("configured") : dim2("not configured")}`);
|
|
26222
26575
|
console.log("");
|
|
26223
26576
|
while (true) {
|
|
26224
26577
|
const choice = await select8({
|
|
@@ -26230,7 +26583,7 @@ async function editChannels(config, updates) {
|
|
|
26230
26583
|
]
|
|
26231
26584
|
});
|
|
26232
26585
|
if (choice === "back") break;
|
|
26233
|
-
if (choice === "telegram") await editTelegram(config, updates);
|
|
26586
|
+
if (choice === "telegram") await editTelegram(config, updates, settingsManager);
|
|
26234
26587
|
if (choice === "discord") await editDiscord(config, updates);
|
|
26235
26588
|
}
|
|
26236
26589
|
}
|
|
@@ -26277,8 +26630,18 @@ async function editWorkspace(config, updates) {
|
|
|
26277
26630
|
updates.workspace = { baseDir: newDir.trim() };
|
|
26278
26631
|
console.log(ok2(`Workspace set to ${newDir.trim()}`));
|
|
26279
26632
|
}
|
|
26280
|
-
async function editSecurity(config, updates) {
|
|
26281
|
-
|
|
26633
|
+
async function editSecurity(config, updates, settingsManager) {
|
|
26634
|
+
let sec = config.security ?? { allowedUserIds: [], maxConcurrentSessions: 20, sessionTimeoutMinutes: 60 };
|
|
26635
|
+
if (settingsManager) {
|
|
26636
|
+
const ps = await settingsManager.loadSettings("@openacp/security");
|
|
26637
|
+
if (Object.keys(ps).length > 0) {
|
|
26638
|
+
sec = {
|
|
26639
|
+
allowedUserIds: ps.allowedUserIds ?? sec.allowedUserIds,
|
|
26640
|
+
maxConcurrentSessions: ps.maxConcurrentSessions ?? sec.maxConcurrentSessions,
|
|
26641
|
+
sessionTimeoutMinutes: ps.sessionTimeoutMinutes ?? sec.sessionTimeoutMinutes
|
|
26642
|
+
};
|
|
26643
|
+
}
|
|
26644
|
+
}
|
|
26282
26645
|
console.log(header("Security"));
|
|
26283
26646
|
console.log(` Allowed user IDs : ${sec.allowedUserIds?.length ? sec.allowedUserIds.join(", ") : dim2("(all users allowed)")}`);
|
|
26284
26647
|
console.log(` Max concurrent sessions : ${sec.maxConcurrentSessions}`);
|
|
@@ -26304,8 +26667,12 @@ async function editSecurity(config, updates) {
|
|
|
26304
26667
|
return true;
|
|
26305
26668
|
}
|
|
26306
26669
|
});
|
|
26307
|
-
if (
|
|
26308
|
-
|
|
26670
|
+
if (settingsManager) {
|
|
26671
|
+
await settingsManager.updatePluginSettings("@openacp/security", { maxConcurrentSessions: Number(val.trim()) });
|
|
26672
|
+
} else {
|
|
26673
|
+
if (!updates.security) updates.security = {};
|
|
26674
|
+
updates.security.maxConcurrentSessions = Number(val.trim());
|
|
26675
|
+
}
|
|
26309
26676
|
console.log(ok2(`Max concurrent sessions set to ${val.trim()}`));
|
|
26310
26677
|
}
|
|
26311
26678
|
if (choice === "timeout") {
|
|
@@ -26318,8 +26685,12 @@ async function editSecurity(config, updates) {
|
|
|
26318
26685
|
return true;
|
|
26319
26686
|
}
|
|
26320
26687
|
});
|
|
26321
|
-
if (
|
|
26322
|
-
|
|
26688
|
+
if (settingsManager) {
|
|
26689
|
+
await settingsManager.updatePluginSettings("@openacp/security", { sessionTimeoutMinutes: Number(val.trim()) });
|
|
26690
|
+
} else {
|
|
26691
|
+
if (!updates.security) updates.security = {};
|
|
26692
|
+
updates.security.sessionTimeoutMinutes = Number(val.trim());
|
|
26693
|
+
}
|
|
26323
26694
|
console.log(ok2(`Session timeout set to ${val.trim()} minutes`));
|
|
26324
26695
|
}
|
|
26325
26696
|
}
|
|
@@ -26444,8 +26815,14 @@ async function editRunMode(config, updates) {
|
|
|
26444
26815
|
}
|
|
26445
26816
|
}
|
|
26446
26817
|
}
|
|
26447
|
-
async function editApi(config, updates) {
|
|
26448
|
-
|
|
26818
|
+
async function editApi(config, updates, settingsManager) {
|
|
26819
|
+
let api = config.api ?? { port: 21420, host: "127.0.0.1" };
|
|
26820
|
+
if (settingsManager) {
|
|
26821
|
+
const ps = await settingsManager.loadSettings("@openacp/api-server");
|
|
26822
|
+
if (Object.keys(ps).length > 0) {
|
|
26823
|
+
api = { port: ps.port ?? api.port, host: ps.host ?? api.host };
|
|
26824
|
+
}
|
|
26825
|
+
}
|
|
26449
26826
|
console.log(header("API"));
|
|
26450
26827
|
console.log(` Port : ${api.port}`);
|
|
26451
26828
|
console.log(` Host : ${api.host} ${dim2("(localhost only)")}`);
|
|
@@ -26459,11 +26836,21 @@ async function editApi(config, updates) {
|
|
|
26459
26836
|
return true;
|
|
26460
26837
|
}
|
|
26461
26838
|
});
|
|
26462
|
-
|
|
26839
|
+
if (settingsManager) {
|
|
26840
|
+
await settingsManager.updatePluginSettings("@openacp/api-server", { port: Number(newPort.trim()) });
|
|
26841
|
+
} else {
|
|
26842
|
+
updates.api = { port: Number(newPort.trim()) };
|
|
26843
|
+
}
|
|
26463
26844
|
console.log(ok2(`API port set to ${newPort.trim()}`));
|
|
26464
26845
|
}
|
|
26465
|
-
async function editTunnel(config, updates) {
|
|
26466
|
-
|
|
26846
|
+
async function editTunnel(config, updates, settingsManager) {
|
|
26847
|
+
let tunnel = config.tunnel ?? { enabled: false, port: 3100, provider: "cloudflare", options: {}, storeTtlMinutes: 60, auth: { enabled: false } };
|
|
26848
|
+
if (settingsManager) {
|
|
26849
|
+
const ps = await settingsManager.loadSettings("@openacp/tunnel");
|
|
26850
|
+
if (Object.keys(ps).length > 0) {
|
|
26851
|
+
tunnel = { ...tunnel, ...ps };
|
|
26852
|
+
}
|
|
26853
|
+
}
|
|
26467
26854
|
const currentUpdates = updates.tunnel ?? {};
|
|
26468
26855
|
const getVal = (key, fallback) => key in currentUpdates ? currentUpdates[key] : tunnel[key] ?? fallback;
|
|
26469
26856
|
console.log(header("Tunnel"));
|
|
@@ -26490,6 +26877,9 @@ async function editTunnel(config, updates) {
|
|
|
26490
26877
|
const tun = updates.tunnel;
|
|
26491
26878
|
if (choice === "toggle") {
|
|
26492
26879
|
const current = getVal("enabled", false);
|
|
26880
|
+
if (settingsManager) {
|
|
26881
|
+
await settingsManager.updatePluginSettings("@openacp/tunnel", { enabled: !current });
|
|
26882
|
+
}
|
|
26493
26883
|
tun.enabled = !current;
|
|
26494
26884
|
console.log(!current ? ok2("Tunnel enabled") : ok2("Tunnel disabled"));
|
|
26495
26885
|
}
|
|
@@ -26503,6 +26893,9 @@ async function editTunnel(config, updates) {
|
|
|
26503
26893
|
{ name: "Tailscale Funnel", value: "tailscale" }
|
|
26504
26894
|
]
|
|
26505
26895
|
});
|
|
26896
|
+
if (settingsManager) {
|
|
26897
|
+
await settingsManager.updatePluginSettings("@openacp/tunnel", { provider, options: {} });
|
|
26898
|
+
}
|
|
26506
26899
|
tun.provider = provider;
|
|
26507
26900
|
tun.options = {};
|
|
26508
26901
|
console.log(ok2(`Provider set to ${provider}`));
|
|
@@ -26517,6 +26910,9 @@ async function editTunnel(config, updates) {
|
|
|
26517
26910
|
return true;
|
|
26518
26911
|
}
|
|
26519
26912
|
});
|
|
26913
|
+
if (settingsManager) {
|
|
26914
|
+
await settingsManager.updatePluginSettings("@openacp/tunnel", { port: Number(val.trim()) });
|
|
26915
|
+
}
|
|
26520
26916
|
tun.port = Number(val.trim());
|
|
26521
26917
|
console.log(ok2(`Tunnel port set to ${val.trim()}`));
|
|
26522
26918
|
}
|
|
@@ -26524,11 +26920,17 @@ async function editTunnel(config, updates) {
|
|
|
26524
26920
|
const provider = getVal("provider", "cloudflare");
|
|
26525
26921
|
const currentOptions = getVal("options", {});
|
|
26526
26922
|
await editProviderOptions(provider, currentOptions, tun);
|
|
26923
|
+
if (settingsManager) {
|
|
26924
|
+
await settingsManager.updatePluginSettings("@openacp/tunnel", { options: tun.options });
|
|
26925
|
+
}
|
|
26527
26926
|
}
|
|
26528
26927
|
if (choice === "auth") {
|
|
26529
26928
|
const currentAuth = getVal("auth", { enabled: false });
|
|
26530
26929
|
if (currentAuth.enabled) {
|
|
26531
26930
|
tun.auth = { enabled: false };
|
|
26931
|
+
if (settingsManager) {
|
|
26932
|
+
await settingsManager.updatePluginSettings("@openacp/tunnel", { auth: { enabled: false } });
|
|
26933
|
+
}
|
|
26532
26934
|
console.log(ok2("Tunnel auth disabled"));
|
|
26533
26935
|
} else {
|
|
26534
26936
|
const token = await input({
|
|
@@ -26536,6 +26938,9 @@ async function editTunnel(config, updates) {
|
|
|
26536
26938
|
default: ""
|
|
26537
26939
|
});
|
|
26538
26940
|
tun.auth = token.trim() ? { enabled: true, token: token.trim() } : { enabled: true };
|
|
26941
|
+
if (settingsManager) {
|
|
26942
|
+
await settingsManager.updatePluginSettings("@openacp/tunnel", { auth: tun.auth });
|
|
26943
|
+
}
|
|
26539
26944
|
console.log(ok2("Tunnel auth enabled"));
|
|
26540
26945
|
}
|
|
26541
26946
|
}
|
|
@@ -26601,7 +27006,7 @@ async function editProviderOptions(provider, currentOptions, tun) {
|
|
|
26601
27006
|
console.log(dim2(`No configurable options for provider "${provider}"`));
|
|
26602
27007
|
}
|
|
26603
27008
|
}
|
|
26604
|
-
async function runConfigEditor(configManager, mode = "file", apiPort) {
|
|
27009
|
+
async function runConfigEditor(configManager, mode = "file", apiPort, settingsManager) {
|
|
26605
27010
|
await configManager.load();
|
|
26606
27011
|
const config = configManager.get();
|
|
26607
27012
|
const updates = {};
|
|
@@ -26636,14 +27041,14 @@ ${c2.cyan}${c2.bold}OpenACP Config Editor${c2.reset}`);
|
|
|
26636
27041
|
break;
|
|
26637
27042
|
}
|
|
26638
27043
|
const sectionUpdates = {};
|
|
26639
|
-
if (choice === "channels") await editChannels(config, sectionUpdates);
|
|
27044
|
+
if (choice === "channels") await editChannels(config, sectionUpdates, settingsManager);
|
|
26640
27045
|
else if (choice === "agent") await editAgent(config, sectionUpdates);
|
|
26641
27046
|
else if (choice === "workspace") await editWorkspace(config, sectionUpdates);
|
|
26642
|
-
else if (choice === "security") await editSecurity(config, sectionUpdates);
|
|
27047
|
+
else if (choice === "security") await editSecurity(config, sectionUpdates, settingsManager);
|
|
26643
27048
|
else if (choice === "logging") await editLogging(config, sectionUpdates);
|
|
26644
27049
|
else if (choice === "runMode") await editRunMode(config, sectionUpdates);
|
|
26645
|
-
else if (choice === "api") await editApi(config, sectionUpdates);
|
|
26646
|
-
else if (choice === "tunnel") await editTunnel(config, sectionUpdates);
|
|
27050
|
+
else if (choice === "api") await editApi(config, sectionUpdates, settingsManager);
|
|
27051
|
+
else if (choice === "tunnel") await editTunnel(config, sectionUpdates, settingsManager);
|
|
26647
27052
|
if (mode === "api" && Object.keys(sectionUpdates).length > 0) {
|
|
26648
27053
|
await sendConfigViaApi(apiPort, sectionUpdates);
|
|
26649
27054
|
await configManager.load();
|
|
@@ -26663,17 +27068,17 @@ ${c2.cyan}${c2.bold}OpenACP Config Editor${c2.reset}`);
|
|
|
26663
27068
|
async function sendConfigViaApi(port, updates) {
|
|
26664
27069
|
const { apiCall: call } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
26665
27070
|
const paths = flattenToPaths(updates);
|
|
26666
|
-
for (const { path:
|
|
27071
|
+
for (const { path: path69, value } of paths) {
|
|
26667
27072
|
const res = await call(port, "/api/config", {
|
|
26668
27073
|
method: "PATCH",
|
|
26669
27074
|
headers: { "Content-Type": "application/json" },
|
|
26670
|
-
body: JSON.stringify({ path:
|
|
27075
|
+
body: JSON.stringify({ path: path69, value })
|
|
26671
27076
|
});
|
|
26672
27077
|
const data = await res.json();
|
|
26673
27078
|
if (!res.ok) {
|
|
26674
|
-
console.log(warn2(`Failed to update ${
|
|
27079
|
+
console.log(warn2(`Failed to update ${path69}: ${data.error}`));
|
|
26675
27080
|
} else if (data.needsRestart) {
|
|
26676
|
-
console.log(warn2(`${
|
|
27081
|
+
console.log(warn2(`${path69} updated \u2014 restart required`));
|
|
26677
27082
|
}
|
|
26678
27083
|
}
|
|
26679
27084
|
}
|
|
@@ -26782,35 +27187,35 @@ __export(instance_prompt_exports, {
|
|
|
26782
27187
|
promptForInstance: () => promptForInstance
|
|
26783
27188
|
});
|
|
26784
27189
|
import fs56 from "fs";
|
|
26785
|
-
import
|
|
26786
|
-
import
|
|
27190
|
+
import path67 from "path";
|
|
27191
|
+
import os32 from "os";
|
|
26787
27192
|
async function promptForInstance(opts) {
|
|
26788
27193
|
const globalRoot = getGlobalRoot();
|
|
26789
|
-
const globalConfigExists = fs56.existsSync(
|
|
27194
|
+
const globalConfigExists = fs56.existsSync(path67.join(globalRoot, "config.json"));
|
|
26790
27195
|
const cwd = process.cwd();
|
|
26791
|
-
const localRoot =
|
|
27196
|
+
const localRoot = path67.join(cwd, ".openacp");
|
|
26792
27197
|
if (!globalConfigExists) return globalRoot;
|
|
26793
27198
|
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
26794
27199
|
if (!isTTY) return globalRoot;
|
|
26795
|
-
const registryPath =
|
|
27200
|
+
const registryPath = path67.join(globalRoot, "instances.json");
|
|
26796
27201
|
const registry = new InstanceRegistry(registryPath);
|
|
26797
27202
|
registry.load();
|
|
26798
27203
|
const instances = registry.list().filter((e) => fs56.existsSync(e.root));
|
|
26799
27204
|
const instanceOptions = instances.map((e) => {
|
|
26800
27205
|
let name = e.id;
|
|
26801
27206
|
try {
|
|
26802
|
-
const raw = fs56.readFileSync(
|
|
27207
|
+
const raw = fs56.readFileSync(path67.join(e.root, "config.json"), "utf-8");
|
|
26803
27208
|
const parsed = JSON.parse(raw);
|
|
26804
27209
|
if (parsed.instanceName) name = parsed.instanceName;
|
|
26805
27210
|
} catch {
|
|
26806
27211
|
}
|
|
26807
27212
|
const isGlobal = e.root === globalRoot;
|
|
26808
|
-
const displayPath = e.root.replace(
|
|
27213
|
+
const displayPath = e.root.replace(os32.homedir(), "~");
|
|
26809
27214
|
const type = isGlobal ? "global" : "local";
|
|
26810
27215
|
return { value: e.root, label: `${name} workspace (${type} \u2014 ${displayPath})` };
|
|
26811
27216
|
});
|
|
26812
27217
|
if (instanceOptions.length === 0) {
|
|
26813
|
-
const globalDisplay = globalRoot.replace(
|
|
27218
|
+
const globalDisplay = globalRoot.replace(os32.homedir(), "~");
|
|
26814
27219
|
instanceOptions.push({ value: globalRoot, label: `Global workspace (${globalDisplay})` });
|
|
26815
27220
|
}
|
|
26816
27221
|
if (instanceOptions.length === 1 && !opts.allowCreate) {
|
|
@@ -26821,7 +27226,7 @@ async function promptForInstance(opts) {
|
|
|
26821
27226
|
label: o.label
|
|
26822
27227
|
}));
|
|
26823
27228
|
if (opts.allowCreate) {
|
|
26824
|
-
const localDisplay = localRoot.replace(
|
|
27229
|
+
const localDisplay = localRoot.replace(os32.homedir(), "~");
|
|
26825
27230
|
options.push({ value: localRoot, label: `New local workspace (${localDisplay})` });
|
|
26826
27231
|
}
|
|
26827
27232
|
const clack10 = await import("@clack/prompts");
|
|
@@ -26847,7 +27252,7 @@ var init_instance_prompt = __esm({
|
|
|
26847
27252
|
|
|
26848
27253
|
// src/cli.ts
|
|
26849
27254
|
import { setDefaultAutoSelectFamily } from "net";
|
|
26850
|
-
import
|
|
27255
|
+
import path68 from "path";
|
|
26851
27256
|
|
|
26852
27257
|
// src/cli/commands/help.ts
|
|
26853
27258
|
function printHelp() {
|
|
@@ -27086,11 +27491,11 @@ Shows all plugins registered in the plugin registry.
|
|
|
27086
27491
|
`);
|
|
27087
27492
|
return;
|
|
27088
27493
|
}
|
|
27089
|
-
const
|
|
27090
|
-
const
|
|
27494
|
+
const os33 = await import("os");
|
|
27495
|
+
const path69 = await import("path");
|
|
27091
27496
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
27092
|
-
const root = instanceRoot ??
|
|
27093
|
-
const registryPath =
|
|
27497
|
+
const root = instanceRoot ?? path69.join(os33.homedir(), ".openacp");
|
|
27498
|
+
const registryPath = path69.join(root, "plugins.json");
|
|
27094
27499
|
const registry = new PluginRegistry2(registryPath);
|
|
27095
27500
|
await registry.load();
|
|
27096
27501
|
const plugins = registry.list();
|
|
@@ -27225,11 +27630,11 @@ async function cmdPlugin(args2 = [], instanceRoot) {
|
|
|
27225
27630
|
}
|
|
27226
27631
|
async function setPluginEnabled(name, enabled, instanceRoot, json = false) {
|
|
27227
27632
|
if (json) await muteForJson();
|
|
27228
|
-
const
|
|
27229
|
-
const
|
|
27633
|
+
const os33 = await import("os");
|
|
27634
|
+
const path69 = await import("path");
|
|
27230
27635
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
27231
|
-
const root = instanceRoot ??
|
|
27232
|
-
const registryPath =
|
|
27636
|
+
const root = instanceRoot ?? path69.join(os33.homedir(), ".openacp");
|
|
27637
|
+
const registryPath = path69.join(root, "plugins.json");
|
|
27233
27638
|
const registry = new PluginRegistry2(registryPath);
|
|
27234
27639
|
await registry.load();
|
|
27235
27640
|
const entry = registry.get(name);
|
|
@@ -27244,8 +27649,8 @@ async function setPluginEnabled(name, enabled, instanceRoot, json = false) {
|
|
|
27244
27649
|
console.log(`Plugin ${name} ${enabled ? "enabled" : "disabled"}. Restart to apply.`);
|
|
27245
27650
|
}
|
|
27246
27651
|
async function configurePlugin(name, instanceRoot) {
|
|
27247
|
-
const
|
|
27248
|
-
const
|
|
27652
|
+
const os33 = await import("os");
|
|
27653
|
+
const path69 = await import("path");
|
|
27249
27654
|
const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
|
|
27250
27655
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
27251
27656
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
@@ -27254,8 +27659,8 @@ async function configurePlugin(name, instanceRoot) {
|
|
|
27254
27659
|
console.error(`Plugin "${name}" not found.`);
|
|
27255
27660
|
process.exit(1);
|
|
27256
27661
|
}
|
|
27257
|
-
const root = instanceRoot ??
|
|
27258
|
-
const basePath =
|
|
27662
|
+
const root = instanceRoot ?? path69.join(os33.homedir(), ".openacp");
|
|
27663
|
+
const basePath = path69.join(root, "plugins", "data");
|
|
27259
27664
|
const settingsManager = new SettingsManager2(basePath);
|
|
27260
27665
|
const ctx = createInstallContext2({ pluginName: name, settingsManager, basePath });
|
|
27261
27666
|
if (plugin2.configure) {
|
|
@@ -27268,14 +27673,14 @@ async function configurePlugin(name, instanceRoot) {
|
|
|
27268
27673
|
}
|
|
27269
27674
|
async function installPlugin(input2, instanceRoot, json = false) {
|
|
27270
27675
|
if (json) await muteForJson();
|
|
27271
|
-
const
|
|
27272
|
-
const
|
|
27676
|
+
const os33 = await import("os");
|
|
27677
|
+
const path69 = await import("path");
|
|
27273
27678
|
const { execFileSync: execFileSync8 } = await import("child_process");
|
|
27274
27679
|
const { getCurrentVersion: getCurrentVersion2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
27275
27680
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
27276
27681
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
27277
27682
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
27278
|
-
const root = instanceRoot ??
|
|
27683
|
+
const root = instanceRoot ?? path69.join(os33.homedir(), ".openacp");
|
|
27279
27684
|
let pkgName;
|
|
27280
27685
|
let pkgVersion;
|
|
27281
27686
|
if (input2.startsWith("@")) {
|
|
@@ -27320,9 +27725,9 @@ async function installPlugin(input2, instanceRoot, json = false) {
|
|
|
27320
27725
|
if (!json) console.log(`Installing ${installSpec}...`);
|
|
27321
27726
|
const { corePlugins: corePlugins2 } = await Promise.resolve().then(() => (init_core_plugins(), core_plugins_exports));
|
|
27322
27727
|
const builtinPlugin = corePlugins2.find((p2) => p2.name === pkgName);
|
|
27323
|
-
const basePath =
|
|
27728
|
+
const basePath = path69.join(root, "plugins", "data");
|
|
27324
27729
|
const settingsManager = new SettingsManager2(basePath);
|
|
27325
|
-
const registryPath =
|
|
27730
|
+
const registryPath = path69.join(root, "plugins.json");
|
|
27326
27731
|
const pluginRegistry = new PluginRegistry2(registryPath);
|
|
27327
27732
|
await pluginRegistry.load();
|
|
27328
27733
|
if (builtinPlugin) {
|
|
@@ -27342,8 +27747,8 @@ async function installPlugin(input2, instanceRoot, json = false) {
|
|
|
27342
27747
|
console.log(`\u2713 ${builtinPlugin.name} installed! Restart to activate.`);
|
|
27343
27748
|
return;
|
|
27344
27749
|
}
|
|
27345
|
-
const pluginsDir =
|
|
27346
|
-
const nodeModulesDir =
|
|
27750
|
+
const pluginsDir = path69.join(root, "plugins");
|
|
27751
|
+
const nodeModulesDir = path69.join(pluginsDir, "node_modules");
|
|
27347
27752
|
try {
|
|
27348
27753
|
execFileSync8("npm", ["install", installSpec, "--prefix", pluginsDir, "--save"], {
|
|
27349
27754
|
stdio: json ? "pipe" : "inherit",
|
|
@@ -27357,8 +27762,8 @@ async function installPlugin(input2, instanceRoot, json = false) {
|
|
|
27357
27762
|
const cliVersion = getCurrentVersion2();
|
|
27358
27763
|
const isLocalPath = pkgName.startsWith("/") || pkgName.startsWith(".");
|
|
27359
27764
|
try {
|
|
27360
|
-
const pluginRoot = isLocalPath ?
|
|
27361
|
-
const installedPkgPath =
|
|
27765
|
+
const pluginRoot = isLocalPath ? path69.resolve(pkgName) : path69.join(nodeModulesDir, pkgName);
|
|
27766
|
+
const installedPkgPath = path69.join(pluginRoot, "package.json");
|
|
27362
27767
|
const { readFileSync: readFileSync19 } = await import("fs");
|
|
27363
27768
|
const installedPkg = JSON.parse(readFileSync19(installedPkgPath, "utf-8"));
|
|
27364
27769
|
const minVersion = installedPkg.engines?.openacp?.replace(/[>=^~\s]/g, "");
|
|
@@ -27373,7 +27778,7 @@ async function installPlugin(input2, instanceRoot, json = false) {
|
|
|
27373
27778
|
}
|
|
27374
27779
|
}
|
|
27375
27780
|
}
|
|
27376
|
-
const pluginModule = await import(
|
|
27781
|
+
const pluginModule = await import(path69.join(pluginRoot, installedPkg.main ?? "dist/index.js"));
|
|
27377
27782
|
const plugin2 = pluginModule.default;
|
|
27378
27783
|
if (plugin2?.install) {
|
|
27379
27784
|
const ctx = createInstallContext2({ pluginName: plugin2.name ?? pkgName, settingsManager, basePath });
|
|
@@ -27403,12 +27808,12 @@ async function installPlugin(input2, instanceRoot, json = false) {
|
|
|
27403
27808
|
}
|
|
27404
27809
|
async function uninstallPlugin(name, purge, instanceRoot, json = false) {
|
|
27405
27810
|
if (json) await muteForJson();
|
|
27406
|
-
const
|
|
27407
|
-
const
|
|
27811
|
+
const os33 = await import("os");
|
|
27812
|
+
const path69 = await import("path");
|
|
27408
27813
|
const fs57 = await import("fs");
|
|
27409
27814
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
27410
|
-
const root = instanceRoot ??
|
|
27411
|
-
const registryPath =
|
|
27815
|
+
const root = instanceRoot ?? path69.join(os33.homedir(), ".openacp");
|
|
27816
|
+
const registryPath = path69.join(root, "plugins.json");
|
|
27412
27817
|
const registry = new PluginRegistry2(registryPath);
|
|
27413
27818
|
await registry.load();
|
|
27414
27819
|
const entry = registry.get(name);
|
|
@@ -27428,7 +27833,7 @@ async function uninstallPlugin(name, purge, instanceRoot, json = false) {
|
|
|
27428
27833
|
if (plugin2?.uninstall) {
|
|
27429
27834
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
27430
27835
|
const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
|
|
27431
|
-
const basePath =
|
|
27836
|
+
const basePath = path69.join(root, "plugins", "data");
|
|
27432
27837
|
const settingsManager = new SettingsManager2(basePath);
|
|
27433
27838
|
const ctx = createInstallContext2({ pluginName: name, settingsManager, basePath });
|
|
27434
27839
|
await plugin2.uninstall(ctx, { purge });
|
|
@@ -27436,7 +27841,7 @@ async function uninstallPlugin(name, purge, instanceRoot, json = false) {
|
|
|
27436
27841
|
} catch {
|
|
27437
27842
|
}
|
|
27438
27843
|
if (purge) {
|
|
27439
|
-
const pluginDir =
|
|
27844
|
+
const pluginDir = path69.join(root, "plugins", name);
|
|
27440
27845
|
fs57.rmSync(pluginDir, { recursive: true, force: true });
|
|
27441
27846
|
}
|
|
27442
27847
|
registry.remove(name);
|
|
@@ -28266,13 +28671,13 @@ init_version();
|
|
|
28266
28671
|
init_helpers();
|
|
28267
28672
|
init_output();
|
|
28268
28673
|
init_instance_hint();
|
|
28269
|
-
import
|
|
28270
|
-
import
|
|
28674
|
+
import path39 from "path";
|
|
28675
|
+
import os17 from "os";
|
|
28271
28676
|
import fs36 from "fs";
|
|
28272
28677
|
async function cmdStart(args2 = [], instanceRoot) {
|
|
28273
28678
|
const json = isJsonMode(args2);
|
|
28274
28679
|
if (json) await muteForJson();
|
|
28275
|
-
const root = instanceRoot ??
|
|
28680
|
+
const root = instanceRoot ?? path39.join(os17.homedir(), ".openacp");
|
|
28276
28681
|
if (!json && wantsHelp(args2)) {
|
|
28277
28682
|
console.log(`
|
|
28278
28683
|
\x1B[1mopenacp start\x1B[0m \u2014 Start OpenACP as a background daemon
|
|
@@ -28298,7 +28703,7 @@ Requires an existing config \u2014 run 'openacp' first to set up.
|
|
|
28298
28703
|
await checkAndPromptUpdate();
|
|
28299
28704
|
const { startDaemon: startDaemon2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
28300
28705
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
28301
|
-
const cm = new ConfigManager2(
|
|
28706
|
+
const cm = new ConfigManager2(path39.join(root, "config.json"));
|
|
28302
28707
|
if (await cm.exists()) {
|
|
28303
28708
|
await cm.load();
|
|
28304
28709
|
const config = cm.get();
|
|
@@ -28309,11 +28714,11 @@ Requires an existing config \u2014 run 'openacp' first to set up.
|
|
|
28309
28714
|
process.exit(1);
|
|
28310
28715
|
}
|
|
28311
28716
|
if (json) {
|
|
28312
|
-
let instanceId =
|
|
28717
|
+
let instanceId = path39.basename(root);
|
|
28313
28718
|
try {
|
|
28314
28719
|
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
28315
28720
|
const { InstanceRegistry: InstanceRegistry2 } = await Promise.resolve().then(() => (init_instance_registry(), instance_registry_exports));
|
|
28316
|
-
const reg = new InstanceRegistry2(
|
|
28721
|
+
const reg = new InstanceRegistry2(path39.join(getGlobalRoot2(), "instances.json"));
|
|
28317
28722
|
reg.load();
|
|
28318
28723
|
const entry = reg.getByRoot(root);
|
|
28319
28724
|
if (entry) instanceId = entry.id;
|
|
@@ -28321,7 +28726,7 @@ Requires an existing config \u2014 run 'openacp' first to set up.
|
|
|
28321
28726
|
}
|
|
28322
28727
|
let port = null;
|
|
28323
28728
|
try {
|
|
28324
|
-
const portStr = fs36.readFileSync(
|
|
28729
|
+
const portStr = fs36.readFileSync(path39.join(root, "api.port"), "utf-8").trim();
|
|
28325
28730
|
port = parseInt(portStr) || null;
|
|
28326
28731
|
} catch {
|
|
28327
28732
|
port = config.api.port ?? null;
|
|
@@ -28330,7 +28735,7 @@ Requires an existing config \u2014 run 'openacp' first to set up.
|
|
|
28330
28735
|
pid: result.pid,
|
|
28331
28736
|
instanceId,
|
|
28332
28737
|
name: config.instanceName ?? null,
|
|
28333
|
-
directory:
|
|
28738
|
+
directory: path39.dirname(root),
|
|
28334
28739
|
dir: root,
|
|
28335
28740
|
port
|
|
28336
28741
|
});
|
|
@@ -28467,16 +28872,20 @@ the API for live updates. When stopped, edits config file directly.
|
|
|
28467
28872
|
}
|
|
28468
28873
|
const { runConfigEditor: runConfigEditor2 } = await Promise.resolve().then(() => (init_config_editor(), config_editor_exports));
|
|
28469
28874
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
28875
|
+
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
28876
|
+
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
28470
28877
|
const cm = new ConfigManager2(instanceRoot ? pathMod.join(instanceRoot, "config.json") : void 0);
|
|
28471
28878
|
if (!await cm.exists()) {
|
|
28472
28879
|
console.error('No config found. Run "openacp" first to set up.');
|
|
28473
28880
|
process.exit(1);
|
|
28474
28881
|
}
|
|
28882
|
+
const root = instanceRoot ?? getGlobalRoot2();
|
|
28883
|
+
const settingsManager = new SettingsManager2(pathMod.join(root, "plugins", "data"));
|
|
28475
28884
|
const port = readApiPort(void 0, instanceRoot);
|
|
28476
28885
|
if (port !== null) {
|
|
28477
|
-
await runConfigEditor2(cm, "api", port);
|
|
28886
|
+
await runConfigEditor2(cm, "api", port, settingsManager);
|
|
28478
28887
|
} else {
|
|
28479
|
-
await runConfigEditor2(cm, "file");
|
|
28888
|
+
await runConfigEditor2(cm, "file", void 0, settingsManager);
|
|
28480
28889
|
}
|
|
28481
28890
|
}
|
|
28482
28891
|
|
|
@@ -28497,9 +28906,9 @@ start fresh with the setup wizard. The daemon must be stopped first.
|
|
|
28497
28906
|
`);
|
|
28498
28907
|
return;
|
|
28499
28908
|
}
|
|
28500
|
-
const
|
|
28501
|
-
const
|
|
28502
|
-
const root = instanceRoot ??
|
|
28909
|
+
const os33 = await import("os");
|
|
28910
|
+
const path69 = await import("path");
|
|
28911
|
+
const root = instanceRoot ?? path69.join(os33.homedir(), ".openacp");
|
|
28503
28912
|
const { getStatus: getStatus2, getPidPath: getPidPath2 } = await Promise.resolve().then(() => (init_daemon2(), daemon_exports));
|
|
28504
28913
|
const status = getStatus2(getPidPath2(root));
|
|
28505
28914
|
if (status.running) {
|
|
@@ -28657,11 +29066,11 @@ init_instance_context();
|
|
|
28657
29066
|
init_status();
|
|
28658
29067
|
init_output();
|
|
28659
29068
|
init_helpers();
|
|
28660
|
-
import
|
|
28661
|
-
import
|
|
29069
|
+
import path60 from "path";
|
|
29070
|
+
import os28 from "os";
|
|
28662
29071
|
import fs52 from "fs";
|
|
28663
29072
|
async function buildInstanceListEntries() {
|
|
28664
|
-
const registryPath =
|
|
29073
|
+
const registryPath = path60.join(getGlobalRoot(), "instances.json");
|
|
28665
29074
|
const registry = new InstanceRegistry(registryPath);
|
|
28666
29075
|
registry.load();
|
|
28667
29076
|
return registry.list().map((entry) => {
|
|
@@ -28669,7 +29078,7 @@ async function buildInstanceListEntries() {
|
|
|
28669
29078
|
return {
|
|
28670
29079
|
id: entry.id,
|
|
28671
29080
|
name: info.name,
|
|
28672
|
-
directory:
|
|
29081
|
+
directory: path60.dirname(entry.root),
|
|
28673
29082
|
root: entry.root,
|
|
28674
29083
|
status: info.pid ? "running" : "stopped",
|
|
28675
29084
|
port: info.apiPort
|
|
@@ -28719,7 +29128,7 @@ async function cmdInstancesList(args2) {
|
|
|
28719
29128
|
for (const e of entries) {
|
|
28720
29129
|
const status = e.status === "running" ? "\u25CF running" : "\u25CB stopped";
|
|
28721
29130
|
const port = e.port ? `:${e.port}` : "\u2014";
|
|
28722
|
-
const dir = e.directory.replace(
|
|
29131
|
+
const dir = e.directory.replace(os28.homedir(), "~");
|
|
28723
29132
|
const name = (e.name ?? e.id).padEnd(16);
|
|
28724
29133
|
console.log(` ${status.padEnd(10)} ${e.id.padEnd(16)} ${name} ${dir} ${port}`);
|
|
28725
29134
|
}
|
|
@@ -28742,9 +29151,9 @@ async function cmdInstancesCreate(args2) {
|
|
|
28742
29151
|
const agentIdx = args2.indexOf("--agent");
|
|
28743
29152
|
const agent = agentIdx !== -1 ? args2[agentIdx + 1] : void 0;
|
|
28744
29153
|
const noInteractive = args2.includes("--no-interactive");
|
|
28745
|
-
const resolvedDir =
|
|
28746
|
-
const instanceRoot =
|
|
28747
|
-
const registryPath =
|
|
29154
|
+
const resolvedDir = path60.resolve(rawDir.replace(/^~/, os28.homedir()));
|
|
29155
|
+
const instanceRoot = path60.join(resolvedDir, ".openacp");
|
|
29156
|
+
const registryPath = path60.join(getGlobalRoot(), "instances.json");
|
|
28748
29157
|
const registry = new InstanceRegistry(registryPath);
|
|
28749
29158
|
registry.load();
|
|
28750
29159
|
if (fs52.existsSync(instanceRoot)) {
|
|
@@ -28754,8 +29163,8 @@ async function cmdInstancesCreate(args2) {
|
|
|
28754
29163
|
console.error(`Error: Instance already exists at ${resolvedDir} (id: ${existing.id})`);
|
|
28755
29164
|
process.exit(1);
|
|
28756
29165
|
}
|
|
28757
|
-
const configPath =
|
|
28758
|
-
let name2 =
|
|
29166
|
+
const configPath = path60.join(instanceRoot, "config.json");
|
|
29167
|
+
let name2 = path60.basename(resolvedDir);
|
|
28759
29168
|
try {
|
|
28760
29169
|
const config = JSON.parse(fs52.readFileSync(configPath, "utf-8"));
|
|
28761
29170
|
name2 = config.instanceName ?? name2;
|
|
@@ -28770,15 +29179,15 @@ async function cmdInstancesCreate(args2) {
|
|
|
28770
29179
|
const name = instanceName ?? `openacp-${registry.list().length + 1}`;
|
|
28771
29180
|
const id = registry.uniqueId(generateSlug(name));
|
|
28772
29181
|
if (rawFrom) {
|
|
28773
|
-
const fromRoot =
|
|
28774
|
-
if (!fs52.existsSync(
|
|
29182
|
+
const fromRoot = path60.join(path60.resolve(rawFrom.replace(/^~/, os28.homedir())), ".openacp");
|
|
29183
|
+
if (!fs52.existsSync(path60.join(fromRoot, "config.json"))) {
|
|
28775
29184
|
console.error(`Error: No OpenACP instance found at ${rawFrom}`);
|
|
28776
29185
|
process.exit(1);
|
|
28777
29186
|
}
|
|
28778
29187
|
fs52.mkdirSync(instanceRoot, { recursive: true });
|
|
28779
29188
|
const { copyInstance: copyInstance2 } = await Promise.resolve().then(() => (init_instance_copy(), instance_copy_exports));
|
|
28780
29189
|
await copyInstance2(fromRoot, instanceRoot, {});
|
|
28781
|
-
const configPath =
|
|
29190
|
+
const configPath = path60.join(instanceRoot, "config.json");
|
|
28782
29191
|
try {
|
|
28783
29192
|
const config = JSON.parse(fs52.readFileSync(configPath, "utf-8"));
|
|
28784
29193
|
config.instanceName = name;
|
|
@@ -28789,14 +29198,14 @@ async function cmdInstancesCreate(args2) {
|
|
|
28789
29198
|
fs52.mkdirSync(instanceRoot, { recursive: true });
|
|
28790
29199
|
const config = { instanceName: name, runMode: "daemon" };
|
|
28791
29200
|
if (agent) config.defaultAgent = agent;
|
|
28792
|
-
fs52.writeFileSync(
|
|
28793
|
-
fs52.writeFileSync(
|
|
29201
|
+
fs52.writeFileSync(path60.join(instanceRoot, "config.json"), JSON.stringify(config, null, 2));
|
|
29202
|
+
fs52.writeFileSync(path60.join(instanceRoot, "plugins.json"), JSON.stringify({ version: 1, installed: {} }, null, 2));
|
|
28794
29203
|
} else {
|
|
28795
29204
|
fs52.mkdirSync(instanceRoot, { recursive: true });
|
|
28796
29205
|
const config = { instanceName: name, runMode: "daemon" };
|
|
28797
29206
|
if (agent) config.defaultAgent = agent;
|
|
28798
|
-
fs52.writeFileSync(
|
|
28799
|
-
fs52.writeFileSync(
|
|
29207
|
+
fs52.writeFileSync(path60.join(instanceRoot, "config.json"), JSON.stringify(config, null, 2));
|
|
29208
|
+
fs52.writeFileSync(path60.join(instanceRoot, "plugins.json"), JSON.stringify({ version: 1, installed: {} }, null, 2));
|
|
28800
29209
|
console.log(`Instance created at ${resolvedDir}. Run 'openacp setup' inside that directory to configure it.`);
|
|
28801
29210
|
}
|
|
28802
29211
|
registry.register(id, instanceRoot);
|
|
@@ -28808,7 +29217,7 @@ async function outputInstance(json, { id, root }) {
|
|
|
28808
29217
|
const entry = {
|
|
28809
29218
|
id,
|
|
28810
29219
|
name: info.name,
|
|
28811
|
-
directory:
|
|
29220
|
+
directory: path60.dirname(root),
|
|
28812
29221
|
root,
|
|
28813
29222
|
status: info.pid ? "running" : "stopped",
|
|
28814
29223
|
port: info.apiPort
|
|
@@ -28817,7 +29226,7 @@ async function outputInstance(json, { id, root }) {
|
|
|
28817
29226
|
jsonSuccess(entry);
|
|
28818
29227
|
return;
|
|
28819
29228
|
}
|
|
28820
|
-
console.log(`Instance created: ${info.name ?? id} at ${
|
|
29229
|
+
console.log(`Instance created: ${info.name ?? id} at ${path60.dirname(root)}`);
|
|
28821
29230
|
}
|
|
28822
29231
|
|
|
28823
29232
|
// src/cli/commands/integrate.ts
|
|
@@ -29580,22 +29989,22 @@ Options:
|
|
|
29580
29989
|
}
|
|
29581
29990
|
|
|
29582
29991
|
// src/cli/commands/onboard.ts
|
|
29583
|
-
import * as
|
|
29992
|
+
import * as path61 from "path";
|
|
29584
29993
|
async function cmdOnboard(instanceRoot) {
|
|
29585
29994
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
29586
29995
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
29587
29996
|
const { PluginRegistry: PluginRegistry2 } = await Promise.resolve().then(() => (init_plugin_registry(), plugin_registry_exports));
|
|
29588
29997
|
const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
29589
29998
|
const OPENACP_DIR = instanceRoot ?? getGlobalRoot2();
|
|
29590
|
-
const PLUGINS_DATA_DIR =
|
|
29591
|
-
const REGISTRY_PATH =
|
|
29592
|
-
const cm = new ConfigManager2(
|
|
29999
|
+
const PLUGINS_DATA_DIR = path61.join(OPENACP_DIR, "plugins", "data");
|
|
30000
|
+
const REGISTRY_PATH = path61.join(OPENACP_DIR, "plugins.json");
|
|
30001
|
+
const cm = new ConfigManager2(path61.join(OPENACP_DIR, "config.json"));
|
|
29593
30002
|
const settingsManager = new SettingsManager2(PLUGINS_DATA_DIR);
|
|
29594
30003
|
const pluginRegistry = new PluginRegistry2(REGISTRY_PATH);
|
|
29595
30004
|
await pluginRegistry.load();
|
|
29596
30005
|
if (await cm.exists()) {
|
|
29597
30006
|
const { runReconfigure: runReconfigure2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
|
|
29598
|
-
await runReconfigure2(cm);
|
|
30007
|
+
await runReconfigure2(cm, settingsManager);
|
|
29599
30008
|
} else {
|
|
29600
30009
|
const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
|
|
29601
30010
|
await runSetup2(cm, { skipRunMode: true, settingsManager, pluginRegistry, instanceRoot: OPENACP_DIR });
|
|
@@ -29608,17 +30017,17 @@ init_instance_context();
|
|
|
29608
30017
|
init_instance_registry();
|
|
29609
30018
|
init_instance_hint();
|
|
29610
30019
|
init_output();
|
|
29611
|
-
import
|
|
29612
|
-
import
|
|
30020
|
+
import path62 from "path";
|
|
30021
|
+
import os29 from "os";
|
|
29613
30022
|
import fs53 from "fs";
|
|
29614
30023
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
29615
30024
|
async function cmdDefault(command2, instanceRoot) {
|
|
29616
30025
|
const args2 = command2 ? [command2] : [];
|
|
29617
30026
|
const json = isJsonMode(args2);
|
|
29618
30027
|
if (json) await muteForJson();
|
|
29619
|
-
const root = instanceRoot ??
|
|
29620
|
-
const pluginsDataDir =
|
|
29621
|
-
const registryPath =
|
|
30028
|
+
const root = instanceRoot ?? path62.join(os29.homedir(), ".openacp");
|
|
30029
|
+
const pluginsDataDir = path62.join(root, "plugins", "data");
|
|
30030
|
+
const registryPath = path62.join(root, "plugins.json");
|
|
29622
30031
|
const forceForeground = command2 === "--foreground";
|
|
29623
30032
|
if (command2 && !command2.startsWith("-")) {
|
|
29624
30033
|
const { suggestMatch: suggestMatch2 } = await Promise.resolve().then(() => (init_suggest(), suggest_exports));
|
|
@@ -29650,7 +30059,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29650
30059
|
}
|
|
29651
30060
|
await checkAndPromptUpdate();
|
|
29652
30061
|
const { ConfigManager: ConfigManager2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
29653
|
-
const configPath =
|
|
30062
|
+
const configPath = path62.join(root, "config.json");
|
|
29654
30063
|
const cm = new ConfigManager2(configPath);
|
|
29655
30064
|
if (!await cm.exists()) {
|
|
29656
30065
|
const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
|
|
@@ -29678,9 +30087,9 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29678
30087
|
process.exit(1);
|
|
29679
30088
|
}
|
|
29680
30089
|
if (json) {
|
|
29681
|
-
let instanceId2 =
|
|
30090
|
+
let instanceId2 = path62.basename(root);
|
|
29682
30091
|
try {
|
|
29683
|
-
const reg2 = new InstanceRegistry(
|
|
30092
|
+
const reg2 = new InstanceRegistry(path62.join(getGlobalRoot(), "instances.json"));
|
|
29684
30093
|
reg2.load();
|
|
29685
30094
|
const entry = reg2.getByRoot(root);
|
|
29686
30095
|
if (entry) instanceId2 = entry.id;
|
|
@@ -29688,7 +30097,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29688
30097
|
}
|
|
29689
30098
|
let port = null;
|
|
29690
30099
|
try {
|
|
29691
|
-
const portStr = fs53.readFileSync(
|
|
30100
|
+
const portStr = fs53.readFileSync(path62.join(root, "api.port"), "utf-8").trim();
|
|
29692
30101
|
port = parseInt(portStr) || null;
|
|
29693
30102
|
} catch {
|
|
29694
30103
|
port = config.api.port ?? null;
|
|
@@ -29697,7 +30106,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29697
30106
|
pid: result.pid,
|
|
29698
30107
|
instanceId: instanceId2,
|
|
29699
30108
|
name: config.instanceName ?? null,
|
|
29700
|
-
directory:
|
|
30109
|
+
directory: path62.dirname(root),
|
|
29701
30110
|
dir: root,
|
|
29702
30111
|
port
|
|
29703
30112
|
});
|
|
@@ -29710,7 +30119,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29710
30119
|
markRunning2(root);
|
|
29711
30120
|
printInstanceHint(root);
|
|
29712
30121
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
29713
|
-
const reg = new InstanceRegistry(
|
|
30122
|
+
const reg = new InstanceRegistry(path62.join(getGlobalRoot(), "instances.json"));
|
|
29714
30123
|
reg.load();
|
|
29715
30124
|
const existingEntry = reg.getByRoot(root);
|
|
29716
30125
|
const instanceId = existingEntry?.id ?? randomUUID5();
|
|
@@ -29722,7 +30131,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29722
30131
|
if (json) {
|
|
29723
30132
|
let port = null;
|
|
29724
30133
|
try {
|
|
29725
|
-
const portStr = fs53.readFileSync(
|
|
30134
|
+
const portStr = fs53.readFileSync(path62.join(root, "api.port"), "utf-8").trim();
|
|
29726
30135
|
port = parseInt(portStr) || null;
|
|
29727
30136
|
} catch {
|
|
29728
30137
|
port = config.api.port ?? null;
|
|
@@ -29731,7 +30140,7 @@ async function cmdDefault(command2, instanceRoot) {
|
|
|
29731
30140
|
pid: process.pid,
|
|
29732
30141
|
instanceId,
|
|
29733
30142
|
name: config.instanceName ?? null,
|
|
29734
|
-
directory:
|
|
30143
|
+
directory: path62.dirname(root),
|
|
29735
30144
|
dir: root,
|
|
29736
30145
|
port
|
|
29737
30146
|
});
|
|
@@ -29800,7 +30209,7 @@ async function showAlreadyRunningMenu(root) {
|
|
|
29800
30209
|
// src/cli/commands/dev.ts
|
|
29801
30210
|
init_helpers();
|
|
29802
30211
|
import fs54 from "fs";
|
|
29803
|
-
import
|
|
30212
|
+
import path63 from "path";
|
|
29804
30213
|
async function cmdDev(args2 = []) {
|
|
29805
30214
|
if (wantsHelp(args2)) {
|
|
29806
30215
|
console.log(`
|
|
@@ -29827,12 +30236,12 @@ async function cmdDev(args2 = []) {
|
|
|
29827
30236
|
console.error("Error: missing plugin path. Usage: openacp dev <plugin-path>");
|
|
29828
30237
|
process.exit(1);
|
|
29829
30238
|
}
|
|
29830
|
-
const pluginPath =
|
|
30239
|
+
const pluginPath = path63.resolve(pluginPathArg);
|
|
29831
30240
|
if (!fs54.existsSync(pluginPath)) {
|
|
29832
30241
|
console.error(`Error: plugin path does not exist: ${pluginPath}`);
|
|
29833
30242
|
process.exit(1);
|
|
29834
30243
|
}
|
|
29835
|
-
const tsconfigPath =
|
|
30244
|
+
const tsconfigPath = path63.join(pluginPath, "tsconfig.json");
|
|
29836
30245
|
const hasTsconfig = fs54.existsSync(tsconfigPath);
|
|
29837
30246
|
if (hasTsconfig) {
|
|
29838
30247
|
console.log("Compiling plugin TypeScript...");
|
|
@@ -29874,10 +30283,10 @@ async function cmdDev(args2 = []) {
|
|
|
29874
30283
|
|
|
29875
30284
|
// src/cli/commands/attach.ts
|
|
29876
30285
|
init_helpers();
|
|
29877
|
-
import
|
|
29878
|
-
import
|
|
30286
|
+
import path64 from "path";
|
|
30287
|
+
import os30 from "os";
|
|
29879
30288
|
async function cmdAttach(args2 = [], instanceRoot) {
|
|
29880
|
-
const root = instanceRoot ??
|
|
30289
|
+
const root = instanceRoot ?? path64.join(os30.homedir(), ".openacp");
|
|
29881
30290
|
if (wantsHelp(args2)) {
|
|
29882
30291
|
console.log(`
|
|
29883
30292
|
\x1B[1mopenacp attach\x1B[0m \u2014 Attach to a running daemon
|
|
@@ -29911,15 +30320,15 @@ Press Ctrl+C to detach.
|
|
|
29911
30320
|
console.log("");
|
|
29912
30321
|
const { spawn: spawn9 } = await import("child_process");
|
|
29913
30322
|
const { expandHome: expandHome4 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
29914
|
-
let logDir2 =
|
|
30323
|
+
let logDir2 = path64.join(root, "logs");
|
|
29915
30324
|
try {
|
|
29916
|
-
const configPath =
|
|
30325
|
+
const configPath = path64.join(root, "config.json");
|
|
29917
30326
|
const { readFileSync: readFileSync19 } = await import("fs");
|
|
29918
30327
|
const config = JSON.parse(readFileSync19(configPath, "utf-8"));
|
|
29919
30328
|
if (config.logging?.logDir) logDir2 = expandHome4(config.logging.logDir);
|
|
29920
30329
|
} catch {
|
|
29921
30330
|
}
|
|
29922
|
-
const logFile =
|
|
30331
|
+
const logFile = path64.join(logDir2, "openacp.log");
|
|
29923
30332
|
const tail = spawn9("tail", ["-f", "-n", "50", logFile], { stdio: "inherit" });
|
|
29924
30333
|
tail.on("error", (err) => {
|
|
29925
30334
|
console.error(`Cannot tail log file: ${err.message}`);
|
|
@@ -29931,8 +30340,8 @@ Press Ctrl+C to detach.
|
|
|
29931
30340
|
init_api_client();
|
|
29932
30341
|
init_instance_registry();
|
|
29933
30342
|
init_output();
|
|
29934
|
-
import
|
|
29935
|
-
import
|
|
30343
|
+
import path65 from "path";
|
|
30344
|
+
import os31 from "os";
|
|
29936
30345
|
import qrcode from "qrcode-terminal";
|
|
29937
30346
|
async function cmdRemote(args2, instanceRoot) {
|
|
29938
30347
|
const json = isJsonMode(args2);
|
|
@@ -29947,7 +30356,7 @@ async function cmdRemote(args2, instanceRoot) {
|
|
|
29947
30356
|
const scopes = scopesRaw ? scopesRaw.split(",").map((s) => s.trim()) : void 0;
|
|
29948
30357
|
let resolvedInstanceRoot2 = instanceRoot;
|
|
29949
30358
|
if (instanceId) {
|
|
29950
|
-
const registryPath =
|
|
30359
|
+
const registryPath = path65.join(os31.homedir(), ".openacp", "instances.json");
|
|
29951
30360
|
const registry = new InstanceRegistry(registryPath);
|
|
29952
30361
|
await registry.load();
|
|
29953
30362
|
const entry = registry.get(instanceId);
|
|
@@ -30085,7 +30494,7 @@ function extractFlag(args2, flag) {
|
|
|
30085
30494
|
// src/cli/commands/setup.ts
|
|
30086
30495
|
init_output();
|
|
30087
30496
|
import * as fs55 from "fs";
|
|
30088
|
-
import * as
|
|
30497
|
+
import * as path66 from "path";
|
|
30089
30498
|
function parseFlag(args2, flag) {
|
|
30090
30499
|
const idx = args2.indexOf(flag);
|
|
30091
30500
|
return idx !== -1 ? args2[idx + 1] : void 0;
|
|
@@ -30113,7 +30522,7 @@ async function cmdSetup(args2, instanceRoot) {
|
|
|
30113
30522
|
}
|
|
30114
30523
|
const runMode = rawRunMode;
|
|
30115
30524
|
const defaultAgent = agentRaw.split(",")[0].trim();
|
|
30116
|
-
const configPath =
|
|
30525
|
+
const configPath = path66.join(instanceRoot, "config.json");
|
|
30117
30526
|
let existing = {};
|
|
30118
30527
|
if (fs55.existsSync(configPath)) {
|
|
30119
30528
|
try {
|
|
@@ -30221,7 +30630,7 @@ async function main() {
|
|
|
30221
30630
|
if (envRoot) {
|
|
30222
30631
|
const { createInstanceContext: createInstanceContext2, getGlobalRoot: getGlobal } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
|
|
30223
30632
|
const { InstanceRegistry: InstanceRegistry2 } = await Promise.resolve().then(() => (init_instance_registry(), instance_registry_exports));
|
|
30224
|
-
const registry = new InstanceRegistry2(
|
|
30633
|
+
const registry = new InstanceRegistry2(path68.join(getGlobal(), "instances.json"));
|
|
30225
30634
|
await registry.load();
|
|
30226
30635
|
const entry = registry.getByRoot(envRoot);
|
|
30227
30636
|
const { randomUUID: randomUUID6 } = await import("crypto");
|