nextclaw 0.16.33 → 0.17.0
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 +1493 -1042
- package/package.json +15 -14
- package/{templates → resources}/USAGE.md +98 -47
- package/templates/AGENTS.md +1 -1
- package/ui-dist/assets/{ChannelsList-DVDu1xvz.js → ChannelsList-NKNKsf1J.js} +1 -1
- package/ui-dist/assets/ChatPage-p23OnnEI.js +43 -0
- package/ui-dist/assets/DocBrowser-C8b2uPgL.js +1 -0
- package/ui-dist/assets/{DocBrowser-BmtBLFU0.js → DocBrowser-DxdSujSc.js} +1 -1
- package/ui-dist/assets/{DocBrowserContext-YIKkPb76.js → DocBrowserContext-CQ-8jMha.js} +1 -1
- package/ui-dist/assets/{LogoBadge-F7ZWdxLT.js → LogoBadge-D-KQIN4U.js} +1 -1
- package/ui-dist/assets/{MarketplacePage-Buo9HrOz.js → MarketplacePage-CRNvxtvx.js} +2 -2
- package/ui-dist/assets/MarketplacePage-GGkEXowp.js +1 -0
- package/ui-dist/assets/{McpMarketplacePage-JnkYwK7p.js → McpMarketplacePage-Cu7GmCcc.js} +2 -2
- package/ui-dist/assets/{ModelConfig-BYRhgp0c.js → ModelConfig-CEpx9fro.js} +1 -1
- package/ui-dist/assets/{ProvidersList-DmLyyHvX.js → ProvidersList-BWbUb7-2.js} +1 -1
- package/ui-dist/assets/{RemoteAccessPage-CDSSvH7Z.js → RemoteAccessPage-NsawrZb0.js} +1 -1
- package/ui-dist/assets/RuntimeConfig-BJHBsVTd.js +1 -0
- package/ui-dist/assets/{SearchConfig-D5f1EkLE.js → SearchConfig-BsaX_WYy.js} +1 -1
- package/ui-dist/assets/{SecretsConfig-D61IKcYt.js → SecretsConfig-CgDZOd3w.js} +1 -1
- package/ui-dist/assets/{SessionsConfig-BRIxVTEv.js → SessionsConfig-Dd-KM7F7.js} +2 -2
- package/ui-dist/assets/{book-open-CXoF5nQC.js → book-open-FnK2xCQd.js} +1 -1
- package/ui-dist/assets/chat-session-display-BD_AN71I.js +1 -0
- package/ui-dist/assets/{chunk-JZWAC4HX-CvRWvTy5.js → chunk-JZWAC4HX-B5l0hr_u.js} +1 -1
- package/ui-dist/assets/{config-DJswxxE8.js → config-JKmXfZ3q.js} +1 -1
- package/ui-dist/assets/{createLucideIcon-CjGHOWb6.js → createLucideIcon-o1WWhwhd.js} +1 -1
- package/ui-dist/assets/{dist-nqTTbVdA.js → dist-C_moWYv7.js} +1 -1
- package/ui-dist/assets/{dist-Cl2QB-2y.js → dist-DazA6Wd_.js} +1 -1
- package/ui-dist/assets/{external-link-tIO7zING.js → external-link-BKje3SiD.js} +1 -1
- package/ui-dist/assets/{hash-JWUyl1pT.js → hash-DfW4DT8O.js} +1 -1
- package/ui-dist/assets/i18n-BK1w-oBy.js +1 -0
- package/ui-dist/assets/index-BZaB1TqM.js +6 -0
- package/ui-dist/assets/index-DaR9igPC.css +1 -0
- package/ui-dist/assets/{label-BIpeNu4r.js → label-BzDWmdOe.js} +1 -1
- package/ui-dist/assets/loader-circle-DdZPxBUz.js +1 -0
- package/ui-dist/assets/{logos-DThdM9lk.js → logos-CTLlde_T.js} +1 -1
- package/ui-dist/assets/{page-layout-D3Xo605Z.js → page-layout-BagR3t59.js} +1 -1
- package/ui-dist/assets/plus-DP2PSCPO.js +1 -0
- package/ui-dist/assets/{popover-BJRUGA_H.js → popover-5DWhNfd4.js} +1 -1
- package/ui-dist/assets/{provider-models-bz5y28rq.js → provider-models-DJ29qHuA.js} +1 -1
- package/ui-dist/assets/{react-7ZHqQtEV.js → react-C3yu5yge.js} +1 -1
- package/ui-dist/assets/{refresh-ccw-CC6-_QuL.js → refresh-ccw-BAJf-h7w.js} +1 -1
- package/ui-dist/assets/{save-DJM5RRWW.js → save-aa6z4GJL.js} +1 -1
- package/ui-dist/assets/search-pD6ZwQYF.js +1 -0
- package/ui-dist/assets/{security-config-DbUyWcQz.js → security-config-DRDxrApx.js} +1 -1
- package/ui-dist/assets/{select-DSkTc61S.js → select-BHJPiJWt.js} +1 -1
- package/ui-dist/assets/skeleton-D6kCk9Y6.js +1 -0
- package/ui-dist/assets/{status-dot-LNBlDu3q.js → status-dot-DUwsTIdv.js} +1 -1
- package/ui-dist/assets/{switch-Bo-Y46HZ.js → switch-B6nCfcOB.js} +1 -1
- package/ui-dist/assets/{tabs-custom-DXv507_2.js → tabs-custom-B57SMElx.js} +1 -1
- package/ui-dist/assets/{trash-2-DFZmW6Gg.js → trash-2-CrjYH5ok.js} +1 -1
- package/ui-dist/assets/{useConfirmDialog-COwYXDKm.js → useConfirmDialog-DsxnXB1B.js} +1 -1
- package/ui-dist/assets/{useMutation-DrZrOgVL.js → useMutation-oTTWXgLG.js} +1 -1
- package/ui-dist/assets/x-CTIQHUuD.js +1 -0
- package/ui-dist/index.html +18 -18
- package/ui-dist/assets/ChatPage-Z9tRzm_n.js +0 -43
- package/ui-dist/assets/DocBrowser-B9OaZjmg.js +0 -1
- package/ui-dist/assets/MarketplacePage-D6rVQEQR.js +0 -1
- package/ui-dist/assets/RuntimeConfig-v7a7Fe3x.js +0 -1
- package/ui-dist/assets/chat-session-display-D0WpnuRZ.js +0 -1
- package/ui-dist/assets/i18n-CDHMXlRZ.js +0 -1
- package/ui-dist/assets/index-BuwbBgmT.js +0 -6
- package/ui-dist/assets/index-bZ8cqQIS.css +0 -1
- package/ui-dist/assets/loader-circle-Cs8XVFTw.js +0 -1
- package/ui-dist/assets/plus-PHf8q-Ct.js +0 -1
- package/ui-dist/assets/search-C91yH_6y.js +0 -1
- package/ui-dist/assets/skeleton-Dzg-HOiN.js +0 -1
- package/ui-dist/assets/x-D7Q1yqSF.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -6,32 +6,18 @@ import { APP_NAME as APP_NAME6, APP_TAGLINE } from "@nextclaw/core";
|
|
|
6
6
|
import { registerRemoteCommands } from "@nextclaw/remote";
|
|
7
7
|
|
|
8
8
|
// src/cli/runtime.ts
|
|
9
|
-
import {
|
|
10
|
-
loadConfig as loadConfig21,
|
|
11
|
-
saveConfig as saveConfig11,
|
|
12
|
-
getConfigPath as getConfigPath11,
|
|
13
|
-
getDataDir as getDataDir11,
|
|
14
|
-
getWorkspacePath as getWorkspacePath13,
|
|
15
|
-
expandHome as expandHome2,
|
|
16
|
-
MessageBus as MessageBus3,
|
|
17
|
-
AgentLoop,
|
|
18
|
-
ProviderManager as ProviderManager2,
|
|
19
|
-
resolveConfigSecrets as resolveConfigSecrets7,
|
|
20
|
-
APP_NAME as APP_NAME5,
|
|
21
|
-
DEFAULT_WORKSPACE_DIR,
|
|
22
|
-
DEFAULT_WORKSPACE_PATH
|
|
23
|
-
} from "@nextclaw/core";
|
|
9
|
+
import { loadConfig as loadConfig22, saveConfig as saveConfig11, getConfigPath as getConfigPath11, getDataDir as getDataDir11, getWorkspacePath as getWorkspacePath14, expandHome as expandHome3, MessageBus as MessageBus3, AgentLoop, ProviderManager as ProviderManager2, resolveConfigSecrets as resolveConfigSecrets7, APP_NAME as APP_NAME5, DEFAULT_WORKSPACE_DIR, DEFAULT_WORKSPACE_PATH } from "@nextclaw/core";
|
|
24
10
|
import { RemoteRuntimeActions } from "@nextclaw/remote";
|
|
25
11
|
import {
|
|
26
12
|
getPluginChannelBindings as getPluginChannelBindings6,
|
|
27
13
|
resolvePluginChannelMessageToolHints as resolvePluginChannelMessageToolHints3,
|
|
28
14
|
setPluginRuntimeBridge as setPluginRuntimeBridge3
|
|
29
15
|
} from "@nextclaw/openclaw-compat";
|
|
30
|
-
import { existsSync as
|
|
31
|
-
import { join as join9, resolve as
|
|
16
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
17
|
+
import { join as join9, resolve as resolve16 } from "path";
|
|
32
18
|
import { createInterface as createInterface3 } from "readline";
|
|
33
19
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
34
|
-
import { spawn as
|
|
20
|
+
import { spawn as spawn5 } from "child_process";
|
|
35
21
|
|
|
36
22
|
// src/cli/restart-coordinator.ts
|
|
37
23
|
var RestartCoordinator = class {
|
|
@@ -197,6 +183,26 @@ function parseSessionKey(sessionKey) {
|
|
|
197
183
|
};
|
|
198
184
|
}
|
|
199
185
|
|
|
186
|
+
// src/cli/runtime-helpers.ts
|
|
187
|
+
import { expandHome, getWorkspacePath } from "@nextclaw/core";
|
|
188
|
+
function resolveSkillsInstallWorkdir(params) {
|
|
189
|
+
if (params.explicitWorkdir) {
|
|
190
|
+
return expandHome(params.explicitWorkdir);
|
|
191
|
+
}
|
|
192
|
+
return getWorkspacePath(params.configuredWorkspace);
|
|
193
|
+
}
|
|
194
|
+
function parseStartTimeoutMs(value) {
|
|
195
|
+
if (value === void 0) {
|
|
196
|
+
return void 0;
|
|
197
|
+
}
|
|
198
|
+
const parsed = Number(value);
|
|
199
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
200
|
+
console.error("Invalid --start-timeout value. Provide milliseconds (e.g. 45000).");
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
return Math.floor(parsed);
|
|
204
|
+
}
|
|
205
|
+
|
|
200
206
|
// src/cli/startup-trace.ts
|
|
201
207
|
var STARTUP_TRACE_ENABLED = process.env.NEXTCLAW_STARTUP_TRACE === "1";
|
|
202
208
|
var STARTUP_TRACE_ORIGIN_MS = Date.now();
|
|
@@ -238,7 +244,7 @@ async function measureStartupAsync(step, fn, fields) {
|
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
// src/cli/skills/marketplace.ts
|
|
241
|
-
import {
|
|
247
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
242
248
|
import { basename, dirname, isAbsolute, join, relative, resolve as resolve3 } from "path";
|
|
243
249
|
import { SkillsLoader } from "@nextclaw/core";
|
|
244
250
|
|
|
@@ -456,8 +462,8 @@ function isRecord(value) {
|
|
|
456
462
|
var MARKETPLACE_NETWORK_RETRY_ATTEMPTS = 5;
|
|
457
463
|
var MARKETPLACE_NETWORK_RETRY_BASE_MS = 350;
|
|
458
464
|
function sleepMs(ms) {
|
|
459
|
-
return new Promise((
|
|
460
|
-
setTimeout(
|
|
465
|
+
return new Promise((resolve17) => {
|
|
466
|
+
setTimeout(resolve17, ms);
|
|
461
467
|
});
|
|
462
468
|
}
|
|
463
469
|
function isRetryableMarketplaceNetworkError(error) {
|
|
@@ -503,36 +509,54 @@ async function installMarketplaceSkill(options) {
|
|
|
503
509
|
if (!existsSync4(workdir)) {
|
|
504
510
|
throw new Error(`Workdir does not exist: ${workdir}`);
|
|
505
511
|
}
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
512
|
+
const destinationDir = resolveMarketplaceSkillDestinationDir({
|
|
513
|
+
workdir,
|
|
514
|
+
slug,
|
|
515
|
+
dir: options.dir
|
|
516
|
+
});
|
|
509
517
|
const apiBase = resolveMarketplaceApiBase(options.apiBaseUrl);
|
|
510
518
|
const item = await fetchMarketplaceSkillItem(apiBase, slug);
|
|
511
519
|
if (item.install.kind === "builtin") {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
destinationDir,
|
|
517
|
-
alreadyInstalled: true,
|
|
518
|
-
source: "builtin"
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
throw new Error(`Skill directory already exists: ${destinationDir} (use --force)`);
|
|
522
|
-
}
|
|
523
|
-
if (existsSync4(destinationDir) && options.force) {
|
|
524
|
-
rmSync2(destinationDir, { recursive: true, force: true });
|
|
525
|
-
}
|
|
526
|
-
installBuiltinSkill(workdir, destinationDir, slug);
|
|
527
|
-
return {
|
|
528
|
-
slug,
|
|
529
|
-
destinationDir,
|
|
530
|
-
source: "builtin"
|
|
531
|
-
};
|
|
520
|
+
return resolveBuiltinMarketplaceInstallResult({
|
|
521
|
+
workdir,
|
|
522
|
+
slug
|
|
523
|
+
});
|
|
532
524
|
}
|
|
533
525
|
const filesPayload = await fetchMarketplaceSkillFiles(apiBase, slug);
|
|
534
|
-
|
|
535
|
-
|
|
526
|
+
const existingInstall = prepareMarketplaceSkillDestinationDir({
|
|
527
|
+
destinationDir,
|
|
528
|
+
files: filesPayload.files,
|
|
529
|
+
force: options.force,
|
|
530
|
+
slug
|
|
531
|
+
});
|
|
532
|
+
if (existingInstall) {
|
|
533
|
+
return existingInstall;
|
|
534
|
+
}
|
|
535
|
+
await writeMarketplaceSkillFiles({
|
|
536
|
+
destinationDir,
|
|
537
|
+
files: filesPayload.files,
|
|
538
|
+
apiBase,
|
|
539
|
+
slug
|
|
540
|
+
});
|
|
541
|
+
ensureInstalledMarketplaceSkill(destinationDir, slug);
|
|
542
|
+
return buildMarketplaceInstallResult(slug, destinationDir);
|
|
543
|
+
}
|
|
544
|
+
function resolveMarketplaceSkillDestinationDir(params) {
|
|
545
|
+
const dirName = params.dir?.trim() || "skills";
|
|
546
|
+
return isAbsolute(dirName) ? resolve3(dirName, params.slug) : resolve3(params.workdir, dirName, params.slug);
|
|
547
|
+
}
|
|
548
|
+
function resolveBuiltinMarketplaceInstallResult(params) {
|
|
549
|
+
return {
|
|
550
|
+
slug: params.slug,
|
|
551
|
+
destinationDir: resolveBuiltinSkillDir(params.workdir, params.slug),
|
|
552
|
+
alreadyInstalled: true,
|
|
553
|
+
source: "builtin"
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
function prepareMarketplaceSkillDestinationDir(params) {
|
|
557
|
+
const { destinationDir, files, force, slug } = params;
|
|
558
|
+
if (!force && existsSync4(destinationDir)) {
|
|
559
|
+
const existingDirState = inspectMarketplaceSkillDirectory(destinationDir, files);
|
|
536
560
|
if (existingDirState === "installed") {
|
|
537
561
|
return {
|
|
538
562
|
slug,
|
|
@@ -541,17 +565,20 @@ async function installMarketplaceSkill(options) {
|
|
|
541
565
|
source: "marketplace"
|
|
542
566
|
};
|
|
543
567
|
}
|
|
544
|
-
if (existingDirState
|
|
545
|
-
rmSync2(destinationDir, { recursive: true, force: true });
|
|
546
|
-
} else {
|
|
568
|
+
if (existingDirState !== "recoverable") {
|
|
547
569
|
throw new Error(`Skill directory already exists: ${destinationDir} (use --force)`);
|
|
548
570
|
}
|
|
571
|
+
rmSync2(destinationDir, { recursive: true, force: true });
|
|
549
572
|
}
|
|
550
|
-
if (existsSync4(destinationDir)
|
|
573
|
+
if (force && existsSync4(destinationDir)) {
|
|
551
574
|
rmSync2(destinationDir, { recursive: true, force: true });
|
|
552
575
|
}
|
|
553
576
|
mkdirSync2(destinationDir, { recursive: true });
|
|
554
|
-
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
async function writeMarketplaceSkillFiles(params) {
|
|
580
|
+
const { destinationDir, files, apiBase, slug } = params;
|
|
581
|
+
for (const file of files) {
|
|
555
582
|
const targetPath = resolve3(destinationDir, ...file.path.split("/"));
|
|
556
583
|
const rel = relative(destinationDir, targetPath);
|
|
557
584
|
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
@@ -561,9 +588,13 @@ async function installMarketplaceSkill(options) {
|
|
|
561
588
|
const bytes = file.contentBase64 ? decodeMarketplaceFileContent(file.path, file.contentBase64) : await fetchMarketplaceSkillFileBlob(apiBase, slug, file);
|
|
562
589
|
writeFileSync2(targetPath, bytes);
|
|
563
590
|
}
|
|
591
|
+
}
|
|
592
|
+
function ensureInstalledMarketplaceSkill(destinationDir, slug) {
|
|
564
593
|
if (!existsSync4(join(destinationDir, "SKILL.md"))) {
|
|
565
594
|
throw new Error(`Marketplace skill ${slug} does not include SKILL.md`);
|
|
566
595
|
}
|
|
596
|
+
}
|
|
597
|
+
function buildMarketplaceInstallResult(slug, destinationDir) {
|
|
567
598
|
return {
|
|
568
599
|
slug,
|
|
569
600
|
destinationDir,
|
|
@@ -696,13 +727,13 @@ function collectFiles(rootDir) {
|
|
|
696
727
|
walk(rootDir, "");
|
|
697
728
|
return output;
|
|
698
729
|
}
|
|
699
|
-
function
|
|
730
|
+
function resolveBuiltinSkillDir(workdir, skillName) {
|
|
700
731
|
const loader = new SkillsLoader(workdir);
|
|
701
|
-
const
|
|
702
|
-
if (!
|
|
703
|
-
throw new Error(`
|
|
732
|
+
const builtinSkill = loader.listSkills(false).find((skill) => skill.name === skillName && skill.source === "builtin");
|
|
733
|
+
if (!builtinSkill) {
|
|
734
|
+
throw new Error(`Built-in skill not found in local installation: ${skillName}`);
|
|
704
735
|
}
|
|
705
|
-
|
|
736
|
+
return dirname(builtinSkill.path);
|
|
706
737
|
}
|
|
707
738
|
async function fetchMarketplaceSkillItem(apiBase, slug) {
|
|
708
739
|
return runWithMarketplaceNetworkRetry(async () => {
|
|
@@ -909,10 +940,6 @@ async function resolvePublicIp(timeoutMs = 1500) {
|
|
|
909
940
|
}
|
|
910
941
|
return null;
|
|
911
942
|
}
|
|
912
|
-
function buildServeArgs(options) {
|
|
913
|
-
const cliPath = fileURLToPath(new URL("./index.js", import.meta.url));
|
|
914
|
-
return [cliPath, "serve", "--ui-port", String(options.uiPort)];
|
|
915
|
-
}
|
|
916
943
|
function readServiceState() {
|
|
917
944
|
const path2 = resolveServiceStatePath();
|
|
918
945
|
if (!existsSync5(path2)) {
|
|
@@ -965,7 +992,7 @@ async function waitForExit(pid, timeoutMs) {
|
|
|
965
992
|
if (!isProcessRunning(pid)) {
|
|
966
993
|
return true;
|
|
967
994
|
}
|
|
968
|
-
await new Promise((
|
|
995
|
+
await new Promise((resolve17) => setTimeout(resolve17, 200));
|
|
969
996
|
}
|
|
970
997
|
return !isProcessRunning(pid);
|
|
971
998
|
}
|
|
@@ -1096,8 +1123,8 @@ function printAgentResponse(response) {
|
|
|
1096
1123
|
async function prompt(rl, question) {
|
|
1097
1124
|
rl.setPrompt(question);
|
|
1098
1125
|
rl.prompt();
|
|
1099
|
-
return new Promise((
|
|
1100
|
-
rl.once("line", (line) =>
|
|
1126
|
+
return new Promise((resolve17) => {
|
|
1127
|
+
rl.once("line", (line) => resolve17(line));
|
|
1101
1128
|
});
|
|
1102
1129
|
}
|
|
1103
1130
|
|
|
@@ -1159,7 +1186,7 @@ import {
|
|
|
1159
1186
|
resolveUninstallDirectoryTargets
|
|
1160
1187
|
} from "@nextclaw/openclaw-compat";
|
|
1161
1188
|
|
|
1162
|
-
// src/cli/commands/plugin-command-utils.ts
|
|
1189
|
+
// src/cli/commands/plugin/plugin-command-utils.ts
|
|
1163
1190
|
import { builtinProviderIds } from "@nextclaw/runtime";
|
|
1164
1191
|
var RESERVED_PROVIDER_IDS = builtinProviderIds();
|
|
1165
1192
|
var RESERVED_TOOL_NAMES = [
|
|
@@ -1208,7 +1235,7 @@ function appendPluginCapabilityLines(lines, plugin) {
|
|
|
1208
1235
|
}
|
|
1209
1236
|
}
|
|
1210
1237
|
|
|
1211
|
-
// src/cli/commands/dev-first-party-plugin-load-paths.ts
|
|
1238
|
+
// src/cli/commands/plugin/dev-first-party-plugin-load-paths.ts
|
|
1212
1239
|
import fs from "fs";
|
|
1213
1240
|
import path from "path";
|
|
1214
1241
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1362,12 +1389,12 @@ var applyDevFirstPartyPluginLoadPaths = (config2, workspaceExtensionsDir) => {
|
|
|
1362
1389
|
// src/cli/commands/plugins.ts
|
|
1363
1390
|
import {
|
|
1364
1391
|
loadConfig as loadConfig3,
|
|
1365
|
-
getWorkspacePath as
|
|
1392
|
+
getWorkspacePath as getWorkspacePath3
|
|
1366
1393
|
} from "@nextclaw/core";
|
|
1367
1394
|
import { createInterface } from "readline";
|
|
1368
1395
|
import { resolve as resolve7 } from "path";
|
|
1369
1396
|
|
|
1370
|
-
// src/cli/commands/plugin-mutation-actions.ts
|
|
1397
|
+
// src/cli/commands/plugin/plugin-mutation-actions.ts
|
|
1371
1398
|
import {
|
|
1372
1399
|
addPluginLoadPath,
|
|
1373
1400
|
buildPluginStatusReport,
|
|
@@ -1380,7 +1407,11 @@ import {
|
|
|
1380
1407
|
} from "@nextclaw/openclaw-compat";
|
|
1381
1408
|
import { existsSync as existsSync6 } from "fs";
|
|
1382
1409
|
import { resolve as resolve6 } from "path";
|
|
1383
|
-
import { expandHome, getWorkspacePath, loadConfig as loadConfig2, saveConfig } from "@nextclaw/core";
|
|
1410
|
+
import { expandHome as expandHome2, getWorkspacePath as getWorkspacePath2, loadConfig as loadConfig2, saveConfig } from "@nextclaw/core";
|
|
1411
|
+
var pluginInstallLogger = {
|
|
1412
|
+
info: (message) => console.log(message),
|
|
1413
|
+
warn: (message) => console.warn(message)
|
|
1414
|
+
};
|
|
1384
1415
|
function resolveFileNpmSpecToLocalPath(raw) {
|
|
1385
1416
|
const trimmed = raw.trim();
|
|
1386
1417
|
if (!trimmed.toLowerCase().startsWith("file:")) {
|
|
@@ -1411,6 +1442,79 @@ function isArchivePath(filePath) {
|
|
|
1411
1442
|
const lower = filePath.toLowerCase();
|
|
1412
1443
|
return lower.endsWith(".zip") || lower.endsWith(".tgz") || lower.endsWith(".tar.gz") || lower.endsWith(".tar");
|
|
1413
1444
|
}
|
|
1445
|
+
function saveLinkedPluginInstall(config2, params) {
|
|
1446
|
+
let next = addPluginLoadPath(config2, params.resolvedPath);
|
|
1447
|
+
next = enablePluginInConfig(next, params.pluginId);
|
|
1448
|
+
next = recordPluginInstall(next, {
|
|
1449
|
+
pluginId: params.pluginId,
|
|
1450
|
+
source: "path",
|
|
1451
|
+
sourcePath: params.resolvedPath,
|
|
1452
|
+
installPath: params.resolvedPath,
|
|
1453
|
+
version: params.version ?? void 0
|
|
1454
|
+
});
|
|
1455
|
+
saveConfig(next);
|
|
1456
|
+
return {
|
|
1457
|
+
message: `Linked plugin path: ${params.resolvedPath}`
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
function saveInstalledPluginResult(config2, params) {
|
|
1461
|
+
let next = enablePluginInConfig(config2, params.pluginId);
|
|
1462
|
+
next = recordPluginInstall(next, {
|
|
1463
|
+
pluginId: params.pluginId,
|
|
1464
|
+
source: params.source,
|
|
1465
|
+
sourcePath: params.sourcePath,
|
|
1466
|
+
spec: params.spec,
|
|
1467
|
+
installPath: params.installPath,
|
|
1468
|
+
version: params.version ?? void 0
|
|
1469
|
+
});
|
|
1470
|
+
saveConfig(next);
|
|
1471
|
+
return {
|
|
1472
|
+
message: `Installed plugin: ${params.pluginId}`
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
async function installPluginFromLocalPath(config2, resolvedPath, link) {
|
|
1476
|
+
if (link) {
|
|
1477
|
+
const probe = await installPluginFromPath({ path: resolvedPath, dryRun: true });
|
|
1478
|
+
if (!probe.ok) {
|
|
1479
|
+
throw new Error(probe.error);
|
|
1480
|
+
}
|
|
1481
|
+
return saveLinkedPluginInstall(config2, {
|
|
1482
|
+
resolvedPath,
|
|
1483
|
+
pluginId: probe.pluginId,
|
|
1484
|
+
version: probe.version
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
const result = await installPluginFromPath({
|
|
1488
|
+
path: resolvedPath,
|
|
1489
|
+
logger: pluginInstallLogger
|
|
1490
|
+
});
|
|
1491
|
+
if (!result.ok) {
|
|
1492
|
+
throw new Error(result.error);
|
|
1493
|
+
}
|
|
1494
|
+
return saveInstalledPluginResult(config2, {
|
|
1495
|
+
pluginId: result.pluginId,
|
|
1496
|
+
source: isArchivePath(resolvedPath) ? "archive" : "path",
|
|
1497
|
+
sourcePath: resolvedPath,
|
|
1498
|
+
installPath: result.targetDir,
|
|
1499
|
+
version: result.version
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
async function installPluginFromRegistrySpec(config2, spec) {
|
|
1503
|
+
const result = await installPluginFromNpmSpec({
|
|
1504
|
+
spec,
|
|
1505
|
+
logger: pluginInstallLogger
|
|
1506
|
+
});
|
|
1507
|
+
if (!result.ok) {
|
|
1508
|
+
throw new Error(result.error);
|
|
1509
|
+
}
|
|
1510
|
+
return saveInstalledPluginResult(config2, {
|
|
1511
|
+
pluginId: result.pluginId,
|
|
1512
|
+
source: "npm",
|
|
1513
|
+
spec,
|
|
1514
|
+
installPath: result.targetDir,
|
|
1515
|
+
version: result.version
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1414
1518
|
async function enablePluginMutation(id) {
|
|
1415
1519
|
const config2 = loadConfig2();
|
|
1416
1520
|
const next = enablePluginInConfig(config2, id);
|
|
@@ -1429,7 +1533,7 @@ async function disablePluginMutation(id) {
|
|
|
1429
1533
|
}
|
|
1430
1534
|
async function uninstallPluginMutation(id, opts = {}) {
|
|
1431
1535
|
const config2 = loadConfig2();
|
|
1432
|
-
const workspaceDir =
|
|
1536
|
+
const workspaceDir = getWorkspacePath2(config2.agents.defaults.workspace);
|
|
1433
1537
|
const report = buildPluginStatusReport({
|
|
1434
1538
|
config: config2,
|
|
1435
1539
|
workspaceDir,
|
|
@@ -1484,50 +1588,10 @@ async function installPluginMutation(pathOrSpec, opts = {}) {
|
|
|
1484
1588
|
throw new Error(fileSpec.error);
|
|
1485
1589
|
}
|
|
1486
1590
|
const normalized = fileSpec && fileSpec.ok ? fileSpec.path : pathOrSpec;
|
|
1487
|
-
const resolved = resolve6(
|
|
1591
|
+
const resolved = resolve6(expandHome2(normalized));
|
|
1488
1592
|
const config2 = loadConfig2();
|
|
1489
1593
|
if (existsSync6(resolved)) {
|
|
1490
|
-
|
|
1491
|
-
const probe = await installPluginFromPath({ path: resolved, dryRun: true });
|
|
1492
|
-
if (!probe.ok) {
|
|
1493
|
-
throw new Error(probe.error);
|
|
1494
|
-
}
|
|
1495
|
-
let next3 = addPluginLoadPath(config2, resolved);
|
|
1496
|
-
next3 = enablePluginInConfig(next3, probe.pluginId);
|
|
1497
|
-
next3 = recordPluginInstall(next3, {
|
|
1498
|
-
pluginId: probe.pluginId,
|
|
1499
|
-
source: "path",
|
|
1500
|
-
sourcePath: resolved,
|
|
1501
|
-
installPath: resolved,
|
|
1502
|
-
version: probe.version
|
|
1503
|
-
});
|
|
1504
|
-
saveConfig(next3);
|
|
1505
|
-
return {
|
|
1506
|
-
message: `Linked plugin path: ${resolved}`
|
|
1507
|
-
};
|
|
1508
|
-
}
|
|
1509
|
-
const result2 = await installPluginFromPath({
|
|
1510
|
-
path: resolved,
|
|
1511
|
-
logger: {
|
|
1512
|
-
info: (message) => console.log(message),
|
|
1513
|
-
warn: (message) => console.warn(message)
|
|
1514
|
-
}
|
|
1515
|
-
});
|
|
1516
|
-
if (!result2.ok) {
|
|
1517
|
-
throw new Error(result2.error);
|
|
1518
|
-
}
|
|
1519
|
-
let next2 = enablePluginInConfig(config2, result2.pluginId);
|
|
1520
|
-
next2 = recordPluginInstall(next2, {
|
|
1521
|
-
pluginId: result2.pluginId,
|
|
1522
|
-
source: isArchivePath(resolved) ? "archive" : "path",
|
|
1523
|
-
sourcePath: resolved,
|
|
1524
|
-
installPath: result2.targetDir,
|
|
1525
|
-
version: result2.version
|
|
1526
|
-
});
|
|
1527
|
-
saveConfig(next2);
|
|
1528
|
-
return {
|
|
1529
|
-
message: `Installed plugin: ${result2.pluginId}`
|
|
1530
|
-
};
|
|
1594
|
+
return installPluginFromLocalPath(config2, resolved, Boolean(opts.link));
|
|
1531
1595
|
}
|
|
1532
1596
|
if (opts.link) {
|
|
1533
1597
|
throw new Error("`--link` requires a local path.");
|
|
@@ -1535,31 +1599,10 @@ async function installPluginMutation(pathOrSpec, opts = {}) {
|
|
|
1535
1599
|
if (looksLikePath(pathOrSpec)) {
|
|
1536
1600
|
throw new Error(`Path not found: ${resolved}`);
|
|
1537
1601
|
}
|
|
1538
|
-
|
|
1539
|
-
spec: pathOrSpec,
|
|
1540
|
-
logger: {
|
|
1541
|
-
info: (message) => console.log(message),
|
|
1542
|
-
warn: (message) => console.warn(message)
|
|
1543
|
-
}
|
|
1544
|
-
});
|
|
1545
|
-
if (!result.ok) {
|
|
1546
|
-
throw new Error(result.error);
|
|
1547
|
-
}
|
|
1548
|
-
let next = enablePluginInConfig(config2, result.pluginId);
|
|
1549
|
-
next = recordPluginInstall(next, {
|
|
1550
|
-
pluginId: result.pluginId,
|
|
1551
|
-
source: "npm",
|
|
1552
|
-
spec: pathOrSpec,
|
|
1553
|
-
installPath: result.targetDir,
|
|
1554
|
-
version: result.version
|
|
1555
|
-
});
|
|
1556
|
-
saveConfig(next);
|
|
1557
|
-
return {
|
|
1558
|
-
message: `Installed plugin: ${result.pluginId}`
|
|
1559
|
-
};
|
|
1602
|
+
return installPluginFromRegistrySpec(config2, pathOrSpec);
|
|
1560
1603
|
}
|
|
1561
1604
|
|
|
1562
|
-
// src/cli/commands/plugin-extension-registry.ts
|
|
1605
|
+
// src/cli/commands/plugin/plugin-extension-registry.ts
|
|
1563
1606
|
function toExtensionRegistry(pluginRegistry) {
|
|
1564
1607
|
return {
|
|
1565
1608
|
tools: pluginRegistry.tools.map((tool) => ({
|
|
@@ -1647,7 +1690,7 @@ var PluginCommands = class {
|
|
|
1647
1690
|
}
|
|
1648
1691
|
pluginsList(opts = {}) {
|
|
1649
1692
|
const config2 = loadConfig3();
|
|
1650
|
-
const workspaceDir =
|
|
1693
|
+
const workspaceDir = getWorkspacePath3(config2.agents.defaults.workspace);
|
|
1651
1694
|
const report = buildPluginStatusReport2({
|
|
1652
1695
|
config: config2,
|
|
1653
1696
|
workspaceDir,
|
|
@@ -1699,7 +1742,7 @@ var PluginCommands = class {
|
|
|
1699
1742
|
}
|
|
1700
1743
|
pluginsInfo(id, opts = {}) {
|
|
1701
1744
|
const config2 = loadConfig3();
|
|
1702
|
-
const workspaceDir =
|
|
1745
|
+
const workspaceDir = getWorkspacePath3(config2.agents.defaults.workspace);
|
|
1703
1746
|
const report = buildPluginStatusReport2({
|
|
1704
1747
|
config: config2,
|
|
1705
1748
|
workspaceDir,
|
|
@@ -1780,7 +1823,7 @@ var PluginCommands = class {
|
|
|
1780
1823
|
console.log("`--keep-config` is deprecated, use `--keep-files`.");
|
|
1781
1824
|
}
|
|
1782
1825
|
const config2 = loadConfig3();
|
|
1783
|
-
const workspaceDir =
|
|
1826
|
+
const workspaceDir = getWorkspacePath3(config2.agents.defaults.workspace);
|
|
1784
1827
|
const report = buildPluginStatusReport2({
|
|
1785
1828
|
config: config2,
|
|
1786
1829
|
workspaceDir,
|
|
@@ -1864,7 +1907,7 @@ var PluginCommands = class {
|
|
|
1864
1907
|
}
|
|
1865
1908
|
pluginsDoctor() {
|
|
1866
1909
|
const config2 = loadConfig3();
|
|
1867
|
-
const workspaceDir =
|
|
1910
|
+
const workspaceDir = getWorkspacePath3(config2.agents.defaults.workspace);
|
|
1868
1911
|
const report = buildPluginStatusReport2({
|
|
1869
1912
|
config: config2,
|
|
1870
1913
|
workspaceDir,
|
|
@@ -1898,8 +1941,8 @@ var PluginCommands = class {
|
|
|
1898
1941
|
input: process.stdin,
|
|
1899
1942
|
output: process.stdout
|
|
1900
1943
|
});
|
|
1901
|
-
const answer = await new Promise((
|
|
1902
|
-
rl.question(`${question} [y/N] `, (line) =>
|
|
1944
|
+
const answer = await new Promise((resolve17) => {
|
|
1945
|
+
rl.question(`${question} [y/N] `, (line) => resolve17(line));
|
|
1903
1946
|
});
|
|
1904
1947
|
rl.close();
|
|
1905
1948
|
const normalized = answer.trim().toLowerCase();
|
|
@@ -1908,7 +1951,7 @@ var PluginCommands = class {
|
|
|
1908
1951
|
};
|
|
1909
1952
|
|
|
1910
1953
|
// src/cli/commands/config.ts
|
|
1911
|
-
import { buildReloadPlan, diffConfigPaths, getWorkspacePath as
|
|
1954
|
+
import { buildReloadPlan, diffConfigPaths, getWorkspacePath as getWorkspacePath4, loadConfig as loadConfig4, saveConfig as saveConfig2 } from "@nextclaw/core";
|
|
1912
1955
|
import { getPluginChannelBindings } from "@nextclaw/openclaw-compat";
|
|
1913
1956
|
|
|
1914
1957
|
// src/cli/config-path.ts
|
|
@@ -2016,33 +2059,48 @@ function setAtConfigPath(root, pathSegments, value) {
|
|
|
2016
2059
|
const next = pathSegments[i + 1];
|
|
2017
2060
|
const nextIsIndex = Boolean(next && isIndexSegment(next));
|
|
2018
2061
|
if (Array.isArray(current)) {
|
|
2019
|
-
|
|
2020
|
-
throw new Error(`Expected numeric index for array segment "${segment}"`);
|
|
2021
|
-
}
|
|
2022
|
-
const index = Number.parseInt(segment, 10);
|
|
2023
|
-
const existing2 = current[index];
|
|
2024
|
-
if (!existing2 || typeof existing2 !== "object") {
|
|
2025
|
-
current[index] = nextIsIndex ? [] : {};
|
|
2026
|
-
}
|
|
2027
|
-
current = current[index];
|
|
2062
|
+
current = getOrCreateArraySegment(current, segment, nextIsIndex, pathSegments.slice(0, i));
|
|
2028
2063
|
continue;
|
|
2029
2064
|
}
|
|
2030
|
-
|
|
2031
|
-
throw new Error(`Cannot traverse into "${segment}" (not an object)`);
|
|
2032
|
-
}
|
|
2033
|
-
const record = current;
|
|
2034
|
-
const existing = record[segment];
|
|
2035
|
-
if (!existing || typeof existing !== "object") {
|
|
2036
|
-
record[segment] = nextIsIndex ? [] : {};
|
|
2037
|
-
}
|
|
2038
|
-
current = record[segment];
|
|
2065
|
+
current = getOrCreateObjectSegment(current, segment, nextIsIndex);
|
|
2039
2066
|
}
|
|
2040
|
-
|
|
2067
|
+
setConfigPathValue(current, pathSegments[pathSegments.length - 1], value, pathSegments.slice(0, -1));
|
|
2068
|
+
}
|
|
2069
|
+
function ensureWritableArrayIndex(current, index, parentPath) {
|
|
2070
|
+
if (!Number.isFinite(index) || index < 0) {
|
|
2071
|
+
throw new Error(`Invalid array index "${index}"`);
|
|
2072
|
+
}
|
|
2073
|
+
if (index <= current.length) {
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
const parentPathExpr = formatConfigPath(parentPath);
|
|
2077
|
+
const parentLabel = parentPathExpr ? `"${parentPathExpr}"` : "the root array";
|
|
2078
|
+
throw new Error(`Cannot set sparse array index ${index} under ${parentLabel}. Set indices in order.`);
|
|
2079
|
+
}
|
|
2080
|
+
function getOrCreateArraySegment(current, segment, nextIsIndex, parentPath) {
|
|
2081
|
+
const index = parseArrayIndexSegment(segment);
|
|
2082
|
+
ensureWritableArrayIndex(current, index, parentPath);
|
|
2083
|
+
const existing = current[index];
|
|
2084
|
+
if (!existing || typeof existing !== "object") {
|
|
2085
|
+
current[index] = nextIsIndex ? [] : {};
|
|
2086
|
+
}
|
|
2087
|
+
return current[index];
|
|
2088
|
+
}
|
|
2089
|
+
function getOrCreateObjectSegment(current, segment, nextIsIndex) {
|
|
2090
|
+
if (!current || typeof current !== "object") {
|
|
2091
|
+
throw new Error(`Cannot traverse into "${segment}" (not an object)`);
|
|
2092
|
+
}
|
|
2093
|
+
const record = current;
|
|
2094
|
+
const existing = record[segment];
|
|
2095
|
+
if (!existing || typeof existing !== "object") {
|
|
2096
|
+
record[segment] = nextIsIndex ? [] : {};
|
|
2097
|
+
}
|
|
2098
|
+
return record[segment];
|
|
2099
|
+
}
|
|
2100
|
+
function setConfigPathValue(current, last, value, parentPath) {
|
|
2041
2101
|
if (Array.isArray(current)) {
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
}
|
|
2045
|
-
const index = Number.parseInt(last, 10);
|
|
2102
|
+
const index = parseArrayIndexSegment(last);
|
|
2103
|
+
ensureWritableArrayIndex(current, index, parentPath);
|
|
2046
2104
|
current[index] = value;
|
|
2047
2105
|
return;
|
|
2048
2106
|
}
|
|
@@ -2051,6 +2109,23 @@ function setAtConfigPath(root, pathSegments, value) {
|
|
|
2051
2109
|
}
|
|
2052
2110
|
current[last] = value;
|
|
2053
2111
|
}
|
|
2112
|
+
function parseArrayIndexSegment(segment) {
|
|
2113
|
+
if (!isIndexSegment(segment)) {
|
|
2114
|
+
throw new Error(`Expected numeric index for array segment "${segment}"`);
|
|
2115
|
+
}
|
|
2116
|
+
return Number.parseInt(segment, 10);
|
|
2117
|
+
}
|
|
2118
|
+
function formatConfigPath(pathSegments) {
|
|
2119
|
+
let expr = "";
|
|
2120
|
+
for (const segment of pathSegments) {
|
|
2121
|
+
if (isIndexSegment(segment)) {
|
|
2122
|
+
expr += `[${segment}]`;
|
|
2123
|
+
continue;
|
|
2124
|
+
}
|
|
2125
|
+
expr += expr ? `.${segment}` : segment;
|
|
2126
|
+
}
|
|
2127
|
+
return expr;
|
|
2128
|
+
}
|
|
2054
2129
|
function unsetAtConfigPath(root, pathSegments) {
|
|
2055
2130
|
let current = root;
|
|
2056
2131
|
for (let i = 0; i < pathSegments.length - 1; i += 1) {
|
|
@@ -2098,7 +2173,7 @@ function unsetAtConfigPath(root, pathSegments) {
|
|
|
2098
2173
|
return true;
|
|
2099
2174
|
}
|
|
2100
2175
|
|
|
2101
|
-
// src/cli/commands/channel-config-view.ts
|
|
2176
|
+
// src/cli/commands/channel/channel-config-view.ts
|
|
2102
2177
|
import { toPluginConfigView as toPluginConfigView2 } from "@nextclaw/openclaw-compat";
|
|
2103
2178
|
function resolveChannelConfigView(config2, bindings) {
|
|
2104
2179
|
return toPluginConfigView2(config2, bindings);
|
|
@@ -2221,7 +2296,7 @@ var ConfigCommands = class {
|
|
|
2221
2296
|
};
|
|
2222
2297
|
}
|
|
2223
2298
|
loadPluginChannelBindings(config2) {
|
|
2224
|
-
const workspaceDir =
|
|
2299
|
+
const workspaceDir = getWorkspacePath4(config2.agents.defaults.workspace);
|
|
2225
2300
|
const pluginRegistry = loadPluginRegistry(config2, workspaceDir);
|
|
2226
2301
|
return {
|
|
2227
2302
|
bindings: getPluginChannelBindings(pluginRegistry)
|
|
@@ -2797,7 +2872,7 @@ var SecretsCommands = class {
|
|
|
2797
2872
|
|
|
2798
2873
|
// src/cli/commands/channels.ts
|
|
2799
2874
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
2800
|
-
import { getWorkspacePath as
|
|
2875
|
+
import { getWorkspacePath as getWorkspacePath5, loadConfig as loadConfig7, saveConfig as saveConfig5 } from "@nextclaw/core";
|
|
2801
2876
|
import { BUILTIN_CHANNEL_PLUGIN_IDS, builtinProviderIds as builtinProviderIds2 } from "@nextclaw/runtime";
|
|
2802
2877
|
import { buildPluginStatusReport as buildPluginStatusReport3, enablePluginInConfig as enablePluginInConfig2, getPluginChannelBindings as getPluginChannelBindings2 } from "@nextclaw/openclaw-compat";
|
|
2803
2878
|
var CHANNEL_LABELS = {
|
|
@@ -2820,7 +2895,7 @@ var ChannelCommands = class {
|
|
|
2820
2895
|
}
|
|
2821
2896
|
channelsStatus() {
|
|
2822
2897
|
const config2 = loadConfig7();
|
|
2823
|
-
const workspaceDir =
|
|
2898
|
+
const workspaceDir = getWorkspacePath5(config2.agents.defaults.workspace);
|
|
2824
2899
|
const pluginRegistry = loadPluginRegistry(config2, workspaceDir);
|
|
2825
2900
|
const channelConfig = resolveChannelConfigView(config2, getPluginChannelBindings2(pluginRegistry));
|
|
2826
2901
|
console.log("Channel Status");
|
|
@@ -2878,7 +2953,7 @@ var ChannelCommands = class {
|
|
|
2878
2953
|
}
|
|
2879
2954
|
}
|
|
2880
2955
|
resolvePluginChannelContext(config2, channelId) {
|
|
2881
|
-
const workspaceDir =
|
|
2956
|
+
const workspaceDir = getWorkspacePath5(config2.agents.defaults.workspace);
|
|
2882
2957
|
const pluginRegistry = loadPluginRegistry(config2, workspaceDir);
|
|
2883
2958
|
const bindings = getPluginChannelBindings2(pluginRegistry);
|
|
2884
2959
|
const binding = bindings.find((entry) => entry.channelId === channelId || entry.pluginId === channelId);
|
|
@@ -2954,7 +3029,7 @@ var ChannelCommands = class {
|
|
|
2954
3029
|
process.exit(1);
|
|
2955
3030
|
}
|
|
2956
3031
|
const config2 = loadConfig7();
|
|
2957
|
-
const workspaceDir =
|
|
3032
|
+
const workspaceDir = getWorkspacePath5(config2.agents.defaults.workspace);
|
|
2958
3033
|
const pluginRegistry = loadPluginRegistry(config2, workspaceDir);
|
|
2959
3034
|
const bindings = getPluginChannelBindings2(pluginRegistry);
|
|
2960
3035
|
const binding = bindings.find((entry) => entry.channelId === channelId || entry.pluginId === channelId);
|
|
@@ -3005,7 +3080,7 @@ var ChannelCommands = class {
|
|
|
3005
3080
|
}
|
|
3006
3081
|
};
|
|
3007
3082
|
|
|
3008
|
-
// src/cli/commands/cron/cron-local.service.ts
|
|
3083
|
+
// src/cli/commands/cron-support/cron-local.service.ts
|
|
3009
3084
|
import { CronService, getDataDir as getDataDir3 } from "@nextclaw/core";
|
|
3010
3085
|
import { join as join3 } from "path";
|
|
3011
3086
|
function createCronService() {
|
|
@@ -3039,6 +3114,7 @@ var CronLocalService = class {
|
|
|
3039
3114
|
name: opts.name,
|
|
3040
3115
|
schedule,
|
|
3041
3116
|
message: opts.message,
|
|
3117
|
+
agentId: opts.agent,
|
|
3042
3118
|
deliver: Boolean(opts.deliver),
|
|
3043
3119
|
channel: opts.channel,
|
|
3044
3120
|
to: opts.to,
|
|
@@ -3060,7 +3136,7 @@ var CronLocalService = class {
|
|
|
3060
3136
|
};
|
|
3061
3137
|
};
|
|
3062
3138
|
|
|
3063
|
-
// src/cli/commands/cron/cron-job.utils.ts
|
|
3139
|
+
// src/cli/commands/cron-support/cron-job.utils.ts
|
|
3064
3140
|
function formatCronSchedule(schedule) {
|
|
3065
3141
|
if (schedule.kind === "every") {
|
|
3066
3142
|
return `every ${Math.round((schedule.everyMs ?? 0) / 1e3)}s`;
|
|
@@ -3239,11 +3315,128 @@ var CronCommands = class {
|
|
|
3239
3315
|
};
|
|
3240
3316
|
};
|
|
3241
3317
|
|
|
3318
|
+
// src/cli/commands/agents.ts
|
|
3319
|
+
import {
|
|
3320
|
+
BUILTIN_MAIN_AGENT_ID,
|
|
3321
|
+
createAgentProfile,
|
|
3322
|
+
loadConfig as loadConfig8,
|
|
3323
|
+
removeAgentProfile,
|
|
3324
|
+
resolveEffectiveAgentProfiles,
|
|
3325
|
+
updateAgentProfile
|
|
3326
|
+
} from "@nextclaw/core";
|
|
3327
|
+
var AgentCommands = class {
|
|
3328
|
+
constructor(deps) {
|
|
3329
|
+
this.deps = deps;
|
|
3330
|
+
}
|
|
3331
|
+
agentsList = (opts = {}) => {
|
|
3332
|
+
const config2 = loadConfig8();
|
|
3333
|
+
const agents = resolveEffectiveAgentProfiles(config2).map((agent) => this.toAgentListEntry(agent));
|
|
3334
|
+
if (opts.json) {
|
|
3335
|
+
console.log(JSON.stringify(agents, null, 2));
|
|
3336
|
+
return;
|
|
3337
|
+
}
|
|
3338
|
+
for (const agent of agents) {
|
|
3339
|
+
const head = agent.builtIn ? `${agent.id} (built-in)` : agent.id;
|
|
3340
|
+
console.log(head);
|
|
3341
|
+
console.log(` name: ${agent.displayName ?? "-"}`);
|
|
3342
|
+
console.log(` description: ${agent.description ?? "-"}`);
|
|
3343
|
+
console.log(` home: ${agent.workspace}`);
|
|
3344
|
+
console.log(` avatar: ${agent.avatar ?? "-"}`);
|
|
3345
|
+
}
|
|
3346
|
+
};
|
|
3347
|
+
agentsNew = async (agentId, opts = {}) => {
|
|
3348
|
+
const created = createAgentProfile(
|
|
3349
|
+
{
|
|
3350
|
+
id: agentId,
|
|
3351
|
+
displayName: opts.name,
|
|
3352
|
+
description: opts.description,
|
|
3353
|
+
avatar: opts.avatar,
|
|
3354
|
+
home: opts.home
|
|
3355
|
+
},
|
|
3356
|
+
{
|
|
3357
|
+
initializeHomeDirectory: this.deps.initializeAgentHomeDirectory
|
|
3358
|
+
}
|
|
3359
|
+
);
|
|
3360
|
+
if (opts.json) {
|
|
3361
|
+
console.log(JSON.stringify({
|
|
3362
|
+
agent: created,
|
|
3363
|
+
restartRequired: true
|
|
3364
|
+
}, null, 2));
|
|
3365
|
+
return;
|
|
3366
|
+
}
|
|
3367
|
+
await this.deps.requestRestart({
|
|
3368
|
+
reason: "agents-updated",
|
|
3369
|
+
manualMessage: `Created agent '${created.id}'. Restart ${this.deps.appName} to apply agent runtime changes.`
|
|
3370
|
+
});
|
|
3371
|
+
console.log(`\u2713 Created agent ${created.id}`);
|
|
3372
|
+
console.log(` name: ${created.displayName ?? "-"}`);
|
|
3373
|
+
console.log(` description: ${created.description ?? "-"}`);
|
|
3374
|
+
console.log(` home: ${created.workspace}`);
|
|
3375
|
+
console.log(` avatar: ${created.avatar ?? "-"}`);
|
|
3376
|
+
};
|
|
3377
|
+
agentsUpdate = async (agentId, opts = {}) => {
|
|
3378
|
+
const updated = updateAgentProfile({
|
|
3379
|
+
id: agentId,
|
|
3380
|
+
displayName: opts.name,
|
|
3381
|
+
description: opts.description,
|
|
3382
|
+
avatar: opts.avatar
|
|
3383
|
+
});
|
|
3384
|
+
if (opts.json) {
|
|
3385
|
+
console.log(JSON.stringify({
|
|
3386
|
+
agent: updated,
|
|
3387
|
+
restartRequired: true
|
|
3388
|
+
}, null, 2));
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
await this.deps.requestRestart({
|
|
3392
|
+
reason: "agents-updated",
|
|
3393
|
+
manualMessage: `Updated agent '${updated.id}'. Restart ${this.deps.appName} to apply agent runtime changes.`
|
|
3394
|
+
});
|
|
3395
|
+
console.log(`\u2713 Updated agent ${updated.id}`);
|
|
3396
|
+
console.log(` name: ${updated.displayName ?? "-"}`);
|
|
3397
|
+
console.log(` description: ${updated.description ?? "-"}`);
|
|
3398
|
+
console.log(` home: ${updated.workspace}`);
|
|
3399
|
+
console.log(` avatar: ${updated.avatar ?? "-"}`);
|
|
3400
|
+
};
|
|
3401
|
+
agentsRemove = async (agentId, opts = {}) => {
|
|
3402
|
+
if (agentId.trim().toLowerCase() === BUILTIN_MAIN_AGENT_ID) {
|
|
3403
|
+
throw new Error(`agent id '${BUILTIN_MAIN_AGENT_ID}' is reserved`);
|
|
3404
|
+
}
|
|
3405
|
+
const removed = removeAgentProfile(agentId);
|
|
3406
|
+
if (!removed) {
|
|
3407
|
+
throw new Error(`agent '${agentId}' not found`);
|
|
3408
|
+
}
|
|
3409
|
+
if (opts.json) {
|
|
3410
|
+
console.log(JSON.stringify({
|
|
3411
|
+
removed: true,
|
|
3412
|
+
agentId,
|
|
3413
|
+
restartRequired: true
|
|
3414
|
+
}, null, 2));
|
|
3415
|
+
return;
|
|
3416
|
+
}
|
|
3417
|
+
await this.deps.requestRestart({
|
|
3418
|
+
reason: "agents-updated",
|
|
3419
|
+
manualMessage: `Removed agent '${agentId}'. Restart ${this.deps.appName} to apply agent runtime changes.`
|
|
3420
|
+
});
|
|
3421
|
+
console.log(`\u2713 Removed agent ${agentId}`);
|
|
3422
|
+
};
|
|
3423
|
+
toAgentListEntry = (agent) => {
|
|
3424
|
+
return {
|
|
3425
|
+
id: agent.id,
|
|
3426
|
+
displayName: agent.displayName ?? null,
|
|
3427
|
+
description: agent.description ?? null,
|
|
3428
|
+
avatar: agent.avatar ?? null,
|
|
3429
|
+
workspace: agent.workspace,
|
|
3430
|
+
builtIn: agent.builtIn === true
|
|
3431
|
+
};
|
|
3432
|
+
};
|
|
3433
|
+
};
|
|
3434
|
+
|
|
3242
3435
|
// src/cli/commands/platform-auth.ts
|
|
3243
|
-
import { getConfigPath as getConfigPath3, loadConfig as
|
|
3436
|
+
import { getConfigPath as getConfigPath3, loadConfig as loadConfig9, saveConfig as saveConfig6 } from "@nextclaw/core";
|
|
3244
3437
|
import { createInterface as createInterface2 } from "readline";
|
|
3245
3438
|
|
|
3246
|
-
// src/cli/commands/platform-api-base.ts
|
|
3439
|
+
// src/cli/commands/remote-support/platform-api-base.ts
|
|
3247
3440
|
var DEFAULT_PLATFORM_API_BASE = "https://ai-gateway-api.nextclaw.io/v1";
|
|
3248
3441
|
var INVALID_PLATFORM_HINT = `Use ${DEFAULT_PLATFORM_API_BASE} or the platform root URL without a trailing path.`;
|
|
3249
3442
|
function trimTrailingSlash(value) {
|
|
@@ -3294,7 +3487,7 @@ function buildPlatformApiBaseErrorMessage(inputApiBase, rawMessage) {
|
|
|
3294
3487
|
// src/cli/commands/platform-auth.ts
|
|
3295
3488
|
function resolveProviderConfig(opts) {
|
|
3296
3489
|
const configPath = getConfigPath3();
|
|
3297
|
-
const config2 =
|
|
3490
|
+
const config2 = loadConfig9(configPath);
|
|
3298
3491
|
const providers = config2.providers;
|
|
3299
3492
|
const nextclawProvider = providers.nextclaw ?? {
|
|
3300
3493
|
displayName: "",
|
|
@@ -3542,14 +3735,14 @@ var PlatformAuthCommands = class {
|
|
|
3542
3735
|
};
|
|
3543
3736
|
|
|
3544
3737
|
// src/cli/commands/remote.ts
|
|
3545
|
-
import { getConfigPath as getConfigPath5, loadConfig as
|
|
3738
|
+
import { getConfigPath as getConfigPath5, loadConfig as loadConfig11, saveConfig as saveConfig7 } from "@nextclaw/core";
|
|
3546
3739
|
import {
|
|
3547
3740
|
readPlatformSessionTokenState
|
|
3548
3741
|
} from "@nextclaw/remote";
|
|
3549
3742
|
import { hostname } from "os";
|
|
3550
3743
|
|
|
3551
|
-
// src/cli/commands/remote-runtime-support.ts
|
|
3552
|
-
import { getConfigPath as getConfigPath4, getDataDir as getDataDir4, loadConfig as
|
|
3744
|
+
// src/cli/commands/remote-support/remote-runtime-support.ts
|
|
3745
|
+
import { getConfigPath as getConfigPath4, getDataDir as getDataDir4, loadConfig as loadConfig10 } from "@nextclaw/core";
|
|
3553
3746
|
import {
|
|
3554
3747
|
RemoteConnector,
|
|
3555
3748
|
RemotePlatformClient,
|
|
@@ -3564,7 +3757,7 @@ function hasRunningNextclawManagedService() {
|
|
|
3564
3757
|
}
|
|
3565
3758
|
function createNextclawRemotePlatformClient() {
|
|
3566
3759
|
return new RemotePlatformClient({
|
|
3567
|
-
loadConfig: () =>
|
|
3760
|
+
loadConfig: () => loadConfig10(getConfigPath4()),
|
|
3568
3761
|
getDataDir: getDataDir4,
|
|
3569
3762
|
getPackageVersion,
|
|
3570
3763
|
resolvePlatformBase: (rawApiBase) => resolvePlatformApiBase({
|
|
@@ -3695,7 +3888,7 @@ var RemoteCommands = class {
|
|
|
3695
3888
|
this.deps = deps;
|
|
3696
3889
|
}
|
|
3697
3890
|
updateConfig(params = {}) {
|
|
3698
|
-
const config2 =
|
|
3891
|
+
const config2 = loadConfig11(getConfigPath5());
|
|
3699
3892
|
const nextEnabled = typeof params.enabled === "boolean" ? params.enabled : config2.remote.enabled;
|
|
3700
3893
|
const nextPlatformApiBase = typeof params.apiBase === "string" ? params.apiBase.trim() : config2.remote.platformApiBase;
|
|
3701
3894
|
const nextDeviceName = typeof params.name === "string" ? params.name.trim() : config2.remote.deviceName;
|
|
@@ -3732,7 +3925,7 @@ var RemoteCommands = class {
|
|
|
3732
3925
|
});
|
|
3733
3926
|
}
|
|
3734
3927
|
getStatusView() {
|
|
3735
|
-
const config2 =
|
|
3928
|
+
const config2 = loadConfig11(getConfigPath5());
|
|
3736
3929
|
const snapshot = resolveNextclawRemoteStatusSnapshot(config2);
|
|
3737
3930
|
const resolvedLocalOrigin = snapshot.runtime?.localOrigin ?? this.deps.currentLocalOrigin ?? resolveConfiguredLocalOrigin(config2);
|
|
3738
3931
|
return {
|
|
@@ -3768,7 +3961,7 @@ var RemoteCommands = class {
|
|
|
3768
3961
|
}
|
|
3769
3962
|
}
|
|
3770
3963
|
async getDoctorView() {
|
|
3771
|
-
const config2 =
|
|
3964
|
+
const config2 = loadConfig11(getConfigPath5());
|
|
3772
3965
|
const snapshot = resolveNextclawRemoteStatusSnapshot(config2);
|
|
3773
3966
|
const localOrigin = snapshot.runtime?.localOrigin ?? this.deps.currentLocalOrigin ?? resolveConfiguredLocalOrigin(config2);
|
|
3774
3967
|
const localUi = await probeLocalUi(localOrigin);
|
|
@@ -3824,13 +4017,13 @@ import {
|
|
|
3824
4017
|
APP_NAME as APP_NAME2,
|
|
3825
4018
|
getConfigPath as getConfigPath6,
|
|
3826
4019
|
getDataDir as getDataDir5,
|
|
3827
|
-
getWorkspacePath as
|
|
4020
|
+
getWorkspacePath as getWorkspacePath6,
|
|
3828
4021
|
hasSecretRef,
|
|
3829
|
-
loadConfig as
|
|
4022
|
+
loadConfig as loadConfig12
|
|
3830
4023
|
} from "@nextclaw/core";
|
|
3831
4024
|
import { listBuiltinProviders } from "@nextclaw/runtime";
|
|
3832
4025
|
|
|
3833
|
-
// src/cli/commands/diagnostics-render.ts
|
|
4026
|
+
// src/cli/commands/diagnostics-support/diagnostics-render.ts
|
|
3834
4027
|
import { APP_NAME } from "@nextclaw/core";
|
|
3835
4028
|
function printStatusReport(params) {
|
|
3836
4029
|
const { logo, report, verbose } = params;
|
|
@@ -4012,8 +4205,8 @@ var DiagnosticsCommands = class {
|
|
|
4012
4205
|
}
|
|
4013
4206
|
async collectRuntimeStatus(params) {
|
|
4014
4207
|
const configPath = getConfigPath6();
|
|
4015
|
-
const config2 =
|
|
4016
|
-
const workspacePath =
|
|
4208
|
+
const config2 = loadConfig12();
|
|
4209
|
+
const workspacePath = getWorkspacePath6(config2.agents.defaults.workspace);
|
|
4017
4210
|
const serviceStatePath = resolve8(getDataDir5(), "run", "service.json");
|
|
4018
4211
|
const fixActions = [];
|
|
4019
4212
|
let serviceState = readServiceState();
|
|
@@ -4183,17 +4376,17 @@ var DiagnosticsCommands = class {
|
|
|
4183
4376
|
}
|
|
4184
4377
|
}
|
|
4185
4378
|
async checkPortAvailability(params) {
|
|
4186
|
-
return await new Promise((
|
|
4379
|
+
return await new Promise((resolve17) => {
|
|
4187
4380
|
const server = createNetServer();
|
|
4188
4381
|
server.once("error", (error) => {
|
|
4189
|
-
|
|
4382
|
+
resolve17({
|
|
4190
4383
|
available: false,
|
|
4191
4384
|
detail: `bind failed on ${params.host}:${params.port} (${String(error)})`
|
|
4192
4385
|
});
|
|
4193
4386
|
});
|
|
4194
4387
|
server.listen(params.port, params.host, () => {
|
|
4195
4388
|
server.close(() => {
|
|
4196
|
-
|
|
4389
|
+
resolve17({
|
|
4197
4390
|
available: true,
|
|
4198
4391
|
detail: `bind ok on ${params.host}:${params.port}`
|
|
4199
4392
|
});
|
|
@@ -4210,9 +4403,9 @@ import {
|
|
|
4210
4403
|
setPluginRuntimeBridge as setPluginRuntimeBridge2,
|
|
4211
4404
|
stopPluginChannelGateways as stopPluginChannelGateways2
|
|
4212
4405
|
} from "@nextclaw/openclaw-compat";
|
|
4213
|
-
import { appendFileSync
|
|
4214
|
-
import {
|
|
4215
|
-
import { spawn as
|
|
4406
|
+
import { appendFileSync } from "fs";
|
|
4407
|
+
import { join as join7, resolve as resolve14 } from "path";
|
|
4408
|
+
import { spawn as spawn4 } from "child_process";
|
|
4216
4409
|
import { request as httpRequest } from "http";
|
|
4217
4410
|
import { request as httpsRequest } from "https";
|
|
4218
4411
|
import { createServer as createNetServer2 } from "net";
|
|
@@ -4237,12 +4430,12 @@ var MissingProvider = class extends LLMProvider {
|
|
|
4237
4430
|
}
|
|
4238
4431
|
};
|
|
4239
4432
|
|
|
4240
|
-
// src/cli/commands/service-marketplace-installer.ts
|
|
4241
|
-
import { getWorkspacePath as
|
|
4433
|
+
// src/cli/commands/service-support/marketplace/service-marketplace-installer.ts
|
|
4434
|
+
import { getWorkspacePath as getWorkspacePath7, loadConfig as loadConfig14 } from "@nextclaw/core";
|
|
4242
4435
|
import { existsSync as existsSync8, rmSync as rmSync4 } from "fs";
|
|
4243
4436
|
import { join as join4 } from "path";
|
|
4244
4437
|
|
|
4245
|
-
// src/cli/commands/service-marketplace-helpers.ts
|
|
4438
|
+
// src/cli/commands/service-support/marketplace/service-marketplace-helpers.ts
|
|
4246
4439
|
var containsAbsoluteFsPath = (line) => {
|
|
4247
4440
|
const normalized = line.trim();
|
|
4248
4441
|
if (!normalized) {
|
|
@@ -4287,8 +4480,8 @@ var buildMarketplaceSkillInstallArgs = (params) => {
|
|
|
4287
4480
|
return args;
|
|
4288
4481
|
};
|
|
4289
4482
|
|
|
4290
|
-
// src/cli/commands/service-mcp-marketplace-ops.ts
|
|
4291
|
-
import { loadConfig as
|
|
4483
|
+
// src/cli/commands/service-support/marketplace/service-mcp-marketplace-ops.ts
|
|
4484
|
+
import { loadConfig as loadConfig13, saveConfig as saveConfig8 } from "@nextclaw/core";
|
|
4292
4485
|
import { McpDoctorFacade as McpDoctorFacade2, McpMutationService as McpMutationService2 } from "@nextclaw/mcp";
|
|
4293
4486
|
var ServiceMcpMarketplaceOps = class {
|
|
4294
4487
|
constructor(options) {
|
|
@@ -4356,18 +4549,18 @@ var ServiceMcpMarketplaceOps = class {
|
|
|
4356
4549
|
}
|
|
4357
4550
|
createMutationService() {
|
|
4358
4551
|
return new McpMutationService2({
|
|
4359
|
-
getConfig: () =>
|
|
4552
|
+
getConfig: () => loadConfig13(),
|
|
4360
4553
|
saveConfig: (config2) => saveConfig8(config2)
|
|
4361
4554
|
});
|
|
4362
4555
|
}
|
|
4363
4556
|
createDoctorFacade() {
|
|
4364
4557
|
return new McpDoctorFacade2({
|
|
4365
|
-
getConfig: () =>
|
|
4558
|
+
getConfig: () => loadConfig13()
|
|
4366
4559
|
});
|
|
4367
4560
|
}
|
|
4368
4561
|
};
|
|
4369
4562
|
|
|
4370
|
-
// src/cli/commands/service-marketplace-installer.ts
|
|
4563
|
+
// src/cli/commands/service-support/marketplace/service-marketplace-installer.ts
|
|
4371
4564
|
var ServiceMarketplaceInstaller = class {
|
|
4372
4565
|
constructor(deps) {
|
|
4373
4566
|
this.deps = deps;
|
|
@@ -4403,7 +4596,7 @@ var ServiceMarketplaceInstaller = class {
|
|
|
4403
4596
|
if (params.kind && params.kind !== "marketplace") {
|
|
4404
4597
|
throw new Error(`Unsupported marketplace skill kind: ${params.kind}`);
|
|
4405
4598
|
}
|
|
4406
|
-
const workspace =
|
|
4599
|
+
const workspace = getWorkspacePath7(loadConfig14().agents.defaults.workspace);
|
|
4407
4600
|
const args = buildMarketplaceSkillInstallArgs({
|
|
4408
4601
|
slug: params.slug,
|
|
4409
4602
|
workspace,
|
|
@@ -4442,7 +4635,7 @@ var ServiceMarketplaceInstaller = class {
|
|
|
4442
4635
|
return { message: result.message };
|
|
4443
4636
|
}
|
|
4444
4637
|
async uninstallSkill(slug) {
|
|
4445
|
-
const workspace =
|
|
4638
|
+
const workspace = getWorkspacePath7(loadConfig14().agents.defaults.workspace);
|
|
4446
4639
|
const targetDir = join4(workspace, "skills", slug);
|
|
4447
4640
|
if (!existsSync8(targetDir)) {
|
|
4448
4641
|
throw new Error(`Skill not installed in workspace: ${slug}`);
|
|
@@ -4471,70 +4664,12 @@ var ServiceMarketplaceInstaller = class {
|
|
|
4471
4664
|
}
|
|
4472
4665
|
};
|
|
4473
4666
|
|
|
4474
|
-
// src/cli/commands/service-startup
|
|
4475
|
-
import
|
|
4476
|
-
import { resolve as
|
|
4477
|
-
|
|
4478
|
-
info: (message) => console.log(`[plugins] ${message}`),
|
|
4479
|
-
warn: (message) => console.warn(`[plugins] ${message}`),
|
|
4480
|
-
error: (message) => console.error(`[plugins] ${message}`),
|
|
4481
|
-
debug: (message) => console.debug(`[plugins] ${message}`)
|
|
4482
|
-
};
|
|
4483
|
-
function logPluginGatewayDiagnostics(diagnostics) {
|
|
4484
|
-
for (const diag of diagnostics) {
|
|
4485
|
-
const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
|
|
4486
|
-
const text = `${prefix}${diag.message}`;
|
|
4487
|
-
if (diag.level === "error") {
|
|
4488
|
-
console.error(`[plugins] ${text}`);
|
|
4489
|
-
} else {
|
|
4490
|
-
console.warn(`[plugins] ${text}`);
|
|
4491
|
-
}
|
|
4492
|
-
}
|
|
4493
|
-
}
|
|
4494
|
-
async function startGatewaySupportServices(params) {
|
|
4495
|
-
if (params.cronJobs > 0) {
|
|
4496
|
-
console.log(`\u2713 Cron: ${params.cronJobs} scheduled jobs`);
|
|
4497
|
-
}
|
|
4498
|
-
console.log("\u2713 Heartbeat: every 30m");
|
|
4499
|
-
params.remoteModule?.start();
|
|
4500
|
-
params.watchConfigFile();
|
|
4501
|
-
await params.startCron();
|
|
4502
|
-
await params.startHeartbeat();
|
|
4503
|
-
}
|
|
4504
|
-
function watchCronStoreFile(params) {
|
|
4505
|
-
const cronStorePath = resolve9(params.cronStorePath);
|
|
4506
|
-
const watcher = chokidar.watch(cronStorePath, {
|
|
4507
|
-
ignoreInitial: true,
|
|
4508
|
-
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
4509
|
-
});
|
|
4510
|
-
watcher.on("all", (event, changedPath) => {
|
|
4511
|
-
if (resolve9(changedPath) !== cronStorePath) {
|
|
4512
|
-
return;
|
|
4513
|
-
}
|
|
4514
|
-
if (event === "add" || event === "change" || event === "unlink") {
|
|
4515
|
-
try {
|
|
4516
|
-
params.reloadCronStore();
|
|
4517
|
-
} catch (error) {
|
|
4518
|
-
console.error(`Cron store reload failed (${event}): ${String(error)}`);
|
|
4519
|
-
}
|
|
4520
|
-
}
|
|
4521
|
-
});
|
|
4522
|
-
}
|
|
4523
|
-
|
|
4524
|
-
// src/cli/commands/cli-subcommand-launch.ts
|
|
4525
|
-
import { createRequire } from "module";
|
|
4526
|
-
import { extname, resolve as resolve10 } from "path";
|
|
4527
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4528
|
-
var require2 = createRequire(import.meta.url);
|
|
4529
|
-
var resolveCliSubcommandEntry = (params) => {
|
|
4530
|
-
const argvEntry = params.argvEntry?.trim();
|
|
4531
|
-
if (argvEntry) {
|
|
4532
|
-
return resolve10(argvEntry);
|
|
4533
|
-
}
|
|
4534
|
-
return fileURLToPath3(new URL("../index.js", params.importMetaUrl));
|
|
4535
|
-
};
|
|
4667
|
+
// src/cli/commands/service-support/runtime/service-managed-startup.ts
|
|
4668
|
+
import { closeSync as closeSync2, mkdirSync as mkdirSync5, openSync as openSync2 } from "fs";
|
|
4669
|
+
import { resolve as resolve10 } from "path";
|
|
4670
|
+
import { spawn as spawn2 } from "child_process";
|
|
4536
4671
|
|
|
4537
|
-
// src/cli/commands/service-remote-runtime.ts
|
|
4672
|
+
// src/cli/commands/service-support/runtime/service-remote-runtime.ts
|
|
4538
4673
|
import { RemoteServiceModule } from "@nextclaw/remote";
|
|
4539
4674
|
import {
|
|
4540
4675
|
closeSync,
|
|
@@ -4546,10 +4681,10 @@ import {
|
|
|
4546
4681
|
unlinkSync,
|
|
4547
4682
|
writeFileSync as writeFileSync4
|
|
4548
4683
|
} from "fs";
|
|
4549
|
-
import { dirname as dirname2, resolve as
|
|
4684
|
+
import { dirname as dirname2, resolve as resolve9 } from "path";
|
|
4550
4685
|
import { getDataDir as getDataDir6 } from "@nextclaw/core";
|
|
4551
4686
|
function resolveRemoteOwnershipLockPath() {
|
|
4552
|
-
return
|
|
4687
|
+
return resolve9(getDataDir6(), "run", "remote-owner.lock.json");
|
|
4553
4688
|
}
|
|
4554
4689
|
function readRemoteOwnershipRecord(lockPath) {
|
|
4555
4690
|
try {
|
|
@@ -4736,20 +4871,230 @@ function writeReadyManagedServiceState(params) {
|
|
|
4736
4871
|
return state;
|
|
4737
4872
|
}
|
|
4738
4873
|
|
|
4739
|
-
// src/cli/commands/
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4874
|
+
// src/cli/commands/service-support/runtime/service-managed-startup.ts
|
|
4875
|
+
function toObjectRecord(value) {
|
|
4876
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4877
|
+
return null;
|
|
4878
|
+
}
|
|
4879
|
+
return value;
|
|
4880
|
+
}
|
|
4881
|
+
function hasSessionRoutingMetadata(params) {
|
|
4882
|
+
const context = toObjectRecord(params.metadata.last_delivery_context) ?? {};
|
|
4883
|
+
const hasPrimaryRoute = Boolean(params.normalizeOptionalString(context.channel)) && Boolean(params.normalizeOptionalString(context.chatId));
|
|
4884
|
+
const hasFallbackRoute = Boolean(params.normalizeOptionalString(params.metadata.last_channel)) && Boolean(params.normalizeOptionalString(params.metadata.last_to));
|
|
4885
|
+
return hasPrimaryRoute || hasFallbackRoute;
|
|
4886
|
+
}
|
|
4887
|
+
function resolveManagedServiceUiBinding(state) {
|
|
4888
|
+
try {
|
|
4889
|
+
const parsed = new URL(state.uiUrl);
|
|
4890
|
+
const parsedPort = Number(parsed.port || 80);
|
|
4891
|
+
return {
|
|
4892
|
+
host: state.uiHost ?? parsed.hostname,
|
|
4893
|
+
port: Number.isFinite(parsedPort) ? parsedPort : state.uiPort ?? 55667
|
|
4894
|
+
};
|
|
4895
|
+
} catch {
|
|
4896
|
+
return {
|
|
4897
|
+
host: state.uiHost ?? "127.0.0.1",
|
|
4898
|
+
port: state.uiPort ?? 55667
|
|
4899
|
+
};
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
function resolveSessionRouteCandidate(params) {
|
|
4903
|
+
const sessionRecord = toObjectRecord(params.session);
|
|
4904
|
+
const key = params.normalizeOptionalString(sessionRecord?.key);
|
|
4905
|
+
if (!key || key.startsWith("cli:")) {
|
|
4906
|
+
return null;
|
|
4907
|
+
}
|
|
4908
|
+
const metadata = toObjectRecord(sessionRecord?.metadata) ?? {};
|
|
4909
|
+
if (!hasSessionRoutingMetadata({ metadata, normalizeOptionalString: params.normalizeOptionalString })) {
|
|
4910
|
+
return null;
|
|
4911
|
+
}
|
|
4912
|
+
const updatedAtRaw = params.normalizeOptionalString(sessionRecord?.updated_at);
|
|
4913
|
+
const updatedAt = updatedAtRaw ? Date.parse(updatedAtRaw) : Number.NaN;
|
|
4914
|
+
return {
|
|
4915
|
+
key,
|
|
4916
|
+
updatedAt: Number.isFinite(updatedAt) ? updatedAt : 0
|
|
4917
|
+
};
|
|
4918
|
+
}
|
|
4919
|
+
function spawnManagedService(params) {
|
|
4920
|
+
const logPath = params.resolveServiceLogPath();
|
|
4921
|
+
const logDir = resolve10(logPath, "..");
|
|
4922
|
+
mkdirSync5(logDir, { recursive: true });
|
|
4923
|
+
const logFd = openSync2(logPath, "a");
|
|
4924
|
+
const readinessTimeoutMs = params.resolveStartupTimeoutMs(params.startupTimeoutMs);
|
|
4925
|
+
const quickPhaseTimeoutMs = Math.min(8e3, readinessTimeoutMs);
|
|
4926
|
+
const extendedPhaseTimeoutMs = Math.max(0, readinessTimeoutMs - quickPhaseTimeoutMs);
|
|
4927
|
+
params.appendStartupStage(
|
|
4928
|
+
logPath,
|
|
4929
|
+
`start requested: ui=${params.uiConfig.host}:${params.uiConfig.port}, readinessTimeoutMs=${readinessTimeoutMs}`
|
|
4930
|
+
);
|
|
4931
|
+
console.log(`Starting ${params.appName} background service (readiness timeout ${Math.ceil(readinessTimeoutMs / 1e3)}s)...`);
|
|
4932
|
+
const serveArgs = ["serve", "--ui-port", String(params.uiConfig.port)];
|
|
4933
|
+
params.appendStartupStage(logPath, `spawning background process: ${process.execPath} ${[...process.execArgv, ...serveArgs].join(" ")}`);
|
|
4934
|
+
const child = spawn2(process.execPath, [...process.execArgv, ...serveArgs], {
|
|
4935
|
+
env: process.env,
|
|
4936
|
+
stdio: ["ignore", logFd, logFd],
|
|
4937
|
+
detached: true
|
|
4938
|
+
});
|
|
4939
|
+
params.appendStartupStage(logPath, `spawned background process pid=${child.pid ?? "unknown"}`);
|
|
4940
|
+
closeSync2(logFd);
|
|
4941
|
+
if (!child.pid) {
|
|
4942
|
+
params.appendStartupStage(logPath, "spawn failed: child pid missing");
|
|
4943
|
+
console.error("Error: Failed to start background service.");
|
|
4944
|
+
params.printStartupFailureDiagnostics({
|
|
4945
|
+
uiUrl: params.uiUrl,
|
|
4946
|
+
apiUrl: params.apiUrl,
|
|
4947
|
+
healthUrl: params.healthUrl,
|
|
4948
|
+
logPath,
|
|
4949
|
+
lastProbeError: null
|
|
4950
|
+
});
|
|
4951
|
+
return null;
|
|
4952
|
+
}
|
|
4953
|
+
const snapshot = {
|
|
4954
|
+
pid: child.pid,
|
|
4955
|
+
uiUrl: params.uiUrl,
|
|
4956
|
+
apiUrl: params.apiUrl,
|
|
4957
|
+
uiHost: params.uiConfig.host,
|
|
4958
|
+
uiPort: params.uiConfig.port,
|
|
4959
|
+
logPath
|
|
4960
|
+
};
|
|
4961
|
+
writeInitialManagedServiceState({
|
|
4962
|
+
config: params.config,
|
|
4963
|
+
readinessTimeoutMs,
|
|
4964
|
+
snapshot
|
|
4965
|
+
});
|
|
4966
|
+
return {
|
|
4967
|
+
child,
|
|
4968
|
+
logPath,
|
|
4969
|
+
readinessTimeoutMs,
|
|
4970
|
+
quickPhaseTimeoutMs,
|
|
4971
|
+
extendedPhaseTimeoutMs,
|
|
4972
|
+
snapshot
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
async function waitForManagedServiceReadiness(params) {
|
|
4976
|
+
params.appendStartupStage(params.logPath, `health probe started: ${params.healthUrl} (phase=quick, timeoutMs=${params.quickPhaseTimeoutMs})`);
|
|
4977
|
+
let readiness = await params.waitForBackgroundServiceReady({
|
|
4978
|
+
pid: params.childPid,
|
|
4979
|
+
healthUrl: params.healthUrl,
|
|
4980
|
+
timeoutMs: params.quickPhaseTimeoutMs
|
|
4981
|
+
});
|
|
4982
|
+
if (!readiness.ready && params.isProcessRunning(params.childPid) && params.extendedPhaseTimeoutMs > 0) {
|
|
4983
|
+
console.warn(
|
|
4984
|
+
`Warning: Background service is still running but not ready after ${Math.ceil(params.quickPhaseTimeoutMs / 1e3)}s; waiting up to ${Math.ceil(params.extendedPhaseTimeoutMs / 1e3)}s more.`
|
|
4985
|
+
);
|
|
4986
|
+
params.appendStartupStage(
|
|
4987
|
+
params.logPath,
|
|
4988
|
+
`health probe entering extended phase (timeoutMs=${params.extendedPhaseTimeoutMs}, lastError=${readiness.lastProbeError ?? "none"})`
|
|
4989
|
+
);
|
|
4990
|
+
readiness = await params.waitForBackgroundServiceReady({
|
|
4991
|
+
pid: params.childPid,
|
|
4992
|
+
healthUrl: params.healthUrl,
|
|
4993
|
+
timeoutMs: params.extendedPhaseTimeoutMs
|
|
4994
|
+
});
|
|
4995
|
+
}
|
|
4996
|
+
if (!readiness.ready && params.isProcessRunning(params.childPid)) {
|
|
4997
|
+
params.appendStartupStage(
|
|
4998
|
+
params.logPath,
|
|
4999
|
+
`startup degraded: process alive but health probe timed out after ${params.readinessTimeoutMs}ms (lastError=${readiness.lastProbeError ?? "none"})`
|
|
5000
|
+
);
|
|
5001
|
+
}
|
|
5002
|
+
return readiness;
|
|
5003
|
+
}
|
|
5004
|
+
async function reportManagedServiceStart(params) {
|
|
5005
|
+
if (!params.readiness.ready) {
|
|
5006
|
+
const hint = params.readiness.lastProbeError ? ` Last probe error: ${params.readiness.lastProbeError}` : "";
|
|
5007
|
+
console.warn(
|
|
5008
|
+
`Warning: ${params.appName} is running (PID ${params.state.pid}) but not healthy yet after ${Math.ceil(params.readinessTimeoutMs / 1e3)}s. Marked as degraded.${hint}`
|
|
5009
|
+
);
|
|
5010
|
+
console.warn(`Tip: Run "${params.appName} status --json" and check logs: ${params.state.logPath}`);
|
|
5011
|
+
} else {
|
|
5012
|
+
console.log(`\u2713 ${params.appName} started in background (PID ${params.state.pid})`);
|
|
5013
|
+
}
|
|
5014
|
+
console.log(`UI: ${params.uiUrl}`);
|
|
5015
|
+
console.log(`API: ${params.apiUrl}`);
|
|
5016
|
+
await params.printPublicUiUrls(params.uiConfig.host, params.uiConfig.port);
|
|
5017
|
+
console.log(`Logs: ${params.state.logPath}`);
|
|
5018
|
+
params.printServiceControlHints();
|
|
5019
|
+
}
|
|
5020
|
+
|
|
5021
|
+
// src/cli/commands/service-support/gateway/service-startup-support.ts
|
|
5022
|
+
import chokidar from "chokidar";
|
|
5023
|
+
import { resolve as resolve11 } from "path";
|
|
5024
|
+
var pluginGatewayLogger = {
|
|
5025
|
+
info: (message) => console.log(`[plugins] ${message}`),
|
|
5026
|
+
warn: (message) => console.warn(`[plugins] ${message}`),
|
|
5027
|
+
error: (message) => console.error(`[plugins] ${message}`),
|
|
5028
|
+
debug: (message) => console.debug(`[plugins] ${message}`)
|
|
5029
|
+
};
|
|
5030
|
+
function logPluginGatewayDiagnostics(diagnostics) {
|
|
5031
|
+
for (const diag of diagnostics) {
|
|
5032
|
+
const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
|
|
5033
|
+
const text = `${prefix}${diag.message}`;
|
|
5034
|
+
if (diag.level === "error") {
|
|
5035
|
+
console.error(`[plugins] ${text}`);
|
|
5036
|
+
} else {
|
|
5037
|
+
console.warn(`[plugins] ${text}`);
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
async function startGatewaySupportServices(params) {
|
|
5042
|
+
if (params.cronJobs > 0) {
|
|
5043
|
+
console.log(`\u2713 Cron: ${params.cronJobs} scheduled jobs`);
|
|
5044
|
+
}
|
|
5045
|
+
console.log("\u2713 Heartbeat: every 30m");
|
|
5046
|
+
params.remoteModule?.start();
|
|
5047
|
+
params.watchConfigFile();
|
|
5048
|
+
await params.startCron();
|
|
5049
|
+
await params.startHeartbeat();
|
|
5050
|
+
}
|
|
5051
|
+
function watchCronStoreFile(params) {
|
|
5052
|
+
const cronStorePath = resolve11(params.cronStorePath);
|
|
5053
|
+
const watcher = chokidar.watch(cronStorePath, {
|
|
5054
|
+
ignoreInitial: true,
|
|
5055
|
+
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
5056
|
+
});
|
|
5057
|
+
watcher.on("all", (event, changedPath) => {
|
|
5058
|
+
if (resolve11(changedPath) !== cronStorePath) {
|
|
5059
|
+
return;
|
|
5060
|
+
}
|
|
5061
|
+
if (event === "add" || event === "change" || event === "unlink") {
|
|
5062
|
+
try {
|
|
5063
|
+
params.reloadCronStore();
|
|
5064
|
+
} catch (error) {
|
|
5065
|
+
console.error(`Cron store reload failed (${event}): ${String(error)}`);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
});
|
|
5069
|
+
}
|
|
5070
|
+
|
|
5071
|
+
// src/cli/commands/service-support/marketplace/cli-subcommand-launch.ts
|
|
5072
|
+
import { createRequire } from "module";
|
|
5073
|
+
import { extname, resolve as resolve12 } from "path";
|
|
5074
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5075
|
+
var require2 = createRequire(import.meta.url);
|
|
5076
|
+
var resolveCliSubcommandEntry = (params) => {
|
|
5077
|
+
const argvEntry = params.argvEntry?.trim();
|
|
5078
|
+
if (argvEntry) {
|
|
5079
|
+
return resolve12(argvEntry);
|
|
5080
|
+
}
|
|
5081
|
+
return fileURLToPath3(new URL("../index.js", params.importMetaUrl));
|
|
5082
|
+
};
|
|
5083
|
+
|
|
5084
|
+
// src/cli/commands/remote-support/remote-access-host.ts
|
|
5085
|
+
import { getConfigPath as getConfigPath8, loadConfig as loadConfig16 } from "@nextclaw/core";
|
|
5086
|
+
import { readPlatformSessionTokenState as readPlatformSessionTokenState2 } from "@nextclaw/remote";
|
|
5087
|
+
|
|
5088
|
+
// src/cli/commands/remote-support/remote-access-service-control.ts
|
|
5089
|
+
import { getConfigPath as getConfigPath7, loadConfig as loadConfig15 } from "@nextclaw/core";
|
|
5090
|
+
import { spawn as spawn3 } from "child_process";
|
|
5091
|
+
var FORCED_PUBLIC_UI_HOST = "0.0.0.0";
|
|
5092
|
+
function resolveRemoteServiceView(currentUi) {
|
|
5093
|
+
if (currentUi) {
|
|
5094
|
+
return {
|
|
5095
|
+
running: true,
|
|
5096
|
+
currentProcess: true,
|
|
5097
|
+
pid: process.pid,
|
|
4753
5098
|
uiUrl: resolveUiApiBase(currentUi.host, currentUi.port),
|
|
4754
5099
|
uiPort: currentUi.port
|
|
4755
5100
|
};
|
|
@@ -4830,7 +5175,7 @@ async function controlManagedService(action, deps) {
|
|
|
4830
5175
|
return { accepted: true, action, message: "Managed service restarted." };
|
|
4831
5176
|
}
|
|
4832
5177
|
function resolveManagedUiOverrides() {
|
|
4833
|
-
const config2 =
|
|
5178
|
+
const config2 = loadConfig15(getConfigPath7());
|
|
4834
5179
|
const resolved = resolveUiConfig(config2, {
|
|
4835
5180
|
enabled: true,
|
|
4836
5181
|
host: FORCED_PUBLIC_UI_HOST,
|
|
@@ -4891,7 +5236,7 @@ function launchManagedSelfControl(params = {}) {
|
|
|
4891
5236
|
" process.exit(0);",
|
|
4892
5237
|
"}, 250);"
|
|
4893
5238
|
].join("");
|
|
4894
|
-
const helper =
|
|
5239
|
+
const helper = spawn3(process.execPath, ["-e", script], {
|
|
4895
5240
|
detached: true,
|
|
4896
5241
|
stdio: "ignore",
|
|
4897
5242
|
env: process.env,
|
|
@@ -4900,7 +5245,7 @@ function launchManagedSelfControl(params = {}) {
|
|
|
4900
5245
|
helper.unref();
|
|
4901
5246
|
}
|
|
4902
5247
|
|
|
4903
|
-
// src/cli/commands/remote-access-host.ts
|
|
5248
|
+
// src/cli/commands/remote-support/remote-access-host.ts
|
|
4904
5249
|
function normalizeOptionalString4(value) {
|
|
4905
5250
|
if (typeof value !== "string") {
|
|
4906
5251
|
return null;
|
|
@@ -4930,7 +5275,7 @@ var RemoteAccessHost = class {
|
|
|
4930
5275
|
this.deps = deps;
|
|
4931
5276
|
}
|
|
4932
5277
|
getStatus() {
|
|
4933
|
-
const config2 =
|
|
5278
|
+
const config2 = loadConfig16(getConfigPath8());
|
|
4934
5279
|
const status = this.deps.remoteCommands.getStatusView();
|
|
4935
5280
|
const account = this.readAccountView({
|
|
4936
5281
|
token: normalizeOptionalString4(config2.providers.nextclaw?.apiKey),
|
|
@@ -4967,7 +5312,7 @@ var RemoteAccessHost = class {
|
|
|
4967
5312
|
};
|
|
4968
5313
|
}
|
|
4969
5314
|
async pollBrowserAuth(input) {
|
|
4970
|
-
const config2 =
|
|
5315
|
+
const config2 = loadConfig16(getConfigPath8());
|
|
4971
5316
|
const result = await this.deps.platformAuthCommands.pollBrowserAuth({
|
|
4972
5317
|
apiBase: normalizeOptionalString4(input.apiBase) ?? normalizeOptionalString4(config2.remote.platformApiBase) ?? normalizeOptionalString4(config2.providers.nextclaw?.apiBase) ?? void 0,
|
|
4973
5318
|
sessionId: input.sessionId
|
|
@@ -5029,7 +5374,7 @@ var RemoteAccessHost = class {
|
|
|
5029
5374
|
}
|
|
5030
5375
|
};
|
|
5031
5376
|
|
|
5032
|
-
// src/cli/commands/service-remote-access.ts
|
|
5377
|
+
// src/cli/commands/service-support/runtime/service-remote-access.ts
|
|
5033
5378
|
function requestManagedServiceRestart(requestRestart, options = {}) {
|
|
5034
5379
|
const uiPort = typeof options.uiPort === "number" && Number.isFinite(options.uiPort) ? Math.floor(options.uiPort) : void 0;
|
|
5035
5380
|
const reason = options.reason?.trim() || "remote access service restart";
|
|
@@ -5077,13 +5422,10 @@ import {
|
|
|
5077
5422
|
readAssistantReasoningNormalizationModeFromMetadata,
|
|
5078
5423
|
writeAssistantReasoningNormalizationModeToMetadata
|
|
5079
5424
|
} from "@nextclaw/ncp";
|
|
5080
|
-
import {
|
|
5081
|
-
createAgentClientFromServer,
|
|
5082
|
-
DefaultNcpAgentBackend
|
|
5083
|
-
} from "@nextclaw/ncp-toolkit";
|
|
5425
|
+
import { DefaultNcpAgentBackend } from "@nextclaw/ncp-toolkit";
|
|
5084
5426
|
|
|
5085
|
-
// src/cli/commands/ncp/ncp-asset-tools.ts
|
|
5086
|
-
import { resolve as
|
|
5427
|
+
// src/cli/commands/ncp/runtime/ncp-asset-tools.ts
|
|
5428
|
+
import { resolve as resolve13 } from "path";
|
|
5087
5429
|
import {
|
|
5088
5430
|
buildAssetContentPath
|
|
5089
5431
|
} from "@nextclaw/ncp-agent-runtime";
|
|
@@ -5199,7 +5541,7 @@ var AssetExportTool = class {
|
|
|
5199
5541
|
if (!assetUri || !targetPath) {
|
|
5200
5542
|
throw new Error("asset_export requires assetUri and targetPath.");
|
|
5201
5543
|
}
|
|
5202
|
-
const exportedPath = await this.assetStore.export({ uri: assetUri },
|
|
5544
|
+
const exportedPath = await this.assetStore.export({ uri: assetUri }, resolve13(targetPath));
|
|
5203
5545
|
return {
|
|
5204
5546
|
ok: true,
|
|
5205
5547
|
assetUri,
|
|
@@ -5258,10 +5600,12 @@ function createAssetTools(params) {
|
|
|
5258
5600
|
import {
|
|
5259
5601
|
buildToolCatalogEntries,
|
|
5260
5602
|
ContextBuilder,
|
|
5603
|
+
findEffectiveAgentProfile,
|
|
5261
5604
|
InputBudgetPruner,
|
|
5262
|
-
getWorkspacePath as
|
|
5605
|
+
getWorkspacePath as getWorkspacePath8,
|
|
5263
5606
|
parseThinkingLevel as parseThinkingLevel2,
|
|
5264
5607
|
readSessionProjectRoot,
|
|
5608
|
+
resolveDefaultAgentProfileId,
|
|
5265
5609
|
resolveSessionWorkspacePath,
|
|
5266
5610
|
resolveThinkingLevel
|
|
5267
5611
|
} from "@nextclaw/core";
|
|
@@ -5456,7 +5800,7 @@ function toLegacyMessages(messages, options = {}) {
|
|
|
5456
5800
|
return legacyMessages;
|
|
5457
5801
|
}
|
|
5458
5802
|
|
|
5459
|
-
// src/cli/commands/ncp/nextclaw-ncp-session-preferences.ts
|
|
5803
|
+
// src/cli/commands/ncp/context/nextclaw-ncp-session-preferences.ts
|
|
5460
5804
|
import { parseThinkingLevel } from "@nextclaw/core";
|
|
5461
5805
|
function normalizeOptionalString5(value) {
|
|
5462
5806
|
if (typeof value !== "string") {
|
|
@@ -5534,7 +5878,7 @@ function resolveSessionChannelContext(params) {
|
|
|
5534
5878
|
return { channel, chatId };
|
|
5535
5879
|
}
|
|
5536
5880
|
|
|
5537
|
-
// src/cli/commands/ncp/nextclaw-ncp-current-turn.ts
|
|
5881
|
+
// src/cli/commands/ncp/context/nextclaw-ncp-current-turn.ts
|
|
5538
5882
|
function isTextLikePart2(part) {
|
|
5539
5883
|
return part.type === "text" || part.type === "rich-text";
|
|
5540
5884
|
}
|
|
@@ -5670,7 +6014,6 @@ var SpawnChildSessionTool = class extends Tool {
|
|
|
5670
6014
|
}
|
|
5671
6015
|
sourceSessionId = "";
|
|
5672
6016
|
sourceSessionMetadata = {};
|
|
5673
|
-
agentId;
|
|
5674
6017
|
handoffDepth = 0;
|
|
5675
6018
|
get name() {
|
|
5676
6019
|
return "spawn";
|
|
@@ -5684,7 +6027,11 @@ var SpawnChildSessionTool = class extends Tool {
|
|
|
5684
6027
|
properties: {
|
|
5685
6028
|
task: { type: "string", description: "Task to run inside the child session." },
|
|
5686
6029
|
label: { type: "string", description: "Optional child session title." },
|
|
5687
|
-
model: { type: "string", description: "Optional model override for the child session." }
|
|
6030
|
+
model: { type: "string", description: "Optional model override for the child session." },
|
|
6031
|
+
agentId: {
|
|
6032
|
+
type: "string",
|
|
6033
|
+
description: "Optional target agent id for the child session. Omit to use the default agent."
|
|
6034
|
+
}
|
|
5688
6035
|
},
|
|
5689
6036
|
required: ["task"]
|
|
5690
6037
|
};
|
|
@@ -5692,7 +6039,6 @@ var SpawnChildSessionTool = class extends Tool {
|
|
|
5692
6039
|
setContext = (params) => {
|
|
5693
6040
|
this.sourceSessionId = params.sourceSessionId;
|
|
5694
6041
|
this.sourceSessionMetadata = structuredClone(params.sourceSessionMetadata);
|
|
5695
|
-
this.agentId = params.agentId;
|
|
5696
6042
|
this.handoffDepth = params.handoffDepth ?? 0;
|
|
5697
6043
|
};
|
|
5698
6044
|
execute = async (params, toolCallId) => {
|
|
@@ -5705,7 +6051,7 @@ var SpawnChildSessionTool = class extends Tool {
|
|
|
5705
6051
|
title: readOptionalString2(params, "label"),
|
|
5706
6052
|
model: readOptionalString2(params, "model"),
|
|
5707
6053
|
handoffDepth: this.handoffDepth,
|
|
5708
|
-
agentId:
|
|
6054
|
+
agentId: readOptionalString2(params, "agentId")
|
|
5709
6055
|
});
|
|
5710
6056
|
};
|
|
5711
6057
|
};
|
|
@@ -5809,7 +6155,6 @@ var SessionSpawnTool = class extends Tool2 {
|
|
|
5809
6155
|
}
|
|
5810
6156
|
sourceSessionId = "";
|
|
5811
6157
|
sourceSessionMetadata = {};
|
|
5812
|
-
agentId;
|
|
5813
6158
|
get name() {
|
|
5814
6159
|
return "sessions_spawn";
|
|
5815
6160
|
}
|
|
@@ -5831,6 +6176,10 @@ var SessionSpawnTool = class extends Tool2 {
|
|
|
5831
6176
|
model: {
|
|
5832
6177
|
type: "string",
|
|
5833
6178
|
description: "Optional model override for the new session."
|
|
6179
|
+
},
|
|
6180
|
+
agentId: {
|
|
6181
|
+
type: "string",
|
|
6182
|
+
description: "Optional target agent id for the new session. Omit to use the default agent."
|
|
5834
6183
|
}
|
|
5835
6184
|
},
|
|
5836
6185
|
required: ["task"]
|
|
@@ -5839,7 +6188,6 @@ var SessionSpawnTool = class extends Tool2 {
|
|
|
5839
6188
|
setContext = (params) => {
|
|
5840
6189
|
this.sourceSessionId = params.sourceSessionId;
|
|
5841
6190
|
this.sourceSessionMetadata = structuredClone(params.sourceSessionMetadata);
|
|
5842
|
-
this.agentId = params.agentId;
|
|
5843
6191
|
};
|
|
5844
6192
|
execute = async (params) => {
|
|
5845
6193
|
const task = readRequiredString2(params.task, "task");
|
|
@@ -5847,12 +6195,13 @@ var SessionSpawnTool = class extends Tool2 {
|
|
|
5847
6195
|
task,
|
|
5848
6196
|
title: readOptionalString3(params.title),
|
|
5849
6197
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
5850
|
-
agentId:
|
|
6198
|
+
agentId: readOptionalString3(params.agentId),
|
|
5851
6199
|
model: readOptionalString3(params.model)
|
|
5852
6200
|
});
|
|
5853
6201
|
return {
|
|
5854
6202
|
kind: "nextclaw.session",
|
|
5855
6203
|
sessionId: session.sessionId,
|
|
6204
|
+
...session.agentId ? { agentId: session.agentId } : {},
|
|
5856
6205
|
...session.parentSessionId ? { parentSessionId: session.parentSessionId } : {},
|
|
5857
6206
|
isChildSession: false,
|
|
5858
6207
|
lifecycle: session.lifecycle,
|
|
@@ -5978,7 +6327,6 @@ var NextclawNcpToolRegistry = class {
|
|
|
5978
6327
|
spawnTool.setContext({
|
|
5979
6328
|
sourceSessionId: context.sessionId,
|
|
5980
6329
|
sourceSessionMetadata: context.metadata,
|
|
5981
|
-
agentId: context.agentId,
|
|
5982
6330
|
handoffDepth: context.handoffDepth
|
|
5983
6331
|
});
|
|
5984
6332
|
this.registerTool(spawnTool);
|
|
@@ -5987,8 +6335,7 @@ var NextclawNcpToolRegistry = class {
|
|
|
5987
6335
|
);
|
|
5988
6336
|
sessionsSpawnTool.setContext({
|
|
5989
6337
|
sourceSessionId: context.sessionId,
|
|
5990
|
-
sourceSessionMetadata: context.metadata
|
|
5991
|
-
agentId: context.agentId
|
|
6338
|
+
sourceSessionMetadata: context.metadata
|
|
5992
6339
|
});
|
|
5993
6340
|
this.registerTool(sessionsSpawnTool);
|
|
5994
6341
|
const sessionsRequestTool = new SessionRequestTool(
|
|
@@ -6128,18 +6475,25 @@ function resolveRequestedToolNames(metadata) {
|
|
|
6128
6475
|
)
|
|
6129
6476
|
);
|
|
6130
6477
|
}
|
|
6131
|
-
function
|
|
6132
|
-
|
|
6133
|
-
|
|
6478
|
+
function readRequestedAgentId(metadata) {
|
|
6479
|
+
return normalizeString(metadata.agent_id)?.toLowerCase() ?? normalizeString(metadata.agentId)?.toLowerCase() ?? null;
|
|
6480
|
+
}
|
|
6481
|
+
function resolveAgentProfile(params) {
|
|
6482
|
+
const defaultAgentId = resolveDefaultAgentProfileId(params.config);
|
|
6483
|
+
const candidateAgentId = normalizeString(params.storedAgentId)?.toLowerCase() ?? readRequestedAgentId(params.requestMetadata) ?? defaultAgentId;
|
|
6484
|
+
const profile = findEffectiveAgentProfile(params.config, candidateAgentId) ?? findEffectiveAgentProfile(params.config, defaultAgentId);
|
|
6485
|
+
if (!profile) {
|
|
6486
|
+
throw new Error(`default agent profile not found: ${defaultAgentId}`);
|
|
6487
|
+
}
|
|
6134
6488
|
return {
|
|
6135
|
-
agentId:
|
|
6136
|
-
workspace:
|
|
6137
|
-
model: profile
|
|
6138
|
-
maxIterations: profile
|
|
6139
|
-
contextTokens: profile
|
|
6140
|
-
restrictToWorkspace:
|
|
6141
|
-
searchConfig:
|
|
6142
|
-
execTimeoutSeconds:
|
|
6489
|
+
agentId: profile.id,
|
|
6490
|
+
workspace: getWorkspacePath8(profile.workspace ?? params.config.agents.defaults.workspace),
|
|
6491
|
+
model: profile.model ?? params.config.agents.defaults.model,
|
|
6492
|
+
maxIterations: profile.maxToolIterations ?? params.config.agents.defaults.maxToolIterations,
|
|
6493
|
+
contextTokens: profile.contextTokens ?? params.config.agents.defaults.contextTokens,
|
|
6494
|
+
restrictToWorkspace: params.config.tools.restrictToWorkspace,
|
|
6495
|
+
searchConfig: params.config.search,
|
|
6496
|
+
execTimeoutSeconds: params.config.tools.exec.timeout
|
|
6143
6497
|
};
|
|
6144
6498
|
}
|
|
6145
6499
|
function shouldAppendTimeHint(content) {
|
|
@@ -6224,9 +6578,13 @@ var NextclawNcpContextBuilder = class {
|
|
|
6224
6578
|
inputBudgetPruner = new InputBudgetPruner();
|
|
6225
6579
|
prepare = (input, _options) => {
|
|
6226
6580
|
const config2 = this.options.getConfig();
|
|
6227
|
-
const profile = resolvePrimaryAgentProfile(config2);
|
|
6228
6581
|
const requestMetadata = mergeInputMetadata(input);
|
|
6229
6582
|
const session = this.options.sessionManager.getOrCreate(input.sessionId);
|
|
6583
|
+
const profile = resolveAgentProfile({
|
|
6584
|
+
config: config2,
|
|
6585
|
+
storedAgentId: session.agentId,
|
|
6586
|
+
requestMetadata
|
|
6587
|
+
});
|
|
6230
6588
|
let effectiveModel = resolveEffectiveModel({
|
|
6231
6589
|
session,
|
|
6232
6590
|
requestMetadata,
|
|
@@ -6325,17 +6683,8 @@ var NextclawNcpContextBuilder = class {
|
|
|
6325
6683
|
};
|
|
6326
6684
|
};
|
|
6327
6685
|
|
|
6328
|
-
// src/cli/commands/ncp/nextclaw-agent-session-
|
|
6686
|
+
// src/cli/commands/ncp/session/nextclaw-agent-session-message-adapter.ts
|
|
6329
6687
|
import { sanitizeAssistantReplyTags as sanitizeAssistantReplyTags2 } from "@nextclaw/ncp";
|
|
6330
|
-
|
|
6331
|
-
// src/cli/commands/ncp/nextclaw-agent-session-metadata.utils.ts
|
|
6332
|
-
function resolvePersistedSessionMetadata(params) {
|
|
6333
|
-
const messageMetadata = extractMessageMetadata(params.sessionRecord.messages);
|
|
6334
|
-
const nextMetadata = params.preserveExistingMetadata ? mergeSessionMetadata(params.currentMetadata, messageMetadata) : mergeSessionMetadata({}, messageMetadata);
|
|
6335
|
-
return mergeSessionMetadata(nextMetadata, cloneMetadata(params.sessionRecord.metadata));
|
|
6336
|
-
}
|
|
6337
|
-
|
|
6338
|
-
// src/cli/commands/ncp/nextclaw-agent-session-store.ts
|
|
6339
6688
|
function tryParseJson(value) {
|
|
6340
6689
|
try {
|
|
6341
6690
|
return JSON.parse(value);
|
|
@@ -6587,6 +6936,21 @@ function resolveLegacyEventType(message) {
|
|
|
6587
6936
|
}
|
|
6588
6937
|
return `message.${role || "other"}`;
|
|
6589
6938
|
}
|
|
6939
|
+
|
|
6940
|
+
// src/cli/commands/ncp/session/nextclaw-agent-session-metadata.utils.ts
|
|
6941
|
+
function resolvePersistedSessionMetadata(params) {
|
|
6942
|
+
const messageMetadata = extractMessageMetadata(params.sessionRecord.messages);
|
|
6943
|
+
const nextMetadata = params.preserveExistingMetadata ? mergeSessionMetadata(params.currentMetadata, messageMetadata) : mergeSessionMetadata({}, messageMetadata);
|
|
6944
|
+
return mergeSessionMetadata(nextMetadata, cloneMetadata(params.sessionRecord.metadata));
|
|
6945
|
+
}
|
|
6946
|
+
|
|
6947
|
+
// src/cli/commands/ncp/nextclaw-agent-session-store.ts
|
|
6948
|
+
function readAgentIdFromMetadata(metadata) {
|
|
6949
|
+
return normalizeString(metadata?.agent_id)?.toLowerCase() ?? normalizeString(metadata?.agentId)?.toLowerCase() ?? void 0;
|
|
6950
|
+
}
|
|
6951
|
+
function resolveSessionRecordAgentId(record) {
|
|
6952
|
+
return normalizeString(record.agentId)?.toLowerCase() ?? readAgentIdFromMetadata(record.metadata);
|
|
6953
|
+
}
|
|
6590
6954
|
var NextclawAgentSessionStore = class {
|
|
6591
6955
|
constructor(sessionManager, options = {}) {
|
|
6592
6956
|
this.sessionManager = sessionManager;
|
|
@@ -6597,7 +6961,13 @@ var NextclawAgentSessionStore = class {
|
|
|
6597
6961
|
if (!session) {
|
|
6598
6962
|
return null;
|
|
6599
6963
|
}
|
|
6600
|
-
return {
|
|
6964
|
+
return {
|
|
6965
|
+
sessionId,
|
|
6966
|
+
...session.agentId ? { agentId: session.agentId } : {},
|
|
6967
|
+
messages: toNcpMessages(sessionId, session.messages),
|
|
6968
|
+
updatedAt: session.updatedAt.toISOString(),
|
|
6969
|
+
metadata: structuredClone(session.metadata)
|
|
6970
|
+
};
|
|
6601
6971
|
};
|
|
6602
6972
|
listSessions = async () => {
|
|
6603
6973
|
const records = this.sessionManager.listSessions();
|
|
@@ -6611,7 +6981,13 @@ var NextclawAgentSessionStore = class {
|
|
|
6611
6981
|
if (!session) {
|
|
6612
6982
|
continue;
|
|
6613
6983
|
}
|
|
6614
|
-
sessions.push({
|
|
6984
|
+
sessions.push({
|
|
6985
|
+
sessionId,
|
|
6986
|
+
...session.agentId ? { agentId: session.agentId } : {},
|
|
6987
|
+
messages: toNcpMessages(sessionId, session.messages),
|
|
6988
|
+
updatedAt: session.updatedAt.toISOString(),
|
|
6989
|
+
metadata: structuredClone(session.metadata)
|
|
6990
|
+
});
|
|
6615
6991
|
}
|
|
6616
6992
|
sessions.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
6617
6993
|
return sessions;
|
|
@@ -6622,6 +6998,10 @@ var NextclawAgentSessionStore = class {
|
|
|
6622
6998
|
}
|
|
6623
6999
|
const session = this.sessionManager.getIfExists(sessionRecord.sessionId) ?? this.sessionManager.getOrCreate(sessionRecord.sessionId);
|
|
6624
7000
|
const legacyMessages = toLegacyMessages(sessionRecord.messages);
|
|
7001
|
+
const nextAgentId = resolveSessionRecordAgentId(sessionRecord);
|
|
7002
|
+
if (nextAgentId) {
|
|
7003
|
+
session.agentId = nextAgentId;
|
|
7004
|
+
}
|
|
6625
7005
|
session.metadata = resolvePersistedSessionMetadata({
|
|
6626
7006
|
currentMetadata: session.metadata,
|
|
6627
7007
|
sessionRecord,
|
|
@@ -6664,7 +7044,7 @@ var NextclawAgentSessionStore = class {
|
|
|
6664
7044
|
};
|
|
6665
7045
|
};
|
|
6666
7046
|
|
|
6667
|
-
// src/cli/commands/ncp/provider-manager-ncp-llm-api.ts
|
|
7047
|
+
// src/cli/commands/ncp/provider/provider-manager-ncp-llm-api.ts
|
|
6668
7048
|
import { parseThinkingLevel as parseThinkingLevel3 } from "@nextclaw/core";
|
|
6669
7049
|
function normalizeModel(value) {
|
|
6670
7050
|
if (typeof value !== "string") {
|
|
@@ -6782,6 +7162,7 @@ var ProviderManagerNcpLLMApi = class {
|
|
|
6782
7162
|
};
|
|
6783
7163
|
|
|
6784
7164
|
// src/cli/commands/ncp/session-request/session-creation.service.ts
|
|
7165
|
+
import { resolveDefaultAgentProfileId as resolveDefaultAgentProfileId2 } from "@nextclaw/core";
|
|
6785
7166
|
import { randomUUID } from "crypto";
|
|
6786
7167
|
var DEFAULT_SESSION_TYPE = "native";
|
|
6787
7168
|
var DEFAULT_LIFECYCLE = "persistent";
|
|
@@ -6827,51 +7208,85 @@ function cloneInheritedMetadata(sourceMetadata) {
|
|
|
6827
7208
|
}
|
|
6828
7209
|
return nextMetadata;
|
|
6829
7210
|
}
|
|
6830
|
-
function buildSessionId(
|
|
6831
|
-
void agentId;
|
|
7211
|
+
function buildSessionId() {
|
|
6832
7212
|
return `ncp-${Date.now().toString(36)}-${randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
6833
7213
|
}
|
|
7214
|
+
function resolveSessionAgentId(params) {
|
|
7215
|
+
return readOptionalString4(params.agentId) ?? resolveDefaultAgentProfileId2(params.getConfig());
|
|
7216
|
+
}
|
|
7217
|
+
function resolveSessionTitle(params) {
|
|
7218
|
+
return readOptionalString4(params.title) ?? summarizeTask(params.task);
|
|
7219
|
+
}
|
|
7220
|
+
function resolveSessionType(params) {
|
|
7221
|
+
return readOptionalString4(params.sessionType) ?? readOptionalString4(params.metadata.session_type) ?? DEFAULT_SESSION_TYPE;
|
|
7222
|
+
}
|
|
7223
|
+
function applySessionOverrides(params) {
|
|
7224
|
+
params.metadata.session_type = params.sessionType;
|
|
7225
|
+
params.metadata[SESSION_METADATA_LABEL_KEY] = params.title;
|
|
7226
|
+
params.metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = params.lifecycle;
|
|
7227
|
+
if (params.parentSessionId) {
|
|
7228
|
+
params.metadata[CHILD_SESSION_PARENT_METADATA_KEY] = params.parentSessionId;
|
|
7229
|
+
params.metadata[CHILD_SESSION_PROMOTED_METADATA_KEY] = false;
|
|
7230
|
+
}
|
|
7231
|
+
if (params.requestId) {
|
|
7232
|
+
params.metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = params.requestId;
|
|
7233
|
+
}
|
|
7234
|
+
if (readOptionalString4(params.model)) {
|
|
7235
|
+
params.metadata.model = params.model?.trim();
|
|
7236
|
+
params.metadata.preferred_model = params.model?.trim();
|
|
7237
|
+
}
|
|
7238
|
+
if (readOptionalString4(params.thinkingLevel)) {
|
|
7239
|
+
params.metadata.thinking = params.thinkingLevel?.trim();
|
|
7240
|
+
params.metadata.preferred_thinking = params.thinkingLevel?.trim();
|
|
7241
|
+
}
|
|
7242
|
+
if (readOptionalString4(params.projectRoot)) {
|
|
7243
|
+
params.metadata.project_root = params.projectRoot?.trim();
|
|
7244
|
+
}
|
|
7245
|
+
}
|
|
6834
7246
|
var SessionCreationService = class {
|
|
6835
|
-
constructor(sessionManager, onSessionUpdated) {
|
|
7247
|
+
constructor(sessionManager, getConfig, onSessionUpdated) {
|
|
6836
7248
|
this.sessionManager = sessionManager;
|
|
7249
|
+
this.getConfig = getConfig;
|
|
6837
7250
|
this.onSessionUpdated = onSessionUpdated;
|
|
6838
7251
|
}
|
|
6839
7252
|
createSession = (params) => {
|
|
6840
|
-
const sessionId = buildSessionId(
|
|
7253
|
+
const sessionId = buildSessionId();
|
|
6841
7254
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
6842
7255
|
const session = this.sessionManager.getOrCreate(sessionId);
|
|
6843
|
-
const
|
|
7256
|
+
const resolvedAgentId = resolveSessionAgentId({
|
|
7257
|
+
agentId: params.agentId,
|
|
7258
|
+
getConfig: this.getConfig
|
|
7259
|
+
});
|
|
7260
|
+
const title = resolveSessionTitle({
|
|
7261
|
+
title: params.title,
|
|
7262
|
+
task: params.task
|
|
7263
|
+
});
|
|
6844
7264
|
const metadata = cloneInheritedMetadata(params.sourceSessionMetadata);
|
|
6845
7265
|
const parentSessionId = readOptionalString4(params.parentSessionId);
|
|
6846
7266
|
const requestId = readOptionalString4(params.requestId);
|
|
6847
|
-
const sessionType =
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
metadata
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
}
|
|
6862
|
-
|
|
6863
|
-
metadata.thinking = params.thinkingLevel?.trim();
|
|
6864
|
-
metadata.preferred_thinking = params.thinkingLevel?.trim();
|
|
6865
|
-
}
|
|
6866
|
-
if (readOptionalString4(params.projectRoot)) {
|
|
6867
|
-
metadata.project_root = params.projectRoot?.trim();
|
|
6868
|
-
}
|
|
7267
|
+
const sessionType = resolveSessionType({
|
|
7268
|
+
sessionType: params.sessionType,
|
|
7269
|
+
metadata
|
|
7270
|
+
});
|
|
7271
|
+
applySessionOverrides({
|
|
7272
|
+
metadata,
|
|
7273
|
+
sessionType,
|
|
7274
|
+
title,
|
|
7275
|
+
lifecycle: DEFAULT_LIFECYCLE,
|
|
7276
|
+
parentSessionId,
|
|
7277
|
+
requestId,
|
|
7278
|
+
model: params.model,
|
|
7279
|
+
thinkingLevel: params.thinkingLevel,
|
|
7280
|
+
projectRoot: params.projectRoot
|
|
7281
|
+
});
|
|
7282
|
+
session.agentId = resolvedAgentId;
|
|
6869
7283
|
session.metadata = metadata;
|
|
6870
7284
|
session.updatedAt = new Date(now3);
|
|
6871
7285
|
this.sessionManager.save(session);
|
|
6872
7286
|
this.onSessionUpdated?.(sessionId);
|
|
6873
7287
|
return {
|
|
6874
7288
|
sessionId,
|
|
7289
|
+
agentId: resolvedAgentId,
|
|
6875
7290
|
sessionType,
|
|
6876
7291
|
runtimeFamily: "native",
|
|
6877
7292
|
...parentSessionId ? { parentSessionId } : {},
|
|
@@ -6910,6 +7325,8 @@ import {
|
|
|
6910
7325
|
NcpEventType
|
|
6911
7326
|
} from "@nextclaw/ncp";
|
|
6912
7327
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
7328
|
+
|
|
7329
|
+
// src/cli/commands/ncp/session-request/session-request-result.ts
|
|
6913
7330
|
function readOptionalString5(value) {
|
|
6914
7331
|
if (typeof value !== "string") {
|
|
6915
7332
|
return null;
|
|
@@ -6917,7 +7334,7 @@ function readOptionalString5(value) {
|
|
|
6917
7334
|
const trimmed = value.trim();
|
|
6918
7335
|
return trimmed.length > 0 ? trimmed : null;
|
|
6919
7336
|
}
|
|
6920
|
-
function
|
|
7337
|
+
function summarizeSessionRequestTask(task) {
|
|
6921
7338
|
const normalized = task.trim().replace(/\s+/g, " ");
|
|
6922
7339
|
if (!normalized) {
|
|
6923
7340
|
return "Session request";
|
|
@@ -6927,21 +7344,7 @@ function summarizeTask2(task) {
|
|
|
6927
7344
|
}
|
|
6928
7345
|
return `${normalized.slice(0, 69)}...`;
|
|
6929
7346
|
}
|
|
6930
|
-
function
|
|
6931
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
6932
|
-
return {
|
|
6933
|
-
id: `${params.sessionId}:user:session-request:${params.requestId}`,
|
|
6934
|
-
sessionId: params.sessionId,
|
|
6935
|
-
role: "user",
|
|
6936
|
-
status: "final",
|
|
6937
|
-
timestamp,
|
|
6938
|
-
parts: [{ type: "text", text: params.task }],
|
|
6939
|
-
metadata: {
|
|
6940
|
-
session_request_id: params.requestId
|
|
6941
|
-
}
|
|
6942
|
-
};
|
|
6943
|
-
}
|
|
6944
|
-
function extractMessageText(message) {
|
|
7347
|
+
function extractSessionMessageText(message) {
|
|
6945
7348
|
if (!message) {
|
|
6946
7349
|
return void 0;
|
|
6947
7350
|
}
|
|
@@ -6968,26 +7371,110 @@ function findLatestAssistantMessage(messages) {
|
|
|
6968
7371
|
function readParentSessionId(metadata) {
|
|
6969
7372
|
return readOptionalString5(metadata?.[CHILD_SESSION_PARENT_METADATA_KEY]) ?? void 0;
|
|
6970
7373
|
}
|
|
6971
|
-
function
|
|
7374
|
+
function buildSessionRequestToolResult(params) {
|
|
7375
|
+
const {
|
|
7376
|
+
request,
|
|
7377
|
+
task,
|
|
7378
|
+
title,
|
|
7379
|
+
agentId,
|
|
7380
|
+
isChildSession,
|
|
7381
|
+
parentSessionId,
|
|
7382
|
+
spawnedByRequestId,
|
|
7383
|
+
message
|
|
7384
|
+
} = params;
|
|
6972
7385
|
return {
|
|
6973
7386
|
kind: "nextclaw.session_request",
|
|
6974
|
-
requestId:
|
|
6975
|
-
sessionId:
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
...
|
|
6979
|
-
|
|
7387
|
+
requestId: request.requestId,
|
|
7388
|
+
sessionId: request.targetSessionId,
|
|
7389
|
+
...agentId ? { agentId } : {},
|
|
7390
|
+
targetKind: isChildSession ? "child" : "session",
|
|
7391
|
+
...parentSessionId ? { parentSessionId } : {},
|
|
7392
|
+
...spawnedByRequestId ? { spawnedByRequestId } : {},
|
|
7393
|
+
isChildSession,
|
|
6980
7394
|
lifecycle: "persistent",
|
|
6981
|
-
...
|
|
6982
|
-
task
|
|
6983
|
-
status:
|
|
6984
|
-
awaitMode:
|
|
6985
|
-
deliveryMode:
|
|
6986
|
-
...
|
|
6987
|
-
...
|
|
6988
|
-
...
|
|
7395
|
+
...title.trim() ? { title } : {},
|
|
7396
|
+
task,
|
|
7397
|
+
status: request.status,
|
|
7398
|
+
awaitMode: request.awaitMode,
|
|
7399
|
+
deliveryMode: request.deliveryMode,
|
|
7400
|
+
...request.finalResponseText ? { finalResponseText: request.finalResponseText } : {},
|
|
7401
|
+
...request.error ? { error: request.error } : {},
|
|
7402
|
+
...message ? { message } : {}
|
|
7403
|
+
};
|
|
7404
|
+
}
|
|
7405
|
+
|
|
7406
|
+
// src/cli/commands/ncp/session-request/session-request-execution.ts
|
|
7407
|
+
function buildSessionRequestUserMessage(params) {
|
|
7408
|
+
const { sessionId, requestId, task } = params;
|
|
7409
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7410
|
+
return {
|
|
7411
|
+
id: `${sessionId}:user:session-request:${requestId}`,
|
|
7412
|
+
sessionId,
|
|
7413
|
+
role: "user",
|
|
7414
|
+
status: "final",
|
|
7415
|
+
timestamp,
|
|
7416
|
+
parts: [{ type: "text", text: task }],
|
|
7417
|
+
metadata: {
|
|
7418
|
+
session_request_id: requestId
|
|
7419
|
+
}
|
|
7420
|
+
};
|
|
7421
|
+
}
|
|
7422
|
+
function createRunningSessionRequest(params) {
|
|
7423
|
+
const {
|
|
7424
|
+
requestId,
|
|
7425
|
+
sourceSessionId,
|
|
7426
|
+
targetSessionId,
|
|
7427
|
+
sourceToolCallId,
|
|
7428
|
+
handoffDepth,
|
|
7429
|
+
awaitMode,
|
|
7430
|
+
deliveryMode,
|
|
7431
|
+
title,
|
|
7432
|
+
task,
|
|
7433
|
+
isChildSession,
|
|
7434
|
+
parentSessionId
|
|
7435
|
+
} = params;
|
|
7436
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7437
|
+
return {
|
|
7438
|
+
requestId,
|
|
7439
|
+
sourceSessionId,
|
|
7440
|
+
targetSessionId,
|
|
7441
|
+
sourceToolCallId,
|
|
7442
|
+
rootRequestId: requestId,
|
|
7443
|
+
handoffDepth,
|
|
7444
|
+
awaitMode,
|
|
7445
|
+
deliveryMode,
|
|
7446
|
+
status: "running",
|
|
7447
|
+
createdAt,
|
|
7448
|
+
startedAt: createdAt,
|
|
7449
|
+
metadata: {
|
|
7450
|
+
title,
|
|
7451
|
+
task,
|
|
7452
|
+
is_child_session: isChildSession,
|
|
7453
|
+
...parentSessionId ? { parent_session_id: parentSessionId } : {}
|
|
7454
|
+
}
|
|
7455
|
+
};
|
|
7456
|
+
}
|
|
7457
|
+
function createCompletedSessionRequest(params) {
|
|
7458
|
+
const { request, completedMessage, finalResponseText } = params;
|
|
7459
|
+
return {
|
|
7460
|
+
...request,
|
|
7461
|
+
status: "completed",
|
|
7462
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7463
|
+
finalResponseMessageId: completedMessage?.id,
|
|
7464
|
+
finalResponseText
|
|
7465
|
+
};
|
|
7466
|
+
}
|
|
7467
|
+
function createFailedSessionRequest(params) {
|
|
7468
|
+
const { request, error } = params;
|
|
7469
|
+
return {
|
|
7470
|
+
...request,
|
|
7471
|
+
status: "failed",
|
|
7472
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7473
|
+
error: error instanceof Error ? error.message : String(error)
|
|
6989
7474
|
};
|
|
6990
7475
|
}
|
|
7476
|
+
|
|
7477
|
+
// src/cli/commands/ncp/session-request/session-request-broker.ts
|
|
6991
7478
|
var SessionRequestBroker = class {
|
|
6992
7479
|
constructor(sessionManager, sessionCreationService, deliveryService, resolveBackend, onSessionUpdated) {
|
|
6993
7480
|
this.sessionManager = sessionManager;
|
|
@@ -6997,200 +7484,275 @@ var SessionRequestBroker = class {
|
|
|
6997
7484
|
this.onSessionUpdated = onSessionUpdated;
|
|
6998
7485
|
}
|
|
6999
7486
|
spawnChildSessionAndRequest = async (params) => {
|
|
7487
|
+
const {
|
|
7488
|
+
sourceSessionId,
|
|
7489
|
+
sourceToolCallId,
|
|
7490
|
+
sourceSessionMetadata,
|
|
7491
|
+
task,
|
|
7492
|
+
title,
|
|
7493
|
+
model,
|
|
7494
|
+
handoffDepth,
|
|
7495
|
+
sessionType,
|
|
7496
|
+
thinkingLevel,
|
|
7497
|
+
projectRoot,
|
|
7498
|
+
agentId
|
|
7499
|
+
} = params;
|
|
7000
7500
|
const requestId = randomUUID2();
|
|
7001
7501
|
const childSession = this.sessionCreationService.createChildSession({
|
|
7002
|
-
parentSessionId:
|
|
7003
|
-
task
|
|
7004
|
-
title
|
|
7005
|
-
sourceSessionMetadata
|
|
7006
|
-
agentId
|
|
7007
|
-
model
|
|
7008
|
-
thinkingLevel
|
|
7009
|
-
sessionType
|
|
7010
|
-
projectRoot
|
|
7502
|
+
parentSessionId: sourceSessionId,
|
|
7503
|
+
task,
|
|
7504
|
+
title,
|
|
7505
|
+
sourceSessionMetadata,
|
|
7506
|
+
agentId,
|
|
7507
|
+
model,
|
|
7508
|
+
thinkingLevel,
|
|
7509
|
+
sessionType,
|
|
7510
|
+
projectRoot,
|
|
7011
7511
|
requestId
|
|
7012
7512
|
});
|
|
7013
7513
|
return this.dispatchRequest({
|
|
7014
7514
|
requestId,
|
|
7015
|
-
sourceSessionId
|
|
7016
|
-
sourceToolCallId
|
|
7515
|
+
sourceSessionId,
|
|
7516
|
+
sourceToolCallId,
|
|
7017
7517
|
targetSessionId: childSession.sessionId,
|
|
7018
|
-
task
|
|
7019
|
-
title: childSession.title ??
|
|
7020
|
-
handoffDepth:
|
|
7518
|
+
task,
|
|
7519
|
+
title: childSession.title ?? summarizeSessionRequestTask(task),
|
|
7520
|
+
handoffDepth: handoffDepth ?? 0,
|
|
7021
7521
|
awaitMode: "final_reply",
|
|
7022
7522
|
deliveryMode: "resume_source",
|
|
7523
|
+
agentId: childSession.agentId,
|
|
7023
7524
|
isChildSession: true,
|
|
7024
|
-
parentSessionId:
|
|
7525
|
+
parentSessionId: sourceSessionId,
|
|
7025
7526
|
spawnedByRequestId: requestId
|
|
7026
7527
|
});
|
|
7027
7528
|
};
|
|
7028
7529
|
requestSession = async (params) => {
|
|
7029
|
-
|
|
7530
|
+
const {
|
|
7531
|
+
sourceSessionId,
|
|
7532
|
+
sourceToolCallId,
|
|
7533
|
+
targetSessionId,
|
|
7534
|
+
task,
|
|
7535
|
+
title,
|
|
7536
|
+
awaitMode,
|
|
7537
|
+
deliveryMode,
|
|
7538
|
+
handoffDepth
|
|
7539
|
+
} = params;
|
|
7540
|
+
const normalizedTargetSessionId = targetSessionId.trim();
|
|
7541
|
+
if (normalizedTargetSessionId === sourceSessionId.trim()) {
|
|
7030
7542
|
throw new Error("sessions_request cannot target the current session.");
|
|
7031
7543
|
}
|
|
7032
7544
|
const backend = this.resolveBackend();
|
|
7033
7545
|
if (!backend) {
|
|
7034
7546
|
throw new Error("NCP backend is not ready for session requests.");
|
|
7035
7547
|
}
|
|
7036
|
-
const targetSummary = await backend.getSession(
|
|
7548
|
+
const targetSummary = await backend.getSession(normalizedTargetSessionId);
|
|
7037
7549
|
if (!targetSummary) {
|
|
7038
|
-
throw new Error(`Target session not found: ${
|
|
7550
|
+
throw new Error(`Target session not found: ${targetSessionId}`);
|
|
7039
7551
|
}
|
|
7040
7552
|
const parentSessionId = readParentSessionId(targetSummary.metadata);
|
|
7041
7553
|
return this.dispatchRequest({
|
|
7042
7554
|
requestId: randomUUID2(),
|
|
7043
|
-
sourceSessionId
|
|
7044
|
-
sourceToolCallId
|
|
7045
|
-
targetSessionId:
|
|
7046
|
-
task
|
|
7047
|
-
title: readOptionalString5(
|
|
7048
|
-
handoffDepth:
|
|
7049
|
-
awaitMode
|
|
7050
|
-
deliveryMode
|
|
7555
|
+
sourceSessionId,
|
|
7556
|
+
sourceToolCallId,
|
|
7557
|
+
targetSessionId: normalizedTargetSessionId,
|
|
7558
|
+
task,
|
|
7559
|
+
title: readOptionalString5(title) ?? readOptionalString5(targetSummary.metadata?.label) ?? summarizeSessionRequestTask(task),
|
|
7560
|
+
handoffDepth: handoffDepth ?? 0,
|
|
7561
|
+
awaitMode,
|
|
7562
|
+
deliveryMode,
|
|
7563
|
+
agentId: targetSummary.agentId,
|
|
7051
7564
|
isChildSession: Boolean(parentSessionId),
|
|
7052
7565
|
parentSessionId: parentSessionId ?? void 0,
|
|
7053
7566
|
spawnedByRequestId: void 0
|
|
7054
7567
|
});
|
|
7055
7568
|
};
|
|
7056
7569
|
dispatchRequest = async (params) => {
|
|
7057
|
-
const
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
targetSessionId
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
handoffDepth
|
|
7065
|
-
awaitMode
|
|
7066
|
-
deliveryMode
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7570
|
+
const {
|
|
7571
|
+
requestId,
|
|
7572
|
+
sourceSessionId,
|
|
7573
|
+
sourceToolCallId,
|
|
7574
|
+
targetSessionId,
|
|
7575
|
+
task,
|
|
7576
|
+
title,
|
|
7577
|
+
handoffDepth,
|
|
7578
|
+
awaitMode,
|
|
7579
|
+
deliveryMode,
|
|
7580
|
+
agentId,
|
|
7581
|
+
isChildSession,
|
|
7582
|
+
parentSessionId,
|
|
7583
|
+
spawnedByRequestId
|
|
7584
|
+
} = params;
|
|
7585
|
+
const request = createRunningSessionRequest({
|
|
7586
|
+
requestId,
|
|
7587
|
+
sourceSessionId,
|
|
7588
|
+
targetSessionId,
|
|
7589
|
+
sourceToolCallId,
|
|
7590
|
+
handoffDepth,
|
|
7591
|
+
awaitMode,
|
|
7592
|
+
deliveryMode,
|
|
7593
|
+
title,
|
|
7594
|
+
task,
|
|
7595
|
+
isChildSession,
|
|
7596
|
+
parentSessionId
|
|
7597
|
+
});
|
|
7077
7598
|
void this.runRequest({
|
|
7078
7599
|
request,
|
|
7079
|
-
task
|
|
7080
|
-
title
|
|
7081
|
-
|
|
7082
|
-
|
|
7600
|
+
task,
|
|
7601
|
+
title,
|
|
7602
|
+
agentId,
|
|
7603
|
+
isChildSession,
|
|
7604
|
+
parentSessionId
|
|
7083
7605
|
}).catch((error) => {
|
|
7084
7606
|
console.error(
|
|
7085
|
-
`[session-request] Background request ${
|
|
7607
|
+
`[session-request] Background request ${requestId} crashed: ${error instanceof Error ? error.message : String(error)}`
|
|
7086
7608
|
);
|
|
7087
7609
|
});
|
|
7088
|
-
return
|
|
7610
|
+
return buildSessionRequestToolResult({
|
|
7089
7611
|
request,
|
|
7090
|
-
task
|
|
7091
|
-
title
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7612
|
+
task,
|
|
7613
|
+
title,
|
|
7614
|
+
agentId,
|
|
7615
|
+
isChildSession,
|
|
7616
|
+
parentSessionId,
|
|
7617
|
+
spawnedByRequestId,
|
|
7095
7618
|
message: `Session request started. You'll receive the final reply when it finishes.`
|
|
7096
7619
|
});
|
|
7097
7620
|
};
|
|
7098
|
-
|
|
7621
|
+
resolveBackendOrThrow = () => {
|
|
7622
|
+
const backend = this.resolveBackend();
|
|
7623
|
+
if (!backend) {
|
|
7624
|
+
throw new Error("NCP backend is not ready for session request execution.");
|
|
7625
|
+
}
|
|
7626
|
+
return backend;
|
|
7627
|
+
};
|
|
7628
|
+
readCompletedMessageFromStream = async (params) => {
|
|
7629
|
+
const { backend, request, task } = params;
|
|
7099
7630
|
let completedMessage;
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
message
|
|
7113
|
-
})) {
|
|
7114
|
-
if (event.type === NcpEventType.MessageAccepted) {
|
|
7115
|
-
this.handleRequestEvent(params.request, event);
|
|
7116
|
-
continue;
|
|
7117
|
-
}
|
|
7118
|
-
if (event.type === NcpEventType.MessageFailed) {
|
|
7119
|
-
throw new Error(event.payload.error.message);
|
|
7120
|
-
}
|
|
7121
|
-
if (event.type === NcpEventType.RunError) {
|
|
7122
|
-
throw new Error(event.payload.error ?? "Session request failed.");
|
|
7123
|
-
}
|
|
7124
|
-
if (event.type === NcpEventType.MessageCompleted) {
|
|
7125
|
-
completedMessage = event.payload.message;
|
|
7126
|
-
}
|
|
7631
|
+
const message = buildSessionRequestUserMessage({
|
|
7632
|
+
sessionId: request.targetSessionId,
|
|
7633
|
+
requestId: request.requestId,
|
|
7634
|
+
task
|
|
7635
|
+
});
|
|
7636
|
+
for await (const event of backend.send({
|
|
7637
|
+
sessionId: request.targetSessionId,
|
|
7638
|
+
message
|
|
7639
|
+
})) {
|
|
7640
|
+
if (event.type === NcpEventType.MessageAccepted) {
|
|
7641
|
+
this.handleRequestEvent(request, event);
|
|
7642
|
+
continue;
|
|
7127
7643
|
}
|
|
7128
|
-
if (
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
}
|
|
7134
|
-
if (
|
|
7135
|
-
|
|
7136
|
-
}
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7644
|
+
if (event.type === NcpEventType.MessageFailed) {
|
|
7645
|
+
throw new Error(event.payload.error.message);
|
|
7646
|
+
}
|
|
7647
|
+
if (event.type === NcpEventType.RunError) {
|
|
7648
|
+
throw new Error(event.payload.error ?? "Session request failed.");
|
|
7649
|
+
}
|
|
7650
|
+
if (event.type === NcpEventType.MessageCompleted) {
|
|
7651
|
+
completedMessage = event.payload.message;
|
|
7652
|
+
}
|
|
7653
|
+
}
|
|
7654
|
+
return completedMessage;
|
|
7655
|
+
};
|
|
7656
|
+
resolveCompletedMessage = async (params) => {
|
|
7657
|
+
const { request, task } = params;
|
|
7658
|
+
const backend = this.resolveBackendOrThrow();
|
|
7659
|
+
const streamedMessage = await this.readCompletedMessageFromStream({
|
|
7660
|
+
backend,
|
|
7661
|
+
request,
|
|
7662
|
+
task
|
|
7663
|
+
});
|
|
7664
|
+
if (streamedMessage) {
|
|
7665
|
+
return streamedMessage;
|
|
7666
|
+
}
|
|
7667
|
+
const targetMessages = await backend.listSessionMessages(
|
|
7668
|
+
request.targetSessionId
|
|
7669
|
+
);
|
|
7670
|
+
const fallbackMessage = findLatestAssistantMessage(targetMessages);
|
|
7671
|
+
if (fallbackMessage) {
|
|
7672
|
+
return fallbackMessage;
|
|
7673
|
+
}
|
|
7674
|
+
throw new Error("Session request completed without a final reply.");
|
|
7675
|
+
};
|
|
7676
|
+
appendRequestEvents = (request, type) => {
|
|
7677
|
+
this.appendRequestEvent(request.sourceSessionId, type, request);
|
|
7678
|
+
this.appendRequestEvent(request.targetSessionId, type, request);
|
|
7679
|
+
};
|
|
7680
|
+
publishRequestOutcome = async (params) => {
|
|
7681
|
+
const {
|
|
7682
|
+
request,
|
|
7683
|
+
task,
|
|
7684
|
+
title,
|
|
7685
|
+
agentId,
|
|
7686
|
+
isChildSession,
|
|
7687
|
+
parentSessionId,
|
|
7688
|
+
spawnedByRequestId
|
|
7689
|
+
} = params;
|
|
7690
|
+
const result = buildSessionRequestToolResult({
|
|
7691
|
+
request,
|
|
7692
|
+
task,
|
|
7693
|
+
title,
|
|
7694
|
+
agentId,
|
|
7695
|
+
isChildSession,
|
|
7696
|
+
parentSessionId,
|
|
7697
|
+
spawnedByRequestId
|
|
7698
|
+
});
|
|
7699
|
+
await this.deliveryService.publishToolResult({
|
|
7700
|
+
request,
|
|
7701
|
+
result
|
|
7702
|
+
});
|
|
7703
|
+
if (request.deliveryMode === "resume_source") {
|
|
7704
|
+
await this.deliveryService.resumeSourceSession({
|
|
7705
|
+
request,
|
|
7706
|
+
result
|
|
7707
|
+
});
|
|
7708
|
+
}
|
|
7709
|
+
};
|
|
7710
|
+
runRequest = async (params) => {
|
|
7711
|
+
const {
|
|
7712
|
+
request,
|
|
7713
|
+
task,
|
|
7714
|
+
title,
|
|
7715
|
+
agentId,
|
|
7716
|
+
isChildSession,
|
|
7717
|
+
parentSessionId,
|
|
7718
|
+
spawnedByRequestId
|
|
7719
|
+
} = params;
|
|
7720
|
+
try {
|
|
7721
|
+
const completedMessage = await this.resolveCompletedMessage({
|
|
7722
|
+
request,
|
|
7723
|
+
task
|
|
7724
|
+
});
|
|
7725
|
+
const finalResponseText = extractSessionMessageText(completedMessage);
|
|
7726
|
+
const completedRequest = createCompletedSessionRequest({
|
|
7727
|
+
request,
|
|
7728
|
+
completedMessage,
|
|
7144
7729
|
finalResponseText
|
|
7145
|
-
};
|
|
7146
|
-
this.appendRequestEvent(params.request.sourceSessionId, "session.request.completed", completedRequest);
|
|
7147
|
-
this.appendRequestEvent(params.request.targetSessionId, "session.request.completed", completedRequest);
|
|
7148
|
-
const result = buildToolResult({
|
|
7149
|
-
request: completedRequest,
|
|
7150
|
-
task: params.task,
|
|
7151
|
-
title: params.title,
|
|
7152
|
-
isChildSession: params.isChildSession,
|
|
7153
|
-
parentSessionId: params.parentSessionId,
|
|
7154
|
-
spawnedByRequestId: params.spawnedByRequestId
|
|
7155
7730
|
});
|
|
7156
|
-
|
|
7731
|
+
this.appendRequestEvents(completedRequest, "session.request.completed");
|
|
7732
|
+
await this.publishRequestOutcome({
|
|
7157
7733
|
request: completedRequest,
|
|
7158
|
-
|
|
7734
|
+
task,
|
|
7735
|
+
title,
|
|
7736
|
+
agentId,
|
|
7737
|
+
isChildSession,
|
|
7738
|
+
parentSessionId,
|
|
7739
|
+
spawnedByRequestId
|
|
7159
7740
|
});
|
|
7160
|
-
if (completedRequest.deliveryMode === "resume_source") {
|
|
7161
|
-
await this.deliveryService.resumeSourceSession({
|
|
7162
|
-
request: completedRequest,
|
|
7163
|
-
result
|
|
7164
|
-
});
|
|
7165
|
-
}
|
|
7166
7741
|
} catch (error) {
|
|
7167
|
-
const
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
status: "failed",
|
|
7171
|
-
completedAt,
|
|
7172
|
-
error: error instanceof Error ? error.message : String(error)
|
|
7173
|
-
};
|
|
7174
|
-
this.appendRequestEvent(params.request.sourceSessionId, "session.request.failed", failedRequest);
|
|
7175
|
-
this.appendRequestEvent(params.request.targetSessionId, "session.request.failed", failedRequest);
|
|
7176
|
-
const result = buildToolResult({
|
|
7177
|
-
request: failedRequest,
|
|
7178
|
-
task: params.task,
|
|
7179
|
-
title: params.title,
|
|
7180
|
-
isChildSession: params.isChildSession,
|
|
7181
|
-
parentSessionId: params.parentSessionId,
|
|
7182
|
-
spawnedByRequestId: params.spawnedByRequestId
|
|
7742
|
+
const failedRequest = createFailedSessionRequest({
|
|
7743
|
+
request,
|
|
7744
|
+
error
|
|
7183
7745
|
});
|
|
7184
|
-
|
|
7746
|
+
this.appendRequestEvents(failedRequest, "session.request.failed");
|
|
7747
|
+
await this.publishRequestOutcome({
|
|
7185
7748
|
request: failedRequest,
|
|
7186
|
-
|
|
7749
|
+
task,
|
|
7750
|
+
title,
|
|
7751
|
+
agentId,
|
|
7752
|
+
isChildSession,
|
|
7753
|
+
parentSessionId,
|
|
7754
|
+
spawnedByRequestId
|
|
7187
7755
|
});
|
|
7188
|
-
if (failedRequest.deliveryMode === "resume_source") {
|
|
7189
|
-
await this.deliveryService.resumeSourceSession({
|
|
7190
|
-
request: failedRequest,
|
|
7191
|
-
result
|
|
7192
|
-
});
|
|
7193
|
-
}
|
|
7194
7756
|
}
|
|
7195
7757
|
};
|
|
7196
7758
|
handleRequestEvent = (request, event) => {
|
|
@@ -7240,7 +7802,7 @@ function scheduleDetached(taskFactory, label) {
|
|
|
7240
7802
|
}, 0);
|
|
7241
7803
|
}
|
|
7242
7804
|
async function sleep(ms) {
|
|
7243
|
-
await new Promise((
|
|
7805
|
+
await new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
7244
7806
|
}
|
|
7245
7807
|
async function waitForSessionToBecomeIdle(params) {
|
|
7246
7808
|
const timeoutMs = params.timeoutMs ?? 15e3;
|
|
@@ -7428,6 +7990,34 @@ var UiNcpRuntimeRegistry = class {
|
|
|
7428
7990
|
}
|
|
7429
7991
|
};
|
|
7430
7992
|
|
|
7993
|
+
// src/cli/commands/ncp/runtime/ui-ncp-agent-handle.ts
|
|
7994
|
+
import { createAgentClientFromServer } from "@nextclaw/ncp-toolkit";
|
|
7995
|
+
function createUiNcpAgentHandle(params) {
|
|
7996
|
+
return {
|
|
7997
|
+
basePath: "/api/ncp/agent",
|
|
7998
|
+
agentClientEndpoint: createAgentClientFromServer(params.backend),
|
|
7999
|
+
streamProvider: params.backend,
|
|
8000
|
+
sessionApi: params.backend,
|
|
8001
|
+
listSessionTypes: (describeParams) => {
|
|
8002
|
+
params.refreshPluginRuntimeRegistrations();
|
|
8003
|
+
return params.runtimeRegistry.listSessionTypes(describeParams);
|
|
8004
|
+
},
|
|
8005
|
+
assetApi: {
|
|
8006
|
+
put: (input) => params.assetStore.putBytes({
|
|
8007
|
+
fileName: input.fileName,
|
|
8008
|
+
mimeType: input.mimeType,
|
|
8009
|
+
bytes: input.bytes,
|
|
8010
|
+
createdAt: input.createdAt
|
|
8011
|
+
}),
|
|
8012
|
+
stat: (uri) => params.assetStore.statRecord(uri),
|
|
8013
|
+
resolveContentPath: (uri) => params.assetStore.resolveContentPath(uri)
|
|
8014
|
+
},
|
|
8015
|
+
applyExtensionRegistry: params.applyExtensionRegistry,
|
|
8016
|
+
applyMcpConfig: params.applyMcpConfig,
|
|
8017
|
+
dispose: params.dispose
|
|
8018
|
+
};
|
|
8019
|
+
}
|
|
8020
|
+
|
|
7431
8021
|
// src/cli/commands/ncp/create-ui-ncp-agent.ts
|
|
7432
8022
|
import { join as join5 } from "path";
|
|
7433
8023
|
var CODEX_RUNTIME_KIND = "codex";
|
|
@@ -7617,31 +8207,6 @@ var PluginRuntimeRegistrationController = class {
|
|
|
7617
8207
|
this.pluginRuntimeSnapshotKey = "";
|
|
7618
8208
|
};
|
|
7619
8209
|
};
|
|
7620
|
-
function createUiNcpAgentHandle(params) {
|
|
7621
|
-
return {
|
|
7622
|
-
basePath: "/api/ncp/agent",
|
|
7623
|
-
agentClientEndpoint: createAgentClientFromServer(params.backend),
|
|
7624
|
-
streamProvider: params.backend,
|
|
7625
|
-
sessionApi: params.backend,
|
|
7626
|
-
listSessionTypes: (describeParams) => {
|
|
7627
|
-
params.refreshPluginRuntimeRegistrations();
|
|
7628
|
-
return params.runtimeRegistry.listSessionTypes(describeParams);
|
|
7629
|
-
},
|
|
7630
|
-
assetApi: {
|
|
7631
|
-
put: (input) => params.assetStore.putBytes({
|
|
7632
|
-
fileName: input.fileName,
|
|
7633
|
-
mimeType: input.mimeType,
|
|
7634
|
-
bytes: input.bytes,
|
|
7635
|
-
createdAt: input.createdAt
|
|
7636
|
-
}),
|
|
7637
|
-
stat: (uri) => params.assetStore.statRecord(uri),
|
|
7638
|
-
resolveContentPath: (uri) => params.assetStore.resolveContentPath(uri)
|
|
7639
|
-
},
|
|
7640
|
-
applyExtensionRegistry: params.applyExtensionRegistry,
|
|
7641
|
-
applyMcpConfig: params.applyMcpConfig,
|
|
7642
|
-
dispose: params.dispose
|
|
7643
|
-
};
|
|
7644
|
-
}
|
|
7645
8210
|
async function createUiNcpAgent(params) {
|
|
7646
8211
|
const sessionStore = new NextclawAgentSessionStore(params.sessionManager, {
|
|
7647
8212
|
onSessionUpdated: params.onSessionUpdated
|
|
@@ -7654,6 +8219,7 @@ async function createUiNcpAgent(params) {
|
|
|
7654
8219
|
let backend = null;
|
|
7655
8220
|
const sessionCreationService = new SessionCreationService(
|
|
7656
8221
|
params.sessionManager,
|
|
8222
|
+
params.getConfig,
|
|
7657
8223
|
params.onSessionUpdated
|
|
7658
8224
|
);
|
|
7659
8225
|
const sessionRequestBroker = new SessionRequestBroker(
|
|
@@ -7705,7 +8271,7 @@ async function createUiNcpAgent(params) {
|
|
|
7705
8271
|
});
|
|
7706
8272
|
}
|
|
7707
8273
|
|
|
7708
|
-
// src/cli/commands/service-gateway-context.ts
|
|
8274
|
+
// src/cli/commands/service-support/gateway/service-gateway-context.ts
|
|
7709
8275
|
import * as NextclawCore from "@nextclaw/core";
|
|
7710
8276
|
import { getPluginChannelBindings as getPluginChannelBindings3, resolvePluginChannelMessageToolHints } from "@nextclaw/openclaw-compat";
|
|
7711
8277
|
import { join as join6 } from "path";
|
|
@@ -8169,14 +8735,16 @@ var ConfigReloader = class {
|
|
|
8169
8735
|
}
|
|
8170
8736
|
};
|
|
8171
8737
|
|
|
8172
|
-
// src/cli/commands/agent-runtime-pool.ts
|
|
8738
|
+
// src/cli/commands/agent/agent-runtime-pool.ts
|
|
8173
8739
|
import {
|
|
8174
8740
|
NativeAgentEngine,
|
|
8175
8741
|
CommandRegistry,
|
|
8176
8742
|
createAssistantStreamDeltaControlMessage,
|
|
8177
8743
|
createAssistantStreamResetControlMessage,
|
|
8178
8744
|
AgentRouteResolver,
|
|
8179
|
-
getWorkspacePath as
|
|
8745
|
+
getWorkspacePath as getWorkspacePath9,
|
|
8746
|
+
resolveDefaultAgentProfileId as resolveDefaultAgentProfileId3,
|
|
8747
|
+
resolveEffectiveAgentProfiles as resolveEffectiveAgentProfiles2,
|
|
8180
8748
|
parseAgentScopedSessionKey
|
|
8181
8749
|
} from "@nextclaw/core";
|
|
8182
8750
|
function normalizeAgentId(value) {
|
|
@@ -8198,33 +8766,21 @@ function toRecord(value) {
|
|
|
8198
8766
|
}
|
|
8199
8767
|
function resolveAgentProfiles(config2) {
|
|
8200
8768
|
const defaults = config2.agents.defaults;
|
|
8201
|
-
const
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
workspace: entry.workspace,
|
|
8205
|
-
model: entry.model,
|
|
8206
|
-
engine: entry.engine,
|
|
8207
|
-
engineConfig: toRecord(entry.engineConfig),
|
|
8208
|
-
maxToolIterations: entry.maxToolIterations,
|
|
8209
|
-
contextTokens: entry.contextTokens
|
|
8210
|
-
})).filter((entry) => Boolean(entry.id)) : [];
|
|
8211
|
-
const defaultAgentId = listed.find((entry) => entry.default)?.id ?? listed[0]?.id ?? "main";
|
|
8212
|
-
const seed = listed.length > 0 ? listed : [{ id: defaultAgentId }];
|
|
8769
|
+
const defaultAgentId = normalizeAgentId(resolveDefaultAgentProfileId3(config2));
|
|
8770
|
+
const listed = resolveEffectiveAgentProfiles2(config2);
|
|
8771
|
+
const seed = listed.length > 0 ? listed : [{ id: defaultAgentId, workspace: defaults.workspace }];
|
|
8213
8772
|
const unique = /* @__PURE__ */ new Map();
|
|
8214
8773
|
for (const entry of seed) {
|
|
8215
8774
|
if (!unique.has(entry.id)) {
|
|
8216
8775
|
unique.set(entry.id, entry);
|
|
8217
8776
|
}
|
|
8218
8777
|
}
|
|
8219
|
-
if (!unique.has(defaultAgentId)) {
|
|
8220
|
-
unique.set(defaultAgentId, { id: defaultAgentId });
|
|
8221
|
-
}
|
|
8222
8778
|
return Array.from(unique.values()).map((entry) => ({
|
|
8223
8779
|
id: entry.id,
|
|
8224
|
-
workspace:
|
|
8780
|
+
workspace: getWorkspacePath9(entry.workspace),
|
|
8225
8781
|
model: entry.model ?? defaults.model,
|
|
8226
8782
|
engine: normalizeEngineKind(entry.engine ?? defaults.engine),
|
|
8227
|
-
engineConfig: entry.engineConfig ?? toRecord(defaults.engineConfig),
|
|
8783
|
+
engineConfig: toRecord(entry.engineConfig) ?? toRecord(defaults.engineConfig),
|
|
8228
8784
|
maxIterations: entry.maxToolIterations ?? defaults.maxToolIterations,
|
|
8229
8785
|
contextTokens: entry.contextTokens ?? defaults.contextTokens
|
|
8230
8786
|
}));
|
|
@@ -8489,7 +9045,7 @@ var GatewayAgentRuntimePool = class {
|
|
|
8489
9045
|
const normalizedAgentId = normalizeAgentId(agentId);
|
|
8490
9046
|
return this.resolvedProfiles.find((profile) => profile.id === normalizedAgentId) ?? this.resolvedProfiles.find((profile) => profile.id === this.defaultAgentId) ?? this.resolvedProfiles[0] ?? {
|
|
8491
9047
|
id: this.defaultAgentId,
|
|
8492
|
-
workspace:
|
|
9048
|
+
workspace: getWorkspacePath9(this.options.config.agents.defaults.workspace),
|
|
8493
9049
|
model: this.options.config.agents.defaults.model,
|
|
8494
9050
|
maxIterations: this.options.config.agents.defaults.maxToolIterations,
|
|
8495
9051
|
contextTokens: this.options.config.agents.defaults.contextTokens,
|
|
@@ -8666,7 +9222,7 @@ function formatUserFacingError(error, maxChars = 320) {
|
|
|
8666
9222
|
return `${normalized.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
8667
9223
|
}
|
|
8668
9224
|
|
|
8669
|
-
// src/cli/commands/service-cron-job-handler.ts
|
|
9225
|
+
// src/cli/commands/service-support/gateway/service-cron-job-handler.ts
|
|
8670
9226
|
function normalizeOptionalString6(value) {
|
|
8671
9227
|
if (typeof value !== "string") {
|
|
8672
9228
|
return void 0;
|
|
@@ -8684,13 +9240,14 @@ function createCronJobHandler(params) {
|
|
|
8684
9240
|
return async (job) => {
|
|
8685
9241
|
const accountId = normalizeOptionalString6(job.payload.accountId);
|
|
8686
9242
|
const metadata = buildCronJobMetadata(accountId);
|
|
9243
|
+
const agentId = normalizeOptionalString6(job.payload.agentId) ?? params.runtimePool.primaryAgentId;
|
|
8687
9244
|
const response = await params.runtimePool.processDirect({
|
|
8688
9245
|
content: job.payload.message,
|
|
8689
9246
|
sessionKey: `cron:${job.id}`,
|
|
8690
9247
|
channel: job.payload.channel ?? "cli",
|
|
8691
9248
|
chatId: job.payload.to ?? "direct",
|
|
8692
9249
|
metadata,
|
|
8693
|
-
agentId
|
|
9250
|
+
agentId
|
|
8694
9251
|
});
|
|
8695
9252
|
if (job.payload.deliver && job.payload.to) {
|
|
8696
9253
|
await params.bus.publishOutbound({
|
|
@@ -8705,15 +9262,15 @@ function createCronJobHandler(params) {
|
|
|
8705
9262
|
};
|
|
8706
9263
|
}
|
|
8707
9264
|
|
|
8708
|
-
// src/cli/commands/service-gateway-context.ts
|
|
9265
|
+
// src/cli/commands/service-support/gateway/service-gateway-context.ts
|
|
8709
9266
|
var {
|
|
8710
9267
|
ChannelManager: ChannelManager2,
|
|
8711
9268
|
CronService: CronService2,
|
|
8712
9269
|
getConfigPath: getConfigPath9,
|
|
8713
9270
|
getDataDir: getDataDir8,
|
|
8714
|
-
getWorkspacePath:
|
|
9271
|
+
getWorkspacePath: getWorkspacePath10,
|
|
8715
9272
|
HeartbeatService,
|
|
8716
|
-
loadConfig:
|
|
9273
|
+
loadConfig: loadConfig17,
|
|
8717
9274
|
MessageBus,
|
|
8718
9275
|
ProviderManager,
|
|
8719
9276
|
resolveConfigSecrets: resolveConfigSecrets2,
|
|
@@ -8727,8 +9284,8 @@ function applyGatewayCapabilityState(gateway, next) {
|
|
|
8727
9284
|
}
|
|
8728
9285
|
function createGatewayShellContext(params) {
|
|
8729
9286
|
const runtimeConfigPath = getConfigPath9();
|
|
8730
|
-
const config2 = resolveConfigSecrets2(
|
|
8731
|
-
const workspace =
|
|
9287
|
+
const config2 = resolveConfigSecrets2(loadConfig17(), { configPath: runtimeConfigPath });
|
|
9288
|
+
const workspace = getWorkspacePath10(config2.agents.defaults.workspace);
|
|
8732
9289
|
const cronStorePath = join6(getDataDir8(), "cron", "jobs.json");
|
|
8733
9290
|
const sessionManager = measureStartupSync(
|
|
8734
9291
|
"service.gateway_shell_context.session_manager",
|
|
@@ -8738,7 +9295,7 @@ function createGatewayShellContext(params) {
|
|
|
8738
9295
|
const uiConfig = resolveUiConfig(config2, params.uiOverrides);
|
|
8739
9296
|
const uiStaticDir = params.uiStaticDir === void 0 ? resolveUiStaticDir() : params.uiStaticDir;
|
|
8740
9297
|
const remoteModule = createManagedRemoteModuleForUi({
|
|
8741
|
-
loadConfig: () => resolveConfigSecrets2(
|
|
9298
|
+
loadConfig: () => resolveConfigSecrets2(loadConfig17(), { configPath: runtimeConfigPath }),
|
|
8742
9299
|
uiConfig
|
|
8743
9300
|
});
|
|
8744
9301
|
return {
|
|
@@ -8808,7 +9365,7 @@ function createGatewayStartupContext(params) {
|
|
|
8808
9365
|
sessionManager: state.sessionManager,
|
|
8809
9366
|
providerManager: state.providerManager,
|
|
8810
9367
|
makeProvider: (nextConfig) => params.makeProvider(nextConfig, { allowMissing: true }) ?? params.makeMissingProvider(nextConfig),
|
|
8811
|
-
loadConfig: () => resolveConfigSecrets2(
|
|
9368
|
+
loadConfig: () => resolveConfigSecrets2(loadConfig17(), { configPath: state.runtimeConfigPath }),
|
|
8812
9369
|
resolveChannelConfig: (nextConfig) => resolveChannelConfigView(nextConfig, state.pluginChannelBindings),
|
|
8813
9370
|
getExtensionChannels: () => state.extensionRegistry.channels,
|
|
8814
9371
|
onRestartRequired: (paths) => {
|
|
@@ -8821,7 +9378,7 @@ function createGatewayStartupContext(params) {
|
|
|
8821
9378
|
})
|
|
8822
9379
|
);
|
|
8823
9380
|
state.applyLiveConfigReload = async () => {
|
|
8824
|
-
await state.reloader.applyReloadPlan(resolveConfigSecrets2(
|
|
9381
|
+
await state.reloader.applyReloadPlan(resolveConfigSecrets2(loadConfig17(), { configPath: state.runtimeConfigPath }));
|
|
8825
9382
|
};
|
|
8826
9383
|
state.gatewayController = measureStartupSync(
|
|
8827
9384
|
"service.gateway_context.gateway_controller",
|
|
@@ -8859,7 +9416,7 @@ function createGatewayStartupContext(params) {
|
|
|
8859
9416
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
8860
9417
|
registry: state.pluginRegistry,
|
|
8861
9418
|
channel,
|
|
8862
|
-
cfg: resolveConfigSecrets2(
|
|
9419
|
+
cfg: resolveConfigSecrets2(loadConfig17(), { configPath: state.runtimeConfigPath }),
|
|
8863
9420
|
accountId
|
|
8864
9421
|
})
|
|
8865
9422
|
})
|
|
@@ -8878,12 +9435,12 @@ function createGatewayStartupContext(params) {
|
|
|
8878
9435
|
return state;
|
|
8879
9436
|
}
|
|
8880
9437
|
|
|
8881
|
-
// src/cli/commands/service-gateway-startup.ts
|
|
9438
|
+
// src/cli/commands/service-support/gateway/service-gateway-startup.ts
|
|
8882
9439
|
import {
|
|
8883
9440
|
startUiServer
|
|
8884
9441
|
} from "@nextclaw/server";
|
|
8885
9442
|
|
|
8886
|
-
// src/cli/commands/service-deferred-ncp-agent.ts
|
|
9443
|
+
// src/cli/commands/service-support/session/service-deferred-ncp-agent.ts
|
|
8887
9444
|
var DEFAULT_BASE_PATH = "/api/ncp/agent";
|
|
8888
9445
|
var DEFERRED_NCP_AGENT_UNAVAILABLE = "ncp agent unavailable during startup";
|
|
8889
9446
|
function createUnavailableError() {
|
|
@@ -8979,7 +9536,7 @@ function createDeferredUiNcpAgent(basePath = DEFAULT_BASE_PATH) {
|
|
|
8979
9536
|
return new DeferredUiNcpAgentControllerOwner(basePath);
|
|
8980
9537
|
}
|
|
8981
9538
|
|
|
8982
|
-
// src/cli/commands/service-gateway-startup.ts
|
|
9539
|
+
// src/cli/commands/service-support/gateway/service-gateway-startup.ts
|
|
8983
9540
|
function wireSystemSessionUpdatedPublisher(params) {
|
|
8984
9541
|
params.runtimePool.setSystemSessionUpdatedHandler(({ sessionKey }) => {
|
|
8985
9542
|
params.publishUiEvent?.({
|
|
@@ -9002,6 +9559,7 @@ async function startUiShell(params) {
|
|
|
9002
9559
|
productVersion: params.productVersion,
|
|
9003
9560
|
staticDir: params.uiStaticDir ?? void 0,
|
|
9004
9561
|
applyLiveConfigReload: params.applyLiveConfigReload,
|
|
9562
|
+
initializeAgentHomeDirectory: params.initializeAgentHomeDirectory,
|
|
9005
9563
|
cronService: params.cronService,
|
|
9006
9564
|
marketplace: params.marketplace,
|
|
9007
9565
|
remoteAccess: params.remoteAccess,
|
|
@@ -9087,7 +9645,7 @@ async function runGatewayRuntimeLoop(params) {
|
|
|
9087
9645
|
}
|
|
9088
9646
|
}
|
|
9089
9647
|
|
|
9090
|
-
// src/cli/commands/ncp/ncp-session-realtime-change.ts
|
|
9648
|
+
// src/cli/commands/ncp/session/ncp-session-realtime-change.ts
|
|
9091
9649
|
function toNcpSessionRealtimeEvent(change) {
|
|
9092
9650
|
if (change.kind === "upsert") {
|
|
9093
9651
|
return {
|
|
@@ -9127,10 +9685,11 @@ function createNcpSessionRealtimeChangePublisher(params) {
|
|
|
9127
9685
|
};
|
|
9128
9686
|
}
|
|
9129
9687
|
|
|
9130
|
-
// src/cli/commands/ncp/ncp-session-summary.ts
|
|
9688
|
+
// src/cli/commands/ncp/session/ncp-session-summary.ts
|
|
9131
9689
|
function createNcpSessionSummary(params) {
|
|
9132
9690
|
return {
|
|
9133
9691
|
sessionId: params.sessionId,
|
|
9692
|
+
...params.agentId ? { agentId: params.agentId } : {},
|
|
9134
9693
|
messageCount: params.messages.length,
|
|
9135
9694
|
updatedAt: params.updatedAt,
|
|
9136
9695
|
status: params.status,
|
|
@@ -9170,6 +9729,7 @@ var UiSessionService = class {
|
|
|
9170
9729
|
sessions.map(
|
|
9171
9730
|
(session) => createNcpSessionSummary({
|
|
9172
9731
|
sessionId: session.sessionId,
|
|
9732
|
+
agentId: session.agentId,
|
|
9173
9733
|
messages: session.messages,
|
|
9174
9734
|
updatedAt: session.updatedAt,
|
|
9175
9735
|
status: "idle",
|
|
@@ -9193,6 +9753,7 @@ var UiSessionService = class {
|
|
|
9193
9753
|
}
|
|
9194
9754
|
return createNcpSessionSummary({
|
|
9195
9755
|
sessionId,
|
|
9756
|
+
agentId: session.agentId,
|
|
9196
9757
|
messages: session.messages,
|
|
9197
9758
|
updatedAt: session.updatedAt,
|
|
9198
9759
|
status: "idle",
|
|
@@ -9217,7 +9778,7 @@ var UiSessionService = class {
|
|
|
9217
9778
|
};
|
|
9218
9779
|
};
|
|
9219
9780
|
|
|
9220
|
-
// src/cli/commands/service-deferred-ncp-session-service.ts
|
|
9781
|
+
// src/cli/commands/service-support/session/service-deferred-ncp-session-service.ts
|
|
9221
9782
|
function createDeferredUiNcpSessionService(fallbackService) {
|
|
9222
9783
|
let activeService = null;
|
|
9223
9784
|
const resolveService = () => activeService ?? fallbackService;
|
|
@@ -9242,7 +9803,7 @@ function createDeferredUiNcpSessionService(fallbackService) {
|
|
|
9242
9803
|
};
|
|
9243
9804
|
}
|
|
9244
9805
|
|
|
9245
|
-
// src/cli/commands/service-ncp-session-realtime-bridge.ts
|
|
9806
|
+
// src/cli/commands/service-support/session/service-ncp-session-realtime-bridge.ts
|
|
9246
9807
|
function createLatestOnlySessionChangePublisher(publishSessionChange) {
|
|
9247
9808
|
const inFlightTasks = /* @__PURE__ */ new Map();
|
|
9248
9809
|
const rerunKeys = /* @__PURE__ */ new Set();
|
|
@@ -9305,7 +9866,7 @@ function createServiceNcpSessionRealtimeBridge(params) {
|
|
|
9305
9866
|
};
|
|
9306
9867
|
}
|
|
9307
9868
|
|
|
9308
|
-
// src/cli/commands/plugin-registry-loader.ts
|
|
9869
|
+
// src/cli/commands/plugin/plugin-registry-loader.ts
|
|
9309
9870
|
import {
|
|
9310
9871
|
discoverPluginStatusReport,
|
|
9311
9872
|
loadOpenClawPluginsProgressively
|
|
@@ -9357,14 +9918,14 @@ function createEmptyPluginRegistry() {
|
|
|
9357
9918
|
};
|
|
9358
9919
|
}
|
|
9359
9920
|
|
|
9360
|
-
// src/cli/commands/service-gateway-bootstrap.ts
|
|
9921
|
+
// src/cli/commands/service-support/gateway/service-gateway-bootstrap.ts
|
|
9361
9922
|
import * as NextclawCore2 from "@nextclaw/core";
|
|
9362
9923
|
import {
|
|
9363
9924
|
getPluginUiMetadataFromRegistry as getPluginUiMetadataFromRegistry2,
|
|
9364
9925
|
startPluginChannelGateways as startPluginChannelGateways2
|
|
9365
9926
|
} from "@nextclaw/openclaw-compat";
|
|
9366
9927
|
|
|
9367
|
-
// src/cli/commands/service-bootstrap-status.ts
|
|
9928
|
+
// src/cli/commands/service-support/gateway/service-bootstrap-status.ts
|
|
9368
9929
|
function now2() {
|
|
9369
9930
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
9370
9931
|
}
|
|
@@ -9488,14 +10049,14 @@ var ServiceBootstrapStatusStore = class {
|
|
|
9488
10049
|
}
|
|
9489
10050
|
};
|
|
9490
10051
|
|
|
9491
|
-
// src/cli/commands/service-capability-hydration.ts
|
|
9492
|
-
import { getWorkspacePath as
|
|
10052
|
+
// src/cli/commands/service-support/gateway/service-capability-hydration.ts
|
|
10053
|
+
import { getWorkspacePath as getWorkspacePath11, loadConfig as loadConfig18, resolveConfigSecrets as resolveConfigSecrets3 } from "@nextclaw/core";
|
|
9493
10054
|
import {
|
|
9494
10055
|
getPluginChannelBindings as getPluginChannelBindings4,
|
|
9495
10056
|
getPluginUiMetadataFromRegistry
|
|
9496
10057
|
} from "@nextclaw/openclaw-compat";
|
|
9497
10058
|
|
|
9498
|
-
// src/cli/commands/plugin-reload.ts
|
|
10059
|
+
// src/cli/commands/plugin/plugin-reload.ts
|
|
9499
10060
|
function buildPluginChannelBindingSignature(binding) {
|
|
9500
10061
|
return `${binding.pluginId}:${binding.channelId}`;
|
|
9501
10062
|
}
|
|
@@ -9568,7 +10129,7 @@ function shouldRestartChannelsForPluginReload(params) {
|
|
|
9568
10129
|
return false;
|
|
9569
10130
|
}
|
|
9570
10131
|
|
|
9571
|
-
// src/cli/commands/service-ui-shell-grace.ts
|
|
10132
|
+
// src/cli/commands/service-support/gateway/service-ui-shell-grace.ts
|
|
9572
10133
|
import { setTimeout as delay } from "timers/promises";
|
|
9573
10134
|
var DEFAULT_UI_SHELL_GRACE_MS = 3e3;
|
|
9574
10135
|
async function waitForUiShellGraceWindow(uiStartup) {
|
|
@@ -9580,14 +10141,14 @@ async function waitForUiShellGraceWindow(uiStartup) {
|
|
|
9580
10141
|
});
|
|
9581
10142
|
}
|
|
9582
10143
|
|
|
9583
|
-
// src/cli/commands/service-capability-hydration.ts
|
|
10144
|
+
// src/cli/commands/service-support/gateway/service-capability-hydration.ts
|
|
9584
10145
|
function countEnabledPlugins(config2, workspaceDir) {
|
|
9585
10146
|
return discoverPluginRegistryStatus(config2, workspaceDir).plugins.filter((plugin) => plugin.enabled).length;
|
|
9586
10147
|
}
|
|
9587
10148
|
async function hydrateServiceCapabilities(params) {
|
|
9588
10149
|
await waitForUiShellGraceWindow(params.uiStartup);
|
|
9589
|
-
const nextConfig = resolveConfigSecrets3(
|
|
9590
|
-
const nextWorkspace =
|
|
10150
|
+
const nextConfig = resolveConfigSecrets3(loadConfig18(), { configPath: params.gateway.runtimeConfigPath });
|
|
10151
|
+
const nextWorkspace = getWorkspacePath11(nextConfig.agents.defaults.workspace);
|
|
9591
10152
|
const totalPluginCount = countEnabledPlugins(nextConfig, nextWorkspace);
|
|
9592
10153
|
let loadedPluginCount = 0;
|
|
9593
10154
|
params.bootstrapStatus.markPluginHydrationRunning({
|
|
@@ -9643,18 +10204,18 @@ async function hydrateServiceCapabilities(params) {
|
|
|
9643
10204
|
}
|
|
9644
10205
|
}
|
|
9645
10206
|
|
|
9646
|
-
// src/cli/commands/service-plugin-runtime-bridge.ts
|
|
9647
|
-
import { loadConfig as
|
|
10207
|
+
// src/cli/commands/service-support/plugin/service-plugin-runtime-bridge.ts
|
|
10208
|
+
import { loadConfig as loadConfig19, resolveConfigSecrets as resolveConfigSecrets4, saveConfig as saveConfig10 } from "@nextclaw/core";
|
|
9648
10209
|
import { setPluginRuntimeBridge } from "@nextclaw/openclaw-compat";
|
|
9649
10210
|
function installPluginRuntimeBridge(params) {
|
|
9650
10211
|
const { runtimePool, runtimeConfigPath, getPluginChannelBindings: getPluginChannelBindings7 } = params;
|
|
9651
10212
|
setPluginRuntimeBridge({
|
|
9652
|
-
loadConfig: () => toPluginConfigView(resolveConfigSecrets4(
|
|
10213
|
+
loadConfig: () => toPluginConfigView(resolveConfigSecrets4(loadConfig19(), { configPath: runtimeConfigPath }), getPluginChannelBindings7()),
|
|
9653
10214
|
writeConfigFile: async (nextConfigView) => {
|
|
9654
10215
|
if (!nextConfigView || typeof nextConfigView !== "object" || Array.isArray(nextConfigView)) {
|
|
9655
10216
|
throw new Error("plugin runtime writeConfigFile expects an object config");
|
|
9656
10217
|
}
|
|
9657
|
-
const current =
|
|
10218
|
+
const current = loadConfig19();
|
|
9658
10219
|
const next = mergePluginConfigView(current, nextConfigView, getPluginChannelBindings7());
|
|
9659
10220
|
saveConfig10(next);
|
|
9660
10221
|
},
|
|
@@ -9759,15 +10320,15 @@ function resolvePluginRuntimeAttachments(ctx) {
|
|
|
9759
10320
|
return attachments;
|
|
9760
10321
|
}
|
|
9761
10322
|
|
|
9762
|
-
// src/cli/commands/service-plugin-reload.ts
|
|
9763
|
-
import { getWorkspacePath as
|
|
10323
|
+
// src/cli/commands/service-support/plugin/service-plugin-reload.ts
|
|
10324
|
+
import { getWorkspacePath as getWorkspacePath12 } from "@nextclaw/core";
|
|
9764
10325
|
import {
|
|
9765
10326
|
getPluginChannelBindings as getPluginChannelBindings5,
|
|
9766
10327
|
startPluginChannelGateways,
|
|
9767
10328
|
stopPluginChannelGateways
|
|
9768
10329
|
} from "@nextclaw/openclaw-compat";
|
|
9769
10330
|
async function reloadServicePlugins(params) {
|
|
9770
|
-
const nextWorkspace =
|
|
10331
|
+
const nextWorkspace = getWorkspacePath12(params.nextConfig.agents.defaults.workspace);
|
|
9771
10332
|
const nextPluginRegistry = loadPluginRegistry(params.nextConfig, nextWorkspace);
|
|
9772
10333
|
const nextExtensionRegistry = toExtensionRegistry(nextPluginRegistry);
|
|
9773
10334
|
const nextPluginChannelBindings = getPluginChannelBindings5(nextPluginRegistry);
|
|
@@ -9799,8 +10360,8 @@ async function reloadServicePlugins(params) {
|
|
|
9799
10360
|
};
|
|
9800
10361
|
}
|
|
9801
10362
|
|
|
9802
|
-
// src/cli/commands/service-gateway-bootstrap.ts
|
|
9803
|
-
var { loadConfig:
|
|
10363
|
+
// src/cli/commands/service-support/gateway/service-gateway-bootstrap.ts
|
|
10364
|
+
var { loadConfig: loadConfig20, resolveConfigSecrets: resolveConfigSecrets5 } = NextclawCore2;
|
|
9804
10365
|
function createBootstrapStatus(remoteEnabled) {
|
|
9805
10366
|
const bootstrapStatus = new ServiceBootstrapStatusStore();
|
|
9806
10367
|
bootstrapStatus.markPluginHydrationPending();
|
|
@@ -9878,7 +10439,7 @@ function createDeferredGatewayStartupHooks(params) {
|
|
|
9878
10439
|
startPluginGateways: async () => {
|
|
9879
10440
|
const startedPluginGateways = await startPluginChannelGateways2({
|
|
9880
10441
|
registry: params.state.pluginRegistry,
|
|
9881
|
-
config: resolveConfigSecrets5(
|
|
10442
|
+
config: resolveConfigSecrets5(loadConfig20(), { configPath: params.gateway.runtimeConfigPath }),
|
|
9882
10443
|
logger: pluginGatewayLogger
|
|
9883
10444
|
});
|
|
9884
10445
|
params.state.pluginGatewayHandles = startedPluginGateways.handles;
|
|
@@ -9909,9 +10470,9 @@ var {
|
|
|
9909
10470
|
getConfigPath: getConfigPath10,
|
|
9910
10471
|
getProvider,
|
|
9911
10472
|
getProviderName,
|
|
9912
|
-
getWorkspacePath:
|
|
10473
|
+
getWorkspacePath: getWorkspacePath13,
|
|
9913
10474
|
LiteLLMProvider,
|
|
9914
|
-
loadConfig:
|
|
10475
|
+
loadConfig: loadConfig21,
|
|
9915
10476
|
MessageBus: MessageBus2,
|
|
9916
10477
|
resolveConfigSecrets: resolveConfigSecrets6,
|
|
9917
10478
|
SessionManager: SessionManager2,
|
|
@@ -9930,7 +10491,7 @@ var ServiceCommands = class {
|
|
|
9930
10491
|
}
|
|
9931
10492
|
applyLiveConfigReload = null;
|
|
9932
10493
|
liveUiNcpAgent = null;
|
|
9933
|
-
async
|
|
10494
|
+
startGateway = async (options = {}) => {
|
|
9934
10495
|
logStartupTrace("service.start_gateway.begin");
|
|
9935
10496
|
this.applyLiveConfigReload = null;
|
|
9936
10497
|
this.liveUiNcpAgent = null;
|
|
@@ -9952,7 +10513,7 @@ var ServiceCommands = class {
|
|
|
9952
10513
|
uiConfig: shellContext.uiConfig,
|
|
9953
10514
|
uiStaticDir: shellContext.uiStaticDir,
|
|
9954
10515
|
cronService: shellContext.cron,
|
|
9955
|
-
getConfig: () => resolveConfigSecrets6(
|
|
10516
|
+
getConfig: () => resolveConfigSecrets6(loadConfig21(), { configPath: shellContext.runtimeConfigPath }),
|
|
9956
10517
|
configPath: getConfigPath10(),
|
|
9957
10518
|
productVersion: getPackageVersion(),
|
|
9958
10519
|
getPluginChannelBindings: () => runtimeState?.pluginChannelBindings ?? [],
|
|
@@ -9962,7 +10523,8 @@ var ServiceCommands = class {
|
|
|
9962
10523
|
getBootstrapStatus: () => bootstrapStatus.getStatus(),
|
|
9963
10524
|
openBrowserWindow: shellContext.uiConfig.open,
|
|
9964
10525
|
applyLiveConfigReload,
|
|
9965
|
-
ncpSessionService: ncpSessionRealtimeBridge.sessionService
|
|
10526
|
+
ncpSessionService: ncpSessionRealtimeBridge.sessionService,
|
|
10527
|
+
initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory
|
|
9966
10528
|
})
|
|
9967
10529
|
);
|
|
9968
10530
|
ncpSessionRealtimeBridge.setUiEventPublisher(uiStartup?.publish);
|
|
@@ -9999,7 +10561,7 @@ var ServiceCommands = class {
|
|
|
9999
10561
|
startHeartbeat: () => gateway.heartbeat.start()
|
|
10000
10562
|
})
|
|
10001
10563
|
);
|
|
10002
|
-
watchCronStoreFile({ cronStorePath:
|
|
10564
|
+
watchCronStoreFile({ cronStorePath: resolve14(join7(NextclawCore3.getDataDir(), "cron", "jobs.json")), reloadCronStore: () => gateway.cron.reloadFromStore() });
|
|
10003
10565
|
const deferredGatewayStartupHooks = createDeferredGatewayStartupHooks({
|
|
10004
10566
|
uiStartup,
|
|
10005
10567
|
gateway,
|
|
@@ -10022,12 +10584,12 @@ var ServiceCommands = class {
|
|
|
10022
10584
|
providerManager: gateway.providerManager,
|
|
10023
10585
|
cronService: gateway.cron,
|
|
10024
10586
|
gatewayController: gateway.gatewayController,
|
|
10025
|
-
getConfig: () => resolveConfigSecrets6(
|
|
10587
|
+
getConfig: () => resolveConfigSecrets6(loadConfig21(), { configPath: gateway.runtimeConfigPath }),
|
|
10026
10588
|
getExtensionRegistry: () => gatewayRuntimeState.extensionRegistry,
|
|
10027
10589
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints2({
|
|
10028
10590
|
registry: gatewayRuntimeState.pluginRegistry,
|
|
10029
10591
|
channel,
|
|
10030
|
-
cfg: resolveConfigSecrets6(
|
|
10592
|
+
cfg: resolveConfigSecrets6(loadConfig21(), { configPath: gateway.runtimeConfigPath }),
|
|
10031
10593
|
accountId
|
|
10032
10594
|
}),
|
|
10033
10595
|
hydrateCapabilities: deferredGatewayStartupHooks.hydrateCapabilities,
|
|
@@ -10056,22 +10618,22 @@ var ServiceCommands = class {
|
|
|
10056
10618
|
}
|
|
10057
10619
|
});
|
|
10058
10620
|
logStartupTrace("service.start_gateway.end");
|
|
10059
|
-
}
|
|
10060
|
-
normalizeOptionalString(value) {
|
|
10621
|
+
};
|
|
10622
|
+
normalizeOptionalString = (value) => {
|
|
10061
10623
|
if (typeof value !== "string") {
|
|
10062
10624
|
return void 0;
|
|
10063
10625
|
}
|
|
10064
10626
|
const trimmed = value.trim();
|
|
10065
10627
|
return trimmed || void 0;
|
|
10066
|
-
}
|
|
10067
|
-
watchConfigFile(reloader) {
|
|
10068
|
-
const configPath =
|
|
10628
|
+
};
|
|
10629
|
+
watchConfigFile = (reloader) => {
|
|
10630
|
+
const configPath = resolve14(getConfigPath10());
|
|
10069
10631
|
const watcher = chokidar2.watch(configPath, {
|
|
10070
10632
|
ignoreInitial: true,
|
|
10071
10633
|
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
10072
10634
|
});
|
|
10073
10635
|
watcher.on("all", (event, changedPath) => {
|
|
10074
|
-
if (
|
|
10636
|
+
if (resolve14(changedPath) !== configPath) {
|
|
10075
10637
|
return;
|
|
10076
10638
|
}
|
|
10077
10639
|
if (event === "add") {
|
|
@@ -10086,34 +10648,24 @@ var ServiceCommands = class {
|
|
|
10086
10648
|
reloader.scheduleReload("config unlink");
|
|
10087
10649
|
}
|
|
10088
10650
|
});
|
|
10089
|
-
}
|
|
10090
|
-
resolveMostRecentRoutableSessionKey(sessionManager) {
|
|
10091
|
-
const sessions = sessionManager.listSessions();
|
|
10651
|
+
};
|
|
10652
|
+
resolveMostRecentRoutableSessionKey = (sessionManager) => {
|
|
10092
10653
|
let best = null;
|
|
10093
|
-
for (const session of
|
|
10094
|
-
const
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
}
|
|
10098
|
-
|
|
10099
|
-
const metadata = metadataRaw && typeof metadataRaw === "object" && !Array.isArray(metadataRaw) ? metadataRaw : {};
|
|
10100
|
-
const contextRaw = metadata.last_delivery_context;
|
|
10101
|
-
const context = contextRaw && typeof contextRaw === "object" && !Array.isArray(contextRaw) ? contextRaw : {};
|
|
10102
|
-
const hasRoute = Boolean(this.normalizeOptionalString(context.channel)) && Boolean(this.normalizeOptionalString(context.chatId));
|
|
10103
|
-
const hasFallbackRoute = Boolean(this.normalizeOptionalString(metadata.last_channel)) && Boolean(this.normalizeOptionalString(metadata.last_to));
|
|
10104
|
-
if (!hasRoute && !hasFallbackRoute) {
|
|
10654
|
+
for (const session of sessionManager.listSessions()) {
|
|
10655
|
+
const candidate = resolveSessionRouteCandidate({
|
|
10656
|
+
session,
|
|
10657
|
+
normalizeOptionalString: (value) => this.normalizeOptionalString(value)
|
|
10658
|
+
});
|
|
10659
|
+
if (!candidate) {
|
|
10105
10660
|
continue;
|
|
10106
10661
|
}
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
const score = Number.isFinite(updatedAt) ? updatedAt : 0;
|
|
10110
|
-
if (!best || score >= best.updatedAt) {
|
|
10111
|
-
best = { key, updatedAt: score };
|
|
10662
|
+
if (!best || candidate.updatedAt >= best.updatedAt) {
|
|
10663
|
+
best = candidate;
|
|
10112
10664
|
}
|
|
10113
10665
|
}
|
|
10114
10666
|
return best?.key;
|
|
10115
|
-
}
|
|
10116
|
-
buildRestartWakePrompt(params) {
|
|
10667
|
+
};
|
|
10668
|
+
buildRestartWakePrompt = (params) => {
|
|
10117
10669
|
const lines = [
|
|
10118
10670
|
"System event: the gateway has restarted successfully.",
|
|
10119
10671
|
"Please send one short confirmation to the user that you are back online.",
|
|
@@ -10134,13 +10686,13 @@ var ServiceCommands = class {
|
|
|
10134
10686
|
lines.push(`Reply target message id: ${replyTo}. If suitable, include [[reply_to:${replyTo}]].`);
|
|
10135
10687
|
}
|
|
10136
10688
|
return lines.join("\n");
|
|
10137
|
-
}
|
|
10138
|
-
async
|
|
10689
|
+
};
|
|
10690
|
+
wakeFromRestartSentinel = async (params) => {
|
|
10139
10691
|
const sentinel = await consumeRestartSentinel();
|
|
10140
10692
|
if (!sentinel) {
|
|
10141
10693
|
return;
|
|
10142
10694
|
}
|
|
10143
|
-
await new Promise((
|
|
10695
|
+
await new Promise((resolve17) => setTimeout(resolve17, 750));
|
|
10144
10696
|
const payload = sentinel.payload;
|
|
10145
10697
|
const summary = formatRestartSentinelMessage(payload);
|
|
10146
10698
|
const sentinelSessionKey = this.normalizeOptionalString(payload.sessionKey);
|
|
@@ -10184,9 +10736,9 @@ var ServiceCommands = class {
|
|
|
10184
10736
|
attachments: [],
|
|
10185
10737
|
metadata
|
|
10186
10738
|
});
|
|
10187
|
-
}
|
|
10188
|
-
async
|
|
10189
|
-
const config2 =
|
|
10739
|
+
};
|
|
10740
|
+
runForeground = async (options) => {
|
|
10741
|
+
const config2 = loadConfig21();
|
|
10190
10742
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
10191
10743
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
10192
10744
|
if (options.open) {
|
|
@@ -10197,48 +10749,39 @@ var ServiceCommands = class {
|
|
|
10197
10749
|
allowMissingProvider: true,
|
|
10198
10750
|
uiStaticDir: resolveUiStaticDir()
|
|
10199
10751
|
});
|
|
10200
|
-
}
|
|
10201
|
-
async
|
|
10202
|
-
|
|
10752
|
+
};
|
|
10753
|
+
handleExistingManagedService = async (params) => {
|
|
10754
|
+
console.log(`\u2713 ${APP_NAME3} is already running (PID ${params.existing.pid})`);
|
|
10755
|
+
console.log(`UI: ${params.existing.uiUrl}`);
|
|
10756
|
+
console.log(`API: ${params.existing.apiUrl}`);
|
|
10757
|
+
const binding = resolveManagedServiceUiBinding(params.existing);
|
|
10758
|
+
if (binding.host !== params.uiConfig.host || binding.port !== params.uiConfig.port) {
|
|
10759
|
+
console.log(
|
|
10760
|
+
`Detected running service UI bind (${binding.host}:${binding.port}); enforcing (${params.uiConfig.host}:${params.uiConfig.port})...`
|
|
10761
|
+
);
|
|
10762
|
+
await this.stopService();
|
|
10763
|
+
const stateAfterStop = readServiceState();
|
|
10764
|
+
if (stateAfterStop && isProcessRunning(stateAfterStop.pid)) {
|
|
10765
|
+
console.error("Error: Failed to stop running service while enforcing public UI exposure.");
|
|
10766
|
+
return true;
|
|
10767
|
+
}
|
|
10768
|
+
await this.startService(params.options);
|
|
10769
|
+
return true;
|
|
10770
|
+
}
|
|
10771
|
+
await this.printPublicUiUrls(binding.host, binding.port);
|
|
10772
|
+
console.log(`Logs: ${params.existing.logPath}`);
|
|
10773
|
+
this.printServiceControlHints();
|
|
10774
|
+
return true;
|
|
10775
|
+
};
|
|
10776
|
+
startService = async (options) => {
|
|
10777
|
+
const config2 = loadConfig21();
|
|
10203
10778
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
10204
10779
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
10205
10780
|
const apiUrl = `${uiUrl}/api`;
|
|
10206
10781
|
const staticDir = resolveUiStaticDir();
|
|
10207
10782
|
const existing = readServiceState();
|
|
10208
10783
|
if (existing && isProcessRunning(existing.pid)) {
|
|
10209
|
-
|
|
10210
|
-
console.log(`UI: ${existing.uiUrl}`);
|
|
10211
|
-
console.log(`API: ${existing.apiUrl}`);
|
|
10212
|
-
const parsedUi = (() => {
|
|
10213
|
-
try {
|
|
10214
|
-
const parsed = new URL(existing.uiUrl);
|
|
10215
|
-
const port = Number(parsed.port || 80);
|
|
10216
|
-
return {
|
|
10217
|
-
host: existing.uiHost ?? parsed.hostname,
|
|
10218
|
-
port: Number.isFinite(port) ? port : existing.uiPort ?? 55667
|
|
10219
|
-
};
|
|
10220
|
-
} catch {
|
|
10221
|
-
return {
|
|
10222
|
-
host: existing.uiHost ?? "127.0.0.1",
|
|
10223
|
-
port: existing.uiPort ?? 55667
|
|
10224
|
-
};
|
|
10225
|
-
}
|
|
10226
|
-
})();
|
|
10227
|
-
if (parsedUi.host !== uiConfig.host || parsedUi.port !== uiConfig.port) {
|
|
10228
|
-
console.log(
|
|
10229
|
-
`Detected running service UI bind (${parsedUi.host}:${parsedUi.port}); enforcing (${uiConfig.host}:${uiConfig.port})...`
|
|
10230
|
-
);
|
|
10231
|
-
await this.stopService();
|
|
10232
|
-
const stateAfterStop = readServiceState();
|
|
10233
|
-
if (stateAfterStop && isProcessRunning(stateAfterStop.pid)) {
|
|
10234
|
-
console.error("Error: Failed to stop running service while enforcing public UI exposure.");
|
|
10235
|
-
return;
|
|
10236
|
-
}
|
|
10237
|
-
return this.startService(options);
|
|
10238
|
-
}
|
|
10239
|
-
await this.printPublicUiUrls(parsedUi.host, parsedUi.port);
|
|
10240
|
-
console.log(`Logs: ${existing.logPath}`);
|
|
10241
|
-
this.printServiceControlHints();
|
|
10784
|
+
await this.handleExistingManagedService({ existing, uiConfig, options });
|
|
10242
10785
|
return;
|
|
10243
10786
|
}
|
|
10244
10787
|
if (existing) {
|
|
@@ -10258,109 +10801,72 @@ var ServiceCommands = class {
|
|
|
10258
10801
|
console.error(portPreflight.message);
|
|
10259
10802
|
return;
|
|
10260
10803
|
}
|
|
10261
|
-
const
|
|
10262
|
-
|
|
10263
|
-
mkdirSync5(logDir, { recursive: true });
|
|
10264
|
-
const logFd = openSync2(logPath, "a");
|
|
10265
|
-
const readinessTimeoutMs = this.resolveStartupTimeoutMs(options.startupTimeoutMs);
|
|
10266
|
-
const quickPhaseTimeoutMs = Math.min(8e3, readinessTimeoutMs);
|
|
10267
|
-
const extendedPhaseTimeoutMs = Math.max(0, readinessTimeoutMs - quickPhaseTimeoutMs);
|
|
10268
|
-
this.appendStartupStage(
|
|
10269
|
-
logPath,
|
|
10270
|
-
`start requested: ui=${uiConfig.host}:${uiConfig.port}, readinessTimeoutMs=${readinessTimeoutMs}`
|
|
10271
|
-
);
|
|
10272
|
-
console.log(`Starting ${APP_NAME3} background service (readiness timeout ${Math.ceil(readinessTimeoutMs / 1e3)}s)...`);
|
|
10273
|
-
const serveArgs = buildServeArgs({ uiPort: uiConfig.port });
|
|
10274
|
-
this.appendStartupStage(logPath, `spawning background process: ${process.execPath} ${[...process.execArgv, ...serveArgs].join(" ")}`);
|
|
10275
|
-
const child = spawn3(process.execPath, [...process.execArgv, ...serveArgs], {
|
|
10276
|
-
env: process.env,
|
|
10277
|
-
stdio: ["ignore", logFd, logFd],
|
|
10278
|
-
detached: true
|
|
10279
|
-
});
|
|
10280
|
-
this.appendStartupStage(logPath, `spawned background process pid=${child.pid ?? "unknown"}`);
|
|
10281
|
-
closeSync2(logFd);
|
|
10282
|
-
if (!child.pid) {
|
|
10283
|
-
this.appendStartupStage(logPath, "spawn failed: child pid missing");
|
|
10284
|
-
console.error("Error: Failed to start background service.");
|
|
10285
|
-
this.printStartupFailureDiagnostics({
|
|
10286
|
-
uiUrl,
|
|
10287
|
-
apiUrl,
|
|
10288
|
-
healthUrl,
|
|
10289
|
-
logPath,
|
|
10290
|
-
lastProbeError: null
|
|
10291
|
-
});
|
|
10292
|
-
return;
|
|
10293
|
-
}
|
|
10294
|
-
writeInitialManagedServiceState({
|
|
10804
|
+
const startup = spawnManagedService({
|
|
10805
|
+
appName: APP_NAME3,
|
|
10295
10806
|
config: config2,
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
this.appendStartupStage(logPath, `health probe started: ${healthUrl} (phase=quick, timeoutMs=${quickPhaseTimeoutMs})`);
|
|
10300
|
-
let readiness = await this.waitForBackgroundServiceReady({
|
|
10301
|
-
pid: child.pid,
|
|
10807
|
+
uiConfig,
|
|
10808
|
+
uiUrl,
|
|
10809
|
+
apiUrl,
|
|
10302
10810
|
healthUrl,
|
|
10303
|
-
|
|
10811
|
+
startupTimeoutMs: options.startupTimeoutMs,
|
|
10812
|
+
resolveStartupTimeoutMs: this.resolveStartupTimeoutMs,
|
|
10813
|
+
appendStartupStage: this.appendStartupStage,
|
|
10814
|
+
printStartupFailureDiagnostics: this.printStartupFailureDiagnostics,
|
|
10815
|
+
resolveServiceLogPath
|
|
10304
10816
|
});
|
|
10305
|
-
if (!
|
|
10306
|
-
|
|
10307
|
-
`Warning: Background service is still running but not ready after ${Math.ceil(quickPhaseTimeoutMs / 1e3)}s; waiting up to ${Math.ceil(extendedPhaseTimeoutMs / 1e3)}s more.`
|
|
10308
|
-
);
|
|
10309
|
-
this.appendStartupStage(
|
|
10310
|
-
logPath,
|
|
10311
|
-
`health probe entering extended phase (timeoutMs=${extendedPhaseTimeoutMs}, lastError=${readiness.lastProbeError ?? "none"})`
|
|
10312
|
-
);
|
|
10313
|
-
readiness = await this.waitForBackgroundServiceReady({
|
|
10314
|
-
pid: child.pid,
|
|
10315
|
-
healthUrl,
|
|
10316
|
-
timeoutMs: extendedPhaseTimeoutMs
|
|
10317
|
-
});
|
|
10817
|
+
if (!startup) {
|
|
10818
|
+
return;
|
|
10318
10819
|
}
|
|
10820
|
+
const readiness = await waitForManagedServiceReadiness({
|
|
10821
|
+
appName: APP_NAME3,
|
|
10822
|
+
childPid: startup.snapshot.pid,
|
|
10823
|
+
healthUrl,
|
|
10824
|
+
logPath: startup.logPath,
|
|
10825
|
+
readinessTimeoutMs: startup.readinessTimeoutMs,
|
|
10826
|
+
quickPhaseTimeoutMs: startup.quickPhaseTimeoutMs,
|
|
10827
|
+
extendedPhaseTimeoutMs: startup.extendedPhaseTimeoutMs,
|
|
10828
|
+
appendStartupStage: this.appendStartupStage,
|
|
10829
|
+
waitForBackgroundServiceReady: this.waitForBackgroundServiceReady,
|
|
10830
|
+
isProcessRunning
|
|
10831
|
+
});
|
|
10319
10832
|
if (!readiness.ready) {
|
|
10320
|
-
if (!isProcessRunning(
|
|
10833
|
+
if (!isProcessRunning(startup.snapshot.pid)) {
|
|
10321
10834
|
clearServiceState();
|
|
10322
10835
|
const hint = readiness.lastProbeError ? ` Last probe error: ${readiness.lastProbeError}` : "";
|
|
10323
|
-
this.appendStartupStage(logPath, `startup failed: process exited before ready.${hint}`);
|
|
10324
|
-
console.error(`Error: Failed to start background service. Check logs: ${logPath}.${hint}`);
|
|
10836
|
+
this.appendStartupStage(startup.logPath, `startup failed: process exited before ready.${hint}`);
|
|
10837
|
+
console.error(`Error: Failed to start background service. Check logs: ${startup.logPath}.${hint}`);
|
|
10325
10838
|
this.printStartupFailureDiagnostics({
|
|
10326
10839
|
uiUrl,
|
|
10327
10840
|
apiUrl,
|
|
10328
10841
|
healthUrl,
|
|
10329
|
-
logPath,
|
|
10842
|
+
logPath: startup.logPath,
|
|
10330
10843
|
lastProbeError: readiness.lastProbeError
|
|
10331
10844
|
});
|
|
10332
10845
|
return;
|
|
10333
10846
|
}
|
|
10334
|
-
this.appendStartupStage(
|
|
10335
|
-
logPath,
|
|
10336
|
-
`startup degraded: process alive but health probe timed out after ${readinessTimeoutMs}ms (lastError=${readiness.lastProbeError ?? "none"})`
|
|
10337
|
-
);
|
|
10338
10847
|
}
|
|
10339
|
-
child.unref();
|
|
10848
|
+
startup.child.unref();
|
|
10340
10849
|
const state = writeReadyManagedServiceState({
|
|
10341
|
-
readinessTimeoutMs,
|
|
10850
|
+
readinessTimeoutMs: startup.readinessTimeoutMs,
|
|
10342
10851
|
readiness,
|
|
10343
|
-
snapshot:
|
|
10852
|
+
snapshot: startup.snapshot
|
|
10853
|
+
});
|
|
10854
|
+
await reportManagedServiceStart({
|
|
10855
|
+
appName: APP_NAME3,
|
|
10856
|
+
state,
|
|
10857
|
+
uiConfig,
|
|
10858
|
+
uiUrl,
|
|
10859
|
+
apiUrl,
|
|
10860
|
+
readinessTimeoutMs: startup.readinessTimeoutMs,
|
|
10861
|
+
readiness,
|
|
10862
|
+
printPublicUiUrls: this.printPublicUiUrls,
|
|
10863
|
+
printServiceControlHints: this.printServiceControlHints
|
|
10344
10864
|
});
|
|
10345
|
-
if (!readiness.ready) {
|
|
10346
|
-
const hint = readiness.lastProbeError ? ` Last probe error: ${readiness.lastProbeError}` : "";
|
|
10347
|
-
console.warn(
|
|
10348
|
-
`Warning: ${APP_NAME3} is running (PID ${state.pid}) but not healthy yet after ${Math.ceil(readinessTimeoutMs / 1e3)}s. Marked as degraded.${hint}`
|
|
10349
|
-
);
|
|
10350
|
-
console.warn(`Tip: Run "${APP_NAME3} status --json" and check logs: ${logPath}`);
|
|
10351
|
-
} else {
|
|
10352
|
-
console.log(`\u2713 ${APP_NAME3} started in background (PID ${state.pid})`);
|
|
10353
|
-
}
|
|
10354
|
-
console.log(`UI: ${uiUrl}`);
|
|
10355
|
-
console.log(`API: ${apiUrl}`);
|
|
10356
|
-
await this.printPublicUiUrls(uiConfig.host, uiConfig.port);
|
|
10357
|
-
console.log(`Logs: ${logPath}`);
|
|
10358
|
-
this.printServiceControlHints();
|
|
10359
10865
|
if (options.open) {
|
|
10360
10866
|
openBrowser(uiUrl);
|
|
10361
10867
|
}
|
|
10362
|
-
}
|
|
10363
|
-
async
|
|
10868
|
+
};
|
|
10869
|
+
stopService = async () => {
|
|
10364
10870
|
const state = readServiceState();
|
|
10365
10871
|
if (!state) {
|
|
10366
10872
|
console.log("No running service found.");
|
|
@@ -10390,8 +10896,8 @@ var ServiceCommands = class {
|
|
|
10390
10896
|
}
|
|
10391
10897
|
clearServiceState();
|
|
10392
10898
|
console.log(`\u2713 ${APP_NAME3} stopped`);
|
|
10393
|
-
}
|
|
10394
|
-
async
|
|
10899
|
+
};
|
|
10900
|
+
waitForBackgroundServiceReady = async (params) => {
|
|
10395
10901
|
const startedAt = Date.now();
|
|
10396
10902
|
let lastProbeError = null;
|
|
10397
10903
|
while (Date.now() - startedAt < params.timeoutMs) {
|
|
@@ -10401,18 +10907,18 @@ var ServiceCommands = class {
|
|
|
10401
10907
|
const probe = await this.probeHealthEndpoint(params.healthUrl);
|
|
10402
10908
|
if (!probe.healthy) {
|
|
10403
10909
|
lastProbeError = probe.error;
|
|
10404
|
-
await new Promise((
|
|
10910
|
+
await new Promise((resolve17) => setTimeout(resolve17, 200));
|
|
10405
10911
|
continue;
|
|
10406
10912
|
}
|
|
10407
|
-
await new Promise((
|
|
10913
|
+
await new Promise((resolve17) => setTimeout(resolve17, 300));
|
|
10408
10914
|
if (isProcessRunning(params.pid)) {
|
|
10409
10915
|
return { ready: true, lastProbeError: null };
|
|
10410
10916
|
}
|
|
10411
|
-
await new Promise((
|
|
10917
|
+
await new Promise((resolve17) => setTimeout(resolve17, 200));
|
|
10412
10918
|
}
|
|
10413
10919
|
return { ready: false, lastProbeError };
|
|
10414
|
-
}
|
|
10415
|
-
resolveStartupTimeoutMs(overrideTimeoutMs) {
|
|
10920
|
+
};
|
|
10921
|
+
resolveStartupTimeoutMs = (overrideTimeoutMs) => {
|
|
10416
10922
|
const fallback = process.platform === "win32" ? 28e3 : 33e3;
|
|
10417
10923
|
const envRaw = process.env.NEXTCLAW_START_TIMEOUT_MS?.trim();
|
|
10418
10924
|
const envValue = envRaw ? Number(envRaw) : Number.NaN;
|
|
@@ -10420,8 +10926,8 @@ var ServiceCommands = class {
|
|
|
10420
10926
|
const fromOverride = Number.isFinite(overrideTimeoutMs) && Number(overrideTimeoutMs) > 0 ? Math.floor(Number(overrideTimeoutMs)) : null;
|
|
10421
10927
|
const resolved = fromOverride ?? fromEnv ?? fallback;
|
|
10422
10928
|
return Math.max(3e3, resolved);
|
|
10423
|
-
}
|
|
10424
|
-
appendStartupStage(logPath, message) {
|
|
10929
|
+
};
|
|
10930
|
+
appendStartupStage = (logPath, message) => {
|
|
10425
10931
|
try {
|
|
10426
10932
|
appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [startup] ${message}
|
|
10427
10933
|
`, "utf-8");
|
|
@@ -10429,8 +10935,8 @@ var ServiceCommands = class {
|
|
|
10429
10935
|
const detail = error instanceof Error ? error.message : String(error);
|
|
10430
10936
|
console.error(`Warning: failed to write startup diagnostics log (${logPath}): ${detail}`);
|
|
10431
10937
|
}
|
|
10432
|
-
}
|
|
10433
|
-
printStartupFailureDiagnostics(params) {
|
|
10938
|
+
};
|
|
10939
|
+
printStartupFailureDiagnostics = (params) => {
|
|
10434
10940
|
const statePath = resolveServiceStatePath();
|
|
10435
10941
|
const lines = [
|
|
10436
10942
|
"Startup diagnostics:",
|
|
@@ -10444,8 +10950,8 @@ var ServiceCommands = class {
|
|
|
10444
10950
|
lines.push(`- Last probe detail: ${params.lastProbeError}`);
|
|
10445
10951
|
}
|
|
10446
10952
|
console.error(lines.join("\n"));
|
|
10447
|
-
}
|
|
10448
|
-
async
|
|
10953
|
+
};
|
|
10954
|
+
checkUiPortPreflight = async (params) => {
|
|
10449
10955
|
const availability = await this.checkPortAvailability({
|
|
10450
10956
|
host: params.host,
|
|
10451
10957
|
port: params.port
|
|
@@ -10477,27 +10983,27 @@ var ServiceCommands = class {
|
|
|
10477
10983
|
ok: false,
|
|
10478
10984
|
message: lines.join("\n")
|
|
10479
10985
|
};
|
|
10480
|
-
}
|
|
10481
|
-
async
|
|
10482
|
-
return await new Promise((
|
|
10986
|
+
};
|
|
10987
|
+
checkPortAvailability = async (params) => {
|
|
10988
|
+
return await new Promise((resolve17) => {
|
|
10483
10989
|
const server = createNetServer2();
|
|
10484
10990
|
server.once("error", (error) => {
|
|
10485
|
-
|
|
10991
|
+
resolve17({
|
|
10486
10992
|
available: false,
|
|
10487
10993
|
detail: `bind failed on ${params.host}:${params.port} (${String(error)})`
|
|
10488
10994
|
});
|
|
10489
10995
|
});
|
|
10490
10996
|
server.listen(params.port, params.host, () => {
|
|
10491
10997
|
server.close(() => {
|
|
10492
|
-
|
|
10998
|
+
resolve17({
|
|
10493
10999
|
available: true,
|
|
10494
11000
|
detail: `bind ok on ${params.host}:${params.port}`
|
|
10495
11001
|
});
|
|
10496
11002
|
});
|
|
10497
11003
|
});
|
|
10498
11004
|
});
|
|
10499
|
-
}
|
|
10500
|
-
getHeaderValue(headers, key) {
|
|
11005
|
+
};
|
|
11006
|
+
getHeaderValue = (headers, key) => {
|
|
10501
11007
|
const value = headers[key];
|
|
10502
11008
|
if (typeof value === "string") {
|
|
10503
11009
|
const normalized = value.trim();
|
|
@@ -10508,16 +11014,16 @@ var ServiceCommands = class {
|
|
|
10508
11014
|
return joined.length > 0 ? joined : null;
|
|
10509
11015
|
}
|
|
10510
11016
|
return null;
|
|
10511
|
-
}
|
|
10512
|
-
formatProbeBodySnippet(raw, maxLength = 180) {
|
|
11017
|
+
};
|
|
11018
|
+
formatProbeBodySnippet = (raw, maxLength = 180) => {
|
|
10513
11019
|
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
10514
11020
|
if (!normalized) {
|
|
10515
11021
|
return null;
|
|
10516
11022
|
}
|
|
10517
11023
|
const clipped = normalized.length > maxLength ? `${normalized.slice(0, maxLength)}...` : normalized;
|
|
10518
11024
|
return JSON.stringify(clipped);
|
|
10519
|
-
}
|
|
10520
|
-
async
|
|
11025
|
+
};
|
|
11026
|
+
probeHealthEndpoint = async (healthUrl) => {
|
|
10521
11027
|
let parsed;
|
|
10522
11028
|
try {
|
|
10523
11029
|
parsed = new URL(healthUrl);
|
|
@@ -10525,7 +11031,7 @@ var ServiceCommands = class {
|
|
|
10525
11031
|
return { healthy: false, error: "invalid health URL" };
|
|
10526
11032
|
}
|
|
10527
11033
|
const requestImpl = parsed.protocol === "https:" ? httpsRequest : httpRequest;
|
|
10528
|
-
return new Promise((
|
|
11034
|
+
return new Promise((resolve17) => {
|
|
10529
11035
|
const req = requestImpl(
|
|
10530
11036
|
{
|
|
10531
11037
|
protocol: parsed.protocol,
|
|
@@ -10561,19 +11067,19 @@ var ServiceCommands = class {
|
|
|
10561
11067
|
if (bodySnippet) {
|
|
10562
11068
|
details.push(`body=${bodySnippet}`);
|
|
10563
11069
|
}
|
|
10564
|
-
|
|
11070
|
+
resolve17({ healthy: false, error: details.join("; ") });
|
|
10565
11071
|
return;
|
|
10566
11072
|
}
|
|
10567
11073
|
try {
|
|
10568
11074
|
const payload = JSON.parse(responseText);
|
|
10569
11075
|
const healthy = payload?.ok === true && payload?.data?.status === "ok";
|
|
10570
11076
|
if (!healthy) {
|
|
10571
|
-
|
|
11077
|
+
resolve17({ healthy: false, error: "health payload not ok" });
|
|
10572
11078
|
return;
|
|
10573
11079
|
}
|
|
10574
|
-
|
|
11080
|
+
resolve17({ healthy: true, error: null });
|
|
10575
11081
|
} catch {
|
|
10576
|
-
|
|
11082
|
+
resolve17({ healthy: false, error: "invalid health JSON response" });
|
|
10577
11083
|
}
|
|
10578
11084
|
});
|
|
10579
11085
|
}
|
|
@@ -10582,24 +11088,24 @@ var ServiceCommands = class {
|
|
|
10582
11088
|
req.destroy(new Error("probe timeout"));
|
|
10583
11089
|
});
|
|
10584
11090
|
req.on("error", (error) => {
|
|
10585
|
-
|
|
11091
|
+
resolve17({ healthy: false, error: error.message || String(error) });
|
|
10586
11092
|
});
|
|
10587
11093
|
req.end();
|
|
10588
11094
|
});
|
|
10589
|
-
}
|
|
10590
|
-
createMissingProvider(config2) {
|
|
11095
|
+
};
|
|
11096
|
+
createMissingProvider = (config2) => {
|
|
10591
11097
|
return this.makeMissingProvider(config2);
|
|
10592
|
-
}
|
|
10593
|
-
createProvider(config2, options) {
|
|
11098
|
+
};
|
|
11099
|
+
createProvider = (config2, options) => {
|
|
10594
11100
|
if (options?.allowMissing) {
|
|
10595
11101
|
return this.makeProvider(config2, { allowMissing: true });
|
|
10596
11102
|
}
|
|
10597
11103
|
return this.makeProvider(config2);
|
|
10598
|
-
}
|
|
10599
|
-
makeMissingProvider(config2) {
|
|
11104
|
+
};
|
|
11105
|
+
makeMissingProvider = (config2) => {
|
|
10600
11106
|
return new MissingProvider(config2.agents.defaults.model);
|
|
10601
|
-
}
|
|
10602
|
-
makeProvider(config2, options) {
|
|
11107
|
+
};
|
|
11108
|
+
makeProvider = (config2, options) => {
|
|
10603
11109
|
const provider = getProvider(config2);
|
|
10604
11110
|
const model = config2.agents.defaults.model;
|
|
10605
11111
|
if (!provider?.apiKey && !model.startsWith("bedrock/")) {
|
|
@@ -10618,8 +11124,8 @@ var ServiceCommands = class {
|
|
|
10618
11124
|
providerName: getProviderName(config2),
|
|
10619
11125
|
wireApi: provider?.wireApi ?? null
|
|
10620
11126
|
});
|
|
10621
|
-
}
|
|
10622
|
-
async
|
|
11127
|
+
};
|
|
11128
|
+
printPublicUiUrls = async (host, port) => {
|
|
10623
11129
|
if (isLoopbackHost(host)) {
|
|
10624
11130
|
console.log("Public URL: disabled (UI host is loopback). Current release expects public exposure; run nextclaw restart.");
|
|
10625
11131
|
return;
|
|
@@ -10641,42 +11147,28 @@ var ServiceCommands = class {
|
|
|
10641
11147
|
console.log(
|
|
10642
11148
|
`If a reverse proxy returns 502, verify its upstream is http://127.0.0.1:${port} (not https://, not a stale port, and not a stopped process).`
|
|
10643
11149
|
);
|
|
10644
|
-
}
|
|
10645
|
-
printServiceControlHints() {
|
|
11150
|
+
};
|
|
11151
|
+
printServiceControlHints = () => {
|
|
10646
11152
|
console.log("Service controls:");
|
|
10647
11153
|
console.log(` - Check status: ${APP_NAME3} status`);
|
|
10648
11154
|
console.log(` - If you need to stop the service, run: ${APP_NAME3} stop`);
|
|
10649
|
-
}
|
|
10650
|
-
installBuiltinMarketplaceSkill(slug,
|
|
10651
|
-
const workspace =
|
|
10652
|
-
const destination = join7(workspace, "skills", slug);
|
|
10653
|
-
const destinationSkillFile = join7(destination, "SKILL.md");
|
|
10654
|
-
if (existsSync11(destinationSkillFile) && !force) {
|
|
10655
|
-
return {
|
|
10656
|
-
message: `${slug} is already installed`
|
|
10657
|
-
};
|
|
10658
|
-
}
|
|
11155
|
+
};
|
|
11156
|
+
installBuiltinMarketplaceSkill = (slug, _force) => {
|
|
11157
|
+
const workspace = getWorkspacePath13(loadConfig21().agents.defaults.workspace);
|
|
10659
11158
|
const loader = createSkillsLoader(workspace);
|
|
10660
11159
|
const builtin = (loader?.listSkills(false) ?? []).find((skill) => skill.name === slug && skill.source === "builtin");
|
|
10661
11160
|
if (!builtin) {
|
|
10662
|
-
if (existsSync11(destinationSkillFile)) {
|
|
10663
|
-
return {
|
|
10664
|
-
message: `${slug} is already installed`
|
|
10665
|
-
};
|
|
10666
|
-
}
|
|
10667
11161
|
return null;
|
|
10668
11162
|
}
|
|
10669
|
-
mkdirSync5(join7(workspace, "skills"), { recursive: true });
|
|
10670
|
-
cpSync2(dirname3(builtin.path), destination, { recursive: true, force: true });
|
|
10671
11163
|
return {
|
|
10672
|
-
message:
|
|
11164
|
+
message: `${slug} is already available (built-in)`
|
|
10673
11165
|
};
|
|
10674
|
-
}
|
|
10675
|
-
mergeCommandOutput(stdout, stderr) {
|
|
11166
|
+
};
|
|
11167
|
+
mergeCommandOutput = (stdout, stderr) => {
|
|
10676
11168
|
return `${stdout}
|
|
10677
11169
|
${stderr}`.trim();
|
|
10678
|
-
}
|
|
10679
|
-
runCliSubcommand(args, timeoutMs = 18e4) {
|
|
11170
|
+
};
|
|
11171
|
+
runCliSubcommand = (args, timeoutMs = 18e4) => {
|
|
10680
11172
|
const cliEntry = resolveCliSubcommandEntry({
|
|
10681
11173
|
argvEntry: process.argv[1],
|
|
10682
11174
|
importMetaUrl: import.meta.url
|
|
@@ -10685,11 +11177,11 @@ ${stderr}`.trim();
|
|
|
10685
11177
|
cwd: process.cwd(),
|
|
10686
11178
|
timeoutMs
|
|
10687
11179
|
}).then((result) => this.mergeCommandOutput(result.stdout, result.stderr));
|
|
10688
|
-
}
|
|
10689
|
-
runCommand(command, args, options = {}) {
|
|
11180
|
+
};
|
|
11181
|
+
runCommand = (command, args, options = {}) => {
|
|
10690
11182
|
const timeoutMs = options.timeoutMs ?? 18e4;
|
|
10691
11183
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
10692
|
-
const child =
|
|
11184
|
+
const child = spawn4(command, args, {
|
|
10693
11185
|
cwd: options.cwd ?? process.cwd(),
|
|
10694
11186
|
env: process.env,
|
|
10695
11187
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -10722,13 +11214,12 @@ ${stderr}`.trim();
|
|
|
10722
11214
|
rejectPromise(new Error(output || `command failed with code ${code ?? 1}`));
|
|
10723
11215
|
});
|
|
10724
11216
|
});
|
|
10725
|
-
}
|
|
11217
|
+
};
|
|
10726
11218
|
};
|
|
10727
11219
|
|
|
10728
11220
|
// src/cli/workspace.ts
|
|
10729
|
-
import { cpSync
|
|
10730
|
-
import {
|
|
10731
|
-
import { dirname as dirname4, join as join8, resolve as resolve14 } from "path";
|
|
11221
|
+
import { cpSync, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
11222
|
+
import { dirname as dirname3, join as join8, resolve as resolve15 } from "path";
|
|
10732
11223
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10733
11224
|
import { APP_NAME as APP_NAME4, getDataDir as getDataDir10 } from "@nextclaw/core";
|
|
10734
11225
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
@@ -10750,7 +11241,6 @@ var WorkspaceManager = class {
|
|
|
10750
11241
|
{ source: "USER.md", target: "USER.md" },
|
|
10751
11242
|
{ source: "IDENTITY.md", target: "IDENTITY.md" },
|
|
10752
11243
|
{ source: "TOOLS.md", target: "TOOLS.md" },
|
|
10753
|
-
{ source: "USAGE.md", target: "USAGE.md" },
|
|
10754
11244
|
{ source: "BOOT.md", target: "BOOT.md" },
|
|
10755
11245
|
{ source: "BOOTSTRAP.md", target: "BOOTSTRAP.md" },
|
|
10756
11246
|
{ source: "HEARTBEAT.md", target: "HEARTBEAT.md" },
|
|
@@ -10759,93 +11249,42 @@ var WorkspaceManager = class {
|
|
|
10759
11249
|
];
|
|
10760
11250
|
for (const entry of templateFiles) {
|
|
10761
11251
|
const filePath = join8(workspace, entry.target);
|
|
10762
|
-
if (!force &&
|
|
11252
|
+
if (!force && existsSync11(filePath)) {
|
|
10763
11253
|
continue;
|
|
10764
11254
|
}
|
|
10765
11255
|
const templatePath = join8(templateDir, entry.source);
|
|
10766
|
-
if (!
|
|
11256
|
+
if (!existsSync11(templatePath)) {
|
|
10767
11257
|
console.warn(`Warning: Template file missing: ${templatePath}`);
|
|
10768
11258
|
continue;
|
|
10769
11259
|
}
|
|
10770
11260
|
const raw = readFileSync9(templatePath, "utf-8");
|
|
10771
11261
|
const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME4);
|
|
10772
|
-
mkdirSync6(
|
|
11262
|
+
mkdirSync6(dirname3(filePath), { recursive: true });
|
|
10773
11263
|
writeFileSync5(filePath, content);
|
|
10774
11264
|
created.push(entry.target);
|
|
10775
11265
|
}
|
|
10776
11266
|
const memoryDir = join8(workspace, "memory");
|
|
10777
|
-
if (!
|
|
11267
|
+
if (!existsSync11(memoryDir)) {
|
|
10778
11268
|
mkdirSync6(memoryDir, { recursive: true });
|
|
10779
11269
|
created.push(join8("memory", ""));
|
|
10780
11270
|
}
|
|
10781
11271
|
const skillsDir = join8(workspace, "skills");
|
|
10782
|
-
if (!
|
|
11272
|
+
if (!existsSync11(skillsDir)) {
|
|
10783
11273
|
mkdirSync6(skillsDir, { recursive: true });
|
|
10784
11274
|
created.push(join8("skills", ""));
|
|
10785
11275
|
}
|
|
10786
|
-
const seeded = this.seedBuiltinSkills(skillsDir, { force });
|
|
10787
|
-
if (seeded > 0) {
|
|
10788
|
-
created.push(`skills (seeded ${seeded} built-ins)`);
|
|
10789
|
-
}
|
|
10790
11276
|
return { created };
|
|
10791
11277
|
}
|
|
10792
|
-
seedBuiltinSkills(targetDir, options = {}) {
|
|
10793
|
-
const sourceDir = this.resolveBuiltinSkillsDir();
|
|
10794
|
-
if (!sourceDir) {
|
|
10795
|
-
return 0;
|
|
10796
|
-
}
|
|
10797
|
-
const force = Boolean(options.force);
|
|
10798
|
-
let seeded = 0;
|
|
10799
|
-
for (const entry of readdirSync2(sourceDir, { withFileTypes: true })) {
|
|
10800
|
-
if (!entry.isDirectory()) {
|
|
10801
|
-
continue;
|
|
10802
|
-
}
|
|
10803
|
-
const src = join8(sourceDir, entry.name);
|
|
10804
|
-
if (!existsSync12(join8(src, "SKILL.md"))) {
|
|
10805
|
-
continue;
|
|
10806
|
-
}
|
|
10807
|
-
const dest = join8(targetDir, entry.name);
|
|
10808
|
-
if (!force && existsSync12(dest)) {
|
|
10809
|
-
continue;
|
|
10810
|
-
}
|
|
10811
|
-
try {
|
|
10812
|
-
cpSync3(src, dest, { recursive: true, force: true });
|
|
10813
|
-
seeded += 1;
|
|
10814
|
-
} catch (error) {
|
|
10815
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
10816
|
-
console.warn(`Warning: Failed to seed builtin skill '${entry.name}': ${message}`);
|
|
10817
|
-
}
|
|
10818
|
-
}
|
|
10819
|
-
return seeded;
|
|
10820
|
-
}
|
|
10821
|
-
resolveBuiltinSkillsDir() {
|
|
10822
|
-
try {
|
|
10823
|
-
const require3 = createRequire2(import.meta.url);
|
|
10824
|
-
const entry = require3.resolve("@nextclaw/core");
|
|
10825
|
-
const pkgRoot = resolve14(dirname4(entry), "..");
|
|
10826
|
-
const distSkills = join8(pkgRoot, "dist", "skills");
|
|
10827
|
-
if (existsSync12(distSkills)) {
|
|
10828
|
-
return distSkills;
|
|
10829
|
-
}
|
|
10830
|
-
const srcSkills = join8(pkgRoot, "src", "agent", "skills");
|
|
10831
|
-
if (existsSync12(srcSkills)) {
|
|
10832
|
-
return srcSkills;
|
|
10833
|
-
}
|
|
10834
|
-
return null;
|
|
10835
|
-
} catch {
|
|
10836
|
-
return null;
|
|
10837
|
-
}
|
|
10838
|
-
}
|
|
10839
11278
|
resolveTemplateDir() {
|
|
10840
11279
|
const override = process.env.NEXTCLAW_TEMPLATE_DIR?.trim();
|
|
10841
11280
|
if (override) {
|
|
10842
11281
|
return override;
|
|
10843
11282
|
}
|
|
10844
|
-
const cliDir =
|
|
10845
|
-
const pkgRoot =
|
|
11283
|
+
const cliDir = resolve15(fileURLToPath4(new URL(".", import.meta.url)));
|
|
11284
|
+
const pkgRoot = resolve15(cliDir, "..", "..");
|
|
10846
11285
|
const candidates = [join8(pkgRoot, "templates")];
|
|
10847
11286
|
for (const candidate of candidates) {
|
|
10848
|
-
if (
|
|
11287
|
+
if (existsSync11(candidate)) {
|
|
10849
11288
|
return candidate;
|
|
10850
11289
|
}
|
|
10851
11290
|
}
|
|
@@ -10853,21 +11292,21 @@ var WorkspaceManager = class {
|
|
|
10853
11292
|
}
|
|
10854
11293
|
getBridgeDir() {
|
|
10855
11294
|
const userBridge = join8(getDataDir10(), "bridge");
|
|
10856
|
-
if (
|
|
11295
|
+
if (existsSync11(join8(userBridge, "dist", "index.js"))) {
|
|
10857
11296
|
return userBridge;
|
|
10858
11297
|
}
|
|
10859
11298
|
if (!which("npm")) {
|
|
10860
11299
|
console.error("npm not found. Please install Node.js >= 18.");
|
|
10861
11300
|
process.exit(1);
|
|
10862
11301
|
}
|
|
10863
|
-
const cliDir =
|
|
10864
|
-
const pkgRoot =
|
|
11302
|
+
const cliDir = resolve15(fileURLToPath4(new URL(".", import.meta.url)));
|
|
11303
|
+
const pkgRoot = resolve15(cliDir, "..", "..");
|
|
10865
11304
|
const pkgBridge = join8(pkgRoot, "bridge");
|
|
10866
11305
|
const srcBridge = join8(pkgRoot, "..", "..", "bridge");
|
|
10867
11306
|
let source = null;
|
|
10868
|
-
if (
|
|
11307
|
+
if (existsSync11(join8(pkgBridge, "package.json"))) {
|
|
10869
11308
|
source = pkgBridge;
|
|
10870
|
-
} else if (
|
|
11309
|
+
} else if (existsSync11(join8(srcBridge, "package.json"))) {
|
|
10871
11310
|
source = srcBridge;
|
|
10872
11311
|
}
|
|
10873
11312
|
if (!source) {
|
|
@@ -10875,11 +11314,11 @@ var WorkspaceManager = class {
|
|
|
10875
11314
|
process.exit(1);
|
|
10876
11315
|
}
|
|
10877
11316
|
console.log(`${this.logo} Setting up bridge...`);
|
|
10878
|
-
mkdirSync6(
|
|
10879
|
-
if (
|
|
11317
|
+
mkdirSync6(resolve15(userBridge, ".."), { recursive: true });
|
|
11318
|
+
if (existsSync11(userBridge)) {
|
|
10880
11319
|
rmSync6(userBridge, { recursive: true, force: true });
|
|
10881
11320
|
}
|
|
10882
|
-
|
|
11321
|
+
cpSync(source, userBridge, {
|
|
10883
11322
|
recursive: true,
|
|
10884
11323
|
filter: (src) => !src.includes("node_modules") && !src.includes("dist")
|
|
10885
11324
|
});
|
|
@@ -10908,12 +11347,6 @@ var WorkspaceManager = class {
|
|
|
10908
11347
|
var LOGO = "\u{1F916}";
|
|
10909
11348
|
var EXIT_COMMANDS = /* @__PURE__ */ new Set(["exit", "quit", "/exit", "/quit", ":q"]);
|
|
10910
11349
|
var FORCED_PUBLIC_UI_HOST2 = "0.0.0.0";
|
|
10911
|
-
function resolveSkillsInstallWorkdir(params) {
|
|
10912
|
-
if (params.explicitWorkdir) {
|
|
10913
|
-
return expandHome2(params.explicitWorkdir);
|
|
10914
|
-
}
|
|
10915
|
-
return getWorkspacePath13(params.configuredWorkspace);
|
|
10916
|
-
}
|
|
10917
11350
|
var CliRuntime = class {
|
|
10918
11351
|
logo;
|
|
10919
11352
|
restartCoordinator;
|
|
@@ -10925,6 +11358,7 @@ var CliRuntime = class {
|
|
|
10925
11358
|
mcpCommands;
|
|
10926
11359
|
secretsCommands;
|
|
10927
11360
|
pluginCommands;
|
|
11361
|
+
agentCommands;
|
|
10928
11362
|
channelCommands;
|
|
10929
11363
|
cronCommands;
|
|
10930
11364
|
platformAuthCommands;
|
|
@@ -10936,7 +11370,8 @@ var CliRuntime = class {
|
|
|
10936
11370
|
this.logo = options.logo ?? LOGO;
|
|
10937
11371
|
this.workspaceManager = measureStartupSync("cli.runtime.workspace_manager", () => new WorkspaceManager(this.logo));
|
|
10938
11372
|
this.serviceCommands = measureStartupSync("cli.runtime.service_commands", () => new ServiceCommands({
|
|
10939
|
-
requestRestart: (params) => this.requestRestart(params)
|
|
11373
|
+
requestRestart: (params) => this.requestRestart(params),
|
|
11374
|
+
initializeAgentHomeDirectory: (homeDirectory) => this.workspaceManager.createWorkspaceTemplates(homeDirectory)
|
|
10940
11375
|
}));
|
|
10941
11376
|
this.configCommands = measureStartupSync("cli.runtime.config_commands", () => new ConfigCommands({
|
|
10942
11377
|
requestRestart: (params) => this.requestRestart(params)
|
|
@@ -10946,6 +11381,11 @@ var CliRuntime = class {
|
|
|
10946
11381
|
requestRestart: (params) => this.requestRestart(params)
|
|
10947
11382
|
}));
|
|
10948
11383
|
this.pluginCommands = measureStartupSync("cli.runtime.plugin_commands", () => new PluginCommands());
|
|
11384
|
+
this.agentCommands = measureStartupSync("cli.runtime.agent_commands", () => new AgentCommands({
|
|
11385
|
+
requestRestart: (params) => this.requestRestart(params),
|
|
11386
|
+
initializeAgentHomeDirectory: (homeDirectory) => this.workspaceManager.createWorkspaceTemplates(homeDirectory),
|
|
11387
|
+
appName: APP_NAME5
|
|
11388
|
+
}));
|
|
10949
11389
|
this.channelCommands = measureStartupSync("cli.runtime.channel_commands", () => new ChannelCommands({
|
|
10950
11390
|
logo: this.logo,
|
|
10951
11391
|
getBridgeDir: () => this.workspaceManager.getBridgeDir(),
|
|
@@ -10974,13 +11414,13 @@ var CliRuntime = class {
|
|
|
10974
11414
|
get version() {
|
|
10975
11415
|
return getPackageVersion();
|
|
10976
11416
|
}
|
|
10977
|
-
scheduleProcessExit(delayMs, reason) {
|
|
11417
|
+
scheduleProcessExit = (delayMs, reason) => {
|
|
10978
11418
|
console.warn(`Gateway restart requested (${reason}).`);
|
|
10979
11419
|
setTimeout(() => {
|
|
10980
11420
|
process.exit(0);
|
|
10981
11421
|
}, delayMs);
|
|
10982
|
-
}
|
|
10983
|
-
async
|
|
11422
|
+
};
|
|
11423
|
+
restartBackgroundService = async (reason) => {
|
|
10984
11424
|
if (this.serviceRestartTask) {
|
|
10985
11425
|
return this.serviceRestartTask;
|
|
10986
11426
|
}
|
|
@@ -11010,8 +11450,8 @@ var CliRuntime = class {
|
|
|
11010
11450
|
} finally {
|
|
11011
11451
|
this.serviceRestartTask = null;
|
|
11012
11452
|
}
|
|
11013
|
-
}
|
|
11014
|
-
armManagedServiceRelaunch(params) {
|
|
11453
|
+
};
|
|
11454
|
+
armManagedServiceRelaunch = (params) => {
|
|
11015
11455
|
const strategy = params.strategy ?? "background-service-or-manual";
|
|
11016
11456
|
if (strategy !== "background-service-or-exit" && strategy !== "exit-process") {
|
|
11017
11457
|
return;
|
|
@@ -11027,7 +11467,7 @@ var CliRuntime = class {
|
|
|
11027
11467
|
const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ? Math.max(0, Math.floor(params.delayMs)) : 100;
|
|
11028
11468
|
const cliPath = process.env.NEXTCLAW_SELF_RELAUNCH_CLI?.trim() || fileURLToPath5(new URL("./index.js", import.meta.url));
|
|
11029
11469
|
const startArgs = [cliPath, "start", "--ui-port", String(uiPort)];
|
|
11030
|
-
const serviceStatePath =
|
|
11470
|
+
const serviceStatePath = resolve16(getDataDir11(), "run", "service.json");
|
|
11031
11471
|
const helperScript = [
|
|
11032
11472
|
'const { spawnSync } = require("node:child_process");',
|
|
11033
11473
|
'const { readFileSync } = require("node:fs");',
|
|
@@ -11086,7 +11526,7 @@ var CliRuntime = class {
|
|
|
11086
11526
|
"}, delayMs);"
|
|
11087
11527
|
].join("\n");
|
|
11088
11528
|
try {
|
|
11089
|
-
const helper =
|
|
11529
|
+
const helper = spawn5(process.execPath, ["-e", helperScript], {
|
|
11090
11530
|
detached: true,
|
|
11091
11531
|
stdio: "ignore",
|
|
11092
11532
|
env: process.env
|
|
@@ -11097,8 +11537,8 @@ var CliRuntime = class {
|
|
|
11097
11537
|
} catch (error) {
|
|
11098
11538
|
console.error(`Failed to arm gateway self-restart: ${String(error)}`);
|
|
11099
11539
|
}
|
|
11100
|
-
}
|
|
11101
|
-
async
|
|
11540
|
+
};
|
|
11541
|
+
requestRestart = async (params) => {
|
|
11102
11542
|
this.armManagedServiceRelaunch({
|
|
11103
11543
|
reason: params.reason,
|
|
11104
11544
|
strategy: params.strategy,
|
|
@@ -11121,8 +11561,8 @@ var CliRuntime = class {
|
|
|
11121
11561
|
return;
|
|
11122
11562
|
}
|
|
11123
11563
|
console.warn(result.message);
|
|
11124
|
-
}
|
|
11125
|
-
async
|
|
11564
|
+
};
|
|
11565
|
+
writeRestartSentinelFromExecContext = async (reason) => {
|
|
11126
11566
|
const sessionKeyRaw = process.env.NEXTCLAW_RUNTIME_SESSION_KEY;
|
|
11127
11567
|
const sessionKey = typeof sessionKeyRaw === "string" ? sessionKeyRaw.trim() : "";
|
|
11128
11568
|
if (!sessionKey) {
|
|
@@ -11144,23 +11584,23 @@ var CliRuntime = class {
|
|
|
11144
11584
|
`Warning: failed to write restart sentinel from exec context: ${String(error)}`
|
|
11145
11585
|
);
|
|
11146
11586
|
}
|
|
11147
|
-
}
|
|
11148
|
-
async
|
|
11587
|
+
};
|
|
11588
|
+
onboard = async () => {
|
|
11149
11589
|
console.warn(
|
|
11150
11590
|
`Warning: ${APP_NAME5} onboard is deprecated. Use "${APP_NAME5} init" instead.`
|
|
11151
11591
|
);
|
|
11152
11592
|
await this.init({ source: "onboard" });
|
|
11153
|
-
}
|
|
11154
|
-
async
|
|
11593
|
+
};
|
|
11594
|
+
init = async (options = {}) => {
|
|
11155
11595
|
const source = options.source ?? "init";
|
|
11156
11596
|
const prefix = options.auto ? "Auto init" : "Init";
|
|
11157
11597
|
const force = Boolean(options.force);
|
|
11158
11598
|
const configPath = getConfigPath11();
|
|
11159
11599
|
const createdConfig = initializeConfigIfMissing(configPath);
|
|
11160
|
-
const config2 =
|
|
11600
|
+
const config2 = loadConfig22();
|
|
11161
11601
|
const workspaceSetting = config2.agents.defaults.workspace;
|
|
11162
|
-
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join9(getDataDir11(), DEFAULT_WORKSPACE_DIR) :
|
|
11163
|
-
const workspaceExisted =
|
|
11602
|
+
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join9(getDataDir11(), DEFAULT_WORKSPACE_DIR) : expandHome3(workspaceSetting);
|
|
11603
|
+
const workspaceExisted = existsSync12(workspacePath);
|
|
11164
11604
|
mkdirSync7(workspacePath, { recursive: true });
|
|
11165
11605
|
const templateResult = this.workspaceManager.createWorkspaceTemplates(
|
|
11166
11606
|
workspacePath,
|
|
@@ -11189,12 +11629,12 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11189
11629
|
`Tip: Run "${APP_NAME5} init${force ? " --force" : ""}" to re-run initialization if needed.`
|
|
11190
11630
|
);
|
|
11191
11631
|
}
|
|
11192
|
-
}
|
|
11193
|
-
async
|
|
11632
|
+
};
|
|
11633
|
+
login = async (opts = {}) => {
|
|
11194
11634
|
await this.init({ source: "login", auto: true });
|
|
11195
11635
|
await this.platformAuthCommands.login(opts);
|
|
11196
|
-
}
|
|
11197
|
-
async
|
|
11636
|
+
};
|
|
11637
|
+
gateway = async (opts) => {
|
|
11198
11638
|
const uiOverrides = {
|
|
11199
11639
|
host: FORCED_PUBLIC_UI_HOST2
|
|
11200
11640
|
};
|
|
@@ -11208,8 +11648,8 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11208
11648
|
uiOverrides.open = true;
|
|
11209
11649
|
}
|
|
11210
11650
|
await this.serviceCommands.startGateway({ uiOverrides });
|
|
11211
|
-
}
|
|
11212
|
-
async
|
|
11651
|
+
};
|
|
11652
|
+
ui = async (opts) => {
|
|
11213
11653
|
const uiOverrides = {
|
|
11214
11654
|
enabled: true,
|
|
11215
11655
|
host: FORCED_PUBLIC_UI_HOST2,
|
|
@@ -11222,9 +11662,9 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11222
11662
|
uiOverrides,
|
|
11223
11663
|
allowMissingProvider: true
|
|
11224
11664
|
});
|
|
11225
|
-
}
|
|
11226
|
-
async
|
|
11227
|
-
const startupTimeoutMs =
|
|
11665
|
+
};
|
|
11666
|
+
start = async (opts) => {
|
|
11667
|
+
const startupTimeoutMs = parseStartTimeoutMs(opts.startTimeout);
|
|
11228
11668
|
await this.init({ source: "start", auto: true });
|
|
11229
11669
|
const uiOverrides = {
|
|
11230
11670
|
enabled: true,
|
|
@@ -11239,8 +11679,8 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11239
11679
|
open: Boolean(opts.open),
|
|
11240
11680
|
startupTimeoutMs
|
|
11241
11681
|
});
|
|
11242
|
-
}
|
|
11243
|
-
async
|
|
11682
|
+
};
|
|
11683
|
+
restart = async (opts) => {
|
|
11244
11684
|
await this.writeRestartSentinelFromExecContext("cli.restart");
|
|
11245
11685
|
const state = readServiceState();
|
|
11246
11686
|
if (state && isProcessRunning(state.pid)) {
|
|
@@ -11253,8 +11693,8 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11253
11693
|
console.log("No running service found. Starting a new service.");
|
|
11254
11694
|
}
|
|
11255
11695
|
await this.start(opts);
|
|
11256
|
-
}
|
|
11257
|
-
async
|
|
11696
|
+
};
|
|
11697
|
+
serve = async (opts) => {
|
|
11258
11698
|
const uiOverrides = {
|
|
11259
11699
|
enabled: true,
|
|
11260
11700
|
host: FORCED_PUBLIC_UI_HOST2,
|
|
@@ -11267,32 +11707,21 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11267
11707
|
uiOverrides,
|
|
11268
11708
|
open: Boolean(opts.open)
|
|
11269
11709
|
});
|
|
11270
|
-
}
|
|
11271
|
-
|
|
11272
|
-
if (value === void 0) {
|
|
11273
|
-
return void 0;
|
|
11274
|
-
}
|
|
11275
|
-
const parsed = Number(value);
|
|
11276
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
11277
|
-
console.error("Invalid --start-timeout value. Provide milliseconds (e.g. 45000).");
|
|
11278
|
-
process.exit(1);
|
|
11279
|
-
}
|
|
11280
|
-
return Math.floor(parsed);
|
|
11281
|
-
}
|
|
11282
|
-
async stop() {
|
|
11710
|
+
};
|
|
11711
|
+
stop = async () => {
|
|
11283
11712
|
await this.serviceCommands.stopService();
|
|
11284
|
-
}
|
|
11285
|
-
async
|
|
11713
|
+
};
|
|
11714
|
+
agent = async (opts) => {
|
|
11286
11715
|
const configPath = getConfigPath11();
|
|
11287
|
-
const config2 = resolveConfigSecrets7(
|
|
11288
|
-
const workspace =
|
|
11716
|
+
const config2 = resolveConfigSecrets7(loadConfig22(), { configPath });
|
|
11717
|
+
const workspace = getWorkspacePath14(config2.agents.defaults.workspace);
|
|
11289
11718
|
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
11290
11719
|
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
11291
11720
|
logPluginDiagnostics(pluginRegistry);
|
|
11292
11721
|
const pluginChannelBindings = getPluginChannelBindings6(pluginRegistry);
|
|
11293
11722
|
setPluginRuntimeBridge3({
|
|
11294
11723
|
loadConfig: () => toPluginConfigView(
|
|
11295
|
-
resolveConfigSecrets7(
|
|
11724
|
+
resolveConfigSecrets7(loadConfig22(), { configPath }),
|
|
11296
11725
|
pluginChannelBindings
|
|
11297
11726
|
),
|
|
11298
11727
|
writeConfigFile: async (nextConfigView) => {
|
|
@@ -11301,7 +11730,7 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11301
11730
|
"plugin runtime writeConfigFile expects an object config"
|
|
11302
11731
|
);
|
|
11303
11732
|
}
|
|
11304
|
-
const current =
|
|
11733
|
+
const current = loadConfig22();
|
|
11305
11734
|
const next = mergePluginConfigView(
|
|
11306
11735
|
current,
|
|
11307
11736
|
nextConfigView,
|
|
@@ -11333,7 +11762,7 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11333
11762
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints3({
|
|
11334
11763
|
registry: pluginRegistry,
|
|
11335
11764
|
channel,
|
|
11336
|
-
cfg: resolveConfigSecrets7(
|
|
11765
|
+
cfg: resolveConfigSecrets7(loadConfig22(), { configPath }),
|
|
11337
11766
|
accountId
|
|
11338
11767
|
})
|
|
11339
11768
|
});
|
|
@@ -11353,9 +11782,9 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11353
11782
|
`
|
|
11354
11783
|
);
|
|
11355
11784
|
const historyFile = join9(getDataDir11(), "history", "cli_history");
|
|
11356
|
-
const historyDir =
|
|
11785
|
+
const historyDir = resolve16(historyFile, "..");
|
|
11357
11786
|
mkdirSync7(historyDir, { recursive: true });
|
|
11358
|
-
const history =
|
|
11787
|
+
const history = existsSync12(historyFile) ? readFileSync10(historyFile, "utf-8").split("\n").filter(Boolean) : [];
|
|
11359
11788
|
const rl = createInterface3({
|
|
11360
11789
|
input: process.stdin,
|
|
11361
11790
|
output: process.stdout
|
|
@@ -11389,8 +11818,8 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11389
11818
|
} finally {
|
|
11390
11819
|
setPluginRuntimeBridge3(null);
|
|
11391
11820
|
}
|
|
11392
|
-
}
|
|
11393
|
-
async
|
|
11821
|
+
};
|
|
11822
|
+
update = async (opts) => {
|
|
11394
11823
|
let timeoutMs;
|
|
11395
11824
|
if (opts.timeout !== void 0) {
|
|
11396
11825
|
const parsed = Number(opts.timeout);
|
|
@@ -11436,76 +11865,88 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11436
11865
|
if (state && isProcessRunning(state.pid)) {
|
|
11437
11866
|
console.log(`Tip: restart ${APP_NAME5} to apply the update.`);
|
|
11438
11867
|
}
|
|
11439
|
-
}
|
|
11440
|
-
|
|
11868
|
+
};
|
|
11869
|
+
agentsList = (opts = {}) => {
|
|
11870
|
+
this.agentCommands.agentsList(opts);
|
|
11871
|
+
};
|
|
11872
|
+
agentsNew = async (agentId, opts = {}) => {
|
|
11873
|
+
await this.agentCommands.agentsNew(agentId, opts);
|
|
11874
|
+
};
|
|
11875
|
+
agentsUpdate = async (agentId, opts = {}) => {
|
|
11876
|
+
await this.agentCommands.agentsUpdate(agentId, opts);
|
|
11877
|
+
};
|
|
11878
|
+
agentsRemove = async (agentId, opts = {}) => {
|
|
11879
|
+
await this.agentCommands.agentsRemove(agentId, opts);
|
|
11880
|
+
};
|
|
11881
|
+
pluginsList = (opts = {}) => {
|
|
11441
11882
|
this.pluginCommands.pluginsList(opts);
|
|
11442
|
-
}
|
|
11443
|
-
pluginsInfo(id, opts = {}) {
|
|
11883
|
+
};
|
|
11884
|
+
pluginsInfo = (id, opts = {}) => {
|
|
11444
11885
|
this.pluginCommands.pluginsInfo(id, opts);
|
|
11445
|
-
}
|
|
11446
|
-
async
|
|
11886
|
+
};
|
|
11887
|
+
pluginsEnable = async (id) => {
|
|
11447
11888
|
await this.pluginCommands.pluginsEnable(id);
|
|
11448
|
-
}
|
|
11449
|
-
async
|
|
11889
|
+
};
|
|
11890
|
+
pluginsDisable = async (id) => {
|
|
11450
11891
|
await this.pluginCommands.pluginsDisable(id);
|
|
11451
|
-
}
|
|
11452
|
-
async
|
|
11892
|
+
};
|
|
11893
|
+
pluginsUninstall = async (id, opts = {}) => {
|
|
11453
11894
|
await this.pluginCommands.pluginsUninstall(id, opts);
|
|
11454
|
-
}
|
|
11455
|
-
async
|
|
11895
|
+
};
|
|
11896
|
+
pluginsInstall = async (pathOrSpec, opts = {}) => {
|
|
11456
11897
|
await this.pluginCommands.pluginsInstall(pathOrSpec, opts);
|
|
11457
|
-
}
|
|
11458
|
-
pluginsDoctor() {
|
|
11898
|
+
};
|
|
11899
|
+
pluginsDoctor = () => {
|
|
11459
11900
|
this.pluginCommands.pluginsDoctor();
|
|
11460
|
-
}
|
|
11461
|
-
configGet(pathExpr, opts = {}) {
|
|
11901
|
+
};
|
|
11902
|
+
configGet = (pathExpr, opts = {}) => {
|
|
11462
11903
|
this.configCommands.configGet(pathExpr, opts);
|
|
11463
|
-
}
|
|
11464
|
-
async
|
|
11904
|
+
};
|
|
11905
|
+
configSet = async (pathExpr, value, opts = {}) => {
|
|
11465
11906
|
await this.configCommands.configSet(pathExpr, value, opts);
|
|
11466
|
-
}
|
|
11467
|
-
async
|
|
11907
|
+
};
|
|
11908
|
+
configUnset = async (pathExpr) => {
|
|
11468
11909
|
await this.configCommands.configUnset(pathExpr);
|
|
11469
|
-
}
|
|
11470
|
-
mcpList(opts = {}) {
|
|
11910
|
+
};
|
|
11911
|
+
mcpList = (opts = {}) => {
|
|
11471
11912
|
this.mcpCommands.mcpList(opts);
|
|
11472
|
-
}
|
|
11473
|
-
async
|
|
11913
|
+
};
|
|
11914
|
+
mcpAdd = async (name, command, opts = {}) => {
|
|
11474
11915
|
await this.mcpCommands.mcpAdd(name, command, opts);
|
|
11475
|
-
}
|
|
11476
|
-
async
|
|
11916
|
+
};
|
|
11917
|
+
mcpRemove = async (name) => {
|
|
11477
11918
|
await this.mcpCommands.mcpRemove(name);
|
|
11478
|
-
}
|
|
11479
|
-
async
|
|
11919
|
+
};
|
|
11920
|
+
mcpEnable = async (name) => {
|
|
11480
11921
|
await this.mcpCommands.mcpEnable(name);
|
|
11481
|
-
}
|
|
11482
|
-
async
|
|
11922
|
+
};
|
|
11923
|
+
mcpDisable = async (name) => {
|
|
11483
11924
|
await this.mcpCommands.mcpDisable(name);
|
|
11484
|
-
}
|
|
11485
|
-
async
|
|
11925
|
+
};
|
|
11926
|
+
mcpDoctor = async (name, opts = {}) => {
|
|
11486
11927
|
await this.mcpCommands.mcpDoctor(name, opts);
|
|
11487
|
-
}
|
|
11488
|
-
secretsAudit(opts = {}) {
|
|
11928
|
+
};
|
|
11929
|
+
secretsAudit = (opts = {}) => {
|
|
11489
11930
|
this.secretsCommands.secretsAudit(opts);
|
|
11490
|
-
}
|
|
11491
|
-
async
|
|
11931
|
+
};
|
|
11932
|
+
secretsConfigure = async (opts) => {
|
|
11492
11933
|
await this.secretsCommands.secretsConfigure(opts);
|
|
11493
|
-
}
|
|
11494
|
-
async
|
|
11934
|
+
};
|
|
11935
|
+
secretsApply = async (opts) => {
|
|
11495
11936
|
await this.secretsCommands.secretsApply(opts);
|
|
11496
|
-
}
|
|
11497
|
-
async
|
|
11937
|
+
};
|
|
11938
|
+
secretsReload = async (opts = {}) => {
|
|
11498
11939
|
await this.secretsCommands.secretsReload(opts);
|
|
11499
|
-
}
|
|
11500
|
-
channelsStatus() {
|
|
11940
|
+
};
|
|
11941
|
+
channelsStatus = () => {
|
|
11501
11942
|
this.channelCommands.channelsStatus();
|
|
11502
|
-
}
|
|
11503
|
-
async
|
|
11943
|
+
};
|
|
11944
|
+
channelsLogin = async (opts) => {
|
|
11504
11945
|
await this.channelCommands.channelsLogin(opts);
|
|
11505
|
-
}
|
|
11506
|
-
async
|
|
11946
|
+
};
|
|
11947
|
+
channelsAdd = async (opts) => {
|
|
11507
11948
|
await this.channelCommands.channelsAdd(opts);
|
|
11508
|
-
}
|
|
11949
|
+
};
|
|
11509
11950
|
cronList = async (opts) => {
|
|
11510
11951
|
await this.cronCommands.cronList(opts);
|
|
11511
11952
|
};
|
|
@@ -11521,14 +11962,14 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11521
11962
|
cronRun = async (jobId, opts) => {
|
|
11522
11963
|
await this.cronCommands.cronRun(jobId, opts);
|
|
11523
11964
|
};
|
|
11524
|
-
async
|
|
11965
|
+
status = async (opts = {}) => {
|
|
11525
11966
|
await this.diagnosticsCommands.status(opts);
|
|
11526
|
-
}
|
|
11527
|
-
async
|
|
11967
|
+
};
|
|
11968
|
+
doctor = async (opts = {}) => {
|
|
11528
11969
|
await this.diagnosticsCommands.doctor(opts);
|
|
11529
|
-
}
|
|
11530
|
-
async
|
|
11531
|
-
const config2 =
|
|
11970
|
+
};
|
|
11971
|
+
skillsInstall = async (options) => {
|
|
11972
|
+
const config2 = loadConfig22();
|
|
11532
11973
|
const workdir = resolveSkillsInstallWorkdir({
|
|
11533
11974
|
explicitWorkdir: options.workdir,
|
|
11534
11975
|
configuredWorkspace: config2.agents.defaults.workspace
|
|
@@ -11546,11 +11987,11 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11546
11987
|
console.log(`\u2713 Installed ${result.slug} (${result.source})`);
|
|
11547
11988
|
}
|
|
11548
11989
|
console.log(` Path: ${result.destinationDir}`);
|
|
11549
|
-
}
|
|
11550
|
-
async
|
|
11990
|
+
};
|
|
11991
|
+
skillsPublish = async (options) => {
|
|
11551
11992
|
const result = await publishMarketplaceSkill({
|
|
11552
|
-
skillDir:
|
|
11553
|
-
metaFile: options.meta ?
|
|
11993
|
+
skillDir: expandHome3(options.dir),
|
|
11994
|
+
metaFile: options.meta ? expandHome3(options.meta) : void 0,
|
|
11554
11995
|
slug: options.slug,
|
|
11555
11996
|
name: options.name,
|
|
11556
11997
|
summary: options.summary,
|
|
@@ -11566,11 +12007,11 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11566
12007
|
});
|
|
11567
12008
|
console.log(`${result.created ? `\u2713 Published new skill: ${result.slug}` : `\u2713 Updated skill: ${result.slug}`}
|
|
11568
12009
|
Files: ${result.fileCount}`);
|
|
11569
|
-
}
|
|
11570
|
-
async
|
|
12010
|
+
};
|
|
12011
|
+
skillsUpdate = async (options) => {
|
|
11571
12012
|
const result = await publishMarketplaceSkill({
|
|
11572
|
-
skillDir:
|
|
11573
|
-
metaFile: options.meta ?
|
|
12013
|
+
skillDir: expandHome3(options.dir),
|
|
12014
|
+
metaFile: options.meta ? expandHome3(options.meta) : void 0,
|
|
11574
12015
|
slug: options.slug,
|
|
11575
12016
|
name: options.name,
|
|
11576
12017
|
summary: options.summary,
|
|
@@ -11586,9 +12027,18 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
|
11586
12027
|
});
|
|
11587
12028
|
console.log(`\u2713 Updated skill: ${result.slug}`);
|
|
11588
12029
|
console.log(` Files: ${result.fileCount}`);
|
|
11589
|
-
}
|
|
12030
|
+
};
|
|
11590
12031
|
};
|
|
11591
12032
|
|
|
12033
|
+
// src/cli/register-agents-commands.ts
|
|
12034
|
+
function registerAgentsCommands(program2, runtime2) {
|
|
12035
|
+
const agents = program2.command("agents").description("Manage agents");
|
|
12036
|
+
agents.command("list").description("List available agents").option("--json", "Output JSON", false).action((opts) => runtime2.agentsList(opts));
|
|
12037
|
+
agents.command("new <agentId>").description("Create a new agent").option("--name <name>", "Agent display name").option("--description <description>", "Agent description").option("--avatar <avatar>", "Remote avatar URL or local image path").option("--home <path>", "Agent home directory").option("--json", "Output JSON", false).action(async (agentId, opts) => runtime2.agentsNew(agentId, opts));
|
|
12038
|
+
agents.command("update <agentId>").description("Update an existing agent").option("--name <name>", "Agent display name").option("--description <description>", "Agent description").option("--avatar <avatar>", "Remote avatar URL or local image path").option("--json", "Output JSON", false).action(async (agentId, opts) => runtime2.agentsUpdate(agentId, opts));
|
|
12039
|
+
agents.command("remove <agentId>").description("Remove an agent").option("--json", "Output JSON", false).action(async (agentId, opts) => runtime2.agentsRemove(agentId, opts));
|
|
12040
|
+
}
|
|
12041
|
+
|
|
11592
12042
|
// src/cli/index.ts
|
|
11593
12043
|
logStartupTrace("cli.index.module_loaded");
|
|
11594
12044
|
var program = new Command();
|
|
@@ -11611,6 +12061,7 @@ skills.command("install <slug>").description("Install a skill from NextClaw mark
|
|
|
11611
12061
|
var withRepeatableTag = (value, previous = []) => [...previous, value];
|
|
11612
12062
|
skills.command("publish <dir>").description("Upload or create a skill in marketplace").option("--meta <path>", "Marketplace metadata file (default: <dir>/marketplace.json)").option("--slug <slug>", "Skill slug (default: directory name)").option("--name <name>", "Skill display name").option("--summary <summary>", "Skill summary").option("--description <description>", "Skill description").option("--author <author>", "Skill author").option("--tag <tag>", "Skill tag (repeatable)", withRepeatableTag, []).option("--source-repo <url>", "Source repository URL").option("--homepage <url>", "Homepage URL").option("--published-at <datetime>", "Published time (ISO datetime)").option("--updated-at <datetime>", "Updated time (ISO datetime)").option("--api-base <url>", "Marketplace API base URL").option("--token <token>", "Marketplace admin token").action(async (dir, opts) => runtime.skillsPublish({ dir, ...opts, apiBaseUrl: opts.apiBase }));
|
|
11613
12063
|
skills.command("update <dir>").description("Update an existing skill in marketplace").option("--meta <path>", "Marketplace metadata file (default: <dir>/marketplace.json)").option("--slug <slug>", "Skill slug (default: directory name)").option("--name <name>", "Skill display name").option("--summary <summary>", "Skill summary").option("--description <description>", "Skill description").option("--author <author>", "Skill author").option("--tag <tag>", "Skill tag (repeatable)", withRepeatableTag, []).option("--source-repo <url>", "Source repository URL").option("--homepage <url>", "Homepage URL").option("--updated-at <datetime>", "Updated time (ISO datetime)").option("--api-base <url>", "Marketplace API base URL").option("--token <token>", "Marketplace admin token").action(async (dir, opts) => runtime.skillsUpdate({ dir, ...opts, apiBaseUrl: opts.apiBase }));
|
|
12064
|
+
registerAgentsCommands(program, runtime);
|
|
11614
12065
|
var plugins = program.command("plugins").description("Manage OpenClaw-compatible plugins");
|
|
11615
12066
|
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));
|
|
11616
12067
|
plugins.command("info <id>").description("Show plugin details").option("--json", "Print JSON").action((id, opts) => runtime.pluginsInfo(id, opts));
|
|
@@ -11646,7 +12097,7 @@ channels.command("status").description("Show channel status").action(() => runti
|
|
|
11646
12097
|
channels.command("login").description("Link device via QR code").option("--channel <id>", "Plugin channel id").option("--account <id>", "Channel account id").option("--url <url>", "Channel API base URL").option("--http-url <url>", "Alias for --url").option("-v, --verbose", "Verbose output", false).action(async (opts) => runtime.channelsLogin(opts));
|
|
11647
12098
|
var cron = program.command("cron").description("Manage scheduled tasks");
|
|
11648
12099
|
cron.command("list").option("--enabled-only", "Show only enabled jobs", false).option("-a, --all", "Deprecated: list all jobs (default behavior)", false).action(async (opts) => runtime.cronList({ enabledOnly: Boolean(opts.enabledOnly) }));
|
|
11649
|
-
cron.command("add").requiredOption("-n, --name <name>", "Job name").requiredOption("-m, --message <message>", "Message for agent").option("-e, --every <seconds>", "Run every N seconds").option("-c, --cron <expr>", "Cron expression").option("--at <iso>", "Run once at time (ISO format)").option("-d, --deliver", "Deliver response to channel").option("--to <recipient>", "Recipient for delivery").option("--channel <channel>", "Channel for delivery").option("--account <id>", "Account id for channel delivery").action(async (opts) => runtime.cronAdd(opts));
|
|
12100
|
+
cron.command("add").requiredOption("-n, --name <name>", "Job name").requiredOption("-m, --message <message>", "Message for agent").option("--agent <id>", "Target agent id").option("-e, --every <seconds>", "Run every N seconds").option("-c, --cron <expr>", "Cron expression").option("--at <iso>", "Run once at time (ISO format)").option("-d, --deliver", "Deliver response to channel").option("--to <recipient>", "Recipient for delivery").option("--channel <channel>", "Channel for delivery").option("--account <id>", "Account id for channel delivery").action(async (opts) => runtime.cronAdd(opts));
|
|
11650
12101
|
cron.command("remove <jobId>").action(async (jobId) => runtime.cronRemove(jobId));
|
|
11651
12102
|
cron.command("enable <jobId>").option("--disable", "Disable instead of enable").action(async (jobId, opts) => runtime.cronEnable(jobId, opts));
|
|
11652
12103
|
cron.command("disable <jobId>").action(async (jobId) => runtime.cronEnable(jobId, { disable: true }));
|