@nextclaw/kernel 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { CHAT_CONTINUATION_TARGET_MESSAGE_METADATA_KEY, CHAT_CONVERSATION_EXCERP
8
8
  import { createHash, createHmac, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
9
9
  import { catchError, filter, from, lastValueFrom, tap } from "rxjs";
10
10
  import { DefaultNcpAgentConversationStateManager, insertMessageByTimeline, mergeToolExecutionTiming } from "@nextclaw/ncp-toolkit";
11
- import { appendFileSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
11
+ import { accessSync, appendFileSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
12
12
  import path, { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
13
13
  import { access, appendFile, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
14
14
  import { AppHomeService, AppInstallationService, AppInstanceInventoryService, AppInstanceStorageService, AppManifestService, AppPlatformTargetService, AppRegistryService, AppServiceLaunchService, FileLockService, isAppComponentManifestBundle } from "@nextclaw/app-runtime";
@@ -3592,6 +3592,30 @@ var AppPackagePresentationService = class {
3592
3592
  };
3593
3593
  };
3594
3594
  //#endregion
3595
+ //#region src/services/app-package-runtime-activation.service.ts
3596
+ const EMPTY_APP_PACKAGE_RUNTIME_HOOKS = {
3597
+ assertCanActivate: async () => void 0,
3598
+ afterActivate: async () => void 0,
3599
+ beforeDeactivate: async () => void 0,
3600
+ beforeUninstall: async () => void 0
3601
+ };
3602
+ var AppPackageRuntimeActivationService = class {
3603
+ recoverFailedActivation = async (params) => {
3604
+ const recoveryErrors = [];
3605
+ try {
3606
+ await params.beforeDeactivate(params.sources);
3607
+ } catch (recoveryError) {
3608
+ recoveryErrors.push(recoveryError);
3609
+ }
3610
+ try {
3611
+ await params.disable();
3612
+ } catch (recoveryError) {
3613
+ recoveryErrors.push(recoveryError);
3614
+ }
3615
+ if (recoveryErrors.length > 0) throw new AggregateError([params.error, ...recoveryErrors], `应用 ${params.appId} 启用失败,且 runtime 状态恢复未完整完成。`);
3616
+ };
3617
+ };
3618
+ //#endregion
3595
3619
  //#region src/types/app-package.types.ts
3596
3620
  var AppPackageError = class extends Error {
3597
3621
  constructor(code, message) {
@@ -3708,11 +3732,6 @@ function compareVersions(left, right) {
3708
3732
  }
3709
3733
  //#endregion
3710
3734
  //#region src/managers/app-package.manager.ts
3711
- const EMPTY_RUNTIME_HOOKS = {
3712
- assertCanActivate: async () => void 0,
3713
- beforeDeactivate: async () => void 0,
3714
- beforeUninstall: async () => void 0
3715
- };
3716
3735
  var AppPackageManager = class {
3717
3736
  appHomeService;
3718
3737
  installationService;
@@ -3720,8 +3739,9 @@ var AppPackageManager = class {
3720
3739
  operationManager;
3721
3740
  platformTargetService = new AppPlatformTargetService();
3722
3741
  presentationService = new AppPackagePresentationService();
3742
+ runtimeActivationService = new AppPackageRuntimeActivationService();
3723
3743
  registryService;
3724
- runtimeHooks = EMPTY_RUNTIME_HOOKS;
3744
+ runtimeHooks = EMPTY_APP_PACKAGE_RUNTIME_HOOKS;
3725
3745
  builtInBootstrapPromise;
3726
3746
  builtInDefinitionsPromise;
3727
3747
  constructor(params) {
@@ -3827,6 +3847,20 @@ var AppPackageManager = class {
3827
3847
  const sources = this.toComponentSources(app);
3828
3848
  await this.runtimeHooks.assertCanActivate(sources);
3829
3849
  await this.installationService.setEnabled(appId, true);
3850
+ try {
3851
+ await this.runtimeHooks.afterActivate(sources);
3852
+ } catch (error) {
3853
+ await this.runtimeActivationService.recoverFailedActivation({
3854
+ appId,
3855
+ error,
3856
+ sources,
3857
+ beforeDeactivate: this.runtimeHooks.beforeDeactivate,
3858
+ disable: async () => {
3859
+ await this.installationService.setEnabled(appId, false);
3860
+ }
3861
+ });
3862
+ throw error;
3863
+ }
3830
3864
  return await this.getPackage(appId);
3831
3865
  });
3832
3866
  };
@@ -3861,6 +3895,7 @@ var AppPackageManager = class {
3861
3895
  await this.runtimeHooks.assertCanActivate(this.toComponentSources(candidate));
3862
3896
  }
3863
3897
  activated = (await this.installationService.rollback(appId, result.version)).rolledBack;
3898
+ if (current.enabled) await this.runtimeHooks.afterActivate(this.toComponentSources(candidate));
3864
3899
  return {
3865
3900
  package: await this.getPackage(appId),
3866
3901
  result
@@ -3869,6 +3904,7 @@ var AppPackageManager = class {
3869
3904
  if (activated) await this.installationService.rollback(appId, result.previousVersion);
3870
3905
  if (deactivated) try {
3871
3906
  await this.runtimeHooks.assertCanActivate(this.toComponentSources(current));
3907
+ await this.runtimeHooks.afterActivate(this.toComponentSources(current));
3872
3908
  } catch (recoveryError) {
3873
3909
  throw new AggregateError([error, recoveryError], `应用 ${appId} 更新失败,且旧 runtime 恢复探测失败。`);
3874
3910
  }
@@ -3900,6 +3936,7 @@ var AppPackageManager = class {
3900
3936
  await this.runtimeHooks.assertCanActivate(this.toComponentSources(candidate));
3901
3937
  }
3902
3938
  result = await this.installationService.rollback(appId, version);
3939
+ if (current.enabled) await this.runtimeHooks.afterActivate(this.toComponentSources(candidate));
3903
3940
  return {
3904
3941
  package: await this.getPackage(appId),
3905
3942
  result
@@ -3908,6 +3945,7 @@ var AppPackageManager = class {
3908
3945
  if (result?.rolledBack) await this.installationService.rollback(appId, result.previousVersion);
3909
3946
  if (deactivated) try {
3910
3947
  await this.runtimeHooks.assertCanActivate(this.toComponentSources(current));
3948
+ await this.runtimeHooks.afterActivate(this.toComponentSources(current));
3911
3949
  } catch (recoveryError) {
3912
3950
  throw new AggregateError([error, recoveryError], `应用 ${appId} 回滚失败,且旧 runtime 恢复探测失败。`);
3913
3951
  }
@@ -3965,7 +4003,8 @@ var AppPackageManager = class {
3965
4003
  const manifestBundle = await this.manifestService.load(activeVersion.installDirectory);
3966
4004
  const security = manifestBundle.manifest.schemaVersion === 2 ? this.manifestService.resolvePlatformSecurity(manifestBundle.manifest) : {
3967
4005
  runtimeProfile: "wasi",
3968
- isolation: manifestBundle.manifest.main.kind === "wasi-http-component" ? "host-mediated" : "sandboxed"
4006
+ isolation: manifestBundle.manifest.main.kind === "wasi-http-component" ? "host-mediated" : "sandboxed",
4007
+ permissions: manifestBundle.manifest.permissions ?? {}
3969
4008
  };
3970
4009
  return {
3971
4010
  id: info.appId,
@@ -3991,6 +4030,7 @@ var AppPackageManager = class {
3991
4030
  storage: info.storage,
3992
4031
  runtimeProfile: security.runtimeProfile,
3993
4032
  isolation: security.isolation,
4033
+ permissions: security.permissions,
3994
4034
  ...await this.presentationService.readManifest(component.manifestPath)
3995
4035
  }))),
3996
4036
  dataDirectory: info.dataDirectory,
@@ -4004,16 +4044,19 @@ var AppPackageManager = class {
4004
4044
  resolveSecurity = (version, appId) => {
4005
4045
  if (version.security) return {
4006
4046
  runtimeProfile: version.security.runtimeProfile,
4007
- isolation: version.security.isolation
4047
+ isolation: version.security.isolation,
4048
+ permissions: version.security.permissions
4008
4049
  };
4009
4050
  const hasService = version.components?.some((component) => component.kind === "service") ?? false;
4010
4051
  if (version.manifestSchemaVersion !== 2) throw new AppPackageError("APP_PACKAGE_INCOMPATIBLE", `应用 ${appId} 仍使用 legacy schema,不能投影组件。`);
4011
4052
  return hasService ? {
4012
4053
  runtimeProfile: "native-process",
4013
- isolation: "full-user"
4054
+ isolation: "full-user",
4055
+ permissions: {}
4014
4056
  } : {
4015
4057
  runtimeProfile: "panel-only",
4016
- isolation: "sandboxed"
4058
+ isolation: "sandboxed",
4059
+ permissions: {}
4017
4060
  };
4018
4061
  };
4019
4062
  toComponentSources = (app) => app.components.map((component) => ({ ...component }));
@@ -4954,7 +4997,7 @@ function readRequiredString$8(value, name) {
4954
4997
  if (!trimmed) throw new Error(`${name} is required`);
4955
4998
  return trimmed;
4956
4999
  }
4957
- function readOptionalNumber(value) {
5000
+ function readOptionalNumber$1(value) {
4958
5001
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4959
5002
  }
4960
5003
  function readTextContent(value) {
@@ -4971,7 +5014,7 @@ function readInboundAttachments(value) {
4971
5014
  ...readString$8(entry.url) ? { url: readString$8(entry.url) } : {},
4972
5015
  ...readString$8(entry.assetUri) ? { assetUri: readString$8(entry.assetUri) } : {},
4973
5016
  ...readString$8(entry.mimeType) ? { mimeType: readString$8(entry.mimeType) } : {},
4974
- ...readOptionalNumber(entry.size) !== void 0 ? { size: readOptionalNumber(entry.size) } : {},
5017
+ ...readOptionalNumber$1(entry.size) !== void 0 ? { size: readOptionalNumber$1(entry.size) } : {},
4975
5018
  ...readString$8(entry.source) ? { source: readString$8(entry.source) } : {},
4976
5019
  ...entry.status === "ready" || entry.status === "remote-only" ? { status: entry.status } : {},
4977
5020
  ...readString$8(entry.errorCode) ? { errorCode: readString$8(entry.errorCode) } : {}
@@ -5007,7 +5050,7 @@ function normalizeAuthPollResult(value) {
5007
5050
  channel: readRequiredString$8(record.channel, "channel"),
5008
5051
  status: record.status,
5009
5052
  message: readString$8(record.message),
5010
- nextPollMs: readOptionalNumber(record.nextPollMs),
5053
+ nextPollMs: readOptionalNumber$1(record.nextPollMs),
5011
5054
  accountId: typeof record.accountId === "string" ? record.accountId : null,
5012
5055
  notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
5013
5056
  channelConfig: normalizeChannelConfigResult(record)
@@ -5044,8 +5087,8 @@ var ExtensionIngressDiagnosticsService = class {
5044
5087
  parentCorrelationId: readString$8(payload.parentCorrelationId),
5045
5088
  reasonCode: readString$8(payload.reasonCode),
5046
5089
  providerCode: readString$8(payload.providerCode),
5047
- durationMs: readOptionalNumber(payload.durationMs),
5048
- attempt: readOptionalNumber(payload.attempt),
5090
+ durationMs: readOptionalNumber$1(payload.durationMs),
5091
+ attempt: readOptionalNumber$1(payload.attempt),
5049
5092
  facts: {
5050
5093
  ...readRecord$2(payload.facts),
5051
5094
  extensionId: credential.extensionId,
@@ -5674,6 +5717,70 @@ function isRecord$15(value) {
5674
5717
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5675
5718
  }
5676
5719
  //#endregion
5720
+ //#region src/utils/service-app-error.utils.ts
5721
+ const SERVICE_APP_ERROR_CODES = new Set([
5722
+ "AUTHORIZATION_REQUIRED",
5723
+ "SERVICE_APP_ACTION_NOT_DECLARED",
5724
+ "SERVICE_APP_ACTION_NOT_FOUND",
5725
+ "SERVICE_APP_INVALID_ACTION",
5726
+ "SERVICE_APP_INVALID_CALLER",
5727
+ "SERVICE_APP_INVALID_MANIFEST",
5728
+ "SERVICE_APP_MANAGED_SOURCE",
5729
+ "SERVICE_APP_NOT_FOUND",
5730
+ "SERVICE_APP_READ_FAILED",
5731
+ "SERVICE_APP_RUNTIME_FAILED"
5732
+ ]);
5733
+ var ServiceAppError = class extends Error {
5734
+ constructor(code, message) {
5735
+ super(message);
5736
+ this.code = code;
5737
+ this.name = "ServiceAppError";
5738
+ }
5739
+ };
5740
+ const isServiceAppError = (error) => error instanceof ServiceAppError || typeof error === "object" && error !== null && error.name === "ServiceAppError" && typeof error.message === "string" && SERVICE_APP_ERROR_CODES.has(error.code);
5741
+ //#endregion
5742
+ //#region src/utils/service-action.utils.ts
5743
+ const DEFAULT_SERVICE_ACTION_RISK = "dangerous";
5744
+ function buildServiceActionId(appId, actionName) {
5745
+ return `${appId}.${actionName}`;
5746
+ }
5747
+ function getServiceActionName(actionId, appId) {
5748
+ const prefix = `${appId}.`;
5749
+ if (!actionId.startsWith(prefix)) throw new Error("service action does not belong to service app.");
5750
+ const name = actionId.slice(prefix.length).trim();
5751
+ if (!name) throw new Error("service action name is required.");
5752
+ return name;
5753
+ }
5754
+ function parseServiceActionCallerKey(key) {
5755
+ const [surface, callerId, ...rest] = key.split(":");
5756
+ if (!callerId || rest.length > 0) return null;
5757
+ if (surface === "panel-app") return {
5758
+ surface,
5759
+ appId: callerId
5760
+ };
5761
+ if (surface === "agent") return {
5762
+ surface,
5763
+ agentId: callerId
5764
+ };
5765
+ return null;
5766
+ }
5767
+ function getServiceActionCallerId(caller) {
5768
+ return caller.surface === "panel-app" ? caller.appId : caller.agentId;
5769
+ }
5770
+ function assertServiceActionCaller(caller, hasAgent) {
5771
+ if (caller.surface === "panel-app" && caller.appId.trim()) return;
5772
+ if (caller.surface === "agent" && caller.agentId.trim() && (hasAgent?.(caller.agentId) ?? true)) return;
5773
+ throw new ServiceAppError("SERVICE_APP_INVALID_CALLER", "service action caller is invalid");
5774
+ }
5775
+ function assertServiceActionDeclared(caller, actionId, declaredActions) {
5776
+ if (caller.surface === "agent") return;
5777
+ if (!declaredActions?.includes(actionId)) throw new ServiceAppError("SERVICE_APP_ACTION_NOT_DECLARED", "panel app did not declare this service action");
5778
+ }
5779
+ function resolveServiceActionGrantState({ actionId, declaredActions, granted }) {
5780
+ if (declaredActions && !declaredActions.includes(actionId)) return "not-declared";
5781
+ return granted ? "granted" : "not-granted";
5782
+ }
5783
+ //#endregion
5677
5784
  //#region src/features/capability-grants/utils/capability-grant-resource.utils.ts
5678
5785
  function createPanelAppClientGrantRequest(appId) {
5679
5786
  return {
@@ -5693,7 +5800,7 @@ function createPanelAppAgentGrantRequest(caller, capability) {
5693
5800
  return {
5694
5801
  subject: {
5695
5802
  type: caller.surface,
5696
- id: caller.appId
5803
+ id: getServiceActionCallerId(caller)
5697
5804
  },
5698
5805
  resource: {
5699
5806
  type: "agent.capability",
@@ -5707,7 +5814,7 @@ function createServiceActionGrantRequest(caller, action) {
5707
5814
  return {
5708
5815
  subject: {
5709
5816
  type: caller.surface,
5710
- id: caller.appId
5817
+ id: getServiceActionCallerId(caller)
5711
5818
  },
5712
5819
  resource: {
5713
5820
  type: "service.action",
@@ -5742,31 +5849,6 @@ function isPanelAppAgentCapability(value) {
5742
5849
  return PANEL_APP_AGENT_CAPABILITIES.includes(value);
5743
5850
  }
5744
5851
  //#endregion
5745
- //#region src/utils/service-action.utils.ts
5746
- const DEFAULT_SERVICE_ACTION_RISK = "dangerous";
5747
- function buildServiceActionId(appId, actionName) {
5748
- return `${appId}.${actionName}`;
5749
- }
5750
- function getServiceActionName(actionId, appId) {
5751
- const prefix = `${appId}.`;
5752
- if (!actionId.startsWith(prefix)) throw new Error("service action does not belong to service app.");
5753
- const name = actionId.slice(prefix.length).trim();
5754
- if (!name) throw new Error("service action name is required.");
5755
- return name;
5756
- }
5757
- function parseServiceActionCallerKey(key) {
5758
- const [surface, appId, ...rest] = key.split(":");
5759
- if (surface !== "panel-app" || !appId || rest.length > 0) return null;
5760
- return {
5761
- surface,
5762
- appId
5763
- };
5764
- }
5765
- function resolveServiceActionGrantState({ actionId, declaredActions, granted }) {
5766
- if (declaredActions && !declaredActions.includes(actionId)) return "not-declared";
5767
- return granted ? "granted" : "not-granted";
5768
- }
5769
- //#endregion
5770
5852
  //#region src/features/capability-grants/services/capability-grant-legacy-migration.service.ts
5771
5853
  const PANEL_AGENT_GRANTS_FILE_NAME = ".panel-app-capability-grants.json";
5772
5854
  const PANEL_CLIENT_GRANTS_FILE_NAME = ".panel-app-client-grants.json";
@@ -5905,7 +5987,7 @@ function parseServiceActionGrants(value) {
5905
5987
  return {
5906
5988
  subject: {
5907
5989
  type: caller.surface,
5908
- id: caller.appId
5990
+ id: caller.surface === "panel-app" ? caller.appId : caller.agentId
5909
5991
  },
5910
5992
  resource: {
5911
5993
  type: "service.action",
@@ -7502,7 +7584,7 @@ var ExtensionRuntimeService = class {
7502
7584
  const credential = this.assertAuthorized(envelope, context);
7503
7585
  const payload = readRecord$2(envelope.payload);
7504
7586
  const generation = readRequiredString$8(payload.generation, "generation");
7505
- const pid = readOptionalNumber(payload.pid);
7587
+ const pid = readOptionalNumber$1(payload.pid);
7506
7588
  if (generation !== credential.generation || pid === void 0 || !Number.isInteger(pid) || pid <= 0) throw new Error("Invalid extension runtime ready payload");
7507
7589
  this.lifecycle.markReady({
7508
7590
  extensionId: credential.extensionId,
@@ -13419,6 +13501,7 @@ var McpServiceAppRuntimeService = class {
13419
13501
  this.states.clear();
13420
13502
  };
13421
13503
  toMcpServerRecord = (app, manifest) => {
13504
+ if (!manifest.command || !manifest.args) throw new Error(`MCP Service App ${app.id} is missing its launch command.`);
13422
13505
  const launch = resolveRuntimeCommandLaunch(manifest.command);
13423
13506
  return {
13424
13507
  name: app.id,
@@ -13480,6 +13563,466 @@ var McpServiceAppRuntimeService = class {
13480
13563
  };
13481
13564
  };
13482
13565
  //#endregion
13566
+ //#region src/services/portable-service-runner-client.service.ts
13567
+ const PORTABLE_RUNNER_PROTOCOL_VERSION = "0.1.0";
13568
+ var PortableServiceRunnerError = class extends Error {
13569
+ constructor(code, message) {
13570
+ super(message);
13571
+ this.code = code;
13572
+ this.name = "PortableServiceRunnerError";
13573
+ }
13574
+ };
13575
+ var PortableServiceRunnerClientService = class {
13576
+ child;
13577
+ pending = /* @__PURE__ */ new Map();
13578
+ stderrTail = [];
13579
+ constructor(params = {}) {
13580
+ this.params = params;
13581
+ }
13582
+ listActions = async (app) => this.request({
13583
+ operation: "list-actions",
13584
+ app
13585
+ }, 7e3);
13586
+ invoke = async (app, actionName, input, timeoutMs = 7e3) => this.request({
13587
+ operation: "invoke",
13588
+ app,
13589
+ actionName,
13590
+ input
13591
+ }, timeoutMs);
13592
+ startResident = async (app, config) => this.request({
13593
+ operation: "start-resident",
13594
+ app,
13595
+ input: config
13596
+ }, 7e3);
13597
+ startProvider = async (app, config) => this.request({
13598
+ operation: "start-provider",
13599
+ app,
13600
+ input: config
13601
+ }, 7e3);
13602
+ deliverEvent = async (app, event) => this.request({
13603
+ operation: "deliver-event",
13604
+ app,
13605
+ input: event
13606
+ }, 7e3);
13607
+ stats = async () => this.request({ operation: "stats" }, 2e3);
13608
+ stop = async (app) => {
13609
+ await this.request({
13610
+ operation: "stop",
13611
+ app,
13612
+ input: {
13613
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
13614
+ reason: "host-stop"
13615
+ }
13616
+ }, 2e3);
13617
+ };
13618
+ dispose = async () => {
13619
+ const child = this.child;
13620
+ this.child = void 0;
13621
+ if (!child) return;
13622
+ child.stdin.end();
13623
+ await new Promise((resolve) => {
13624
+ const timeout = setTimeout(() => {
13625
+ child.kill("SIGKILL");
13626
+ resolve();
13627
+ }, 1e3);
13628
+ timeout.unref();
13629
+ child.once("exit", () => {
13630
+ clearTimeout(timeout);
13631
+ resolve();
13632
+ });
13633
+ });
13634
+ };
13635
+ request = async (request, timeoutMs) => {
13636
+ const child = this.ensureChild();
13637
+ const requestId = randomUUID();
13638
+ const payload = {
13639
+ ...request,
13640
+ requestId,
13641
+ app: request.app ? this.toRunnerApp(request.app) : void 0
13642
+ };
13643
+ return await new Promise((resolve, reject) => {
13644
+ const timeout = setTimeout(() => {
13645
+ const error = new PortableServiceRunnerError("PORTABLE_RUNTIME_TIMEOUT", `Portable component exceeded its ${timeoutMs}ms execution budget.`);
13646
+ this.failAll(error);
13647
+ this.child?.kill("SIGKILL");
13648
+ this.child = void 0;
13649
+ }, timeoutMs);
13650
+ timeout.unref();
13651
+ this.pending.set(requestId, {
13652
+ resolve: (value) => resolve(value),
13653
+ reject,
13654
+ timeout
13655
+ });
13656
+ child.stdin.write(`${JSON.stringify(payload)}\n`, (error) => {
13657
+ if (!error) return;
13658
+ const pending = this.pending.get(requestId);
13659
+ if (!pending) return;
13660
+ clearTimeout(pending.timeout);
13661
+ this.pending.delete(requestId);
13662
+ reject(error);
13663
+ });
13664
+ });
13665
+ };
13666
+ ensureChild = () => {
13667
+ if (this.child && this.child.exitCode === null) return this.child;
13668
+ const child = spawn(this.resolveRunnerPath(), [], { stdio: [
13669
+ "pipe",
13670
+ "pipe",
13671
+ "pipe"
13672
+ ] });
13673
+ this.child = child;
13674
+ this.stderrTail = [];
13675
+ createInterface({ input: child.stdout }).on("line", this.handleLine);
13676
+ child.stderr.on("data", (chunk) => {
13677
+ const message = chunk.toString("utf8").trim();
13678
+ if (!message) return;
13679
+ this.stderrTail = [...this.stderrTail, message].slice(-20);
13680
+ process.stderr.write(`${message}\n`);
13681
+ });
13682
+ child.stdin.on("error", (error) => {
13683
+ if (this.child !== child) return;
13684
+ this.handleChildFailure(new PortableServiceRunnerError("PORTABLE_RUNNER_IO_FAILED", `Portable runner input failed: ${error.message}. ${this.stderrTail.join(" ")}`.trim()));
13685
+ });
13686
+ child.once("error", (error) => {
13687
+ if (this.child === child) this.handleChildFailure(error);
13688
+ });
13689
+ child.once("exit", (code, signal) => {
13690
+ if (this.child !== child) return;
13691
+ this.child = void 0;
13692
+ const error = new PortableServiceRunnerError("PORTABLE_RUNNER_EXITED", `Portable runner exited (${signal ?? code ?? "unknown"}). ${this.stderrTail.join(" ")}`.trim());
13693
+ this.failAll(error);
13694
+ this.params.onUnexpectedExit?.(error);
13695
+ });
13696
+ return child;
13697
+ };
13698
+ handleLine = (line) => {
13699
+ let response;
13700
+ try {
13701
+ response = JSON.parse(line);
13702
+ } catch {
13703
+ this.handleChildFailure(/* @__PURE__ */ new Error(`Portable runner returned invalid JSON: ${line}`));
13704
+ return;
13705
+ }
13706
+ if (response.protocolVersion !== PORTABLE_RUNNER_PROTOCOL_VERSION) {
13707
+ const error = new PortableServiceRunnerError("PORTABLE_RUNNER_PROTOCOL_MISMATCH", `Portable runner protocol mismatch: expected ${PORTABLE_RUNNER_PROTOCOL_VERSION}, received ${response.protocolVersion ?? "missing"}.`);
13708
+ const child = this.child;
13709
+ this.handleChildFailure(error);
13710
+ child?.kill("SIGKILL");
13711
+ return;
13712
+ }
13713
+ const pending = this.pending.get(response.requestId);
13714
+ if (!pending) return;
13715
+ clearTimeout(pending.timeout);
13716
+ this.pending.delete(response.requestId);
13717
+ if (response.ok) {
13718
+ pending.resolve(response.result);
13719
+ return;
13720
+ }
13721
+ pending.reject(new PortableServiceRunnerError(response.error?.code ?? "PORTABLE_RUNTIME_FAILED", response.error?.message ?? "Portable runner request failed."));
13722
+ };
13723
+ handleChildFailure = (error) => {
13724
+ this.failAll(error);
13725
+ this.child = void 0;
13726
+ };
13727
+ failAll = (error) => {
13728
+ for (const pending of this.pending.values()) {
13729
+ clearTimeout(pending.timeout);
13730
+ pending.reject(error);
13731
+ }
13732
+ this.pending.clear();
13733
+ };
13734
+ toRunnerApp = (app) => ({
13735
+ id: app.id,
13736
+ componentPath: app.componentPath,
13737
+ dataDirectory: app.dataDirectory,
13738
+ allowedDomains: app.permissions.allowedDomains ?? [],
13739
+ allowedProviderIds: app.providerIds ?? [],
13740
+ storageEnabled: Boolean(app.permissions.storage)
13741
+ });
13742
+ resolveRunnerPath = () => {
13743
+ const runnerPath = (this.params.env ?? process.env).NEXTCLAW_WASMTIME_RUNNER_PATH?.trim() || this.params.runnerPath?.trim();
13744
+ if (!runnerPath) throw new PortableServiceRunnerError("PORTABLE_RUNNER_UNAVAILABLE", "Portable runner is not part of this NextClaw distribution. Build the product runtime resource; runner developers may set NEXTCLAW_WASMTIME_RUNNER_PATH explicitly.");
13745
+ try {
13746
+ accessSync(runnerPath, process.platform === "win32" ? constants.F_OK : constants.X_OK);
13747
+ } catch {
13748
+ throw new PortableServiceRunnerError("PORTABLE_RUNNER_UNAVAILABLE", `Portable runner is missing or not executable: ${runnerPath}`);
13749
+ }
13750
+ return runnerPath;
13751
+ };
13752
+ };
13753
+ //#endregion
13754
+ //#region src/services/portable-service-app-runtime.service.ts
13755
+ var PortableServiceAppRuntimeService = class {
13756
+ runner;
13757
+ states = /* @__PURE__ */ new Map();
13758
+ apps = /* @__PURE__ */ new Map();
13759
+ providers = /* @__PURE__ */ new Set();
13760
+ persistentRegistrations = /* @__PURE__ */ new Map();
13761
+ residentTimers = /* @__PURE__ */ new Map();
13762
+ residentDeliveries = /* @__PURE__ */ new Map();
13763
+ recoveryPromise;
13764
+ constructor(params = {}) {
13765
+ this.runner = new PortableServiceRunnerClientService({
13766
+ runnerPath: params.runnerPath,
13767
+ onUnexpectedExit: (error) => {
13768
+ this.recoverPersistentComponentsIfNeeded(error);
13769
+ }
13770
+ });
13771
+ }
13772
+ getStatus = (appId) => this.states.get(appId) ?? { status: "idle" };
13773
+ start = async ({ app, manifest }) => {
13774
+ if (!app.enabled || !manifest.lifecycle || manifest.lifecycle.mode === "action") return;
13775
+ this.persistentRegistrations.set(app.id, {
13776
+ app,
13777
+ manifest
13778
+ });
13779
+ const runnerApp = this.toRunnerApp(app, manifest.providerIds);
13780
+ this.apps.set(app.id, runnerApp);
13781
+ if (manifest.lifecycle.mode === "provider") {
13782
+ if (this.providers.has(app.id)) return;
13783
+ const lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13784
+ this.states.set(app.id, {
13785
+ status: "starting",
13786
+ lastStartedAt
13787
+ });
13788
+ try {
13789
+ await this.runner.startProvider(runnerApp, {
13790
+ mode: "provider",
13791
+ startedAt: lastStartedAt
13792
+ });
13793
+ this.providers.add(app.id);
13794
+ this.states.set(app.id, {
13795
+ status: "running",
13796
+ lastStartedAt,
13797
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13798
+ });
13799
+ } catch (error) {
13800
+ this.markFailed(app.id, lastStartedAt, error);
13801
+ throw error;
13802
+ }
13803
+ return;
13804
+ }
13805
+ if (this.residentTimers.has(app.id)) return;
13806
+ const lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13807
+ this.states.set(app.id, {
13808
+ status: "starting",
13809
+ lastStartedAt
13810
+ });
13811
+ try {
13812
+ await this.runner.startResident(runnerApp, {
13813
+ eventIntervalMs: manifest.lifecycle.eventIntervalMs,
13814
+ startedAt: lastStartedAt
13815
+ });
13816
+ const timer = setInterval(() => {
13817
+ this.scheduleResidentEvent({
13818
+ appId: app.id,
13819
+ eventIntervalMs: manifest.lifecycle?.mode === "resident" ? manifest.lifecycle.eventIntervalMs : 0
13820
+ });
13821
+ }, manifest.lifecycle.eventIntervalMs);
13822
+ timer.unref();
13823
+ this.residentTimers.set(app.id, timer);
13824
+ this.states.set(app.id, {
13825
+ status: "running",
13826
+ lastStartedAt,
13827
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13828
+ });
13829
+ } catch (error) {
13830
+ this.markFailed(app.id, lastStartedAt, error);
13831
+ throw error;
13832
+ }
13833
+ };
13834
+ listActions = async ({ app, manifest }) => {
13835
+ if (!app.enabled) return [];
13836
+ const runnerApp = this.toRunnerApp(app, manifest.providerIds);
13837
+ this.apps.set(app.id, runnerApp);
13838
+ const persistent = manifest.lifecycle?.mode === "resident" || manifest.lifecycle?.mode === "provider";
13839
+ const lastStartedAt = persistent ? this.states.get(app.id)?.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
13840
+ if (!persistent) this.states.set(app.id, {
13841
+ status: "starting",
13842
+ lastStartedAt
13843
+ });
13844
+ try {
13845
+ const actions = await this.runner.listActions(runnerApp);
13846
+ if (!persistent) this.states.set(app.id, {
13847
+ status: "running",
13848
+ lastStartedAt,
13849
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13850
+ });
13851
+ return actions.map((action) => {
13852
+ const declared = manifest.actions[action.name];
13853
+ return {
13854
+ id: buildServiceActionId(app.id, action.name),
13855
+ appId: app.id,
13856
+ name: action.name,
13857
+ title: declared?.title ?? action.title,
13858
+ description: declared?.description ?? action.description,
13859
+ inputSchema: declared?.inputSchema,
13860
+ risk: declared?.risk ?? "dangerous"
13861
+ };
13862
+ });
13863
+ } catch (error) {
13864
+ this.markFailed(app.id, lastStartedAt, error);
13865
+ await this.recoverPersistentComponentsIfNeeded(error);
13866
+ throw error;
13867
+ }
13868
+ };
13869
+ invokeAction = async ({ app, manifest, actionName, input }) => {
13870
+ await this.start({
13871
+ app,
13872
+ manifest
13873
+ });
13874
+ const runnerApp = this.toRunnerApp(app, manifest.providerIds);
13875
+ this.apps.set(app.id, runnerApp);
13876
+ if (manifest.lifecycle?.mode === "resident") try {
13877
+ return await this.runner.invoke(runnerApp, actionName, input, manifest.actions[actionName]?.timeoutMs ?? 7e3);
13878
+ } catch (error) {
13879
+ this.markFailed(app.id, this.states.get(app.id)?.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString(), error);
13880
+ await this.recoverPersistentComponentsIfNeeded(error);
13881
+ throw error;
13882
+ }
13883
+ const lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13884
+ this.states.set(app.id, {
13885
+ status: "starting",
13886
+ lastStartedAt
13887
+ });
13888
+ try {
13889
+ const result = await this.runner.invoke(runnerApp, actionName, input, manifest.actions[actionName]?.timeoutMs ?? 7e3);
13890
+ this.states.set(app.id, {
13891
+ status: "running",
13892
+ lastStartedAt,
13893
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13894
+ });
13895
+ return result;
13896
+ } catch (error) {
13897
+ this.markFailed(app.id, lastStartedAt, error);
13898
+ await this.recoverPersistentComponentsIfNeeded(error);
13899
+ throw error;
13900
+ }
13901
+ };
13902
+ stop = async (appId) => {
13903
+ this.clearResidentTimer(appId);
13904
+ this.providers.delete(appId);
13905
+ this.persistentRegistrations.delete(appId);
13906
+ const app = this.apps.get(appId);
13907
+ this.apps.delete(appId);
13908
+ if (app) await this.runner.stop(app);
13909
+ this.states.set(appId, { status: "idle" });
13910
+ };
13911
+ restart = async (appId) => await this.stop(appId);
13912
+ dispose = async () => {
13913
+ if (this.recoveryPromise) await this.recoveryPromise;
13914
+ for (const appId of this.residentTimers.keys()) this.clearResidentTimer(appId);
13915
+ await Promise.allSettled(this.residentDeliveries.values());
13916
+ await this.runner.dispose();
13917
+ this.states.clear();
13918
+ this.apps.clear();
13919
+ this.providers.clear();
13920
+ this.persistentRegistrations.clear();
13921
+ this.residentDeliveries.clear();
13922
+ };
13923
+ scheduleResidentEvent = (params) => {
13924
+ if (this.residentDeliveries.has(params.appId)) return;
13925
+ const delivery = this.deliverResidentEvent(params).finally(() => {
13926
+ this.residentDeliveries.delete(params.appId);
13927
+ });
13928
+ this.residentDeliveries.set(params.appId, delivery);
13929
+ };
13930
+ deliverResidentEvent = async (params) => {
13931
+ const app = this.apps.get(params.appId);
13932
+ if (!app) return;
13933
+ const triggeredAt = (/* @__PURE__ */ new Date()).toISOString();
13934
+ try {
13935
+ await this.runner.deliverEvent(app, {
13936
+ eventId: `timer-${triggeredAt}`,
13937
+ kind: "timer",
13938
+ triggeredAt,
13939
+ eventIntervalMs: params.eventIntervalMs
13940
+ });
13941
+ } catch (error) {
13942
+ this.clearResidentTimer(params.appId);
13943
+ this.markFailed(params.appId, this.states.get(params.appId)?.lastStartedAt ?? triggeredAt, error);
13944
+ await this.recoverPersistentComponentsIfNeeded(error);
13945
+ }
13946
+ };
13947
+ clearResidentTimer = (appId) => {
13948
+ const timer = this.residentTimers.get(appId);
13949
+ if (timer) clearInterval(timer);
13950
+ this.residentTimers.delete(appId);
13951
+ };
13952
+ recoverPersistentComponentsIfNeeded = async (error) => {
13953
+ if (!(error instanceof PortableServiceRunnerError) || !["PORTABLE_RUNTIME_TIMEOUT", "PORTABLE_RUNNER_EXITED"].includes(error.code)) return;
13954
+ if (this.recoveryPromise) return await this.recoveryPromise;
13955
+ const registrations = Array.from(this.persistentRegistrations.values());
13956
+ if (registrations.length === 0) return;
13957
+ this.recoveryPromise = (async () => {
13958
+ for (const appId of this.residentTimers.keys()) this.clearResidentTimer(appId);
13959
+ this.providers.clear();
13960
+ const ordered = [...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "provider"), ...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "resident")];
13961
+ for (const registration of ordered) try {
13962
+ await this.start(registration);
13963
+ } catch {}
13964
+ })().finally(() => {
13965
+ this.recoveryPromise = void 0;
13966
+ });
13967
+ await this.recoveryPromise;
13968
+ };
13969
+ toRunnerApp = (app, providerIds) => {
13970
+ if (!app.componentPath || !app.dataDirectory) throw new Error(`Portable Service App ${app.id} is missing component or data storage.`);
13971
+ return {
13972
+ id: app.id,
13973
+ componentPath: app.componentPath,
13974
+ dataDirectory: app.dataDirectory,
13975
+ permissions: app.permissions ?? {},
13976
+ providerIds
13977
+ };
13978
+ };
13979
+ markFailed = (appId, lastStartedAt, error) => {
13980
+ this.states.set(appId, {
13981
+ status: "failed",
13982
+ lastError: error instanceof Error ? error.message : String(error),
13983
+ lastStartedAt,
13984
+ lastFailedAt: (/* @__PURE__ */ new Date()).toISOString()
13985
+ });
13986
+ };
13987
+ };
13988
+ //#endregion
13989
+ //#region src/services/service-app-runtime.service.ts
13990
+ var ServiceAppRuntimeService = class {
13991
+ mcp;
13992
+ portable;
13993
+ protocols = /* @__PURE__ */ new Map();
13994
+ constructor(params) {
13995
+ this.mcp = new McpServiceAppRuntimeService(params);
13996
+ this.portable = new PortableServiceAppRuntimeService({ runnerPath: params.portableServiceRunnerPath });
13997
+ }
13998
+ getStatus = (appId) => {
13999
+ return this.protocols.get(appId) === "wasi-component" ? this.portable.getStatus(appId) : this.mcp.getStatus(appId);
14000
+ };
14001
+ start = async (call) => {
14002
+ this.protocols.set(call.app.id, call.manifest.protocol);
14003
+ if (call.manifest.protocol === "wasi-component") await this.portable.start(call);
14004
+ };
14005
+ listActions = async (call) => {
14006
+ this.protocols.set(call.app.id, call.manifest.protocol);
14007
+ return call.manifest.protocol === "wasi-component" ? await this.portable.listActions(call) : await this.mcp.listActions(call);
14008
+ };
14009
+ invokeAction = async (call) => {
14010
+ this.protocols.set(call.app.id, call.manifest.protocol);
14011
+ return call.manifest.protocol === "wasi-component" ? await this.portable.invokeAction(call) : await this.mcp.invokeAction(call);
14012
+ };
14013
+ stop = async (appId) => {
14014
+ const protocol = this.protocols.get(appId);
14015
+ if (protocol === "wasi-component") await this.portable.stop(appId);
14016
+ else if (protocol === "mcp") await this.mcp.stop(appId);
14017
+ else await Promise.all([this.mcp.stop(appId), this.portable.stop(appId)]);
14018
+ };
14019
+ restart = async (appId) => await this.stop(appId);
14020
+ dispose = async () => {
14021
+ await Promise.all([this.mcp.dispose(), this.portable.dispose()]);
14022
+ this.protocols.clear();
14023
+ };
14024
+ };
14025
+ //#endregion
13483
14026
  //#region src/utils/service-app-manifest.utils.ts
13484
14027
  const SERVICE_APP_ID_PATTERN$1 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
13485
14028
  const SERVICE_ACTION_RISKS = new Set([
@@ -13506,19 +14049,56 @@ function parseServiceAppManifest(raw, options = {}) {
13506
14049
  const id = readRequiredString$6(parsed, "id");
13507
14050
  if (!SERVICE_APP_ID_PATTERN$1.test(id)) throw new Error("service app id must be kebab-case.");
13508
14051
  const protocol = readOptionalString$8(parsed, "protocol") ?? "mcp";
13509
- if (protocol !== "mcp") throw new Error("service app protocol must be mcp.");
13510
- const launch = new AppServiceLaunchService(options.platformTargetService).resolve(parsed, options.target);
14052
+ if (protocol !== "mcp" && protocol !== "wasi-component") throw new Error("service app protocol must be mcp or wasi-component.");
14053
+ const launch = protocol === "mcp" ? new AppServiceLaunchService(options.platformTargetService).resolve(parsed, options.target) : void 0;
14054
+ const componentEntry = protocol === "wasi-component" ? readPortableComponentEntry(parsed) : void 0;
14055
+ const lifecycle = readServiceAppLifecycle(parsed.lifecycle);
14056
+ if (lifecycle.mode !== "action" && protocol !== "wasi-component") throw new Error(`${lifecycle.mode} service app lifecycle requires wasi-component protocol.`);
13511
14057
  return {
13512
14058
  id,
13513
14059
  title: readRequiredString$6(parsed, "title"),
13514
14060
  description: readOptionalString$8(parsed, "description"),
13515
14061
  enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
13516
14062
  protocol,
13517
- command: launch.command,
13518
- args: launch.args,
14063
+ command: launch?.command,
14064
+ args: launch?.args,
14065
+ componentEntry,
14066
+ providerIds: readProviderIds(parsed.providers),
14067
+ lifecycle,
13519
14068
  actions: readManifestActions(parsed.actions)
13520
14069
  };
13521
14070
  }
14071
+ function readServiceAppLifecycle(value) {
14072
+ if (value === void 0) return { mode: "action" };
14073
+ if (!isRecord$7(value)) throw new Error("service app lifecycle must be an object.");
14074
+ const mode = readOptionalString$8(value, "mode") ?? "action";
14075
+ if (mode === "action") return { mode };
14076
+ if (mode === "provider") return { mode };
14077
+ if (mode !== "resident") throw new Error("service app lifecycle.mode must be action, resident or provider.");
14078
+ const eventIntervalMs = readOptionalNumber(value, "eventIntervalMs");
14079
+ if (eventIntervalMs === void 0 || !Number.isInteger(eventIntervalMs) || eventIntervalMs < 250 || eventIntervalMs > 6e4) throw new Error("resident service app lifecycle.eventIntervalMs must be an integer between 250 and 60000.");
14080
+ return {
14081
+ mode,
14082
+ eventIntervalMs
14083
+ };
14084
+ }
14085
+ function readProviderIds(value) {
14086
+ if (value === void 0) return [];
14087
+ if (!Array.isArray(value)) throw new Error("service app providers must be an array.");
14088
+ const providerIds = value.map((entry) => {
14089
+ if (typeof entry !== "string" || !SERVICE_APP_ID_PATTERN$1.test(entry.trim())) throw new Error("service app providers must contain kebab-case service app ids.");
14090
+ return entry.trim();
14091
+ });
14092
+ return Array.from(new Set(providerIds));
14093
+ }
14094
+ function readPortableComponentEntry(record) {
14095
+ const component = record.component;
14096
+ if (!isRecord$7(component)) throw new Error("service app component is required for wasi-component.");
14097
+ const entry = readRequiredString$6(component, "entry").replace(/\\/g, "/");
14098
+ if (path.isAbsolute(entry) || entry.includes("\0") || entry.split("/").includes("..")) throw new Error("service app component.entry must be a package-relative path.");
14099
+ if (!entry.endsWith(".wasm")) throw new Error("service app component.entry must reference a .wasm file.");
14100
+ return entry;
14101
+ }
13522
14102
  function readManifestActions(value) {
13523
14103
  if (value === void 0) throw new Error("service app actions are required.");
13524
14104
  if (!isRecord$7(value)) throw new Error("service app actions must be an object.");
@@ -13531,11 +14111,14 @@ function readManifestActions(value) {
13531
14111
  if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
13532
14112
  const inputSchema = action.inputSchema;
13533
14113
  if (inputSchema !== void 0 && !isRecord$7(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
14114
+ const timeoutMs = readOptionalNumber(action, "timeoutMs");
14115
+ if (timeoutMs !== void 0 && (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 3e5)) throw new Error(`service app action ${name} timeoutMs must be an integer between 100 and 300000.`);
13534
14116
  actions[name] = {
13535
14117
  risk,
13536
14118
  title: readOptionalString$8(action, "title"),
13537
14119
  description: readOptionalString$8(action, "description"),
13538
- inputSchema
14120
+ inputSchema,
14121
+ timeoutMs
13539
14122
  };
13540
14123
  }
13541
14124
  return actions;
@@ -13553,10 +14136,49 @@ function readOptionalBoolean$1(record, key) {
13553
14136
  if (typeof record[key] !== "boolean") throw new Error(`service app ${key} must be boolean.`);
13554
14137
  return record[key];
13555
14138
  }
14139
+ function readOptionalNumber(record, key) {
14140
+ if (record[key] === void 0) return;
14141
+ if (typeof record[key] !== "number") throw new Error(`service app ${key} must be number.`);
14142
+ return record[key];
14143
+ }
13556
14144
  function isRecord$7(value) {
13557
14145
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
13558
14146
  }
13559
14147
  //#endregion
14148
+ //#region src/services/service-app-lifecycle.service.ts
14149
+ var ServiceAppLifecycleService = class {
14150
+ constructor(params) {
14151
+ this.params = params;
14152
+ }
14153
+ startDiscovered = async (registrations) => {
14154
+ const active = registrations.filter(({ manifest, record }) => record.enabled && manifest.lifecycle && manifest.lifecycle.mode !== "action");
14155
+ await Promise.allSettled(this.order(active).map(async ({ manifest, record }) => await this.params.runtimeService.start?.({
14156
+ app: record,
14157
+ manifest
14158
+ })));
14159
+ };
14160
+ activatePackageComponents = async (components) => {
14161
+ const registrations = [];
14162
+ for (const component of components.filter((entry) => entry.kind === "service")) {
14163
+ const manifest = await readServiceAppManifest(component.sourcePath);
14164
+ if (!manifest.lifecycle || manifest.lifecycle.mode === "action") continue;
14165
+ registrations.push({
14166
+ manifest,
14167
+ record: this.params.recordService.fromManifest(component.sourcePath, manifest, component, component.storage)
14168
+ });
14169
+ }
14170
+ for (const { manifest, record } of this.order(registrations)) await this.params.runtimeService.start?.({
14171
+ app: record,
14172
+ manifest
14173
+ });
14174
+ };
14175
+ deactivatePackageComponents = async (components) => {
14176
+ const serviceIds = components.filter((component) => component.kind === "service").map((component) => component.id);
14177
+ await Promise.all(serviceIds.map(async (serviceId) => await this.params.runtimeService.stop(serviceId)));
14178
+ };
14179
+ order = (registrations) => [...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "provider"), ...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "resident")];
14180
+ };
14181
+ //#endregion
13560
14182
  //#region src/services/service-app-record.service.ts
13561
14183
  var ServiceAppRecordService = class {
13562
14184
  instanceStorageService = new AppInstanceStorageService();
@@ -13638,7 +14260,12 @@ var ServiceAppRecordService = class {
13638
14260
  dataDirectory: storage?.dataDirectory,
13639
14261
  instanceId: packageSource?.instanceId ?? storage?.instanceId,
13640
14262
  storage,
13641
- isolation: packageSource?.isolation ?? "full-user"
14263
+ isolation: packageSource?.isolation ?? "full-user",
14264
+ runtimeProfile: packageSource?.runtimeProfile ?? "native-process",
14265
+ permissions: packageSource?.permissions ?? {},
14266
+ componentPath: manifest.componentEntry ? join(dirPath, manifest.componentEntry) : void 0,
14267
+ providerIds: manifest.providerIds,
14268
+ lifecycle: manifest.lifecycle
13642
14269
  };
13643
14270
  };
13644
14271
  failedWorkspaceRecord = (id, dirPath, error) => ({
@@ -13669,7 +14296,9 @@ var ServiceAppRecordService = class {
13669
14296
  dataDirectory: source.dataDirectory,
13670
14297
  instanceId: source.instanceId,
13671
14298
  storage: source.storage,
13672
- isolation: source.isolation
14299
+ isolation: source.isolation,
14300
+ runtimeProfile: source.runtimeProfile,
14301
+ permissions: source.permissions
13673
14302
  });
13674
14303
  toTitle = (value) => basename(value).replace(/[-_]+/g, " ").trim() || value;
13675
14304
  getWorkspaceInstanceDirectory = (serviceId) => join(this.params.getWorkspacePath(), ".nextclaw", "app-instances", serviceId, "default");
@@ -13838,13 +14467,16 @@ var ServiceActionGrantService = class {
13838
14467
  const results = [];
13839
14468
  for (const grant of grants) {
13840
14469
  const actionId = readServiceActionTargetId(grant.resource.target);
13841
- if (!actionId || grant.subject.type !== "panel-app") continue;
14470
+ if (!actionId || grant.subject.type !== "panel-app" && grant.subject.type !== "agent") continue;
13842
14471
  try {
13843
14472
  const action = await this.params.resolveAction(actionId);
13844
14473
  results.push({
13845
- caller: {
14474
+ caller: grant.subject.type === "panel-app" ? {
13846
14475
  surface: "panel-app",
13847
14476
  appId: grant.subject.id
14477
+ } : {
14478
+ surface: "agent",
14479
+ agentId: grant.subject.id
13848
14480
  },
13849
14481
  actionId,
13850
14482
  risk: action.risk,
@@ -13860,7 +14492,7 @@ var ServiceActionGrantService = class {
13860
14492
  await this.params.capabilityGrantManager.revoke({
13861
14493
  subject: {
13862
14494
  type: caller.surface,
13863
- id: caller.appId
14495
+ id: getServiceActionCallerId(caller)
13864
14496
  },
13865
14497
  resourceType: "service.action",
13866
14498
  target: { actionId }
@@ -13961,28 +14593,6 @@ function mergeServiceAppRuntimeActions({ record, manifest, runtimeActions }) {
13961
14593
  return [...declared, ...undeclared].sort((left, right) => left.id.localeCompare(right.id));
13962
14594
  }
13963
14595
  //#endregion
13964
- //#region src/utils/service-app-error.utils.ts
13965
- const SERVICE_APP_ERROR_CODES = new Set([
13966
- "AUTHORIZATION_REQUIRED",
13967
- "SERVICE_APP_ACTION_NOT_DECLARED",
13968
- "SERVICE_APP_ACTION_NOT_FOUND",
13969
- "SERVICE_APP_INVALID_ACTION",
13970
- "SERVICE_APP_INVALID_CALLER",
13971
- "SERVICE_APP_INVALID_MANIFEST",
13972
- "SERVICE_APP_MANAGED_SOURCE",
13973
- "SERVICE_APP_NOT_FOUND",
13974
- "SERVICE_APP_READ_FAILED",
13975
- "SERVICE_APP_RUNTIME_FAILED"
13976
- ]);
13977
- var ServiceAppError = class extends Error {
13978
- constructor(code, message) {
13979
- super(message);
13980
- this.code = code;
13981
- this.name = "ServiceAppError";
13982
- }
13983
- };
13984
- const isServiceAppError = (error) => error instanceof ServiceAppError || typeof error === "object" && error !== null && error.name === "ServiceAppError" && typeof error.message === "string" && SERVICE_APP_ERROR_CODES.has(error.code);
13985
- //#endregion
13986
14596
  //#region src/managers/service-app.manager.ts
13987
14597
  const SERVICE_APP_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
13988
14598
  var ServiceAppManager = class {
@@ -13991,14 +14601,22 @@ var ServiceAppManager = class {
13991
14601
  recordService;
13992
14602
  actionGrants;
13993
14603
  packageRuntime;
14604
+ lifecycleService;
13994
14605
  reconciliationDiagnostics = [];
13995
14606
  constructor(params) {
13996
14607
  this.params = params;
13997
- this.runtimeService = params.runtimeService ?? new McpServiceAppRuntimeService({ getConfig: () => params.configManager.config });
14608
+ this.runtimeService = params.runtimeService ?? new ServiceAppRuntimeService({
14609
+ getConfig: () => params.configManager.config,
14610
+ portableServiceRunnerPath: params.portableServiceRunnerPath
14611
+ });
13998
14612
  this.recordService = new ServiceAppRecordService({
13999
14613
  getWorkspacePath: this.getWorkspacePath,
14000
14614
  runtimeService: this.runtimeService
14001
14615
  });
14616
+ this.lifecycleService = new ServiceAppLifecycleService({
14617
+ recordService: this.recordService,
14618
+ runtimeService: this.runtimeService
14619
+ });
14002
14620
  this.actionGrants = new ServiceActionGrantService({
14003
14621
  capabilityGrantManager: params.capabilityGrantManager,
14004
14622
  resolveAction: this.requireServiceAction
@@ -14017,6 +14635,7 @@ var ServiceAppManager = class {
14017
14635
  lockPathForAppId: (appId) => this.getServiceAppLockPath(this.getWorkspacePath(), appId),
14018
14636
  serviceAppsPath: this.getServiceAppsPath(this.getWorkspacePath())
14019
14637
  });
14638
+ await this.lifecycleService.startDiscovered(await this.listValidServiceApps());
14020
14639
  };
14021
14640
  listServiceApps = async () => {
14022
14641
  const workspacePath = this.getWorkspacePath();
@@ -14052,8 +14671,8 @@ var ServiceAppManager = class {
14052
14671
  });
14053
14672
  };
14054
14673
  invokeServiceAction = async (actionId, request) => {
14055
- this.assertCaller(request.caller);
14056
- this.assertDeclaredAction(actionId, request.declaredActions);
14674
+ assertServiceActionCaller(request.caller, this.params.hasAgent);
14675
+ assertServiceActionDeclared(request.caller, actionId, request.declaredActions);
14057
14676
  const { manifest, record } = await this.requireServiceAppForAction(actionId, true);
14058
14677
  const actionName = getServiceActionName(actionId, record.id);
14059
14678
  if (!Object.hasOwn(manifest.actions, actionName)) throw new ServiceAppError("SERVICE_APP_ACTION_NOT_FOUND", "service action not found");
@@ -14080,30 +14699,33 @@ var ServiceAppManager = class {
14080
14699
  return grant;
14081
14700
  };
14082
14701
  grantServiceActions = async (actionIds, request) => {
14083
- this.assertCaller(request.caller);
14702
+ assertServiceActionCaller(request.caller, this.params.hasAgent);
14084
14703
  const normalizedActionIds = this.normalizeActionIds(actionIds);
14085
14704
  if (normalizedActionIds.length === 0) throw new ServiceAppError("SERVICE_APP_INVALID_ACTION", "service action id is invalid");
14086
14705
  const actions = [];
14087
14706
  for (const actionId of normalizedActionIds) {
14088
- this.assertDeclaredAction(actionId, request.declaredActions);
14707
+ assertServiceActionDeclared(request.caller, actionId, request.declaredActions);
14089
14708
  actions.push(await this.requireServiceAction(actionId));
14090
14709
  }
14091
14710
  return await this.actionGrants.grant(request.caller, actions);
14092
14711
  };
14093
14712
  listServiceActionGrants = async () => await this.actionGrants.list();
14094
14713
  revokeServiceAction = async (caller, actionId) => {
14095
- this.assertCaller(caller);
14714
+ assertServiceActionCaller(caller, this.params.hasAgent);
14096
14715
  await this.actionGrants.revoke(caller, actionId);
14097
14716
  };
14098
14717
  matchesCapabilityGrant = async (grant) => {
14099
- if (grant.subject.type !== "panel-app" || grant.resource.type !== "service.action") return false;
14718
+ if (grant.subject.type !== "panel-app" && grant.subject.type !== "agent" || grant.resource.type !== "service.action") return false;
14100
14719
  const actionId = readServiceActionTargetId(grant.resource.target);
14101
14720
  if (!actionId) return false;
14102
14721
  try {
14103
14722
  const action = await this.requireServiceAction(actionId);
14104
- return getCapabilityGrantKey(grant) === getCapabilityGrantKey(createServiceActionGrantRequest({
14723
+ return getCapabilityGrantKey(grant) === getCapabilityGrantKey(createServiceActionGrantRequest(grant.subject.type === "panel-app" ? {
14105
14724
  surface: "panel-app",
14106
14725
  appId: grant.subject.id
14726
+ } : {
14727
+ surface: "agent",
14728
+ agentId: grant.subject.id
14107
14729
  }, action));
14108
14730
  } catch {
14109
14731
  return false;
@@ -14183,10 +14805,8 @@ var ServiceAppManager = class {
14183
14805
  }
14184
14806
  }
14185
14807
  };
14186
- deactivatePackageComponents = async (components) => {
14187
- const serviceIds = components.filter((component) => component.kind === "service").map((component) => component.id);
14188
- await Promise.all(serviceIds.map(async (serviceId) => await this.runtimeService.stop(serviceId)));
14189
- };
14808
+ activatePackageComponents = async (components) => await this.lifecycleService.activatePackageComponents(components);
14809
+ deactivatePackageComponents = async (components) => await this.lifecycleService.deactivatePackageComponents(components);
14190
14810
  preparePackageComponentDeactivation = async (components) => await this.packageRuntime.prepareDeactivation(components);
14191
14811
  removePackageComponentGrants = async (components) => await this.actionGrants.removePackageGrants(new Set(components.filter((component) => component.kind === "service").map((component) => component.id)));
14192
14812
  withGrantState = async (action, params) => {
@@ -14267,12 +14887,6 @@ var ServiceAppManager = class {
14267
14887
  }));
14268
14888
  return [...workspaceEntries, ...packageEntries].filter((entry) => Boolean(entry));
14269
14889
  };
14270
- assertCaller = (caller) => {
14271
- if (caller.surface !== "panel-app" || !caller.appId.trim()) throw new ServiceAppError("SERVICE_APP_INVALID_CALLER", "service action caller is invalid");
14272
- };
14273
- assertDeclaredAction = (actionId, declaredActions) => {
14274
- if (!declaredActions.includes(actionId)) throw new ServiceAppError("SERVICE_APP_ACTION_NOT_DECLARED", "panel app did not declare this service action");
14275
- };
14276
14890
  normalizeActionIds = (actionIds) => Array.from(new Set(actionIds.map((actionId) => actionId.trim()).filter((actionId) => actionId.length > 0)));
14277
14891
  getWorkspacePath = () => getWorkspacePathFromConfig(this.params.configManager.config);
14278
14892
  getServiceAppsPath = (workspacePath) => join(workspacePath, DEFAULT_SERVICE_APPS_DIR);
@@ -21248,6 +21862,57 @@ function readOptionalString$1(value) {
21248
21862
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
21249
21863
  }
21250
21864
  //#endregion
21865
+ //#region src/utils/service-action-tool.utils.ts
21866
+ const MAX_TOOL_NAME_LENGTH = 64;
21867
+ const HASH_LENGTH = 8;
21868
+ const TOOL_PREFIX = "service__";
21869
+ function buildServiceActionToolName(actionId) {
21870
+ const readable = actionId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "action";
21871
+ const suffix = `__${createHash("sha256").update(actionId).digest("hex").slice(0, HASH_LENGTH)}`;
21872
+ const available = MAX_TOOL_NAME_LENGTH - 9 - suffix.length;
21873
+ return `${TOOL_PREFIX}${readable.slice(0, available)}${suffix}`;
21874
+ }
21875
+ //#endregion
21876
+ //#region src/contributions/tool-provider/providers/service-action-tool.provider.ts
21877
+ const EMPTY_OBJECT_SCHEMA = {
21878
+ type: "object",
21879
+ properties: {},
21880
+ additionalProperties: false
21881
+ };
21882
+ var ServiceActionToolProvider = class {
21883
+ constructor(runContextService, serviceAppManager) {
21884
+ this.runContextService = runContextService;
21885
+ this.serviceAppManager = serviceAppManager;
21886
+ }
21887
+ provide = async (request) => {
21888
+ const { toolRunContext } = await this.runContextService.resolve(request);
21889
+ const caller = {
21890
+ surface: "agent",
21891
+ agentId: toolRunContext.agentId
21892
+ };
21893
+ return (await this.serviceAppManager.listServiceActions({ caller })).filter((action) => action.grantState === "granted").map((action) => this.toTool(caller, action));
21894
+ };
21895
+ toTool = (caller, action) => ({
21896
+ name: buildServiceActionToolName(action.id),
21897
+ description: [
21898
+ action.title ?? action.name,
21899
+ action.description,
21900
+ `NextClaw Service Action: ${action.id}`
21901
+ ].filter(Boolean).join("\n"),
21902
+ parameters: action.inputSchema ?? EMPTY_OBJECT_SCHEMA,
21903
+ supportsParallelToolCalls: action.risk === "read",
21904
+ execute: async (args) => await this.serviceAppManager.invokeServiceAction(action.id, {
21905
+ caller,
21906
+ input: readInput(args)
21907
+ })
21908
+ });
21909
+ };
21910
+ function readInput(value) {
21911
+ if (value === void 0) return {};
21912
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Service Action tool input must be an object.");
21913
+ return value;
21914
+ }
21915
+ //#endregion
21251
21916
  //#region src/contributions/tool-provider/services/tool-provider-run-context.service.ts
21252
21917
  var ToolProviderRunContextService = class {
21253
21918
  constructor(sessionManager, agentManager, configManager) {
@@ -21304,6 +21969,7 @@ var ToolProviderContribution = class extends Contribution$1 {
21304
21969
  new ProjectToolProvider(this.kernel.projectManager),
21305
21970
  new SessionToolProvider(runContextService, this.kernel.sessionManager, this.kernel.sessionRequests, this.kernel.sessionSearch),
21306
21971
  new AssetToolProvider(this.kernel.assetStore),
21972
+ new ServiceActionToolProvider(runContextService, this.kernel.serviceAppManager),
21307
21973
  new McpToolProvider(runContextService, this.kernel.mcpManager)
21308
21974
  ];
21309
21975
  };
@@ -21332,11 +21998,13 @@ function createKernelOperationalManagers(params) {
21332
21998
  };
21333
21999
  }
21334
22000
  function createKernelServiceAppManagers(params) {
21335
- const { appHomeDirectory, appPackageManager, capabilityGrantManager, configManager } = params;
22001
+ const { appHomeDirectory, appPackageManager, capabilityGrantManager, configManager, hasAgent, portableServiceRunnerPath } = params;
21336
22002
  const serviceAppManager = new ServiceAppManager({
21337
22003
  configManager,
21338
22004
  listPackageComponentSources: appPackageManager.listActiveComponentSources,
21339
- capabilityGrantManager
22005
+ capabilityGrantManager,
22006
+ hasAgent,
22007
+ portableServiceRunnerPath
21340
22008
  });
21341
22009
  return {
21342
22010
  serviceAppManager,
@@ -21405,6 +22073,9 @@ function installKernelAppPackageRuntimeHooks(params) {
21405
22073
  await panelAppManager.assertCanActivatePackageComponents(sources);
21406
22074
  await serviceAppManager.assertCanActivatePackageComponents(sources);
21407
22075
  },
22076
+ afterActivate: async (sources) => {
22077
+ await serviceAppManager.activatePackageComponents(sources);
22078
+ },
21408
22079
  beforeDeactivate: async (sources) => {
21409
22080
  panelAppManager.deactivatePackageComponents(sources);
21410
22081
  await serviceAppManager.deactivatePackageComponents(sources);
@@ -21548,7 +22219,9 @@ var NextclawKernel = class {
21548
22219
  appHomeDirectory: resolveKernelAppHomeDirectory(options),
21549
22220
  appPackageManager: this.appPackageManager,
21550
22221
  configManager: this.configManager,
21551
- capabilityGrantManager: this.capabilityGrants
22222
+ capabilityGrantManager: this.capabilityGrants,
22223
+ hasAgent: (agentId) => this.agents.getAgent(agentId) !== null,
22224
+ portableServiceRunnerPath: options.portableServiceRunnerPath
21552
22225
  }));
21553
22226
  installKernelAppPackageRuntimeHooks({
21554
22227
  appPackageManager: this.appPackageManager,
@@ -22776,6 +23449,6 @@ function resolveLegacyEventType(message) {
22776
23449
  return `message.${role || "other"}`;
22777
23450
  }
22778
23451
  //#endregion
22779
- export { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, AccessManager, AgentManager, AgentRunClient, AppDataError, AppDataManager, AppPackageError, AppPackageManager, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_CONTINUATION_TEXT, CONTEXT_COMPACTION_PROJECTION_KIND, CONTEXT_COMPACTION_PROJECTION_METADATA_KEY, CONTEXT_COMPACTION_SYSTEM_PREAMBLE, CONTEXT_COMPACTION_TIMELINE_KIND, CapabilityGrantLegacyMigrationService, CapabilityGrantManager, CapabilityGrantStore, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionJournalRecoveryService, ContextCompactionPreflightService, Contribution, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, DESKTOP_HOST_ACCESS, DESKTOP_HOST_PROTOCOL_VERSION, DesktopHostCapabilityManager, DesktopNodeReplService, DesktopSessionStateService, EventBus, ExtensionManager, FeatureControlsService, GatewayInboundProcessor, InboxDeliveryError, InboxDeliveryManager, Ingress, LlmProviderManager, LlmUsageManager, LlmUsageStore, MAX_INBOX_DELIVERY_CONTENT_LENGTH, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawHarness, NextclawHarnessError, NextclawKernel, ObservationManager, PANEL_APP_AGENT_CAPABILITIES, PROJECT_TEMPLATE_IDS, PROVIDER_MODEL_CATALOG_REFRESH_INTERVAL_MS, PanelAppAssetTokenService, PanelAppError, PanelAppManager, PreferenceError, PreferenceManager, ProjectError, ProjectManager, ProviderManagerNcpLLMApi, ProviderModelCatalogManager, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionContextCompactionError, SessionContextCompactionManager, SessionManager, SessionMessageCursorError, SessionRequestManager, SessionSettingsError, SkillManager, SystemObjectReferenceError, SystemObjectReferenceManager, UnavailableDesktopHost, UpdateManifestReader, assertObservationJsonValue, assertObservationPredicate, buildAgentRunSendPayload, buildContextCompactionModelProjection, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildNextclawNcpRunContext, buildObservationEventModelMessage, buildServiceActionId, capabilityGrantCovers, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createCapabilityDeclarationFingerprint, createContextCompactionMessageId, createContextWindowSignature, createCronJobSystemObjectProvider, createDesktopHostError, createInboxDeliverySystemObjectProvider, createLlmUsageRecord, createPanelAppAgentGrantRequest, createPanelAppClientGrantRequest, createServiceActionGrantRequest, createTypedKey, describeAgentRuntimeSessionTypes, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, dispatchPromptOverNcpResult, evaluateObservationEventAdmission, eventKeys, getAutomaticUpdateCheckDelay, getCapabilityGrantKey, getServiceActionName, getServiceAppManifestPath, getUiContentParamsBootstrapScript, getUnsignedUpdateManifest, hasLlmUsageTelemetry, ingressKeys, injectUiContentParamsBootstrap, isAppDataError, isAppPackageError, isContextCompactionProjectionMessage, isContextCompactionTimelineMessage, isContextWindowSnapshot, isInboxDeliveryError, isPanelAppAgentCapability, isPanelAppError, isPreferenceError, isProjectError, isReplyCapableChannel, isServiceAppError, isSessionContextCompactionError, isSessionMessageCursorError, isSessionSettingsError, isSystemObjectReferenceError, listExtensionChannelIds, listServiceAppManifestActions, matchesCapabilityGrantFilter, matchesObservationPredicate, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeCapabilityGrantRequest, normalizeLlmUsageModel, normalizeOptionalString, parseObservationDuration, parseServiceAppManifest, parseSkillFrontmatter, readContextCompactionCheckpoint, readContextWindowEventSessionId, readJsonPointer, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceActionTargetId, readServiceAppManifest, resolveAgentRuntimeEntries, resolveAutomaticUpdateCheckIntervalMs, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveSessionChannelContext, runGatewayInboundLoop, runNextclawTask, sanitizeLlmUsage, serializeContextTail, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, startPromptOverNcpExecution, stripSkillFrontmatter, syncSessionThinkingPreference, toBoundedJson, toNcpMessages, waitForAgentRuntimeSessionReply };
23452
+ export { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, AccessManager, AgentManager, AgentRunClient, AppDataError, AppDataManager, AppPackageError, AppPackageManager, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_CONTINUATION_TEXT, CONTEXT_COMPACTION_PROJECTION_KIND, CONTEXT_COMPACTION_PROJECTION_METADATA_KEY, CONTEXT_COMPACTION_SYSTEM_PREAMBLE, CONTEXT_COMPACTION_TIMELINE_KIND, CapabilityGrantLegacyMigrationService, CapabilityGrantManager, CapabilityGrantStore, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionJournalRecoveryService, ContextCompactionPreflightService, Contribution, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, DESKTOP_HOST_ACCESS, DESKTOP_HOST_PROTOCOL_VERSION, DesktopHostCapabilityManager, DesktopNodeReplService, DesktopSessionStateService, EventBus, ExtensionManager, FeatureControlsService, GatewayInboundProcessor, InboxDeliveryError, InboxDeliveryManager, Ingress, LlmProviderManager, LlmUsageManager, LlmUsageStore, MAX_INBOX_DELIVERY_CONTENT_LENGTH, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawHarness, NextclawHarnessError, NextclawKernel, ObservationManager, PANEL_APP_AGENT_CAPABILITIES, PROJECT_TEMPLATE_IDS, PROVIDER_MODEL_CATALOG_REFRESH_INTERVAL_MS, PanelAppAssetTokenService, PanelAppError, PanelAppManager, PreferenceError, PreferenceManager, ProjectError, ProjectManager, ProviderManagerNcpLLMApi, ProviderModelCatalogManager, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, ServiceAppRuntimeService, SessionContextCompactionError, SessionContextCompactionManager, SessionManager, SessionMessageCursorError, SessionRequestManager, SessionSettingsError, SkillManager, SystemObjectReferenceError, SystemObjectReferenceManager, UnavailableDesktopHost, UpdateManifestReader, assertObservationJsonValue, assertObservationPredicate, buildAgentRunSendPayload, buildContextCompactionModelProjection, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildNextclawNcpRunContext, buildObservationEventModelMessage, buildServiceActionId, capabilityGrantCovers, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createCapabilityDeclarationFingerprint, createContextCompactionMessageId, createContextWindowSignature, createCronJobSystemObjectProvider, createDesktopHostError, createInboxDeliverySystemObjectProvider, createLlmUsageRecord, createPanelAppAgentGrantRequest, createPanelAppClientGrantRequest, createServiceActionGrantRequest, createTypedKey, describeAgentRuntimeSessionTypes, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, dispatchPromptOverNcpResult, evaluateObservationEventAdmission, eventKeys, getAutomaticUpdateCheckDelay, getCapabilityGrantKey, getServiceActionName, getServiceAppManifestPath, getUiContentParamsBootstrapScript, getUnsignedUpdateManifest, hasLlmUsageTelemetry, ingressKeys, injectUiContentParamsBootstrap, isAppDataError, isAppPackageError, isContextCompactionProjectionMessage, isContextCompactionTimelineMessage, isContextWindowSnapshot, isInboxDeliveryError, isPanelAppAgentCapability, isPanelAppError, isPreferenceError, isProjectError, isReplyCapableChannel, isServiceAppError, isSessionContextCompactionError, isSessionMessageCursorError, isSessionSettingsError, isSystemObjectReferenceError, listExtensionChannelIds, listServiceAppManifestActions, matchesCapabilityGrantFilter, matchesObservationPredicate, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeCapabilityGrantRequest, normalizeLlmUsageModel, normalizeOptionalString, parseObservationDuration, parseServiceAppManifest, parseSkillFrontmatter, readContextCompactionCheckpoint, readContextWindowEventSessionId, readJsonPointer, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceActionTargetId, readServiceAppManifest, resolveAgentRuntimeEntries, resolveAutomaticUpdateCheckIntervalMs, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveSessionChannelContext, runGatewayInboundLoop, runNextclawTask, sanitizeLlmUsage, serializeContextTail, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, startPromptOverNcpExecution, stripSkillFrontmatter, syncSessionThinkingPreference, toBoundedJson, toNcpMessages, waitForAgentRuntimeSessionReply };
22780
23453
 
22781
23454
  //# sourceMappingURL=index.js.map