@nextclaw/kernel 0.11.0 → 0.12.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/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,462 @@ 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.once("error", (error) => {
13683
+ if (this.child === child) this.handleChildFailure(error);
13684
+ });
13685
+ child.once("exit", (code, signal) => {
13686
+ if (this.child !== child) return;
13687
+ this.child = void 0;
13688
+ const error = new PortableServiceRunnerError("PORTABLE_RUNNER_EXITED", `Portable runner exited (${signal ?? code ?? "unknown"}). ${this.stderrTail.join(" ")}`.trim());
13689
+ this.failAll(error);
13690
+ this.params.onUnexpectedExit?.(error);
13691
+ });
13692
+ return child;
13693
+ };
13694
+ handleLine = (line) => {
13695
+ let response;
13696
+ try {
13697
+ response = JSON.parse(line);
13698
+ } catch {
13699
+ this.handleChildFailure(/* @__PURE__ */ new Error(`Portable runner returned invalid JSON: ${line}`));
13700
+ return;
13701
+ }
13702
+ if (response.protocolVersion !== PORTABLE_RUNNER_PROTOCOL_VERSION) {
13703
+ const error = new PortableServiceRunnerError("PORTABLE_RUNNER_PROTOCOL_MISMATCH", `Portable runner protocol mismatch: expected ${PORTABLE_RUNNER_PROTOCOL_VERSION}, received ${response.protocolVersion ?? "missing"}.`);
13704
+ const child = this.child;
13705
+ this.handleChildFailure(error);
13706
+ child?.kill("SIGKILL");
13707
+ return;
13708
+ }
13709
+ const pending = this.pending.get(response.requestId);
13710
+ if (!pending) return;
13711
+ clearTimeout(pending.timeout);
13712
+ this.pending.delete(response.requestId);
13713
+ if (response.ok) {
13714
+ pending.resolve(response.result);
13715
+ return;
13716
+ }
13717
+ pending.reject(new PortableServiceRunnerError(response.error?.code ?? "PORTABLE_RUNTIME_FAILED", response.error?.message ?? "Portable runner request failed."));
13718
+ };
13719
+ handleChildFailure = (error) => {
13720
+ this.failAll(error);
13721
+ this.child = void 0;
13722
+ };
13723
+ failAll = (error) => {
13724
+ for (const pending of this.pending.values()) {
13725
+ clearTimeout(pending.timeout);
13726
+ pending.reject(error);
13727
+ }
13728
+ this.pending.clear();
13729
+ };
13730
+ toRunnerApp = (app) => ({
13731
+ id: app.id,
13732
+ componentPath: app.componentPath,
13733
+ dataDirectory: app.dataDirectory,
13734
+ allowedDomains: app.permissions.allowedDomains ?? [],
13735
+ allowedProviderIds: app.providerIds ?? [],
13736
+ storageEnabled: Boolean(app.permissions.storage)
13737
+ });
13738
+ resolveRunnerPath = () => {
13739
+ const runnerPath = (this.params.env ?? process.env).NEXTCLAW_WASMTIME_RUNNER_PATH?.trim() || this.params.runnerPath?.trim();
13740
+ 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.");
13741
+ try {
13742
+ accessSync(runnerPath, process.platform === "win32" ? constants.F_OK : constants.X_OK);
13743
+ } catch {
13744
+ throw new PortableServiceRunnerError("PORTABLE_RUNNER_UNAVAILABLE", `Portable runner is missing or not executable: ${runnerPath}`);
13745
+ }
13746
+ return runnerPath;
13747
+ };
13748
+ };
13749
+ //#endregion
13750
+ //#region src/services/portable-service-app-runtime.service.ts
13751
+ var PortableServiceAppRuntimeService = class {
13752
+ runner;
13753
+ states = /* @__PURE__ */ new Map();
13754
+ apps = /* @__PURE__ */ new Map();
13755
+ providers = /* @__PURE__ */ new Set();
13756
+ persistentRegistrations = /* @__PURE__ */ new Map();
13757
+ residentTimers = /* @__PURE__ */ new Map();
13758
+ residentDeliveries = /* @__PURE__ */ new Map();
13759
+ recoveryPromise;
13760
+ constructor(params = {}) {
13761
+ this.runner = new PortableServiceRunnerClientService({
13762
+ runnerPath: params.runnerPath,
13763
+ onUnexpectedExit: (error) => {
13764
+ this.recoverPersistentComponentsIfNeeded(error);
13765
+ }
13766
+ });
13767
+ }
13768
+ getStatus = (appId) => this.states.get(appId) ?? { status: "idle" };
13769
+ start = async ({ app, manifest }) => {
13770
+ if (!app.enabled || !manifest.lifecycle || manifest.lifecycle.mode === "action") return;
13771
+ this.persistentRegistrations.set(app.id, {
13772
+ app,
13773
+ manifest
13774
+ });
13775
+ const runnerApp = this.toRunnerApp(app, manifest.providerIds);
13776
+ this.apps.set(app.id, runnerApp);
13777
+ if (manifest.lifecycle.mode === "provider") {
13778
+ if (this.providers.has(app.id)) return;
13779
+ const lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13780
+ this.states.set(app.id, {
13781
+ status: "starting",
13782
+ lastStartedAt
13783
+ });
13784
+ try {
13785
+ await this.runner.startProvider(runnerApp, {
13786
+ mode: "provider",
13787
+ startedAt: lastStartedAt
13788
+ });
13789
+ this.providers.add(app.id);
13790
+ this.states.set(app.id, {
13791
+ status: "running",
13792
+ lastStartedAt,
13793
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13794
+ });
13795
+ } catch (error) {
13796
+ this.markFailed(app.id, lastStartedAt, error);
13797
+ throw error;
13798
+ }
13799
+ return;
13800
+ }
13801
+ if (this.residentTimers.has(app.id)) return;
13802
+ const lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13803
+ this.states.set(app.id, {
13804
+ status: "starting",
13805
+ lastStartedAt
13806
+ });
13807
+ try {
13808
+ await this.runner.startResident(runnerApp, {
13809
+ eventIntervalMs: manifest.lifecycle.eventIntervalMs,
13810
+ startedAt: lastStartedAt
13811
+ });
13812
+ const timer = setInterval(() => {
13813
+ this.scheduleResidentEvent({
13814
+ appId: app.id,
13815
+ eventIntervalMs: manifest.lifecycle?.mode === "resident" ? manifest.lifecycle.eventIntervalMs : 0
13816
+ });
13817
+ }, manifest.lifecycle.eventIntervalMs);
13818
+ timer.unref();
13819
+ this.residentTimers.set(app.id, timer);
13820
+ this.states.set(app.id, {
13821
+ status: "running",
13822
+ lastStartedAt,
13823
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13824
+ });
13825
+ } catch (error) {
13826
+ this.markFailed(app.id, lastStartedAt, error);
13827
+ throw error;
13828
+ }
13829
+ };
13830
+ listActions = async ({ app, manifest }) => {
13831
+ if (!app.enabled) return [];
13832
+ const runnerApp = this.toRunnerApp(app, manifest.providerIds);
13833
+ this.apps.set(app.id, runnerApp);
13834
+ const persistent = manifest.lifecycle?.mode === "resident" || manifest.lifecycle?.mode === "provider";
13835
+ const lastStartedAt = persistent ? this.states.get(app.id)?.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
13836
+ if (!persistent) this.states.set(app.id, {
13837
+ status: "starting",
13838
+ lastStartedAt
13839
+ });
13840
+ try {
13841
+ const actions = await this.runner.listActions(runnerApp);
13842
+ if (!persistent) this.states.set(app.id, {
13843
+ status: "running",
13844
+ lastStartedAt,
13845
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13846
+ });
13847
+ return actions.map((action) => {
13848
+ const declared = manifest.actions[action.name];
13849
+ return {
13850
+ id: buildServiceActionId(app.id, action.name),
13851
+ appId: app.id,
13852
+ name: action.name,
13853
+ title: declared?.title ?? action.title,
13854
+ description: declared?.description ?? action.description,
13855
+ inputSchema: declared?.inputSchema,
13856
+ risk: declared?.risk ?? "dangerous"
13857
+ };
13858
+ });
13859
+ } catch (error) {
13860
+ this.markFailed(app.id, lastStartedAt, error);
13861
+ await this.recoverPersistentComponentsIfNeeded(error);
13862
+ throw error;
13863
+ }
13864
+ };
13865
+ invokeAction = async ({ app, manifest, actionName, input }) => {
13866
+ await this.start({
13867
+ app,
13868
+ manifest
13869
+ });
13870
+ const runnerApp = this.toRunnerApp(app, manifest.providerIds);
13871
+ this.apps.set(app.id, runnerApp);
13872
+ if (manifest.lifecycle?.mode === "resident") try {
13873
+ return await this.runner.invoke(runnerApp, actionName, input, manifest.actions[actionName]?.timeoutMs ?? 7e3);
13874
+ } catch (error) {
13875
+ this.markFailed(app.id, this.states.get(app.id)?.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString(), error);
13876
+ await this.recoverPersistentComponentsIfNeeded(error);
13877
+ throw error;
13878
+ }
13879
+ const lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13880
+ this.states.set(app.id, {
13881
+ status: "starting",
13882
+ lastStartedAt
13883
+ });
13884
+ try {
13885
+ const result = await this.runner.invoke(runnerApp, actionName, input, manifest.actions[actionName]?.timeoutMs ?? 7e3);
13886
+ this.states.set(app.id, {
13887
+ status: "running",
13888
+ lastStartedAt,
13889
+ lastReadyAt: (/* @__PURE__ */ new Date()).toISOString()
13890
+ });
13891
+ return result;
13892
+ } catch (error) {
13893
+ this.markFailed(app.id, lastStartedAt, error);
13894
+ await this.recoverPersistentComponentsIfNeeded(error);
13895
+ throw error;
13896
+ }
13897
+ };
13898
+ stop = async (appId) => {
13899
+ this.clearResidentTimer(appId);
13900
+ this.providers.delete(appId);
13901
+ this.persistentRegistrations.delete(appId);
13902
+ const app = this.apps.get(appId);
13903
+ this.apps.delete(appId);
13904
+ if (app) await this.runner.stop(app);
13905
+ this.states.set(appId, { status: "idle" });
13906
+ };
13907
+ restart = async (appId) => await this.stop(appId);
13908
+ dispose = async () => {
13909
+ if (this.recoveryPromise) await this.recoveryPromise;
13910
+ for (const appId of this.residentTimers.keys()) this.clearResidentTimer(appId);
13911
+ await Promise.allSettled(this.residentDeliveries.values());
13912
+ await this.runner.dispose();
13913
+ this.states.clear();
13914
+ this.apps.clear();
13915
+ this.providers.clear();
13916
+ this.persistentRegistrations.clear();
13917
+ this.residentDeliveries.clear();
13918
+ };
13919
+ scheduleResidentEvent = (params) => {
13920
+ if (this.residentDeliveries.has(params.appId)) return;
13921
+ const delivery = this.deliverResidentEvent(params).finally(() => {
13922
+ this.residentDeliveries.delete(params.appId);
13923
+ });
13924
+ this.residentDeliveries.set(params.appId, delivery);
13925
+ };
13926
+ deliverResidentEvent = async (params) => {
13927
+ const app = this.apps.get(params.appId);
13928
+ if (!app) return;
13929
+ const triggeredAt = (/* @__PURE__ */ new Date()).toISOString();
13930
+ try {
13931
+ await this.runner.deliverEvent(app, {
13932
+ eventId: `timer-${triggeredAt}`,
13933
+ kind: "timer",
13934
+ triggeredAt,
13935
+ eventIntervalMs: params.eventIntervalMs
13936
+ });
13937
+ } catch (error) {
13938
+ this.clearResidentTimer(params.appId);
13939
+ this.markFailed(params.appId, this.states.get(params.appId)?.lastStartedAt ?? triggeredAt, error);
13940
+ await this.recoverPersistentComponentsIfNeeded(error);
13941
+ }
13942
+ };
13943
+ clearResidentTimer = (appId) => {
13944
+ const timer = this.residentTimers.get(appId);
13945
+ if (timer) clearInterval(timer);
13946
+ this.residentTimers.delete(appId);
13947
+ };
13948
+ recoverPersistentComponentsIfNeeded = async (error) => {
13949
+ if (!(error instanceof PortableServiceRunnerError) || !["PORTABLE_RUNTIME_TIMEOUT", "PORTABLE_RUNNER_EXITED"].includes(error.code)) return;
13950
+ if (this.recoveryPromise) return await this.recoveryPromise;
13951
+ const registrations = Array.from(this.persistentRegistrations.values());
13952
+ if (registrations.length === 0) return;
13953
+ this.recoveryPromise = (async () => {
13954
+ for (const appId of this.residentTimers.keys()) this.clearResidentTimer(appId);
13955
+ this.providers.clear();
13956
+ const ordered = [...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "provider"), ...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "resident")];
13957
+ for (const registration of ordered) try {
13958
+ await this.start(registration);
13959
+ } catch {}
13960
+ })().finally(() => {
13961
+ this.recoveryPromise = void 0;
13962
+ });
13963
+ await this.recoveryPromise;
13964
+ };
13965
+ toRunnerApp = (app, providerIds) => {
13966
+ if (!app.componentPath || !app.dataDirectory) throw new Error(`Portable Service App ${app.id} is missing component or data storage.`);
13967
+ return {
13968
+ id: app.id,
13969
+ componentPath: app.componentPath,
13970
+ dataDirectory: app.dataDirectory,
13971
+ permissions: app.permissions ?? {},
13972
+ providerIds
13973
+ };
13974
+ };
13975
+ markFailed = (appId, lastStartedAt, error) => {
13976
+ this.states.set(appId, {
13977
+ status: "failed",
13978
+ lastError: error instanceof Error ? error.message : String(error),
13979
+ lastStartedAt,
13980
+ lastFailedAt: (/* @__PURE__ */ new Date()).toISOString()
13981
+ });
13982
+ };
13983
+ };
13984
+ //#endregion
13985
+ //#region src/services/service-app-runtime.service.ts
13986
+ var ServiceAppRuntimeService = class {
13987
+ mcp;
13988
+ portable;
13989
+ protocols = /* @__PURE__ */ new Map();
13990
+ constructor(params) {
13991
+ this.mcp = new McpServiceAppRuntimeService(params);
13992
+ this.portable = new PortableServiceAppRuntimeService({ runnerPath: params.portableServiceRunnerPath });
13993
+ }
13994
+ getStatus = (appId) => {
13995
+ return this.protocols.get(appId) === "wasi-component" ? this.portable.getStatus(appId) : this.mcp.getStatus(appId);
13996
+ };
13997
+ start = async (call) => {
13998
+ this.protocols.set(call.app.id, call.manifest.protocol);
13999
+ if (call.manifest.protocol === "wasi-component") await this.portable.start(call);
14000
+ };
14001
+ listActions = async (call) => {
14002
+ this.protocols.set(call.app.id, call.manifest.protocol);
14003
+ return call.manifest.protocol === "wasi-component" ? await this.portable.listActions(call) : await this.mcp.listActions(call);
14004
+ };
14005
+ invokeAction = async (call) => {
14006
+ this.protocols.set(call.app.id, call.manifest.protocol);
14007
+ return call.manifest.protocol === "wasi-component" ? await this.portable.invokeAction(call) : await this.mcp.invokeAction(call);
14008
+ };
14009
+ stop = async (appId) => {
14010
+ const protocol = this.protocols.get(appId);
14011
+ if (protocol === "wasi-component") await this.portable.stop(appId);
14012
+ else if (protocol === "mcp") await this.mcp.stop(appId);
14013
+ else await Promise.all([this.mcp.stop(appId), this.portable.stop(appId)]);
14014
+ };
14015
+ restart = async (appId) => await this.stop(appId);
14016
+ dispose = async () => {
14017
+ await Promise.all([this.mcp.dispose(), this.portable.dispose()]);
14018
+ this.protocols.clear();
14019
+ };
14020
+ };
14021
+ //#endregion
13483
14022
  //#region src/utils/service-app-manifest.utils.ts
