nextclaw 0.4.11 → 0.4.13
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 +393 -103
- package/package.json +4 -4
package/dist/cli/index.js
CHANGED
|
@@ -83,9 +83,9 @@ import { join, resolve } from "path";
|
|
|
83
83
|
import { spawn } from "child_process";
|
|
84
84
|
import { createServer } from "net";
|
|
85
85
|
import { fileURLToPath } from "url";
|
|
86
|
-
import { getDataDir, getPackageVersion } from "@nextclaw/core";
|
|
87
|
-
function resolveUiConfig(
|
|
88
|
-
const base =
|
|
86
|
+
import { getDataDir, getPackageVersion as getCorePackageVersion } from "@nextclaw/core";
|
|
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) {
|
|
@@ -234,6 +234,34 @@ function which(binary) {
|
|
|
234
234
|
}
|
|
235
235
|
return false;
|
|
236
236
|
}
|
|
237
|
+
function resolveVersionFromPackageTree(startDir, expectedName) {
|
|
238
|
+
let current = resolve(startDir);
|
|
239
|
+
while (current.length > 0) {
|
|
240
|
+
const pkgPath = join(current, "package.json");
|
|
241
|
+
if (existsSync(pkgPath)) {
|
|
242
|
+
try {
|
|
243
|
+
const raw = readFileSync(pkgPath, "utf-8");
|
|
244
|
+
const parsed = JSON.parse(raw);
|
|
245
|
+
if (typeof parsed.version === "string") {
|
|
246
|
+
if (!expectedName || parsed.name === expectedName) {
|
|
247
|
+
return parsed.version;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const parent = resolve(current, "..");
|
|
254
|
+
if (parent === current) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
current = parent;
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
function getPackageVersion() {
|
|
262
|
+
const cliDir = resolve(fileURLToPath(new URL(".", import.meta.url)));
|
|
263
|
+
return resolveVersionFromPackageTree(cliDir, "nextclaw") ?? resolveVersionFromPackageTree(cliDir) ?? getCorePackageVersion();
|
|
264
|
+
}
|
|
237
265
|
function startUiFrontend(options) {
|
|
238
266
|
const uiDir = options.dir ?? resolveUiFrontendDir();
|
|
239
267
|
if (!uiDir) {
|
|
@@ -361,21 +389,21 @@ var readConfigSnapshot = (getConfigPath2, plugins2) => {
|
|
|
361
389
|
parsed = {};
|
|
362
390
|
}
|
|
363
391
|
}
|
|
364
|
-
let
|
|
392
|
+
let config2;
|
|
365
393
|
let valid = true;
|
|
366
394
|
try {
|
|
367
|
-
|
|
395
|
+
config2 = ConfigSchema.parse(parsed);
|
|
368
396
|
} catch {
|
|
369
|
-
|
|
397
|
+
config2 = ConfigSchema.parse({});
|
|
370
398
|
valid = false;
|
|
371
399
|
}
|
|
372
400
|
if (!raw) {
|
|
373
|
-
raw = JSON.stringify(
|
|
401
|
+
raw = JSON.stringify(config2, null, 2);
|
|
374
402
|
}
|
|
375
403
|
const hash = hashRaw(raw);
|
|
376
404
|
const schema = buildConfigSchema({ version: getPackageVersion(), plugins: plugins2 });
|
|
377
|
-
const redacted = redactConfigObject(
|
|
378
|
-
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 };
|
|
379
407
|
};
|
|
380
408
|
var redactValue = (value, plugins2) => {
|
|
381
409
|
const schema = buildConfigSchema({ version: getPackageVersion(), plugins: plugins2 });
|
|
@@ -599,6 +627,191 @@ function buildClawHubArgs(slug, options) {
|
|
|
599
627
|
// src/cli/runtime.ts
|
|
600
628
|
var LOGO = "\u{1F916}";
|
|
601
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
|
+
}
|
|
602
815
|
var ConfigReloader = class {
|
|
603
816
|
constructor(options) {
|
|
604
817
|
this.options = options;
|
|
@@ -730,12 +943,12 @@ var CliRuntime = class {
|
|
|
730
943
|
const configPath = getConfigPath();
|
|
731
944
|
let createdConfig = false;
|
|
732
945
|
if (!existsSync4(configPath)) {
|
|
733
|
-
const
|
|
734
|
-
saveConfig(
|
|
946
|
+
const config3 = ConfigSchema2.parse({});
|
|
947
|
+
saveConfig(config3);
|
|
735
948
|
createdConfig = true;
|
|
736
949
|
}
|
|
737
|
-
const
|
|
738
|
-
const workspaceSetting =
|
|
950
|
+
const config2 = loadConfig();
|
|
951
|
+
const workspaceSetting = config2.agents.defaults.workspace;
|
|
739
952
|
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join3(getDataDir2(), DEFAULT_WORKSPACE_DIR) : expandHome(workspaceSetting);
|
|
740
953
|
const workspaceExisted = existsSync4(workspacePath);
|
|
741
954
|
mkdirSync2(workspacePath, { recursive: true });
|
|
@@ -876,23 +1089,23 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
876
1089
|
await this.stopService();
|
|
877
1090
|
}
|
|
878
1091
|
async agent(opts) {
|
|
879
|
-
const
|
|
880
|
-
const workspace = getWorkspacePath(
|
|
881
|
-
const pluginRegistry = this.loadPluginRegistry(
|
|
1092
|
+
const config2 = loadConfig();
|
|
1093
|
+
const workspace = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1094
|
+
const pluginRegistry = this.loadPluginRegistry(config2, workspace);
|
|
882
1095
|
const extensionRegistry = this.toExtensionRegistry(pluginRegistry);
|
|
883
1096
|
this.logPluginDiagnostics(pluginRegistry);
|
|
884
1097
|
const bus = new MessageBus();
|
|
885
|
-
const provider = this.makeProvider(
|
|
1098
|
+
const provider = this.makeProvider(config2);
|
|
886
1099
|
const providerManager = new ProviderManager(provider);
|
|
887
1100
|
const agentLoop = new AgentLoop({
|
|
888
1101
|
bus,
|
|
889
1102
|
providerManager,
|
|
890
1103
|
workspace,
|
|
891
|
-
braveApiKey:
|
|
892
|
-
execConfig:
|
|
893
|
-
restrictToWorkspace:
|
|
894
|
-
contextConfig:
|
|
895
|
-
config,
|
|
1104
|
+
braveApiKey: config2.tools.web.search.apiKey || void 0,
|
|
1105
|
+
execConfig: config2.tools.exec,
|
|
1106
|
+
restrictToWorkspace: config2.tools.restrictToWorkspace,
|
|
1107
|
+
contextConfig: config2.agents.context,
|
|
1108
|
+
config: config2,
|
|
896
1109
|
extensionRegistry,
|
|
897
1110
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
898
1111
|
registry: pluginRegistry,
|
|
@@ -978,12 +1191,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
978
1191
|
}
|
|
979
1192
|
}
|
|
980
1193
|
pluginsList(opts = {}) {
|
|
981
|
-
const
|
|
982
|
-
const workspaceDir = getWorkspacePath(
|
|
1194
|
+
const config2 = loadConfig();
|
|
1195
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
983
1196
|
const report = buildPluginStatusReport({
|
|
984
|
-
config,
|
|
1197
|
+
config: config2,
|
|
985
1198
|
workspaceDir,
|
|
986
|
-
reservedChannelIds: Object.keys(
|
|
1199
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
987
1200
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
988
1201
|
});
|
|
989
1202
|
const list = opts.enabled ? report.plugins.filter((plugin) => plugin.status === "loaded") : report.plugins;
|
|
@@ -1035,12 +1248,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1035
1248
|
}
|
|
1036
1249
|
}
|
|
1037
1250
|
pluginsInfo(id, opts = {}) {
|
|
1038
|
-
const
|
|
1039
|
-
const workspaceDir = getWorkspacePath(
|
|
1251
|
+
const config2 = loadConfig();
|
|
1252
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1040
1253
|
const report = buildPluginStatusReport({
|
|
1041
|
-
config,
|
|
1254
|
+
config: config2,
|
|
1042
1255
|
workspaceDir,
|
|
1043
|
-
reservedChannelIds: Object.keys(
|
|
1256
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1044
1257
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1045
1258
|
});
|
|
1046
1259
|
const plugin = report.plugins.find((entry) => entry.id === id || entry.name === id);
|
|
@@ -1052,7 +1265,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1052
1265
|
console.log(JSON.stringify(plugin, null, 2));
|
|
1053
1266
|
return;
|
|
1054
1267
|
}
|
|
1055
|
-
const install =
|
|
1268
|
+
const install = config2.plugins.installs?.[plugin.id];
|
|
1056
1269
|
const lines = [];
|
|
1057
1270
|
lines.push(plugin.name || plugin.id);
|
|
1058
1271
|
if (plugin.name && plugin.name !== plugin.id) {
|
|
@@ -1101,25 +1314,98 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1101
1314
|
}
|
|
1102
1315
|
console.log(lines.join("\n"));
|
|
1103
1316
|
}
|
|
1317
|
+
configGet(pathExpr, opts = {}) {
|
|
1318
|
+
const config2 = loadConfig();
|
|
1319
|
+
let parsedPath;
|
|
1320
|
+
try {
|
|
1321
|
+
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
console.error(String(error));
|
|
1324
|
+
process.exit(1);
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
const result = getAtConfigPath(config2, parsedPath);
|
|
1328
|
+
if (!result.found) {
|
|
1329
|
+
console.error(`Config path not found: ${pathExpr}`);
|
|
1330
|
+
process.exit(1);
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
if (opts.json) {
|
|
1334
|
+
console.log(JSON.stringify(result.value ?? null, null, 2));
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
if (typeof result.value === "string" || typeof result.value === "number" || typeof result.value === "boolean") {
|
|
1338
|
+
console.log(String(result.value));
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
console.log(JSON.stringify(result.value ?? null, null, 2));
|
|
1342
|
+
}
|
|
1343
|
+
configSet(pathExpr, value, opts = {}) {
|
|
1344
|
+
let parsedPath;
|
|
1345
|
+
try {
|
|
1346
|
+
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
console.error(String(error));
|
|
1349
|
+
process.exit(1);
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
let parsedValue;
|
|
1353
|
+
try {
|
|
1354
|
+
parsedValue = parseConfigSetValue(value, opts);
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
console.error(`Failed to parse config value: ${String(error)}`);
|
|
1357
|
+
process.exit(1);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
const config2 = loadConfig();
|
|
1361
|
+
try {
|
|
1362
|
+
setAtConfigPath(config2, parsedPath, parsedValue);
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
console.error(String(error));
|
|
1365
|
+
process.exit(1);
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
saveConfig(config2);
|
|
1369
|
+
console.log(`Updated ${pathExpr}. Restart the gateway to apply.`);
|
|
1370
|
+
}
|
|
1371
|
+
configUnset(pathExpr) {
|
|
1372
|
+
let parsedPath;
|
|
1373
|
+
try {
|
|
1374
|
+
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
1375
|
+
} catch (error) {
|
|
1376
|
+
console.error(String(error));
|
|
1377
|
+
process.exit(1);
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const config2 = loadConfig();
|
|
1381
|
+
const removed = unsetAtConfigPath(config2, parsedPath);
|
|
1382
|
+
if (!removed) {
|
|
1383
|
+
console.error(`Config path not found: ${pathExpr}`);
|
|
1384
|
+
process.exit(1);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
saveConfig(config2);
|
|
1388
|
+
console.log(`Removed ${pathExpr}. Restart the gateway to apply.`);
|
|
1389
|
+
}
|
|
1104
1390
|
pluginsEnable(id) {
|
|
1105
|
-
const
|
|
1106
|
-
const next = enablePluginInConfig(
|
|
1391
|
+
const config2 = loadConfig();
|
|
1392
|
+
const next = enablePluginInConfig(config2, id);
|
|
1107
1393
|
saveConfig(next);
|
|
1108
1394
|
console.log(`Enabled plugin "${id}". Restart the gateway to apply.`);
|
|
1109
1395
|
}
|
|
1110
1396
|
pluginsDisable(id) {
|
|
1111
|
-
const
|
|
1112
|
-
const next = disablePluginInConfig(
|
|
1397
|
+
const config2 = loadConfig();
|
|
1398
|
+
const next = disablePluginInConfig(config2, id);
|
|
1113
1399
|
saveConfig(next);
|
|
1114
1400
|
console.log(`Disabled plugin "${id}". Restart the gateway to apply.`);
|
|
1115
1401
|
}
|
|
1116
1402
|
async pluginsUninstall(id, opts = {}) {
|
|
1117
|
-
const
|
|
1118
|
-
const workspaceDir = getWorkspacePath(
|
|
1403
|
+
const config2 = loadConfig();
|
|
1404
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1119
1405
|
const report = buildPluginStatusReport({
|
|
1120
|
-
config,
|
|
1406
|
+
config: config2,
|
|
1121
1407
|
workspaceDir,
|
|
1122
|
-
reservedChannelIds: Object.keys(
|
|
1408
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1123
1409
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1124
1410
|
});
|
|
1125
1411
|
const keepFiles = Boolean(opts.keepFiles || opts.keepConfig);
|
|
@@ -1128,8 +1414,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1128
1414
|
}
|
|
1129
1415
|
const plugin = report.plugins.find((entry) => entry.id === id || entry.name === id);
|
|
1130
1416
|
const pluginId = plugin?.id ?? id;
|
|
1131
|
-
const hasEntry = pluginId in (
|
|
1132
|
-
const hasInstall = pluginId in (
|
|
1417
|
+
const hasEntry = pluginId in (config2.plugins.entries ?? {});
|
|
1418
|
+
const hasInstall = pluginId in (config2.plugins.installs ?? {});
|
|
1133
1419
|
if (!hasEntry && !hasInstall) {
|
|
1134
1420
|
if (plugin) {
|
|
1135
1421
|
console.error(
|
|
@@ -1140,8 +1426,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1140
1426
|
}
|
|
1141
1427
|
process.exit(1);
|
|
1142
1428
|
}
|
|
1143
|
-
const install =
|
|
1144
|
-
const isLinked = install?.source === "path";
|
|
1429
|
+
const install = config2.plugins.installs?.[pluginId];
|
|
1430
|
+
const isLinked = install?.source === "path" && (!install.installPath || !install.sourcePath || resolve4(install.installPath) === resolve4(install.sourcePath));
|
|
1145
1431
|
const preview = [];
|
|
1146
1432
|
if (hasEntry) {
|
|
1147
1433
|
preview.push("config entry");
|
|
@@ -1149,10 +1435,10 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1149
1435
|
if (hasInstall) {
|
|
1150
1436
|
preview.push("install record");
|
|
1151
1437
|
}
|
|
1152
|
-
if (
|
|
1438
|
+
if (config2.plugins.allow?.includes(pluginId)) {
|
|
1153
1439
|
preview.push("allowlist entry");
|
|
1154
1440
|
}
|
|
1155
|
-
if (isLinked && install?.sourcePath &&
|
|
1441
|
+
if (isLinked && install?.sourcePath && config2.plugins.load?.paths?.includes(install.sourcePath)) {
|
|
1156
1442
|
preview.push("load path");
|
|
1157
1443
|
}
|
|
1158
1444
|
const deleteTarget = !keepFiles ? resolveUninstallDirectoryTarget({
|
|
@@ -1179,7 +1465,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1179
1465
|
}
|
|
1180
1466
|
}
|
|
1181
1467
|
const result = await uninstallPlugin({
|
|
1182
|
-
config,
|
|
1468
|
+
config: config2,
|
|
1183
1469
|
pluginId,
|
|
1184
1470
|
deleteFiles: !keepFiles
|
|
1185
1471
|
});
|
|
@@ -1218,7 +1504,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1218
1504
|
}
|
|
1219
1505
|
const normalized = fileSpec && fileSpec.ok ? fileSpec.path : pathOrSpec;
|
|
1220
1506
|
const resolved = resolve4(expandHome(normalized));
|
|
1221
|
-
const
|
|
1507
|
+
const config2 = loadConfig();
|
|
1222
1508
|
if (existsSync4(resolved)) {
|
|
1223
1509
|
if (opts.link) {
|
|
1224
1510
|
const probe = await installPluginFromPath({ path: resolved, dryRun: true });
|
|
@@ -1226,7 +1512,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1226
1512
|
console.error(probe.error);
|
|
1227
1513
|
process.exit(1);
|
|
1228
1514
|
}
|
|
1229
|
-
let next3 = addPluginLoadPath(
|
|
1515
|
+
let next3 = addPluginLoadPath(config2, resolved);
|
|
1230
1516
|
next3 = enablePluginInConfig(next3, probe.pluginId);
|
|
1231
1517
|
next3 = recordPluginInstall(next3, {
|
|
1232
1518
|
pluginId: probe.pluginId,
|
|
@@ -1251,7 +1537,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1251
1537
|
console.error(result2.error);
|
|
1252
1538
|
process.exit(1);
|
|
1253
1539
|
}
|
|
1254
|
-
let next2 = enablePluginInConfig(
|
|
1540
|
+
let next2 = enablePluginInConfig(config2, result2.pluginId);
|
|
1255
1541
|
next2 = recordPluginInstall(next2, {
|
|
1256
1542
|
pluginId: result2.pluginId,
|
|
1257
1543
|
source: this.isArchivePath(resolved) ? "archive" : "path",
|
|
@@ -1283,7 +1569,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1283
1569
|
console.error(result.error);
|
|
1284
1570
|
process.exit(1);
|
|
1285
1571
|
}
|
|
1286
|
-
let next = enablePluginInConfig(
|
|
1572
|
+
let next = enablePluginInConfig(config2, result.pluginId);
|
|
1287
1573
|
next = recordPluginInstall(next, {
|
|
1288
1574
|
pluginId: result.pluginId,
|
|
1289
1575
|
source: "npm",
|
|
@@ -1296,12 +1582,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1296
1582
|
console.log("Restart the gateway to load plugins.");
|
|
1297
1583
|
}
|
|
1298
1584
|
pluginsDoctor() {
|
|
1299
|
-
const
|
|
1300
|
-
const workspaceDir = getWorkspacePath(
|
|
1585
|
+
const config2 = loadConfig();
|
|
1586
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1301
1587
|
const report = buildPluginStatusReport({
|
|
1302
|
-
config,
|
|
1588
|
+
config: config2,
|
|
1303
1589
|
workspaceDir,
|
|
1304
|
-
reservedChannelIds: Object.keys(
|
|
1590
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1305
1591
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1306
1592
|
});
|
|
1307
1593
|
const pluginErrors = report.plugins.filter((plugin) => plugin.status === "error");
|
|
@@ -1349,20 +1635,20 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1349
1635
|
console.log(` Path: ${result.destinationDir}`);
|
|
1350
1636
|
}
|
|
1351
1637
|
channelsStatus() {
|
|
1352
|
-
const
|
|
1638
|
+
const config2 = loadConfig();
|
|
1353
1639
|
console.log("Channel Status");
|
|
1354
|
-
console.log(`WhatsApp: ${
|
|
1355
|
-
console.log(`Discord: ${
|
|
1356
|
-
console.log(`Feishu: ${
|
|
1357
|
-
console.log(`Mochat: ${
|
|
1358
|
-
console.log(`Telegram: ${
|
|
1359
|
-
console.log(`Slack: ${
|
|
1360
|
-
console.log(`QQ: ${
|
|
1361
|
-
const workspaceDir = getWorkspacePath(
|
|
1640
|
+
console.log(`WhatsApp: ${config2.channels.whatsapp.enabled ? "\u2713" : "\u2717"}`);
|
|
1641
|
+
console.log(`Discord: ${config2.channels.discord.enabled ? "\u2713" : "\u2717"}`);
|
|
1642
|
+
console.log(`Feishu: ${config2.channels.feishu.enabled ? "\u2713" : "\u2717"}`);
|
|
1643
|
+
console.log(`Mochat: ${config2.channels.mochat.enabled ? "\u2713" : "\u2717"}`);
|
|
1644
|
+
console.log(`Telegram: ${config2.channels.telegram.enabled ? "\u2713" : "\u2717"}`);
|
|
1645
|
+
console.log(`Slack: ${config2.channels.slack.enabled ? "\u2713" : "\u2717"}`);
|
|
1646
|
+
console.log(`QQ: ${config2.channels.qq.enabled ? "\u2713" : "\u2717"}`);
|
|
1647
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1362
1648
|
const report = buildPluginStatusReport({
|
|
1363
|
-
config,
|
|
1649
|
+
config: config2,
|
|
1364
1650
|
workspaceDir,
|
|
1365
|
-
reservedChannelIds: Object.keys(
|
|
1651
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1366
1652
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
1367
1653
|
});
|
|
1368
1654
|
const pluginChannels = report.plugins.filter((plugin) => plugin.status === "loaded" && plugin.channelIds.length > 0);
|
|
@@ -1389,9 +1675,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1389
1675
|
console.error("--channel is required");
|
|
1390
1676
|
process.exit(1);
|
|
1391
1677
|
}
|
|
1392
|
-
const
|
|
1393
|
-
const workspaceDir = getWorkspacePath(
|
|
1394
|
-
const pluginRegistry = this.loadPluginRegistry(
|
|
1678
|
+
const config2 = loadConfig();
|
|
1679
|
+
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1680
|
+
const pluginRegistry = this.loadPluginRegistry(config2, workspaceDir);
|
|
1395
1681
|
const bindings = getPluginChannelBindings(pluginRegistry);
|
|
1396
1682
|
const binding = bindings.find((entry) => entry.channelId === channelId || entry.pluginId === channelId);
|
|
1397
1683
|
if (!binding) {
|
|
@@ -1410,7 +1696,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1410
1696
|
url: opts.url,
|
|
1411
1697
|
httpUrl: opts.httpUrl
|
|
1412
1698
|
};
|
|
1413
|
-
const currentView = this.toPluginConfigView(
|
|
1699
|
+
const currentView = this.toPluginConfigView(config2, bindings);
|
|
1414
1700
|
const accountId = binding.channel.config?.defaultAccountId?.(currentView) ?? "default";
|
|
1415
1701
|
const validateError = setup.validateInput?.({
|
|
1416
1702
|
cfg: currentView,
|
|
@@ -1430,17 +1716,17 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1430
1716
|
console.error("Channel setup returned invalid config payload.");
|
|
1431
1717
|
process.exit(1);
|
|
1432
1718
|
}
|
|
1433
|
-
let next = this.mergePluginConfigView(
|
|
1719
|
+
let next = this.mergePluginConfigView(config2, nextView, bindings);
|
|
1434
1720
|
next = enablePluginInConfig(next, binding.pluginId);
|
|
1435
1721
|
saveConfig(next);
|
|
1436
1722
|
console.log(`Configured channel "${binding.channelId}" via plugin "${binding.pluginId}".`);
|
|
1437
1723
|
console.log("Restart the gateway to apply changes.");
|
|
1438
1724
|
}
|
|
1439
|
-
toPluginConfigView(
|
|
1440
|
-
const view = JSON.parse(JSON.stringify(
|
|
1725
|
+
toPluginConfigView(config2, bindings) {
|
|
1726
|
+
const view = JSON.parse(JSON.stringify(config2));
|
|
1441
1727
|
const channels2 = view.channels && typeof view.channels === "object" && !Array.isArray(view.channels) ? { ...view.channels } : {};
|
|
1442
1728
|
for (const binding of bindings) {
|
|
1443
|
-
const pluginConfig =
|
|
1729
|
+
const pluginConfig = config2.plugins.entries?.[binding.pluginId]?.config;
|
|
1444
1730
|
if (!pluginConfig || typeof pluginConfig !== "object" || Array.isArray(pluginConfig)) {
|
|
1445
1731
|
continue;
|
|
1446
1732
|
}
|
|
@@ -1544,15 +1830,15 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1544
1830
|
}
|
|
1545
1831
|
status() {
|
|
1546
1832
|
const configPath = getConfigPath();
|
|
1547
|
-
const
|
|
1548
|
-
const workspace = getWorkspacePath(
|
|
1833
|
+
const config2 = loadConfig();
|
|
1834
|
+
const workspace = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1549
1835
|
console.log(`${this.logo} ${APP_NAME} Status
|
|
1550
1836
|
`);
|
|
1551
1837
|
console.log(`Config: ${configPath} ${existsSync4(configPath) ? "\u2713" : "\u2717"}`);
|
|
1552
1838
|
console.log(`Workspace: ${workspace} ${existsSync4(workspace) ? "\u2713" : "\u2717"}`);
|
|
1553
|
-
console.log(`Model: ${
|
|
1839
|
+
console.log(`Model: ${config2.agents.defaults.model}`);
|
|
1554
1840
|
for (const spec of PROVIDERS) {
|
|
1555
|
-
const provider =
|
|
1841
|
+
const provider = config2.providers[spec.name];
|
|
1556
1842
|
if (!provider) {
|
|
1557
1843
|
continue;
|
|
1558
1844
|
}
|
|
@@ -1563,9 +1849,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1563
1849
|
}
|
|
1564
1850
|
}
|
|
1565
1851
|
}
|
|
1566
|
-
loadPluginRegistry(
|
|
1852
|
+
loadPluginRegistry(config2, workspaceDir) {
|
|
1567
1853
|
return loadOpenClawPlugins({
|
|
1568
|
-
config,
|
|
1854
|
+
config: config2,
|
|
1569
1855
|
workspaceDir,
|
|
1570
1856
|
reservedToolNames: [
|
|
1571
1857
|
"read_file",
|
|
@@ -1586,7 +1872,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1586
1872
|
"gateway",
|
|
1587
1873
|
"cron"
|
|
1588
1874
|
],
|
|
1589
|
-
reservedChannelIds: Object.keys(
|
|
1875
|
+
reservedChannelIds: Object.keys(config2.channels),
|
|
1590
1876
|
reservedProviderIds: PROVIDERS.map((provider) => provider.name),
|
|
1591
1877
|
logger: {
|
|
1592
1878
|
info: (message) => console.log(message),
|
|
@@ -1630,19 +1916,19 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1630
1916
|
}
|
|
1631
1917
|
}
|
|
1632
1918
|
async startGateway(options = {}) {
|
|
1633
|
-
const
|
|
1634
|
-
const workspace = getWorkspacePath(
|
|
1635
|
-
const pluginRegistry = this.loadPluginRegistry(
|
|
1919
|
+
const config2 = loadConfig();
|
|
1920
|
+
const workspace = getWorkspacePath(config2.agents.defaults.workspace);
|
|
1921
|
+
const pluginRegistry = this.loadPluginRegistry(config2, workspace);
|
|
1636
1922
|
const extensionRegistry = this.toExtensionRegistry(pluginRegistry);
|
|
1637
1923
|
this.logPluginDiagnostics(pluginRegistry);
|
|
1638
1924
|
const bus = new MessageBus();
|
|
1639
|
-
const provider = options.allowMissingProvider === true ? this.makeProvider(
|
|
1925
|
+
const provider = options.allowMissingProvider === true ? this.makeProvider(config2, { allowMissing: true }) : this.makeProvider(config2);
|
|
1640
1926
|
const providerManager = provider ? new ProviderManager(provider) : null;
|
|
1641
1927
|
const sessionManager = new SessionManager(workspace);
|
|
1642
1928
|
const cronStorePath = join3(getDataDir2(), "cron", "jobs.json");
|
|
1643
1929
|
const cron2 = new CronService(cronStorePath);
|
|
1644
1930
|
const pluginUiMetadata = getPluginUiMetadataFromRegistry(pluginRegistry);
|
|
1645
|
-
const uiConfig = resolveUiConfig(
|
|
1931
|
+
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
1646
1932
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
1647
1933
|
if (!provider) {
|
|
1648
1934
|
this.startUiIfEnabled(uiConfig, uiStaticDir);
|
|
@@ -1651,9 +1937,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1651
1937
|
});
|
|
1652
1938
|
return;
|
|
1653
1939
|
}
|
|
1654
|
-
const channels2 = new ChannelManager(
|
|
1940
|
+
const channels2 = new ChannelManager(config2, bus, sessionManager, extensionRegistry.channels);
|
|
1655
1941
|
const reloader = new ConfigReloader({
|
|
1656
|
-
initialConfig:
|
|
1942
|
+
initialConfig: config2,
|
|
1657
1943
|
channels: channels2,
|
|
1658
1944
|
bus,
|
|
1659
1945
|
sessionManager,
|
|
@@ -1676,16 +1962,16 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1676
1962
|
bus,
|
|
1677
1963
|
providerManager: providerManager ?? new ProviderManager(provider),
|
|
1678
1964
|
workspace,
|
|
1679
|
-
model:
|
|
1680
|
-
maxIterations:
|
|
1681
|
-
braveApiKey:
|
|
1682
|
-
execConfig:
|
|
1965
|
+
model: config2.agents.defaults.model,
|
|
1966
|
+
maxIterations: config2.agents.defaults.maxToolIterations,
|
|
1967
|
+
braveApiKey: config2.tools.web.search.apiKey || void 0,
|
|
1968
|
+
execConfig: config2.tools.exec,
|
|
1683
1969
|
cronService: cron2,
|
|
1684
|
-
restrictToWorkspace:
|
|
1970
|
+
restrictToWorkspace: config2.tools.restrictToWorkspace,
|
|
1685
1971
|
sessionManager,
|
|
1686
|
-
contextConfig:
|
|
1972
|
+
contextConfig: config2.agents.context,
|
|
1687
1973
|
gatewayController,
|
|
1688
|
-
config,
|
|
1974
|
+
config: config2,
|
|
1689
1975
|
extensionRegistry,
|
|
1690
1976
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
1691
1977
|
registry: pluginRegistry,
|
|
@@ -1825,8 +2111,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1825
2111
|
}
|
|
1826
2112
|
}
|
|
1827
2113
|
async runForeground(options) {
|
|
1828
|
-
const
|
|
1829
|
-
const uiConfig = resolveUiConfig(
|
|
2114
|
+
const config2 = loadConfig();
|
|
2115
|
+
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
1830
2116
|
const shouldStartFrontend = options.frontend;
|
|
1831
2117
|
const frontendPort = Number.isFinite(options.frontendPort) ? options.frontendPort : 5173;
|
|
1832
2118
|
const frontendDir = shouldStartFrontend ? resolveUiFrontendDir() : null;
|
|
@@ -1858,8 +2144,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1858
2144
|
});
|
|
1859
2145
|
}
|
|
1860
2146
|
async startService(options) {
|
|
1861
|
-
const
|
|
1862
|
-
const uiConfig = resolveUiConfig(
|
|
2147
|
+
const config2 = loadConfig();
|
|
2148
|
+
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
1863
2149
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
1864
2150
|
const apiUrl = `${uiUrl}/api`;
|
|
1865
2151
|
const staticDir = resolveUiStaticDir();
|
|
@@ -1959,9 +2245,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1959
2245
|
const normalized = answer.trim().toLowerCase();
|
|
1960
2246
|
return normalized === "y" || normalized === "yes";
|
|
1961
2247
|
}
|
|
1962
|
-
makeProvider(
|
|
1963
|
-
const provider = getProvider(
|
|
1964
|
-
const model =
|
|
2248
|
+
makeProvider(config2, options) {
|
|
2249
|
+
const provider = getProvider(config2);
|
|
2250
|
+
const model = config2.agents.defaults.model;
|
|
1965
2251
|
if (!provider?.apiKey && !model.startsWith("bedrock/")) {
|
|
1966
2252
|
if (options?.allowMissing) {
|
|
1967
2253
|
return null;
|
|
@@ -1972,10 +2258,10 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1972
2258
|
}
|
|
1973
2259
|
return new LiteLLMProvider({
|
|
1974
2260
|
apiKey: provider?.apiKey ?? null,
|
|
1975
|
-
apiBase: getApiBase(
|
|
2261
|
+
apiBase: getApiBase(config2),
|
|
1976
2262
|
defaultModel: model,
|
|
1977
2263
|
extraHeaders: provider?.extraHeaders ?? null,
|
|
1978
|
-
providerName: getProviderName(
|
|
2264
|
+
providerName: getProviderName(config2),
|
|
1979
2265
|
wireApi: provider?.wireApi ?? null
|
|
1980
2266
|
});
|
|
1981
2267
|
}
|
|
@@ -2203,6 +2489,10 @@ plugins.command("disable <id>").description("Disable a plugin in config").action
|
|
|
2203
2489
|
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));
|
|
2204
2490
|
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));
|
|
2205
2491
|
plugins.command("doctor").description("Report plugin load issues").action(() => runtime.pluginsDoctor());
|
|
2492
|
+
var config = program.command("config").description("Manage config values");
|
|
2493
|
+
config.command("get <path>").description("Get a config value by dot path").option("--json", "Output JSON", false).action((path, opts) => runtime.configGet(path, opts));
|
|
2494
|
+
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));
|
|
2495
|
+
config.command("unset <path>").description("Remove a config value by dot path").action((path) => runtime.configUnset(path));
|
|
2206
2496
|
var channels = program.command("channels").description("Manage channels");
|
|
2207
2497
|
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));
|
|
2208
2498
|
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.13",
|
|
4
4
|
"description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"chokidar": "^3.6.0",
|
|
40
40
|
"commander": "^12.1.0",
|
|
41
|
-
"@nextclaw/core": "^0.4.
|
|
41
|
+
"@nextclaw/core": "^0.4.10",
|
|
42
42
|
"@nextclaw/server": "^0.3.5",
|
|
43
43
|
"@nextclaw/openclaw-compat": "^0.1.2"
|
|
44
44
|
},
|
|
@@ -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",
|