@nextclaw/service 0.2.8 → 0.2.10-beta.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/commands/cron/services/cron-local.service.d.ts.map +1 -1
- package/dist/cli/commands/cron/services/cron-local.service.js +1 -9
- package/dist/cli/commands/cron/services/cron-local.service.js.map +1 -1
- package/dist/cli/commands/cron/utils/cron-job.utils.d.ts +0 -4
- package/dist/cli/commands/cron/utils/cron-job.utils.d.ts.map +1 -1
- package/dist/cli/commands/cron/utils/cron-job.utils.js.map +1 -1
- package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +2 -2
- package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts.map +1 -1
- package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +3 -4
- package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js.map +1 -1
- package/dist/shared/services/gateway/utils/cron-job-handler.utils.d.ts +0 -6
- package/dist/shared/services/gateway/utils/cron-job-handler.utils.d.ts.map +1 -1
- package/dist/shared/services/gateway/utils/cron-job-handler.utils.js +22 -18
- package/dist/shared/services/gateway/utils/cron-job-handler.utils.js.map +1 -1
- package/dist/shared/services/runtime/utils/service-remote-runtime.utils.d.ts.map +1 -1
- package/dist/shared/services/runtime/utils/service-remote-runtime.utils.js +30 -26
- package/dist/shared/services/runtime/utils/service-remote-runtime.utils.js.map +1 -1
- package/dist/shared/stores/companion-runtime.store.js +2 -2
- package/dist/shared/stores/companion-runtime.store.js.map +1 -1
- package/dist/shared/stores/local-ui-runtime.store.js +2 -2
- package/dist/shared/stores/local-ui-runtime.store.js.map +1 -1
- package/dist/shared/stores/managed-service-state.store.js +2 -2
- package/dist/shared/stores/managed-service-state.store.js.map +1 -1
- package/dist/shared/types/cli.types.d.ts +0 -4
- package/dist/shared/types/cli.types.d.ts.map +1 -1
- package/dist/shared/utils/cli.utils.js +2 -2
- package/dist/shared/utils/cli.utils.js.map +1 -1
- package/dist/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.d.ts +5 -0
- package/dist/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.d.ts.map +1 -0
- package/dist/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.js +29 -0
- package/dist/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.js.map +1 -0
- package/dist/shared/utils/restart/restart-sentinel.utils.js +2 -2
- package/dist/shared/utils/restart/restart-sentinel.utils.js.map +1 -1
- package/package.json +26 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron-local.service.d.ts","names":[],"sources":["../../../../../src/cli/commands/cron/services/cron-local.service.ts"],"mappings":";;;;;;iBAwCgB,uBAAA,CAAwB,IAAA,EAAM,cAAA;EAAmB,OAAA,GAAU,iBAAA;EAAmB,KAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"cron-local.service.d.ts","names":[],"sources":["../../../../../src/cli/commands/cron/services/cron-local.service.ts"],"mappings":";;;;;;iBAwCgB,uBAAA,CAAwB,IAAA,EAAM,cAAA;EAAmB,OAAA,GAAU,iBAAA;EAAmB,KAAA;AAAA;AAAA,cAqBjF,gBAAA;EAAA,iBAEQ,UAAA;cAAA,UAAA,GAAU,iBAAA;EAAA,SAKpB,IAAA,GAAQ,GAAA,cAAe,WAAA;EAAA,SAIvB,UAAA,GAAc,OAAA,EAAS,iBAAA,KAAoB,WAAA;EAAA,SAW3C,GAAA,GAAO,IAAA,EAAM,cAAA;IAAmB,GAAA,EAAK,WAAA;IAAoB,KAAA;EAAA;EAAA,SAQzD,MAAA,GAAU,KAAA;EAAA,SAIV,MAAA,GAAU,KAAA,UAAe,OAAA,cAAmB,WAAA;EAAA,SAI5C,GAAA,GAAa,KAAA,UAAe,KAAA,cAAiB,OAAA;AAAA"}
|
|
@@ -45,11 +45,7 @@ function createCronCreateRequest(opts) {
|
|
|
45
45
|
message,
|
|
46
46
|
schedule: schedule.schedule,
|
|
47
47
|
agentId: readTrimmed(opts.agent),
|
|
48
|
-
sessionId: readTrimmed(opts.session)
|
|
49
|
-
deliver: Boolean(opts.deliver),
|
|
50
|
-
channel: readTrimmed(opts.channel),
|
|
51
|
-
to: readTrimmed(opts.to),
|
|
52
|
-
accountId: readTrimmed(opts.account)
|
|
48
|
+
sessionId: readTrimmed(opts.session)
|
|
53
49
|
} };
|
|
54
50
|
}
|
|
55
51
|
var CronLocalService = class {
|
|
@@ -66,10 +62,6 @@ var CronLocalService = class {
|
|
|
66
62
|
message: request.message,
|
|
67
63
|
agentId: request.agentId ?? void 0,
|
|
68
64
|
sessionId: request.sessionId ?? void 0,
|
|
69
|
-
deliver: request.deliver === true,
|
|
70
|
-
channel: request.channel ?? void 0,
|
|
71
|
-
to: request.to ?? void 0,
|
|
72
|
-
accountId: request.accountId ?? void 0,
|
|
73
65
|
deleteAfterRun: request.deleteAfterRun === true
|
|
74
66
|
});
|
|
75
67
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron-local.service.js","names":[],"sources":["../../../../../src/cli/commands/cron/services/cron-local.service.ts"],"sourcesContent":["import { getDataDir } from \"@nextclaw/core\";\nimport { AutomationManager } from \"@nextclaw/kernel\";\nimport type { CronCreateRequest } from \"@nextclaw/server\";\nimport type { CronAddOptions } from \"@nextclaw-service/shared/types/cli.types.js\";\nimport type { CronJobView } from \"@nextclaw-service/cli/commands/cron/utils/cron-job.utils.js\";\nimport { resolve } from \"node:path\";\n\nfunction readTrimmed(value: string | undefined): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction toSchedule(opts: CronAddOptions): { schedule?: CronCreateRequest[\"schedule\"]; error?: string } {\n const every = readTrimmed(opts.every);\n const cron = readTrimmed(opts.cron);\n const at = readTrimmed(opts.at);\n const scheduleFlags = [every, cron, at].filter((value) => value !== undefined);\n if (scheduleFlags.length !== 1) {\n return { error: \"Error: Must specify exactly one of --every, --cron, or --at\" };\n }\n if (every) {\n const everySeconds = Number(every);\n if (!Number.isFinite(everySeconds) || everySeconds <= 0) {\n return { error: \"Error: --every must be a positive number of seconds\" };\n }\n return { schedule: { kind: \"every\", everyMs: everySeconds * 1000 } };\n }\n if (cron) {\n return { schedule: { kind: \"cron\", expr: cron } };\n }\n const atMs = Date.parse(String(at));\n if (!Number.isFinite(atMs)) {\n return { error: \"Error: --at must be a valid ISO datetime\" };\n }\n return { schedule: { kind: \"at\", atMs } };\n}\n\nexport function createCronCreateRequest(opts: CronAddOptions): { request?: CronCreateRequest; error?: string } {\n const name = readTrimmed(opts.name);\n const message = readTrimmed(opts.message);\n if (!name || !message) {\n return { error: \"Error: name and message are required\" };\n }\n const schedule = toSchedule(opts);\n if (!schedule.schedule) {\n return { error: schedule.error ?? \"Error: Must specify --every, --cron, or --at\" };\n }\n return {\n request: {\n name,\n message,\n schedule: schedule.schedule,\n agentId: readTrimmed(opts.agent),\n sessionId: readTrimmed(opts.session),\n
|
|
1
|
+
{"version":3,"file":"cron-local.service.js","names":[],"sources":["../../../../../src/cli/commands/cron/services/cron-local.service.ts"],"sourcesContent":["import { getDataDir } from \"@nextclaw/core\";\nimport { AutomationManager } from \"@nextclaw/kernel\";\nimport type { CronCreateRequest } from \"@nextclaw/server\";\nimport type { CronAddOptions } from \"@nextclaw-service/shared/types/cli.types.js\";\nimport type { CronJobView } from \"@nextclaw-service/cli/commands/cron/utils/cron-job.utils.js\";\nimport { resolve } from \"node:path\";\n\nfunction readTrimmed(value: string | undefined): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction toSchedule(opts: CronAddOptions): { schedule?: CronCreateRequest[\"schedule\"]; error?: string } {\n const every = readTrimmed(opts.every);\n const cron = readTrimmed(opts.cron);\n const at = readTrimmed(opts.at);\n const scheduleFlags = [every, cron, at].filter((value) => value !== undefined);\n if (scheduleFlags.length !== 1) {\n return { error: \"Error: Must specify exactly one of --every, --cron, or --at\" };\n }\n if (every) {\n const everySeconds = Number(every);\n if (!Number.isFinite(everySeconds) || everySeconds <= 0) {\n return { error: \"Error: --every must be a positive number of seconds\" };\n }\n return { schedule: { kind: \"every\", everyMs: everySeconds * 1000 } };\n }\n if (cron) {\n return { schedule: { kind: \"cron\", expr: cron } };\n }\n const atMs = Date.parse(String(at));\n if (!Number.isFinite(atMs)) {\n return { error: \"Error: --at must be a valid ISO datetime\" };\n }\n return { schedule: { kind: \"at\", atMs } };\n}\n\nexport function createCronCreateRequest(opts: CronAddOptions): { request?: CronCreateRequest; error?: string } {\n const name = readTrimmed(opts.name);\n const message = readTrimmed(opts.message);\n if (!name || !message) {\n return { error: \"Error: name and message are required\" };\n }\n const schedule = toSchedule(opts);\n if (!schedule.schedule) {\n return { error: schedule.error ?? \"Error: Must specify --every, --cron, or --at\" };\n }\n return {\n request: {\n name,\n message,\n schedule: schedule.schedule,\n agentId: readTrimmed(opts.agent),\n sessionId: readTrimmed(opts.session),\n }\n };\n}\n\nexport class CronLocalService {\n constructor(\n private readonly automation = new AutomationManager({\n storePath: resolve(getDataDir(), \"cron\", \"jobs.json\")\n })\n ) {}\n\n readonly list = (all: boolean): CronJobView[] => {\n return this.automation.listJobs(all) as CronJobView[];\n };\n\n readonly addRequest = (request: CronCreateRequest): CronJobView => {\n return this.automation.addJob({\n name: request.name,\n schedule: request.schedule,\n message: request.message,\n agentId: request.agentId ?? undefined,\n sessionId: request.sessionId ?? undefined,\n deleteAfterRun: request.deleteAfterRun === true\n }) as CronJobView;\n };\n\n readonly add = (opts: CronAddOptions): { job: CronJobView | null; error?: string } => {\n const request = createCronCreateRequest(opts);\n if (!request.request) {\n return { job: null, error: request.error };\n }\n return { job: this.addRequest(request.request) };\n };\n\n readonly remove = (jobId: string): boolean => {\n return this.automation.removeJob(jobId);\n };\n\n readonly enable = (jobId: string, enabled: boolean): CronJobView | null => {\n return (this.automation.enableJob(jobId, enabled) as CronJobView | null) ?? null;\n };\n\n readonly run = async (jobId: string, force: boolean): Promise<boolean> => {\n return this.automation.runJob(jobId, force);\n };\n}\n"],"mappings":";;;;AAOA,SAAS,YAAY,OAA+C;AAClE,KAAI,OAAO,UAAU,SACnB;AAGF,QADgB,MAAM,MAAM,IACV,KAAA;;AAGpB,SAAS,WAAW,MAAoF;CACtG,MAAM,QAAQ,YAAY,KAAK,MAAM;CACrC,MAAM,OAAO,YAAY,KAAK,KAAK;CACnC,MAAM,KAAK,YAAY,KAAK,GAAG;AAE/B,KADsB;EAAC;EAAO;EAAM;EAAG,CAAC,QAAQ,UAAU,UAAU,KAAA,EAAU,CAC5D,WAAW,EAC3B,QAAO,EAAE,OAAO,+DAA+D;AAEjF,KAAI,OAAO;EACT,MAAM,eAAe,OAAO,MAAM;AAClC,MAAI,CAAC,OAAO,SAAS,aAAa,IAAI,gBAAgB,EACpD,QAAO,EAAE,OAAO,uDAAuD;AAEzE,SAAO,EAAE,UAAU;GAAE,MAAM;GAAS,SAAS,eAAe;GAAM,EAAE;;AAEtE,KAAI,KACF,QAAO,EAAE,UAAU;EAAE,MAAM;EAAQ,MAAM;EAAM,EAAE;CAEnD,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG,CAAC;AACnC,KAAI,CAAC,OAAO,SAAS,KAAK,CACxB,QAAO,EAAE,OAAO,4CAA4C;AAE9D,QAAO,EAAE,UAAU;EAAE,MAAM;EAAM;EAAM,EAAE;;AAG3C,SAAgB,wBAAwB,MAAuE;CAC7G,MAAM,OAAO,YAAY,KAAK,KAAK;CACnC,MAAM,UAAU,YAAY,KAAK,QAAQ;AACzC,KAAI,CAAC,QAAQ,CAAC,QACZ,QAAO,EAAE,OAAO,wCAAwC;CAE1D,MAAM,WAAW,WAAW,KAAK;AACjC,KAAI,CAAC,SAAS,SACZ,QAAO,EAAE,OAAO,SAAS,SAAS,gDAAgD;AAEpF,QAAO,EACL,SAAS;EACP;EACA;EACA,UAAU,SAAS;EACnB,SAAS,YAAY,KAAK,MAAM;EAChC,WAAW,YAAY,KAAK,QAAQ;EACrC,EACF;;AAGH,IAAa,mBAAb,MAA8B;CAC5B,YACE,aAA8B,IAAI,kBAAkB,EAClD,WAAW,QAAQ,YAAY,EAAE,QAAQ,YAAY,EACtD,CAAC,EACF;AAHiB,OAAA,aAAA;;CAKnB,QAAiB,QAAgC;AAC/C,SAAO,KAAK,WAAW,SAAS,IAAI;;CAGtC,cAAuB,YAA4C;AACjE,SAAO,KAAK,WAAW,OAAO;GAC5B,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,SAAS,QAAQ;GACjB,SAAS,QAAQ,WAAW,KAAA;GAC5B,WAAW,QAAQ,aAAa,KAAA;GAChC,gBAAgB,QAAQ,mBAAmB;GAC5C,CAAC;;CAGJ,OAAgB,SAAsE;EACpF,MAAM,UAAU,wBAAwB,KAAK;AAC7C,MAAI,CAAC,QAAQ,QACX,QAAO;GAAE,KAAK;GAAM,OAAO,QAAQ;GAAO;AAE5C,SAAO,EAAE,KAAK,KAAK,WAAW,QAAQ,QAAQ,EAAE;;CAGlD,UAAmB,UAA2B;AAC5C,SAAO,KAAK,WAAW,UAAU,MAAM;;CAGzC,UAAmB,OAAe,YAAyC;AACzE,SAAQ,KAAK,WAAW,UAAU,OAAO,QAAQ,IAA2B;;CAG9E,MAAe,OAAO,OAAe,UAAqC;AACxE,SAAO,KAAK,WAAW,OAAO,OAAO,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron-job.utils.d.ts","names":[],"sources":["../../../../../src/cli/commands/cron/utils/cron-job.utils.ts"],"mappings":";KAAY,YAAA;EACN,IAAA;EAAe,OAAA;AAAA;EACf,IAAA;EAAc,IAAA;AAAA;EACd,IAAA;EAAY,IAAA;AAAA;AAAA,KAEN,WAAA;EACV,OAAA;EACA,OAAA;EACA,SAAA;
|
|
1
|
+
{"version":3,"file":"cron-job.utils.d.ts","names":[],"sources":["../../../../../src/cli/commands/cron/utils/cron-job.utils.ts"],"mappings":";KAAY,YAAA;EACN,IAAA;EAAe,OAAA;AAAA;EACf,IAAA;EAAc,IAAA;AAAA;EACd,IAAA;EAAY,IAAA;AAAA;AAAA,KAEN,WAAA;EACV,OAAA;EACA,OAAA;EACA,SAAA;AAAA;AAAA,KAGU,WAAA;EACV,EAAA;EACA,IAAA;EACA,OAAA;EACA,QAAA,EAAU,YAAA;EACV,OAAA,EAAS,WAAA;AAAA;AAAA,iBAGK,kBAAA,CAAmB,QAAA,EAAU,YAAA;AAAA,iBAU7B,aAAA,CAAc,IAAA,EAAM,WAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron-job.utils.js","names":[],"sources":["../../../../../src/cli/commands/cron/utils/cron-job.utils.ts"],"sourcesContent":["export type CronSchedule =\n | { kind: \"every\"; everyMs?: number | null }\n | { kind: \"cron\"; expr?: string | null }\n | { kind: \"at\"; atMs?: number | null };\n\nexport type CronPayload = {\n message: string;\n agentId?: string | null;\n sessionId?: string | null;\n
|
|
1
|
+
{"version":3,"file":"cron-job.utils.js","names":[],"sources":["../../../../../src/cli/commands/cron/utils/cron-job.utils.ts"],"sourcesContent":["export type CronSchedule =\n | { kind: \"every\"; everyMs?: number | null }\n | { kind: \"cron\"; expr?: string | null }\n | { kind: \"at\"; atMs?: number | null };\n\nexport type CronPayload = {\n message: string;\n agentId?: string | null;\n sessionId?: string | null;\n};\n\nexport type CronJobView = {\n id: string;\n name: string;\n enabled: boolean;\n schedule: CronSchedule;\n payload: CronPayload;\n};\n\nexport function formatCronSchedule(schedule: CronSchedule): string {\n if (schedule.kind === \"every\") {\n return `every ${Math.round((schedule.everyMs ?? 0) / 1000)}s`;\n }\n if (schedule.kind === \"cron\") {\n return schedule.expr ?? \"\";\n }\n return schedule.atMs ? new Date(schedule.atMs).toISOString() : \"\";\n}\n\nexport function printCronJobs(jobs: CronJobView[]): void {\n if (!jobs.length) {\n console.log(\"No scheduled jobs.\");\n return;\n }\n for (const job of jobs) {\n console.log(`${job.id} [${job.enabled ? \"enabled\" : \"disabled\"}] ${job.name} ${formatCronSchedule(job.schedule)}`);\n }\n}\n"],"mappings":";AAmBA,SAAgB,mBAAmB,UAAgC;AACjE,KAAI,SAAS,SAAS,QACpB,QAAO,SAAS,KAAK,OAAO,SAAS,WAAW,KAAK,IAAK,CAAC;AAE7D,KAAI,SAAS,SAAS,OACpB,QAAO,SAAS,QAAQ;AAE1B,QAAO,SAAS,OAAO,IAAI,KAAK,SAAS,KAAK,CAAC,aAAa,GAAG;;AAGjE,SAAgB,cAAc,MAA2B;AACvD,KAAI,CAAC,KAAK,QAAQ;AAChB,UAAQ,IAAI,qBAAqB;AACjC;;AAEF,MAAK,MAAM,OAAO,KAChB,SAAQ,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,UAAU,YAAY,WAAW,IAAI,IAAI,KAAK,GAAG,mBAAmB,IAAI,SAAS,GAAG"}
|
|
@@ -14,7 +14,7 @@ import { EventBus, Ingress } from "@nextclaw/shared";
|
|
|
14
14
|
|
|
15
15
|
//#region src/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts
|
|
16
16
|
type Config$1 = NextclawCore.Config;
|
|
17
|
-
type MessageBus
|
|
17
|
+
type MessageBus = NextclawCore.MessageBus;
|
|
18
18
|
type GatewayRuntimeOptions = {
|
|
19
19
|
uiOverrides?: Partial<Config$1["ui"]>;
|
|
20
20
|
uiStaticDir?: string | null;
|
|
@@ -38,7 +38,7 @@ declare class NextclawGatewayRuntime {
|
|
|
38
38
|
private readonly options;
|
|
39
39
|
readonly kernel: NextclawKernel;
|
|
40
40
|
readonly appEventBus: EventBus;
|
|
41
|
-
readonly messageBus: MessageBus
|
|
41
|
+
readonly messageBus: MessageBus;
|
|
42
42
|
readonly sessionManager: SessionManager;
|
|
43
43
|
readonly automation: AutomationManager;
|
|
44
44
|
readonly agentRunClient: AgentRunClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextclaw-gateway-runtime.service.d.ts","names":[],"sources":["../../../../src/shared/services/gateway/nextclaw-gateway-runtime.service.ts"],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"nextclaw-gateway-runtime.service.d.ts","names":[],"sources":["../../../../src/shared/services/gateway/nextclaw-gateway-runtime.service.ts"],"mappings":";;;;;;;;;;;;;;;KA8DK,QAAA,GAAS,YAAA,CAAa,MAAA;AAAA,KACtB,UAAA,GAAa,YAAA,CAAa,UAAA;AAAA,KAE1B,qBAAA;EACH,WAAA,GAAc,OAAA,CAAQ,QAAA;EACtB,WAAA;AAAA;AAAA,KAGU,kBAAA;EACV,cAAA,GAAiB,MAAA,EAAQ,oBAAA,KAAyB,OAAA;EAClD,4BAAA,GAA+B,aAAA;EAC/B,YAAA,GAAe,OAAA;IAAW,WAAA,EAAa,MAAA;IAAyB,IAAA;EAAA,MAAoB,OAAA;EACpF,WAAA,QAAmB,OAAA;EACnB,gBAAA,GAAmB,IAAA,eAAmB,OAAA;EACtC,8BAAA,GAAiC,IAAA,UAAc,KAAA;IAAiC,OAAA;IAAiB,MAAA;EAAA;AAAA;AAAA,cAGtF,sBAAA;EAAA,iBA6BQ,IAAA;EAAA,iBACA,OAAA;EAAA,SA7BV,MAAA,EAAQ,cAAA;EAAA,SACR,WAAA,EAAa,QAAA;EAAA,SACb,UAAA,EAAY,UAAA;EAAA,SACZ,cAAA,EAAgB,cAAA;EAAA,SAChB,UAAA,EAAY,iBAAA;EAAA,SACZ,cAAA,EAAgB,cAAA;EAAA,SAChB,cAAA,EAAgB,oBAAA;EAAA,SAChB,aAAA,EAAe,mBAAA;EAAA,SACf,OAAA,EAAS,OAAA;EAAA,SACT,YAAA,EADgB,oBAAA;EAAA,SAEhB,cAAA;EAAA,SACA,eAAA,EAAiB,kBAAA;EAAA,SACjB,iBAAA,EAAmB,qBAAA;EAAA,SAEnB,aAAA,EAAe,aAAA;EAAA,SACf,QAAA,EAAU,QAAA;EAAA,SACV,WAAA;EAAA,SACA,SAAA;EAAA,SACA,aAAA,EAAe,oBAAA;EAAA,SACf,WAAA,EAAa,oBAAA;EAAA,SACb,UAAA,EAAY,uBAAA;EAAA,SACZ,WAAA,EAAa,yBAAA;EACtB,eAAA,EAAiB,2BAAA;EACjB,SAAA,EAAW,eAAA;EAAA,SACF,YAAA,EAAY,0BAAA;EAAA,QACb,sBAAA;cAGW,IAAA,EAAM,kBAAA,EACN,OAAA,EAAS,qBAAA;EA4D5B,KAAA,QAAkB,OAAA;EAAA,QAaV,KAAA;EAAA,QAOA,qBAAA;EAAA,QAOA,uBAAA;EAAA,QAIA,cAAA;EAAA,QAiCA,qBAAA;EAAA,QAmBA,cAAA;EAAA,QAmBA,oBAAA;EAAA,SAKC,qBAAA,QAAkC,OAAA;EAAA,iBAI1B,aAAA;EAAA,QAWT,iBAAA;EAAA,QASA,OAAA;EAAA,QAOA,kBAAA;EAAA,QAKA,uBAAA;EAAA,QAqBA,oBAAA;EAAA,QAgBA,sBAAA;EAAA,QAiBA,wBAAA;AAAA"}
|
|
@@ -16,6 +16,7 @@ import { ServiceFileWatcherRegistry, markLocalUiRuntimeIfStarted, startGatewayRu
|
|
|
16
16
|
import { ServiceMarketplaceInstaller } from "../marketplace/service-marketplace-installer.service.js";
|
|
17
17
|
import { NpmRuntimeUpdateHost } from "../ui/npm-runtime-update-host.service.js";
|
|
18
18
|
import { createRuntimeControlHost } from "../ui/runtime-control-host.service.js";
|
|
19
|
+
import { readPanelAppClientSdkScript } from "../../utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.js";
|
|
19
20
|
import * as NextclawCore from "@nextclaw/core";
|
|
20
21
|
import { AgentRunClient, NextclawKernel, runGatewayInboundLoop } from "@nextclaw/kernel";
|
|
21
22
|
import { resolve } from "node:path";
|
|
@@ -105,10 +106,7 @@ var NextclawGatewayRuntime = class {
|
|
|
105
106
|
this.gatewayController = this.createGatewayController();
|
|
106
107
|
this.kernel.provideGatewayController(this.gatewayController);
|
|
107
108
|
this.deferredChannelStarter = this.startChannels;
|
|
108
|
-
this.automation.onJob = createCronJobHandler({
|
|
109
|
-
agentRunClient: this.agentRunClient,
|
|
110
|
-
bus: this.messageBus
|
|
111
|
-
});
|
|
109
|
+
this.automation.onJob = createCronJobHandler({ agentRunClient: this.agentRunClient });
|
|
112
110
|
}
|
|
113
111
|
start = async () => {
|
|
114
112
|
logStartupTrace("service.start_gateway.begin");
|
|
@@ -165,6 +163,7 @@ var NextclawGatewayRuntime = class {
|
|
|
165
163
|
appEventBus: this.appEventBus,
|
|
166
164
|
uiConfig: this.uiConfig,
|
|
167
165
|
uiStaticDir: this.uiStaticDir,
|
|
166
|
+
panelAppClientSdkScript: readPanelAppClientSdkScript,
|
|
168
167
|
productVersion: this.productVersion,
|
|
169
168
|
applyLiveConfigReload: this.configManager.applyLiveConfigReload,
|
|
170
169
|
initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextclaw-gateway-runtime.service.js","names":["getConfigPath","getDataDir","getWorkspacePath","waitForNextTick"],"sources":["../../../../src/shared/services/gateway/nextclaw-gateway-runtime.service.ts"],"sourcesContent":["import * as NextclawCore from \"@nextclaw/core\";\nimport {\n AgentRunClient,\n NextclawKernel,\n runGatewayInboundLoop,\n type AutomationManager,\n type ConfigManager,\n type LlmProviderManager,\n type SessionManager,\n} from \"@nextclaw/kernel\";\nimport type { EventBus, Ingress } from \"@nextclaw/shared\";\nimport {\n startUiServer,\n type MarketplaceApiConfig,\n type UiRouterOptions,\n type UiRuntimeControlHost,\n type UiRuntimeUpdateHost,\n} from \"@nextclaw/server\";\nimport { resolve } from \"node:path\";\nimport { setImmediate as waitForNextTick } from \"node:timers/promises\";\nimport { GatewayControllerImpl } from \"@nextclaw-service/shared/controllers/gateway.controller.js\";\nimport { GatewayExtensionManager } from \"@nextclaw-service/shared/services/gateway/managers/gateway-extension.manager.js\";\nimport { GatewayRemoteManager } from \"@nextclaw-service/shared/services/gateway/managers/gateway-remote.manager.js\";\nimport { GatewayRestartWakeService } from \"@nextclaw-service/shared/services/gateway/gateway-restart-wake.service.js\";\nimport { createCronJobHandler } from \"@nextclaw-service/shared/services/gateway/utils/cron-job-handler.utils.js\";\nimport { companionRuntimeService } from \"@nextclaw-service/shared/services/ui/companion-runtime.service.js\";\nimport { handleGatewayDeferredStartupError } from \"@nextclaw-service/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.js\";\nimport { NextclawApp, type UiStartupHandle } from \"@nextclaw-service/shared/services/gateway/nextclaw-app.service.js\";\nimport { NextclawDistributionService } from \"@nextclaw-service/shared/services/runtime/nextclaw-distribution.service.js\";\nimport { ServiceBootstrapStatusStore } from \"@nextclaw-service/shared/services/gateway/service-bootstrap-status.service.js\";\nimport { ServiceFileWatcherRegistry, markLocalUiRuntimeIfStarted, startGatewayRuntimeSupport, watchServiceConfigFile } from \"@nextclaw-service/shared/services/gateway/service-startup-support.service.js\";\nimport { ServiceMarketplaceInstaller } from \"@nextclaw-service/shared/services/marketplace/service-marketplace-installer.service.js\";\nimport { NpmRuntimeUpdateHost } from \"@nextclaw-service/shared/services/ui/npm-runtime-update-host.service.js\";\nimport { createRuntimeControlHost } from \"@nextclaw-service/shared/services/ui/runtime-control-host.service.js\";\nimport { localUiRuntimeStore } from \"@nextclaw-service/shared/stores/local-ui-runtime.store.js\";\nimport { managedServiceStateStore } from \"@nextclaw-service/shared/stores/managed-service-state.store.js\";\nimport type { RequestRestartParams } from \"@nextclaw-service/shared/types/cli.types.js\";\nimport { openBrowser, resolveUiConfig, resolveUiStaticDir } from \"@nextclaw-service/shared/utils/cli.utils.js\";\nimport { logStartupTrace, measureStartupAsync, measureStartupSync } from \"@nextclaw-service/shared/utils/startup-trace.js\";\n\nconst {\n getConfigPath,\n getDataDir,\n getWorkspacePath,\n} = NextclawCore;\n\nfunction resolveApplyRestartMode(uiPort: number): \"managed-service-restart\" | \"manual-process-restart\" {\n const serviceState = managedServiceStateStore.read();\n if (serviceState?.pid === process.pid) {\n return \"managed-service-restart\";\n }\n if (\n process.env.NEXTCLAW_RUNTIME_BUNDLE_CHILD === \"1\" &&\n typeof serviceState?.uiPort === \"number\" &&\n serviceState.uiPort === uiPort\n ) {\n return \"managed-service-restart\";\n }\n return \"manual-process-restart\";\n}\n\ntype Config = NextclawCore.Config;\ntype MessageBus = NextclawCore.MessageBus;\n\ntype GatewayRuntimeOptions = {\n uiOverrides?: Partial<Config[\"ui\"]>;\n uiStaticDir?: string | null;\n};\n\nexport type GatewayRuntimeDeps = {\n requestRestart: (params: RequestRestartParams) => Promise<void>;\n initializeAgentHomeDirectory: (homeDirectory: string) => void;\n startService: (options: { uiOverrides: Record<string, unknown>; open: boolean }) => Promise<void>;\n stopService: () => Promise<void>;\n runCliSubcommand: (args: string[]) => Promise<string>;\n installBuiltinMarketplaceSkill: (slug: string, force: boolean | undefined) => { message: string; output?: string } | null;\n};\n\nexport class NextclawGatewayRuntime {\n readonly kernel: NextclawKernel;\n readonly appEventBus: EventBus;\n readonly messageBus: MessageBus;\n readonly sessionManager: SessionManager;\n readonly automation: AutomationManager;\n readonly agentRunClient: AgentRunClient;\n readonly runtimeControl: UiRuntimeControlHost;\n readonly runtimeUpdate: UiRuntimeUpdateHost | null;\n readonly ingress: Ingress;\n readonly distribution = NextclawDistributionService.get();\n readonly productVersion: string;\n readonly providerManager: LlmProviderManager;\n readonly gatewayController: GatewayControllerImpl;\n\n readonly configManager: ConfigManager;\n readonly uiConfig: Config[\"ui\"];\n readonly uiStaticDir: string | null;\n readonly workspace: string;\n readonly remoteManager: GatewayRemoteManager;\n readonly marketplace: MarketplaceApiConfig;\n readonly extensions: GatewayExtensionManager;\n readonly restartWake: GatewayRestartWakeService;\n bootstrapStatus: ServiceBootstrapStatusStore;\n uiStartup: UiStartupHandle;\n readonly fileWatchers = new ServiceFileWatcherRegistry();\n private deferredChannelStarter: () => Promise<void>;\n\n constructor(\n private readonly deps: GatewayRuntimeDeps,\n private readonly options: GatewayRuntimeOptions,\n ) {\n const configPath = getConfigPath();\n this.kernel = measureStartupSync(\n \"service.gateway.kernel\",\n () => new NextclawKernel({\n homeDir: getDataDir(),\n configPath,\n }),\n );\n this.configManager = this.kernel.configManager;\n const config = this.configManager.config;\n this.uiConfig = resolveUiConfig(config, options.uiOverrides);\n this.uiStaticDir = options.uiStaticDir === undefined ? resolveUiStaticDir(this.distribution.uiDistDir) : options.uiStaticDir;\n this.workspace = getWorkspacePath(config.agents.defaults.workspace);\n this.appEventBus = this.kernel.eventBus;\n this.ingress = this.kernel.ingress;\n this.agentRunClient = new AgentRunClient({\n eventBus: this.kernel.eventBus,\n ingress: this.kernel.ingress,\n });\n this.messageBus = this.kernel.messageBus;\n this.sessionManager = this.kernel.sessionManager;\n this.automation = this.kernel.automation;\n this.productVersion = this.distribution.version;\n this.extensions = new GatewayExtensionManager(this);\n this.providerManager = this.kernel.llmProviders;\n this.installConfigHostHooks();\n this.restartWake = new GatewayRestartWakeService(this);\n this.bootstrapStatus = this.createBootstrapStatus();\n this.uiStartup = this.createDisabledUiStartup();\n this.remoteManager = new GatewayRemoteManager({\n deps: this.deps,\n configManager: this.configManager,\n uiConfig: this.uiConfig,\n onRemoteStateChange: (state) => this.bootstrapStatus.syncRemoteRuntimeState(state),\n });\n this.marketplace = this.createMarketplace();\n this.runtimeControl = createRuntimeControlHost({\n serviceCommands: this.deps,\n requestRestart: this.deps.requestRestart,\n uiConfig: this.uiConfig,\n });\n this.runtimeUpdate =\n process.env.NEXTCLAW_DISABLE_RUNTIME_UPDATE_HOST === \"1\"\n ? null\n : new NpmRuntimeUpdateHost({\n eventBus: this.appEventBus,\n applyRestartMode: resolveApplyRestartMode(this.uiConfig.port),\n requestRestart: this.deps.requestRestart,\n uiConfig: this.uiConfig,\n });\n this.gatewayController = this.createGatewayController();\n this.kernel.provideGatewayController(this.gatewayController);\n this.deferredChannelStarter = this.startChannels;\n this.automation.onJob = createCronJobHandler({\n agentRunClient: this.agentRunClient,\n bus: this.messageBus,\n });\n }\n\n start = async (): Promise<void> => {\n logStartupTrace(\"service.start_gateway.begin\");\n await this.reset();\n this.configureIngressHandlers();\n this.uiStartup = await this.startUiRuntime();\n await companionRuntimeService.applyConfig(this.configManager.config);\n await this.markUiRuntimeReady();\n await this.startSupportServices();\n await this.runRuntimeLoop();\n await companionRuntimeService.ensureStopped();\n logStartupTrace(\"service.start_gateway.end\");\n };\n\n private reset = async (): Promise<void> => {\n await this.fileWatchers.clear();\n this.bootstrapStatus = this.createBootstrapStatus();\n this.uiStartup = this.createDisabledUiStartup();\n this.deferredChannelStarter = this.startChannels;\n };\n\n private createBootstrapStatus = (): ServiceBootstrapStatusStore => {\n const bootstrapStatus = new ServiceBootstrapStatusStore();\n bootstrapStatus.markChannelsPending();\n bootstrapStatus.setRemoteState(this.configManager.config.remote.enabled ? \"pending\" : \"disabled\");\n return bootstrapStatus;\n };\n\n private createDisabledUiStartup = (): UiStartupHandle => ({\n endpoint: \"\",\n });\n\n private startUiRuntime = async (): Promise<UiStartupHandle> => {\n const uiStartup = await measureStartupAsync(\"service.start_ui_runtime\", async () => {\n logStartupTrace(\"service.start_ui_runtime.begin\");\n if (!this.uiConfig.enabled) {\n return this.createDisabledUiStartup();\n }\n const uiServer = await startUiServer(this.createUiRouterOptions());\n const uiUrl = NextclawCore.resolveLocalUiBaseUrl({\n host: uiServer.host,\n port: uiServer.port,\n });\n console.log(`✓ UI API: ${uiUrl}/api`);\n if (this.uiStaticDir) {\n console.log(`✓ UI frontend: ${uiUrl}`);\n }\n if (this.uiConfig.open) {\n openBrowser(uiUrl);\n }\n logStartupTrace(\"service.start_ui_runtime.ready\", {\n host: uiServer.host,\n port: uiServer.port,\n });\n return {\n endpoint: uiUrl,\n };\n });\n markLocalUiRuntimeIfStarted({\n uiStartup: this.uiConfig.enabled ? uiStartup : null,\n uiConfig: this.uiConfig,\n });\n return uiStartup;\n };\n\n private createUiRouterOptions = (): UiRouterOptions => ({\n kernel: this.kernel,\n configPath: this.configManager.configPath,\n appEventBus: this.appEventBus,\n uiConfig: this.uiConfig,\n uiStaticDir: this.uiStaticDir,\n productVersion: this.productVersion,\n applyLiveConfigReload: this.configManager.applyLiveConfigReload,\n initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory,\n marketplace: this.marketplace,\n cron: this.automation,\n remoteAccess: this.remoteManager.remoteAccess,\n runtimeControl: this.runtimeControl,\n ...(this.runtimeUpdate ? { runtimeUpdate: this.runtimeUpdate } : {}),\n bootstrapStatus: this.bootstrapStatus,\n extensions: this.extensions,\n });\n\n private runRuntimeLoop = async (): Promise<void> => {\n logStartupTrace(\"service.start_gateway.runtime_loop_begin\");\n let startupTask: Promise<void> | null = null;\n try {\n const runtimeLoopTask = runGatewayInboundLoop(this);\n startupTask = this.startDeferredRuntime();\n void startupTask.catch((error) => handleGatewayDeferredStartupError({\n bootstrapStatus: this.bootstrapStatus,\n error,\n }));\n await runtimeLoopTask;\n } finally {\n if (startupTask) {\n await startupTask.catch(() => undefined);\n }\n await this.cleanup();\n }\n };\n\n private startDeferredRuntime = async (): Promise<void> => {\n const app = new NextclawApp(this);\n await app.start();\n };\n\n readonly startDeferredChannels = async (): Promise<void> => {\n await this.deferredChannelStarter();\n };\n\n private readonly startChannels = async (): Promise<void> => {\n await this.kernel.channels.start();\n const enabledChannels = this.kernel.channels.enabledChannels;\n if (enabledChannels.length > 0) {\n console.log(`✓ Channels enabled: ${enabledChannels.join(\", \")}`);\n } else {\n console.log(\"Warning: No channels enabled\");\n }\n this.bootstrapStatus.markChannelsReady(enabledChannels);\n };\n\n private createMarketplace = (): MarketplaceApiConfig => ({\n apiBaseUrl: process.env.NEXTCLAW_MARKETPLACE_API_BASE,\n installer: new ServiceMarketplaceInstaller({\n applyLiveConfigReload: this.configManager.applyLiveConfigReload,\n runCliSubcommand: this.deps.runCliSubcommand,\n installBuiltinSkill: this.deps.installBuiltinMarketplaceSkill,\n }).createInstaller(),\n });\n\n private cleanup = async (): Promise<void> => {\n localUiRuntimeStore.clearIfOwnedByProcess();\n await this.fileWatchers.clear();\n await this.kernel.extensions.stop();\n await this.remoteManager.stop();\n };\n\n private markUiRuntimeReady = async (): Promise<void> => {\n this.bootstrapStatus.markShellReady();\n await waitForNextTick();\n };\n\n private createGatewayController = (): GatewayControllerImpl => {\n return measureStartupSync(\n \"service.gateway.gateway_controller\",\n () => new GatewayControllerImpl({\n configManager: this.configManager,\n channels: this.kernel.channels,\n cron: this.automation,\n sessionManager: this.sessionManager,\n requestRestart: async (options) => {\n await this.deps.requestRestart({\n reason: options?.reason ?? \"gateway tool restart\",\n manualMessage: \"Restart the gateway to apply changes.\",\n strategy: \"background-service-or-exit\",\n delayMs: options?.delayMs,\n silentOnServiceRestart: true,\n });\n },\n })\n );\n };\n\n private startSupportServices = async (): Promise<void> => {\n this.extensions.publishConfigChanges();\n await measureStartupAsync(\"service.start_gateway_support_services\", async () =>\n await startGatewayRuntimeSupport({\n automation: this.automation,\n remoteModule: this.remoteManager.remoteModule,\n watchConfigFile: () => watchServiceConfigFile({\n configPath: resolve(getConfigPath()),\n watcherRegistry: this.fileWatchers,\n scheduleReload: (reason) => this.configManager.scheduleReload(reason)\n }),\n watcherRegistry: this.fileWatchers\n })\n );\n };\n\n private installConfigHostHooks = (): void => {\n this.configManager.installRuntimeHooks({\n reloadCompanion: async ({ config: nextConfig }) => {\n await companionRuntimeService.applyConfig(nextConfig);\n },\n onRestartRequired: (paths) => {\n void this.deps.requestRestart({\n changedPaths: paths,\n manualMessage: `已保存以下改动,等待你手动重启后生效:${paths.join(\", \")}`,\n mode: \"notify\",\n reason: `config reload requires restart: ${paths.join(\", \")}`,\n strategy: \"background-service-or-manual\",\n });\n },\n });\n };\n\n private configureIngressHandlers = (): void => {\n this.kernel.extensions.registerIngressHandlers();\n };\n\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nextclaw-gateway-runtime.service.js","names":["getConfigPath","getDataDir","getWorkspacePath","waitForNextTick"],"sources":["../../../../src/shared/services/gateway/nextclaw-gateway-runtime.service.ts"],"sourcesContent":["import * as NextclawCore from \"@nextclaw/core\";\nimport {\n AgentRunClient,\n NextclawKernel,\n runGatewayInboundLoop,\n type AutomationManager,\n type ConfigManager,\n type LlmProviderManager,\n type SessionManager,\n} from \"@nextclaw/kernel\";\nimport type { EventBus, Ingress } from \"@nextclaw/shared\";\nimport {\n startUiServer,\n type MarketplaceApiConfig,\n type UiRouterOptions,\n type UiRuntimeControlHost,\n type UiRuntimeUpdateHost,\n} from \"@nextclaw/server\";\nimport { resolve } from \"node:path\";\nimport { setImmediate as waitForNextTick } from \"node:timers/promises\";\nimport { GatewayControllerImpl } from \"@nextclaw-service/shared/controllers/gateway.controller.js\";\nimport { GatewayExtensionManager } from \"@nextclaw-service/shared/services/gateway/managers/gateway-extension.manager.js\";\nimport { GatewayRemoteManager } from \"@nextclaw-service/shared/services/gateway/managers/gateway-remote.manager.js\";\nimport { GatewayRestartWakeService } from \"@nextclaw-service/shared/services/gateway/gateway-restart-wake.service.js\";\nimport { createCronJobHandler } from \"@nextclaw-service/shared/services/gateway/utils/cron-job-handler.utils.js\";\nimport { companionRuntimeService } from \"@nextclaw-service/shared/services/ui/companion-runtime.service.js\";\nimport { handleGatewayDeferredStartupError } from \"@nextclaw-service/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.js\";\nimport { NextclawApp, type UiStartupHandle } from \"@nextclaw-service/shared/services/gateway/nextclaw-app.service.js\";\nimport { NextclawDistributionService } from \"@nextclaw-service/shared/services/runtime/nextclaw-distribution.service.js\";\nimport { ServiceBootstrapStatusStore } from \"@nextclaw-service/shared/services/gateway/service-bootstrap-status.service.js\";\nimport { ServiceFileWatcherRegistry, markLocalUiRuntimeIfStarted, startGatewayRuntimeSupport, watchServiceConfigFile } from \"@nextclaw-service/shared/services/gateway/service-startup-support.service.js\";\nimport { ServiceMarketplaceInstaller } from \"@nextclaw-service/shared/services/marketplace/service-marketplace-installer.service.js\";\nimport { NpmRuntimeUpdateHost } from \"@nextclaw-service/shared/services/ui/npm-runtime-update-host.service.js\";\nimport { createRuntimeControlHost } from \"@nextclaw-service/shared/services/ui/runtime-control-host.service.js\";\nimport { localUiRuntimeStore } from \"@nextclaw-service/shared/stores/local-ui-runtime.store.js\";\nimport { managedServiceStateStore } from \"@nextclaw-service/shared/stores/managed-service-state.store.js\";\nimport type { RequestRestartParams } from \"@nextclaw-service/shared/types/cli.types.js\";\nimport { openBrowser, resolveUiConfig, resolveUiStaticDir } from \"@nextclaw-service/shared/utils/cli.utils.js\";\nimport { readPanelAppClientSdkScript } from \"@nextclaw-service/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.js\";\nimport { logStartupTrace, measureStartupAsync, measureStartupSync } from \"@nextclaw-service/shared/utils/startup-trace.js\";\n\nconst {\n getConfigPath,\n getDataDir,\n getWorkspacePath,\n} = NextclawCore;\n\nfunction resolveApplyRestartMode(uiPort: number): \"managed-service-restart\" | \"manual-process-restart\" {\n const serviceState = managedServiceStateStore.read();\n if (serviceState?.pid === process.pid) {\n return \"managed-service-restart\";\n }\n if (\n process.env.NEXTCLAW_RUNTIME_BUNDLE_CHILD === \"1\" &&\n typeof serviceState?.uiPort === \"number\" &&\n serviceState.uiPort === uiPort\n ) {\n return \"managed-service-restart\";\n }\n return \"manual-process-restart\";\n}\n\ntype Config = NextclawCore.Config;\ntype MessageBus = NextclawCore.MessageBus;\n\ntype GatewayRuntimeOptions = {\n uiOverrides?: Partial<Config[\"ui\"]>;\n uiStaticDir?: string | null;\n};\n\nexport type GatewayRuntimeDeps = {\n requestRestart: (params: RequestRestartParams) => Promise<void>;\n initializeAgentHomeDirectory: (homeDirectory: string) => void;\n startService: (options: { uiOverrides: Record<string, unknown>; open: boolean }) => Promise<void>;\n stopService: () => Promise<void>;\n runCliSubcommand: (args: string[]) => Promise<string>;\n installBuiltinMarketplaceSkill: (slug: string, force: boolean | undefined) => { message: string; output?: string } | null;\n};\n\nexport class NextclawGatewayRuntime {\n readonly kernel: NextclawKernel;\n readonly appEventBus: EventBus;\n readonly messageBus: MessageBus;\n readonly sessionManager: SessionManager;\n readonly automation: AutomationManager;\n readonly agentRunClient: AgentRunClient;\n readonly runtimeControl: UiRuntimeControlHost;\n readonly runtimeUpdate: UiRuntimeUpdateHost | null;\n readonly ingress: Ingress;\n readonly distribution = NextclawDistributionService.get();\n readonly productVersion: string;\n readonly providerManager: LlmProviderManager;\n readonly gatewayController: GatewayControllerImpl;\n\n readonly configManager: ConfigManager;\n readonly uiConfig: Config[\"ui\"];\n readonly uiStaticDir: string | null;\n readonly workspace: string;\n readonly remoteManager: GatewayRemoteManager;\n readonly marketplace: MarketplaceApiConfig;\n readonly extensions: GatewayExtensionManager;\n readonly restartWake: GatewayRestartWakeService;\n bootstrapStatus: ServiceBootstrapStatusStore;\n uiStartup: UiStartupHandle;\n readonly fileWatchers = new ServiceFileWatcherRegistry();\n private deferredChannelStarter: () => Promise<void>;\n\n constructor(\n private readonly deps: GatewayRuntimeDeps,\n private readonly options: GatewayRuntimeOptions,\n ) {\n const configPath = getConfigPath();\n this.kernel = measureStartupSync(\n \"service.gateway.kernel\",\n () => new NextclawKernel({\n homeDir: getDataDir(),\n configPath,\n }),\n );\n this.configManager = this.kernel.configManager;\n const config = this.configManager.config;\n this.uiConfig = resolveUiConfig(config, options.uiOverrides);\n this.uiStaticDir = options.uiStaticDir === undefined ? resolveUiStaticDir(this.distribution.uiDistDir) : options.uiStaticDir;\n this.workspace = getWorkspacePath(config.agents.defaults.workspace);\n this.appEventBus = this.kernel.eventBus;\n this.ingress = this.kernel.ingress;\n this.agentRunClient = new AgentRunClient({\n eventBus: this.kernel.eventBus,\n ingress: this.kernel.ingress,\n });\n this.messageBus = this.kernel.messageBus;\n this.sessionManager = this.kernel.sessionManager;\n this.automation = this.kernel.automation;\n this.productVersion = this.distribution.version;\n this.extensions = new GatewayExtensionManager(this);\n this.providerManager = this.kernel.llmProviders;\n this.installConfigHostHooks();\n this.restartWake = new GatewayRestartWakeService(this);\n this.bootstrapStatus = this.createBootstrapStatus();\n this.uiStartup = this.createDisabledUiStartup();\n this.remoteManager = new GatewayRemoteManager({\n deps: this.deps,\n configManager: this.configManager,\n uiConfig: this.uiConfig,\n onRemoteStateChange: (state) => this.bootstrapStatus.syncRemoteRuntimeState(state),\n });\n this.marketplace = this.createMarketplace();\n this.runtimeControl = createRuntimeControlHost({\n serviceCommands: this.deps,\n requestRestart: this.deps.requestRestart,\n uiConfig: this.uiConfig,\n });\n this.runtimeUpdate =\n process.env.NEXTCLAW_DISABLE_RUNTIME_UPDATE_HOST === \"1\"\n ? null\n : new NpmRuntimeUpdateHost({\n eventBus: this.appEventBus,\n applyRestartMode: resolveApplyRestartMode(this.uiConfig.port),\n requestRestart: this.deps.requestRestart,\n uiConfig: this.uiConfig,\n });\n this.gatewayController = this.createGatewayController();\n this.kernel.provideGatewayController(this.gatewayController);\n this.deferredChannelStarter = this.startChannels;\n this.automation.onJob = createCronJobHandler({\n agentRunClient: this.agentRunClient,\n });\n }\n\n start = async (): Promise<void> => {\n logStartupTrace(\"service.start_gateway.begin\");\n await this.reset();\n this.configureIngressHandlers();\n this.uiStartup = await this.startUiRuntime();\n await companionRuntimeService.applyConfig(this.configManager.config);\n await this.markUiRuntimeReady();\n await this.startSupportServices();\n await this.runRuntimeLoop();\n await companionRuntimeService.ensureStopped();\n logStartupTrace(\"service.start_gateway.end\");\n };\n\n private reset = async (): Promise<void> => {\n await this.fileWatchers.clear();\n this.bootstrapStatus = this.createBootstrapStatus();\n this.uiStartup = this.createDisabledUiStartup();\n this.deferredChannelStarter = this.startChannels;\n };\n\n private createBootstrapStatus = (): ServiceBootstrapStatusStore => {\n const bootstrapStatus = new ServiceBootstrapStatusStore();\n bootstrapStatus.markChannelsPending();\n bootstrapStatus.setRemoteState(this.configManager.config.remote.enabled ? \"pending\" : \"disabled\");\n return bootstrapStatus;\n };\n\n private createDisabledUiStartup = (): UiStartupHandle => ({\n endpoint: \"\",\n });\n\n private startUiRuntime = async (): Promise<UiStartupHandle> => {\n const uiStartup = await measureStartupAsync(\"service.start_ui_runtime\", async () => {\n logStartupTrace(\"service.start_ui_runtime.begin\");\n if (!this.uiConfig.enabled) {\n return this.createDisabledUiStartup();\n }\n const uiServer = await startUiServer(this.createUiRouterOptions());\n const uiUrl = NextclawCore.resolveLocalUiBaseUrl({\n host: uiServer.host,\n port: uiServer.port,\n });\n console.log(`✓ UI API: ${uiUrl}/api`);\n if (this.uiStaticDir) {\n console.log(`✓ UI frontend: ${uiUrl}`);\n }\n if (this.uiConfig.open) {\n openBrowser(uiUrl);\n }\n logStartupTrace(\"service.start_ui_runtime.ready\", {\n host: uiServer.host,\n port: uiServer.port,\n });\n return {\n endpoint: uiUrl,\n };\n });\n markLocalUiRuntimeIfStarted({\n uiStartup: this.uiConfig.enabled ? uiStartup : null,\n uiConfig: this.uiConfig,\n });\n return uiStartup;\n };\n\n private createUiRouterOptions = (): UiRouterOptions => ({\n kernel: this.kernel,\n configPath: this.configManager.configPath,\n appEventBus: this.appEventBus,\n uiConfig: this.uiConfig,\n uiStaticDir: this.uiStaticDir,\n panelAppClientSdkScript: readPanelAppClientSdkScript,\n productVersion: this.productVersion,\n applyLiveConfigReload: this.configManager.applyLiveConfigReload,\n initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory,\n marketplace: this.marketplace,\n cron: this.automation,\n remoteAccess: this.remoteManager.remoteAccess,\n runtimeControl: this.runtimeControl,\n ...(this.runtimeUpdate ? { runtimeUpdate: this.runtimeUpdate } : {}),\n bootstrapStatus: this.bootstrapStatus,\n extensions: this.extensions,\n });\n\n private runRuntimeLoop = async (): Promise<void> => {\n logStartupTrace(\"service.start_gateway.runtime_loop_begin\");\n let startupTask: Promise<void> | null = null;\n try {\n const runtimeLoopTask = runGatewayInboundLoop(this);\n startupTask = this.startDeferredRuntime();\n void startupTask.catch((error) => handleGatewayDeferredStartupError({\n bootstrapStatus: this.bootstrapStatus,\n error,\n }));\n await runtimeLoopTask;\n } finally {\n if (startupTask) {\n await startupTask.catch(() => undefined);\n }\n await this.cleanup();\n }\n };\n\n private startDeferredRuntime = async (): Promise<void> => {\n const app = new NextclawApp(this);\n await app.start();\n };\n\n readonly startDeferredChannels = async (): Promise<void> => {\n await this.deferredChannelStarter();\n };\n\n private readonly startChannels = async (): Promise<void> => {\n await this.kernel.channels.start();\n const enabledChannels = this.kernel.channels.enabledChannels;\n if (enabledChannels.length > 0) {\n console.log(`✓ Channels enabled: ${enabledChannels.join(\", \")}`);\n } else {\n console.log(\"Warning: No channels enabled\");\n }\n this.bootstrapStatus.markChannelsReady(enabledChannels);\n };\n\n private createMarketplace = (): MarketplaceApiConfig => ({\n apiBaseUrl: process.env.NEXTCLAW_MARKETPLACE_API_BASE,\n installer: new ServiceMarketplaceInstaller({\n applyLiveConfigReload: this.configManager.applyLiveConfigReload,\n runCliSubcommand: this.deps.runCliSubcommand,\n installBuiltinSkill: this.deps.installBuiltinMarketplaceSkill,\n }).createInstaller(),\n });\n\n private cleanup = async (): Promise<void> => {\n localUiRuntimeStore.clearIfOwnedByProcess();\n await this.fileWatchers.clear();\n await this.kernel.extensions.stop();\n await this.remoteManager.stop();\n };\n\n private markUiRuntimeReady = async (): Promise<void> => {\n this.bootstrapStatus.markShellReady();\n await waitForNextTick();\n };\n\n private createGatewayController = (): GatewayControllerImpl => {\n return measureStartupSync(\n \"service.gateway.gateway_controller\",\n () => new GatewayControllerImpl({\n configManager: this.configManager,\n channels: this.kernel.channels,\n cron: this.automation,\n sessionManager: this.sessionManager,\n requestRestart: async (options) => {\n await this.deps.requestRestart({\n reason: options?.reason ?? \"gateway tool restart\",\n manualMessage: \"Restart the gateway to apply changes.\",\n strategy: \"background-service-or-exit\",\n delayMs: options?.delayMs,\n silentOnServiceRestart: true,\n });\n },\n })\n );\n };\n\n private startSupportServices = async (): Promise<void> => {\n this.extensions.publishConfigChanges();\n await measureStartupAsync(\"service.start_gateway_support_services\", async () =>\n await startGatewayRuntimeSupport({\n automation: this.automation,\n remoteModule: this.remoteManager.remoteModule,\n watchConfigFile: () => watchServiceConfigFile({\n configPath: resolve(getConfigPath()),\n watcherRegistry: this.fileWatchers,\n scheduleReload: (reason) => this.configManager.scheduleReload(reason)\n }),\n watcherRegistry: this.fileWatchers\n })\n );\n };\n\n private installConfigHostHooks = (): void => {\n this.configManager.installRuntimeHooks({\n reloadCompanion: async ({ config: nextConfig }) => {\n await companionRuntimeService.applyConfig(nextConfig);\n },\n onRestartRequired: (paths) => {\n void this.deps.requestRestart({\n changedPaths: paths,\n manualMessage: `已保存以下改动,等待你手动重启后生效:${paths.join(\", \")}`,\n mode: \"notify\",\n reason: `config reload requires restart: ${paths.join(\", \")}`,\n strategy: \"background-service-or-manual\",\n });\n },\n });\n };\n\n private configureIngressHandlers = (): void => {\n this.kernel.extensions.registerIngressHandlers();\n };\n\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,MAAM,EACJ,eAAA,iBACA,YAAA,cACA,kBAAA,uBACE;AAEJ,SAAS,wBAAwB,QAAsE;CACrG,MAAM,eAAe,yBAAyB,MAAM;AACpD,KAAI,cAAc,QAAQ,QAAQ,IAChC,QAAO;AAET,KACE,QAAQ,IAAI,kCAAkC,OAC9C,OAAO,cAAc,WAAW,YAChC,aAAa,WAAW,OAExB,QAAO;AAET,QAAO;;AAoBT,IAAa,yBAAb,MAAoC;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,eAAwB,4BAA4B,KAAK;CACzD;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,eAAwB,IAAI,4BAA4B;CACxD;CAEA,YACE,MACA,SACA;AAFiB,OAAA,OAAA;AACA,OAAA,UAAA;EAEjB,MAAM,aAAaA,iBAAe;AAClC,OAAK,SAAS,mBACZ,gCACM,IAAI,eAAe;GACvB,SAASC,cAAY;GACrB;GACD,CAAC,CACH;AACD,OAAK,gBAAgB,KAAK,OAAO;EACjC,MAAM,SAAS,KAAK,cAAc;AAClC,OAAK,WAAW,gBAAgB,QAAQ,QAAQ,YAAY;AAC5D,OAAK,cAAc,QAAQ,gBAAgB,KAAA,IAAY,mBAAmB,KAAK,aAAa,UAAU,GAAG,QAAQ;AACjH,OAAK,YAAYC,mBAAiB,OAAO,OAAO,SAAS,UAAU;AACnE,OAAK,cAAc,KAAK,OAAO;AAC/B,OAAK,UAAU,KAAK,OAAO;AAC3B,OAAK,iBAAiB,IAAI,eAAe;GACvC,UAAU,KAAK,OAAO;GACtB,SAAS,KAAK,OAAO;GACtB,CAAC;AACF,OAAK,aAAa,KAAK,OAAO;AAC9B,OAAK,iBAAiB,KAAK,OAAO;AAClC,OAAK,aAAa,KAAK,OAAO;AAC9B,OAAK,iBAAiB,KAAK,aAAa;AACxC,OAAK,aAAa,IAAI,wBAAwB,KAAK;AACnD,OAAK,kBAAkB,KAAK,OAAO;AACnC,OAAK,wBAAwB;AAC7B,OAAK,cAAc,IAAI,0BAA0B,KAAK;AACtD,OAAK,kBAAkB,KAAK,uBAAuB;AACnD,OAAK,YAAY,KAAK,yBAAyB;AAC/C,OAAK,gBAAgB,IAAI,qBAAqB;GAC5C,MAAM,KAAK;GACX,eAAe,KAAK;GACpB,UAAU,KAAK;GACf,sBAAsB,UAAU,KAAK,gBAAgB,uBAAuB,MAAM;GACnF,CAAC;AACF,OAAK,cAAc,KAAK,mBAAmB;AAC3C,OAAK,iBAAiB,yBAAyB;GAC7C,iBAAiB,KAAK;GACtB,gBAAgB,KAAK,KAAK;GAC1B,UAAU,KAAK;GAChB,CAAC;AACF,OAAK,gBACH,QAAQ,IAAI,yCAAyC,MACjD,OACA,IAAI,qBAAqB;GACvB,UAAU,KAAK;GACf,kBAAkB,wBAAwB,KAAK,SAAS,KAAK;GAC7D,gBAAgB,KAAK,KAAK;GAC1B,UAAU,KAAK;GACtB,CAAC;AACF,OAAK,oBAAoB,KAAK,yBAAyB;AACvD,OAAK,OAAO,yBAAyB,KAAK,kBAAkB;AAC5D,OAAK,yBAAyB,KAAK;AACnC,OAAK,WAAW,QAAQ,qBAAqB,EAC3C,gBAAgB,KAAK,gBACtB,CAAC;;CAGJ,QAAQ,YAA2B;AACjC,kBAAgB,8BAA8B;AAC9C,QAAM,KAAK,OAAO;AAClB,OAAK,0BAA0B;AAC/B,OAAK,YAAY,MAAM,KAAK,gBAAgB;AAC5C,QAAM,wBAAwB,YAAY,KAAK,cAAc,OAAO;AACpE,QAAM,KAAK,oBAAoB;AAC/B,QAAM,KAAK,sBAAsB;AACjC,QAAM,KAAK,gBAAgB;AAC3B,QAAM,wBAAwB,eAAe;AAC7C,kBAAgB,4BAA4B;;CAG9C,QAAgB,YAA2B;AACzC,QAAM,KAAK,aAAa,OAAO;AAC/B,OAAK,kBAAkB,KAAK,uBAAuB;AACnD,OAAK,YAAY,KAAK,yBAAyB;AAC/C,OAAK,yBAAyB,KAAK;;CAGrC,8BAAmE;EACjE,MAAM,kBAAkB,IAAI,6BAA6B;AACzD,kBAAgB,qBAAqB;AACrC,kBAAgB,eAAe,KAAK,cAAc,OAAO,OAAO,UAAU,YAAY,WAAW;AACjG,SAAO;;CAGT,iCAA0D,EACxD,UAAU,IACX;CAED,iBAAyB,YAAsC;EAC7D,MAAM,YAAY,MAAM,oBAAoB,4BAA4B,YAAY;AAClF,mBAAgB,iCAAiC;AACjD,OAAI,CAAC,KAAK,SAAS,QACjB,QAAO,KAAK,yBAAyB;GAEvC,MAAM,WAAW,MAAM,cAAc,KAAK,uBAAuB,CAAC;GAClE,MAAM,QAAQ,aAAa,sBAAsB;IAC/C,MAAM,SAAS;IACf,MAAM,SAAS;IAChB,CAAC;AACF,WAAQ,IAAI,aAAa,MAAM,MAAM;AACrC,OAAI,KAAK,YACP,SAAQ,IAAI,kBAAkB,QAAQ;AAExC,OAAI,KAAK,SAAS,KAChB,aAAY,MAAM;AAEpB,mBAAgB,kCAAkC;IAChD,MAAM,SAAS;IACf,MAAM,SAAS;IAChB,CAAC;AACF,UAAO,EACL,UAAU,OACX;IACD;AACF,8BAA4B;GAC1B,WAAW,KAAK,SAAS,UAAU,YAAY;GAC/C,UAAU,KAAK;GAChB,CAAC;AACF,SAAO;;CAGT,+BAAwD;EACtD,QAAQ,KAAK;EACb,YAAY,KAAK,cAAc;EAC/B,aAAa,KAAK;EAClB,UAAU,KAAK;EACf,aAAa,KAAK;EAClB,yBAAyB;EACzB,gBAAgB,KAAK;EACrB,uBAAuB,KAAK,cAAc;EAC1C,8BAA8B,KAAK,KAAK;EACxC,aAAa,KAAK;EAClB,MAAM,KAAK;EACX,cAAc,KAAK,cAAc;EACjC,gBAAgB,KAAK;EACrB,GAAI,KAAK,gBAAgB,EAAE,eAAe,KAAK,eAAe,GAAG,EAAE;EACnE,iBAAiB,KAAK;EACtB,YAAY,KAAK;EAClB;CAED,iBAAyB,YAA2B;AAClD,kBAAgB,2CAA2C;EAC3D,IAAI,cAAoC;AACxC,MAAI;GACF,MAAM,kBAAkB,sBAAsB,KAAK;AACnD,iBAAc,KAAK,sBAAsB;AACpC,eAAY,OAAO,UAAU,kCAAkC;IAClE,iBAAiB,KAAK;IACtB;IACD,CAAC,CAAC;AACH,SAAM;YACE;AACR,OAAI,YACF,OAAM,YAAY,YAAY,KAAA,EAAU;AAE1C,SAAM,KAAK,SAAS;;;CAIxB,uBAA+B,YAA2B;AAExD,QADY,IAAI,YAAY,KAAK,CACvB,OAAO;;CAGnB,wBAAiC,YAA2B;AAC1D,QAAM,KAAK,wBAAwB;;CAGrC,gBAAiC,YAA2B;AAC1D,QAAM,KAAK,OAAO,SAAS,OAAO;EAClC,MAAM,kBAAkB,KAAK,OAAO,SAAS;AAC7C,MAAI,gBAAgB,SAAS,EAC3B,SAAQ,IAAI,uBAAuB,gBAAgB,KAAK,KAAK,GAAG;MAEhE,SAAQ,IAAI,+BAA+B;AAE7C,OAAK,gBAAgB,kBAAkB,gBAAgB;;CAGzD,2BAAyD;EACvD,YAAY,QAAQ,IAAI;EACxB,WAAW,IAAI,4BAA4B;GACzC,uBAAuB,KAAK,cAAc;GAC1C,kBAAkB,KAAK,KAAK;GAC5B,qBAAqB,KAAK,KAAK;GAChC,CAAC,CAAC,iBAAiB;EACrB;CAED,UAAkB,YAA2B;AAC3C,sBAAoB,uBAAuB;AAC3C,QAAM,KAAK,aAAa,OAAO;AAC/B,QAAM,KAAK,OAAO,WAAW,MAAM;AACnC,QAAM,KAAK,cAAc,MAAM;;CAGjC,qBAA6B,YAA2B;AACtD,OAAK,gBAAgB,gBAAgB;AACrC,QAAMC,cAAiB;;CAGzB,gCAA+D;AAC7D,SAAO,mBACL,4CACM,IAAI,sBAAsB;GAC9B,eAAe,KAAK;GACpB,UAAU,KAAK,OAAO;GACtB,MAAM,KAAK;GACX,gBAAgB,KAAK;GACrB,gBAAgB,OAAO,YAAY;AACjC,UAAM,KAAK,KAAK,eAAe;KAC7B,QAAQ,SAAS,UAAU;KAC3B,eAAe;KACf,UAAU;KACV,SAAS,SAAS;KAClB,wBAAwB;KACzB,CAAC;;GAEL,CAAC,CACH;;CAGH,uBAA+B,YAA2B;AACxD,OAAK,WAAW,sBAAsB;AACtC,QAAM,oBAAoB,0CAA0C,YAClE,MAAM,2BAA2B;GAC/B,YAAY,KAAK;GACjB,cAAc,KAAK,cAAc;GACjC,uBAAuB,uBAAuB;IAC5C,YAAY,QAAQH,iBAAe,CAAC;IACpC,iBAAiB,KAAK;IACtB,iBAAiB,WAAW,KAAK,cAAc,eAAe,OAAO;IACtE,CAAC;GACF,iBAAiB,KAAK;GACvB,CAAC,CACH;;CAGH,+BAA6C;AAC3C,OAAK,cAAc,oBAAoB;GACrC,iBAAiB,OAAO,EAAE,QAAQ,iBAAiB;AACjD,UAAM,wBAAwB,YAAY,WAAW;;GAEvD,oBAAoB,UAAU;AACvB,SAAK,KAAK,eAAe;KAC5B,cAAc;KACd,eAAe,sBAAsB,MAAM,KAAK,KAAK;KACrD,MAAM;KACN,QAAQ,mCAAmC,MAAM,KAAK,KAAK;KAC3D,UAAU;KACX,CAAC;;GAEL,CAAC;;CAGJ,iCAA+C;AAC7C,OAAK,OAAO,WAAW,yBAAyB"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { MessageBus } from "@nextclaw/core";
|
|
2
1
|
import { AgentRunClient } from "@nextclaw/kernel";
|
|
3
2
|
|
|
4
3
|
//#region src/shared/services/gateway/utils/cron-job-handler.utils.d.ts
|
|
@@ -9,15 +8,10 @@ type CronJobLike = {
|
|
|
9
8
|
message: string;
|
|
10
9
|
agentId?: string | null;
|
|
11
10
|
sessionId?: string | null;
|
|
12
|
-
deliver?: boolean;
|
|
13
|
-
channel?: string | null;
|
|
14
|
-
to?: string | null;
|
|
15
|
-
accountId?: string | null;
|
|
16
11
|
};
|
|
17
12
|
};
|
|
18
13
|
declare function createCronJobHandler(params: {
|
|
19
14
|
agentRunClient: AgentRunClient;
|
|
20
|
-
bus: MessageBus;
|
|
21
15
|
}): (job: CronJobLike) => Promise<string>;
|
|
22
16
|
//#endregion
|
|
23
17
|
export { createCronJobHandler };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron-job-handler.utils.d.ts","names":[],"sources":["../../../../../src/shared/services/gateway/utils/cron-job-handler.utils.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"cron-job-handler.utils.d.ts","names":[],"sources":["../../../../../src/shared/services/gateway/utils/cron-job-handler.utils.ts"],"mappings":";;;KAMK,WAAA;EACH,EAAA;EACA,IAAA;EACA,OAAA;IACE,OAAA;IACA,OAAA;IACA,SAAA;EAAA;AAAA;AAAA,iBAqDY,oBAAA,CAAqB,MAAA;EACnC,cAAA,EAAgB,cAAA;AAAA,KACb,GAAA,EAAK,WAAA,KAAgB,OAAA"}
|
|
@@ -5,45 +5,49 @@ function normalizeOptionalString(value) {
|
|
|
5
5
|
return value.trim() || void 0;
|
|
6
6
|
}
|
|
7
7
|
function buildCronSessionMetadata(params) {
|
|
8
|
-
const { job, agentId
|
|
9
|
-
|
|
8
|
+
const { job, agentId } = params;
|
|
9
|
+
return {
|
|
10
10
|
agentId,
|
|
11
|
-
channel: normalizeOptionalString(job.payload.channel) ?? "cli",
|
|
12
|
-
chatId: normalizeOptionalString(job.payload.to) ?? "direct",
|
|
13
11
|
label: job.name,
|
|
14
12
|
cron_job_id: job.id,
|
|
15
13
|
cron_job_name: job.name,
|
|
16
14
|
session_origin: "cron"
|
|
17
15
|
};
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
}
|
|
17
|
+
function readToolFailureMessage(result) {
|
|
18
|
+
if (typeof result === "string" && result.startsWith("Error:")) return result.slice(6).trim() || result;
|
|
19
|
+
if (!result || typeof result !== "object" || !("ok" in result) || result.ok !== false) return null;
|
|
20
|
+
const error = "error" in result ? result.error : null;
|
|
21
|
+
if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
|
|
22
|
+
return "message tool failed";
|
|
23
|
+
}
|
|
24
|
+
function findMessageToolFailure(message) {
|
|
25
|
+
for (const part of message.parts) {
|
|
26
|
+
if (part.type !== "tool-invocation" || part.toolName !== "message" || part.state !== "result") continue;
|
|
27
|
+
const failureMessage = readToolFailureMessage(part.result);
|
|
28
|
+
if (failureMessage) return failureMessage;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
20
31
|
}
|
|
21
32
|
function createCronJobHandler(params) {
|
|
22
33
|
return async (job) => {
|
|
23
|
-
const accountId = normalizeOptionalString(job.payload.accountId);
|
|
24
34
|
const agentId = normalizeOptionalString(job.payload.agentId) ?? "main";
|
|
25
35
|
const sessionId = normalizeOptionalString(job.payload.sessionId) ?? `cron:${job.id}`;
|
|
26
36
|
const metadata = buildCronSessionMetadata({
|
|
27
37
|
job,
|
|
28
|
-
agentId
|
|
29
|
-
accountId
|
|
38
|
+
agentId
|
|
30
39
|
});
|
|
31
|
-
const
|
|
40
|
+
const result = await params.agentRunClient.sendAndWaitForReply(await buildAgentRunSendPayload({
|
|
32
41
|
sessionId,
|
|
33
42
|
content: job.payload.message,
|
|
34
43
|
metadata
|
|
35
44
|
}), {
|
|
36
45
|
missingCompletedMessageError: "cron job completed without a final assistant message",
|
|
37
46
|
runErrorMessage: "cron job failed"
|
|
38
|
-
})).text;
|
|
39
|
-
if (job.payload.deliver && job.payload.to) await params.bus.publishOutbound({
|
|
40
|
-
channel: job.payload.channel ?? "cli",
|
|
41
|
-
chatId: job.payload.to,
|
|
42
|
-
content: response,
|
|
43
|
-
media: [],
|
|
44
|
-
metadata
|
|
45
47
|
});
|
|
46
|
-
|
|
48
|
+
const messageFailure = findMessageToolFailure(result.completedMessage);
|
|
49
|
+
if (messageFailure) throw new Error(`cron message delivery failed: ${messageFailure}`);
|
|
50
|
+
return result.text;
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron-job-handler.utils.js","names":[],"sources":["../../../../../src/shared/services/gateway/utils/cron-job-handler.utils.ts"],"sourcesContent":["import type
|
|
1
|
+
{"version":3,"file":"cron-job-handler.utils.js","names":[],"sources":["../../../../../src/shared/services/gateway/utils/cron-job-handler.utils.ts"],"sourcesContent":["import {\n buildAgentRunSendPayload,\n type AgentRunClient,\n} from \"@nextclaw/kernel\";\nimport type { NcpMessage, NcpToolInvocationPart } from \"@nextclaw/ncp\";\n\ntype CronJobLike = {\n id: string;\n name: string;\n payload: {\n message: string;\n agentId?: string | null;\n sessionId?: string | null;\n };\n};\n\nfunction normalizeOptionalString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction buildCronSessionMetadata(params: {\n job: CronJobLike;\n agentId: string;\n}): Record<string, unknown> {\n const { job, agentId } = params;\n return {\n agentId,\n label: job.name,\n cron_job_id: job.id,\n cron_job_name: job.name,\n session_origin: \"cron\",\n };\n}\n\nfunction readToolFailureMessage(result: unknown): string | null {\n if (typeof result === \"string\" && result.startsWith(\"Error:\")) {\n return result.slice(\"Error:\".length).trim() || result;\n }\n if (!result || typeof result !== \"object\" || !(\"ok\" in result) || result.ok !== false) {\n return null;\n }\n const error = \"error\" in result ? result.error : null;\n if (error && typeof error === \"object\" && \"message\" in error && typeof error.message === \"string\") {\n return error.message;\n }\n return \"message tool failed\";\n}\n\nfunction findMessageToolFailure(message: NcpMessage): string | null {\n for (const part of message.parts) {\n if (part.type !== \"tool-invocation\" || part.toolName !== \"message\" || part.state !== \"result\") {\n continue;\n }\n const failureMessage = readToolFailureMessage((part as NcpToolInvocationPart).result);\n if (failureMessage) {\n return failureMessage;\n }\n }\n return null;\n}\n\nexport function createCronJobHandler(params: {\n agentRunClient: AgentRunClient;\n}): (job: CronJobLike) => Promise<string> {\n return async (job: CronJobLike): Promise<string> => {\n const agentId = normalizeOptionalString(job.payload.agentId) ?? \"main\";\n const sessionId = normalizeOptionalString(job.payload.sessionId) ?? `cron:${job.id}`;\n const metadata = buildCronSessionMetadata({\n job,\n agentId,\n });\n const result = await params.agentRunClient.sendAndWaitForReply(await buildAgentRunSendPayload({\n sessionId,\n content: job.payload.message,\n metadata,\n }), {\n missingCompletedMessageError: \"cron job completed without a final assistant message\",\n runErrorMessage: \"cron job failed\",\n });\n const messageFailure = findMessageToolFailure(result.completedMessage);\n if (messageFailure) {\n throw new Error(`cron message delivery failed: ${messageFailure}`);\n }\n return result.text;\n };\n}\n"],"mappings":";;AAgBA,SAAS,wBAAwB,OAAoC;AACnE,KAAI,OAAO,UAAU,SACnB;AAGF,QADgB,MAAM,MAAM,IACV,KAAA;;AAGpB,SAAS,yBAAyB,QAGN;CAC1B,MAAM,EAAE,KAAK,YAAY;AACzB,QAAO;EACL;EACA,OAAO,IAAI;EACX,aAAa,IAAI;EACjB,eAAe,IAAI;EACnB,gBAAgB;EACjB;;AAGH,SAAS,uBAAuB,QAAgC;AAC9D,KAAI,OAAO,WAAW,YAAY,OAAO,WAAW,SAAS,CAC3D,QAAO,OAAO,MAAM,EAAgB,CAAC,MAAM,IAAI;AAEjD,KAAI,CAAC,UAAU,OAAO,WAAW,YAAY,EAAE,QAAQ,WAAW,OAAO,OAAO,MAC9E,QAAO;CAET,MAAM,QAAQ,WAAW,SAAS,OAAO,QAAQ;AACjD,KAAI,SAAS,OAAO,UAAU,YAAY,aAAa,SAAS,OAAO,MAAM,YAAY,SACvF,QAAO,MAAM;AAEf,QAAO;;AAGT,SAAS,uBAAuB,SAAoC;AAClE,MAAK,MAAM,QAAQ,QAAQ,OAAO;AAChC,MAAI,KAAK,SAAS,qBAAqB,KAAK,aAAa,aAAa,KAAK,UAAU,SACnF;EAEF,MAAM,iBAAiB,uBAAwB,KAA+B,OAAO;AACrF,MAAI,eACF,QAAO;;AAGX,QAAO;;AAGT,SAAgB,qBAAqB,QAEK;AACxC,QAAO,OAAO,QAAsC;EAClD,MAAM,UAAU,wBAAwB,IAAI,QAAQ,QAAQ,IAAI;EAChE,MAAM,YAAY,wBAAwB,IAAI,QAAQ,UAAU,IAAI,QAAQ,IAAI;EAChF,MAAM,WAAW,yBAAyB;GACxC;GACA;GACD,CAAC;EACF,MAAM,SAAS,MAAM,OAAO,eAAe,oBAAoB,MAAM,yBAAyB;GAC5F;GACA,SAAS,IAAI,QAAQ;GACrB;GACD,CAAC,EAAE;GACF,8BAA8B;GAC9B,iBAAiB;GAClB,CAAC;EACF,MAAM,iBAAiB,uBAAuB,OAAO,iBAAiB;AACtE,MAAI,eACF,OAAM,IAAI,MAAM,iCAAiC,iBAAiB;AAEpE,SAAO,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-remote-runtime.utils.d.ts","names":[],"sources":["../../../../../src/shared/services/runtime/utils/service-remote-runtime.utils.ts"],"mappings":";;;;;KA0BK,sBAAA;EACH,GAAA;EACA,KAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA;AAAA;AAAA,KASG,2BAAA;EAAgC,EAAA;EAAU,OAAA;AAAA;EAA0B,EAAA;EAAW,KAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"service-remote-runtime.utils.d.ts","names":[],"sources":["../../../../../src/shared/services/runtime/utils/service-remote-runtime.utils.ts"],"mappings":";;;;;KA0BK,sBAAA;EACH,GAAA;EACA,KAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA;AAAA;AAAA,KASG,2BAAA;EAAgC,EAAA;EAAU,OAAA;AAAA;EAA0B,EAAA;EAAW,KAAA;AAAA;AAAA,iBA4IpE,kCAAA,CAAmC,MAAA;EACjD,WAAA;EACA,QAAA;EACA,UAAA;EACA,GAAA;EACA,kBAAA,IAAsB,GAAA;EACtB,kBAAA,SAA2B,mBAAA;AAAA,IACzB,2BAAA;AAAA,iBAuCY,yBAAA,CAA0B,MAAA;EACxC,UAAA,QAAkB,MAAA;EAClB,SAAA;EACA,WAAA;EACA,mBAAA,IAAuB,KAAA,EAAO,kBAAA;AAAA,IAC5B,mBAAA;AAAA,iBAoBY,8BAAA,CAA+B,MAAA;EAC7C,UAAA,QAAkB,MAAA;EAClB,QAAA,EAAU,IAAA,CAAK,MAAA;EACf,mBAAA;EAA8B,mBAAA,IAAuB,KAAA,EAAO,kBAAA;AAAA,IAC1D,mBAAA;AAAA,iBAcY,+BAAA,CAAgC,MAAA;EAC9C,MAAA,EAAQ,MAAA;EACR,KAAA,GAAQ,mBAAA;EACR,kBAAA;EACA,QAAA,EAAU,sBAAA;AAAA;AAAA,iBAmBI,6BAAA,CAA8B,MAAA;EAC5C,KAAA,GAAQ,mBAAA;EACR,kBAAA;EACA,SAAA;IAAa,KAAA;IAAgB,cAAA;EAAA;EAC7B,QAAA,EAAU,sBAAA;AAAA,IACR,mBAAA"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { isProcessRunning, resolveUiApiBase } from "../../../utils/cli.utils.js";
|
|
2
2
|
import { managedServiceStateStore } from "../../../stores/managed-service-state.store.js";
|
|
3
3
|
import { buildNextclawConfiguredRemoteState, createNextclawRemoteConnector, createNextclawRemoteStatusStore } from "../../../../commands/remote/utils/remote-runtime-support.utils.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getRunPath } from "@nextclaw/core";
|
|
5
5
|
import { RemoteServiceModule } from "@nextclaw/remote";
|
|
6
6
|
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, resolve } from "node:path";
|
|
8
8
|
//#region src/shared/services/runtime/utils/service-remote-runtime.utils.ts
|
|
9
9
|
function resolveRemoteOwnershipLockPath() {
|
|
10
|
-
return resolve(
|
|
10
|
+
return resolve(getRunPath(), "remote-owner.lock.json");
|
|
11
11
|
}
|
|
12
12
|
function readRemoteOwnershipRecord(lockPath) {
|
|
13
13
|
try {
|
|
@@ -57,15 +57,16 @@ function detectManagedRemoteOwnershipConflict(params) {
|
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
function tryClaimRemoteOwnershipLock(params) {
|
|
60
|
+
const { claim, currentPid, isProcessRunningFn, lockPath } = params;
|
|
60
61
|
for (let attempt = 0; attempt < 2; attempt += 1) try {
|
|
61
|
-
const fd = openSync(
|
|
62
|
-
writeFileSync(fd, `${JSON.stringify(
|
|
62
|
+
const fd = openSync(lockPath, "wx");
|
|
63
|
+
writeFileSync(fd, `${JSON.stringify(claim, null, 2)}\n`, "utf-8");
|
|
63
64
|
closeSync(fd);
|
|
64
65
|
return {
|
|
65
66
|
ok: true,
|
|
66
67
|
release: createRemoteOwnershipRelease({
|
|
67
|
-
lockPath
|
|
68
|
-
claim
|
|
68
|
+
lockPath,
|
|
69
|
+
claim
|
|
69
70
|
})
|
|
70
71
|
};
|
|
71
72
|
} catch (error) {
|
|
@@ -73,12 +74,12 @@ function tryClaimRemoteOwnershipLock(params) {
|
|
|
73
74
|
ok: false,
|
|
74
75
|
error: `Failed to claim local remote runtime ownership: ${error instanceof Error ? error.message : String(error)}`
|
|
75
76
|
};
|
|
76
|
-
const existing = readRemoteOwnershipRecord(
|
|
77
|
-
if (existing && existing.pid !==
|
|
77
|
+
const existing = readRemoteOwnershipRecord(lockPath);
|
|
78
|
+
if (existing && existing.pid !== currentPid && isProcessRunningFn(existing.pid)) return {
|
|
78
79
|
ok: false,
|
|
79
80
|
error: buildLocalProcessOwnershipError(existing)
|
|
80
81
|
};
|
|
81
|
-
removeRemoteOwnershipLock(
|
|
82
|
+
removeRemoteOwnershipLock(lockPath);
|
|
82
83
|
}
|
|
83
84
|
return {
|
|
84
85
|
ok: false,
|
|
@@ -86,14 +87,15 @@ function tryClaimRemoteOwnershipLock(params) {
|
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
89
|
function claimManagedRemoteRuntimeOwnership(params) {
|
|
89
|
-
const lockPath = params
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const
|
|
90
|
+
const { localOrigin, lockPath: lockPathOverride, currentPid: currentPidOverride, now: nowOverride, isProcessRunningFn: isProcessRunningOverride, readServiceStateFn: readServiceStateOverride } = params;
|
|
91
|
+
const lockPath = lockPathOverride ?? resolveRemoteOwnershipLockPath();
|
|
92
|
+
const currentPid = currentPidOverride ?? process.pid;
|
|
93
|
+
const now = nowOverride ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
94
|
+
const isProcessRunningFn = isProcessRunningOverride ?? isProcessRunning;
|
|
93
95
|
const managedConflict = detectManagedRemoteOwnershipConflict({
|
|
94
96
|
currentPid,
|
|
95
97
|
isProcessRunningFn,
|
|
96
|
-
readServiceStateFn:
|
|
98
|
+
readServiceStateFn: readServiceStateOverride ?? managedServiceStateStore.read
|
|
97
99
|
});
|
|
98
100
|
if (managedConflict) return {
|
|
99
101
|
ok: false,
|
|
@@ -104,7 +106,7 @@ function claimManagedRemoteRuntimeOwnership(params) {
|
|
|
104
106
|
lockPath,
|
|
105
107
|
claim: {
|
|
106
108
|
pid: currentPid,
|
|
107
|
-
localOrigin
|
|
109
|
+
localOrigin,
|
|
108
110
|
claimedAt: now()
|
|
109
111
|
},
|
|
110
112
|
currentPid,
|
|
@@ -112,14 +114,15 @@ function claimManagedRemoteRuntimeOwnership(params) {
|
|
|
112
114
|
});
|
|
113
115
|
}
|
|
114
116
|
function createManagedRemoteModule(params) {
|
|
115
|
-
|
|
117
|
+
const { loadConfig, localOrigin, onRemoteStateChange, uiEnabled } = params;
|
|
118
|
+
if (!uiEnabled) return null;
|
|
116
119
|
return new RemoteServiceModule({
|
|
117
|
-
loadConfig
|
|
118
|
-
uiEnabled
|
|
119
|
-
localOrigin
|
|
120
|
-
statusStore: createNextclawRemoteStatusStore("service",
|
|
120
|
+
loadConfig,
|
|
121
|
+
uiEnabled,
|
|
122
|
+
localOrigin,
|
|
123
|
+
statusStore: createNextclawRemoteStatusStore("service", onRemoteStateChange),
|
|
121
124
|
createConnector: (logger) => createNextclawRemoteConnector({ logger }),
|
|
122
|
-
claimOwnership: () => claimManagedRemoteRuntimeOwnership({ localOrigin
|
|
125
|
+
claimOwnership: () => claimManagedRemoteRuntimeOwnership({ localOrigin }),
|
|
123
126
|
logger: {
|
|
124
127
|
info: (message) => console.log(`[remote] ${message}`),
|
|
125
128
|
warn: (message) => console.warn(`[remote] ${message}`),
|
|
@@ -128,12 +131,13 @@ function createManagedRemoteModule(params) {
|
|
|
128
131
|
});
|
|
129
132
|
}
|
|
130
133
|
function createManagedRemoteModuleForUi(params) {
|
|
131
|
-
const
|
|
134
|
+
const { loadConfig, localOriginOverride, onRemoteStateChange, uiConfig } = params;
|
|
135
|
+
const explicitLocalOrigin = localOriginOverride?.trim() ?? process.env.NEXTCLAW_REMOTE_LOCAL_ORIGIN?.trim();
|
|
132
136
|
return createManagedRemoteModule({
|
|
133
|
-
loadConfig
|
|
134
|
-
uiEnabled:
|
|
135
|
-
onRemoteStateChange
|
|
136
|
-
localOrigin: explicitLocalOrigin && explicitLocalOrigin.length > 0 ? explicitLocalOrigin.replace(/\/+$/, "") : resolveUiApiBase(
|
|
137
|
+
loadConfig,
|
|
138
|
+
uiEnabled: uiConfig.enabled,
|
|
139
|
+
onRemoteStateChange,
|
|
140
|
+
localOrigin: explicitLocalOrigin && explicitLocalOrigin.length > 0 ? explicitLocalOrigin.replace(/\/+$/, "") : resolveUiApiBase(uiConfig.host, uiConfig.port)
|
|
137
141
|
});
|
|
138
142
|
}
|
|
139
143
|
function writeInitialManagedServiceState(params) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-remote-runtime.utils.js","names":[],"sources":["../../../../../src/shared/services/runtime/utils/service-remote-runtime.utils.ts"],"sourcesContent":["import type { Config } from \"@nextclaw/core\";\nimport { RemoteServiceModule, type RemoteRuntimeState } from \"@nextclaw/remote\";\nimport {\n closeSync,\n existsSync,\n mkdirSync,\n openSync,\n readFileSync,\n rmSync,\n unlinkSync,\n writeFileSync\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { getDataDir } from \"@nextclaw/core\";\nimport { resolveUiApiBase, isProcessRunning } from \"@nextclaw-service/shared/utils/cli.utils.js\";\nimport {\n managedServiceStateStore,\n type ManagedServiceLease,\n type ManagedServiceState\n} from \"@nextclaw-service/shared/stores/managed-service-state.store.js\";\nimport {\n buildNextclawConfiguredRemoteState,\n createNextclawRemoteConnector,\n createNextclawRemoteStatusStore\n} from \"@nextclaw-service/commands/remote/utils/remote-runtime-support.utils.js\";\n\ntype ManagedServiceSnapshot = {\n pid: number;\n uiUrl: string;\n apiUrl: string;\n uiHost: string;\n uiPort: number;\n logPath: string;\n};\n\ntype RemoteRuntimeOwnerRecord = {\n pid: number;\n localOrigin: string;\n claimedAt: string;\n};\n\ntype RemoteRuntimeOwnershipClaim = { ok: true; release: () => void } | { ok: false; error: string };\n\nfunction resolveRemoteOwnershipLockPath(): string {\n return resolve(getDataDir(), \"run\", \"remote-owner.lock.json\");\n}\n\nfunction readRemoteOwnershipRecord(lockPath: string): RemoteRuntimeOwnerRecord | null {\n try {\n const raw = JSON.parse(readFileSync(lockPath, \"utf-8\")) as Partial<RemoteRuntimeOwnerRecord>;\n if (typeof raw.pid !== \"number\" || !Number.isFinite(raw.pid)) {\n return null;\n }\n return {\n pid: raw.pid,\n localOrigin: typeof raw.localOrigin === \"string\" ? raw.localOrigin : \"\",\n claimedAt: typeof raw.claimedAt === \"string\" ? raw.claimedAt : \"\"\n };\n } catch {\n return null;\n }\n}\n\nfunction removeRemoteOwnershipLock(lockPath: string): void {\n if (!existsSync(lockPath)) {\n return;\n }\n try {\n unlinkSync(lockPath);\n } catch {\n try {\n rmSync(lockPath, { force: true });\n } catch {\n // Ignore cleanup failures.\n }\n }\n}\n\nfunction buildManagedServiceOwnershipError(params: {\n pid: number;\n ownerOrigin?: string;\n}): string {\n return (\n `Remote access is already owned by running NextClaw service PID ${params.pid}`\n + `${params.ownerOrigin ? ` (${params.ownerOrigin})` : \"\"}. `\n + \"Stop that service or disable remote there before starting another process with the same NEXTCLAW_HOME.\"\n );\n}\n\nfunction buildLocalProcessOwnershipError(record: RemoteRuntimeOwnerRecord): string {\n const originText = record.localOrigin ? ` (${record.localOrigin})` : \"\";\n return (\n `Remote access is already owned by local NextClaw process PID ${record.pid}${originText}. `\n + \"Stop that process or use a different NEXTCLAW_HOME before starting another remote-enabled process.\"\n );\n}\n\nfunction createRemoteOwnershipRelease(params: {\n lockPath: string;\n claim: RemoteRuntimeOwnerRecord;\n}): () => void {\n let released = false;\n return () => {\n if (released) {\n return;\n }\n released = true;\n const current = readRemoteOwnershipRecord(params.lockPath);\n if (!current || (current.pid === params.claim.pid && current.claimedAt === params.claim.claimedAt)) {\n removeRemoteOwnershipLock(params.lockPath);\n }\n };\n}\n\nfunction detectManagedRemoteOwnershipConflict(params: {\n currentPid: number;\n isProcessRunningFn: (pid: number) => boolean;\n readServiceStateFn: () => ManagedServiceState | null;\n}): string | null {\n const runningService = params.readServiceStateFn();\n if (\n !runningService\n || runningService.pid === params.currentPid\n || !params.isProcessRunningFn(runningService.pid)\n || !runningService.remote?.enabled\n ) {\n return null;\n }\n\n return buildManagedServiceOwnershipError({\n pid: runningService.pid,\n ownerOrigin: runningService.remote.localOrigin ?? runningService.uiUrl\n });\n}\n\nfunction tryClaimRemoteOwnershipLock(params: {\n lockPath: string;\n claim: RemoteRuntimeOwnerRecord;\n currentPid: number;\n isProcessRunningFn: (pid: number) => boolean;\n}): RemoteRuntimeOwnershipClaim {\n for (let attempt = 0; attempt < 2; attempt += 1) {\n try {\n const fd = openSync(params.lockPath, \"wx\");\n writeFileSync(fd, `${JSON.stringify(params.claim, null, 2)}\\n`, \"utf-8\");\n closeSync(fd);\n return {\n ok: true,\n release: createRemoteOwnershipRelease({\n lockPath: params.lockPath,\n claim: params.claim\n })\n };\n } catch (error) {\n const code = typeof error === \"object\" && error && \"code\" in error ? String(error.code) : \"\";\n if (code !== \"EEXIST\") {\n return {\n ok: false,\n error: `Failed to claim local remote runtime ownership: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n\n const existing = readRemoteOwnershipRecord(params.lockPath);\n if (existing && existing.pid !== params.currentPid && params.isProcessRunningFn(existing.pid)) {\n return {\n ok: false,\n error: buildLocalProcessOwnershipError(existing)\n };\n }\n\n removeRemoteOwnershipLock(params.lockPath);\n }\n }\n\n return {\n ok: false,\n error: \"Failed to claim local remote runtime ownership after clearing a stale lock.\"\n };\n}\n\nexport function claimManagedRemoteRuntimeOwnership(params: {\n localOrigin: string;\n lockPath?: string;\n currentPid?: number;\n now?: () => string;\n isProcessRunningFn?: (pid: number) => boolean;\n readServiceStateFn?: () => ManagedServiceState | null;\n}): RemoteRuntimeOwnershipClaim {\n const lockPath = params.lockPath ?? resolveRemoteOwnershipLockPath();\n const currentPid = params.currentPid ?? process.pid;\n const now = params.now ?? (() => new Date().toISOString());\n const isProcessRunningFn = params.isProcessRunningFn ?? isProcessRunning;\n const readServiceStateFn = params.readServiceStateFn ?? managedServiceStateStore.read;\n const managedConflict = detectManagedRemoteOwnershipConflict({\n currentPid,\n isProcessRunningFn,\n readServiceStateFn\n });\n if (managedConflict) {\n return {\n ok: false,\n error: managedConflict\n };\n }\n\n mkdirSync(dirname(lockPath), { recursive: true });\n return tryClaimRemoteOwnershipLock({\n lockPath,\n claim: {\n pid: currentPid,\n localOrigin: params.localOrigin,\n claimedAt: now()\n },\n currentPid,\n isProcessRunningFn\n });\n}\n\nexport function createManagedRemoteModule(params: {\n loadConfig: () => Config;\n uiEnabled: boolean;\n localOrigin: string;\n onRemoteStateChange?: (state: RemoteRuntimeState) => void;\n}): RemoteServiceModule | null {\n if (!params.uiEnabled) {\n return null;\n }\n return new RemoteServiceModule({\n loadConfig: params.loadConfig,\n uiEnabled: params.uiEnabled,\n localOrigin: params.localOrigin,\n statusStore: createNextclawRemoteStatusStore(\"service\", params.onRemoteStateChange),\n createConnector: (logger) => createNextclawRemoteConnector({ logger }),\n claimOwnership: () => claimManagedRemoteRuntimeOwnership({ localOrigin: params.localOrigin }),\n logger: {\n info: (message) => console.log(`[remote] ${message}`),\n warn: (message) => console.warn(`[remote] ${message}`),\n error: (message) => console.error(`[remote] ${message}`)\n }\n });\n}\n\nexport function createManagedRemoteModuleForUi(params: {\n loadConfig: () => Config;\n uiConfig: Pick<Config[\"ui\"], \"enabled\" | \"host\" | \"port\">;\n localOriginOverride?: string; onRemoteStateChange?: (state: RemoteRuntimeState) => void;\n}): RemoteServiceModule | null {\n const explicitLocalOrigin = params.localOriginOverride?.trim() ?? process.env.NEXTCLAW_REMOTE_LOCAL_ORIGIN?.trim();\n return createManagedRemoteModule({\n loadConfig: params.loadConfig,\n uiEnabled: params.uiConfig.enabled,\n onRemoteStateChange: params.onRemoteStateChange,\n localOrigin:\n explicitLocalOrigin && explicitLocalOrigin.length > 0\n ? explicitLocalOrigin.replace(/\\/+$/, \"\")\n : resolveUiApiBase(params.uiConfig.host, params.uiConfig.port)\n });\n}\n\nexport function writeInitialManagedServiceState(params: {\n config: Config;\n lease?: ManagedServiceLease;\n readinessTimeoutMs: number;\n snapshot: ManagedServiceSnapshot;\n}): void {\n const { config, lease, readinessTimeoutMs, snapshot } = params;\n managedServiceStateStore.write({\n pid: snapshot.pid,\n startedAt: new Date().toISOString(),\n uiUrl: snapshot.uiUrl,\n apiUrl: snapshot.apiUrl,\n uiHost: snapshot.uiHost,\n uiPort: snapshot.uiPort,\n logPath: snapshot.logPath,\n ...(lease ? { lease } : {}),\n startupLastProbeError: null,\n startupTimeoutMs: readinessTimeoutMs,\n startupCheckedAt: new Date().toISOString(),\n ...(config.remote.enabled ? { remote: buildNextclawConfiguredRemoteState(config) } : {})\n });\n}\n\nexport function writeReadyManagedServiceState(params: {\n lease?: ManagedServiceLease;\n readinessTimeoutMs: number;\n readiness: { ready: boolean; lastProbeError: string | null };\n snapshot: ManagedServiceSnapshot;\n}): ManagedServiceState {\n const { lease, readiness, readinessTimeoutMs, snapshot } = params;\n const currentState = managedServiceStateStore.read();\n const state: ManagedServiceState = {\n pid: snapshot.pid,\n startedAt: currentState?.startedAt ?? new Date().toISOString(),\n uiUrl: snapshot.uiUrl,\n apiUrl: snapshot.apiUrl,\n uiHost: snapshot.uiHost,\n uiPort: snapshot.uiPort,\n logPath: snapshot.logPath,\n ...(lease ? { lease } : currentState?.lease ? { lease: currentState.lease } : {}),\n startupState: readiness.ready ? \"ready\" : \"degraded\",\n startupLastProbeError: readiness.lastProbeError,\n startupTimeoutMs: readinessTimeoutMs,\n startupCheckedAt: new Date().toISOString(),\n ...(currentState?.remote ? { remote: currentState.remote } : {})\n };\n managedServiceStateStore.write(state);\n return state;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service-remote-runtime.utils.js","names":[],"sources":["../../../../../src/shared/services/runtime/utils/service-remote-runtime.utils.ts"],"sourcesContent":["import type { Config } from \"@nextclaw/core\";\nimport { RemoteServiceModule, type RemoteRuntimeState } from \"@nextclaw/remote\";\nimport {\n closeSync,\n existsSync,\n mkdirSync,\n openSync,\n readFileSync,\n rmSync,\n unlinkSync,\n writeFileSync\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { getRunPath } from \"@nextclaw/core\";\nimport { resolveUiApiBase, isProcessRunning } from \"@nextclaw-service/shared/utils/cli.utils.js\";\nimport {\n managedServiceStateStore,\n type ManagedServiceLease,\n type ManagedServiceState\n} from \"@nextclaw-service/shared/stores/managed-service-state.store.js\";\nimport {\n buildNextclawConfiguredRemoteState,\n createNextclawRemoteConnector,\n createNextclawRemoteStatusStore\n} from \"@nextclaw-service/commands/remote/utils/remote-runtime-support.utils.js\";\n\ntype ManagedServiceSnapshot = {\n pid: number;\n uiUrl: string;\n apiUrl: string;\n uiHost: string;\n uiPort: number;\n logPath: string;\n};\n\ntype RemoteRuntimeOwnerRecord = {\n pid: number;\n localOrigin: string;\n claimedAt: string;\n};\n\ntype RemoteRuntimeOwnershipClaim = { ok: true; release: () => void } | { ok: false; error: string };\n\nfunction resolveRemoteOwnershipLockPath(): string {\n return resolve(getRunPath(), \"remote-owner.lock.json\");\n}\n\nfunction readRemoteOwnershipRecord(lockPath: string): RemoteRuntimeOwnerRecord | null {\n try {\n const raw = JSON.parse(readFileSync(lockPath, \"utf-8\")) as Partial<RemoteRuntimeOwnerRecord>;\n if (typeof raw.pid !== \"number\" || !Number.isFinite(raw.pid)) {\n return null;\n }\n return {\n pid: raw.pid,\n localOrigin: typeof raw.localOrigin === \"string\" ? raw.localOrigin : \"\",\n claimedAt: typeof raw.claimedAt === \"string\" ? raw.claimedAt : \"\"\n };\n } catch {\n return null;\n }\n}\n\nfunction removeRemoteOwnershipLock(lockPath: string): void {\n if (!existsSync(lockPath)) {\n return;\n }\n try {\n unlinkSync(lockPath);\n } catch {\n try {\n rmSync(lockPath, { force: true });\n } catch {\n // Ignore cleanup failures.\n }\n }\n}\n\nfunction buildManagedServiceOwnershipError(params: {\n pid: number;\n ownerOrigin?: string;\n}): string {\n return (\n `Remote access is already owned by running NextClaw service PID ${params.pid}`\n + `${params.ownerOrigin ? ` (${params.ownerOrigin})` : \"\"}. `\n + \"Stop that service or disable remote there before starting another process with the same NEXTCLAW_HOME.\"\n );\n}\n\nfunction buildLocalProcessOwnershipError(record: RemoteRuntimeOwnerRecord): string {\n const originText = record.localOrigin ? ` (${record.localOrigin})` : \"\";\n return (\n `Remote access is already owned by local NextClaw process PID ${record.pid}${originText}. `\n + \"Stop that process or use a different NEXTCLAW_HOME before starting another remote-enabled process.\"\n );\n}\n\nfunction createRemoteOwnershipRelease(params: {\n lockPath: string;\n claim: RemoteRuntimeOwnerRecord;\n}): () => void {\n let released = false;\n return () => {\n if (released) {\n return;\n }\n released = true;\n const current = readRemoteOwnershipRecord(params.lockPath);\n if (!current || (current.pid === params.claim.pid && current.claimedAt === params.claim.claimedAt)) {\n removeRemoteOwnershipLock(params.lockPath);\n }\n };\n}\n\nfunction detectManagedRemoteOwnershipConflict(params: {\n currentPid: number;\n isProcessRunningFn: (pid: number) => boolean;\n readServiceStateFn: () => ManagedServiceState | null;\n}): string | null {\n const runningService = params.readServiceStateFn();\n if (\n !runningService\n || runningService.pid === params.currentPid\n || !params.isProcessRunningFn(runningService.pid)\n || !runningService.remote?.enabled\n ) {\n return null;\n }\n\n return buildManagedServiceOwnershipError({\n pid: runningService.pid,\n ownerOrigin: runningService.remote.localOrigin ?? runningService.uiUrl\n });\n}\n\nfunction tryClaimRemoteOwnershipLock(params: {\n lockPath: string;\n claim: RemoteRuntimeOwnerRecord;\n currentPid: number;\n isProcessRunningFn: (pid: number) => boolean;\n}): RemoteRuntimeOwnershipClaim {\n const { claim, currentPid, isProcessRunningFn, lockPath } = params;\n for (let attempt = 0; attempt < 2; attempt += 1) {\n try {\n const fd = openSync(lockPath, \"wx\");\n writeFileSync(fd, `${JSON.stringify(claim, null, 2)}\\n`, \"utf-8\");\n closeSync(fd);\n return {\n ok: true,\n release: createRemoteOwnershipRelease({\n lockPath,\n claim\n })\n };\n } catch (error) {\n const code = typeof error === \"object\" && error && \"code\" in error ? String(error.code) : \"\";\n if (code !== \"EEXIST\") {\n return {\n ok: false,\n error: `Failed to claim local remote runtime ownership: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n\n const existing = readRemoteOwnershipRecord(lockPath);\n if (existing && existing.pid !== currentPid && isProcessRunningFn(existing.pid)) {\n return {\n ok: false,\n error: buildLocalProcessOwnershipError(existing)\n };\n }\n\n removeRemoteOwnershipLock(lockPath);\n }\n }\n\n return {\n ok: false,\n error: \"Failed to claim local remote runtime ownership after clearing a stale lock.\"\n };\n}\n\nexport function claimManagedRemoteRuntimeOwnership(params: {\n localOrigin: string;\n lockPath?: string;\n currentPid?: number;\n now?: () => string;\n isProcessRunningFn?: (pid: number) => boolean;\n readServiceStateFn?: () => ManagedServiceState | null;\n}): RemoteRuntimeOwnershipClaim {\n const {\n localOrigin,\n lockPath: lockPathOverride,\n currentPid: currentPidOverride,\n now: nowOverride,\n isProcessRunningFn: isProcessRunningOverride,\n readServiceStateFn: readServiceStateOverride\n } = params;\n const lockPath = lockPathOverride ?? resolveRemoteOwnershipLockPath();\n const currentPid = currentPidOverride ?? process.pid;\n const now = nowOverride ?? (() => new Date().toISOString());\n const isProcessRunningFn = isProcessRunningOverride ?? isProcessRunning;\n const readServiceStateFn = readServiceStateOverride ?? managedServiceStateStore.read;\n const managedConflict = detectManagedRemoteOwnershipConflict({\n currentPid,\n isProcessRunningFn,\n readServiceStateFn\n });\n if (managedConflict) {\n return {\n ok: false,\n error: managedConflict\n };\n }\n\n mkdirSync(dirname(lockPath), { recursive: true });\n return tryClaimRemoteOwnershipLock({\n lockPath,\n claim: {\n pid: currentPid,\n localOrigin,\n claimedAt: now()\n },\n currentPid,\n isProcessRunningFn\n });\n}\n\nexport function createManagedRemoteModule(params: {\n loadConfig: () => Config;\n uiEnabled: boolean;\n localOrigin: string;\n onRemoteStateChange?: (state: RemoteRuntimeState) => void;\n}): RemoteServiceModule | null {\n const { loadConfig, localOrigin, onRemoteStateChange, uiEnabled } = params;\n if (!uiEnabled) {\n return null;\n }\n return new RemoteServiceModule({\n loadConfig,\n uiEnabled,\n localOrigin,\n statusStore: createNextclawRemoteStatusStore(\"service\", onRemoteStateChange),\n createConnector: (logger) => createNextclawRemoteConnector({ logger }),\n claimOwnership: () => claimManagedRemoteRuntimeOwnership({ localOrigin }),\n logger: {\n info: (message) => console.log(`[remote] ${message}`),\n warn: (message) => console.warn(`[remote] ${message}`),\n error: (message) => console.error(`[remote] ${message}`)\n }\n });\n}\n\nexport function createManagedRemoteModuleForUi(params: {\n loadConfig: () => Config;\n uiConfig: Pick<Config[\"ui\"], \"enabled\" | \"host\" | \"port\">;\n localOriginOverride?: string; onRemoteStateChange?: (state: RemoteRuntimeState) => void;\n}): RemoteServiceModule | null {\n const { loadConfig, localOriginOverride, onRemoteStateChange, uiConfig } = params;\n const explicitLocalOrigin = localOriginOverride?.trim() ?? process.env.NEXTCLAW_REMOTE_LOCAL_ORIGIN?.trim();\n return createManagedRemoteModule({\n loadConfig,\n uiEnabled: uiConfig.enabled,\n onRemoteStateChange,\n localOrigin:\n explicitLocalOrigin && explicitLocalOrigin.length > 0\n ? explicitLocalOrigin.replace(/\\/+$/, \"\")\n : resolveUiApiBase(uiConfig.host, uiConfig.port)\n });\n}\n\nexport function writeInitialManagedServiceState(params: {\n config: Config;\n lease?: ManagedServiceLease;\n readinessTimeoutMs: number;\n snapshot: ManagedServiceSnapshot;\n}): void {\n const { config, lease, readinessTimeoutMs, snapshot } = params;\n managedServiceStateStore.write({\n pid: snapshot.pid,\n startedAt: new Date().toISOString(),\n uiUrl: snapshot.uiUrl,\n apiUrl: snapshot.apiUrl,\n uiHost: snapshot.uiHost,\n uiPort: snapshot.uiPort,\n logPath: snapshot.logPath,\n ...(lease ? { lease } : {}),\n startupLastProbeError: null,\n startupTimeoutMs: readinessTimeoutMs,\n startupCheckedAt: new Date().toISOString(),\n ...(config.remote.enabled ? { remote: buildNextclawConfiguredRemoteState(config) } : {})\n });\n}\n\nexport function writeReadyManagedServiceState(params: {\n lease?: ManagedServiceLease;\n readinessTimeoutMs: number;\n readiness: { ready: boolean; lastProbeError: string | null };\n snapshot: ManagedServiceSnapshot;\n}): ManagedServiceState {\n const { lease, readiness, readinessTimeoutMs, snapshot } = params;\n const currentState = managedServiceStateStore.read();\n const state: ManagedServiceState = {\n pid: snapshot.pid,\n startedAt: currentState?.startedAt ?? new Date().toISOString(),\n uiUrl: snapshot.uiUrl,\n apiUrl: snapshot.apiUrl,\n uiHost: snapshot.uiHost,\n uiPort: snapshot.uiPort,\n logPath: snapshot.logPath,\n ...(lease ? { lease } : currentState?.lease ? { lease: currentState.lease } : {}),\n startupState: readiness.ready ? \"ready\" : \"degraded\",\n startupLastProbeError: readiness.lastProbeError,\n startupTimeoutMs: readinessTimeoutMs,\n startupCheckedAt: new Date().toISOString(),\n ...(currentState?.remote ? { remote: currentState.remote } : {})\n };\n managedServiceStateStore.write(state);\n return state;\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRunPath } from "@nextclaw/core";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
//#region src/shared/stores/companion-runtime.store.ts
|
|
5
5
|
var CompanionRuntimeStore = class {
|
|
6
6
|
get path() {
|
|
7
|
-
return resolve(
|
|
7
|
+
return resolve(getRunPath(), "companion.json");
|
|
8
8
|
}
|
|
9
9
|
read = () => {
|
|
10
10
|
if (!existsSync(this.path)) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"companion-runtime.store.js","names":[],"sources":["../../../src/shared/stores/companion-runtime.store.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {
|
|
1
|
+
{"version":3,"file":"companion-runtime.store.js","names":[],"sources":["../../../src/shared/stores/companion-runtime.store.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { getRunPath } from \"@nextclaw/core\";\n\nexport type CompanionRuntimeState = {\n pid: number;\n startedAt: string;\n baseUrl: string;\n};\n\nexport class CompanionRuntimeStore {\n get path(): string {\n return resolve(getRunPath(), \"companion.json\");\n }\n\n readonly read = (): CompanionRuntimeState | null => {\n if (!existsSync(this.path)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(this.path, \"utf-8\")) as CompanionRuntimeState;\n } catch {\n return null;\n }\n };\n\n readonly write = (state: CompanionRuntimeState): void => {\n mkdirSync(resolve(this.path, \"..\"), { recursive: true });\n writeFileSync(this.path, JSON.stringify(state, null, 2));\n };\n\n readonly clear = (): void => {\n if (existsSync(this.path)) {\n rmSync(this.path, { force: true });\n }\n };\n}\n\nexport const companionRuntimeStore = new CompanionRuntimeStore();\n"],"mappings":";;;;AAUA,IAAa,wBAAb,MAAmC;CACjC,IAAI,OAAe;AACjB,SAAO,QAAQ,YAAY,EAAE,iBAAiB;;CAGhD,aAAoD;AAClD,MAAI,CAAC,WAAW,KAAK,KAAK,CACxB,QAAO;AAET,MAAI;AACF,UAAO,KAAK,MAAM,aAAa,KAAK,MAAM,QAAQ,CAAC;UAC7C;AACN,UAAO;;;CAIX,SAAkB,UAAuC;AACvD,YAAU,QAAQ,KAAK,MAAM,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AACxD,gBAAc,KAAK,MAAM,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;;CAG1D,cAA6B;AAC3B,MAAI,WAAW,KAAK,KAAK,CACvB,QAAO,KAAK,MAAM,EAAE,OAAO,MAAM,CAAC;;;AAKxC,MAAa,wBAAwB,IAAI,uBAAuB"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { resolveUiApiBase } from "../utils/cli.utils.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getRunPath } from "@nextclaw/core";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
//#region src/shared/stores/local-ui-runtime.store.ts
|
|
6
6
|
var LocalUiRuntimeStore = class {
|
|
7
7
|
get path() {
|
|
8
|
-
return resolve(
|
|
8
|
+
return resolve(getRunPath(), "ui-runtime.json");
|
|
9
9
|
}
|
|
10
10
|
read = () => {
|
|
11
11
|
if (!existsSync(this.path)) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-ui-runtime.store.js","names":[],"sources":["../../../src/shared/stores/local-ui-runtime.store.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {
|
|
1
|
+
{"version":3,"file":"local-ui-runtime.store.js","names":[],"sources":["../../../src/shared/stores/local-ui-runtime.store.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { getRunPath, type Config } from \"@nextclaw/core\";\nimport type { RemoteRuntimeState } from \"@nextclaw/remote\";\nimport { resolveUiApiBase } from \"../utils/cli.utils.js\";\n\nexport type LocalUiRuntimeState = {\n pid: number;\n startedAt: string;\n uiUrl: string;\n apiUrl: string;\n uiHost?: string;\n uiPort?: number;\n remote?: RemoteRuntimeState;\n};\n\nexport class LocalUiRuntimeStore {\n get path(): string {\n return resolve(getRunPath(), \"ui-runtime.json\");\n }\n\n readonly read = (): LocalUiRuntimeState | null => {\n if (!existsSync(this.path)) {\n return null;\n }\n try {\n const raw = readFileSync(this.path, \"utf-8\");\n return JSON.parse(raw) as LocalUiRuntimeState;\n } catch {\n return null;\n }\n };\n\n readonly write = (state: LocalUiRuntimeState): void => {\n mkdirSync(resolve(this.path, \"..\"), { recursive: true });\n writeFileSync(this.path, JSON.stringify(state, null, 2));\n };\n\n readonly update = (updater: (state: LocalUiRuntimeState) => LocalUiRuntimeState): LocalUiRuntimeState | null => {\n const current = this.read();\n if (!current) {\n return null;\n }\n const next = updater(current);\n this.write(next);\n return next;\n };\n\n readonly clear = (): void => {\n if (existsSync(this.path)) {\n rmSync(this.path, { force: true });\n }\n };\n\n readonly clearIfOwnedByProcess = (pid = process.pid): void => {\n if (this.read()?.pid === pid) {\n this.clear();\n }\n };\n\n readonly writeCurrentProcess = (\n uiConfig: Pick<Config[\"ui\"], \"host\" | \"port\">,\n pid = process.pid\n ): LocalUiRuntimeState => {\n const existing = this.read();\n const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);\n const state: LocalUiRuntimeState = {\n pid,\n startedAt:\n existing?.pid === pid && typeof existing.startedAt === \"string\"\n ? existing.startedAt\n : new Date().toISOString(),\n uiUrl,\n apiUrl: `${uiUrl}/api`,\n uiHost: uiConfig.host,\n uiPort: uiConfig.port,\n ...(existing?.remote ? { remote: existing.remote } : {})\n };\n this.write(state);\n return state;\n };\n}\n\nexport const localUiRuntimeStore = new LocalUiRuntimeStore();\n"],"mappings":";;;;;AAgBA,IAAa,sBAAb,MAAiC;CAC/B,IAAI,OAAe;AACjB,SAAO,QAAQ,YAAY,EAAE,kBAAkB;;CAGjD,aAAkD;AAChD,MAAI,CAAC,WAAW,KAAK,KAAK,CACxB,QAAO;AAET,MAAI;GACF,MAAM,MAAM,aAAa,KAAK,MAAM,QAAQ;AAC5C,UAAO,KAAK,MAAM,IAAI;UAChB;AACN,UAAO;;;CAIX,SAAkB,UAAqC;AACrD,YAAU,QAAQ,KAAK,MAAM,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AACxD,gBAAc,KAAK,MAAM,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;;CAG1D,UAAmB,YAA6F;EAC9G,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,CAAC,QACH,QAAO;EAET,MAAM,OAAO,QAAQ,QAAQ;AAC7B,OAAK,MAAM,KAAK;AAChB,SAAO;;CAGT,cAA6B;AAC3B,MAAI,WAAW,KAAK,KAAK,CACvB,QAAO,KAAK,MAAM,EAAE,OAAO,MAAM,CAAC;;CAItC,yBAAkC,MAAM,QAAQ,QAAc;AAC5D,MAAI,KAAK,MAAM,EAAE,QAAQ,IACvB,MAAK,OAAO;;CAIhB,uBACE,UACA,MAAM,QAAQ,QACU;EACxB,MAAM,WAAW,KAAK,MAAM;EAC5B,MAAM,QAAQ,iBAAiB,SAAS,MAAM,SAAS,KAAK;EAC5D,MAAM,QAA6B;GACjC;GACA,WACE,UAAU,QAAQ,OAAO,OAAO,SAAS,cAAc,WACnD,SAAS,6BACT,IAAI,MAAM,EAAC,aAAa;GAC9B;GACA,QAAQ,GAAG,MAAM;GACjB,QAAQ,SAAS;GACjB,QAAQ,SAAS;GACjB,GAAI,UAAU,SAAS,EAAE,QAAQ,SAAS,QAAQ,GAAG,EAAE;GACxD;AACD,OAAK,MAAM,MAAM;AACjB,SAAO;;;AAIX,MAAa,sBAAsB,IAAI,qBAAqB"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRunPath } from "@nextclaw/core";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
//#region src/shared/stores/managed-service-state.store.ts
|
|
5
5
|
var ManagedServiceStateStore = class {
|
|
6
6
|
get path() {
|
|
7
|
-
return resolve(
|
|
7
|
+
return resolve(getRunPath(), "service.json");
|
|
8
8
|
}
|
|
9
9
|
read = () => {
|
|
10
10
|
if (!existsSync(this.path)) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-service-state.store.js","names":[],"sources":["../../../src/shared/stores/managed-service-state.store.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {
|
|
1
|
+
{"version":3,"file":"managed-service-state.store.js","names":[],"sources":["../../../src/shared/stores/managed-service-state.store.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { getRunPath } from \"@nextclaw/core\";\nimport type { RemoteRuntimeState } from \"@nextclaw/remote\";\n\nexport type ManagedServiceLease = {\n ownerPid: number;\n heartbeatAt: string;\n heartbeatIntervalMs: number;\n ttlMs: number;\n};\n\ntype ManagedServiceExitReason =\n | \"exit\"\n | \"signal\"\n | \"uncaughtException\";\n\nexport type ManagedServiceLastExit = {\n pid: number;\n reason: ManagedServiceExitReason;\n exitedAt: string;\n code?: number | null;\n signal?: string | null;\n message?: string | null;\n};\n\nexport type ManagedServiceState = {\n pid: number;\n startedAt: string;\n uiUrl: string;\n apiUrl: string;\n uiHost?: string;\n uiPort?: number;\n logPath: string;\n startupState?: \"ready\" | \"degraded\";\n startupLastProbeError?: string | null;\n startupTimeoutMs?: number;\n startupCheckedAt?: string;\n lease?: ManagedServiceLease;\n lastExit?: ManagedServiceLastExit;\n remote?: RemoteRuntimeState;\n};\n\nexport class ManagedServiceStateStore {\n get path(): string {\n return resolve(getRunPath(), \"service.json\");\n }\n\n readonly read = (): ManagedServiceState | null => {\n if (!existsSync(this.path)) {\n return null;\n }\n try {\n const raw = readFileSync(this.path, \"utf-8\");\n return JSON.parse(raw) as ManagedServiceState;\n } catch {\n return null;\n }\n };\n\n readonly write = (state: ManagedServiceState): void => {\n mkdirSync(resolve(this.path, \"..\"), { recursive: true });\n writeFileSync(this.path, JSON.stringify(state, null, 2));\n };\n\n readonly update = (updater: (state: ManagedServiceState) => ManagedServiceState): ManagedServiceState | null => {\n const current = this.read();\n if (!current) {\n return null;\n }\n const next = updater(current);\n this.write(next);\n return next;\n };\n\n readonly clear = (): void => {\n if (existsSync(this.path)) {\n rmSync(this.path, { force: true });\n }\n };\n\n readonly clearIfOwnedByProcess = (pid = process.pid): void => {\n if (this.read()?.pid === pid) {\n this.clear();\n }\n };\n}\n\nexport const managedServiceStateStore = new ManagedServiceStateStore();\n"],"mappings":";;;;AA2CA,IAAa,2BAAb,MAAsC;CACpC,IAAI,OAAe;AACjB,SAAO,QAAQ,YAAY,EAAE,eAAe;;CAG9C,aAAkD;AAChD,MAAI,CAAC,WAAW,KAAK,KAAK,CACxB,QAAO;AAET,MAAI;GACF,MAAM,MAAM,aAAa,KAAK,MAAM,QAAQ;AAC5C,UAAO,KAAK,MAAM,IAAI;UAChB;AACN,UAAO;;;CAIX,SAAkB,UAAqC;AACrD,YAAU,QAAQ,KAAK,MAAM,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AACxD,gBAAc,KAAK,MAAM,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;;CAG1D,UAAmB,YAA6F;EAC9G,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,CAAC,QACH,QAAO;EAET,MAAM,OAAO,QAAQ,QAAQ;AAC7B,OAAK,MAAM,KAAK;AAChB,SAAO;;CAGT,cAA6B;AAC3B,MAAI,WAAW,KAAK,KAAK,CACvB,QAAO,KAAK,MAAM,EAAE,OAAO,MAAM,CAAC;;CAItC,yBAAkC,MAAM,QAAQ,QAAc;AAC5D,MAAI,KAAK,MAAM,EAAE,QAAQ,IACvB,MAAK,OAAO;;;AAKlB,MAAa,2BAA2B,IAAI,0BAA0B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.types.d.ts","names":[],"sources":["../../../src/shared/types/cli.types.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cli.types.d.ts","names":[],"sources":["../../../src/shared/types/cli.types.ts"],"mappings":";;;;KAUY,qBAAA;EACV,EAAA;EACA,MAAA;EACA,MAAA;AAAA;AAAA,KAGU,gBAAA;EACV,IAAA;EACA,IAAA;AAAA;AAAA,KAGU,mBAAA;EACV,MAAA;EACA,IAAA;EACA,YAAA;AAAA;AAAA,KAGU,8BAAA;EACV,IAAA;EACA,MAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,KAGU,mBAAA;EACV,OAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;AAAA;AAAA,KAGU,6BAAA;EACV,OAAA;EACA,KAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,KAGU,wBAAA;EACV,OAAA;EACA,IAAA;AAAA;AAAA,KAGU,qCAAA;EACV,OAAA;EACA,KAAA;EACA,GAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,KAGU,wCAAA;EACV,OAAA;EACA,KAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,KAGU,qCAAA;EACV,OAAA;EACA,OAAA;EACA,GAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,KAGU,oBAAA;EACV,KAAA;EACA,QAAA;EACA,YAAA;EACA,KAAA;EACA,OAAA;EACA,WAAA;EACA,IAAA;AAAA;AAAA,KAGU,mBAAA;EACV,OAAA;EACA,KAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,KAGU,qBAAA;EACV,OAAA;EACA,IAAA;AAAA;AAAA,KAGU,gCAAA;EACV,OAAA;EACA,IAAA;AAAA;AAAA,KAGU,kBAAA;EACV,IAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,KAGU,wBAAA;EACV,IAAA;AAAA;AAAA,KAGU,4BAAA;EACV,IAAA;EACA,KAAA;AAAA;AAAA,KAGU,uBAAA;EACV,IAAA;EACA,WAAA;EACA,MAAA;EACA,IAAA;EACA,OAAA;EACA,IAAA;AAAA;AAAA,KAGU,0BAAA;EACV,IAAA;EACA,WAAA;EACA,MAAA;EACA,OAAA;EACA,IAAA;AAAA;AAAA,KAGU,0BAAA;EACV,IAAA;AAAA;AAAA,KAGU,kBAAA;EACV,IAAA;AAAA;AAAA,KAGU,qBAAA;EACV,IAAA;AAAA;AAAA,KAGU,uBAAA;EACV,SAAA;EACA,UAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,KAGU,kBAAA;EACV,OAAA;EACA,IAAA;EACA,KAAA;EACA,IAAA;EACA,GAAA;EACA,OAAA;AAAA;AAAA,KAGU,mBAAA;EACV,IAAA;AAAA;AAAA,KAGU,oBAAA;EACV,OAAA;EACA,OAAA;EACA,GAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,KAGU,gBAAA;EACV,IAAA;AAAA;AAAA,KAGU,gBAAA;EACV,IAAA;AAAA;AAAA,KAGU,cAAA;EACV,IAAA;AAAA;AAAA,KAGU,oBAAA;EACV,SAAA;EACA,GAAA;EACA,MAAA;EACA,GAAA;EACA,GAAA;EACA,SAAA;EACA,QAAA;EACA,SAAA;EACA,KAAA;EACA,MAAA;EACA,QAAA;AAAA;AAAA,KAGU,gBAAA;EACV,IAAA;AAAA;AAAA,KAGU,mBAAA;EACV,IAAA;EACA,MAAA;AAAA;AAAA,KAGU,uBAAA;EACV,QAAA;EACA,MAAA;EACA,MAAA;EACA,IAAA;EACA,OAAA;EACA,GAAA;EACA,GAAA;EACA,SAAA;EACA,UAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,KAGU,mBAAA;EACV,IAAA;EACA,MAAA;EACA,EAAA;EACA,QAAA;EACA,IAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA;EACA,IAAA;AAAA;AAAA,KAGU,oBAAA;EACV,IAAA;AAAA;AAAA,KAGU,cAAA;EACV,IAAA;EACA,OAAA;EACA,KAAA;EACA,OAAA;EACA,KAAA;EACA,IAAA;EACA,EAAA;AAAA;AAAA,KAGU,oBAAA;EACV,IAAA;EACA,OAAA;EACA,GAAA;AAAA;AAAA,KAGU,oBAAA;EACV,IAAA;EACA,OAAA;EACA,GAAA;AAAA;AAAA,KAGU,sBAAA;EACV,KAAA;EACA,KAAA;AAAA;AAAA,KAGU,mBAAA;EACV,IAAA;EACA,OAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,KAGU,WAAA;EACV,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AAAA,KAGU,mBAAA;EACV,WAAA;EACA,UAAA;EACA,YAAA;EACA,aAAA;EACA,eAAA;EACA,KAAA;EACA,SAAA,EAAW,KAAA;IAAQ,IAAA;IAAc,UAAA;IAAqB,MAAA;EAAA;EACtD,gBAAA;EACA,kBAAA;EACA,UAAA;EACA,OAAA;IACE,cAAA;IACA,GAAA;IACA,OAAA;IACA,UAAA;IACA,WAAA;IACA,eAAA;IACA,SAAA;IACA,KAAA;MACE,WAAA;MACA,OAAA;MACA,OAAA;IAAA;IAEF,QAAA;MACE,GAAA;MACA,MAAA;MACA,QAAA;MACA,IAAA;MACA,MAAA;MACA,OAAA;IAAA;EAAA;EAGJ,SAAA;IACE,KAAA;IACA,MAAA;IACA,eAAA;IACA,gBAAA;EAAA;EAEF,MAAA;IACE,OAAA,EAAS,WAAA;IACT,UAAA,EAAY,WAAA;EAAA;EAEd,MAAA;EACA,eAAA;EACA,OAAA;EACA,MAAA;IACE,iBAAA;IACA,OAAA,EAAS,kBAAA;EAAA;EAEX,KAAA;EACA,QAAA;AAAA;AAAA,KAGU,oBAAA;EACV,MAAA;EACA,aAAA;EACA,QAAA,GAAW,eAAA;EACX,OAAA;EACA,sBAAA;EACA,YAAA;EACA,IAAA;AAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getPackageVersion } from "./package/package-manifest.utils.js";
|
|
2
|
-
import { createExternalCommandEnv,
|
|
2
|
+
import { createExternalCommandEnv, getRuntimeLogsPath, resolveLocalUiBaseUrl } from "@nextclaw/core";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { spawn, spawnSync } from "node:child_process";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
@@ -52,7 +52,7 @@ async function resolvePublicIp(timeoutMs = 1500) {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
function resolveServiceLogPath() {
|
|
55
|
-
return resolve(
|
|
55
|
+
return resolve(getRuntimeLogsPath(), "service.log");
|
|
56
56
|
}
|
|
57
57
|
function isProcessRunning(pid) {
|
|
58
58
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.utils.js","names":[],"sources":["../../../src/shared/utils/cli.utils.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { isIP } from \"node:net\";\nimport type { Interface } from \"node:readline\";\nimport {\n createExternalCommandEnv,\n getLogsPath,\n resolveLocalUiBaseUrl,\n type Config\n} from \"@nextclaw/core\";\n\nexport { getPackageVersion } from \"./package/package-manifest.utils.js\";\n\nexport function resolveUiConfig(config: Config, overrides?: Partial<Config[\"ui\"]>): Config[\"ui\"] {\n const base = config.ui ?? { enabled: false, host: \"127.0.0.1\", port: 55667, open: false };\n return { ...base, ...(overrides ?? {}) };\n}\n\nexport function resolveUiApiBase(host: string, port: number): string {\n return resolveLocalUiBaseUrl({ host, port });\n}\n\nexport function isLoopbackHost(host: string): boolean {\n const normalized = host.trim().toLowerCase();\n return normalized === \"127.0.0.1\" || normalized === \"localhost\" || normalized === \"::1\";\n}\n\nconst PUBLIC_IP_CHECK_URLS = [\"https://api.ipify.org\", \"https://ifconfig.me/ip\"];\n\nasync function fetchPublicIpFrom(url: string, timeoutMs: number): Promise<string | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n signal: controller.signal,\n headers: {\n Accept: \"text/plain\"\n }\n });\n if (!response.ok) {\n return null;\n }\n const text = (await response.text()).trim();\n return isIP(text) ? text : null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function resolvePublicIp(timeoutMs = 1500): Promise<string | null> {\n for (const endpoint of PUBLIC_IP_CHECK_URLS) {\n const candidate = await fetchPublicIpFrom(endpoint, timeoutMs);\n if (candidate) {\n return candidate;\n }\n }\n return null;\n}\n\nexport function resolveServiceLogPath(): string {\n return resolve(getLogsPath(), \"service.log\");\n}\n\nexport function isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function waitForExit(pid: number, timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (!isProcessRunning(pid)) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, 200));\n }\n return !isProcessRunning(pid);\n}\n\nexport type ListeningProcessInfo = {\n pid: number;\n command: string | null;\n};\n\ntype CommandResult = {\n ok: boolean;\n stdout: string;\n};\n\nfunction runLookupCommand(command: string, args: string[]): CommandResult {\n try {\n const result = spawnSync(command, args, {\n encoding: \"utf8\",\n env: createExternalCommandEnv(process.env)\n });\n if (result.error || result.status !== 0) {\n return {\n ok: false,\n stdout: \"\"\n };\n }\n return {\n ok: true,\n stdout: result.stdout ?? \"\"\n };\n } catch {\n return {\n ok: false,\n stdout: \"\"\n };\n }\n}\n\nfunction parseListeningPidFromLsof(raw: string): number | null {\n for (const line of raw.split(\"\\n\")) {\n if (!line.startsWith(\"p\")) {\n continue;\n }\n const pid = Number(line.slice(1));\n if (Number.isFinite(pid) && pid > 0) {\n return pid;\n }\n }\n return null;\n}\n\nfunction parseListeningPidFromNetstat(raw: string, port: number): number | null {\n const portSuffix = `:${port}`;\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed || !trimmed.includes(\"LISTEN\")) {\n continue;\n }\n const columns = trimmed.split(/\\s+/);\n if (columns.length < 5) {\n continue;\n }\n const localAddress = columns[1] ?? \"\";\n if (!localAddress.endsWith(portSuffix)) {\n continue;\n }\n const pid = Number(columns[4]);\n if (Number.isFinite(pid) && pid > 0) {\n return pid;\n }\n }\n return null;\n}\n\nfunction lookupProcessCommandByPid(pid: number): string | null {\n if (!Number.isFinite(pid) || pid <= 0) {\n return null;\n }\n\n if (process.platform === \"win32\") {\n const script = `(Get-CimInstance Win32_Process -Filter \"ProcessId = ${pid}\").CommandLine`;\n const result = runLookupCommand(\"powershell\", [\"-NoProfile\", \"-Command\", script]);\n if (!result.ok) {\n return null;\n }\n const command = result.stdout.trim();\n return command.length > 0 ? command : null;\n }\n\n const result = runLookupCommand(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"]);\n if (!result.ok) {\n return null;\n }\n const command = result.stdout.trim();\n return command.length > 0 ? command : null;\n}\n\nexport function findListeningProcessByPort(port: number): ListeningProcessInfo | null {\n if (!Number.isFinite(port) || port <= 0) {\n return null;\n }\n\n let pid: number | null = null;\n if (process.platform === \"win32\") {\n const result = runLookupCommand(\"netstat\", [\"-ano\", \"-p\", \"tcp\"]);\n if (!result.ok) {\n return null;\n }\n pid = parseListeningPidFromNetstat(result.stdout, port);\n } else {\n const result = runLookupCommand(\"lsof\", [\"-nP\", `-iTCP:${port}`, \"-sTCP:LISTEN\", \"-F\", \"p\"]);\n if (!result.ok) {\n return null;\n }\n pid = parseListeningPidFromLsof(result.stdout);\n }\n\n if (!pid) {\n return null;\n }\n\n return {\n pid,\n command: lookupProcessCommandByPid(pid)\n };\n}\n\nexport function resolveUiStaticDir(packagedUiDistDir?: string | null): string | null {\n if (process.env.NEXTCLAW_DISABLE_STATIC_UI === \"1\") {\n return null;\n }\n\n const envDir = process.env.NEXTCLAW_UI_STATIC_DIR;\n if (envDir) {\n return existsSync(join(envDir, \"index.html\")) ? envDir : null;\n }\n\n if (!packagedUiDistDir) {\n return null;\n }\n return existsSync(join(packagedUiDistDir, \"index.html\")) ? packagedUiDistDir : null;\n}\n\nexport function openBrowser(url: string): boolean {\n const platform = process.platform;\n let command: string;\n let args: string[];\n if (platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (platform === \"win32\") {\n command = \"cmd\";\n args = [\"/c\", \"start\", \"\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n if (!findExecutableOnPath(command)) {\n return false;\n }\n try {\n const child = spawn(command, args, {\n stdio: \"ignore\",\n detached: true,\n env: createExternalCommandEnv(process.env),\n windowsHide: true\n });\n child.unref();\n return true;\n } catch {\n return false;\n }\n}\n\nexport type ExecutableLookupEnv = {\n [key: string]: string | undefined;\n PATH?: string;\n Path?: string;\n path?: string;\n PATHEXT?: string;\n};\n\nfunction normalizePathEntries(rawPath: string, platform: NodeJS.Platform): string[] {\n const delimiter = platform === \"win32\" ? \";\" : \":\";\n return rawPath.split(delimiter).map((entry) => entry.trim().replace(/^\"+|\"+$/g, \"\")).filter(Boolean);\n}\n\nfunction normalizeWindowsPathExt(rawPathExt: string | undefined): string[] {\n const source = (rawPathExt && rawPathExt.trim().length > 0) ? rawPathExt : \".COM;.EXE;.BAT;.CMD\";\n const unique = new Set<string>();\n for (const ext of source.split(\";\")) {\n const trimmed = ext.trim();\n if (!trimmed) {\n continue;\n }\n const normalized = trimmed.startsWith(\".\") ? trimmed : `.${trimmed}`;\n unique.add(normalized.toUpperCase());\n }\n return [...unique];\n}\n\nfunction hasFileExtension(binary: string): boolean {\n return binary.lastIndexOf(\".\") > Math.max(binary.lastIndexOf(\"/\"), binary.lastIndexOf(\"\\\\\"));\n}\n\nexport function findExecutableOnPath(\n binary: string,\n env: ExecutableLookupEnv = process.env,\n platform: NodeJS.Platform = process.platform\n): string | null {\n const target = binary.trim();\n if (!target) {\n return null;\n }\n\n if (target.includes(\"/\") || target.includes(\"\\\\\")) {\n return existsSync(target) ? target : null;\n }\n\n const rawPath = env.PATH ?? env.Path ?? env.path ?? \"\";\n if (!rawPath.trim()) {\n return null;\n }\n\n const entries = normalizePathEntries(rawPath, platform);\n if (entries.length === 0) {\n return null;\n }\n\n for (const dir of entries) {\n const direct = join(dir, target);\n if (existsSync(direct)) {\n return direct;\n }\n\n if (platform !== \"win32\" || hasFileExtension(target)) {\n continue;\n }\n\n for (const ext of normalizeWindowsPathExt(env.PATHEXT)) {\n const withExt = join(dir, `${target}${ext}`);\n if (existsSync(withExt)) {\n return withExt;\n }\n }\n }\n\n return null;\n}\n\nexport function printAgentResponse(response: string): void {\n console.log(\"\\n\" + response + \"\\n\");\n}\n\nexport async function prompt(rl: Interface, question: string): Promise<string> {\n rl.setPrompt(question);\n rl.prompt();\n return new Promise((resolve) => {\n rl.once(\"line\", (line) => resolve(line));\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.utils.js","names":[],"sources":["../../../src/shared/utils/cli.utils.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { isIP } from \"node:net\";\nimport type { Interface } from \"node:readline\";\nimport {\n createExternalCommandEnv,\n getRuntimeLogsPath,\n resolveLocalUiBaseUrl,\n type Config\n} from \"@nextclaw/core\";\n\nexport { getPackageVersion } from \"./package/package-manifest.utils.js\";\n\nexport function resolveUiConfig(config: Config, overrides?: Partial<Config[\"ui\"]>): Config[\"ui\"] {\n const base = config.ui ?? { enabled: false, host: \"127.0.0.1\", port: 55667, open: false };\n return { ...base, ...(overrides ?? {}) };\n}\n\nexport function resolveUiApiBase(host: string, port: number): string {\n return resolveLocalUiBaseUrl({ host, port });\n}\n\nexport function isLoopbackHost(host: string): boolean {\n const normalized = host.trim().toLowerCase();\n return normalized === \"127.0.0.1\" || normalized === \"localhost\" || normalized === \"::1\";\n}\n\nconst PUBLIC_IP_CHECK_URLS = [\"https://api.ipify.org\", \"https://ifconfig.me/ip\"];\n\nasync function fetchPublicIpFrom(url: string, timeoutMs: number): Promise<string | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n signal: controller.signal,\n headers: {\n Accept: \"text/plain\"\n }\n });\n if (!response.ok) {\n return null;\n }\n const text = (await response.text()).trim();\n return isIP(text) ? text : null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function resolvePublicIp(timeoutMs = 1500): Promise<string | null> {\n for (const endpoint of PUBLIC_IP_CHECK_URLS) {\n const candidate = await fetchPublicIpFrom(endpoint, timeoutMs);\n if (candidate) {\n return candidate;\n }\n }\n return null;\n}\n\nexport function resolveServiceLogPath(): string {\n return resolve(getRuntimeLogsPath(), \"service.log\");\n}\n\nexport function isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function waitForExit(pid: number, timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (!isProcessRunning(pid)) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, 200));\n }\n return !isProcessRunning(pid);\n}\n\nexport type ListeningProcessInfo = {\n pid: number;\n command: string | null;\n};\n\ntype CommandResult = {\n ok: boolean;\n stdout: string;\n};\n\nfunction runLookupCommand(command: string, args: string[]): CommandResult {\n try {\n const result = spawnSync(command, args, {\n encoding: \"utf8\",\n env: createExternalCommandEnv(process.env)\n });\n if (result.error || result.status !== 0) {\n return {\n ok: false,\n stdout: \"\"\n };\n }\n return {\n ok: true,\n stdout: result.stdout ?? \"\"\n };\n } catch {\n return {\n ok: false,\n stdout: \"\"\n };\n }\n}\n\nfunction parseListeningPidFromLsof(raw: string): number | null {\n for (const line of raw.split(\"\\n\")) {\n if (!line.startsWith(\"p\")) {\n continue;\n }\n const pid = Number(line.slice(1));\n if (Number.isFinite(pid) && pid > 0) {\n return pid;\n }\n }\n return null;\n}\n\nfunction parseListeningPidFromNetstat(raw: string, port: number): number | null {\n const portSuffix = `:${port}`;\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed || !trimmed.includes(\"LISTEN\")) {\n continue;\n }\n const columns = trimmed.split(/\\s+/);\n if (columns.length < 5) {\n continue;\n }\n const localAddress = columns[1] ?? \"\";\n if (!localAddress.endsWith(portSuffix)) {\n continue;\n }\n const pid = Number(columns[4]);\n if (Number.isFinite(pid) && pid > 0) {\n return pid;\n }\n }\n return null;\n}\n\nfunction lookupProcessCommandByPid(pid: number): string | null {\n if (!Number.isFinite(pid) || pid <= 0) {\n return null;\n }\n\n if (process.platform === \"win32\") {\n const script = `(Get-CimInstance Win32_Process -Filter \"ProcessId = ${pid}\").CommandLine`;\n const result = runLookupCommand(\"powershell\", [\"-NoProfile\", \"-Command\", script]);\n if (!result.ok) {\n return null;\n }\n const command = result.stdout.trim();\n return command.length > 0 ? command : null;\n }\n\n const result = runLookupCommand(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"]);\n if (!result.ok) {\n return null;\n }\n const command = result.stdout.trim();\n return command.length > 0 ? command : null;\n}\n\nexport function findListeningProcessByPort(port: number): ListeningProcessInfo | null {\n if (!Number.isFinite(port) || port <= 0) {\n return null;\n }\n\n let pid: number | null = null;\n if (process.platform === \"win32\") {\n const result = runLookupCommand(\"netstat\", [\"-ano\", \"-p\", \"tcp\"]);\n if (!result.ok) {\n return null;\n }\n pid = parseListeningPidFromNetstat(result.stdout, port);\n } else {\n const result = runLookupCommand(\"lsof\", [\"-nP\", `-iTCP:${port}`, \"-sTCP:LISTEN\", \"-F\", \"p\"]);\n if (!result.ok) {\n return null;\n }\n pid = parseListeningPidFromLsof(result.stdout);\n }\n\n if (!pid) {\n return null;\n }\n\n return {\n pid,\n command: lookupProcessCommandByPid(pid)\n };\n}\n\nexport function resolveUiStaticDir(packagedUiDistDir?: string | null): string | null {\n if (process.env.NEXTCLAW_DISABLE_STATIC_UI === \"1\") {\n return null;\n }\n\n const envDir = process.env.NEXTCLAW_UI_STATIC_DIR;\n if (envDir) {\n return existsSync(join(envDir, \"index.html\")) ? envDir : null;\n }\n\n if (!packagedUiDistDir) {\n return null;\n }\n return existsSync(join(packagedUiDistDir, \"index.html\")) ? packagedUiDistDir : null;\n}\n\nexport function openBrowser(url: string): boolean {\n const platform = process.platform;\n let command: string;\n let args: string[];\n if (platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (platform === \"win32\") {\n command = \"cmd\";\n args = [\"/c\", \"start\", \"\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n if (!findExecutableOnPath(command)) {\n return false;\n }\n try {\n const child = spawn(command, args, {\n stdio: \"ignore\",\n detached: true,\n env: createExternalCommandEnv(process.env),\n windowsHide: true\n });\n child.unref();\n return true;\n } catch {\n return false;\n }\n}\n\nexport type ExecutableLookupEnv = {\n [key: string]: string | undefined;\n PATH?: string;\n Path?: string;\n path?: string;\n PATHEXT?: string;\n};\n\nfunction normalizePathEntries(rawPath: string, platform: NodeJS.Platform): string[] {\n const delimiter = platform === \"win32\" ? \";\" : \":\";\n return rawPath.split(delimiter).map((entry) => entry.trim().replace(/^\"+|\"+$/g, \"\")).filter(Boolean);\n}\n\nfunction normalizeWindowsPathExt(rawPathExt: string | undefined): string[] {\n const source = (rawPathExt && rawPathExt.trim().length > 0) ? rawPathExt : \".COM;.EXE;.BAT;.CMD\";\n const unique = new Set<string>();\n for (const ext of source.split(\";\")) {\n const trimmed = ext.trim();\n if (!trimmed) {\n continue;\n }\n const normalized = trimmed.startsWith(\".\") ? trimmed : `.${trimmed}`;\n unique.add(normalized.toUpperCase());\n }\n return [...unique];\n}\n\nfunction hasFileExtension(binary: string): boolean {\n return binary.lastIndexOf(\".\") > Math.max(binary.lastIndexOf(\"/\"), binary.lastIndexOf(\"\\\\\"));\n}\n\nexport function findExecutableOnPath(\n binary: string,\n env: ExecutableLookupEnv = process.env,\n platform: NodeJS.Platform = process.platform\n): string | null {\n const target = binary.trim();\n if (!target) {\n return null;\n }\n\n if (target.includes(\"/\") || target.includes(\"\\\\\")) {\n return existsSync(target) ? target : null;\n }\n\n const rawPath = env.PATH ?? env.Path ?? env.path ?? \"\";\n if (!rawPath.trim()) {\n return null;\n }\n\n const entries = normalizePathEntries(rawPath, platform);\n if (entries.length === 0) {\n return null;\n }\n\n for (const dir of entries) {\n const direct = join(dir, target);\n if (existsSync(direct)) {\n return direct;\n }\n\n if (platform !== \"win32\" || hasFileExtension(target)) {\n continue;\n }\n\n for (const ext of normalizeWindowsPathExt(env.PATHEXT)) {\n const withExt = join(dir, `${target}${ext}`);\n if (existsSync(withExt)) {\n return withExt;\n }\n }\n }\n\n return null;\n}\n\nexport function printAgentResponse(response: string): void {\n console.log(\"\\n\" + response + \"\\n\");\n}\n\nexport async function prompt(rl: Interface, question: string): Promise<string> {\n rl.setPrompt(question);\n rl.prompt();\n return new Promise((resolve) => {\n rl.once(\"line\", (line) => resolve(line));\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.d.ts
|
|
2
|
+
declare function readPanelAppClientSdkScript(): Promise<string>;
|
|
3
|
+
//#endregion
|
|
4
|
+
export { readPanelAppClientSdkScript };
|
|
5
|
+
//# sourceMappingURL=panel-app-client-sdk-script.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-app-client-sdk-script.utils.d.ts","names":[],"sources":["../../../../src/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.ts"],"mappings":";iBAUgB,2BAAA,CAAA,GAA+B,OAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
//#region src/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.ts
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const CLIENT_SDK_BROWSER_BUNDLE = join("browser", "browser-global-registration.utils.iife.js");
|
|
8
|
+
let cachedScript = null;
|
|
9
|
+
function readPanelAppClientSdkScript() {
|
|
10
|
+
cachedScript ??= readFile(resolvePanelAppClientSdkScriptPath(), "utf8");
|
|
11
|
+
return cachedScript;
|
|
12
|
+
}
|
|
13
|
+
function resolvePanelAppClientSdkScriptPath() {
|
|
14
|
+
const bundlePath = join(resolveClientSdkPackageRoot(), "dist", CLIENT_SDK_BROWSER_BUNDLE);
|
|
15
|
+
if (!existsSync(bundlePath)) throw new Error(`Panel App client SDK browser bundle is missing at ${bundlePath}. Run @nextclaw/client-sdk build first.`);
|
|
16
|
+
return bundlePath;
|
|
17
|
+
}
|
|
18
|
+
function resolveClientSdkPackageRoot() {
|
|
19
|
+
let current = dirname(require.resolve("@nextclaw/client-sdk"));
|
|
20
|
+
while (current !== dirname(current)) {
|
|
21
|
+
if (existsSync(join(current, "package.json"))) return current;
|
|
22
|
+
current = dirname(current);
|
|
23
|
+
}
|
|
24
|
+
throw new Error("Unable to resolve @nextclaw/client-sdk package root.");
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { readPanelAppClientSdkScript };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=panel-app-client-sdk-script.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-app-client-sdk-script.utils.js","names":[],"sources":["../../../../src/shared/utils/panel-app-client-sdk/panel-app-client-sdk-script.utils.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\n\nconst require = createRequire(import.meta.url);\nconst CLIENT_SDK_BROWSER_BUNDLE = join(\"browser\", \"browser-global-registration.utils.iife.js\");\n\nlet cachedScript: Promise<string> | null = null;\n\nexport function readPanelAppClientSdkScript(): Promise<string> {\n cachedScript ??= readFile(resolvePanelAppClientSdkScriptPath(), \"utf8\");\n return cachedScript;\n}\n\nfunction resolvePanelAppClientSdkScriptPath(): string {\n const packageRoot = resolveClientSdkPackageRoot();\n const bundlePath = join(packageRoot, \"dist\", CLIENT_SDK_BROWSER_BUNDLE);\n if (!existsSync(bundlePath)) {\n throw new Error(\n `Panel App client SDK browser bundle is missing at ${bundlePath}. Run @nextclaw/client-sdk build first.`,\n );\n }\n return bundlePath;\n}\n\nfunction resolveClientSdkPackageRoot(): string {\n let current = dirname(require.resolve(\"@nextclaw/client-sdk\"));\n while (current !== dirname(current)) {\n if (existsSync(join(current, \"package.json\"))) {\n return current;\n }\n current = dirname(current);\n }\n throw new Error(\"Unable to resolve @nextclaw/client-sdk package root.\");\n}\n"],"mappings":";;;;;AAKA,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;AAC9C,MAAM,4BAA4B,KAAK,WAAW,4CAA4C;AAE9F,IAAI,eAAuC;AAE3C,SAAgB,8BAA+C;AAC7D,kBAAiB,SAAS,oCAAoC,EAAE,OAAO;AACvE,QAAO;;AAGT,SAAS,qCAA6C;CAEpD,MAAM,aAAa,KADC,6BAA6B,EACZ,QAAQ,0BAA0B;AACvE,KAAI,CAAC,WAAW,WAAW,CACzB,OAAM,IAAI,MACR,qDAAqD,WAAW,yCACjE;AAEH,QAAO;;AAGT,SAAS,8BAAsC;CAC7C,IAAI,UAAU,QAAQ,QAAQ,QAAQ,uBAAuB,CAAC;AAC9D,QAAO,YAAY,QAAQ,QAAQ,EAAE;AACnC,MAAI,WAAW,KAAK,SAAS,eAAe,CAAC,CAC3C,QAAO;AAET,YAAU,QAAQ,QAAQ;;AAE5B,OAAM,IAAI,MAAM,uDAAuD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRunPath } from "@nextclaw/core";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
//#region src/shared/utils/restart/restart-sentinel.utils.ts
|
|
@@ -17,7 +17,7 @@ function normalizeLine(value, maxChars) {
|
|
|
17
17
|
return trimmed ? trimmed : null;
|
|
18
18
|
}
|
|
19
19
|
function resolveRestartSentinelPath() {
|
|
20
|
-
return resolve(
|
|
20
|
+
return resolve(getRunPath(), RESTART_SENTINEL_FILENAME);
|
|
21
21
|
}
|
|
22
22
|
async function writeRestartSentinel(payload) {
|
|
23
23
|
const path = resolveRestartSentinelPath();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restart-sentinel.utils.js","names":[],"sources":["../../../../src/shared/utils/restart/restart-sentinel.utils.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {
|
|
1
|
+
{"version":3,"file":"restart-sentinel.utils.js","names":[],"sources":["../../../../src/shared/utils/restart/restart-sentinel.utils.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { getRunPath } from \"@nextclaw/core\";\n\nexport type RestartSentinelDeliveryContext = {\n channel?: string;\n chatId?: string;\n replyTo?: string | null;\n accountId?: string | null;\n metadata?: Record<string, unknown>;\n};\n\nexport type RestartSentinelPayload = {\n kind: \"config.apply\" | \"config.patch\" | \"update.run\" | \"restart\";\n status: \"ok\" | \"error\" | \"skipped\";\n ts: number;\n sessionKey?: string;\n deliveryContext?: RestartSentinelDeliveryContext;\n message?: string | null;\n stats?: {\n reason?: string | null;\n strategy?: string | null;\n durationMs?: number | null;\n };\n};\n\ntype RestartSentinelFile = {\n version: 1;\n payload: RestartSentinelPayload;\n};\n\nconst RESTART_SENTINEL_FILENAME = \"restart-sentinel.json\";\nconst RESTART_REASON_MAX_CHARS = 240;\nconst RESTART_NOTE_MAX_CHARS = 600;\nconst RESTART_OUTBOUND_MAX_CHARS = 1200;\n\nfunction trimTo(value: string, maxChars: number): string {\n const text = value.trim();\n if (!text) {\n return \"\";\n }\n if (text.length <= maxChars) {\n return text;\n }\n return `${text.slice(0, Math.max(0, maxChars - 1)).trimEnd()}…`;\n}\n\nfunction normalizeLine(value: string, maxChars: number): string | null {\n const trimmed = trimTo(value, maxChars);\n return trimmed ? trimmed : null;\n}\n\nexport function resolveRestartSentinelPath(): string {\n return resolve(getRunPath(), RESTART_SENTINEL_FILENAME);\n}\n\nexport async function writeRestartSentinel(payload: RestartSentinelPayload): Promise<string> {\n const path = resolveRestartSentinelPath();\n mkdirSync(resolve(path, \"..\"), { recursive: true });\n const file: RestartSentinelFile = {\n version: 1,\n payload\n };\n writeFileSync(path, `${JSON.stringify(file, null, 2)}\\n`, \"utf-8\");\n return path;\n}\n\nexport async function consumeRestartSentinel(): Promise<RestartSentinelFile | null> {\n const path = resolveRestartSentinelPath();\n if (!existsSync(path)) {\n return null;\n }\n try {\n const raw = readFileSync(path, \"utf-8\");\n const parsed = JSON.parse(raw) as RestartSentinelFile;\n if (!parsed || parsed.version !== 1 || !parsed.payload) {\n rmSync(path, { force: true });\n return null;\n }\n rmSync(path, { force: true });\n return parsed;\n } catch {\n rmSync(path, { force: true });\n return null;\n }\n}\n\nexport function summarizeRestartSentinel(payload: RestartSentinelPayload): string {\n const reason = normalizeLine(payload.stats?.reason ?? \"\", RESTART_REASON_MAX_CHARS);\n if (payload.kind === \"update.run\") {\n return payload.status === \"ok\"\n ? \"✅ NextClaw update completed and service restarted.\"\n : \"⚠️ NextClaw update finished with issues.\";\n }\n if (payload.kind === \"config.apply\" || payload.kind === \"config.patch\") {\n return payload.status === \"ok\"\n ? \"✅ Config applied and service restarted.\"\n : \"⚠️ Config change restart finished with issues.\";\n }\n if (reason) {\n return `Gateway restart complete (${reason}).`;\n }\n return \"Gateway restart complete.\";\n}\n\nexport function formatRestartSentinelMessage(payload: RestartSentinelPayload): string {\n const lines = [summarizeRestartSentinel(payload)];\n const note = normalizeLine(payload.message ?? \"\", RESTART_NOTE_MAX_CHARS);\n if (note) {\n lines.push(note);\n }\n const reason = normalizeLine(payload.stats?.reason ?? \"\", RESTART_REASON_MAX_CHARS);\n if (reason && !lines.some((line) => line.includes(reason))) {\n lines.push(`Reason: ${reason}`);\n }\n\n const message = lines.join(\"\\n\").trim();\n return trimTo(message, RESTART_OUTBOUND_MAX_CHARS);\n}\n\nexport function parseSessionKey(\n sessionKey?: string\n): { channel: string; chatId: string } | null {\n const value = sessionKey?.trim();\n if (!value) {\n return null;\n }\n const separator = value.indexOf(\":\");\n if (separator <= 0 || separator >= value.length - 1) {\n return null;\n }\n return {\n channel: value.slice(0, separator),\n chatId: value.slice(separator + 1)\n };\n}\n"],"mappings":";;;;AA+BA,MAAM,4BAA4B;AAClC,MAAM,2BAA2B;AACjC,MAAM,yBAAyB;AAC/B,MAAM,6BAA6B;AAEnC,SAAS,OAAO,OAAe,UAA0B;CACvD,MAAM,OAAO,MAAM,MAAM;AACzB,KAAI,CAAC,KACH,QAAO;AAET,KAAI,KAAK,UAAU,SACjB,QAAO;AAET,QAAO,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC;;AAG/D,SAAS,cAAc,OAAe,UAAiC;CACrE,MAAM,UAAU,OAAO,OAAO,SAAS;AACvC,QAAO,UAAU,UAAU;;AAG7B,SAAgB,6BAAqC;AACnD,QAAO,QAAQ,YAAY,EAAE,0BAA0B;;AAGzD,eAAsB,qBAAqB,SAAkD;CAC3F,MAAM,OAAO,4BAA4B;AACzC,WAAU,QAAQ,MAAM,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAKnD,eAAc,MAAM,GAAG,KAAK,UAJM;EAChC,SAAS;EACT;EACD,EAC2C,MAAM,EAAE,CAAC,KAAK,QAAQ;AAClE,QAAO;;AAGT,eAAsB,yBAA8D;CAClF,MAAM,OAAO,4BAA4B;AACzC,KAAI,CAAC,WAAW,KAAK,CACnB,QAAO;AAET,KAAI;EACF,MAAM,MAAM,aAAa,MAAM,QAAQ;EACvC,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,CAAC,UAAU,OAAO,YAAY,KAAK,CAAC,OAAO,SAAS;AACtD,UAAO,MAAM,EAAE,OAAO,MAAM,CAAC;AAC7B,UAAO;;AAET,SAAO,MAAM,EAAE,OAAO,MAAM,CAAC;AAC7B,SAAO;SACD;AACN,SAAO,MAAM,EAAE,OAAO,MAAM,CAAC;AAC7B,SAAO;;;AAIX,SAAgB,yBAAyB,SAAyC;CAChF,MAAM,SAAS,cAAc,QAAQ,OAAO,UAAU,IAAI,yBAAyB;AACnF,KAAI,QAAQ,SAAS,aACnB,QAAO,QAAQ,WAAW,OACtB,uDACA;AAEN,KAAI,QAAQ,SAAS,kBAAkB,QAAQ,SAAS,eACtD,QAAO,QAAQ,WAAW,OACtB,4CACA;AAEN,KAAI,OACF,QAAO,6BAA6B,OAAO;AAE7C,QAAO;;AAGT,SAAgB,6BAA6B,SAAyC;CACpF,MAAM,QAAQ,CAAC,yBAAyB,QAAQ,CAAC;CACjD,MAAM,OAAO,cAAc,QAAQ,WAAW,IAAI,uBAAuB;AACzE,KAAI,KACF,OAAM,KAAK,KAAK;CAElB,MAAM,SAAS,cAAc,QAAQ,OAAO,UAAU,IAAI,yBAAyB;AACnF,KAAI,UAAU,CAAC,MAAM,MAAM,SAAS,KAAK,SAAS,OAAO,CAAC,CACxD,OAAM,KAAK,WAAW,SAAS;AAIjC,QAAO,OADS,MAAM,KAAK,KAAK,CAAC,MAAM,EAChB,2BAA2B;;AAGpD,SAAgB,gBACd,YAC4C;CAC5C,MAAM,QAAQ,YAAY,MAAM;AAChC,KAAI,CAAC,MACH,QAAO;CAET,MAAM,YAAY,MAAM,QAAQ,IAAI;AACpC,KAAI,aAAa,KAAK,aAAa,MAAM,SAAS,EAChD,QAAO;AAET,QAAO;EACL,SAAS,MAAM,MAAM,GAAG,UAAU;EAClC,QAAQ,MAAM,MAAM,YAAY,EAAE;EACnC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/service",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10-beta.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "NextClaw long-running service host and runtime lifecycle.",
|
|
6
6
|
"type": "module",
|
|
@@ -42,30 +42,31 @@
|
|
|
42
42
|
"chokidar": "^3.6.0",
|
|
43
43
|
"commander": "^12.1.0",
|
|
44
44
|
"jszip": "^3.10.1",
|
|
45
|
-
"@nextclaw/channel-extension-dingtalk": "0.1.
|
|
46
|
-
"@nextclaw/channel-extension-discord": "0.1.
|
|
47
|
-
"@nextclaw/channel-extension-
|
|
48
|
-
"@nextclaw/channel-extension-
|
|
49
|
-
"@nextclaw/channel-extension-
|
|
50
|
-
"@nextclaw/channel-extension-
|
|
51
|
-
"@nextclaw/channel-extension-
|
|
52
|
-
"@nextclaw/channel-extension-
|
|
53
|
-
"@nextclaw/
|
|
54
|
-
"@nextclaw/
|
|
55
|
-
"@nextclaw/
|
|
56
|
-
"@nextclaw/
|
|
57
|
-
"@nextclaw/
|
|
58
|
-
"@nextclaw/ncp
|
|
59
|
-
"@nextclaw/
|
|
60
|
-
"@nextclaw/
|
|
61
|
-
"@nextclaw/
|
|
62
|
-
"@nextclaw/
|
|
63
|
-
"@nextclaw/
|
|
64
|
-
"@nextclaw/
|
|
65
|
-
"@nextclaw/
|
|
66
|
-
"@nextclaw/
|
|
67
|
-
"@nextclaw/
|
|
68
|
-
"@nextclaw/
|
|
45
|
+
"@nextclaw/channel-extension-dingtalk": "0.1.14-beta.0",
|
|
46
|
+
"@nextclaw/channel-extension-discord": "0.1.14-beta.0",
|
|
47
|
+
"@nextclaw/channel-extension-email": "0.1.14-beta.0",
|
|
48
|
+
"@nextclaw/channel-extension-qq": "0.1.18-beta.0",
|
|
49
|
+
"@nextclaw/channel-extension-feishu": "0.1.21-beta.0",
|
|
50
|
+
"@nextclaw/channel-extension-slack": "0.1.14-beta.0",
|
|
51
|
+
"@nextclaw/channel-extension-telegram": "0.1.14-beta.0",
|
|
52
|
+
"@nextclaw/channel-extension-wecom": "0.1.14-beta.0",
|
|
53
|
+
"@nextclaw/channel-extension-weixin": "0.1.25-beta.0",
|
|
54
|
+
"@nextclaw/channel-extension-whatsapp": "0.1.14-beta.0",
|
|
55
|
+
"@nextclaw/core": "0.13.10-beta.0",
|
|
56
|
+
"@nextclaw/client-sdk": "0.2.10-beta.0",
|
|
57
|
+
"@nextclaw/kernel": "0.3.4-beta.0",
|
|
58
|
+
"@nextclaw/ncp": "0.5.29-beta.0",
|
|
59
|
+
"@nextclaw/mcp": "0.2.10-beta.0",
|
|
60
|
+
"@nextclaw/ncp-agent-runtime": "0.3.40-beta.0",
|
|
61
|
+
"@nextclaw/ncp-mcp": "0.1.105-beta.0",
|
|
62
|
+
"@nextclaw/ncp-toolkit": "0.5.34-beta.0",
|
|
63
|
+
"@nextclaw/nextclaw-hermes-acp-bridge": "0.2.9-beta.0",
|
|
64
|
+
"@nextclaw/nextclaw-ncp-runtime-http-client": "0.2.9-beta.0",
|
|
65
|
+
"@nextclaw/nextclaw-ncp-runtime-stdio-client": "0.2.9-beta.0",
|
|
66
|
+
"@nextclaw/remote": "0.2.10-beta.0",
|
|
67
|
+
"@nextclaw/shared": "0.2.9-beta.0",
|
|
68
|
+
"@nextclaw/server": "0.13.10-beta.0",
|
|
69
|
+
"@nextclaw/runtime": "0.3.10-beta.0"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"@types/node": "^20.17.6",
|