nextclaw 0.5.6 → 0.6.1
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 +101 -851
- package/package.json +3 -4
- package/templates/USAGE.md +11 -46
package/dist/cli/index.js
CHANGED
|
@@ -6,13 +6,13 @@ import { APP_NAME as APP_NAME5, APP_TAGLINE } from "@nextclaw/core";
|
|
|
6
6
|
|
|
7
7
|
// src/cli/runtime.ts
|
|
8
8
|
import {
|
|
9
|
-
loadConfig as
|
|
10
|
-
saveConfig as
|
|
9
|
+
loadConfig as loadConfig5,
|
|
10
|
+
saveConfig as saveConfig3,
|
|
11
11
|
getConfigPath as getConfigPath3,
|
|
12
12
|
getDataDir as getDataDir6,
|
|
13
13
|
ConfigSchema as ConfigSchema2,
|
|
14
|
-
getWorkspacePath as
|
|
15
|
-
expandHome
|
|
14
|
+
getWorkspacePath as getWorkspacePath3,
|
|
15
|
+
expandHome,
|
|
16
16
|
MessageBus as MessageBus2,
|
|
17
17
|
AgentLoop as AgentLoop2,
|
|
18
18
|
ProviderManager as ProviderManager2,
|
|
@@ -20,10 +20,9 @@ import {
|
|
|
20
20
|
DEFAULT_WORKSPACE_DIR,
|
|
21
21
|
DEFAULT_WORKSPACE_PATH
|
|
22
22
|
} from "@nextclaw/core";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { createInterface as createInterface2 } from "readline";
|
|
23
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
24
|
+
import { join as join6, resolve as resolve7 } from "path";
|
|
25
|
+
import { createInterface } from "readline";
|
|
27
26
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28
27
|
import { spawn as spawn3 } from "child_process";
|
|
29
28
|
|
|
@@ -255,7 +254,7 @@ async function waitForExit(pid, timeoutMs) {
|
|
|
255
254
|
if (!isProcessRunning(pid)) {
|
|
256
255
|
return true;
|
|
257
256
|
}
|
|
258
|
-
await new Promise((
|
|
257
|
+
await new Promise((resolve8) => setTimeout(resolve8, 200));
|
|
259
258
|
}
|
|
260
259
|
return !isProcessRunning(pid);
|
|
261
260
|
}
|
|
@@ -345,8 +344,8 @@ function printAgentResponse(response) {
|
|
|
345
344
|
async function prompt(rl, question) {
|
|
346
345
|
rl.setPrompt(question);
|
|
347
346
|
rl.prompt();
|
|
348
|
-
return new Promise((
|
|
349
|
-
rl.once("line", (line) =>
|
|
347
|
+
return new Promise((resolve8) => {
|
|
348
|
+
rl.once("line", (line) => resolve8(line));
|
|
350
349
|
});
|
|
351
350
|
}
|
|
352
351
|
|
|
@@ -392,549 +391,8 @@ function runSelfUpdate(options = {}) {
|
|
|
392
391
|
return { ok: false, error: "no update strategy available", strategy: "none", steps };
|
|
393
392
|
}
|
|
394
393
|
|
|
395
|
-
// src/cli/commands/plugins.ts
|
|
396
|
-
import {
|
|
397
|
-
addPluginLoadPath,
|
|
398
|
-
buildPluginStatusReport,
|
|
399
|
-
disablePluginInConfig,
|
|
400
|
-
enablePluginInConfig,
|
|
401
|
-
installPluginFromNpmSpec,
|
|
402
|
-
installPluginFromPath,
|
|
403
|
-
loadOpenClawPlugins,
|
|
404
|
-
recordPluginInstall,
|
|
405
|
-
resolveUninstallDirectoryTarget,
|
|
406
|
-
uninstallPlugin
|
|
407
|
-
} from "@nextclaw/openclaw-compat";
|
|
408
|
-
import {
|
|
409
|
-
loadConfig,
|
|
410
|
-
saveConfig,
|
|
411
|
-
getWorkspacePath,
|
|
412
|
-
PROVIDERS,
|
|
413
|
-
expandHome
|
|
414
|
-
} from "@nextclaw/core";
|
|
415
|
-
import { createInterface } from "readline";
|
|
416
|
-
import { existsSync as existsSync3 } from "fs";
|
|
417
|
-
import { resolve as resolve4 } from "path";
|
|
418
|
-
function loadPluginRegistry(config2, workspaceDir) {
|
|
419
|
-
return loadOpenClawPlugins({
|
|
420
|
-
config: config2,
|
|
421
|
-
workspaceDir,
|
|
422
|
-
reservedToolNames: [
|
|
423
|
-
"read_file",
|
|
424
|
-
"write_file",
|
|
425
|
-
"edit_file",
|
|
426
|
-
"list_dir",
|
|
427
|
-
"exec",
|
|
428
|
-
"web_search",
|
|
429
|
-
"web_fetch",
|
|
430
|
-
"message",
|
|
431
|
-
"spawn",
|
|
432
|
-
"sessions_list",
|
|
433
|
-
"sessions_history",
|
|
434
|
-
"sessions_send",
|
|
435
|
-
"memory_search",
|
|
436
|
-
"memory_get",
|
|
437
|
-
"subagents",
|
|
438
|
-
"gateway",
|
|
439
|
-
"cron"
|
|
440
|
-
],
|
|
441
|
-
reservedChannelIds: Object.keys(config2.channels),
|
|
442
|
-
reservedProviderIds: PROVIDERS.map((provider) => provider.name),
|
|
443
|
-
logger: {
|
|
444
|
-
info: (message) => console.log(message),
|
|
445
|
-
warn: (message) => console.warn(message),
|
|
446
|
-
error: (message) => console.error(message),
|
|
447
|
-
debug: (message) => console.debug(message)
|
|
448
|
-
}
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
function toExtensionRegistry(pluginRegistry) {
|
|
452
|
-
return {
|
|
453
|
-
tools: pluginRegistry.tools.map((tool) => ({
|
|
454
|
-
extensionId: tool.pluginId,
|
|
455
|
-
factory: tool.factory,
|
|
456
|
-
names: tool.names,
|
|
457
|
-
optional: tool.optional,
|
|
458
|
-
source: tool.source
|
|
459
|
-
})),
|
|
460
|
-
channels: pluginRegistry.channels.map((channel) => ({
|
|
461
|
-
extensionId: channel.pluginId,
|
|
462
|
-
channel: channel.channel,
|
|
463
|
-
source: channel.source
|
|
464
|
-
})),
|
|
465
|
-
diagnostics: pluginRegistry.diagnostics.map((diag) => ({
|
|
466
|
-
level: diag.level,
|
|
467
|
-
message: diag.message,
|
|
468
|
-
extensionId: diag.pluginId,
|
|
469
|
-
source: diag.source
|
|
470
|
-
}))
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
function logPluginDiagnostics(registry) {
|
|
474
|
-
for (const diag of registry.diagnostics) {
|
|
475
|
-
const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
|
|
476
|
-
const text = `${prefix}${diag.message}`;
|
|
477
|
-
if (diag.level === "error") {
|
|
478
|
-
console.error(`[plugins] ${text}`);
|
|
479
|
-
} else {
|
|
480
|
-
console.warn(`[plugins] ${text}`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
function toPluginConfigView(config2, bindings) {
|
|
485
|
-
const view = JSON.parse(JSON.stringify(config2));
|
|
486
|
-
const channels2 = view.channels && typeof view.channels === "object" && !Array.isArray(view.channels) ? { ...view.channels } : {};
|
|
487
|
-
for (const binding of bindings) {
|
|
488
|
-
const pluginConfig = config2.plugins.entries?.[binding.pluginId]?.config;
|
|
489
|
-
if (!pluginConfig || typeof pluginConfig !== "object" || Array.isArray(pluginConfig)) {
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
|
-
channels2[binding.channelId] = JSON.parse(JSON.stringify(pluginConfig));
|
|
493
|
-
}
|
|
494
|
-
view.channels = channels2;
|
|
495
|
-
return view;
|
|
496
|
-
}
|
|
497
|
-
function mergePluginConfigView(baseConfig, pluginViewConfig, bindings) {
|
|
498
|
-
const next = JSON.parse(JSON.stringify(baseConfig));
|
|
499
|
-
const pluginChannels = pluginViewConfig.channels && typeof pluginViewConfig.channels === "object" && !Array.isArray(pluginViewConfig.channels) ? pluginViewConfig.channels : {};
|
|
500
|
-
const entries = { ...next.plugins.entries ?? {} };
|
|
501
|
-
for (const binding of bindings) {
|
|
502
|
-
if (!Object.prototype.hasOwnProperty.call(pluginChannels, binding.channelId)) {
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
const channelConfig = pluginChannels[binding.channelId];
|
|
506
|
-
if (!channelConfig || typeof channelConfig !== "object" || Array.isArray(channelConfig)) {
|
|
507
|
-
continue;
|
|
508
|
-
}
|
|
509
|
-
entries[binding.pluginId] = {
|
|
510
|
-
...entries[binding.pluginId] ?? {},
|
|
511
|
-
config: channelConfig
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
next.plugins = {
|
|
515
|
-
...next.plugins,
|
|
516
|
-
entries
|
|
517
|
-
};
|
|
518
|
-
return next;
|
|
519
|
-
}
|
|
520
|
-
var PluginCommands = class {
|
|
521
|
-
constructor(deps) {
|
|
522
|
-
this.deps = deps;
|
|
523
|
-
}
|
|
524
|
-
pluginsList(opts = {}) {
|
|
525
|
-
const config2 = loadConfig();
|
|
526
|
-
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
527
|
-
const report = buildPluginStatusReport({
|
|
528
|
-
config: config2,
|
|
529
|
-
workspaceDir,
|
|
530
|
-
reservedChannelIds: Object.keys(config2.channels),
|
|
531
|
-
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
532
|
-
});
|
|
533
|
-
const list = opts.enabled ? report.plugins.filter((plugin) => plugin.status === "loaded") : report.plugins;
|
|
534
|
-
if (opts.json) {
|
|
535
|
-
console.log(
|
|
536
|
-
JSON.stringify(
|
|
537
|
-
{
|
|
538
|
-
workspaceDir,
|
|
539
|
-
plugins: list,
|
|
540
|
-
diagnostics: report.diagnostics
|
|
541
|
-
},
|
|
542
|
-
null,
|
|
543
|
-
2
|
|
544
|
-
)
|
|
545
|
-
);
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
if (list.length === 0) {
|
|
549
|
-
console.log("No plugins discovered.");
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
for (const plugin of list) {
|
|
553
|
-
const status = plugin.status === "loaded" ? "loaded" : plugin.status === "disabled" ? "disabled" : "error";
|
|
554
|
-
const title = plugin.name && plugin.name !== plugin.id ? `${plugin.name} (${plugin.id})` : plugin.id;
|
|
555
|
-
if (!opts.verbose) {
|
|
556
|
-
const desc = plugin.description ? plugin.description.length > 80 ? `${plugin.description.slice(0, 77)}...` : plugin.description : "(no description)";
|
|
557
|
-
console.log(`${title} ${status} - ${desc}`);
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
console.log(`${title} ${status}`);
|
|
561
|
-
console.log(` source: ${plugin.source}`);
|
|
562
|
-
console.log(` origin: ${plugin.origin}`);
|
|
563
|
-
if (plugin.version) {
|
|
564
|
-
console.log(` version: ${plugin.version}`);
|
|
565
|
-
}
|
|
566
|
-
if (plugin.toolNames.length > 0) {
|
|
567
|
-
console.log(` tools: ${plugin.toolNames.join(", ")}`);
|
|
568
|
-
}
|
|
569
|
-
if (plugin.channelIds.length > 0) {
|
|
570
|
-
console.log(` channels: ${plugin.channelIds.join(", ")}`);
|
|
571
|
-
}
|
|
572
|
-
if (plugin.providerIds.length > 0) {
|
|
573
|
-
console.log(` providers: ${plugin.providerIds.join(", ")}`);
|
|
574
|
-
}
|
|
575
|
-
if (plugin.error) {
|
|
576
|
-
console.log(` error: ${plugin.error}`);
|
|
577
|
-
}
|
|
578
|
-
console.log("");
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
pluginsInfo(id, opts = {}) {
|
|
582
|
-
const config2 = loadConfig();
|
|
583
|
-
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
584
|
-
const report = buildPluginStatusReport({
|
|
585
|
-
config: config2,
|
|
586
|
-
workspaceDir,
|
|
587
|
-
reservedChannelIds: Object.keys(config2.channels),
|
|
588
|
-
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
589
|
-
});
|
|
590
|
-
const plugin = report.plugins.find((entry) => entry.id === id || entry.name === id);
|
|
591
|
-
if (!plugin) {
|
|
592
|
-
console.error(`Plugin not found: ${id}`);
|
|
593
|
-
process.exit(1);
|
|
594
|
-
}
|
|
595
|
-
if (opts.json) {
|
|
596
|
-
console.log(JSON.stringify(plugin, null, 2));
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
const install = config2.plugins.installs?.[plugin.id];
|
|
600
|
-
const lines = [];
|
|
601
|
-
lines.push(plugin.name || plugin.id);
|
|
602
|
-
if (plugin.name && plugin.name !== plugin.id) {
|
|
603
|
-
lines.push(`id: ${plugin.id}`);
|
|
604
|
-
}
|
|
605
|
-
if (plugin.description) {
|
|
606
|
-
lines.push(plugin.description);
|
|
607
|
-
}
|
|
608
|
-
lines.push("");
|
|
609
|
-
lines.push(`Status: ${plugin.status}`);
|
|
610
|
-
lines.push(`Source: ${plugin.source}`);
|
|
611
|
-
lines.push(`Origin: ${plugin.origin}`);
|
|
612
|
-
if (plugin.version) {
|
|
613
|
-
lines.push(`Version: ${plugin.version}`);
|
|
614
|
-
}
|
|
615
|
-
if (plugin.toolNames.length > 0) {
|
|
616
|
-
lines.push(`Tools: ${plugin.toolNames.join(", ")}`);
|
|
617
|
-
}
|
|
618
|
-
if (plugin.channelIds.length > 0) {
|
|
619
|
-
lines.push(`Channels: ${plugin.channelIds.join(", ")}`);
|
|
620
|
-
}
|
|
621
|
-
if (plugin.providerIds.length > 0) {
|
|
622
|
-
lines.push(`Providers: ${plugin.providerIds.join(", ")}`);
|
|
623
|
-
}
|
|
624
|
-
if (plugin.error) {
|
|
625
|
-
lines.push(`Error: ${plugin.error}`);
|
|
626
|
-
}
|
|
627
|
-
if (install) {
|
|
628
|
-
lines.push("");
|
|
629
|
-
lines.push(`Install: ${install.source}`);
|
|
630
|
-
if (install.spec) {
|
|
631
|
-
lines.push(`Spec: ${install.spec}`);
|
|
632
|
-
}
|
|
633
|
-
if (install.sourcePath) {
|
|
634
|
-
lines.push(`Source path: ${install.sourcePath}`);
|
|
635
|
-
}
|
|
636
|
-
if (install.installPath) {
|
|
637
|
-
lines.push(`Install path: ${install.installPath}`);
|
|
638
|
-
}
|
|
639
|
-
if (install.version) {
|
|
640
|
-
lines.push(`Recorded version: ${install.version}`);
|
|
641
|
-
}
|
|
642
|
-
if (install.installedAt) {
|
|
643
|
-
lines.push(`Installed at: ${install.installedAt}`);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
console.log(lines.join("\n"));
|
|
647
|
-
}
|
|
648
|
-
async pluginsEnable(id) {
|
|
649
|
-
const config2 = loadConfig();
|
|
650
|
-
const next = enablePluginInConfig(config2, id);
|
|
651
|
-
saveConfig(next);
|
|
652
|
-
await this.deps.requestRestart({
|
|
653
|
-
reason: `plugin enabled: ${id}`,
|
|
654
|
-
manualMessage: `Enabled plugin "${id}". Restart the gateway to apply.`
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
async pluginsDisable(id) {
|
|
658
|
-
const config2 = loadConfig();
|
|
659
|
-
const next = disablePluginInConfig(config2, id);
|
|
660
|
-
saveConfig(next);
|
|
661
|
-
await this.deps.requestRestart({
|
|
662
|
-
reason: `plugin disabled: ${id}`,
|
|
663
|
-
manualMessage: `Disabled plugin "${id}". Restart the gateway to apply.`
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
async pluginsUninstall(id, opts = {}) {
|
|
667
|
-
const config2 = loadConfig();
|
|
668
|
-
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
669
|
-
const report = buildPluginStatusReport({
|
|
670
|
-
config: config2,
|
|
671
|
-
workspaceDir,
|
|
672
|
-
reservedChannelIds: Object.keys(config2.channels),
|
|
673
|
-
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
674
|
-
});
|
|
675
|
-
const keepFiles = Boolean(opts.keepFiles || opts.keepConfig);
|
|
676
|
-
if (opts.keepConfig) {
|
|
677
|
-
console.log("`--keep-config` is deprecated, use `--keep-files`.");
|
|
678
|
-
}
|
|
679
|
-
const plugin = report.plugins.find((entry) => entry.id === id || entry.name === id);
|
|
680
|
-
const pluginId = plugin?.id ?? id;
|
|
681
|
-
const hasEntry = pluginId in (config2.plugins.entries ?? {});
|
|
682
|
-
const hasInstall = pluginId in (config2.plugins.installs ?? {});
|
|
683
|
-
if (!hasEntry && !hasInstall) {
|
|
684
|
-
if (plugin) {
|
|
685
|
-
console.error(
|
|
686
|
-
`Plugin "${pluginId}" is not managed by plugins config/install records and cannot be uninstalled.`
|
|
687
|
-
);
|
|
688
|
-
} else {
|
|
689
|
-
console.error(`Plugin not found: ${id}`);
|
|
690
|
-
}
|
|
691
|
-
process.exit(1);
|
|
692
|
-
}
|
|
693
|
-
const install = config2.plugins.installs?.[pluginId];
|
|
694
|
-
const isLinked = install?.source === "path" && (!install.installPath || !install.sourcePath || resolve4(install.installPath) === resolve4(install.sourcePath));
|
|
695
|
-
const preview = [];
|
|
696
|
-
if (hasEntry) {
|
|
697
|
-
preview.push("config entry");
|
|
698
|
-
}
|
|
699
|
-
if (hasInstall) {
|
|
700
|
-
preview.push("install record");
|
|
701
|
-
}
|
|
702
|
-
if (config2.plugins.allow?.includes(pluginId)) {
|
|
703
|
-
preview.push("allowlist entry");
|
|
704
|
-
}
|
|
705
|
-
if (isLinked && install?.sourcePath && config2.plugins.load?.paths?.includes(install.sourcePath)) {
|
|
706
|
-
preview.push("load path");
|
|
707
|
-
}
|
|
708
|
-
const deleteTarget = !keepFiles ? resolveUninstallDirectoryTarget({
|
|
709
|
-
pluginId,
|
|
710
|
-
hasInstall,
|
|
711
|
-
installRecord: install
|
|
712
|
-
}) : null;
|
|
713
|
-
if (deleteTarget) {
|
|
714
|
-
preview.push(`directory: ${deleteTarget}`);
|
|
715
|
-
}
|
|
716
|
-
const pluginName = plugin?.name || pluginId;
|
|
717
|
-
const pluginTitle = pluginName !== pluginId ? `${pluginName} (${pluginId})` : pluginName;
|
|
718
|
-
console.log(`Plugin: ${pluginTitle}`);
|
|
719
|
-
console.log(`Will remove: ${preview.length > 0 ? preview.join(", ") : "(nothing)"}`);
|
|
720
|
-
if (opts.dryRun) {
|
|
721
|
-
console.log("Dry run, no changes made.");
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
if (!opts.force) {
|
|
725
|
-
const confirmed = await this.confirmYesNo(`Uninstall plugin "${pluginId}"?`);
|
|
726
|
-
if (!confirmed) {
|
|
727
|
-
console.log("Cancelled.");
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
const result = await uninstallPlugin({
|
|
732
|
-
config: config2,
|
|
733
|
-
pluginId,
|
|
734
|
-
deleteFiles: !keepFiles
|
|
735
|
-
});
|
|
736
|
-
if (!result.ok) {
|
|
737
|
-
console.error(result.error);
|
|
738
|
-
process.exit(1);
|
|
739
|
-
}
|
|
740
|
-
for (const warning of result.warnings) {
|
|
741
|
-
console.warn(warning);
|
|
742
|
-
}
|
|
743
|
-
saveConfig(result.config);
|
|
744
|
-
const removed = [];
|
|
745
|
-
if (result.actions.entry) {
|
|
746
|
-
removed.push("config entry");
|
|
747
|
-
}
|
|
748
|
-
if (result.actions.install) {
|
|
749
|
-
removed.push("install record");
|
|
750
|
-
}
|
|
751
|
-
if (result.actions.allowlist) {
|
|
752
|
-
removed.push("allowlist");
|
|
753
|
-
}
|
|
754
|
-
if (result.actions.loadPath) {
|
|
755
|
-
removed.push("load path");
|
|
756
|
-
}
|
|
757
|
-
if (result.actions.directory) {
|
|
758
|
-
removed.push("directory");
|
|
759
|
-
}
|
|
760
|
-
console.log(`Uninstalled plugin "${pluginId}". Removed: ${removed.length > 0 ? removed.join(", ") : "nothing"}.`);
|
|
761
|
-
await this.deps.requestRestart({
|
|
762
|
-
reason: `plugin uninstalled: ${pluginId}`,
|
|
763
|
-
manualMessage: "Restart the gateway to apply changes."
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
async pluginsInstall(pathOrSpec, opts = {}) {
|
|
767
|
-
const fileSpec = this.resolveFileNpmSpecToLocalPath(pathOrSpec);
|
|
768
|
-
if (fileSpec && !fileSpec.ok) {
|
|
769
|
-
console.error(fileSpec.error);
|
|
770
|
-
process.exit(1);
|
|
771
|
-
}
|
|
772
|
-
const normalized = fileSpec && fileSpec.ok ? fileSpec.path : pathOrSpec;
|
|
773
|
-
const resolved = resolve4(expandHome(normalized));
|
|
774
|
-
const config2 = loadConfig();
|
|
775
|
-
if (existsSync3(resolved)) {
|
|
776
|
-
if (opts.link) {
|
|
777
|
-
const probe = await installPluginFromPath({ path: resolved, dryRun: true });
|
|
778
|
-
if (!probe.ok) {
|
|
779
|
-
console.error(probe.error);
|
|
780
|
-
process.exit(1);
|
|
781
|
-
}
|
|
782
|
-
let next3 = addPluginLoadPath(config2, resolved);
|
|
783
|
-
next3 = enablePluginInConfig(next3, probe.pluginId);
|
|
784
|
-
next3 = recordPluginInstall(next3, {
|
|
785
|
-
pluginId: probe.pluginId,
|
|
786
|
-
source: "path",
|
|
787
|
-
sourcePath: resolved,
|
|
788
|
-
installPath: resolved,
|
|
789
|
-
version: probe.version
|
|
790
|
-
});
|
|
791
|
-
saveConfig(next3);
|
|
792
|
-
console.log(`Linked plugin path: ${resolved}`);
|
|
793
|
-
await this.deps.requestRestart({
|
|
794
|
-
reason: `plugin linked: ${probe.pluginId}`,
|
|
795
|
-
manualMessage: "Restart the gateway to load plugins."
|
|
796
|
-
});
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
const result2 = await installPluginFromPath({
|
|
800
|
-
path: resolved,
|
|
801
|
-
logger: {
|
|
802
|
-
info: (message) => console.log(message),
|
|
803
|
-
warn: (message) => console.warn(message)
|
|
804
|
-
}
|
|
805
|
-
});
|
|
806
|
-
if (!result2.ok) {
|
|
807
|
-
console.error(result2.error);
|
|
808
|
-
process.exit(1);
|
|
809
|
-
}
|
|
810
|
-
let next2 = enablePluginInConfig(config2, result2.pluginId);
|
|
811
|
-
next2 = recordPluginInstall(next2, {
|
|
812
|
-
pluginId: result2.pluginId,
|
|
813
|
-
source: this.isArchivePath(resolved) ? "archive" : "path",
|
|
814
|
-
sourcePath: resolved,
|
|
815
|
-
installPath: result2.targetDir,
|
|
816
|
-
version: result2.version
|
|
817
|
-
});
|
|
818
|
-
saveConfig(next2);
|
|
819
|
-
console.log(`Installed plugin: ${result2.pluginId}`);
|
|
820
|
-
await this.deps.requestRestart({
|
|
821
|
-
reason: `plugin installed: ${result2.pluginId}`,
|
|
822
|
-
manualMessage: "Restart the gateway to load plugins."
|
|
823
|
-
});
|
|
824
|
-
return;
|
|
825
|
-
}
|
|
826
|
-
if (opts.link) {
|
|
827
|
-
console.error("`--link` requires a local path.");
|
|
828
|
-
process.exit(1);
|
|
829
|
-
}
|
|
830
|
-
if (this.looksLikePath(pathOrSpec)) {
|
|
831
|
-
console.error(`Path not found: ${resolved}`);
|
|
832
|
-
process.exit(1);
|
|
833
|
-
}
|
|
834
|
-
const result = await installPluginFromNpmSpec({
|
|
835
|
-
spec: pathOrSpec,
|
|
836
|
-
logger: {
|
|
837
|
-
info: (message) => console.log(message),
|
|
838
|
-
warn: (message) => console.warn(message)
|
|
839
|
-
}
|
|
840
|
-
});
|
|
841
|
-
if (!result.ok) {
|
|
842
|
-
console.error(result.error);
|
|
843
|
-
process.exit(1);
|
|
844
|
-
}
|
|
845
|
-
let next = enablePluginInConfig(config2, result.pluginId);
|
|
846
|
-
next = recordPluginInstall(next, {
|
|
847
|
-
pluginId: result.pluginId,
|
|
848
|
-
source: "npm",
|
|
849
|
-
spec: pathOrSpec,
|
|
850
|
-
installPath: result.targetDir,
|
|
851
|
-
version: result.version
|
|
852
|
-
});
|
|
853
|
-
saveConfig(next);
|
|
854
|
-
console.log(`Installed plugin: ${result.pluginId}`);
|
|
855
|
-
await this.deps.requestRestart({
|
|
856
|
-
reason: `plugin installed: ${result.pluginId}`,
|
|
857
|
-
manualMessage: "Restart the gateway to load plugins."
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
pluginsDoctor() {
|
|
861
|
-
const config2 = loadConfig();
|
|
862
|
-
const workspaceDir = getWorkspacePath(config2.agents.defaults.workspace);
|
|
863
|
-
const report = buildPluginStatusReport({
|
|
864
|
-
config: config2,
|
|
865
|
-
workspaceDir,
|
|
866
|
-
reservedChannelIds: Object.keys(config2.channels),
|
|
867
|
-
reservedProviderIds: PROVIDERS.map((provider) => provider.name)
|
|
868
|
-
});
|
|
869
|
-
const pluginErrors = report.plugins.filter((plugin) => plugin.status === "error");
|
|
870
|
-
const diagnostics = report.diagnostics.filter((diag) => diag.level === "error");
|
|
871
|
-
if (pluginErrors.length === 0 && diagnostics.length === 0) {
|
|
872
|
-
console.log("No plugin issues detected.");
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
|
-
if (pluginErrors.length > 0) {
|
|
876
|
-
console.log("Plugin errors:");
|
|
877
|
-
for (const entry of pluginErrors) {
|
|
878
|
-
console.log(`- ${entry.id}: ${entry.error ?? "failed to load"} (${entry.source})`);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
if (diagnostics.length > 0) {
|
|
882
|
-
if (pluginErrors.length > 0) {
|
|
883
|
-
console.log("");
|
|
884
|
-
}
|
|
885
|
-
console.log("Diagnostics:");
|
|
886
|
-
for (const diag of diagnostics) {
|
|
887
|
-
const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
|
|
888
|
-
console.log(`- ${prefix}${diag.message}`);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
async confirmYesNo(question) {
|
|
893
|
-
const rl = createInterface({
|
|
894
|
-
input: process.stdin,
|
|
895
|
-
output: process.stdout
|
|
896
|
-
});
|
|
897
|
-
const answer = await new Promise((resolve9) => {
|
|
898
|
-
rl.question(`${question} [y/N] `, (line) => resolve9(line));
|
|
899
|
-
});
|
|
900
|
-
rl.close();
|
|
901
|
-
const normalized = answer.trim().toLowerCase();
|
|
902
|
-
return normalized === "y" || normalized === "yes";
|
|
903
|
-
}
|
|
904
|
-
resolveFileNpmSpecToLocalPath(raw) {
|
|
905
|
-
const trimmed = raw.trim();
|
|
906
|
-
if (!trimmed.toLowerCase().startsWith("file:")) {
|
|
907
|
-
return null;
|
|
908
|
-
}
|
|
909
|
-
const rest = trimmed.slice("file:".length);
|
|
910
|
-
if (!rest) {
|
|
911
|
-
return { ok: false, error: "unsupported file: spec: missing path" };
|
|
912
|
-
}
|
|
913
|
-
if (rest.startsWith("///")) {
|
|
914
|
-
return { ok: true, path: rest.slice(2) };
|
|
915
|
-
}
|
|
916
|
-
if (rest.startsWith("//localhost/")) {
|
|
917
|
-
return { ok: true, path: rest.slice("//localhost".length) };
|
|
918
|
-
}
|
|
919
|
-
if (rest.startsWith("//")) {
|
|
920
|
-
return {
|
|
921
|
-
ok: false,
|
|
922
|
-
error: 'unsupported file: URL host (expected "file:<path>" or "file:///abs/path")'
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
return { ok: true, path: rest };
|
|
926
|
-
}
|
|
927
|
-
looksLikePath(raw) {
|
|
928
|
-
return raw.startsWith(".") || raw.startsWith("~") || raw.startsWith("/") || raw.endsWith(".ts") || raw.endsWith(".js") || raw.endsWith(".mjs") || raw.endsWith(".cjs") || raw.endsWith(".tgz") || raw.endsWith(".tar.gz") || raw.endsWith(".tar") || raw.endsWith(".zip");
|
|
929
|
-
}
|
|
930
|
-
isArchivePath(filePath) {
|
|
931
|
-
const lower = filePath.toLowerCase();
|
|
932
|
-
return lower.endsWith(".zip") || lower.endsWith(".tgz") || lower.endsWith(".tar.gz") || lower.endsWith(".tar");
|
|
933
|
-
}
|
|
934
|
-
};
|
|
935
|
-
|
|
936
394
|
// src/cli/commands/config.ts
|
|
937
|
-
import { buildReloadPlan, diffConfigPaths, loadConfig
|
|
395
|
+
import { buildReloadPlan, diffConfigPaths, loadConfig, saveConfig } from "@nextclaw/core";
|
|
938
396
|
|
|
939
397
|
// src/cli/config-path.ts
|
|
940
398
|
function isIndexSegment(raw) {
|
|
@@ -1129,7 +587,7 @@ var ConfigCommands = class {
|
|
|
1129
587
|
this.deps = deps;
|
|
1130
588
|
}
|
|
1131
589
|
configGet(pathExpr, opts = {}) {
|
|
1132
|
-
const config2 =
|
|
590
|
+
const config2 = loadConfig();
|
|
1133
591
|
let parsedPath;
|
|
1134
592
|
try {
|
|
1135
593
|
parsedPath = parseRequiredConfigPath(pathExpr);
|
|
@@ -1171,7 +629,7 @@ var ConfigCommands = class {
|
|
|
1171
629
|
process.exit(1);
|
|
1172
630
|
return;
|
|
1173
631
|
}
|
|
1174
|
-
const prevConfig =
|
|
632
|
+
const prevConfig = loadConfig();
|
|
1175
633
|
const nextConfig = structuredClone(prevConfig);
|
|
1176
634
|
try {
|
|
1177
635
|
setAtConfigPath(nextConfig, parsedPath, parsedValue);
|
|
@@ -1180,7 +638,7 @@ var ConfigCommands = class {
|
|
|
1180
638
|
process.exit(1);
|
|
1181
639
|
return;
|
|
1182
640
|
}
|
|
1183
|
-
|
|
641
|
+
saveConfig(nextConfig);
|
|
1184
642
|
await this.requestRestartForConfigDiff({
|
|
1185
643
|
prevConfig,
|
|
1186
644
|
nextConfig,
|
|
@@ -1197,7 +655,7 @@ var ConfigCommands = class {
|
|
|
1197
655
|
process.exit(1);
|
|
1198
656
|
return;
|
|
1199
657
|
}
|
|
1200
|
-
const prevConfig =
|
|
658
|
+
const prevConfig = loadConfig();
|
|
1201
659
|
const nextConfig = structuredClone(prevConfig);
|
|
1202
660
|
const removed = unsetAtConfigPath(nextConfig, parsedPath);
|
|
1203
661
|
if (!removed) {
|
|
@@ -1205,7 +663,7 @@ var ConfigCommands = class {
|
|
|
1205
663
|
process.exit(1);
|
|
1206
664
|
return;
|
|
1207
665
|
}
|
|
1208
|
-
|
|
666
|
+
saveConfig(nextConfig);
|
|
1209
667
|
await this.requestRestartForConfigDiff({
|
|
1210
668
|
prevConfig,
|
|
1211
669
|
nextConfig,
|
|
@@ -1231,14 +689,13 @@ var ConfigCommands = class {
|
|
|
1231
689
|
|
|
1232
690
|
// src/cli/commands/channels.ts
|
|
1233
691
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
1234
|
-
import {
|
|
1235
|
-
import { buildPluginStatusReport as buildPluginStatusReport2, enablePluginInConfig as enablePluginInConfig2, getPluginChannelBindings } from "@nextclaw/openclaw-compat";
|
|
692
|
+
import { loadConfig as loadConfig2 } from "@nextclaw/core";
|
|
1236
693
|
var ChannelCommands = class {
|
|
1237
694
|
constructor(deps) {
|
|
1238
695
|
this.deps = deps;
|
|
1239
696
|
}
|
|
1240
697
|
channelsStatus() {
|
|
1241
|
-
const config2 =
|
|
698
|
+
const config2 = loadConfig2();
|
|
1242
699
|
console.log("Channel Status");
|
|
1243
700
|
console.log(`WhatsApp: ${config2.channels.whatsapp.enabled ? "\u2713" : "\u2717"}`);
|
|
1244
701
|
console.log(`Discord: ${config2.channels.discord.enabled ? "\u2713" : "\u2717"}`);
|
|
@@ -1247,21 +704,6 @@ var ChannelCommands = class {
|
|
|
1247
704
|
console.log(`Telegram: ${config2.channels.telegram.enabled ? "\u2713" : "\u2717"}`);
|
|
1248
705
|
console.log(`Slack: ${config2.channels.slack.enabled ? "\u2713" : "\u2717"}`);
|
|
1249
706
|
console.log(`QQ: ${config2.channels.qq.enabled ? "\u2713" : "\u2717"}`);
|
|
1250
|
-
const workspaceDir = getWorkspacePath2(config2.agents.defaults.workspace);
|
|
1251
|
-
const report = buildPluginStatusReport2({
|
|
1252
|
-
config: config2,
|
|
1253
|
-
workspaceDir,
|
|
1254
|
-
reservedChannelIds: Object.keys(config2.channels),
|
|
1255
|
-
reservedProviderIds: PROVIDERS2.map((provider) => provider.name)
|
|
1256
|
-
});
|
|
1257
|
-
const pluginChannels = report.plugins.filter((plugin) => plugin.status === "loaded" && plugin.channelIds.length > 0);
|
|
1258
|
-
if (pluginChannels.length > 0) {
|
|
1259
|
-
console.log("Plugin Channels:");
|
|
1260
|
-
for (const plugin of pluginChannels) {
|
|
1261
|
-
const channels2 = plugin.channelIds.join(", ");
|
|
1262
|
-
console.log(`- ${channels2} (plugin: ${plugin.id})`);
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
707
|
}
|
|
1266
708
|
channelsLogin() {
|
|
1267
709
|
const bridgeDir = this.deps.getBridgeDir();
|
|
@@ -1272,62 +714,6 @@ var ChannelCommands = class {
|
|
|
1272
714
|
console.error(`Bridge failed: ${result.status ?? 1}`);
|
|
1273
715
|
}
|
|
1274
716
|
}
|
|
1275
|
-
async channelsAdd(opts) {
|
|
1276
|
-
const channelId = opts.channel?.trim();
|
|
1277
|
-
if (!channelId) {
|
|
1278
|
-
console.error("--channel is required");
|
|
1279
|
-
process.exit(1);
|
|
1280
|
-
}
|
|
1281
|
-
const config2 = loadConfig3();
|
|
1282
|
-
const workspaceDir = getWorkspacePath2(config2.agents.defaults.workspace);
|
|
1283
|
-
const pluginRegistry = loadPluginRegistry(config2, workspaceDir);
|
|
1284
|
-
const bindings = getPluginChannelBindings(pluginRegistry);
|
|
1285
|
-
const binding = bindings.find((entry) => entry.channelId === channelId || entry.pluginId === channelId);
|
|
1286
|
-
if (!binding) {
|
|
1287
|
-
console.error(`No plugin channel found for: ${channelId}`);
|
|
1288
|
-
process.exit(1);
|
|
1289
|
-
}
|
|
1290
|
-
const setup = binding.channel.setup;
|
|
1291
|
-
if (!setup?.applyAccountConfig) {
|
|
1292
|
-
console.error(`Channel "${binding.channelId}" does not support setup.`);
|
|
1293
|
-
process.exit(1);
|
|
1294
|
-
}
|
|
1295
|
-
const input = {
|
|
1296
|
-
name: opts.name,
|
|
1297
|
-
token: opts.token,
|
|
1298
|
-
code: opts.code,
|
|
1299
|
-
url: opts.url,
|
|
1300
|
-
httpUrl: opts.httpUrl
|
|
1301
|
-
};
|
|
1302
|
-
const currentView = toPluginConfigView(config2, bindings);
|
|
1303
|
-
const accountId = binding.channel.config?.defaultAccountId?.(currentView) ?? "default";
|
|
1304
|
-
const validateError = setup.validateInput?.({
|
|
1305
|
-
cfg: currentView,
|
|
1306
|
-
input,
|
|
1307
|
-
accountId
|
|
1308
|
-
});
|
|
1309
|
-
if (validateError) {
|
|
1310
|
-
console.error(`Channel setup validation failed: ${validateError}`);
|
|
1311
|
-
process.exit(1);
|
|
1312
|
-
}
|
|
1313
|
-
const nextView = setup.applyAccountConfig({
|
|
1314
|
-
cfg: currentView,
|
|
1315
|
-
input,
|
|
1316
|
-
accountId
|
|
1317
|
-
});
|
|
1318
|
-
if (!nextView || typeof nextView !== "object" || Array.isArray(nextView)) {
|
|
1319
|
-
console.error("Channel setup returned invalid config payload.");
|
|
1320
|
-
process.exit(1);
|
|
1321
|
-
}
|
|
1322
|
-
let next = mergePluginConfigView(config2, nextView, bindings);
|
|
1323
|
-
next = enablePluginInConfig2(next, binding.pluginId);
|
|
1324
|
-
saveConfig3(next);
|
|
1325
|
-
console.log(`Configured channel "${binding.channelId}" via plugin "${binding.pluginId}".`);
|
|
1326
|
-
await this.deps.requestRestart({
|
|
1327
|
-
reason: `channel configured via plugin: ${binding.pluginId}`,
|
|
1328
|
-
manualMessage: "Restart the gateway to apply changes."
|
|
1329
|
-
});
|
|
1330
|
-
}
|
|
1331
717
|
};
|
|
1332
718
|
|
|
1333
719
|
// src/cli/commands/cron.ts
|
|
@@ -1408,15 +794,15 @@ var CronCommands = class {
|
|
|
1408
794
|
|
|
1409
795
|
// src/cli/commands/diagnostics.ts
|
|
1410
796
|
import { createServer as createNetServer } from "net";
|
|
1411
|
-
import { existsSync as
|
|
1412
|
-
import { resolve as
|
|
797
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
798
|
+
import { resolve as resolve4 } from "path";
|
|
1413
799
|
import {
|
|
1414
800
|
APP_NAME,
|
|
1415
801
|
getConfigPath,
|
|
1416
802
|
getDataDir as getDataDir3,
|
|
1417
|
-
getWorkspacePath
|
|
1418
|
-
loadConfig as
|
|
1419
|
-
PROVIDERS
|
|
803
|
+
getWorkspacePath,
|
|
804
|
+
loadConfig as loadConfig3,
|
|
805
|
+
PROVIDERS
|
|
1420
806
|
} from "@nextclaw/core";
|
|
1421
807
|
var DiagnosticsCommands = class {
|
|
1422
808
|
constructor(deps) {
|
|
@@ -1577,9 +963,9 @@ var DiagnosticsCommands = class {
|
|
|
1577
963
|
}
|
|
1578
964
|
async collectRuntimeStatus(params) {
|
|
1579
965
|
const configPath = getConfigPath();
|
|
1580
|
-
const config2 =
|
|
1581
|
-
const workspacePath =
|
|
1582
|
-
const serviceStatePath =
|
|
966
|
+
const config2 = loadConfig3();
|
|
967
|
+
const workspacePath = getWorkspacePath(config2.agents.defaults.workspace);
|
|
968
|
+
const serviceStatePath = resolve4(getDataDir3(), "run", "service.json");
|
|
1583
969
|
const fixActions = [];
|
|
1584
970
|
let serviceState = readServiceState();
|
|
1585
971
|
if (params.fix && serviceState && !isProcessRunning(serviceState.pid)) {
|
|
@@ -1598,7 +984,7 @@ var DiagnosticsCommands = class {
|
|
|
1598
984
|
const managedHealth = running && managedApiUrl ? await this.probeApiHealth(`${managedApiUrl}/health`) : { state: "unreachable", detail: "service not running" };
|
|
1599
985
|
const configuredHealth = await this.probeApiHealth(`${configuredApiUrl}/health`, 900);
|
|
1600
986
|
const orphanSuspected = !running && configuredHealth.state === "ok";
|
|
1601
|
-
const providers =
|
|
987
|
+
const providers = PROVIDERS.map((spec) => {
|
|
1602
988
|
const provider = config2.providers[spec.name];
|
|
1603
989
|
if (!provider) {
|
|
1604
990
|
return { name: spec.displayName ?? spec.name, configured: false, detail: "missing config" };
|
|
@@ -1618,11 +1004,11 @@ var DiagnosticsCommands = class {
|
|
|
1618
1004
|
});
|
|
1619
1005
|
const issues = [];
|
|
1620
1006
|
const recommendations = [];
|
|
1621
|
-
if (!
|
|
1007
|
+
if (!existsSync3(configPath)) {
|
|
1622
1008
|
issues.push("Config file is missing.");
|
|
1623
1009
|
recommendations.push(`Run ${APP_NAME} init to create config files.`);
|
|
1624
1010
|
}
|
|
1625
|
-
if (!
|
|
1011
|
+
if (!existsSync3(workspacePath)) {
|
|
1626
1012
|
issues.push("Workspace directory does not exist.");
|
|
1627
1013
|
recommendations.push(`Run ${APP_NAME} init to create workspace templates.`);
|
|
1628
1014
|
}
|
|
@@ -1650,13 +1036,13 @@ var DiagnosticsCommands = class {
|
|
|
1650
1036
|
return {
|
|
1651
1037
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1652
1038
|
configPath,
|
|
1653
|
-
configExists:
|
|
1039
|
+
configExists: existsSync3(configPath),
|
|
1654
1040
|
workspacePath,
|
|
1655
|
-
workspaceExists:
|
|
1041
|
+
workspaceExists: existsSync3(workspacePath),
|
|
1656
1042
|
model: config2.agents.defaults.model,
|
|
1657
1043
|
providers,
|
|
1658
1044
|
serviceStatePath,
|
|
1659
|
-
serviceStateExists:
|
|
1045
|
+
serviceStateExists: existsSync3(serviceStatePath),
|
|
1660
1046
|
fixActions,
|
|
1661
1047
|
process: {
|
|
1662
1048
|
managedByState,
|
|
@@ -1706,7 +1092,7 @@ var DiagnosticsCommands = class {
|
|
|
1706
1092
|
}
|
|
1707
1093
|
}
|
|
1708
1094
|
readLogTail(path, maxLines = 25) {
|
|
1709
|
-
if (!
|
|
1095
|
+
if (!existsSync3(path)) {
|
|
1710
1096
|
return [];
|
|
1711
1097
|
}
|
|
1712
1098
|
try {
|
|
@@ -1720,17 +1106,17 @@ var DiagnosticsCommands = class {
|
|
|
1720
1106
|
}
|
|
1721
1107
|
}
|
|
1722
1108
|
async checkPortAvailability(params) {
|
|
1723
|
-
return await new Promise((
|
|
1109
|
+
return await new Promise((resolve8) => {
|
|
1724
1110
|
const server = createNetServer();
|
|
1725
1111
|
server.once("error", (error) => {
|
|
1726
|
-
|
|
1112
|
+
resolve8({
|
|
1727
1113
|
available: false,
|
|
1728
1114
|
detail: `bind failed on ${params.host}:${params.port} (${String(error)})`
|
|
1729
1115
|
});
|
|
1730
1116
|
});
|
|
1731
1117
|
server.listen(params.port, params.host, () => {
|
|
1732
1118
|
server.close(() => {
|
|
1733
|
-
|
|
1119
|
+
resolve8({
|
|
1734
1120
|
available: true,
|
|
1735
1121
|
detail: `bind ok on ${params.host}:${params.port}`
|
|
1736
1122
|
});
|
|
@@ -1751,43 +1137,35 @@ import {
|
|
|
1751
1137
|
getDataDir as getDataDir4,
|
|
1752
1138
|
getProvider,
|
|
1753
1139
|
getProviderName,
|
|
1754
|
-
getWorkspacePath as
|
|
1140
|
+
getWorkspacePath as getWorkspacePath2,
|
|
1755
1141
|
HeartbeatService,
|
|
1756
1142
|
LiteLLMProvider,
|
|
1757
|
-
loadConfig as
|
|
1143
|
+
loadConfig as loadConfig4,
|
|
1758
1144
|
MessageBus,
|
|
1759
1145
|
ProviderManager,
|
|
1760
|
-
saveConfig as
|
|
1146
|
+
saveConfig as saveConfig2,
|
|
1761
1147
|
SessionManager
|
|
1762
1148
|
} from "@nextclaw/core";
|
|
1763
|
-
import {
|
|
1764
|
-
getPluginChannelBindings as getPluginChannelBindings2,
|
|
1765
|
-
getPluginUiMetadataFromRegistry,
|
|
1766
|
-
resolvePluginChannelMessageToolHints,
|
|
1767
|
-
setPluginRuntimeBridge,
|
|
1768
|
-
startPluginChannelGateways,
|
|
1769
|
-
stopPluginChannelGateways
|
|
1770
|
-
} from "@nextclaw/openclaw-compat";
|
|
1771
1149
|
import { startUiServer } from "@nextclaw/server";
|
|
1772
1150
|
import { closeSync, mkdirSync as mkdirSync2, openSync } from "fs";
|
|
1773
|
-
import { join as join4, resolve as
|
|
1151
|
+
import { join as join4, resolve as resolve5 } from "path";
|
|
1774
1152
|
import { spawn as spawn2 } from "child_process";
|
|
1775
1153
|
import chokidar from "chokidar";
|
|
1776
1154
|
|
|
1777
1155
|
// src/cli/gateway/controller.ts
|
|
1778
1156
|
import { createHash } from "crypto";
|
|
1779
|
-
import { existsSync as
|
|
1157
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1780
1158
|
import {
|
|
1781
1159
|
buildConfigSchema,
|
|
1782
1160
|
ConfigSchema,
|
|
1783
1161
|
redactConfigObject
|
|
1784
1162
|
} from "@nextclaw/core";
|
|
1785
1163
|
var hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
|
|
1786
|
-
var readConfigSnapshot = (getConfigPath4
|
|
1164
|
+
var readConfigSnapshot = (getConfigPath4) => {
|
|
1787
1165
|
const path = getConfigPath4();
|
|
1788
1166
|
let raw = "";
|
|
1789
1167
|
let parsed = {};
|
|
1790
|
-
if (
|
|
1168
|
+
if (existsSync4(path)) {
|
|
1791
1169
|
raw = readFileSync3(path, "utf-8");
|
|
1792
1170
|
try {
|
|
1793
1171
|
parsed = JSON.parse(raw);
|
|
@@ -1807,12 +1185,12 @@ var readConfigSnapshot = (getConfigPath4, plugins2) => {
|
|
|
1807
1185
|
raw = JSON.stringify(config2, null, 2);
|
|
1808
1186
|
}
|
|
1809
1187
|
const hash = hashRaw(raw);
|
|
1810
|
-
const schema = buildConfigSchema({ version: getPackageVersion()
|
|
1188
|
+
const schema = buildConfigSchema({ version: getPackageVersion() });
|
|
1811
1189
|
const redacted = redactConfigObject(config2, schema.uiHints);
|
|
1812
1190
|
return { raw: valid ? JSON.stringify(redacted, null, 2) : null, hash: valid ? hash : null, config: config2, redacted, valid };
|
|
1813
1191
|
};
|
|
1814
|
-
var redactValue = (value
|
|
1815
|
-
const schema = buildConfigSchema({ version: getPackageVersion()
|
|
1192
|
+
var redactValue = (value) => {
|
|
1193
|
+
const schema = buildConfigSchema({ version: getPackageVersion() });
|
|
1816
1194
|
return redactConfigObject(value, schema.uiHints);
|
|
1817
1195
|
};
|
|
1818
1196
|
var mergeDeep = (base, patch) => {
|
|
@@ -1861,8 +1239,7 @@ var GatewayControllerImpl = class {
|
|
|
1861
1239
|
return "Restart scheduled";
|
|
1862
1240
|
}
|
|
1863
1241
|
async getConfig() {
|
|
1864
|
-
const
|
|
1865
|
-
const snapshot = readConfigSnapshot(this.deps.getConfigPath, plugins2);
|
|
1242
|
+
const snapshot = readConfigSnapshot(this.deps.getConfigPath);
|
|
1866
1243
|
return {
|
|
1867
1244
|
raw: snapshot.raw,
|
|
1868
1245
|
hash: snapshot.hash,
|
|
@@ -1874,11 +1251,10 @@ var GatewayControllerImpl = class {
|
|
|
1874
1251
|
};
|
|
1875
1252
|
}
|
|
1876
1253
|
async getConfigSchema() {
|
|
1877
|
-
return buildConfigSchema({ version: getPackageVersion()
|
|
1254
|
+
return buildConfigSchema({ version: getPackageVersion() });
|
|
1878
1255
|
}
|
|
1879
1256
|
async applyConfig(params) {
|
|
1880
|
-
const
|
|
1881
|
-
const snapshot = readConfigSnapshot(this.deps.getConfigPath, plugins2);
|
|
1257
|
+
const snapshot = readConfigSnapshot(this.deps.getConfigPath);
|
|
1882
1258
|
if (!params.baseHash) {
|
|
1883
1259
|
return { ok: false, error: "config base hash required; re-run config.get and retry" };
|
|
1884
1260
|
}
|
|
@@ -1907,13 +1283,12 @@ var GatewayControllerImpl = class {
|
|
|
1907
1283
|
ok: true,
|
|
1908
1284
|
note: params.note ?? null,
|
|
1909
1285
|
path: this.deps.getConfigPath(),
|
|
1910
|
-
config: redactValue(validated
|
|
1286
|
+
config: redactValue(validated),
|
|
1911
1287
|
restart: { scheduled: true, delayMs }
|
|
1912
1288
|
};
|
|
1913
1289
|
}
|
|
1914
1290
|
async patchConfig(params) {
|
|
1915
|
-
const
|
|
1916
|
-
const snapshot = readConfigSnapshot(this.deps.getConfigPath, plugins2);
|
|
1291
|
+
const snapshot = readConfigSnapshot(this.deps.getConfigPath);
|
|
1917
1292
|
if (!params.baseHash) {
|
|
1918
1293
|
return { ok: false, error: "config base hash required; re-run config.get and retry" };
|
|
1919
1294
|
}
|
|
@@ -1943,7 +1318,7 @@ var GatewayControllerImpl = class {
|
|
|
1943
1318
|
ok: true,
|
|
1944
1319
|
note: params.note ?? null,
|
|
1945
1320
|
path: this.deps.getConfigPath(),
|
|
1946
|
-
config: redactValue(validated
|
|
1321
|
+
config: redactValue(validated),
|
|
1947
1322
|
restart: { scheduled: true, delayMs }
|
|
1948
1323
|
};
|
|
1949
1324
|
}
|
|
@@ -2116,24 +1491,20 @@ var ServiceCommands = class {
|
|
|
2116
1491
|
this.deps = deps;
|
|
2117
1492
|
}
|
|
2118
1493
|
async startGateway(options = {}) {
|
|
2119
|
-
const config2 =
|
|
2120
|
-
const workspace =
|
|
2121
|
-
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
2122
|
-
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
2123
|
-
logPluginDiagnostics(pluginRegistry);
|
|
1494
|
+
const config2 = loadConfig4();
|
|
1495
|
+
const workspace = getWorkspacePath2(config2.agents.defaults.workspace);
|
|
2124
1496
|
const bus = new MessageBus();
|
|
2125
1497
|
const provider = options.allowMissingProvider === true ? this.makeProvider(config2, { allowMissing: true }) : this.makeProvider(config2);
|
|
2126
1498
|
const providerManager = new ProviderManager(provider ?? this.makeMissingProvider(config2));
|
|
2127
1499
|
const sessionManager = new SessionManager(workspace);
|
|
2128
1500
|
const cronStorePath = join4(getDataDir4(), "cron", "jobs.json");
|
|
2129
1501
|
const cron2 = new CronService2(cronStorePath);
|
|
2130
|
-
const pluginUiMetadata = getPluginUiMetadataFromRegistry(pluginRegistry);
|
|
2131
1502
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
2132
1503
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
2133
1504
|
if (!provider) {
|
|
2134
1505
|
console.warn("Warning: No API key configured. The gateway is running, but agent replies are disabled until provider config is set.");
|
|
2135
1506
|
}
|
|
2136
|
-
const channels2 = new ChannelManager2(config2, bus, sessionManager,
|
|
1507
|
+
const channels2 = new ChannelManager2(config2, bus, sessionManager, []);
|
|
2137
1508
|
const reloader = new ConfigReloader({
|
|
2138
1509
|
initialConfig: config2,
|
|
2139
1510
|
channels: channels2,
|
|
@@ -2141,8 +1512,7 @@ var ServiceCommands = class {
|
|
|
2141
1512
|
sessionManager,
|
|
2142
1513
|
providerManager,
|
|
2143
1514
|
makeProvider: (nextConfig) => this.makeProvider(nextConfig, { allowMissing: true }) ?? this.makeMissingProvider(nextConfig),
|
|
2144
|
-
loadConfig:
|
|
2145
|
-
getExtensionChannels: () => extensionRegistry.channels,
|
|
1515
|
+
loadConfig: loadConfig4,
|
|
2146
1516
|
onRestartRequired: (paths) => {
|
|
2147
1517
|
void this.deps.requestRestart({
|
|
2148
1518
|
reason: `config reload requires restart: ${paths.join(", ")}`,
|
|
@@ -2155,8 +1525,7 @@ var ServiceCommands = class {
|
|
|
2155
1525
|
reloader,
|
|
2156
1526
|
cron: cron2,
|
|
2157
1527
|
getConfigPath: getConfigPath2,
|
|
2158
|
-
saveConfig:
|
|
2159
|
-
getPluginUiMetadata: () => pluginUiMetadata,
|
|
1528
|
+
saveConfig: saveConfig2,
|
|
2160
1529
|
requestRestart: async (options2) => {
|
|
2161
1530
|
await this.deps.requestRestart({
|
|
2162
1531
|
reason: options2?.reason ?? "gateway tool restart",
|
|
@@ -2182,55 +1551,9 @@ var ServiceCommands = class {
|
|
|
2182
1551
|
sessionManager,
|
|
2183
1552
|
contextConfig: config2.agents.context,
|
|
2184
1553
|
gatewayController,
|
|
2185
|
-
config: config2
|
|
2186
|
-
extensionRegistry,
|
|
2187
|
-
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
2188
|
-
registry: pluginRegistry,
|
|
2189
|
-
channel,
|
|
2190
|
-
cfg: loadConfig5(),
|
|
2191
|
-
accountId
|
|
2192
|
-
})
|
|
1554
|
+
config: config2
|
|
2193
1555
|
});
|
|
2194
1556
|
reloader.setApplyAgentRuntimeConfig((nextConfig) => agent.applyRuntimeConfig(nextConfig));
|
|
2195
|
-
const pluginChannelBindings = getPluginChannelBindings2(pluginRegistry);
|
|
2196
|
-
setPluginRuntimeBridge({
|
|
2197
|
-
loadConfig: () => toPluginConfigView(loadConfig5(), pluginChannelBindings),
|
|
2198
|
-
writeConfigFile: async (nextConfigView) => {
|
|
2199
|
-
if (!nextConfigView || typeof nextConfigView !== "object" || Array.isArray(nextConfigView)) {
|
|
2200
|
-
throw new Error("plugin runtime writeConfigFile expects an object config");
|
|
2201
|
-
}
|
|
2202
|
-
const current = loadConfig5();
|
|
2203
|
-
const next = mergePluginConfigView(current, nextConfigView, pluginChannelBindings);
|
|
2204
|
-
saveConfig4(next);
|
|
2205
|
-
},
|
|
2206
|
-
dispatchReplyWithBufferedBlockDispatcher: async ({ ctx, dispatcherOptions }) => {
|
|
2207
|
-
const bodyForAgent = typeof ctx.BodyForAgent === "string" ? ctx.BodyForAgent : "";
|
|
2208
|
-
const body = typeof ctx.Body === "string" ? ctx.Body : "";
|
|
2209
|
-
const content = (bodyForAgent || body).trim();
|
|
2210
|
-
if (!content) {
|
|
2211
|
-
return;
|
|
2212
|
-
}
|
|
2213
|
-
const sessionKey = typeof ctx.SessionKey === "string" && ctx.SessionKey.trim().length > 0 ? ctx.SessionKey : `plugin:${typeof ctx.OriginatingChannel === "string" ? ctx.OriginatingChannel : "channel"}:${typeof ctx.SenderId === "string" ? ctx.SenderId : "unknown"}`;
|
|
2214
|
-
const channel = typeof ctx.OriginatingChannel === "string" && ctx.OriginatingChannel.trim().length > 0 ? ctx.OriginatingChannel : "cli";
|
|
2215
|
-
const chatId = typeof ctx.OriginatingTo === "string" && ctx.OriginatingTo.trim().length > 0 ? ctx.OriginatingTo : typeof ctx.SenderId === "string" && ctx.SenderId.trim().length > 0 ? ctx.SenderId : "direct";
|
|
2216
|
-
try {
|
|
2217
|
-
const response = await agent.processDirect({
|
|
2218
|
-
content,
|
|
2219
|
-
sessionKey,
|
|
2220
|
-
channel,
|
|
2221
|
-
chatId,
|
|
2222
|
-
metadata: typeof ctx.AccountId === "string" && ctx.AccountId.trim().length > 0 ? { account_id: ctx.AccountId } : {}
|
|
2223
|
-
});
|
|
2224
|
-
const replyText = typeof response === "string" ? response : String(response ?? "");
|
|
2225
|
-
if (replyText.trim()) {
|
|
2226
|
-
await dispatcherOptions.deliver({ text: replyText }, { kind: "final" });
|
|
2227
|
-
}
|
|
2228
|
-
} catch (error) {
|
|
2229
|
-
dispatcherOptions.onError?.(error);
|
|
2230
|
-
throw error;
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
});
|
|
2234
1557
|
cron2.onJob = async (job) => {
|
|
2235
1558
|
const response = await agent.processDirect({
|
|
2236
1559
|
content: job.payload.message,
|
|
@@ -2276,35 +1599,10 @@ var ServiceCommands = class {
|
|
|
2276
1599
|
watcher.on("unlink", () => reloader.scheduleReload("config unlink"));
|
|
2277
1600
|
await cron2.start();
|
|
2278
1601
|
await heartbeat.start();
|
|
2279
|
-
|
|
2280
|
-
try {
|
|
2281
|
-
const startedPluginGateways = await startPluginChannelGateways({
|
|
2282
|
-
registry: pluginRegistry,
|
|
2283
|
-
logger: {
|
|
2284
|
-
info: (message) => console.log(`[plugins] ${message}`),
|
|
2285
|
-
warn: (message) => console.warn(`[plugins] ${message}`),
|
|
2286
|
-
error: (message) => console.error(`[plugins] ${message}`),
|
|
2287
|
-
debug: (message) => console.debug(`[plugins] ${message}`)
|
|
2288
|
-
}
|
|
2289
|
-
});
|
|
2290
|
-
pluginGatewayHandles = startedPluginGateways.handles;
|
|
2291
|
-
for (const diag of startedPluginGateways.diagnostics) {
|
|
2292
|
-
const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
|
|
2293
|
-
const text = `${prefix}${diag.message}`;
|
|
2294
|
-
if (diag.level === "error") {
|
|
2295
|
-
console.error(`[plugins] ${text}`);
|
|
2296
|
-
} else {
|
|
2297
|
-
console.warn(`[plugins] ${text}`);
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
await Promise.allSettled([agent.run(), reloader.getChannels().startAll()]);
|
|
2301
|
-
} finally {
|
|
2302
|
-
await stopPluginChannelGateways(pluginGatewayHandles);
|
|
2303
|
-
setPluginRuntimeBridge(null);
|
|
2304
|
-
}
|
|
1602
|
+
await Promise.allSettled([agent.run(), reloader.getChannels().startAll()]);
|
|
2305
1603
|
}
|
|
2306
1604
|
async runForeground(options) {
|
|
2307
|
-
const config2 =
|
|
1605
|
+
const config2 = loadConfig4();
|
|
2308
1606
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
2309
1607
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
2310
1608
|
if (options.open) {
|
|
@@ -2317,7 +1615,7 @@ var ServiceCommands = class {
|
|
|
2317
1615
|
});
|
|
2318
1616
|
}
|
|
2319
1617
|
async startService(options) {
|
|
2320
|
-
const config2 =
|
|
1618
|
+
const config2 = loadConfig4();
|
|
2321
1619
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
2322
1620
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
2323
1621
|
const apiUrl = `${uiUrl}/api`;
|
|
@@ -2366,7 +1664,7 @@ var ServiceCommands = class {
|
|
|
2366
1664
|
console.log("Warning: UI frontend not found in package assets.");
|
|
2367
1665
|
}
|
|
2368
1666
|
const logPath = resolveServiceLogPath();
|
|
2369
|
-
const logDir =
|
|
1667
|
+
const logDir = resolve5(logPath, "..");
|
|
2370
1668
|
mkdirSync2(logDir, { recursive: true });
|
|
2371
1669
|
const logFd = openSync(logPath, "a");
|
|
2372
1670
|
const serveArgs = buildServeArgs({
|
|
@@ -2461,22 +1759,22 @@ var ServiceCommands = class {
|
|
|
2461
1759
|
try {
|
|
2462
1760
|
const response = await fetch(params.healthUrl, { method: "GET" });
|
|
2463
1761
|
if (!response.ok) {
|
|
2464
|
-
await new Promise((
|
|
1762
|
+
await new Promise((resolve8) => setTimeout(resolve8, 200));
|
|
2465
1763
|
continue;
|
|
2466
1764
|
}
|
|
2467
1765
|
const payload = await response.json();
|
|
2468
1766
|
const healthy = payload?.ok === true && payload?.data?.status === "ok";
|
|
2469
1767
|
if (!healthy) {
|
|
2470
|
-
await new Promise((
|
|
1768
|
+
await new Promise((resolve8) => setTimeout(resolve8, 200));
|
|
2471
1769
|
continue;
|
|
2472
1770
|
}
|
|
2473
|
-
await new Promise((
|
|
1771
|
+
await new Promise((resolve8) => setTimeout(resolve8, 300));
|
|
2474
1772
|
if (isProcessRunning(params.pid)) {
|
|
2475
1773
|
return true;
|
|
2476
1774
|
}
|
|
2477
1775
|
} catch {
|
|
2478
1776
|
}
|
|
2479
|
-
await new Promise((
|
|
1777
|
+
await new Promise((resolve8) => setTimeout(resolve8, 200));
|
|
2480
1778
|
}
|
|
2481
1779
|
return false;
|
|
2482
1780
|
}
|
|
@@ -2549,9 +1847,9 @@ var ServiceCommands = class {
|
|
|
2549
1847
|
};
|
|
2550
1848
|
|
|
2551
1849
|
// src/cli/workspace.ts
|
|
2552
|
-
import { cpSync, existsSync as
|
|
1850
|
+
import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2553
1851
|
import { createRequire } from "module";
|
|
2554
|
-
import { dirname, join as join5, resolve as
|
|
1852
|
+
import { dirname, join as join5, resolve as resolve6 } from "path";
|
|
2555
1853
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2556
1854
|
import { APP_NAME as APP_NAME3, getDataDir as getDataDir5 } from "@nextclaw/core";
|
|
2557
1855
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
@@ -2582,11 +1880,11 @@ var WorkspaceManager = class {
|
|
|
2582
1880
|
];
|
|
2583
1881
|
for (const entry of templateFiles) {
|
|
2584
1882
|
const filePath = join5(workspace, entry.target);
|
|
2585
|
-
if (!force &&
|
|
1883
|
+
if (!force && existsSync5(filePath)) {
|
|
2586
1884
|
continue;
|
|
2587
1885
|
}
|
|
2588
1886
|
const templatePath = join5(templateDir, entry.source);
|
|
2589
|
-
if (!
|
|
1887
|
+
if (!existsSync5(templatePath)) {
|
|
2590
1888
|
console.warn(`Warning: Template file missing: ${templatePath}`);
|
|
2591
1889
|
continue;
|
|
2592
1890
|
}
|
|
@@ -2597,12 +1895,12 @@ var WorkspaceManager = class {
|
|
|
2597
1895
|
created.push(entry.target);
|
|
2598
1896
|
}
|
|
2599
1897
|
const memoryDir = join5(workspace, "memory");
|
|
2600
|
-
if (!
|
|
1898
|
+
if (!existsSync5(memoryDir)) {
|
|
2601
1899
|
mkdirSync3(memoryDir, { recursive: true });
|
|
2602
1900
|
created.push(join5("memory", ""));
|
|
2603
1901
|
}
|
|
2604
1902
|
const skillsDir = join5(workspace, "skills");
|
|
2605
|
-
if (!
|
|
1903
|
+
if (!existsSync5(skillsDir)) {
|
|
2606
1904
|
mkdirSync3(skillsDir, { recursive: true });
|
|
2607
1905
|
created.push(join5("skills", ""));
|
|
2608
1906
|
}
|
|
@@ -2624,11 +1922,11 @@ var WorkspaceManager = class {
|
|
|
2624
1922
|
continue;
|
|
2625
1923
|
}
|
|
2626
1924
|
const src = join5(sourceDir, entry.name);
|
|
2627
|
-
if (!
|
|
1925
|
+
if (!existsSync5(join5(src, "SKILL.md"))) {
|
|
2628
1926
|
continue;
|
|
2629
1927
|
}
|
|
2630
1928
|
const dest = join5(targetDir, entry.name);
|
|
2631
|
-
if (!force &&
|
|
1929
|
+
if (!force && existsSync5(dest)) {
|
|
2632
1930
|
continue;
|
|
2633
1931
|
}
|
|
2634
1932
|
cpSync(src, dest, { recursive: true, force: true });
|
|
@@ -2640,13 +1938,13 @@ var WorkspaceManager = class {
|
|
|
2640
1938
|
try {
|
|
2641
1939
|
const require2 = createRequire(import.meta.url);
|
|
2642
1940
|
const entry = require2.resolve("@nextclaw/core");
|
|
2643
|
-
const pkgRoot =
|
|
1941
|
+
const pkgRoot = resolve6(dirname(entry), "..");
|
|
2644
1942
|
const distSkills = join5(pkgRoot, "dist", "skills");
|
|
2645
|
-
if (
|
|
1943
|
+
if (existsSync5(distSkills)) {
|
|
2646
1944
|
return distSkills;
|
|
2647
1945
|
}
|
|
2648
1946
|
const srcSkills = join5(pkgRoot, "src", "agent", "skills");
|
|
2649
|
-
if (
|
|
1947
|
+
if (existsSync5(srcSkills)) {
|
|
2650
1948
|
return srcSkills;
|
|
2651
1949
|
}
|
|
2652
1950
|
return null;
|
|
@@ -2659,11 +1957,11 @@ var WorkspaceManager = class {
|
|
|
2659
1957
|
if (override) {
|
|
2660
1958
|
return override;
|
|
2661
1959
|
}
|
|
2662
|
-
const cliDir =
|
|
2663
|
-
const pkgRoot =
|
|
1960
|
+
const cliDir = resolve6(fileURLToPath2(new URL(".", import.meta.url)));
|
|
1961
|
+
const pkgRoot = resolve6(cliDir, "..", "..");
|
|
2664
1962
|
const candidates = [join5(pkgRoot, "templates")];
|
|
2665
1963
|
for (const candidate of candidates) {
|
|
2666
|
-
if (
|
|
1964
|
+
if (existsSync5(candidate)) {
|
|
2667
1965
|
return candidate;
|
|
2668
1966
|
}
|
|
2669
1967
|
}
|
|
@@ -2671,21 +1969,21 @@ var WorkspaceManager = class {
|
|
|
2671
1969
|
}
|
|
2672
1970
|
getBridgeDir() {
|
|
2673
1971
|
const userBridge = join5(getDataDir5(), "bridge");
|
|
2674
|
-
if (
|
|
1972
|
+
if (existsSync5(join5(userBridge, "dist", "index.js"))) {
|
|
2675
1973
|
return userBridge;
|
|
2676
1974
|
}
|
|
2677
1975
|
if (!which("npm")) {
|
|
2678
1976
|
console.error("npm not found. Please install Node.js >= 18.");
|
|
2679
1977
|
process.exit(1);
|
|
2680
1978
|
}
|
|
2681
|
-
const cliDir =
|
|
2682
|
-
const pkgRoot =
|
|
1979
|
+
const cliDir = resolve6(fileURLToPath2(new URL(".", import.meta.url)));
|
|
1980
|
+
const pkgRoot = resolve6(cliDir, "..", "..");
|
|
2683
1981
|
const pkgBridge = join5(pkgRoot, "bridge");
|
|
2684
1982
|
const srcBridge = join5(pkgRoot, "..", "..", "bridge");
|
|
2685
1983
|
let source = null;
|
|
2686
|
-
if (
|
|
1984
|
+
if (existsSync5(join5(pkgBridge, "package.json"))) {
|
|
2687
1985
|
source = pkgBridge;
|
|
2688
|
-
} else if (
|
|
1986
|
+
} else if (existsSync5(join5(srcBridge, "package.json"))) {
|
|
2689
1987
|
source = srcBridge;
|
|
2690
1988
|
}
|
|
2691
1989
|
if (!source) {
|
|
@@ -2693,8 +1991,8 @@ var WorkspaceManager = class {
|
|
|
2693
1991
|
process.exit(1);
|
|
2694
1992
|
}
|
|
2695
1993
|
console.log(`${this.logo} Setting up bridge...`);
|
|
2696
|
-
mkdirSync3(
|
|
2697
|
-
if (
|
|
1994
|
+
mkdirSync3(resolve6(userBridge, ".."), { recursive: true });
|
|
1995
|
+
if (existsSync5(userBridge)) {
|
|
2698
1996
|
rmSync2(userBridge, { recursive: true, force: true });
|
|
2699
1997
|
}
|
|
2700
1998
|
cpSync(source, userBridge, {
|
|
@@ -2734,7 +2032,6 @@ var CliRuntime = class {
|
|
|
2734
2032
|
workspaceManager;
|
|
2735
2033
|
serviceCommands;
|
|
2736
2034
|
configCommands;
|
|
2737
|
-
pluginCommands;
|
|
2738
2035
|
channelCommands;
|
|
2739
2036
|
cronCommands;
|
|
2740
2037
|
diagnosticsCommands;
|
|
@@ -2747,13 +2044,9 @@ var CliRuntime = class {
|
|
|
2747
2044
|
this.configCommands = new ConfigCommands({
|
|
2748
2045
|
requestRestart: (params) => this.requestRestart(params)
|
|
2749
2046
|
});
|
|
2750
|
-
this.pluginCommands = new PluginCommands({
|
|
2751
|
-
requestRestart: (params) => this.requestRestart(params)
|
|
2752
|
-
});
|
|
2753
2047
|
this.channelCommands = new ChannelCommands({
|
|
2754
2048
|
logo: this.logo,
|
|
2755
|
-
getBridgeDir: () => this.workspaceManager.getBridgeDir()
|
|
2756
|
-
requestRestart: (params) => this.requestRestart(params)
|
|
2049
|
+
getBridgeDir: () => this.workspaceManager.getBridgeDir()
|
|
2757
2050
|
});
|
|
2758
2051
|
this.cronCommands = new CronCommands();
|
|
2759
2052
|
this.diagnosticsCommands = new DiagnosticsCommands({ logo: this.logo });
|
|
@@ -2819,7 +2112,7 @@ var CliRuntime = class {
|
|
|
2819
2112
|
const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ? Math.max(0, Math.floor(params.delayMs)) : 100;
|
|
2820
2113
|
const cliPath = process.env.NEXTCLAW_SELF_RELAUNCH_CLI?.trim() || fileURLToPath3(new URL("./index.js", import.meta.url));
|
|
2821
2114
|
const startArgs = [cliPath, "start", "--ui-port", String(uiPort)];
|
|
2822
|
-
const serviceStatePath =
|
|
2115
|
+
const serviceStatePath = resolve7(getDataDir6(), "run", "service.json");
|
|
2823
2116
|
const helperScript = [
|
|
2824
2117
|
'const { spawnSync } = require("node:child_process");',
|
|
2825
2118
|
'const { readFileSync } = require("node:fs");',
|
|
@@ -2924,15 +2217,15 @@ var CliRuntime = class {
|
|
|
2924
2217
|
const force = Boolean(options.force);
|
|
2925
2218
|
const configPath = getConfigPath3();
|
|
2926
2219
|
let createdConfig = false;
|
|
2927
|
-
if (!
|
|
2220
|
+
if (!existsSync6(configPath)) {
|
|
2928
2221
|
const config3 = ConfigSchema2.parse({});
|
|
2929
|
-
|
|
2222
|
+
saveConfig3(config3);
|
|
2930
2223
|
createdConfig = true;
|
|
2931
2224
|
}
|
|
2932
|
-
const config2 =
|
|
2225
|
+
const config2 = loadConfig5();
|
|
2933
2226
|
const workspaceSetting = config2.agents.defaults.workspace;
|
|
2934
|
-
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join6(getDataDir6(), DEFAULT_WORKSPACE_DIR) :
|
|
2935
|
-
const workspaceExisted =
|
|
2227
|
+
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join6(getDataDir6(), DEFAULT_WORKSPACE_DIR) : expandHome(workspaceSetting);
|
|
2228
|
+
const workspaceExisted = existsSync6(workspacePath);
|
|
2936
2229
|
mkdirSync4(workspacePath, { recursive: true });
|
|
2937
2230
|
const templateResult = this.workspaceManager.createWorkspaceTemplates(workspacePath, { force });
|
|
2938
2231
|
if (createdConfig) {
|
|
@@ -3029,11 +2322,8 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
3029
2322
|
await this.serviceCommands.stopService();
|
|
3030
2323
|
}
|
|
3031
2324
|
async agent(opts) {
|
|
3032
|
-
const config2 =
|
|
3033
|
-
const workspace =
|
|
3034
|
-
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
3035
|
-
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
3036
|
-
logPluginDiagnostics(pluginRegistry);
|
|
2325
|
+
const config2 = loadConfig5();
|
|
2326
|
+
const workspace = getWorkspacePath3(config2.agents.defaults.workspace);
|
|
3037
2327
|
const bus = new MessageBus2();
|
|
3038
2328
|
const provider = this.serviceCommands.createProvider(config2) ?? this.serviceCommands.createMissingProvider(config2);
|
|
3039
2329
|
const providerManager = new ProviderManager2(provider);
|
|
@@ -3049,14 +2339,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
3049
2339
|
execConfig: config2.tools.exec,
|
|
3050
2340
|
restrictToWorkspace: config2.tools.restrictToWorkspace,
|
|
3051
2341
|
contextConfig: config2.agents.context,
|
|
3052
|
-
config: config2
|
|
3053
|
-
extensionRegistry,
|
|
3054
|
-
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints2({
|
|
3055
|
-
registry: pluginRegistry,
|
|
3056
|
-
channel,
|
|
3057
|
-
cfg: loadConfig6(),
|
|
3058
|
-
accountId
|
|
3059
|
-
})
|
|
2342
|
+
config: config2
|
|
3060
2343
|
});
|
|
3061
2344
|
if (opts.message) {
|
|
3062
2345
|
const response = await agentLoop.processDirect({
|
|
@@ -3071,10 +2354,10 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
3071
2354
|
console.log(`${this.logo} Interactive mode (type exit or Ctrl+C to quit)
|
|
3072
2355
|
`);
|
|
3073
2356
|
const historyFile = join6(getDataDir6(), "history", "cli_history");
|
|
3074
|
-
const historyDir =
|
|
2357
|
+
const historyDir = resolve7(historyFile, "..");
|
|
3075
2358
|
mkdirSync4(historyDir, { recursive: true });
|
|
3076
|
-
const history =
|
|
3077
|
-
const rl =
|
|
2359
|
+
const history = existsSync6(historyFile) ? readFileSync5(historyFile, "utf-8").split("\n").filter(Boolean) : [];
|
|
2360
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
3078
2361
|
rl.on("close", () => {
|
|
3079
2362
|
const merged = history.concat(rl.history ?? []);
|
|
3080
2363
|
writeFileSync3(historyFile, merged.join("\n"));
|
|
@@ -3134,27 +2417,6 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
3134
2417
|
console.log(`Tip: restart ${APP_NAME4} to apply the update.`);
|
|
3135
2418
|
}
|
|
3136
2419
|
}
|
|
3137
|
-
pluginsList(opts = {}) {
|
|
3138
|
-
this.pluginCommands.pluginsList(opts);
|
|
3139
|
-
}
|
|
3140
|
-
pluginsInfo(id, opts = {}) {
|
|
3141
|
-
this.pluginCommands.pluginsInfo(id, opts);
|
|
3142
|
-
}
|
|
3143
|
-
async pluginsEnable(id) {
|
|
3144
|
-
await this.pluginCommands.pluginsEnable(id);
|
|
3145
|
-
}
|
|
3146
|
-
async pluginsDisable(id) {
|
|
3147
|
-
await this.pluginCommands.pluginsDisable(id);
|
|
3148
|
-
}
|
|
3149
|
-
async pluginsUninstall(id, opts = {}) {
|
|
3150
|
-
await this.pluginCommands.pluginsUninstall(id, opts);
|
|
3151
|
-
}
|
|
3152
|
-
async pluginsInstall(pathOrSpec, opts = {}) {
|
|
3153
|
-
await this.pluginCommands.pluginsInstall(pathOrSpec, opts);
|
|
3154
|
-
}
|
|
3155
|
-
pluginsDoctor() {
|
|
3156
|
-
this.pluginCommands.pluginsDoctor();
|
|
3157
|
-
}
|
|
3158
2420
|
configGet(pathExpr, opts = {}) {
|
|
3159
2421
|
this.configCommands.configGet(pathExpr, opts);
|
|
3160
2422
|
}
|
|
@@ -3170,9 +2432,6 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
3170
2432
|
channelsLogin() {
|
|
3171
2433
|
this.channelCommands.channelsLogin();
|
|
3172
2434
|
}
|
|
3173
|
-
async channelsAdd(opts) {
|
|
3174
|
-
await this.channelCommands.channelsAdd(opts);
|
|
3175
|
-
}
|
|
3176
2435
|
cronList(opts) {
|
|
3177
2436
|
this.cronCommands.cronList(opts);
|
|
3178
2437
|
}
|
|
@@ -3195,7 +2454,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
3195
2454
|
await this.diagnosticsCommands.doctor(opts);
|
|
3196
2455
|
}
|
|
3197
2456
|
async skillsInstall(options) {
|
|
3198
|
-
const workdir = options.workdir ?
|
|
2457
|
+
const workdir = options.workdir ? expandHome(options.workdir) : getWorkspacePath3();
|
|
3199
2458
|
const result = await installClawHubSkill({
|
|
3200
2459
|
slug: options.slug,
|
|
3201
2460
|
version: options.version,
|
|
@@ -3238,20 +2497,11 @@ var skills = program.command("skills").description("Manage skills");
|
|
|
3238
2497
|
registerClawHubInstall(skills);
|
|
3239
2498
|
var clawhub = program.command("clawhub").description("Install skills from ClawHub");
|
|
3240
2499
|
registerClawHubInstall(clawhub);
|
|
3241
|
-
var plugins = program.command("plugins").description("Manage OpenClaw-compatible plugins");
|
|
3242
|
-
plugins.command("list").description("List discovered plugins").option("--json", "Print JSON").option("--enabled", "Only show enabled plugins", false).option("--verbose", "Show detailed entries", false).action((opts) => runtime.pluginsList(opts));
|
|
3243
|
-
plugins.command("info <id>").description("Show plugin details").option("--json", "Print JSON").action((id, opts) => runtime.pluginsInfo(id, opts));
|
|
3244
|
-
plugins.command("enable <id>").description("Enable a plugin in config").action((id) => runtime.pluginsEnable(id));
|
|
3245
|
-
plugins.command("disable <id>").description("Disable a plugin in config").action((id) => runtime.pluginsDisable(id));
|
|
3246
|
-
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));
|
|
3247
|
-
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));
|
|
3248
|
-
plugins.command("doctor").description("Report plugin load issues").action(() => runtime.pluginsDoctor());
|
|
3249
2500
|
var config = program.command("config").description("Manage config values");
|
|
3250
2501
|
config.command("get <path>").description("Get a config value by dot path").option("--json", "Output JSON", false).action((path, opts) => runtime.configGet(path, opts));
|
|
3251
2502
|
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));
|
|
3252
2503
|
config.command("unset <path>").description("Remove a config value by dot path").action((path) => runtime.configUnset(path));
|
|
3253
2504
|
var channels = program.command("channels").description("Manage channels");
|
|
3254
|
-
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));
|
|
3255
2505
|
channels.command("status").description("Show channel status").action(() => runtime.channelsStatus());
|
|
3256
2506
|
channels.command("login").description("Link device via QR code").action(() => runtime.channelsLogin());
|
|
3257
2507
|
var cron = program.command("cron").description("Manage scheduled tasks");
|