@nextclaw/kernel 0.1.15-beta.7 → 0.1.16

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
@@ -9,7 +9,7 @@ import { catchError, from, lastValueFrom, tap } from "rxjs";
9
9
  import { appendFileSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { spawn } from "node:child_process";
11
11
  import { access, appendFile, mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
12
- import { basename, delimiter, dirname, join, relative, resolve } from "node:path";
12
+ import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
  import { BUILTIN_PROVIDER_PLUGINS } from "@nextclaw/runtime";
15
15
  import { McpRegistryService, McpServerLifecycleManager } from "@nextclaw/mcp";
@@ -572,7 +572,7 @@ var AgentRunContextCompactionManager = class {
572
572
  //#region src/managers/agent-run-request.manager.ts
573
573
  function toAgentRunRequest(envelope) {
574
574
  const metadata = envelope.metadata ?? {};
575
- const peerId = readOptionalString$8(envelope.peerId);
575
+ const peerId = readOptionalString$9(envelope.peerId);
576
576
  const requestMetadata = {
577
577
  agentRuntimeId: metadata.agentRuntimeId,
578
578
  agentId: metadata.agentId,
@@ -585,7 +585,7 @@ function toAgentRunRequest(envelope) {
585
585
  thinkingEffort: metadata.thinkingEffort
586
586
  };
587
587
  if (Array.isArray(envelope.content)) {
588
- const sessionId = readOptionalString$8(envelope.sessionId);
588
+ const sessionId = readOptionalString$9(envelope.sessionId);
589
589
  if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
590
590
  return {
591
591
  ...requestMetadata,
@@ -603,8 +603,8 @@ function toAgentRunRequest(envelope) {
603
603
  }
604
604
  const sourceMessage = envelope.message;
605
605
  if (!sourceMessage) throw new Error("Invalid agent run send request.");
606
- const envelopeSessionId = readOptionalString$8(envelope.sessionId);
607
- const messageSessionId = readOptionalString$8(sourceMessage.sessionId);
606
+ const envelopeSessionId = readOptionalString$9(envelope.sessionId);
607
+ const messageSessionId = readOptionalString$9(sourceMessage.sessionId);
608
608
  const sessionId = envelopeSessionId ?? messageSessionId;
609
609
  if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
610
610
  const message = {
@@ -623,7 +623,7 @@ function toAgentRunRequest(envelope) {
623
623
  message
624
624
  };
625
625
  }
626
- function readOptionalString$8(value) {
626
+ function readOptionalString$9(value) {
627
627
  if (typeof value !== "string") return;
628
628
  return value.trim() || void 0;
629
629
  }
@@ -1593,7 +1593,7 @@ const runtimeRequire = createRequire(import.meta.url);
1593
1593
  function readString$6(value) {
1594
1594
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1595
1595
  }
1596
- function readStringArray$1(value) {
1596
+ function readStringArray$2(value) {
1597
1597
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
1598
1598
  }
1599
1599
  function readStringRecord(value) {
@@ -1652,7 +1652,7 @@ function toManifest(value, rootDir) {
1652
1652
  server: {
1653
1653
  type: "stdio",
1654
1654
  command,
1655
- ...readStringArray$1(server.args) ? { args: readStringArray$1(server.args) } : {},
1655
+ ...readStringArray$2(server.args) ? { args: readStringArray$2(server.args) } : {},
1656
1656
  ...readStringRecord(server.env) ? { env: readStringRecord(server.env) } : {}
1657
1657
  },
1658
1658
  ...record.contributes && typeof record.contributes === "object" && !Array.isArray(record.contributes) ? { contributes: record.contributes } : {}
@@ -1753,7 +1753,7 @@ function readString$5(value) {
1753
1753
  function readRecord$2(value) {
1754
1754
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1755
1755
  }
1756
- function readRequiredString$3(value, name) {
1756
+ function readRequiredString$4(value, name) {
1757
1757
  const trimmed = readString$5(value);
1758
1758
  if (!trimmed) throw new Error(`${name} is required`);
1759
1759
  return trimmed;
@@ -1784,9 +1784,9 @@ function readInboundAttachments(value) {
1784
1784
  function toInboundMessage(value) {
1785
1785
  const payload = readRecord$2(value);
1786
1786
  return {
1787
- channel: readRequiredString$3(payload.channelId, "channelId"),
1788
- chatId: readRequiredString$3(payload.conversationId, "conversationId"),
1789
- senderId: readRequiredString$3(payload.senderId, "senderId"),
1787
+ channel: readRequiredString$4(payload.channelId, "channelId"),
1788
+ chatId: readRequiredString$4(payload.conversationId, "conversationId"),
1789
+ senderId: readRequiredString$4(payload.senderId, "senderId"),
1790
1790
  content: readTextContent(payload.content),
1791
1791
  timestamp: /* @__PURE__ */ new Date(),
1792
1792
  attachments: readInboundAttachments(payload.attachments),
@@ -1808,7 +1808,7 @@ function normalizeAuthPollResult(value) {
1808
1808
  if (!value) return null;
1809
1809
  const record = readRecord$2(value);
1810
1810
  return {
1811
- channel: readRequiredString$3(record.channel, "channel"),
1811
+ channel: readRequiredString$4(record.channel, "channel"),
1812
1812
  status: record.status,
1813
1813
  message: readString$5(record.message),
1814
1814
  nextPollMs: readOptionalNumber(record.nextPollMs),
@@ -1955,7 +1955,7 @@ var ExtensionRuntimeService = class {
1955
1955
  };
1956
1956
  handleChannelConfigGet = (envelope, context) => {
1957
1957
  this.assertAuthorized(context);
1958
- const channelId = readRequiredString$3(readRecord$2(envelope.payload).channelId, "channelId");
1958
+ const channelId = readRequiredString$4(readRecord$2(envelope.payload).channelId, "channelId");
1959
1959
  return { config: this.options.getConfig().channels[channelId] ?? {} };
1960
1960
  };
1961
1961
  handleChannelMessageSubmit = async (envelope, context) => {
@@ -1970,9 +1970,9 @@ var ExtensionRuntimeService = class {
1970
1970
  handleChannelCommandExecute = async (envelope, context) => {
1971
1971
  this.assertAuthorized(context);
1972
1972
  const payload = readRecord$2(envelope.payload);
1973
- const channel = readRequiredString$3(payload.channelId, "channelId");
1974
- const chatId = readRequiredString$3(payload.conversationId, "conversationId");
1975
- const senderId = readRequiredString$3(payload.senderId, "senderId");
1973
+ const channel = readRequiredString$4(payload.channelId, "channelId");
1974
+ const chatId = readRequiredString$4(payload.conversationId, "conversationId");
1975
+ const senderId = readRequiredString$4(payload.senderId, "senderId");
1976
1976
  const metadata = readRecord$2(payload.metadata);
1977
1977
  const config = this.options.getConfig();
1978
1978
  const registry = new CommandRegistry(config, this.options.sessionManager);
@@ -1999,7 +1999,7 @@ var ExtensionRuntimeService = class {
1999
1999
  content: "",
2000
2000
  ephemeral: true
2001
2001
  };
2002
- return await registry.execute(readRequiredString$3(payload.commandName, "commandName"), readRecord$2(payload.args), {
2002
+ return await registry.execute(readRequiredString$4(payload.commandName, "commandName"), readRecord$2(payload.args), {
2003
2003
  channel,
2004
2004
  chatId,
2005
2005
  senderId,
@@ -2009,7 +2009,7 @@ var ExtensionRuntimeService = class {
2009
2009
  handleExtensionResponse = (envelope, context) => {
2010
2010
  this.assertAuthorized(context);
2011
2011
  const payload = readRecord$2(envelope.payload);
2012
- const requestId = readRequiredString$3(payload.requestId, "requestId");
2012
+ const requestId = readRequiredString$4(payload.requestId, "requestId");
2013
2013
  const pending = this.pendingRequests.get(requestId);
2014
2014
  if (!pending) return { accepted: false };
2015
2015
  this.pendingRequests.delete(requestId);
@@ -2183,11 +2183,11 @@ var ExtensionManager = class {
2183
2183
  //#endregion
2184
2184
  //#region src/utils/model-message-vision.utils.ts
2185
2185
  const IMAGE_OMITTED_TEXT = "[Image omitted: the selected model is not configured for vision input.]";
2186
- function isRecord$9(value) {
2186
+ function isRecord$10(value) {
2187
2187
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2188
2188
  }
2189
2189
  function isImageContentPart(value) {
2190
- if (!isRecord$9(value)) return false;
2190
+ if (!isRecord$10(value)) return false;
2191
2191
  const type = value.type;
2192
2192
  return type === "image_url" || type === "input_image";
2193
2193
  }
@@ -2203,7 +2203,7 @@ function normalizeContentWithoutVision(content) {
2203
2203
  };
2204
2204
  });
2205
2205
  if (!sawImage) return content;
2206
- const textParts = parts.filter((part) => isRecord$9(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
2206
+ const textParts = parts.filter((part) => isRecord$10(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
2207
2207
  if (textParts.length === parts.length) return textParts.join("\n\n");
2208
2208
  return parts;
2209
2209
  }
@@ -2698,7 +2698,7 @@ function safeNcpSessionFilename(value) {
2698
2698
  function normalizeNcpAgentId(agentId) {
2699
2699
  return agentId?.trim().toLowerCase() || void 0;
2700
2700
  }
2701
- function isRecord$8(value) {
2701
+ function isRecord$9(value) {
2702
2702
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2703
2703
  }
2704
2704
  function toIsoString(value, fallback) {
@@ -2809,11 +2809,11 @@ function createAgentPeerSessionIdentity(params) {
2809
2809
  }
2810
2810
  function resolveAgentPeerScope(params) {
2811
2811
  const metadata = params.metadata ?? {};
2812
- const explicitScope = readOptionalString$7(metadata["agent_peer_scope"]) ?? readOptionalString$7(metadata.agentPeerScope);
2812
+ const explicitScope = readOptionalString$8(metadata["agent_peer_scope"]) ?? readOptionalString$8(metadata.agentPeerScope);
2813
2813
  if (explicitScope) return explicitScope;
2814
- return `agent:${readOptionalString$7(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$7(params.channel) ?? readOptionalString$7(metadata.channel) ?? "agent-run"}:${readOptionalString$7(metadata.accountId) ?? readOptionalString$7(metadata.account_id) ?? "default"}`;
2814
+ return `agent:${readOptionalString$8(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$8(params.channel) ?? readOptionalString$8(metadata.channel) ?? "agent-run"}:${readOptionalString$8(metadata.accountId) ?? readOptionalString$8(metadata.account_id) ?? "default"}`;
2815
2815
  }
2816
- function readOptionalString$7(value) {
2816
+ function readOptionalString$8(value) {
2817
2817
  if (typeof value !== "string") return;
2818
2818
  return value.trim() || void 0;
2819
2819
  }
@@ -2832,7 +2832,7 @@ function applyLimit(items, limit) {
2832
2832
  if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
2833
2833
  return items.slice(0, Math.trunc(limit));
2834
2834
  }
2835
- function readOptionalString$6(value) {
2835
+ function readOptionalString$7(value) {
2836
2836
  if (typeof value !== "string") return null;
2837
2837
  const trimmed = value.trim();
2838
2838
  return trimmed.length > 0 ? trimmed : null;
@@ -2883,7 +2883,7 @@ function mergeMetadataOverrides(metadata, overrides) {
2883
2883
  }
2884
2884
  function resolveSessionType(params) {
2885
2885
  const { metadata, runtime, sessionType } = params;
2886
- return readOptionalString$6(runtime) ?? readOptionalString$6(metadata.runtime) ?? readOptionalString$6(sessionType) ?? readOptionalString$6(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
2886
+ return readOptionalString$7(runtime) ?? readOptionalString$7(metadata.runtime) ?? readOptionalString$7(sessionType) ?? readOptionalString$7(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
2887
2887
  }
2888
2888
  function applySessionOverrides(params) {
2889
2889
  const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
@@ -2893,15 +2893,15 @@ function applySessionOverrides(params) {
2893
2893
  metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
2894
2894
  if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
2895
2895
  if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
2896
- if (readOptionalString$6(model)) {
2896
+ if (readOptionalString$7(model)) {
2897
2897
  metadata.model = model?.trim();
2898
2898
  metadata.preferred_model = model?.trim();
2899
2899
  }
2900
- if (readOptionalString$6(thinkingLevel)) {
2900
+ if (readOptionalString$7(thinkingLevel)) {
2901
2901
  metadata.thinking = thinkingLevel?.trim();
2902
2902
  metadata.preferred_thinking = thinkingLevel?.trim();
2903
2903
  }
2904
- if (readOptionalString$6(projectRoot)) metadata.project_root = projectRoot?.trim();
2904
+ if (readOptionalString$7(projectRoot)) metadata.project_root = projectRoot?.trim();
2905
2905
  }
2906
2906
  function isSessionSummaryRefreshEvent(event) {
2907
2907
  switch (event.type) {
@@ -2941,9 +2941,9 @@ var SessionManager = class {
2941
2941
  const { agentId: requestedAgentId, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
2942
2942
  const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
2943
2943
  const metadata = cloneInheritedMetadata(sourceSessionMetadata);
2944
- const title = readOptionalString$6(requestedTitle) ?? summarizeTask(task);
2945
- const parentSessionId = readOptionalString$6(rawParentSessionId);
2946
- const requestId = readOptionalString$6(rawRequestId);
2944
+ const title = readOptionalString$7(requestedTitle) ?? summarizeTask(task);
2945
+ const parentSessionId = readOptionalString$7(rawParentSessionId);
2946
+ const requestId = readOptionalString$7(rawRequestId);
2947
2947
  const sessionType = resolveSessionType({
2948
2948
  runtime,
2949
2949
  sessionType: requestedSessionType,
@@ -2962,8 +2962,8 @@ var SessionManager = class {
2962
2962
  });
2963
2963
  const now = (/* @__PURE__ */ new Date()).toISOString();
2964
2964
  const nextMetadata = mergeMetadataOverrides(metadata, metadataOverrides);
2965
- const agentId = readOptionalString$6(requestedAgentId) ?? readOptionalString$6(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
2966
- const sessionId = readOptionalString$6(requestedSessionId) ?? buildSessionId();
2965
+ const agentId = readOptionalString$7(requestedAgentId) ?? readOptionalString$7(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
2966
+ const sessionId = readOptionalString$7(requestedSessionId) ?? buildSessionId();
2967
2967
  const record = {
2968
2968
  sessionId,
2969
2969
  ...agentId ? { agentId } : {},
@@ -3068,14 +3068,14 @@ var SessionManager = class {
3068
3068
  createAgentRunSession = async (params) => {
3069
3069
  const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, metadata, model, peerId: rawPeerId, projectRoot, sessionId, task, thinkingEffort } = params;
3070
3070
  const agentRuntimeId = requestedAgentRuntimeId ?? "native";
3071
- const peerId = readOptionalString$6(rawPeerId);
3071
+ const peerId = readOptionalString$7(rawPeerId);
3072
3072
  const peerIdentity = peerId ? createAgentPeerSessionIdentity({
3073
3073
  agentId,
3074
3074
  channel,
3075
3075
  metadata,
3076
3076
  peerId
3077
3077
  }) : void 0;
3078
- const requestedSessionId = readOptionalString$6(sessionId);
3078
+ const requestedSessionId = readOptionalString$7(sessionId);
3079
3079
  const created = await this.createSession({
3080
3080
  sourceSessionMetadata: {},
3081
3081
  sessionId: requestedSessionId ?? peerIdentity?.sessionId,
@@ -3291,7 +3291,7 @@ var PanelAppCapabilityGrantStore = class {
3291
3291
  try {
3292
3292
  return normalizeStoreData$1(JSON.parse(await readFile(this.filePath, "utf8")));
3293
3293
  } catch (error) {
3294
- if (isMissingFileError$1(error)) return structuredClone(EMPTY_GRANTS$1);
3294
+ if (isMissingFileError$2(error)) return structuredClone(EMPTY_GRANTS$1);
3295
3295
  throw error;
3296
3296
  }
3297
3297
  };
@@ -3301,12 +3301,12 @@ var PanelAppCapabilityGrantStore = class {
3301
3301
  };
3302
3302
  };
3303
3303
  function normalizeStoreData$1(value) {
3304
- if (!isRecord$7(value) || value.version !== 1 || !isRecord$7(value.grants)) return structuredClone(EMPTY_GRANTS$1);
3304
+ if (!isRecord$8(value) || value.version !== 1 || !isRecord$8(value.grants)) return structuredClone(EMPTY_GRANTS$1);
3305
3305
  const grants = {};
3306
3306
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
3307
- if (!isRecord$7(callerValue) || !isRecord$7(callerValue.capabilities)) continue;
3307
+ if (!isRecord$8(callerValue) || !isRecord$8(callerValue.capabilities)) continue;
3308
3308
  const capabilities = {};
3309
- for (const [capability, grantValue] of Object.entries(callerValue.capabilities)) if (isRecord$7(grantValue) && typeof grantValue.grantedAt === "string") capabilities[capability] = { grantedAt: grantValue.grantedAt };
3309
+ for (const [capability, grantValue] of Object.entries(callerValue.capabilities)) if (isRecord$8(grantValue) && typeof grantValue.grantedAt === "string") capabilities[capability] = { grantedAt: grantValue.grantedAt };
3310
3310
  grants[callerKey] = { capabilities };
3311
3311
  }
3312
3312
  return {
@@ -3317,10 +3317,10 @@ function normalizeStoreData$1(value) {
3317
3317
  function getCallerKey(caller) {
3318
3318
  return `${caller.surface}:${caller.appId}`;
3319
3319
  }
3320
- function isRecord$7(value) {
3320
+ function isRecord$8(value) {
3321
3321
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3322
3322
  }
3323
- function isMissingFileError$1(error) {
3323
+ function isMissingFileError$2(error) {
3324
3324
  return Boolean(error) && typeof error === "object" && error.code === "ENOENT";
3325
3325
  }
3326
3326
  //#endregion
@@ -3335,8 +3335,9 @@ var PanelAppError = class extends Error {
3335
3335
  function isPanelAppError(error) {
3336
3336
  return error instanceof PanelAppError;
3337
3337
  }
3338
+ const PANEL_APP_AGENT_CAPABILITIES = ["agent:send", "agent:generateObject"];
3338
3339
  function isPanelAppAgentCapability(value) {
3339
- return value === "agent:send" || value === "agent:generateObject";
3340
+ return PANEL_APP_AGENT_CAPABILITIES.includes(value);
3340
3341
  }
3341
3342
  //#endregion
3342
3343
  //#region src/services/agent-run-client.service.ts
@@ -3611,6 +3612,7 @@ function getPanelAppBridgeScript() {
3611
3612
  }
3612
3613
  //#endregion
3613
3614
  //#region src/utils/panel-app-manifest.utils.ts
3615
+ const PANEL_APP_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3614
3616
  function parsePanelAppManifest(html) {
3615
3617
  return {
3616
3618
  ...readHtmlTitle(html),
@@ -3620,6 +3622,26 @@ function parsePanelAppManifest(html) {
3620
3622
  serviceActions: readPanelAppServiceActions(html)
3621
3623
  };
3622
3624
  }
3625
+ function parsePanelAppFolderManifest(raw) {
3626
+ let parsed;
3627
+ try {
3628
+ parsed = JSON.parse(raw);
3629
+ } catch (error) {
3630
+ throw new Error(`panel-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
3631
+ }
3632
+ if (!isRecord$7(parsed)) throw new Error("panel-app.json must contain an object.");
3633
+ const id = readOptionalString$6(parsed, "id");
3634
+ if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
3635
+ return {
3636
+ id,
3637
+ title: readRequiredString$3(parsed, "title"),
3638
+ description: readOptionalString$6(parsed, "description"),
3639
+ icon: readOptionalString$6(parsed, "icon"),
3640
+ entry: readRequiredString$3(parsed, "entry"),
3641
+ capabilities: readStringArray$1(parsed.capabilities, "capabilities"),
3642
+ serviceActions: readStringArray$1(parsed.actions, "actions")
3643
+ };
3644
+ }
3623
3645
  function readPanelAppMeta(html) {
3624
3646
  return {
3625
3647
  ...readPanelAppMetaField(html, "title"),
@@ -3674,6 +3696,22 @@ function parseTokenList(content) {
3674
3696
  if (!content) return [];
3675
3697
  return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
3676
3698
  }
3699
+ function readRequiredString$3(record, key) {
3700
+ const value = readOptionalString$6(record, key);
3701
+ if (!value) throw new Error(`panel app ${key} is required.`);
3702
+ return value;
3703
+ }
3704
+ function readOptionalString$6(record, key) {
3705
+ return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
3706
+ }
3707
+ function readStringArray$1(value, key) {
3708
+ if (value === void 0) return [];
3709
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`panel app ${key} must be a string array.`);
3710
+ return [...new Set(value.map((entry) => entry.trim()).filter(Boolean))];
3711
+ }
3712
+ function isRecord$7(value) {
3713
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3714
+ }
3677
3715
  function normalizeTextValue(value) {
3678
3716
  return decodeHtmlAttribute(value ?? "").replace(/\s+/g, " ").trim() || void 0;
3679
3717
  }
@@ -3687,6 +3725,169 @@ function normalizeIconHref(value) {
3687
3725
  function decodeHtmlAttribute(value) {
3688
3726
  return value.replace(/&quot;/g, "\"").replace(/&#34;/g, "\"").replace(/&apos;/g, "'").replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
3689
3727
  }
3728
+ const PANEL_APP_FOLDER_MANIFEST_FILE_NAME = "panel-app.json";
3729
+ function isPanelAppSourceEntry(entry) {
3730
+ return entry.isFile() && isPanelAppFileName(entry.name) || entry.isDirectory() && isPanelAppDirName(entry.name);
3731
+ }
3732
+ function isPanelAppFileName(fileName) {
3733
+ return hasSafeBaseName(fileName) && fileName.endsWith(".panel.html");
3734
+ }
3735
+ function isPanelAppDirName(dirName) {
3736
+ return hasSafeBaseName(dirName) && dirName.endsWith(".panel");
3737
+ }
3738
+ function toPanelAppTitle(sourceName) {
3739
+ return sourceName.replace(new RegExp(`${escapeRegExp(".panel.html")}$`), "").replace(new RegExp(`${escapeRegExp(".panel")}$`), "").replace(/[-_]+/g, " ").trim() || sourceName;
3740
+ }
3741
+ function encodePanelAppId(sourceName) {
3742
+ return Buffer.from(sourceName, "utf8").toString("base64url");
3743
+ }
3744
+ function decodePanelAppId(id) {
3745
+ const normalizedId = id.trim();
3746
+ if (!normalizedId) throw new PanelAppError("PANEL_APP_INVALID_ID", "panel app id is required");
3747
+ let sourceName = "";
3748
+ try {
3749
+ sourceName = Buffer.from(normalizedId, "base64url").toString("utf8");
3750
+ } catch {
3751
+ throw new PanelAppError("PANEL_APP_INVALID_ID", "invalid panel app id");
3752
+ }
3753
+ if (encodePanelAppId(sourceName) !== normalizedId || !isPanelAppFileName(sourceName) && !isPanelAppDirName(sourceName)) throw new PanelAppError("PANEL_APP_INVALID_ID", "invalid panel app id");
3754
+ return sourceName;
3755
+ }
3756
+ async function readPanelAppFolderManifest(dirPath, dirName) {
3757
+ const manifest = parsePanelAppFolderManifest(await readFile(join(dirPath, PANEL_APP_FOLDER_MANIFEST_FILE_NAME), "utf8"));
3758
+ const expectedId = dirName.slice(0, -6);
3759
+ if (manifest.id && manifest.id !== expectedId) throw new PanelAppError("PANEL_APP_MANIFEST_INVALID", "panel app manifest id must match the directory name");
3760
+ return {
3761
+ ...manifest,
3762
+ id: expectedId
3763
+ };
3764
+ }
3765
+ function resolvePanelAppRelativePath(rootPath, relativePath) {
3766
+ if (!relativePath.trim() || relativePath.includes("\0") || isAbsolute(relativePath)) throw new PanelAppError("PANEL_APP_INVALID_ASSET_PATH", "invalid panel app asset path");
3767
+ const normalizedPath = normalize(relativePath);
3768
+ if (normalizedPath === "." || normalizedPath.startsWith("..")) throw new PanelAppError("PANEL_APP_INVALID_ASSET_PATH", "invalid panel app asset path");
3769
+ const resolvedPath = resolve(rootPath, normalizedPath);
3770
+ const pathFromRoot = relative(resolve(rootPath), resolvedPath);
3771
+ if (pathFromRoot.startsWith("..") || isAbsolute(pathFromRoot)) throw new PanelAppError("PANEL_APP_INVALID_ASSET_PATH", "invalid panel app asset path");
3772
+ return resolvedPath;
3773
+ }
3774
+ function resolvePanelAppAssetContentType(path) {
3775
+ switch (extname(path).toLowerCase()) {
3776
+ case ".css": return "text/css; charset=utf-8";
3777
+ case ".js":
3778
+ case ".mjs": return "application/javascript; charset=utf-8";
3779
+ case ".json": return "application/json; charset=utf-8";
3780
+ case ".png": return "image/png";
3781
+ case ".svg": return "image/svg+xml; charset=utf-8";
3782
+ case ".webp": return "image/webp";
3783
+ case ".txt": return "text/plain; charset=utf-8";
3784
+ default: return "application/octet-stream";
3785
+ }
3786
+ }
3787
+ function resolvePanelAppIconUrl(id, icon) {
3788
+ if (!icon) return;
3789
+ if (icon.startsWith("data:image/") || icon.startsWith("http://") || icon.startsWith("https://") || icon.startsWith("/") || isLikelyTextIcon(icon)) return icon;
3790
+ return `/api/panel-apps/${encodeURIComponent(id)}/assets/${encodePanelAppAssetPath(icon)}`;
3791
+ }
3792
+ function injectPanelAppAssetBase(html, id) {
3793
+ const base = `<base href="/api/panel-apps/${encodeURIComponent(id)}/assets/">`;
3794
+ if (/<base\b/i.test(html)) return html;
3795
+ if (/<head[^>]*>/i.test(html)) return html.replace(/<head[^>]*>/i, (head) => `${head}${base}`);
3796
+ return `${base}${html}`;
3797
+ }
3798
+ function encodePanelAppAssetPath(path) {
3799
+ return path.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
3800
+ }
3801
+ function hasSafeBaseName(name) {
3802
+ return !name.includes("/") && !name.includes("\\") && !name.includes("\0");
3803
+ }
3804
+ function isLikelyTextIcon(icon) {
3805
+ return !icon.includes("/") && !icon.includes(".") && icon.length <= 4;
3806
+ }
3807
+ function escapeRegExp(value) {
3808
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3809
+ }
3810
+ //#endregion
3811
+ //#region src/services/panel-app-source.service.ts
3812
+ var PanelAppSourceService = class {
3813
+ listSources = async (panelsPath) => {
3814
+ try {
3815
+ const entries = await readdir(panelsPath, { withFileTypes: true });
3816
+ const sources = [];
3817
+ for (const entry of entries.filter(isPanelAppSourceEntry)) try {
3818
+ sources.push(await this.readSource(panelsPath, entry.name));
3819
+ } catch (error) {
3820
+ if (!isPanelAppError(error) || error.code !== "PANEL_APP_NOT_FOUND") throw error;
3821
+ }
3822
+ return sources;
3823
+ } catch (error) {
3824
+ if (isPanelAppError(error)) throw error;
3825
+ if (isMissingFileError$1(error)) return [];
3826
+ throw new PanelAppError("PANEL_APP_READ_FAILED", error instanceof Error ? error.message : String(error));
3827
+ }
3828
+ };
3829
+ resolveSource = async (panelsPath, id) => {
3830
+ const sourceName = decodePanelAppId(id);
3831
+ try {
3832
+ return await this.readSource(panelsPath, sourceName);
3833
+ } catch (error) {
3834
+ if (isPanelAppError(error)) throw error;
3835
+ if (isMissingFileError$1(error)) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app not found");
3836
+ throw new PanelAppError("PANEL_APP_READ_FAILED", error instanceof Error ? error.message : String(error));
3837
+ }
3838
+ };
3839
+ getAsset = async (panelsPath, id, assetPath) => {
3840
+ const source = await this.resolveSource(panelsPath, id);
3841
+ if (source.kind !== "folder") throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app asset not found");
3842
+ const filePath = resolvePanelAppRelativePath(source.sourcePath, assetPath);
3843
+ try {
3844
+ if (!(await stat(filePath)).isFile()) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app asset not found");
3845
+ return {
3846
+ content: await readFile(filePath),
3847
+ contentType: resolvePanelAppAssetContentType(filePath)
3848
+ };
3849
+ } catch (error) {
3850
+ if (isPanelAppError(error)) throw error;
3851
+ if (isMissingFileError$1(error)) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app asset not found");
3852
+ throw new PanelAppError("PANEL_APP_READ_FAILED", error instanceof Error ? error.message : String(error));
3853
+ }
3854
+ };
3855
+ readSource = async (panelsPath, sourceName) => {
3856
+ const sourcePath = join(panelsPath, sourceName);
3857
+ const sourceStat = await stat(sourcePath);
3858
+ if (sourceStat.isFile() && isPanelAppFileName(sourceName)) return {
3859
+ kind: "single-file",
3860
+ sourceName,
3861
+ sourcePath,
3862
+ entryPath: sourcePath,
3863
+ sourceStat
3864
+ };
3865
+ if (sourceStat.isDirectory() && isPanelAppDirName(sourceName)) return await this.readFolderSource(sourcePath, sourceName, sourceStat);
3866
+ throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app not found");
3867
+ };
3868
+ readFolderSource = async (sourcePath, sourceName, sourceStat) => {
3869
+ try {
3870
+ const manifest = await readPanelAppFolderManifest(sourcePath, sourceName);
3871
+ const entryPath = resolvePanelAppRelativePath(sourcePath, manifest.entry);
3872
+ if (!(await stat(entryPath)).isFile()) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app entry not found");
3873
+ return {
3874
+ kind: "folder",
3875
+ sourceName,
3876
+ sourcePath,
3877
+ entryPath,
3878
+ manifest,
3879
+ sourceStat
3880
+ };
3881
+ } catch (error) {
3882
+ if (isPanelAppError(error)) throw error;
3883
+ if (isMissingFileError$1(error)) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app not found");
3884
+ throw new PanelAppError("PANEL_APP_MANIFEST_INVALID", error instanceof Error ? error.message : String(error));
3885
+ }
3886
+ };
3887
+ };
3888
+ function isMissingFileError$1(error) {
3889
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
3890
+ }
3690
3891
  //#endregion
3691
3892
  //#region src/utils/panel-app-time.utils.ts
3692
3893
  function resolvePanelAppCreatedAt(fileStat) {
@@ -3881,13 +4082,13 @@ function isRecord$6(value) {
3881
4082
  }
3882
4083
  //#endregion
3883
4084
  //#region src/managers/panel-app.manager.ts
3884
- const PANEL_APP_FILE_SUFFIX = ".panel.html";
3885
4085
  const PANEL_APP_CONTENT_BASE_PATH = "/api/panel-apps";
3886
4086
  const PANEL_APP_CONTENT_TYPE = "text/html; charset=utf-8";
3887
4087
  const PANEL_APP_CAPABILITY_GRANTS_FILE_NAME = ".panel-app-capability-grants.json";
3888
4088
  var PanelAppManager = class {
3889
4089
  bridgeSessions = /* @__PURE__ */ new Map();
3890
4090
  agentRunClient;
4091
+ sourceService = new PanelAppSourceService();
3891
4092
  constructor(params) {
3892
4093
  this.params = params;
3893
4094
  this.agentRunClient = params.agentRunClient ?? (params.eventBus && params.ingress ? new AgentRunClient({
@@ -3898,25 +4099,26 @@ var PanelAppManager = class {
3898
4099
  listPanelApps = async () => {
3899
4100
  const workspacePath = this.getWorkspacePath();
3900
4101
  const panelsPath = this.getPanelsPath(workspacePath);
3901
- const fileNames = await this.listPanelAppFileNames(panelsPath);
4102
+ const sources = await this.sourceService.listSources(panelsPath);
3902
4103
  const appState = await this.createStateStore(panelsPath).load();
3903
4104
  return {
3904
4105
  workspacePath,
3905
4106
  panelsPath,
3906
- entries: (await Promise.all(fileNames.map((fileName) => this.buildPanelAppEntry(panelsPath, fileName, appState[this.encodePanelAppId(fileName)] ?? {})))).sort(this.comparePanelApps)
4107
+ entries: (await Promise.all(sources.map((source) => this.buildPanelAppEntry(source, appState[encodePanelAppId(source.sourceName)] ?? {})))).sort(this.comparePanelApps)
3907
4108
  };
3908
4109
  };
3909
4110
  getPanelAppContent = async (id) => {
3910
- const fileName = this.decodePanelAppId(id);
3911
- const filePath = join(this.getPanelsPath(this.getWorkspacePath()), fileName);
4111
+ const panelsPath = this.getPanelsPath(this.getWorkspacePath());
3912
4112
  try {
3913
- if (!(await stat(filePath)).isFile()) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app not found");
3914
- const html = await readFile(filePath, "utf8");
3915
- const manifest = parsePanelAppManifest(html);
4113
+ const source = await this.sourceService.resolveSource(panelsPath, id);
4114
+ const html = await readFile(source.entryPath, "utf8");
4115
+ const manifest = source.manifest ?? parsePanelAppManifest(html);
4116
+ const sourceId = encodePanelAppId(source.sourceName);
4117
+ const htmlWithBase = source.kind === "folder" ? injectPanelAppAssetBase(html, sourceId) : html;
3916
4118
  return {
3917
- id: this.encodePanelAppId(fileName),
3918
- fileName,
3919
- html: injectPanelAppBridgeScript(html),
4119
+ id: sourceId,
4120
+ fileName: source.sourceName,
4121
+ html: injectPanelAppBridgeScript(htmlWithBase),
3920
4122
  capabilities: manifest.capabilities,
3921
4123
  contentType: PANEL_APP_CONTENT_TYPE,
3922
4124
  serviceActions: manifest.serviceActions
@@ -3927,6 +4129,10 @@ var PanelAppManager = class {
3927
4129
  throw new PanelAppError("PANEL_APP_READ_FAILED", error instanceof Error ? error.message : String(error));
3928
4130
  }
3929
4131
  };
4132
+ getPanelAppAsset = async (id, assetPath) => {
4133
+ const panelsPath = this.getPanelsPath(this.getWorkspacePath());
4134
+ return await this.sourceService.getAsset(panelsPath, id, assetPath);
4135
+ };
3930
4136
  getPanelAppBridgeScript = () => getPanelAppBridgeScript();
3931
4137
  createPanelAppBridgeSession = async (params) => {
3932
4138
  const content = await this.getPanelAppContent(params.id);
@@ -3996,20 +4202,20 @@ var PanelAppManager = class {
3996
4202
  updatePanelAppPreferences = async (id, preferences) => {
3997
4203
  const fileName = await this.resolvePanelAppFileName(id);
3998
4204
  const panelsPath = this.getPanelsPath(this.getWorkspacePath());
3999
- const state = await this.createStateStore(panelsPath).updatePreferences(this.encodePanelAppId(fileName), preferences);
4000
- return await this.buildPanelAppEntry(panelsPath, fileName, state);
4205
+ const state = await this.createStateStore(panelsPath).updatePreferences(encodePanelAppId(fileName), preferences);
4206
+ return await this.buildPanelAppEntry(await this.sourceService.resolveSource(panelsPath, encodePanelAppId(fileName)), state);
4001
4207
  };
4002
4208
  recordPanelAppOpened = async (id) => {
4003
4209
  const fileName = await this.resolvePanelAppFileName(id);
4004
4210
  const panelsPath = this.getPanelsPath(this.getWorkspacePath());
4005
- const state = await this.createStateStore(panelsPath).recordOpened(this.encodePanelAppId(fileName));
4006
- return await this.buildPanelAppEntry(panelsPath, fileName, state);
4211
+ const state = await this.createStateStore(panelsPath).recordOpened(encodePanelAppId(fileName));
4212
+ return await this.buildPanelAppEntry(await this.sourceService.resolveSource(panelsPath, encodePanelAppId(fileName)), state);
4007
4213
  };
4008
4214
  deletePanelApp = async (id) => {
4009
- const fileName = await this.resolvePanelAppFileName(id);
4010
4215
  const panelsPath = this.getPanelsPath(this.getWorkspacePath());
4011
- const panelAppId = this.encodePanelAppId(fileName);
4012
- await rm(join(panelsPath, fileName));
4216
+ const source = await this.sourceService.resolveSource(panelsPath, id);
4217
+ const panelAppId = encodePanelAppId(source.sourceName);
4218
+ await rm(source.sourcePath, { recursive: source.kind === "folder" });
4013
4219
  await this.createStateStore(panelsPath).deleteEntry(panelAppId);
4014
4220
  await this.createCapabilityGrantStore().deleteCaller({
4015
4221
  surface: "panel-app",
@@ -4018,7 +4224,7 @@ var PanelAppManager = class {
4018
4224
  this.deleteBridgeSessionsByPanelAppId(panelAppId);
4019
4225
  return {
4020
4226
  deleted: true,
4021
- fileName,
4227
+ fileName: source.sourceName,
4022
4228
  id: panelAppId
4023
4229
  };
4024
4230
  };
@@ -4027,7 +4233,19 @@ var PanelAppManager = class {
4027
4233
  if (!await this.createCapabilityGrantStore().isGranted(bridgeSession.caller, capability)) throw new PanelAppError("AUTHORIZATION_REQUIRED", `This panel app needs permission to use ${capability}.`);
4028
4234
  };
4029
4235
  assertDeclaredCapability = (bridgeSession, capability) => {
4030
- if (!bridgeSession.declaredCapabilities.includes(capability)) throw new PanelAppError("PANEL_APP_CAPABILITY_NOT_DECLARED", "panel app did not declare this agent capability");
4236
+ if (!bridgeSession.declaredCapabilities.includes(capability)) throw new PanelAppError("PANEL_APP_CAPABILITY_NOT_DECLARED", this.describeMissingAgentCapability(bridgeSession.declaredCapabilities, capability));
4237
+ };
4238
+ describeMissingAgentCapability = (declaredCapabilities, capability) => {
4239
+ const declared = declaredCapabilities.length > 0 ? declaredCapabilities.join(", ") : "none";
4240
+ const valid = PANEL_APP_AGENT_CAPABILITIES.join(", ");
4241
+ const hint = declaredCapabilities.includes(capability.replace(":", ".")) ? ` Use ${capability}, not ${capability.replace(":", ".")}.` : "";
4242
+ return [
4243
+ `panel app did not declare ${capability}.`,
4244
+ `Declared: ${declared}.`,
4245
+ `Valid capabilities: ${valid}.`,
4246
+ `Declare it with nextclaw-panel-capabilities or panel-app.json capabilities.`,
4247
+ hint.trim()
4248
+ ].filter(Boolean).join(" ");
4031
4249
  };
4032
4250
  requireAgentRunClient = () => {
4033
4251
  if (!this.agentRunClient) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "panel app agent client is not configured");
@@ -4037,63 +4255,31 @@ var PanelAppManager = class {
4037
4255
  getPanelsPath = (workspacePath) => join(workspacePath, DEFAULT_PANELS_DIR);
4038
4256
  createStateStore = (panelsPath) => new PanelAppStateStore(panelsPath);
4039
4257
  createCapabilityGrantStore = () => new PanelAppCapabilityGrantStore(join(this.getPanelsPath(this.getWorkspacePath()), PANEL_APP_CAPABILITY_GRANTS_FILE_NAME));
4040
- listPanelAppFileNames = async (panelsPath) => {
4041
- try {
4042
- return (await readdir(panelsPath, { withFileTypes: true })).filter((entry) => entry.isFile() && this.isPanelAppFileName(entry.name)).map((entry) => entry.name);
4043
- } catch (error) {
4044
- if (this.isMissingFileError(error)) return [];
4045
- throw new PanelAppError("PANEL_APP_READ_FAILED", error instanceof Error ? error.message : String(error));
4046
- }
4047
- };
4048
- buildPanelAppEntry = async (panelsPath, fileName, state) => {
4049
- const filePath = join(panelsPath, fileName);
4050
- const [fileStat, html] = await Promise.all([stat(filePath), readFile(filePath, "utf8")]);
4051
- const manifest = parsePanelAppManifest(html);
4052
- const id = this.encodePanelAppId(fileName);
4053
- const createdAt = resolvePanelAppCreatedAt(fileStat);
4054
- const updatedAt = fileStat.mtime.toISOString();
4258
+ buildPanelAppEntry = async (source, state) => {
4259
+ const manifest = source.manifest ?? parsePanelAppManifest(await readFile(source.entryPath, "utf8"));
4260
+ const id = encodePanelAppId(source.sourceName);
4261
+ const createdAt = resolvePanelAppCreatedAt(source.sourceStat);
4262
+ const updatedAt = source.sourceStat.mtime.toISOString();
4055
4263
  const entry = {
4056
4264
  id,
4057
- fileName,
4058
- title: manifest.title ?? this.toPanelAppTitle(fileName),
4265
+ fileName: source.sourceName,
4266
+ kind: source.kind,
4267
+ title: manifest.title ?? toPanelAppTitle(source.sourceName),
4059
4268
  contentPath: `${PANEL_APP_CONTENT_BASE_PATH}/${encodeURIComponent(id)}/content`,
4060
4269
  createdAt,
4061
4270
  updatedAt,
4062
- sizeBytes: fileStat.size,
4271
+ sizeBytes: source.sourceStat.size,
4063
4272
  favorite: state.favorite ?? false,
4064
4273
  openCount: state.openCount ?? 0
4065
4274
  };
4066
4275
  if (manifest.description) entry.description = manifest.description;
4067
- if (manifest.icon) entry.icon = manifest.icon;
4276
+ if (manifest.icon) entry.icon = source.kind === "folder" ? resolvePanelAppIconUrl(id, manifest.icon) : manifest.icon;
4068
4277
  if (state.lastOpenedAt) entry.lastOpenedAt = state.lastOpenedAt;
4069
4278
  return entry;
4070
4279
  };
4071
4280
  resolvePanelAppFileName = async (id) => {
4072
- const fileName = this.decodePanelAppId(id);
4073
- const filePath = join(this.getPanelsPath(this.getWorkspacePath()), fileName);
4074
- try {
4075
- if ((await stat(filePath)).isFile()) return fileName;
4076
- } catch (error) {
4077
- if (this.isMissingFileError(error)) throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app not found");
4078
- throw new PanelAppError("PANEL_APP_READ_FAILED", error instanceof Error ? error.message : String(error));
4079
- }
4080
- throw new PanelAppError("PANEL_APP_NOT_FOUND", "panel app not found");
4081
- };
4082
- encodePanelAppId = (fileName) => Buffer.from(fileName, "utf8").toString("base64url");
4083
- decodePanelAppId = (id) => {
4084
- const normalizedId = id.trim();
4085
- if (!normalizedId) throw new PanelAppError("PANEL_APP_INVALID_ID", "panel app id is required");
4086
- let fileName = "";
4087
- try {
4088
- fileName = Buffer.from(normalizedId, "base64url").toString("utf8");
4089
- } catch {
4090
- throw new PanelAppError("PANEL_APP_INVALID_ID", "invalid panel app id");
4091
- }
4092
- if (this.encodePanelAppId(fileName) !== normalizedId || !this.isPanelAppFileName(fileName)) throw new PanelAppError("PANEL_APP_INVALID_ID", "invalid panel app id");
4093
- return fileName;
4281
+ return (await this.sourceService.resolveSource(this.getPanelsPath(this.getWorkspacePath()), id)).sourceName;
4094
4282
  };
4095
- isPanelAppFileName = (fileName) => fileName.endsWith(PANEL_APP_FILE_SUFFIX) && !fileName.includes("/") && !fileName.includes("\\") && !fileName.includes("\0");
4096
- toPanelAppTitle = (fileName) => fileName.slice(0, -11).replace(/[-_]+/g, " ").trim() || fileName;
4097
4283
  comparePanelApps = (left, right) => resolvePanelAppActivityMs(right) - resolvePanelAppActivityMs(left) || Number(right.favorite) - Number(left.favorite) || left.title.localeCompare(right.title);
4098
4284
  deleteExpiredBridgeSessions = () => {
4099
4285
  const now = Date.now();
@@ -4993,7 +5179,7 @@ var NcpAgentSessionMetadataStore = class {
4993
5179
  read = async (sessionId, activitySnapshot) => {
4994
5180
  try {
4995
5181
  const parsed = JSON.parse(await readFile(this.metadataPath(sessionId), "utf-8"));
4996
- if (!isRecord$8(parsed) || parsed._type !== "metadata" || !isRecord$8(parsed.metadata)) throw new Error(`invalid ncp agent session metadata sidecar: ${sessionId}`);
5182
+ if (!isRecord$9(parsed) || parsed._type !== "metadata" || !isRecord$9(parsed.metadata)) throw new Error(`invalid ncp agent session metadata sidecar: ${sessionId}`);
4997
5183
  const createdAt = toIsoString(parsed.created_at, activitySnapshot.createdAt);
4998
5184
  const agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
4999
5185
  return {
@@ -5094,7 +5280,7 @@ var NcpAgentSessionSummaryIndexStore = class {
5094
5280
  function serializeJournalEntry(entry) {
5095
5281
  const serialized = JSON.stringify(entry);
5096
5282
  if (!serialized) throw new Error("ncp agent session journal entry serialization produced empty output");
5097
- if (!isRecord$8(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
5283
+ if (!isRecord$9(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
5098
5284
  return serialized;
5099
5285
  }
5100
5286
  var NcpAgentSessionJournalStore = class {
@@ -5310,15 +5496,15 @@ var NcpAgentSessionJournalStore = class {
5310
5496
  console.warn(`[ncp-agent-session-journal] skipped corrupted journal line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
5311
5497
  continue;
5312
5498
  }
5313
- if (!isRecord$8(parsed)) continue;
5499
+ if (!isRecord$9(parsed)) continue;
5314
5500
  if (parsed._type === "metadata") {
5315
- metadata = isRecord$8(parsed.metadata) ? structuredClone(parsed.metadata) : {};
5501
+ metadata = isRecord$9(parsed.metadata) ? structuredClone(parsed.metadata) : {};
5316
5502
  agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
5317
5503
  createdAt = toIsoString(parsed.created_at, createdAt);
5318
5504
  updatedAt = toIsoString(parsed.updated_at, updatedAt);
5319
5505
  continue;
5320
5506
  }
5321
- if (parsed._type === "event" && isRecord$8(parsed.event)) {
5507
+ if (parsed._type === "event" && isRecord$9(parsed.event)) {
5322
5508
  const seq = Number(parsed.seq);
5323
5509
  nextSeq = Math.max(nextSeq, Number.isFinite(seq) ? Math.trunc(seq) + 1 : nextSeq);
5324
5510
  updatedAt = toIsoString(parsed.timestamp, updatedAt);
@@ -8575,6 +8761,6 @@ function resolveLegacyEventType(message) {
8575
8761
  return `message.${role || "other"}`;
8576
8762
  }
8577
8763
  //#endregion
8578
- export { AgentManager, AgentRunClient, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildSessionOrchestrationSection, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
8764
+ export { AgentManager, AgentRunClient, AgentRuntimeRegistry, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildSessionOrchestrationSection, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
8579
8765
 
8580
8766
  //# sourceMappingURL=index.js.map