13484
14023
  const SERVICE_APP_ID_PATTERN$1 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
13485
14024
  const SERVICE_ACTION_RISKS = new Set([
@@ -13506,19 +14045,56 @@ function parseServiceAppManifest(raw, options = {}) {
13506
14045
  const id = readRequiredString$6(parsed, "id");
13507
14046
  if (!SERVICE_APP_ID_PATTERN$1.test(id)) throw new Error("service app id must be kebab-case.");
13508
14047
  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);
14048
+ if (protocol !== "mcp" && protocol !== "wasi-component") throw new Error("service app protocol must be mcp or wasi-component.");
14049
+ const launch = protocol === "mcp" ? new AppServiceLaunchService(options.platformTargetService).resolve(parsed, options.target) : void 0;
14050
+ const componentEntry = protocol === "wasi-component" ? readPortableComponentEntry(parsed) : void 0;
14051
+ const lifecycle = readServiceAppLifecycle(parsed.lifecycle);
14052
+ if (lifecycle.mode !== "action" && protocol !== "wasi-component") throw new Error(`${lifecycle.mode} service app lifecycle requires wasi-component protocol.`);
13511
14053
  return {
13512
14054
  id,
13513
14055
  title: readRequiredString$6(parsed, "title"),
13514
14056
  description: readOptionalString$8(parsed, "description"),
13515
14057
  enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
13516
14058
  protocol,
13517
- command: launch.command,
13518
- args: launch.args,
14059
+ command: launch?.command,
14060
+ args: launch?.args,
14061
+ componentEntry,
14062
+ providerIds: readProviderIds(parsed.providers),
14063
+ lifecycle,
13519
14064
  actions: readManifestActions(parsed.actions)
13520
14065
  };
13521
14066
  }
14067
+ function readServiceAppLifecycle(value) {
14068
+ if (value === void 0) return { mode: "action" };
14069
+ if (!isRecord$7(value)) throw new Error("service app lifecycle must be an object.");
14070
+ const mode = readOptionalString$8(value, "mode") ?? "action";
14071
+ if (mode === "action") return { mode };
14072
+ if (mode === "provider") return { mode };
14073
+ if (mode !== "resident") throw new Error("service app lifecycle.mode must be action, resident or provider.");
14074
+ const eventIntervalMs = readOptionalNumber(value, "eventIntervalMs");
14075
+ 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.");
14076
+ return {
14077
+ mode,
14078
+ eventIntervalMs
14079
+ };
14080
+ }
14081
+ function readProviderIds(value) {
14082
+ if (value === void 0) return [];
14083
+ if (!Array.isArray(value)) throw new Error("service app providers must be an array.");
14084
+ const providerIds = value.map((entry) => {
14085
+ 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.");
14086
+ return entry.trim();
14087
+ });
14088
+ return Array.from(new Set(providerIds));
14089
+ }
14090
+ function readPortableComponentEntry(record) {
14091
+ const component = record.component;
14092
+ if (!isRecord$7(component)) throw new Error("service app component is required for wasi-component.");
14093
+ const entry = readRequiredString$6(component, "entry").replace(/\\/g, "/");
14094
+ if (path.isAbsolute(entry) || entry.includes("\0") || entry.split("/").includes("..")) throw new Error("service app component.entry must be a package-relative path.");
14095
+ if (!entry.endsWith(".wasm")) throw new Error("service app component.entry must reference a .wasm file.");
14096
+ return entry;
14097
+ }
13522
14098
  function readManifestActions(value) {
13523
14099
  if (value === void 0) throw new Error("service app actions are required.");
13524
14100
  if (!isRecord$7(value)) throw new Error("service app actions must be an object.");
@@ -13531,11 +14107,14 @@ function readManifestActions(value) {
13531
14107
  if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
13532
14108
  const inputSchema = action.inputSchema;
13533
14109
  if (inputSchema !== void 0 && !isRecord$7(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
14110
+ const timeoutMs = readOptionalNumber(action, "timeoutMs");
14111
+ 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
14112
  actions[name] = {
13535
14113
  risk,
13536
14114
  title: readOptionalString$8(action, "title"),
13537
14115
  description: readOptionalString$8(action, "description"),
13538
- inputSchema
14116
+ inputSchema,
14117
+ timeoutMs
13539
14118
  };
13540
14119
  }
13541
14120
  return actions;
@@ -13553,10 +14132,49 @@ function readOptionalBoolean$1(record, key) {
13553
14132
  if (typeof record[key] !== "boolean") throw new Error(`service app ${key} must be boolean.`);
13554
14133
  return record[key];
13555
14134
  }
14135
+ function readOptionalNumber(record, key) {
14136
+ if (record[key] === void 0) return;
14137
+ if (typeof record[key] !== "number") throw new Error(`service app ${key} must be number.`);
14138
+ return record[key];
14139
+ }
13556
14140
  function isRecord$7(value) {
13557
14141
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
13558
14142
  }
13559
14143
  //#endregion
14144
+ //#region src/services/service-app-lifecycle.service.ts
14145
+ var ServiceAppLifecycleService = class {
14146
+ constructor(params) {
14147
+ this.params = params;
14148
+ }
14149
+ startDiscovered = async (registrations) => {
14150
+ const active = registrations.filter(({ manifest, record }) => record.enabled && manifest.lifecycle && manifest.lifecycle.mode !== "action");
14151
+ await Promise.allSettled(this.order(active).map(async ({ manifest, record }) => await this.params.runtimeService.start?.({
14152
+ app: record,
14153
+ manifest
14154
+ })));
14155
+ };
14156
+ activatePackageComponents = async (components) => {
14157
+ const registrations = [];
14158
+ for (const component of components.filter((entry) => entry.kind === "service")) {
14159
+ const manifest = await readServiceAppManifest(component.sourcePath);
14160
+ if (!manifest.lifecycle || manifest.lifecycle.mode === "action") continue;
14161
+ registrations.push({
14162
+ manifest,
14163
+ record: this.params.recordService.fromManifest(component.sourcePath, manifest, component, component.storage)
14164
+ });
14165
+ }
14166
+ for (const { manifest, record } of this.order(registrations)) await this.params.runtimeService.start?.({
14167
+ app: record,
14168
+ manifest
14169
+ });
14170
+ };
14171
+ deactivatePackageComponents = async (components) => {
14172
+ const serviceIds = components.filter((component) => component.kind === "service").map((component) => component.id);
14173
+ await Promise.all(serviceIds.map(async (serviceId) => await this.params.runtimeService.stop(serviceId)));
14174
+ };
14175
+ order = (registrations) => [...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "provider"), ...registrations.filter(({ manifest }) => manifest.lifecycle?.mode === "resident")];
14176
+ };
14177
+ //#endregion
13560
14178
  //#region src/services/service-app-record.service.ts
13561
14179
  var ServiceAppRecordService = class {
13562
14180
  instanceStorageService = new AppInstanceStorageService();
@@ -13638,7 +14256,12 @@ var ServiceAppRecordService = class {
13638
14256
  dataDirectory: storage?.dataDirectory,
13639
14257
  instanceId: packageSource?.instanceId ?? storage?.instanceId,
13640
14258
  storage,
13641
- isolation: packageSource?.isolation ?? "full-user"
14259
+ isolation: packageSource?.isolation ?? "full-user",
14260
+ runtimeProfile: packageSource?.runtimeProfile ?? "native-process",
14261
+ permissions: packageSource?.permissions ?? {},
14262
+ componentPath: manifest.componentEntry ? join(dirPath, manifest.componentEntry) : void 0,
14263
+ providerIds: manifest.providerIds,
14264
+ lifecycle: manifest.lifecycle
13642
14265
  };
13643
14266
  };
13644
14267
  failedWorkspaceRecord = (id, dirPath, error) => ({
@@ -13669,7 +14292,9 @@ var ServiceAppRecordService = class {
13669
14292
  dataDirectory: source.dataDirectory,
13670
14293
  instanceId: source.instanceId,
13671
14294
  storage: source.storage,
13672
- isolation: source.isolation
14295
+ isolation: source.isolation,
14296
+ runtimeProfile: source.runtimeProfile,
14297
+ permissions: source.permissions
13673
14298
  });
13674
14299
  toTitle = (value) => basename(value).replace(/[-_]+/g, " ").trim() || value;
13675
14300
  getWorkspaceInstanceDirectory = (serviceId) => join(this.params.getWorkspacePath(), ".nextclaw", "app-instances", serviceId, "default");
@@ -13838,13 +14463,16 @@ var ServiceActionGrantService = class {
13838
14463
  const results = [];
13839
14464
  for (const grant of grants) {
13840
14465
  const actionId = readServiceActionTargetId(grant.resource.target);
13841
- if (!actionId || grant.subject.type !== "panel-app") continue;
14466
+ if (!actionId || grant.subject.type !== "panel-app" && grant.subject.type !== "agent") continue;
13842
14467
  try {
13843
14468
  const action = await this.params.resolveAction(actionId);
13844
14469
  results.push({
13845
- caller: {
14470
+ caller: grant.subject.type === "panel-app" ? {
13846
14471
  surface: "panel-app",
13847
14472
  appId: grant.subject.id
14473
+ } : {
14474
+ surface: "agent",
14475
+ agentId: grant.subject.id
13848
14476
  },
13849
14477
  actionId,
13850
14478
  risk: action.risk,
@@ -13860,7 +14488,7 @@ var ServiceActionGrantService = class {
13860
14488
  await this.params.capabilityGrantManager.revoke({
13861
14489
  subject: {
13862
14490
  type: caller.surface,
13863
- id: caller.appId
14491
+ id: getServiceActionCallerId(caller)
13864
14492
  },
13865
14493
  resourceType: "service.action",
13866
14494
  target: { actionId }
@@ -13961,28 +14589,6 @@ function mergeServiceAppRuntimeActions({ record, manifest, runtimeActions }) {
13961
14589
  return [...declared, ...undeclared].sort((left, right) => left.id.localeCompare(right.id));
13962
14590
  }
13963
14591
  //#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
14592
  //#region src/managers/service-app.manager.ts
13987
14593
  const SERVICE_APP_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
13988
14594
  var ServiceAppManager = class {
@@ -13991,14 +14597,22 @@ var ServiceAppManager = class {
13991
14597
  recordService;
13992
14598
  actionGrants;
13993
14599
  packageRuntime;
14600
+ lifecycleService;
13994
14601
  reconciliationDiagnostics = [];
13995
14602
  constructor(params) {
13996
14603
  this.params = params;
13997
- this.runtimeService = params.runtimeService ?? new McpServiceAppRuntimeService({ getConfig: () => params.configManager.config });
14604
+ this.runtimeService = params.runtimeService ?? new ServiceAppRuntimeService({
14605
+ getConfig: () => params.configManager.config,
14606
+ portableServiceRunnerPath: params.portableServiceRunnerPath
14607
+ });
13998
14608
  this.recordService = new ServiceAppRecordService({
13999
14609
  getWorkspacePath: this.getWorkspacePath,
14000
14610
  runtimeService: this.runtimeService
14001
14611
  });
14612
+ this.lifecycleService = new ServiceAppLifecycleService({
14613
+ recordService: this.recordService,
14614
+ runtimeService: this.runtimeService
14615
+ });
14002
14616
  this.actionGrants = new ServiceActionGrantService({
14003
14617
  capabilityGrantManager: params.capabilityGrantManager,
14004
14618
  resolveAction: this.requireServiceAction
@@ -14017,6 +14631,7 @@ var ServiceAppManager = class {
14017
14631
  lockPathForAppId: (appId) => this.getServiceAppLockPath(this.getWorkspacePath(), appId),
14018
14632
  serviceAppsPath: this.getServiceAppsPath(this.getWorkspacePath())
14019
14633
  });
14634
+ await this.lifecycleService.startDiscovered(await this.listValidServiceApps());
14020
14635
  };
14021
14636
  listServiceApps = async () => {
14022
14637
  const workspacePath = this.getWorkspacePath();
@@ -14052,8 +14667,8 @@ var ServiceAppManager = class {
14052
14667
  });
14053
14668
  };
14054
14669
  invokeServiceAction = async (actionId, request) => {
14055
- this.assertCaller(request.caller);
14056
- this.assertDeclaredAction(actionId, request.declaredActions);
14670
+ assertServiceActionCaller(request.caller, this.params.hasAgent);
14671
+ assertServiceActionDeclared(request.caller, actionId, request.declaredActions);
14057
14672
  const { manifest, record } = await this.requireServiceAppForAction(actionId, true);
14058
14673
  const actionName = getServiceActionName(actionId, record.id);
14059
14674
  if (!Object.hasOwn(manifest.actions, actionName)) throw new ServiceAppError("SERVICE_APP_ACTION_NOT_FOUND", "service action not found");
@@ -14080,30 +14695,33 @@ var ServiceAppManager = class {
14080
14695
  return grant;
14081
14696
  };
14082
14697
  grantServiceActions = async (actionIds, request) => {
14083
- this.assertCaller(request.caller);
14698
+ assertServiceActionCaller(request.caller, this.params.hasAgent);
14084
14699
  const normalizedActionIds = this.normalizeActionIds(actionIds);
14085
14700
  if (normalizedActionIds.length === 0) throw new ServiceAppError("SERVICE_APP_INVALID_ACTION", "service action id is invalid");
14086
14701
  const actions = [];
14087
14702
  for (const actionId of normalizedActionIds) {
14088
- this.assertDeclaredAction(actionId, request.declaredActions);
14703
+ assertServiceActionDeclared(request.caller, actionId, request.declaredActions);
14089
14704
  actions.push(await this.requireServiceAction(actionId));
14090
14705
  }
14091
14706
  return await this.actionGrants.grant(request.caller, actions);
14092
14707
  };
14093
14708
  listServiceActionGrants = async () => await this.actionGrants.list();
14094
14709
  revokeServiceAction = async (caller, actionId) => {
14095
- this.assertCaller(caller);
14710
+ assertServiceActionCaller(caller, this.params.hasAgent);
14096
14711
  await this.actionGrants.revoke(caller, actionId);
14097
14712
  };
14098
14713
  matchesCapabilityGrant = async (grant) => {
14099
- if (grant.subject.type !== "panel-app" || grant.resource.type !== "service.action") return false;
14714
+ if (grant.subject.type !== "panel-app" && grant.subject.type !== "agent" || grant.resource.type !== "service.action") return false;
14100
14715
  const actionId = readServiceActionTargetId(grant.resource.target);
14101
14716
  if (!actionId) return false;
14102
14717
  try {
14103
14718
  const action = await this.requireServiceAction(actionId);
14104
- return getCapabilityGrantKey(grant) === getCapabilityGrantKey(createServiceActionGrantRequest({
14719
+ return getCapabilityGrantKey(grant) === getCapabilityGrantKey(createServiceActionGrantRequest(grant.subject.type === "panel-app" ? {
14105
14720
  surface: "panel-app",
14106
14721
  appId: grant.subject.id
14722
+ } : {
14723
+ surface: "agent",
14724
+ agentId: grant.subject.id
14107
14725
  }, action));
14108
14726
  } catch {
14109
14727
  return false;
@@ -14183,10 +14801,8 @@ var ServiceAppManager = class {
14183
14801
  }
14184
14802
  }
14185
14803
  };
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
- };
14804
+ activatePackageComponents = async (components) => await this.lifecycleService.activatePackageComponents(components);
14805
+ deactivatePackageComponents = async (components) => await this.lifecycleService.deactivatePackageComponents(components);
14190
14806
  preparePackageComponentDeactivation = async (components) => await this.packageRuntime.prepareDeactivation(components);
14191
14807
  removePackageComponentGrants = async (components) => await this.actionGrants.removePackageGrants(new Set(components.filter((component) => component.kind === "service").map((component) => component.id)));
14192
14808
  withGrantState = async (action, params) => {
@@ -14267,12 +14883,6 @@ var ServiceAppManager = class {
14267
14883
  }));
14268
14884
  return [...workspaceEntries, ...packageEntries].filter((entry) => Boolean(entry));
14269
14885
  };
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
14886
  normalizeActionIds = (actionIds) => Array.from(new Set(actionIds.map((actionId) => actionId.trim()).filter((actionId) => actionId.length > 0)));
14277
14887
  getWorkspacePath = () => getWorkspacePathFromConfig(this.params.configManager.config);
14278
14888
  getServiceAppsPath = (workspacePath) => join(workspacePath, DEFAULT_SERVICE_APPS_DIR);
@@ -21248,6 +21858,57 @@ function readOptionalString$1(value) {
21248
21858
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
21249
21859
  }
21250
21860
  //#endregion
21861
+ //#region src/utils/service-action-tool.utils.ts
21862
+ const MAX_TOOL_NAME_LENGTH = 64;
21863
+ const HASH_LENGTH = 8;
21864
+ const TOOL_PREFIX = "service__";
21865
+ function buildServiceActionToolName(actionId) {
21866
+ const readable = actionId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "action";
21867
+ const suffix = `__${createHash("sha256").update(actionId).digest("hex").slice(0, HASH_LENGTH)}`;
21868
+ const available = MAX_TOOL_NAME_LENGTH - 9 - suffix.length;
21869
+ return `${TOOL_PREFIX}${readable.slice(0, available)}${suffix}`;
21870
+ }
21871
+ //#endregion
21872
+ //#region src/contributions/tool-provider/providers/service-action-tool.provider.ts
21873
+ const EMPTY_OBJECT_SCHEMA = {
21874
+ type: "object",
21875
+ properties: {},
21876
+ additionalProperties: false
21877
+ };
21878
+ var ServiceActionToolProvider = class {
21879
+ constructor(runContextService, serviceAppManager) {
21880
+ this.runContextService = runContextService;
21881
+ this.serviceAppManager = serviceAppManager;
21882
+ }
21883
+ provide = async (request) => {
21884
+ const { toolRunContext } = await this.runContextService.resolve(request);
21885
+ const caller = {
21886
+ surface: "agent",
21887
+ agentId: toolRunContext.agentId
21888
+ };
21889
+ return (await this.serviceAppManager.listServiceActions({ caller })).filter((action) => action.grantState === "granted").map((action) => this.toTool(caller, action));
21890
+ };
21891
+ toTool = (caller, action) => ({
21892
+ name: buildServiceActionToolName(action.id),
21893
+ description: [
21894
+ action.title ?? action.name,
21895
+ action.description,
21896
+ `NextClaw Service Action: ${action.id}`
21897
+ ].filter(Boolean).join("\n"),
21898
+ parameters: action.inputSchema ?? EMPTY_OBJECT_SCHEMA,
21899
+ supportsParallelToolCalls: action.risk === "read",
21900
+ execute: async (args) => await this.serviceAppManager.invokeServiceAction(action.id, {
21901
+ caller,
21902
+ input: readInput(args)
21903
+ })
21904
+ });
21905
+ };
21906
+ function readInput(value) {
21907
+ if (value === void 0) return {};
21908
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Service Action tool input must be an object.");
21909
+ return value;
21910
+ }
21911
+ //#endregion
21251
21912
  //#region src/contributions/tool-provider/services/tool-provider-run-context.service.ts
21252
21913
  var ToolProviderRunContextService = class {
21253
21914
  constructor(sessionManager, agentManager, configManager) {
@@ -21304,6 +21965,7 @@ var ToolProviderContribution = class extends Contribution$1 {
21304
21965
  new ProjectToolProvider(this.kernel.projectManager),
21305
21966
  new SessionToolProvider(runContextService, this.kernel.sessionManager, this.kernel.sessionRequests, this.kernel.sessionSearch),
21306
21967
  new AssetToolProvider(this.kernel.assetStore),
21968
+ new ServiceActionToolProvider(runContextService, this.kernel.serviceAppManager),
21307
21969
  new McpToolProvider(runContextService, this.kernel.mcpManager)
21308
21970
  ];
21309
21971
  };
@@ -21332,11 +21994,13 @@ function createKernelOperationalManagers(params) {
21332
21994
  };
21333
21995
  }
21334
21996
  function createKernelServiceAppManagers(params) {
21335
- const { appHomeDirectory, appPackageManager, capabilityGrantManager, configManager } = params;
21997
+ const { appHomeDirectory, appPackageManager, capabilityGrantManager, configManager, hasAgent, portableServiceRunnerPath } = params;
21336
21998
  const serviceAppManager = new ServiceAppManager({
21337
21999
  configManager,
21338
22000
  listPackageComponentSources: appPackageManager.listActiveComponentSources,
21339
- capabilityGrantManager
22001
+ capabilityGrantManager,
22002
+ hasAgent,
22003
+ portableServiceRunnerPath
21340
22004
  });
21341
22005
  return {
21342
22006
  serviceAppManager,
@@ -21405,6 +22069,9 @@ function installKernelAppPackageRuntimeHooks(params) {
21405
22069
  await panelAppManager.assertCanActivatePackageComponents(sources);
21406
22070
  await serviceAppManager.assertCanActivatePackageComponents(sources);
21407
22071
  },
22072
+ afterActivate: async (sources) => {
22073
+ await serviceAppManager.activatePackageComponents(sources);
22074
+ },
21408
22075
  beforeDeactivate: async (sources) => {
21409
22076
  panelAppManager.deactivatePackageComponents(sources);
21410
22077
  await serviceAppManager.deactivatePackageComponents(sources);
@@ -21548,7 +22215,9 @@ var NextclawKernel = class {
21548
22215
  appHomeDirectory: resolveKernelAppHomeDirectory(options),
21549
22216
  appPackageManager: this.appPackageManager,
21550
22217
  configManager: this.configManager,
21551
- capabilityGrantManager: this.capabilityGrants
22218
+ capabilityGrantManager: this.capabilityGrants,
22219
+ hasAgent: (agentId) => this.agents.getAgent(agentId) !== null,
22220
+ portableServiceRunnerPath: options.portableServiceRunnerPath
21552
22221
  }));
21553
22222
  installKernelAppPackageRuntimeHooks({
21554
22223
  appPackageManager: this.appPackageManager,
@@ -22776,6 +23445,6 @@ function resolveLegacyEventType(message) {
22776
23445
  return `message.${role || "other"}`;
22777
23446
  }
22778
23447
  //#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 };
23448
+ 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
23449
 
22781
23450
  //# sourceMappingURL=index.js.map