nextclaw 0.4.12 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +378 -102
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -84,8 +84,8 @@ import { spawn } from "child_process";
|
|
|
84
84
|
import { createServer } from "net";
|
|
85
85
|
import { fileURLToPath } from "url";
|
|
86
86
|
import { getDataDir, getPackageVersion as getCorePackageVersion } from "@nextclaw/core";
|
|
87
|
-
function resolveUiConfig(
|
|
88
|
-
const base =
|
|
87
|
+
function resolveUiConfig(config2, overrides) {
|
|
88
|
+
const base = config2.ui ?? { enabled: false, host: "127.0.0.1", port: 18791, open: false };
|
|
89
89
|
return { ...base, ...overrides ?? {} };
|
|
90
90
|
}
|
|
91
91
|
function resolveUiApiBase(host, port) {
|
|
@@ -389,21 +389,21 @@ var readConfigSnapshot = (getConfigPath2, plugins2) => {
|
|
|
389
389
|
parsed = {};
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
|
-
let
|
|
392
|
+
let config2;
|
|
393
393
|
let valid = true;
|
|
394
394
|
try {
|
|
395
|
-
|
|
395
|
+
config2 = ConfigSchema.parse(parsed);
|
|
396
396
|
} catch {
|
|
397
|
-
|
|
397
|
+
config2 = ConfigSchema.parse({});
|
|
398
398
|
valid = false;
|
|
399
399
|
}
|
|
400
400
|
if (!raw) {
|
|
401
|
-
raw = JSON.stringify(
|
|
401
|
+
raw = JSON.stringify(config2, null, 2);
|
|
402
402
|
}
|
|
403
403
|
const hash = hashRaw(raw);
|
|
404
404
|
const schema = buildConfigSchema({ version: getPackageVersion(), plugins: plugins2 });
|
|
405
|
-
const redacted = redactConfigObject(
|
|
406
|
-
return { raw: valid ? JSON.stringify(redacted, null, 2) : null, hash: valid ? hash : null, config, redacted, valid };
|
|
405
|
+
const redacted = redactConfigObject(config2, schema.uiHints);
|
|
406
|
+
return { raw: valid ? JSON.stringify(redacted, null, 2) : null, hash: valid ? hash : null, config: config2, redacted, valid };
|
|
407
407
|
};
|
|
408
408
|
var redactValue = (value, plugins2) => {
|
|
409
409
|
const schema = buildConfigSchema({ version: getPackageVersion(), plugins: plugins2 });
|
|
@@ -627,6 +627,191 @@ function buildClawHubArgs(slug, options) {
|
|
|
627
627
|
// src/cli/runtime.ts
|
|
628
628
|
var LOGO = "\u{1F916}";
|
|
629
629
|
var EXIT_COMMANDS = /* @__PURE__ */ new Set(["exit", "quit", "/exit", "/quit", ":q"]);
|
|
630
|
+
function isIndexSegment(raw) {
|
|
631
|
+
return /^[0-9]+$/.test(raw);
|
|
632
|
+
}
|
|
633
|
+
function parseConfigPath(raw) {
|
|
634
|
+
const trimmed = raw.trim();
|
|
635
|
+
if (!trimmed) {
|
|
636
|
+
return [];
|
|
637
|
+
}
|
|
638
|
+
const parts = [];
|
|
639
|
+
let current = "";
|
|
640
|
+
let i = 0;
|
|
641
|
+
while (i < trimmed.length) {
|
|
642
|
+
const ch = trimmed[i];
|
|
643
|
+
if (ch === "\\") {
|
|
644
|
+
const next = trimmed[i + 1];
|
|
645
|
+
if (next) {
|
|
646
|
+
current += next;
|
|
647
|
+
}
|
|
648
|
+
i += 2;
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
if (ch === ".") {
|
|
652
|
+
if (current) {
|
|
653
|
+
parts.push(current);
|
|
654
|
+
}
|
|
655
|
+
current = "";
|
|
656
|
+
i += 1;
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (ch === "[") {
|
|
660
|
+
if (current) {
|
|
661
|
+
parts.push(current);
|
|
662
|
+
}
|
|
663
|
+
current = "";
|
|
664
|
+
const close = trimmed.indexOf("]", i);
|
|
665
|
+
if (close === -1) {
|
|
666
|
+
throw new Error(`Invalid path (missing "]"): ${raw}`);
|
|
667
|
+
}
|
|
668
|
+
const inside = trimmed.slice(i + 1, close).trim();
|
|
669
|
+
if (!inside) {
|
|
670
|
+
throw new Error(`Invalid path (empty "[]"): ${raw}`);
|
|
671
|
+
}
|
|
672
|
+
parts.push(inside);
|
|
673
|
+
i = close + 1;
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
current += ch;
|
|
677
|
+
i += 1;
|
|
678
|
+
}
|
|
679
|
+
if (current) {
|
|
680
|
+
parts.push(current);
|
|
681
|
+
}
|
|
682
|
+
return parts.map((part) => part.trim()).filter(Boolean);
|
|
683
|
+
}
|
|
684
|
+
function parseRequiredConfigPath(raw) {
|
|
685
|
+
const parsedPath = parseConfigPath(raw);
|
|
686
|
+
if (parsedPath.length === 0) {
|
|
687
|
+
throw new Error("Path is empty.");
|
|
688
|
+
}
|
|
689
|
+
return parsedPath;
|
|
690
|
+
}
|
|
691
|
+
function parseConfigSetValue(raw, opts) {
|
|
692
|
+
const trimmed = raw.trim();
|
|
693
|
+
if (opts.json) {
|
|
694
|
+
return JSON.parse(trimmed);
|
|
695
|
+
}
|
|
696
|
+
try {
|
|
697
|
+
return JSON.parse(trimmed);
|
|
698
|
+
} catch {
|
|
699
|
+
return raw;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
function getAtConfigPath(root, pathSegments) {
|
|
703
|
+
let current = root;
|
|
704
|
+
for (const segment of pathSegments) {
|
|
705
|
+
if (!current || typeof current !== "object") {
|
|
706
|
+
return { found: false };
|
|
707
|
+
}
|
|
708
|
+
if (Array.isArray(current)) {
|
|
709
|
+
if (!isIndexSegment(segment)) {
|
|
710
|
+
return { found: false };
|
|
711
|
+
}
|
|
712
|
+
const index = Number.parseInt(segment, 10);
|
|
713
|
+
if (!Number.isFinite(index) || index < 0 || index >= current.length) {
|
|
714
|
+
return { found: false };
|
|
715
|
+
}
|
|
716
|
+
current = current[index];
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
const record = current;
|
|
720
|
+
if (!Object.prototype.hasOwnProperty.call(record, segment)) {
|
|
721
|
+
return { found: false };
|
|
722
|
+
}
|
|
723
|
+
current = record[segment];
|
|
724
|
+
}
|
|
725
|
+
return { found: true, value: current };
|
|
726
|
+
}
|
|
727
|
+
function setAtConfigPath(root, pathSegments, value) {
|
|
728
|
+
let current = root;
|
|
729
|
+
for (let i = 0; i < pathSegments.length - 1; i += 1) {
|
|
730
|
+
const segment = pathSegments[i];
|
|
731
|
+
const next = pathSegments[i + 1];
|
|
732
|
+
const nextIsIndex = Boolean(next && isIndexSegment(next));
|
|
733
|
+
if (Array.isArray(current)) {
|
|
734
|
+
if (!isIndexSegment(segment)) {
|
|
735
|
+
throw new Error(`Expected numeric index for array segment "${segment}"`);
|
|
736
|
+
}
|
|
737
|
+
const index = Number.parseInt(segment, 10);
|
|
738
|
+
const existing2 = current[index];
|
|
739
|
+
if (!existing2 || typeof existing2 !== "object") {
|
|
740
|
+
current[index] = nextIsIndex ? [] : {};
|
|
741
|
+
}
|
|
742
|
+
current = current[index];
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
if (!current || typeof current !== "object") {
|
|
746
|
+
throw new Error(`Cannot traverse into "${segment}" (not an object)`);
|
|
747
|
+
}
|
|
748
|
+
const record = current;
|
|
749
|
+
const existing = record[segment];
|
|
750
|
+
if (!existing || typeof existing !== "object") {
|
|
751
|
+
record[segment] = nextIsIndex ? [] : {};
|
|
752
|
+
}
|
|
753
|
+
current = record[segment];
|
|
754
|
+
}
|
|
755
|
+
const last = pathSegments[pathSegments.length - 1];
|
|
756
|
+
if (Array.isArray(current)) {
|
|
757
|
+
if (!isIndexSegment(last)) {
|
|
758
|
+
throw new Error(`Expected numeric index for array segment "${last}"`);
|
|
759
|
+
}
|
|
760
|
+
const index = Number.parseInt(last, 10);
|
|
761
|
+
current[index] = value;
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (!current || typeof current !== "object") {
|
|
765
|
+
throw new Error(`Cannot set "${last}" (parent is not an object)`);
|
|
766
|
+
}
|
|
767
|
+
current[last] = value;
|
|
768
|
+
}
|
|
769
|
+
function unsetAtConfigPath(root, pathSegments) {
|
|
770
|
+
let current = root;
|
|
771
|
+
for (let i = 0; i < pathSegments.length - 1; i += 1) {
|
|
772
|
+
const segment = pathSegments[i];
|
|
773
|
+
if (!current || typeof current !== "object") {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
if (Array.isArray(current)) {
|
|
777
|
+
if (!isIndexSegment(segment)) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
const index = Number.parseInt(segment, 10);
|
|
781
|
+
if (!Number.isFinite(index) || index < 0 || index >= current.length) {
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
current = current[index];
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
const record2 = current;
|
|
788
|
+
if (!Object.prototype.hasOwnProperty.call(record2, segment)) {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
current = record2[segment];
|
|
792
|
+
}
|
|
793
|
+
const last = pathSegments[pathSegments.length - 1];
|
|
794
|
+
if (Array.isArray(current)) {
|
|
795
|
+
if (!isIndexSegment(last)) {
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
const index = Number.parseInt(last, 10);
|
|
799
|
+
if (!Number.isFinite(index) || index < 0 || index >= current.length) {
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
current.splice(index, 1);
|
|
803
|
+
return true;
|
|
804
|
+
}
|
|
805
|
+
if (!current || typeof current !== "object") {
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
const record = current;
|
|
809
|
+
if (!Object.prototype.hasOwnProperty.call(record, last)) {
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
delete record[last];
|
|
813
|
+
return true;
|
|
814
|
+
}
|
|
630
815
|
var ConfigReloader = class {
|
|
631
816
|
constructor(options) {
|
|
632
817
|
this.options = options;
|
|
@@ -758,12 +943,12 @@ var CliRuntime = class {
|
|
|
758
943
|
const configPath = getConfigPath();
|
|
759
944
|
let createdConfig = false;
|
|
760
945
|
if (!existsSync4(configPath)) {
|
|
761
|
-
const
|
|
762
|
-
saveConfig(
|
|
946
|
+
const config3 = ConfigSchema2.parse({});
|
|
947
|
+
saveConfig(config3);
|
|
763
948
|
createdConfig = true;
|
|
764
949
|
}
|
|
765
|
-
const
|
|
766
|
-
const workspaceSetting =
|
|
950
|
+
const config2 = loadConfig();
|
|
951
|
+
const workspaceSetting = config2.agents.defaults.workspace;
|
|
767
952
|
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join3(getDataDir2(), DEFAULT_WORKSPACE_DIR) : expandHome(workspaceSetting);
|
|
768
953
|
const workspaceExisted = existsSync4(workspacePath);
|
|
769
954
|
mkdirSync2(workspacePath, { recursive: true });
|
|
@@ -863,6 +1048,19 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
863
1048
|
open: Boolean(opts.open)
|
|
864
1049
|
});
|
|
865
1050
|
}
|
|
1051
|
+
async restart(opts) {
|
|
1052
|
+
const state = readServiceState();
|
|
1053
|
+
if (state && isProcessRunning(state.pid)) {
|
|
1054
|
+
console.log(`Restarting ${APP_NAME}...`);
|
|
1055
|
+
await this.stopService();
|
|
1056
|
+
} else if (state) {
|
|
1057
|
+
clearServiceState();
|
|
1058
|
+
console.log("Service state was stale and has been cleaned up.");
|
|
1059
|
+
} else {
|
|
1060
|
+
console.log("No running service found. Starting a new service.");
|
|
1061
|
+
}
|
|
1062
|
+
await this.start(opts);
|
|
1063
|
+
}
|
|
866
1064
|
async serve(opts) {
|
|
867
1065
|
const uiOverrides = {
|
|
868
1066
|
enabled: true,
|
|
@@ -904,23 +1102,23 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
904
1102
|
await this.stopService();
|
|
905
1103
|
}
|
|
906
1104
|
async agent(opts) {
|
|
907
|
-
const
|
|
908
|
-
const workspace = getWorkspacePath(
|
|
909
|
-
const pluginRegistry = this.loadPluginRegistry(
|
|
1105
|
+
const config2 = loadConfig();
|
|
1106
|
+
const workspace = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1107
|
+
const pluginRegistry = this.loadPluginRegistry(config2, workspace);
|
|
910
1108
|
const extensionRegistry = this.toExtensionRegistry(pluginRegistry);
|
|
911
1109
|
this.logPluginDiagnostics(pluginRegistry);
|
|
912
1110
|
const bus = new MessageBus();
|
|
913
|
-
const provider = this.makeProvider(
|
|
1111
|
+
const provider = this.makeProvider(config2);
|
|
914
1112
|
const providerManager = new ProviderManager(provider);
|
|
915
1113
|
const agentLoop = new AgentLoop({
|
|
916
1114
|
bus,
|
|
917
1115
|
providerManager,
|
|
918
1116
|
workspace,
|
|
919
|
-
braveApiKey:
|
|
920
|
-
execConfig:
|
|
921
|
-
restrictToWorkspace:
|
|
922
|
-
contextConfig:
|
|
923
|
-
config,
|
|
1117
|
+
braveApiKey: config2.tools.web.search.apiKey || void 0,
|
|
1118
|
+
execConfig: config2.tools.exec,
|
|
1119
|
+
restrictToWorkspace: config2.tools.restrictToWorkspace,
|
|
1120
|
+
contextConfig: config2.agents.context,
|
|
1121
|
+
config: config2,
|
|
924
1122
|
extensionRegistry,
|
|
925
1123
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
926
1124
|
registry: pluginRegistry,
|
|
@@ -1006,12 +1204,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1006
1204
|
}
|
|
1007
1205
|
}
|
|
1008
1206
|
pluginsList(opts = {}) {
|
|
1009
|
-
const
|
|
1010
|
-
const workspaceDir = getWorkspacePath(
|
|
1207
|
+
const config2 = loadConfig();
|
|
1208
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1011
1209
|
const report = buildPluginStatusReport({
|
|
1012
|
-
config,
|
|
1210
|
+
config: config2,
|
|
1013
1211
|
workspaceDir,
|
|
1014
|
-
reservedChannelIds: Object.keys(
|
|
1212
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1015
1213
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1016
1214
|
});
|
|
1017
1215
|
const list = opts.enabled ? report.plugins.filter((plugin) => plugin.status === "loaded") : report.plugins;
|
|
@@ -1063,12 +1261,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1063
1261
|
}
|
|
1064
1262
|
}
|
|
1065
1263
|
pluginsInfo(id, opts = {}) {
|
|
1066
|
-
const
|
|
1067
|
-
const workspaceDir = getWorkspacePath(
|
|
1264
|
+
const config2 = loadConfig();
|
|
1265
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1068
1266
|
const report = buildPluginStatusReport({
|
|
1069
|
-
config,
|
|
1267
|
+
config: config2,
|
|
1070
1268
|
workspaceDir,
|
|
1071
|
-
reservedChannelIds: Object.keys(
|
|
1269
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1072
1270
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1073
1271
|
});
|
|
1074
1272
|
const plugin = report.plugins.find((entry) => entry.id === id || entry.name === id);
|
|
@@ -1080,7 +1278,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1080
1278
|
console.log(JSON.stringify(plugin, null, 2));
|
|
1081
1279
|
return;
|
|
1082
1280
|
}
|
|
1083
|
-
const install =
|
|
1281
|
+
const install = config2.plugins.installs?.[plugin.id];
|
|
1084
1282
|
const lines = [];
|
|
1085
1283
|
lines.push(plugin.name || plugin.id);
|
|
1086
1284
|
if (plugin.name && plugin.name !== plugin.id) {
|
|
@@ -1129,25 +1327,98 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1129
1327
|
}
|
|
1130
1328
|
console.log(lines.join("\n"));
|
|
1131
1329
|
}
|
|
1330
|
+
configGet(pathExpr, opts = {}) {
|
|
1331
|
+
const config2 = loadConfig();
|
|
1332
|
+
let parsedPath;
|
|
1333
|
+
try {
|
|
1334
|
+
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
1335
|
+
} catch (error) {
|
|
1336
|
+
console.error(String(error));
|
|
1337
|
+
process.exit(1);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
const result = getAtConfigPath(config2, parsedPath);
|
|
1341
|
+
if (!result.found) {
|
|
1342
|
+
console.error(`Config path not found: ${pathExpr}`);
|
|
1343
|
+
process.exit(1);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
if (opts.json) {
|
|
1347
|
+
console.log(JSON.stringify(result.value ?? null, null, 2));
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
if (typeof result.value === "string" || typeof result.value === "number" || typeof result.value === "boolean") {
|
|
1351
|
+
console.log(String(result.value));
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
console.log(JSON.stringify(result.value ?? null, null, 2));
|
|
1355
|
+
}
|
|
1356
|
+
configSet(pathExpr, value, opts = {}) {
|
|
1357
|
+
let parsedPath;
|
|
1358
|
+
try {
|
|
1359
|
+
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
console.error(String(error));
|
|
1362
|
+
process.exit(1);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
let parsedValue;
|
|
1366
|
+
try {
|
|
1367
|
+
parsedValue = parseConfigSetValue(value, opts);
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
console.error(`Failed to parse config value: ${String(error)}`);
|
|
1370
|
+
process.exit(1);
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
const config2 = loadConfig();
|
|
1374
|
+
try {
|
|
1375
|
+
setAtConfigPath(config2, parsedPath, parsedValue);
|
|
1376
|
+
} catch (error) {
|
|
1377
|
+
console.error(String(error));
|
|
1378
|
+
process.exit(1);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
saveConfig(config2);
|
|
1382
|
+
console.log(`Updated ${pathExpr}. Restart the gateway to apply.`);
|
|
1383
|
+
}
|
|
1384
|
+
configUnset(pathExpr) {
|
|
1385
|
+
let parsedPath;
|
|
1386
|
+
try {
|
|
1387
|
+
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
console.error(String(error));
|
|
1390
|
+
process.exit(1);
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
const config2 = loadConfig();
|
|
1394
|
+
const removed = unsetAtConfigPath(config2, parsedPath);
|
|
1395
|
+
if (!removed) {
|
|
1396
|
+
console.error(`Config path not found: ${pathExpr}`);
|
|
1397
|
+
process.exit(1);
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
saveConfig(config2);
|
|
1401
|
+
console.log(`Removed ${pathExpr}. Restart the gateway to apply.`);
|
|
1402
|
+
}
|
|
1132
1403
|
pluginsEnable(id) {
|
|
1133
|
-
const
|
|
1134
|
-
const next = enablePluginInConfig(
|
|
1404
|
+
const config2 = loadConfig();
|
|
1405
|
+
const next = enablePluginInConfig(config2, id);
|
|
1135
1406
|
saveConfig(next);
|
|
1136
1407
|
console.log(`Enabled plugin "${id}". Restart the gateway to apply.`);
|
|
1137
1408
|
}
|
|
1138
1409
|
pluginsDisable(id) {
|
|
1139
|
-
const
|
|
1140
|
-
const next = disablePluginInConfig(
|
|
1410
|
+
const config2 = loadConfig();
|
|
1411
|
+
const next = disablePluginInConfig(config2, id);
|
|
1141
1412
|
saveConfig(next);
|
|
1142
1413
|
console.log(`Disabled plugin "${id}". Restart the gateway to apply.`);
|
|
1143
1414
|
}
|
|
1144
1415
|
async pluginsUninstall(id, opts = {}) {
|
|
1145
|
-
const
|
|
1146
|
-
const workspaceDir = getWorkspacePath(
|
|
1416
|
+
const config2 = loadConfig();
|
|
1417
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1147
1418
|
const report = buildPluginStatusReport({
|
|
1148
|
-
config,
|
|
1419
|
+
config: config2,
|
|
1149
1420
|
workspaceDir,
|
|
1150
|
-
reservedChannelIds: Object.keys(
|
|
1421
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1151
1422
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1152
1423
|
});
|
|
1153
1424
|
const keepFiles = Boolean(opts.keepFiles || opts.keepConfig);
|
|
@@ -1156,8 +1427,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1156
1427
|
}
|
|
1157
1428
|
const plugin = report.plugins.find((entry) => entry.id === id || entry.name === id);
|
|
1158
1429
|
const pluginId = plugin?.id ?? id;
|
|
1159
|
-
const hasEntry = pluginId in (
|
|
1160
|
-
const hasInstall = pluginId in (
|
|
1430
|
+
const hasEntry = pluginId in (config2.plugins.entries ?? {});
|
|
1431
|
+
const hasInstall = pluginId in (config2.plugins.installs ?? {});
|
|
1161
1432
|
if (!hasEntry && !hasInstall) {
|
|
1162
1433
|
if (plugin) {
|
|
1163
1434
|
console.error(
|
|
@@ -1168,8 +1439,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1168
1439
|
}
|
|
1169
1440
|
process.exit(1);
|
|
1170
1441
|
}
|
|
1171
|
-
const install =
|
|
1172
|
-
const isLinked = install?.source === "path";
|
|
1442
|
+
const install = config2.plugins.installs?.[pluginId];
|
|
1443
|
+
const isLinked = install?.source === "path" && (!install.installPath || !install.sourcePath || resolve4(install.installPath) === resolve4(install.sourcePath));
|
|
1173
1444
|
const preview = [];
|
|
1174
1445
|
if (hasEntry) {
|
|
1175
1446
|
preview.push("config entry");
|
|
@@ -1177,10 +1448,10 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1177
1448
|
if (hasInstall) {
|
|
1178
1449
|
preview.push("install record");
|
|
1179
1450
|
}
|
|
1180
|
-
if (
|
|
1451
|
+
if (config2.plugins.allow?.includes(pluginId)) {
|
|
1181
1452
|
preview.push("allowlist entry");
|
|
1182
1453
|
}
|
|
1183
|
-
if (isLinked && install?.sourcePath &&
|
|
1454
|
+
if (isLinked && install?.sourcePath && config2.plugins.load?.paths?.includes(install.sourcePath)) {
|
|
1184
1455
|
preview.push("load path");
|
|
1185
1456
|
}
|
|
1186
1457
|
const deleteTarget = !keepFiles ? resolveUninstallDirectoryTarget({
|
|
@@ -1207,7 +1478,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1207
1478
|
}
|
|
1208
1479
|
}
|
|
1209
1480
|
const result = await uninstallPlugin({
|
|
1210
|
-
config,
|
|
1481
|
+
config: config2,
|
|
1211
1482
|
pluginId,
|
|
1212
1483
|
deleteFiles: !keepFiles
|
|
1213
1484
|
});
|
|
@@ -1246,7 +1517,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1246
1517
|
}
|
|
1247
1518
|
const normalized = fileSpec && fileSpec.ok ? fileSpec.path : pathOrSpec;
|
|
1248
1519
|
const resolved = resolve4(expandHome(normalized));
|
|
1249
|
-
const
|
|
1520
|
+
const config2 = loadConfig();
|
|
1250
1521
|
if (existsSync4(resolved)) {
|
|
1251
1522
|
if (opts.link) {
|
|
1252
1523
|
const probe = await installPluginFromPath({ path: resolved, dryRun: true });
|
|
@@ -1254,7 +1525,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1254
1525
|
console.error(probe.error);
|
|
1255
1526
|
process.exit(1);
|
|
1256
1527
|
}
|
|
1257
|
-
let next3 = addPluginLoadPath(
|
|
1528
|
+
let next3 = addPluginLoadPath(config2, resolved);
|
|
1258
1529
|
next3 = enablePluginInConfig(next3, probe.pluginId);
|
|
1259
1530
|
next3 = recordPluginInstall(next3, {
|
|
1260
1531
|
pluginId: probe.pluginId,
|
|
@@ -1279,7 +1550,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1279
1550
|
console.error(result2.error);
|
|
1280
1551
|
process.exit(1);
|
|
1281
1552
|
}
|
|
1282
|
-
let next2 = enablePluginInConfig(
|
|
1553
|
+
let next2 = enablePluginInConfig(config2, result2.pluginId);
|
|
1283
1554
|
next2 = recordPluginInstall(next2, {
|
|
1284
1555
|
pluginId: result2.pluginId,
|
|
1285
1556
|
source: this.isArchivePath(resolved) ? "archive" : "path",
|
|
@@ -1311,7 +1582,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1311
1582
|
console.error(result.error);
|
|
1312
1583
|
process.exit(1);
|
|
1313
1584
|
}
|
|
1314
|
-
let next = enablePluginInConfig(
|
|
1585
|
+
let next = enablePluginInConfig(config2, result.pluginId);
|
|
1315
1586
|
next = recordPluginInstall(next, {
|
|
1316
1587
|
pluginId: result.pluginId,
|
|
1317
1588
|
source: "npm",
|
|
@@ -1324,12 +1595,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1324
1595
|
console.log("Restart the gateway to load plugins.");
|
|
1325
1596
|
}
|
|
1326
1597
|
pluginsDoctor() {
|
|
1327
|
-
const
|
|
1328
|
-
const workspaceDir = getWorkspacePath(
|
|
1598
|
+
const config2 = loadConfig();
|
|
1599
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1329
1600
|
const report = buildPluginStatusReport({
|
|
1330
|
-
config,
|
|
1601
|
+
config: config2,
|
|
1331
1602
|
workspaceDir,
|
|
1332
|
-
reservedChannelIds: Object.keys(
|
|
1603
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1333
1604
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1334
1605
|
});
|
|
1335
1606
|
const pluginErrors = report.plugins.filter((plugin) => plugin.status === "error");
|
|
@@ -1377,20 +1648,20 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1377
1648
|
console.log(` Path: ${result.destinationDir}`);
|
|
1378
1649
|
}
|
|
1379
1650
|
channelsStatus() {
|
|
1380
|
-
const
|
|
1651
|
+
const config2 = loadConfig();
|
|
1381
1652
|
console.log("Channel Status");
|
|
1382
|
-
console.log(`WhatsApp: ${
|
|
1383
|
-
console.log(`Discord: ${
|
|
1384
|
-
console.log(`Feishu: ${
|
|
1385
|
-
console.log(`Mochat: ${
|
|
1386
|
-
console.log(`Telegram: ${
|
|
1387
|
-
console.log(`Slack: ${
|
|
1388
|
-
console.log(`QQ: ${
|
|
1389
|
-
const workspaceDir = getWorkspacePath(
|
|
1653
|
+
console.log(`WhatsApp: ${config2.channels.whatsapp.enabled ? "\u2713" : "\u2717"}`);
|
|
1654
|
+
console.log(`Discord: ${config2.channels.discord.enabled ? "\u2713" : "\u2717"}`);
|
|
1655
|
+
console.log(`Feishu: ${config2.channels.feishu.enabled ? "\u2713" : "\u2717"}`);
|
|
1656
|
+
console.log(`Mochat: ${config2.channels.mochat.enabled ? "\u2713" : "\u2717"}`);
|
|
1657
|
+
console.log(`Telegram: ${config2.channels.telegram.enabled ? "\u2713" : "\u2717"}`);
|
|
1658
|
+
console.log(`Slack: ${config2.channels.slack.enabled ? "\u2713" : "\u2717"}`);
|
|
1659
|
+
console.log(`QQ: ${config2.channels.qq.enabled ? "\u2713" : "\u2717"}`);
|
|
1660
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1390
1661
|
const report = buildPluginStatusReport({
|
|
1391
|
-
config,
|
|
1662
|
+
config: config2,
|
|
1392
1663
|
workspaceDir,
|
|
1393
|
-
reservedChannelIds: Object.keys(
|
|
1664
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1394
1665
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1395
1666
|
});
|
|
1396
1667
|
const pluginChannels = report.plugins.filter((plugin) => plugin.status === "loaded" && plugin.channelIds.length > 0);
|
|
@@ -1417,9 +1688,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1417
1688
|
console.error("--channel is required");
|
|
1418
1689
|
process.exit(1);
|
|
1419
1690
|
}
|
|
1420
|
-
const
|
|
1421
|
-
const workspaceDir = getWorkspacePath(
|
|
1422
|
-
const pluginRegistry = this.loadPluginRegistry(
|
|
1691
|
+
const config2 = loadConfig();
|
|
1692
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1693
|
+
const pluginRegistry = this.loadPluginRegistry(config2, workspaceDir);
|
|
1423
1694
|
const bindings = getPluginChannelBindings(pluginRegistry);
|
|
1424
1695
|
const binding = bindings.find((entry) => entry.channelId === channelId || entry.pluginId === channelId);
|
|
1425
1696
|
if (!binding) {
|
|
@@ -1438,7 +1709,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1438
1709
|
url: opts.url,
|
|
1439
1710
|
httpUrl: opts.httpUrl
|
|
1440
1711
|
};
|
|
1441
|
-
const currentView = this.toPluginConfigView(
|
|
1712
|
+
const currentView = this.toPluginConfigView(config2, bindings);
|
|
1442
1713
|
const accountId = binding.channel.config?.defaultAccountId?.(currentView) ?? "default";
|
|
1443
1714
|
const validateError = setup.validateInput?.({
|
|
1444
1715
|
cfg: currentView,
|
|
@@ -1458,17 +1729,17 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1458
1729
|
console.error("Channel setup returned invalid config payload.");
|
|
1459
1730
|
process.exit(1);
|
|
1460
1731
|
}
|
|
1461
|
-
let next = this.mergePluginConfigView(
|
|
1732
|
+
let next = this.mergePluginConfigView(config2, nextView, bindings);
|
|
1462
1733
|
next = enablePluginInConfig(next, binding.pluginId);
|
|
1463
1734
|
saveConfig(next);
|
|
1464
1735
|
console.log(`Configured channel "${binding.channelId}" via plugin "${binding.pluginId}".`);
|
|
1465
1736
|
console.log("Restart the gateway to apply changes.");
|
|
1466
1737
|
}
|
|
1467
|
-
toPluginConfigView(
|
|
1468
|
-
const view = JSON.parse(JSON.stringify(
|
|
1738
|
+
toPluginConfigView(config2, bindings) {
|
|
1739
|
+
const view = JSON.parse(JSON.stringify(config2));
|
|
1469
1740
|
const channels2 = view.channels && typeof view.channels === "object" && !Array.isArray(view.channels) ? { ...view.channels } : {};
|
|
1470
1741
|
for (const binding of bindings) {
|
|
1471
|
-
const pluginConfig =
|
|
1742
|
+
const pluginConfig = config2.plugins.entries?.[binding.pluginId]?.config;
|
|
1472
1743
|
if (!pluginConfig || typeof pluginConfig !== "object" || Array.isArray(pluginConfig)) {
|
|
1473
1744
|
continue;
|
|
1474
1745
|
}
|
|
@@ -1572,15 +1843,15 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1572
1843
|
}
|
|
1573
1844
|
status() {
|
|
1574
1845
|
const configPath = getConfigPath();
|
|
1575
|
-
const
|
|
1576
|
-
const workspace = getWorkspacePath(
|
|
1846
|
+
const config2 = loadConfig();
|
|
1847
|
+
const workspace = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1577
1848
|
console.log(`${this.logo} ${APP_NAME} Status
|
|
1578
1849
|
`);
|
|
1579
1850
|
console.log(`Config: ${configPath} ${existsSync4(configPath) ? "\u2713" : "\u2717"}`);
|
|
1580
1851
|
console.log(`Workspace: ${workspace} ${existsSync4(workspace) ? "\u2713" : "\u2717"}`);
|
|
1581
|
-
console.log(`Model: ${
|
|
1852
|
+
console.log(`Model: ${config2.agents.defaults.model}`);
|
|
1582
1853
|
for (const spec of PROVIDERS) {
|
|
1583
|
-
const provider =
|
|
1854
|
+
const provider = config2.providers[spec.name];
|
|
1584
1855
|
if (!provider) {
|
|
1585
1856
|
continue;
|
|
1586
1857
|
}
|
|
@@ -1591,9 +1862,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1591
1862
|
}
|
|
1592
1863
|
}
|
|
1593
1864
|
}
|
|
1594
|
-
loadPluginRegistry(
|
|
1865
|
+
loadPluginRegistry(config2, workspaceDir) {
|
|
1595
1866
|
return loadOpenClawPlugins({
|
|
1596
|
-
config,
|
|
1867
|
+
config: config2,
|
|
1597
1868
|
workspaceDir,
|
|
1598
1869
|
reservedToolNames: [
|
|
1599
1870
|
"read_file",
|
|
@@ -1614,7 +1885,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1614
1885
|
"gateway",
|
|
1615
1886
|
"cron"
|
|
1616
1887
|
],
|
|
1617
|
-
reservedChannelIds: Object.keys(
|
|
1888
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1618
1889
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name),
|
|
1619
1890
|
logger: {
|
|
1620
1891
|
info: (message) => console.log(message),
|
|
@@ -1658,19 +1929,19 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1658
1929
|
}
|
|
1659
1930
|
}
|
|
1660
1931
|
async startGateway(options = {}) {
|
|
1661
|
-
const
|
|
1662
|
-
const workspace = getWorkspacePath(
|
|
1663
|
-
const pluginRegistry = this.loadPluginRegistry(
|
|
1932
|
+
const config2 = loadConfig();
|
|
1933
|
+
const workspace = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1934
|
+
const pluginRegistry = this.loadPluginRegistry(config2, workspace);
|
|
1664
1935
|
const extensionRegistry = this.toExtensionRegistry(pluginRegistry);
|
|
1665
1936
|
this.logPluginDiagnostics(pluginRegistry);
|
|
1666
1937
|
const bus = new MessageBus();
|
|
1667
|
-
const provider = options.allowMissingProvider === true ? this.makeProvider(
|
|
1938
|
+
const provider = options.allowMissingProvider === true ? this.makeProvider(config2, { allowMissing: true }) : this.makeProvider(config2);
|
|
1668
1939
|
const providerManager = provider ? new ProviderManager(provider) : null;
|
|
1669
1940
|
const sessionManager = new SessionManager(workspace);
|
|
1670
1941
|
const cronStorePath = join3(getDataDir2(), "cron", "jobs.json");
|
|
1671
1942
|
const cron2 = new CronService(cronStorePath);
|
|
1672
1943
|
const pluginUiMetadata = getPluginUiMetadataFromRegistry(pluginRegistry);
|
|
1673
|
-
const uiConfig = resolveUiConfig(
|
|
1944
|
+
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
1674
1945
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
1675
1946
|
if (!provider) {
|
|
1676
1947
|
this.startUiIfEnabled(uiConfig, uiStaticDir);
|
|
@@ -1679,9 +1950,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1679
1950
|
});
|
|
1680
1951
|
return;
|
|
1681
1952
|
}
|
|
1682
|
-
const channels2 = new ChannelManager(
|
|
1953
|
+
const channels2 = new ChannelManager(config2, bus, sessionManager, extensionRegistry.channels);
|
|
1683
1954
|
const reloader = new ConfigReloader({
|
|
1684
|
-
initialConfig:
|
|
1955
|
+
initialConfig: config2,
|
|
1685
1956
|
channels: channels2,
|
|
1686
1957
|
bus,
|
|
1687
1958
|
sessionManager,
|
|
@@ -1704,16 +1975,16 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1704
1975
|
bus,
|
|
1705
1976
|
providerManager: providerManager ?? new ProviderManager(provider),
|
|
1706
1977
|
workspace,
|
|
1707
|
-
model:
|
|
1708
|
-
maxIterations:
|
|
1709
|
-
braveApiKey:
|
|
1710
|
-
execConfig:
|
|
1978
|
+
model: config2.agents.defaults.model,
|
|
1979
|
+
maxIterations: config2.agents.defaults.maxToolIterations,
|
|
1980
|
+
braveApiKey: config2.tools.web.search.apiKey || void 0,
|
|
1981
|
+
execConfig: config2.tools.exec,
|
|
1711
1982
|
cronService: cron2,
|
|
1712
|
-
restrictToWorkspace:
|
|
1983
|
+
restrictToWorkspace: config2.tools.restrictToWorkspace,
|
|
1713
1984
|
sessionManager,
|
|
1714
|
-
contextConfig:
|
|
1985
|
+
contextConfig: config2.agents.context,
|
|
1715
1986
|
gatewayController,
|
|
1716
|
-
config,
|
|
1987
|
+
config: config2,
|
|
1717
1988
|
extensionRegistry,
|
|
1718
1989
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
1719
1990
|
registry: pluginRegistry,
|
|
@@ -1853,8 +2124,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1853
2124
|
}
|
|
1854
2125
|
}
|
|
1855
2126
|
async runForeground(options) {
|
|
1856
|
-
const
|
|
1857
|
-
const uiConfig = resolveUiConfig(
|
|
2127
|
+
const config2 = loadConfig();
|
|
2128
|
+
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
1858
2129
|
const shouldStartFrontend = options.frontend;
|
|
1859
2130
|
const frontendPort = Number.isFinite(options.frontendPort) ? options.frontendPort : 5173;
|
|
1860
2131
|
const frontendDir = shouldStartFrontend ? resolveUiFrontendDir() : null;
|
|
@@ -1886,8 +2157,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1886
2157
|
});
|
|
1887
2158
|
}
|
|
1888
2159
|
async startService(options) {
|
|
1889
|
-
const
|
|
1890
|
-
const uiConfig = resolveUiConfig(
|
|
2160
|
+
const config2 = loadConfig();
|
|
2161
|
+
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
1891
2162
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
1892
2163
|
const apiUrl = `${uiUrl}/api`;
|
|
1893
2164
|
const staticDir = resolveUiStaticDir();
|
|
@@ -1987,9 +2258,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1987
2258
|
const normalized = answer.trim().toLowerCase();
|
|
1988
2259
|
return normalized === "y" || normalized === "yes";
|
|
1989
2260
|
}
|
|
1990
|
-
makeProvider(
|
|
1991
|
-
const provider = getProvider(
|
|
1992
|
-
const model =
|
|
2261
|
+
makeProvider(config2, options) {
|
|
2262
|
+
const provider = getProvider(config2);
|
|
2263
|
+
const model = config2.agents.defaults.model;
|
|
1993
2264
|
if (!provider?.apiKey && !model.startsWith("bedrock/")) {
|
|
1994
2265
|
if (options?.allowMissing) {
|
|
1995
2266
|
return null;
|
|
@@ -2000,10 +2271,10 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
2000
2271
|
}
|
|
2001
2272
|
return new LiteLLMProvider({
|
|
2002
2273
|
apiKey: provider?.apiKey ?? null,
|
|
2003
|
-
apiBase: getApiBase(
|
|
2274
|
+
apiBase: getApiBase(config2),
|
|
2004
2275
|
defaultModel: model,
|
|
2005
2276
|
extraHeaders: provider?.extraHeaders ?? null,
|
|
2006
|
-
providerName: getProviderName(
|
|
2277
|
+
providerName: getProviderName(config2),
|
|
2007
2278
|
wireApi: provider?.wireApi ?? null
|
|
2008
2279
|
});
|
|
2009
2280
|
}
|
|
@@ -2212,6 +2483,7 @@ program.command("init").description(`Initialize ${APP_NAME2} configuration and w
|
|
|
2212
2483
|
program.command("gateway").description(`Start the ${APP_NAME2} gateway`).option("-p, --port <port>", "Gateway port", "18790").option("-v, --verbose", "Verbose output", false).option("--ui", "Enable UI server", false).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--ui-open", "Open browser when UI starts", false).action(async (opts) => runtime.gateway(opts));
|
|
2213
2484
|
program.command("ui").description(`Start the ${APP_NAME2} UI with gateway`).option("--host <host>", "UI host").option("--port <port>", "UI port").option("--no-open", "Disable opening browser").action(async (opts) => runtime.ui(opts));
|
|
2214
2485
|
program.command("start").description(`Start the ${APP_NAME2} gateway + UI in the background`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).action(async (opts) => runtime.start(opts));
|
|
2486
|
+
program.command("restart").description(`Restart the ${APP_NAME2} background service`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after restart", false).action(async (opts) => runtime.restart(opts));
|
|
2215
2487
|
program.command("serve").description(`Run the ${APP_NAME2} gateway + UI in the foreground`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).action(async (opts) => runtime.serve(opts));
|
|
2216
2488
|
program.command("stop").description(`Stop the ${APP_NAME2} background service`).action(async () => runtime.stop());
|
|
2217
2489
|
program.command("agent").description("Interact with the agent directly").option("-m, --message <message>", "Message to send to the agent").option("-s, --session <session>", "Session ID", "cli:default").option("--no-markdown", "Disable Markdown rendering").action(async (opts) => runtime.agent(opts));
|
|
@@ -2231,6 +2503,10 @@ plugins.command("disable <id>").description("Disable a plugin in config").action
|
|
|
2231
2503
|
plugins.command("uninstall <id>").description("Uninstall a plugin").option("--keep-files", "Keep installed files on disk", false).option("--keep-config", "Deprecated alias for --keep-files", false).option("--force", "Skip confirmation prompt", false).option("--dry-run", "Show what would be removed without making changes", false).action(async (id, opts) => runtime.pluginsUninstall(id, opts));
|
|
2232
2504
|
plugins.command("install <path-or-spec>").description("Install a plugin (path, archive, or npm spec)").option("-l, --link", "Link a local path instead of copying", false).action(async (pathOrSpec, opts) => runtime.pluginsInstall(pathOrSpec, opts));
|
|
2233
2505
|
plugins.command("doctor").description("Report plugin load issues").action(() => runtime.pluginsDoctor());
|
|
2506
|
+
var config = program.command("config").description("Manage config values");
|
|
2507
|
+
config.command("get <path>").description("Get a config value by dot path").option("--json", "Output JSON", false).action((path, opts) => runtime.configGet(path, opts));
|
|
2508
|
+
config.command("set <path> <value>").description("Set a config value by dot path").option("--json", "Parse value as JSON", false).action((path, value, opts) => runtime.configSet(path, value, opts));
|
|
2509
|
+
config.command("unset <path>").description("Remove a config value by dot path").action((path) => runtime.configUnset(path));
|
|
2234
2510
|
var channels = program.command("channels").description("Manage channels");
|
|
2235
2511
|
channels.command("add").description("Configure a plugin channel (OpenClaw-compatible setup)").requiredOption("--channel <id>", "Plugin channel id").option("--code <code>", "Pairing code").option("--token <token>", "Connector token").option("--name <name>", "Display name").option("--url <url>", "API base URL").option("--http-url <url>", "Alias for --url").action((opts) => runtime.channelsAdd(opts));
|
|
2236
2512
|
channels.command("status").description("Show channel status").action(() => runtime.channelsStatus());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nextclaw",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.14",
|
|
4
4
|
"description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"dev": "tsx watch --tsconfig tsconfig.json src/cli/index.ts",
|
|
59
|
-
"dev:build": "
|
|
60
|
-
"build": "
|
|
59
|
+
"dev:build": "tsx src/cli/index.ts",
|
|
60
|
+
"build": "tsup src/index.ts src/cli/index.ts --format esm --dts --out-dir dist && node scripts/copy-ui-dist.mjs",
|
|
61
61
|
"start": "node dist/cli.js",
|
|
62
62
|
"lint": "eslint .",
|
|
63
63
|
"tsc": "tsc -p tsconfig.json",
|