@nextclaw/kernel 0.5.0 → 0.5.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import { n as getUnsignedUpdateManifest, r as serializeUnsignedUpdateManifest, t as UpdateManifestReader } from "./update-manifest.types-C0qPrjGQ.js";
2
2
  import { createRequire } from "node:module";
3
- import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, evaluateSilentReply, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, isNextclawControlMessage, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeAgentProfileId, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
3
+ import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, evaluateSilentReply, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, isNextclawControlMessage, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeAgentProfileId, normalizeInlineSecretRefs, normalizeModelThinkingCapability, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
4
4
  import { NcpEventType, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
5
5
  import { LocalAssetStore, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
6
6
  import { createHash, createHmac, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
7
7
  import { EventBus, Ingress, eventKeys, ingressKeys, isRuntimeDefaultModelValue, normalizeRuntimeModelSelectionMode } from "@nextclaw/shared";
8
8
  import { catchError, from, lastValueFrom, tap } from "rxjs";
9
- import { appendFileSync, chmodSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
9
+ import { appendFileSync, chmodSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve } from "node:path";
11
- import { spawn } from "node:child_process";
11
+ import { execFileSync, spawn } from "node:child_process";
12
12
  import { access, appendFile, mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
13
13
  import { fileURLToPath } from "node:url";
14
14
  import { BUILTIN_PROVIDER_PLUGINS } from "@nextclaw/runtime";
@@ -703,13 +703,16 @@ var AgentRunRequestManager = class {
703
703
  const contextBlocks = await this.contextProviderManager.buildContext(providerRequest);
704
704
  const tools = await this.toolProviderManager.buildTools(providerRequest);
705
705
  let messageCompletedSeen = false;
706
+ let runtimeFailed = false;
706
707
  lastValueFrom(from(runtime.run(spec, {
707
708
  contextBlocks,
709
+ session,
708
710
  sessionRun,
709
711
  signal: activeRun.signal,
710
712
  tools
711
713
  })).pipe(tap((event) => {
712
714
  const eventsToPublish = [];
715
+ if (event.type === NcpEventType.RunError) runtimeFailed = true;
713
716
  if (event.type === NcpEventType.MessageCompleted) messageCompletedSeen = true;
714
717
  if (event.type === NcpEventType.RunFinished && !messageCompletedSeen) {
715
718
  const message = findCompletedAssistantMessage(sessionRun.getSnapshot().messages, event.payload.messageId);
@@ -730,6 +733,7 @@ var AgentRunRequestManager = class {
730
733
  source: "agent-run-request"
731
734
  });
732
735
  }), catchError(async (error) => {
736
+ runtimeFailed = true;
733
737
  const event = {
734
738
  type: NcpEventType.RunError,
735
739
  payload: {
@@ -744,7 +748,14 @@ var AgentRunRequestManager = class {
744
748
  emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
745
749
  source: "agent-run-request"
746
750
  });
747
- })), { defaultValue: void 0 });
751
+ })), { defaultValue: void 0 }).finally(() => {
752
+ if (!runtimeFailed) return;
753
+ this.agentRuntimeManager.disposeRuntime({
754
+ agentRuntimeId: session.agentRuntimeId,
755
+ session,
756
+ sessionRun
757
+ }).catch(() => void 0);
758
+ });
748
759
  return {
749
760
  sessionId: session.sessionId,
750
761
  userMessageId: message.id,
@@ -855,6 +866,7 @@ async function describeAgentRuntimeSessionTypes(params) {
855
866
  reasonMessage: `Runtime provider unavailable for type "${entry.type}".`,
856
867
  recommendedModel: null,
857
868
  modelSelectionMode: "nextclaw",
869
+ runtimeDefaultThinking: null,
858
870
  cta: {
859
871
  kind: "settings",
860
872
  label: "Configure Runtime"
@@ -873,6 +885,7 @@ async function describeAgentRuntimeSessionTypes(params) {
873
885
  reasonMessage: descriptor?.reasonMessage ?? null,
874
886
  recommendedModel: descriptor?.recommendedModel ?? null,
875
887
  modelSelectionMode: descriptor?.modelSelectionMode ?? "nextclaw",
888
+ runtimeDefaultThinking: descriptor?.runtimeDefaultThinking ?? null,
876
889
  cta: descriptor?.cta ?? null,
877
890
  ...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
878
891
  };
@@ -909,12 +922,8 @@ var AgentRuntimeManager = class {
909
922
  });
910
923
  };
911
924
  getOrCreate = (params) => {
912
- const { agentRuntimeId, session, sessionRun } = params;
913
- const entry = this.getEntry(agentRuntimeId);
914
- const provider = this.getProvider(entry.type);
915
- const reuseScope = this.resolveReuseScope(entry, provider);
916
- const cacheKey = reuseScope === "global" ? entry.id : `${entry.id}:${session.sessionId}`;
917
- const cache = reuseScope === "global" ? this.globalRuntimes : this.sessionRuntimes;
925
+ const { session, sessionRun } = params;
926
+ const { cache, cacheKey, entry, provider } = this.resolveRuntimeCache(params);
918
927
  const existing = cache.get(cacheKey);
919
928
  if (existing) return existing;
920
929
  const agentRuntime = provider.createRuntime({
@@ -925,6 +934,14 @@ var AgentRuntimeManager = class {
925
934
  cache.set(cacheKey, agentRuntime);
926
935
  return agentRuntime;
927
936
  };
937
+ disposeRuntime = async (params) => {
938
+ const { cache, cacheKey } = this.resolveRuntimeCache(params);
939
+ const runtime = cache.get(cacheKey);
940
+ if (!runtime) return false;
941
+ cache.delete(cacheKey);
942
+ await runtime.dispose?.();
943
+ return true;
944
+ };
928
945
  listSessionTypes = async (params) => describeAgentRuntimeSessionTypes({
929
946
  entries: [...this.entries.values()],
930
947
  providers: this.providers,
@@ -954,6 +971,19 @@ var AgentRuntimeManager = class {
954
971
  resolveReuseScope = (entry, provider) => {
955
972
  return entry.config?.reuseScope === "session" || entry.config?.reuseScope === "global" ? entry.config.reuseScope : provider.defaultReuseScope;
956
973
  };
974
+ resolveRuntimeCache = (params) => {
975
+ const { agentRuntimeId, session } = params;
976
+ const entry = this.getEntry(agentRuntimeId);
977
+ const provider = this.getProvider(entry.type);
978
+ const reuseScope = this.resolveReuseScope(entry, provider);
979
+ const cacheKey = reuseScope === "global" ? entry.id : `${entry.id}:${session.sessionId}`;
980
+ return {
981
+ cache: reuseScope === "global" ? this.globalRuntimes : this.sessionRuntimes,
982
+ cacheKey,
983
+ entry,
984
+ provider
985
+ };
986
+ };
957
987
  disposeAllRuntimes = async () => {
958
988
  for (const runtime of [...this.globalRuntimes.values(), ...this.sessionRuntimes.values()]) await runtime.dispose?.();
959
989
  this.globalRuntimes.clear();
@@ -1993,7 +2023,11 @@ var CommandRegistry = class {
1993
2023
  //#region src/features/extension-runtime/services/extension-lifecycle.service.ts
1994
2024
  var ExtensionLifecycleService = class {
1995
2025
  processes = /* @__PURE__ */ new Map();
2026
+ constructor(options = {}) {
2027
+ this.options = options;
2028
+ }
1996
2029
  startAll = (manifests, params) => {
2030
+ this.cleanupOrphanProcesses(manifests);
1997
2031
  const started = [];
1998
2032
  for (const manifest of manifests) try {
1999
2033
  started.push(this.start(manifest, params));
@@ -2024,6 +2058,7 @@ var ExtensionLifecycleService = class {
2024
2058
  ...manifest.server.env,
2025
2059
  NEXTCLAW_EXTENSION_ID: manifest.id,
2026
2060
  NEXTCLAW_EXTENSION_ENDPOINT: params.endpoint,
2061
+ NEXTCLAW_EXTENSION_PARENT_PID: String(process.pid),
2027
2062
  NEXTCLAW_EXTENSION_TOKEN: params.tokenForExtension(manifest.id)
2028
2063
  }, { inheritBaseEnv: true }),
2029
2064
  stdio: [
@@ -2047,6 +2082,86 @@ var ExtensionLifecycleService = class {
2047
2082
  });
2048
2083
  return running;
2049
2084
  };
2085
+ cleanupOrphanProcesses = (manifests) => {
2086
+ if (this.options.cleanupOrphanProcesses) {
2087
+ this.options.cleanupOrphanProcesses(manifests);
2088
+ return;
2089
+ }
2090
+ if (process.platform === "win32" || process.env.NEXTCLAW_EXTENSION_ORPHAN_CLEANUP === "0") return;
2091
+ try {
2092
+ const roots = this.resolveManifestRoots(manifests);
2093
+ for (const snapshot of this.listOrphanNodeDistMainProcesses()) {
2094
+ const cwd = this.readProcessCwd(snapshot.pid);
2095
+ if (!cwd || !this.isNextClawChannelExtensionCwd(cwd, roots)) continue;
2096
+ try {
2097
+ process.kill(snapshot.pid, "SIGTERM");
2098
+ console.warn(`Stopped orphan extension process ${snapshot.pid} (${cwd}).`);
2099
+ } catch (error) {
2100
+ console.warn(`Failed to stop orphan extension process ${snapshot.pid}: ${error instanceof Error ? error.message : String(error)}`);
2101
+ }
2102
+ }
2103
+ } catch (error) {
2104
+ console.warn(`Extension orphan cleanup skipped: ${error instanceof Error ? error.message : String(error)}`);
2105
+ }
2106
+ };
2107
+ resolveManifestRoots = (manifests) => {
2108
+ return new Set(manifests.map((manifest) => this.normalizePath(manifest.rootDir)));
2109
+ };
2110
+ normalizePath = (value) => {
2111
+ try {
2112
+ return realpathSync(value);
2113
+ } catch {
2114
+ return resolve(value);
2115
+ }
2116
+ };
2117
+ listOrphanNodeDistMainProcesses = () => {
2118
+ return execFileSync("ps", ["-axo", "pid=,ppid=,command="], {
2119
+ encoding: "utf8",
2120
+ maxBuffer: 16 * 1024 * 1024
2121
+ }).split("\n").map((line) => {
2122
+ const match = line.trim().match(/^(\d+)\s+(\d+)\s+(.*)$/);
2123
+ if (!match) return null;
2124
+ return {
2125
+ pid: Number(match[1]),
2126
+ ppid: Number(match[2]),
2127
+ command: match[3] ?? ""
2128
+ };
2129
+ }).filter((snapshot) => Boolean(snapshot && snapshot.ppid === 1 && this.isNodeDistMainCommand(snapshot.command)));
2130
+ };
2131
+ isNodeDistMainCommand = (command) => {
2132
+ return /(?:^|\s|\/)node(?:\.exe)?\s+dist\/main\.js(?:\s|$)/.test(command);
2133
+ };
2134
+ readProcessCwd = (pid) => {
2135
+ if (process.platform === "linux") try {
2136
+ return this.normalizePath(readlinkSync(`/proc/${pid}/cwd`));
2137
+ } catch {
2138
+ return null;
2139
+ }
2140
+ try {
2141
+ const cwd = execFileSync("lsof", [
2142
+ "-a",
2143
+ "-p",
2144
+ String(pid),
2145
+ "-d",
2146
+ "cwd",
2147
+ "-Fn"
2148
+ ], {
2149
+ encoding: "utf8",
2150
+ stdio: [
2151
+ "ignore",
2152
+ "pipe",
2153
+ "ignore"
2154
+ ]
2155
+ }).split("\n").find((line) => line.startsWith("n"))?.slice(1).trim();
2156
+ return cwd ? this.normalizePath(cwd) : null;
2157
+ } catch {
2158
+ return null;
2159
+ }
2160
+ };
2161
+ isNextClawChannelExtensionCwd = (cwd, roots) => {
2162
+ if (roots.has(cwd)) return true;
2163
+ return /(?:^|\/)nextclaw-channel-extension-[^/]+$/.test(cwd) || /\/node_modules\/@nextclaw\/channel-extension-[^/]+$/.test(cwd) || /\/node_modules\/\.nextclaw-[^/]+\/node_modules\/@nextclaw\/channel-extension-[^/]+$/.test(cwd);
2164
+ };
2050
2165
  };
2051
2166
  //#endregion
2052
2167
  //#region src/features/extension-runtime/services/extension-manifest-discovery.service.ts
@@ -3443,6 +3558,262 @@ function readEventSessionId$1(event) {
3443
3558
  return "payload" in event && "sessionId" in event.payload ? readOptionalMetadataString(event.payload.sessionId) : void 0;
3444
3559
  }
3445
3560
  //#endregion
3561
+ //#region src/contributions/session-activity-preview/utils/session-activity-preview-ncp-event.utils.ts
3562
+ const PREVIEW_TEXT_MAX_LENGTH = 160;
3563
+ function readSessionId(value) {
3564
+ if (typeof value !== "string") return null;
3565
+ const trimmed = value.trim();
3566
+ return trimmed.length > 0 ? trimmed : null;
3567
+ }
3568
+ function compactPreviewText(value) {
3569
+ return value.replace(/\s+/g, " ").trim();
3570
+ }
3571
+ function truncatePreviewText(value) {
3572
+ const compacted = compactPreviewText(value);
3573
+ if (compacted.length <= PREVIEW_TEXT_MAX_LENGTH) return compacted;
3574
+ return compacted.slice(0, PREVIEW_TEXT_MAX_LENGTH - 1).trimEnd();
3575
+ }
3576
+ function readSessionActivityPreviewText(message) {
3577
+ const chunks = [];
3578
+ for (const part of message.parts) if ((part.type === "text" || part.type === "rich-text") && part.text.trim()) chunks.push(part.text);
3579
+ const previewText = truncatePreviewText(chunks.join(" "));
3580
+ return previewText.length > 0 ? previewText : null;
3581
+ }
3582
+ function createProjection(sessionId, preview) {
3583
+ if (!sessionId) return null;
3584
+ return {
3585
+ sessionId,
3586
+ preview
3587
+ };
3588
+ }
3589
+ function formatErrorStatus(error) {
3590
+ if (typeof error === "string" && error.trim()) return `运行出错:${truncatePreviewText(error)}`;
3591
+ if (error && typeof error === "object" && "message" in error) {
3592
+ const message = error.message;
3593
+ if (typeof message === "string" && message.trim()) return `运行出错:${truncatePreviewText(message)}`;
3594
+ }
3595
+ return "运行出错";
3596
+ }
3597
+ function readToolCallId(value) {
3598
+ if (typeof value !== "string") return null;
3599
+ const trimmed = value.trim();
3600
+ return trimmed.length > 0 ? trimmed : null;
3601
+ }
3602
+ function formatToolDoneStatus(toolName) {
3603
+ return toolName ? `工具调用完成:${toolName}` : "工具调用完成";
3604
+ }
3605
+ function createSessionActivityPreviewFromNcpEvent(event, timestamp, options = {}) {
3606
+ switch (event.type) {
3607
+ case NcpEventType.RunStarted: return createProjection(readSessionId(event.payload.sessionId), {
3608
+ state: "running",
3609
+ statusText: "正在思考",
3610
+ timestamp
3611
+ });
3612
+ case NcpEventType.RunFinished: return createProjection(readSessionId(event.payload.sessionId), {
3613
+ state: "completed",
3614
+ timestamp
3615
+ });
3616
+ case NcpEventType.RunError: return createProjection(readSessionId(event.payload.sessionId), {
3617
+ state: "failed",
3618
+ statusText: formatErrorStatus(event.payload.error),
3619
+ timestamp
3620
+ });
3621
+ case NcpEventType.MessageSent: {
3622
+ const text = readSessionActivityPreviewText(event.payload.message);
3623
+ if (!text || event.payload.message.role !== "user") return null;
3624
+ return createProjection(readSessionId(event.payload.sessionId), {
3625
+ state: "running",
3626
+ statusText: text,
3627
+ timestamp: event.payload.message.timestamp || timestamp
3628
+ });
3629
+ }
3630
+ case NcpEventType.MessageCompleted: {
3631
+ const text = readSessionActivityPreviewText(event.payload.message);
3632
+ if (!text || event.payload.message.role !== "assistant") return null;
3633
+ return createProjection(readSessionId(event.payload.sessionId), {
3634
+ state: "completed",
3635
+ replyText: text,
3636
+ timestamp: event.payload.message.timestamp || timestamp
3637
+ });
3638
+ }
3639
+ case NcpEventType.MessageFailed: return createProjection(readSessionId(event.payload.sessionId), {
3640
+ state: "failed",
3641
+ statusText: formatErrorStatus(event.payload.error),
3642
+ timestamp
3643
+ });
3644
+ case NcpEventType.MessageToolCallStart: return createProjection(readSessionId(event.payload.sessionId), {
3645
+ state: "running",
3646
+ statusText: `正在调用工具:${event.payload.toolName}`,
3647
+ timestamp
3648
+ });
3649
+ case NcpEventType.MessageToolCallEnd:
3650
+ case NcpEventType.MessageToolCallResult: {
3651
+ const sessionId = readSessionId(event.payload.sessionId);
3652
+ const toolCallId = readToolCallId(event.payload.toolCallId);
3653
+ return createProjection(sessionId, {
3654
+ state: "running",
3655
+ statusText: formatToolDoneStatus(sessionId && toolCallId ? options.readToolName?.(sessionId, toolCallId) ?? null : null),
3656
+ timestamp
3657
+ });
3658
+ }
3659
+ default: return null;
3660
+ }
3661
+ }
3662
+ //#endregion
3663
+ //#region src/contributions/session-activity-preview/utils/session-activity-preview-metadata.utils.ts
3664
+ const SESSION_ACTIVITY_PREVIEW_METADATA_KEY = "last_activity_preview";
3665
+ const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
3666
+ "running",
3667
+ "completed",
3668
+ "failed",
3669
+ "idle"
3670
+ ]);
3671
+ function isRecord$10(value) {
3672
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3673
+ }
3674
+ function readOptionalString$7(value) {
3675
+ if (typeof value !== "string") return;
3676
+ const trimmed = value.trim();
3677
+ return trimmed.length > 0 ? trimmed : void 0;
3678
+ }
3679
+ function readSessionActivityPreviewMetadata(value) {
3680
+ if (!isRecord$10(value)) return null;
3681
+ const state = value.state;
3682
+ const timestamp = readOptionalString$7(value.timestamp);
3683
+ if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
3684
+ return {
3685
+ state,
3686
+ timestamp,
3687
+ ...readOptionalString$7(value.statusText) ? { statusText: readOptionalString$7(value.statusText) } : {},
3688
+ ...readOptionalString$7(value.replyText) ? { replyText: readOptionalString$7(value.replyText) } : {}
3689
+ };
3690
+ }
3691
+ function compareIsoTimestamp(left, right) {
3692
+ const leftTime = Date.parse(left);
3693
+ const rightTime = Date.parse(right);
3694
+ if (!Number.isFinite(leftTime) || !Number.isFinite(rightTime)) return left.localeCompare(right);
3695
+ return leftTime - rightTime;
3696
+ }
3697
+ function mergeSessionActivityPreview(current, incoming) {
3698
+ if (current && compareIsoTimestamp(incoming.timestamp, current.timestamp) < 0) return incoming.replyText && !current.replyText ? {
3699
+ ...current,
3700
+ replyText: incoming.replyText
3701
+ } : current;
3702
+ return {
3703
+ state: incoming.state,
3704
+ timestamp: incoming.timestamp,
3705
+ ...incoming.statusText ?? (incoming.state === "completed" ? current?.statusText : void 0) ? { statusText: incoming.statusText ?? current?.statusText } : {},
3706
+ ...incoming.replyText ?? (incoming.state === "completed" ? current?.replyText : void 0) ? { replyText: incoming.replyText ?? current?.replyText } : {}
3707
+ };
3708
+ }
3709
+ function areSessionActivityPreviewsEqual(left, right) {
3710
+ return Boolean(left) && left?.state === right.state && left.timestamp === right.timestamp && left.statusText === right.statusText && left.replyText === right.replyText;
3711
+ }
3712
+ function writeSessionActivityPreviewMetadata(metadata, projection) {
3713
+ const current = readSessionActivityPreviewMetadata(metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY]);
3714
+ const next = mergeSessionActivityPreview(current, projection.preview);
3715
+ if (areSessionActivityPreviewsEqual(current, next)) return null;
3716
+ return {
3717
+ ...metadata ?? {},
3718
+ [SESSION_ACTIVITY_PREVIEW_METADATA_KEY]: next
3719
+ };
3720
+ }
3721
+ //#endregion
3722
+ //#region src/contributions/session-activity-preview/services/session-activity-preview-event.service.ts
3723
+ var SessionActivityPreviewEventService = class {
3724
+ toolNames = /* @__PURE__ */ new Map();
3725
+ constructor(options) {
3726
+ this.options = options;
3727
+ }
3728
+ projectEvent = (event, timestamp) => {
3729
+ this.rememberToolName(event);
3730
+ const projection = createSessionActivityPreviewFromNcpEvent(event, timestamp, { readToolName: this.readToolName });
3731
+ this.clearFinishedRunToolNames(event);
3732
+ return projection;
3733
+ };
3734
+ updatePreview = async (projection) => {
3735
+ const session = await this.options.getSessionRecord(projection.sessionId);
3736
+ const replyText = projection.preview.replyText ?? (projection.preview.state === "completed" ? this.readLatestAssistantPreviewText(session?.messages) : void 0);
3737
+ const nextMetadata = writeSessionActivityPreviewMetadata(session?.metadata, {
3738
+ ...projection,
3739
+ preview: {
3740
+ ...projection.preview,
3741
+ replyText
3742
+ }
3743
+ });
3744
+ if (nextMetadata) await this.options.updateSessionMetadata(projection.sessionId, nextMetadata);
3745
+ };
3746
+ clear = () => {
3747
+ this.toolNames.clear();
3748
+ };
3749
+ rememberToolName = (event) => {
3750
+ if (event.type !== NcpEventType.MessageToolCallStart) return;
3751
+ const { sessionId, toolCallId, toolName } = event.payload;
3752
+ if (sessionId && toolCallId && toolName) this.toolNames.set(this.createToolNameKey(sessionId, toolCallId), toolName);
3753
+ };
3754
+ readToolName = (sessionId, toolCallId) => this.toolNames.get(this.createToolNameKey(sessionId, toolCallId)) ?? null;
3755
+ clearFinishedRunToolNames = (event) => {
3756
+ if (event.type !== NcpEventType.RunFinished && event.type !== NcpEventType.RunError) return;
3757
+ const sessionId = event.payload.sessionId;
3758
+ for (const key of this.toolNames.keys()) if (key.startsWith(`${sessionId}:`)) this.toolNames.delete(key);
3759
+ };
3760
+ createToolNameKey = (sessionId, toolCallId) => `${sessionId}:${toolCallId}`;
3761
+ readLatestAssistantPreviewText = (messages) => {
3762
+ for (let index = (messages?.length ?? 0) - 1; index >= 0; index -= 1) {
3763
+ const message = messages?.[index];
3764
+ if (message?.role === "assistant") return readSessionActivityPreviewText(message) ?? void 0;
3765
+ }
3766
+ };
3767
+ };
3768
+ //#endregion
3769
+ //#region src/services/session-event-ingestion.service.ts
3770
+ const SESSION_METADATA_PATCH_RUN_METADATA_KIND = "session_metadata_patch";
3771
+ function isDurableSessionEvent(event) {
3772
+ return event.type !== NcpEventType.ContextWindowUpdated;
3773
+ }
3774
+ function readRuntimeSessionMetadataPatch(event) {
3775
+ if (event.type !== NcpEventType.RunMetadata) return null;
3776
+ const metadata = event.payload.metadata;
3777
+ if (metadata.kind !== SESSION_METADATA_PATCH_RUN_METADATA_KIND || !metadata.sessionMetadataPatch || typeof metadata.sessionMetadataPatch !== "object" || Array.isArray(metadata.sessionMetadataPatch)) return null;
3778
+ const patch = metadata.sessionMetadataPatch;
3779
+ return Object.keys(patch).length > 0 ? structuredClone(patch) : null;
3780
+ }
3781
+ var SessionEventIngestionService = class {
3782
+ activityPreview;
3783
+ chains = /* @__PURE__ */ new Map();
3784
+ constructor(options) {
3785
+ this.options = options;
3786
+ this.activityPreview = new SessionActivityPreviewEventService({
3787
+ getSessionRecord: options.getSessionRecord,
3788
+ updateSessionMetadata: options.updateSessionMetadata
3789
+ });
3790
+ }
3791
+ handleEvent = (event) => {
3792
+ const sessionId = readEventSessionId$1(event);
3793
+ if (!sessionId || !isDurableSessionEvent(event)) return;
3794
+ const next = (this.chains.get(sessionId) ?? Promise.resolve()).then(() => this.handleDurableEvent(sessionId, event));
3795
+ this.chains.set(sessionId, next.catch(() => void 0));
3796
+ next.catch((error) => this.options.onError(sessionId, error));
3797
+ };
3798
+ clear = () => {
3799
+ this.chains.clear();
3800
+ this.activityPreview.clear();
3801
+ };
3802
+ handleDurableEvent = async (sessionId, event) => {
3803
+ const preview = this.activityPreview.projectEvent(event, (/* @__PURE__ */ new Date()).toISOString());
3804
+ const metadataPatch = readRuntimeSessionMetadataPatch(event);
3805
+ if (metadataPatch) {
3806
+ await this.options.updateSessionMetadata(sessionId, metadataPatch);
3807
+ return;
3808
+ }
3809
+ await this.options.appendSessionEvent({
3810
+ event,
3811
+ sessionId
3812
+ });
3813
+ if (preview) await this.activityPreview.updatePreview(preview);
3814
+ };
3815
+ };
3816
+ //#endregion
3446
3817
  //#region src/services/session-working-dir-resolver.service.ts
3447
3818
  var SessionWorkingDirResolver = class {
3448
3819
  constructor(agentManager) {
@@ -3471,10 +3842,6 @@ const SESSION_METADATA_LABEL_KEY = "label";
3471
3842
  const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3472
3843
  const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3473
3844
  const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3474
- const SESSION_METADATA_PATCH_RUN_METADATA_KIND = "session_metadata_patch";
3475
- function isDurableSessionEvent(event) {
3476
- return event.type !== NcpEventType.ContextWindowUpdated;
3477
- }
3478
3845
  function readThinkingEffort(metadata) {
3479
3846
  return readOptionalMetadataString(metadata?.thinkingEffort) ?? null;
3480
3847
  }
@@ -3542,42 +3909,34 @@ function isSessionSummaryRefreshEvent(event) {
3542
3909
  default: return false;
3543
3910
  }
3544
3911
  }
3545
- function readRuntimeSessionMetadataPatch(event) {
3546
- if (event.type !== NcpEventType.RunMetadata) return null;
3547
- const metadata = event.payload.metadata;
3548
- if (metadata.kind !== SESSION_METADATA_PATCH_RUN_METADATA_KIND || !metadata.sessionMetadataPatch || typeof metadata.sessionMetadataPatch !== "object" || Array.isArray(metadata.sessionMetadataPatch)) return null;
3549
- const patch = metadata.sessionMetadataPatch;
3550
- return Object.keys(patch).length > 0 ? structuredClone(patch) : null;
3551
- }
3552
3912
  var SessionManager = class {
3553
3913
  cleanups = [];
3554
3914
  contextWindowPreview;
3915
+ eventIngestion;
3555
3916
  workingDirResolver;
3556
3917
  started = false;
3557
3918
  constructor(options) {
3558
3919
  this.options = options;
3920
+ this.eventIngestion = new SessionEventIngestionService({
3921
+ appendSessionEvent: (params) => this.appendSessionEvent(params),
3922
+ getSessionRecord: (sessionId) => this.getSessionRecord(sessionId),
3923
+ onError: (sessionId, error) => {
3924
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
3925
+ console.error(`[session-manager] failed to handle ncp event for ${sessionId}: ${message}`);
3926
+ },
3927
+ updateSessionMetadata: (sessionId, metadata) => this.updateSessionMetadata(sessionId, metadata)
3928
+ });
3559
3929
  this.contextWindowPreview = new ContextWindowPreviewManager(options.agentManager);
3560
3930
  this.workingDirResolver = new SessionWorkingDirResolver(options.agentManager);
3561
3931
  }
3562
3932
  start = () => {
3563
3933
  if (this.started) return;
3564
3934
  this.started = true;
3565
- this.cleanups.push(this.options.eventBus.on(eventKeys.ncpEvent, async (event) => {
3566
- const sessionId = readEventSessionId$1(event);
3567
- if (!sessionId || !isDurableSessionEvent(event)) return;
3568
- const metadataPatch = readRuntimeSessionMetadataPatch(event);
3569
- if (metadataPatch) {
3570
- await this.updateSessionMetadata(sessionId, metadataPatch);
3571
- return;
3572
- }
3573
- await this.appendSessionEvent({
3574
- event,
3575
- sessionId
3576
- });
3577
- }));
3935
+ this.cleanups.push(this.options.eventBus.on(eventKeys.ncpEvent, this.eventIngestion.handleEvent));
3578
3936
  };
3579
3937
  dispose = () => {
3580
3938
  while (this.cleanups.length > 0) this.cleanups.pop()?.();
3939
+ this.eventIngestion.clear();
3581
3940
  this.started = false;
3582
3941
  };
3583
3942
  createSession = async (params) => {
@@ -3706,6 +4065,10 @@ var SessionManager = class {
3706
4065
  metadata: structuredClone(record.metadata ?? {}),
3707
4066
  model,
3708
4067
  projectRoot: readProjectRoot(record.metadata),
4068
+ workingDir: this.workingDirResolver.resolve({
4069
+ agentId: record.agentId,
4070
+ metadata: record.metadata
4071
+ }),
3709
4072
  thinkingEffort: readThinkingEffort(record.metadata)
3710
4073
  };
3711
4074
  };
@@ -3742,6 +4105,10 @@ var SessionManager = class {
3742
4105
  metadata: structuredClone(created.metadata ?? {}),
3743
4106
  model,
3744
4107
  projectRoot,
4108
+ workingDir: this.workingDirResolver.resolve({
4109
+ agentId,
4110
+ metadata: created.metadata
4111
+ }),
3745
4112
  thinkingEffort: thinkingEffort ?? null
3746
4113
  };
3747
4114
  };
@@ -4009,12 +4376,12 @@ var PanelAppCapabilityGrantStore = class {
4009
4376
  };
4010
4377
  };
4011
4378
  function normalizeStoreData$2(value) {
4012
- if (!isRecord$10(value) || value.version !== 1 || !isRecord$10(value.grants)) return structuredClone(EMPTY_GRANTS$2);
4379
+ if (!isRecord$9(value) || value.version !== 1 || !isRecord$9(value.grants)) return structuredClone(EMPTY_GRANTS$2);
4013
4380
  const grants = {};
4014
4381
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
4015
- if (!isRecord$10(callerValue) || !isRecord$10(callerValue.capabilities)) continue;
4382
+ if (!isRecord$9(callerValue) || !isRecord$9(callerValue.capabilities)) continue;
4016
4383
  const capabilities = {};
4017
- for (const [capability, grantValue] of Object.entries(callerValue.capabilities)) if (isRecord$10(grantValue) && typeof grantValue.grantedAt === "string") capabilities[capability] = { grantedAt: grantValue.grantedAt };
4384
+ for (const [capability, grantValue] of Object.entries(callerValue.capabilities)) if (isRecord$9(grantValue) && typeof grantValue.grantedAt === "string") capabilities[capability] = { grantedAt: grantValue.grantedAt };
4018
4385
  grants[callerKey] = { capabilities };
4019
4386
  }
4020
4387
  return {
@@ -4025,7 +4392,7 @@ function normalizeStoreData$2(value) {
4025
4392
  function getCallerKey(caller) {
4026
4393
  return `${caller.surface}:${caller.appId}`;
4027
4394
  }
4028
- function isRecord$10(value) {
4395
+ function isRecord$9(value) {
4029
4396
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4030
4397
  }
4031
4398
  function isMissingFileError$3(error) {
@@ -4071,19 +4438,19 @@ var PanelAppClientGrantStore = class {
4071
4438
  };
4072
4439
  };
4073
4440
  function normalizeStoreData$1(value) {
4074
- if (!isRecord$9(value) || value.version !== 1 || !isRecord$9(value.grants)) return structuredClone(EMPTY_GRANTS$1);
4441
+ if (!isRecord$8(value) || value.version !== 1 || !isRecord$8(value.grants)) return structuredClone(EMPTY_GRANTS$1);
4075
4442
  const grants = {};
4076
- for (const [appId, grant] of Object.entries(value.grants)) if (isRecord$9(grant) && typeof grant.grantedAt === "string") grants[appId] = { grantedAt: grant.grantedAt };
4443
+ for (const [appId, grant] of Object.entries(value.grants)) if (isRecord$8(grant) && typeof grant.grantedAt === "string") grants[appId] = { grantedAt: grant.grantedAt };
4077
4444
  return {
4078
4445
  grants,
4079
4446
  version: 1
4080
4447
  };
4081
4448
  }
4082
- function isRecord$9(value) {
4449
+ function isRecord$8(value) {
4083
4450
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4084
4451
  }
4085
4452
  function isMissingFileError$2(error) {
4086
- return isRecord$9(error) && error.code === "ENOENT";
4453
+ return isRecord$8(error) && error.code === "ENOENT";
4087
4454
  }
4088
4455
  //#endregion
4089
4456
  //#region src/services/agent-run-client.service.ts
@@ -4302,7 +4669,7 @@ const PANEL_APP_AGENT_MAX_CONTEXT_CHARS = 8e4;
4302
4669
  function normalizePanelAppGenerateObjectInput(input) {
4303
4670
  const peerId = input.peerId.trim();
4304
4671
  const prompt = input.prompt.trim();
4305
- if (!peerId || !prompt || !isRecord$8(input.schema)) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "invalid generateObject request");
4672
+ if (!peerId || !prompt || !isRecord$7(input.schema)) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "invalid generateObject request");
4306
4673
  if (prompt.length > PANEL_APP_AGENT_MAX_PROMPT_CHARS) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "generateObject prompt is too large");
4307
4674
  if (stringifyJsonValue(input.context ?? null).length > PANEL_APP_AGENT_MAX_CONTEXT_CHARS) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "generateObject context is too large");
4308
4675
  return {
@@ -4443,7 +4810,7 @@ function readStructuredResultEvent(event, resultToolCallId) {
4443
4810
  };
4444
4811
  }
4445
4812
  function assertToolResultContent(content) {
4446
- if (!isRecord$8(content) || content.ok !== false || !isRecord$8(content.error)) return;
4813
+ if (!isRecord$7(content) || content.ok !== false || !isRecord$7(content.error)) return;
4447
4814
  if (content.error.code === "invalid_tool_arguments") throw new PanelAppError("AGENT_OBJECT_RESULT_SCHEMA_INVALID", "agent object result did not match the schema");
4448
4815
  throw new PanelAppError("AGENT_OBJECT_REQUEST_FAILED", typeof content.error.message === "string" ? content.error.message : "agent object request failed");
4449
4816
  }
@@ -4459,7 +4826,7 @@ function stringifyJsonValue(value) {
4459
4826
  throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "value is not JSON serializable");
4460
4827
  }
4461
4828
  }
4462
- function isRecord$8(value) {
4829
+ function isRecord$7(value) {
4463
4830
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4464
4831
  }
4465
4832
  //#endregion
@@ -4733,14 +5100,14 @@ function parsePanelAppFolderManifest(raw) {
4733
5100
  } catch (error) {
4734
5101
  throw new Error(`panel-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
4735
5102
  }
4736
- if (!isRecord$7(parsed)) throw new Error("panel-app.json must contain an object.");
4737
- const id = readOptionalString$7(parsed, "id");
5103
+ if (!isRecord$6(parsed)) throw new Error("panel-app.json must contain an object.");
5104
+ const id = readOptionalString$6(parsed, "id");
4738
5105
  if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
4739
5106
  return {
4740
5107
  id,
4741
5108
  title: readRequiredString$4(parsed, "title"),
4742
- description: readOptionalString$7(parsed, "description"),
4743
- icon: readOptionalString$7(parsed, "icon"),
5109
+ description: readOptionalString$6(parsed, "description"),
5110
+ icon: readOptionalString$6(parsed, "icon"),
4744
5111
  entry: readRequiredString$4(parsed, "entry"),
4745
5112
  capabilities: readStringArray$1(parsed.capabilities, "capabilities"),
4746
5113
  client: readOptionalBoolean$2(parsed, "client"),
@@ -4802,11 +5169,11 @@ function parseTokenList(content) {
4802
5169
  return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
4803
5170
  }
4804
5171
  function readRequiredString$4(record, key) {
4805
- const value = readOptionalString$7(record, key);
5172
+ const value = readOptionalString$6(record, key);
4806
5173
  if (!value) throw new Error(`panel app ${key} is required.`);
4807
5174
  return value;
4808
5175
  }
4809
- function readOptionalString$7(record, key) {
5176
+ function readOptionalString$6(record, key) {
4810
5177
  return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
4811
5178
  }
4812
5179
  function readOptionalBoolean$2(record, key) {
@@ -4820,7 +5187,7 @@ function readStringArray$1(value, key) {
4820
5187
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`panel app ${key} must be a string array.`);
4821
5188
  return [...new Set(value.map((entry) => entry.trim()).filter(Boolean))];
4822
5189
  }
4823
- function isRecord$7(value) {
5190
+ function isRecord$6(value) {
4824
5191
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4825
5192
  }
4826
5193
  function normalizeTextValue(value) {
@@ -5301,27 +5668,146 @@ var PanelAppManager = class {
5301
5668
  clientGranted: await this.isPanelAppClientGranted(appId, manifest.client),
5302
5669
  openCount: state.openCount ?? 0
5303
5670
  };
5304
- if (manifest.description) entry.description = manifest.description;
5305
- if (manifest.icon) entry.icon = source.kind === "folder" ? resolvePanelAppIconUrl(id, manifest.icon) : manifest.icon;
5306
- if (state.lastOpenedAt) entry.lastOpenedAt = state.lastOpenedAt;
5307
- return entry;
5671
+ if (manifest.description) entry.description = manifest.description;
5672
+ if (manifest.icon) entry.icon = source.kind === "folder" ? resolvePanelAppIconUrl(id, manifest.icon) : manifest.icon;
5673
+ if (state.lastOpenedAt) entry.lastOpenedAt = state.lastOpenedAt;
5674
+ return entry;
5675
+ };
5676
+ resolvePanelAppFileName = async (id) => {
5677
+ return (await this.sourceService.resolveSource(this.getPanelsPath(this.getWorkspacePath()), id)).sourceName;
5678
+ };
5679
+ comparePanelApps = (left, right) => resolvePanelAppActivityMs(right) - resolvePanelAppActivityMs(left) || Number(right.favorite) - Number(left.favorite) || left.title.localeCompare(right.title);
5680
+ deleteExpiredBridgeSessions = () => {
5681
+ const now = Date.now();
5682
+ for (const [token, session] of this.bridgeSessions) if (new Date(session.expiresAt).getTime() <= now) this.bridgeSessions.delete(token);
5683
+ };
5684
+ deleteBridgeSessionsByPanelAppId = (panelAppId) => {
5685
+ for (const [token, session] of this.bridgeSessions) if (session.appId === panelAppId) this.bridgeSessions.delete(token);
5686
+ };
5687
+ isPanelAppClientGranted = async (appId, clientDeclared) => {
5688
+ if (!clientDeclared) return false;
5689
+ return await this.createClientGrantStore().isGranted(appId);
5690
+ };
5691
+ isMissingFileError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
5692
+ };
5693
+ //#endregion
5694
+ //#region src/stores/preference.store.ts
5695
+ const PREFERENCE_STORE_VERSION = 1;
5696
+ var PreferenceStore = class {
5697
+ constructor(storePath) {
5698
+ this.storePath = storePath;
5699
+ }
5700
+ get = async (key) => {
5701
+ return (await this.load())[key] ?? null;
5702
+ };
5703
+ set = async (key, value, updatedAt = /* @__PURE__ */ new Date()) => {
5704
+ const entries = await this.load();
5705
+ const entry = {
5706
+ key,
5707
+ value,
5708
+ updatedAt: updatedAt.toISOString()
5709
+ };
5710
+ entries[key] = entry;
5711
+ await this.persist(entries);
5712
+ return entry;
5713
+ };
5714
+ delete = async (key) => {
5715
+ const entries = await this.load();
5716
+ if (!(key in entries)) return false;
5717
+ delete entries[key];
5718
+ await this.persist(entries);
5719
+ return true;
5720
+ };
5721
+ load = async () => {
5722
+ try {
5723
+ const parsed = JSON.parse(await readFile(this.storePath, "utf8"));
5724
+ return this.normalizeStoreFile(parsed).entries;
5725
+ } catch (error) {
5726
+ if (this.isMissingFileError(error) || error instanceof SyntaxError) return {};
5727
+ throw error;
5728
+ }
5729
+ };
5730
+ persist = async (entries) => {
5731
+ const tempPath = `${this.storePath}.${randomUUID()}.tmp`;
5732
+ const storeFile = {
5733
+ version: PREFERENCE_STORE_VERSION,
5734
+ entries
5735
+ };
5736
+ await mkdir(dirname(this.storePath), { recursive: true });
5737
+ try {
5738
+ await writeFile(tempPath, `${JSON.stringify(storeFile, null, 2)}\n`, "utf8");
5739
+ await rename(tempPath, this.storePath);
5740
+ } catch (error) {
5741
+ await rm(tempPath, { force: true }).catch(() => void 0);
5742
+ throw error;
5743
+ }
5744
+ };
5745
+ normalizeStoreFile = (value) => {
5746
+ if (!this.isRecord(value) || !this.isRecord(value.entries)) return {
5747
+ version: PREFERENCE_STORE_VERSION,
5748
+ entries: {}
5749
+ };
5750
+ return {
5751
+ version: PREFERENCE_STORE_VERSION,
5752
+ entries: Object.fromEntries(Object.entries(value.entries).flatMap(([key, entry]) => {
5753
+ if (!this.isRecord(entry) || !this.isJsonValue(entry.value)) return [];
5754
+ return [[key, {
5755
+ key,
5756
+ value: entry.value,
5757
+ updatedAt: typeof entry.updatedAt === "string" ? entry.updatedAt : (/* @__PURE__ */ new Date(0)).toISOString()
5758
+ }]];
5759
+ }))
5760
+ };
5308
5761
  };
5309
- resolvePanelAppFileName = async (id) => {
5310
- return (await this.sourceService.resolveSource(this.getPanelsPath(this.getWorkspacePath()), id)).sourceName;
5762
+ isJsonValue = (value) => {
5763
+ if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return true;
5764
+ if (Array.isArray(value)) return value.every((item) => this.isJsonValue(item));
5765
+ if (this.isPlainRecord(value)) return Object.values(value).every((item) => this.isJsonValue(item));
5766
+ return false;
5311
5767
  };
5312
- comparePanelApps = (left, right) => resolvePanelAppActivityMs(right) - resolvePanelAppActivityMs(left) || Number(right.favorite) - Number(left.favorite) || left.title.localeCompare(right.title);
5313
- deleteExpiredBridgeSessions = () => {
5314
- const now = Date.now();
5315
- for (const [token, session] of this.bridgeSessions) if (new Date(session.expiresAt).getTime() <= now) this.bridgeSessions.delete(token);
5768
+ isRecord = (value) => this.isPlainRecord(value);
5769
+ isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
5770
+ isMissingFileError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
5771
+ };
5772
+ //#endregion
5773
+ //#region src/managers/preference.manager.ts
5774
+ var PreferenceError = class extends Error {
5775
+ constructor(code, message) {
5776
+ super(message);
5777
+ this.code = code;
5778
+ this.name = "PreferenceError";
5779
+ }
5780
+ };
5781
+ function isPreferenceError(error) {
5782
+ return error instanceof PreferenceError;
5783
+ }
5784
+ var PreferenceManager = class {
5785
+ store;
5786
+ constructor(options) {
5787
+ this.store = new PreferenceStore(options.storePath);
5788
+ }
5789
+ getPreference = async (key) => {
5790
+ return await this.store.get(this.normalizeKey(key));
5316
5791
  };
5317
- deleteBridgeSessionsByPanelAppId = (panelAppId) => {
5318
- for (const [token, session] of this.bridgeSessions) if (session.appId === panelAppId) this.bridgeSessions.delete(token);
5792
+ setPreference = async (key, value) => {
5793
+ if (value === void 0 || !this.isJsonValue(value)) throw new PreferenceError("PREFERENCE_INVALID_VALUE", "preference value must be JSON serializable");
5794
+ return await this.store.set(this.normalizeKey(key), value);
5319
5795
  };
5320
- isPanelAppClientGranted = async (appId, clientDeclared) => {
5321
- if (!clientDeclared) return false;
5322
- return await this.createClientGrantStore().isGranted(appId);
5796
+ deletePreference = async (key) => {
5797
+ return await this.store.delete(this.normalizeKey(key));
5323
5798
  };
5324
- isMissingFileError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
5799
+ normalizeKey = (key) => {
5800
+ const normalized = key.trim();
5801
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(normalized)) throw new PreferenceError("PREFERENCE_INVALID_KEY", "preference key is invalid");
5802
+ return normalized;
5803
+ };
5804
+ isJsonValue = (value) => {
5805
+ if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return true;
5806
+ if (Array.isArray(value)) return value.every((item) => this.isJsonValue(item));
5807
+ if (this.isPlainRecord(value)) return Object.values(value).every((item) => this.isJsonValue(item));
5808
+ return false;
5809
+ };
5810
+ isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
5325
5811
  };
5326
5812
  //#endregion
5327
5813
  //#region src/utils/service-action.utils.ts
@@ -5538,12 +6024,12 @@ var ServiceActionGrantStore = class {
5538
6024
  };
5539
6025
  };
5540
6026
  function normalizeStoreData(value) {
5541
- if (!isRecord$6(value) || value.version !== 1 || !isRecord$6(value.grants)) return structuredClone(EMPTY_GRANTS);
6027
+ if (!isRecord$5(value) || value.version !== 1 || !isRecord$5(value.grants)) return structuredClone(EMPTY_GRANTS);
5542
6028
  const grants = {};
5543
6029
  for (const [callerKey, callerValue] of Object.entries(value.grants)) {
5544
- if (!isRecord$6(callerValue) || !isRecord$6(callerValue.actions)) continue;
6030
+ if (!isRecord$5(callerValue) || !isRecord$5(callerValue.actions)) continue;
5545
6031
  const actions = {};
5546
- for (const [actionId, actionValue] of Object.entries(callerValue.actions)) if (isRecord$6(actionValue) && typeof actionValue.grantedAt === "string" && isServiceActionRisk(actionValue.risk)) actions[actionId] = {
6032
+ for (const [actionId, actionValue] of Object.entries(callerValue.actions)) if (isRecord$5(actionValue) && typeof actionValue.grantedAt === "string" && isServiceActionRisk(actionValue.risk)) actions[actionId] = {
5547
6033
  grantedAt: actionValue.grantedAt,
5548
6034
  risk: actionValue.risk
5549
6035
  };
@@ -5557,11 +6043,11 @@ function normalizeStoreData(value) {
5557
6043
  function isServiceActionRisk(value) {
5558
6044
  return value === "read" || value === "write" || value === "external" || value === "dangerous";
5559
6045
  }
5560
- function isRecord$6(value) {
6046
+ function isRecord$5(value) {
5561
6047
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5562
6048
  }
5563
6049
  function isMissingFileError(error) {
5564
- return isRecord$6(error) && error.code === "ENOENT";
6050
+ return isRecord$5(error) && error.code === "ENOENT";
5565
6051
  }
5566
6052
  //#endregion
5567
6053
  //#region src/utils/service-app-manifest.utils.ts
@@ -5586,15 +6072,15 @@ function parseServiceAppManifest(raw) {
5586
6072
  } catch (error) {
5587
6073
  throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
5588
6074
  }
5589
- if (!isRecord$5(parsed)) throw new Error("service-app.json must contain an object.");
6075
+ if (!isRecord$4(parsed)) throw new Error("service-app.json must contain an object.");
5590
6076
  const id = readRequiredString$3(parsed, "id");
5591
6077
  if (!SERVICE_APP_ID_PATTERN.test(id)) throw new Error("service app id must be kebab-case.");
5592
- const protocol = readOptionalString$6(parsed, "protocol") ?? "mcp";
6078
+ const protocol = readOptionalString$5(parsed, "protocol") ?? "mcp";
5593
6079
  if (protocol !== "mcp") throw new Error("service app protocol must be mcp.");
5594
6080
  return {
5595
6081
  id,
5596
6082
  title: readRequiredString$3(parsed, "title"),
5597
- description: readOptionalString$6(parsed, "description"),
6083
+ description: readOptionalString$5(parsed, "description"),
5598
6084
  enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
5599
6085
  protocol,
5600
6086
  command: readRequiredString$3(parsed, "command"),
@@ -5604,31 +6090,31 @@ function parseServiceAppManifest(raw) {
5604
6090
  }
5605
6091
  function readManifestActions(value) {
5606
6092
  if (value === void 0) throw new Error("service app actions are required.");
5607
- if (!isRecord$5(value)) throw new Error("service app actions must be an object.");
6093
+ if (!isRecord$4(value)) throw new Error("service app actions must be an object.");
5608
6094
  if (Object.keys(value).length === 0) throw new Error("service app actions cannot be empty.");
5609
6095
  const actions = {};
5610
6096
  for (const [name, action] of Object.entries(value)) {
5611
6097
  if (!name.trim()) throw new Error("service app action name cannot be empty.");
5612
- if (!isRecord$5(action)) throw new Error(`service app action ${name} must be an object.`);
5613
- const risk = readOptionalString$6(action, "risk");
6098
+ if (!isRecord$4(action)) throw new Error(`service app action ${name} must be an object.`);
6099
+ const risk = readOptionalString$5(action, "risk");
5614
6100
  if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
5615
6101
  const inputSchema = action.inputSchema;
5616
- if (inputSchema !== void 0 && !isRecord$5(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
6102
+ if (inputSchema !== void 0 && !isRecord$4(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
5617
6103
  actions[name] = {
5618
6104
  risk,
5619
- title: readOptionalString$6(action, "title"),
5620
- description: readOptionalString$6(action, "description"),
6105
+ title: readOptionalString$5(action, "title"),
6106
+ description: readOptionalString$5(action, "description"),
5621
6107
  inputSchema
5622
6108
  };
5623
6109
  }
5624
6110
  return actions;
5625
6111
  }
5626
6112
  function readRequiredString$3(record, key) {
5627
- const value = readOptionalString$6(record, key);
6113
+ const value = readOptionalString$5(record, key);
5628
6114
  if (!value) throw new Error(`service app ${key} is required.`);
5629
6115
  return value;
5630
6116
  }
5631
- function readOptionalString$6(record, key) {
6117
+ function readOptionalString$5(record, key) {
5632
6118
  return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
5633
6119
  }
5634
6120
  function readOptionalBoolean$1(record, key) {
@@ -5641,7 +6127,7 @@ function readStringArray(value, key) {
5641
6127
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`service app ${key} must be a string array.`);
5642
6128
  return value;
5643
6129
  }
5644
- function isRecord$5(value) {
6130
+ function isRecord$4(value) {
5645
6131
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5646
6132
  }
5647
6133
  //#endregion
@@ -6064,7 +6550,7 @@ function parseFrontmatterBlock(raw) {
6064
6550
  function parseYamlFrontmatter(raw) {
6065
6551
  try {
6066
6552
  const parsed = parse(raw);
6067
- return isRecord$4(parsed) ? parsed : {};
6553
+ return isRecord$3(parsed) ? parsed : {};
6068
6554
  } catch (error) {
6069
6555
  const message = error instanceof Error ? error.message : String(error);
6070
6556
  throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
@@ -6076,7 +6562,7 @@ function readString$3(record, ...names) {
6076
6562
  }
6077
6563
  function readLocalizedTextMap(record, ...names) {
6078
6564
  const value = readValue(record, names);
6079
- if (!isRecord$4(value)) return;
6565
+ if (!isRecord$3(value)) return;
6080
6566
  const localized = Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0).map(([locale, text]) => [normalizeLocaleTag(locale), text.trim()]));
6081
6567
  return Object.keys(localized).length > 0 ? localized : void 0;
6082
6568
  }
@@ -6100,7 +6586,7 @@ function normalizeFrontmatterKey(raw) {
6100
6586
  function normalizeLocaleTag(raw) {
6101
6587
  return raw.trim().toLowerCase();
6102
6588
  }
6103
- function isRecord$4(value) {
6589
+ function isRecord$3(value) {
6104
6590
  return typeof value === "object" && value !== null && !Array.isArray(value);
6105
6591
  }
6106
6592
  //#endregion
@@ -6925,9 +7411,6 @@ function readString$2(value) {
6925
7411
  if (typeof value !== "string") return;
6926
7412
  return value.trim() || void 0;
6927
7413
  }
6928
- function resolveEntryIcon(entry) {
6929
- return entry.icon ?? null;
6930
- }
6931
7414
  function resolveRequestedModel(params) {
6932
7415
  const { configuredModel, defaultModel, input, modelSelectionMode, sessionMetadata } = params;
6933
7416
  if (modelSelectionMode === "runtime-default") return;
@@ -6981,25 +7464,28 @@ var BuiltinHttpRuntimeSessionTypeService = class {
6981
7464
  describeInternal = async () => {
6982
7465
  const config = new HttpRuntimeConfigResolver(this.entry.config ?? {}).resolve({ defaultModel: this.defaultModel });
6983
7466
  const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
7467
+ const baseDescriptor = {
7468
+ icon: this.entry.icon ?? null,
7469
+ modelSelectionMode,
7470
+ runtimeDefaultThinking: normalizeModelThinkingCapability(this.entry.config?.runtimeDefaultThinking)
7471
+ };
6984
7472
  if (!config.baseUrl) return {
6985
- icon: resolveEntryIcon(this.entry),
7473
+ ...baseDescriptor,
6986
7474
  ready: false,
6987
7475
  reason: "base_url_missing",
6988
7476
  reasonMessage: "Configure the runtime entry baseUrl before starting an HTTP runtime session.",
6989
7477
  recommendedModel: config.recommendedModel ?? null,
6990
- modelSelectionMode,
6991
7478
  cta: {
6992
7479
  kind: "settings",
6993
7480
  label: "Configure HTTP Runtime"
6994
7481
  }
6995
7482
  };
6996
7483
  if (!((config.capabilityProbe ?? true) && Boolean(config.healthcheckUrl))) return {
6997
- icon: resolveEntryIcon(this.entry),
7484
+ ...baseDescriptor,
6998
7485
  ready: true,
6999
7486
  reason: null,
7000
7487
  reasonMessage: null,
7001
7488
  recommendedModel: config.recommendedModel ?? null,
7002
- modelSelectionMode,
7003
7489
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
7004
7490
  cta: null
7005
7491
  };
@@ -7013,28 +7499,26 @@ var BuiltinHttpRuntimeSessionTypeService = class {
7013
7499
  signal: controller.signal
7014
7500
  });
7015
7501
  if (!response.ok) return {
7016
- icon: resolveEntryIcon(this.entry),
7502
+ ...baseDescriptor,
7017
7503
  ready: false,
7018
7504
  reason: "healthcheck_failed",
7019
7505
  reasonMessage: `HTTP runtime healthcheck returned HTTP ${response.status}.`,
7020
7506
  recommendedModel: config.recommendedModel ?? null,
7021
- modelSelectionMode,
7022
7507
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
7023
7508
  cta: null
7024
7509
  };
7025
7510
  return {
7026
- icon: resolveEntryIcon(this.entry),
7511
+ ...baseDescriptor,
7027
7512
  ready: true,
7028
7513
  reason: null,
7029
7514
  reasonMessage: null,
7030
7515
  recommendedModel: config.recommendedModel ?? null,
7031
- modelSelectionMode,
7032
7516
  ...config.supportedModels ? { supportedModels: config.supportedModels } : {},
7033
7517
  cta: null
7034
7518
  };
7035
7519
  } catch (error) {
7036
7520
  return {
7037
- icon: resolveEntryIcon(this.entry),
7521
+ ...baseDescriptor,
7038
7522
  ready: false,
7039
7523
  reason: "healthcheck_unreachable",
7040
7524
  reasonMessage: error instanceof Error ? error.message : "Failed to reach the configured HTTP runtime healthcheck.",
@@ -7067,53 +7551,54 @@ var BuiltinStdioRuntimeSessionTypeService = class {
7067
7551
  describeInternal = async (describeMode) => {
7068
7552
  const resolver = new StdioRuntimeConfigResolver(this.entry.config ?? {});
7069
7553
  const modelSelectionMode = normalizeRuntimeModelSelectionMode(this.entry.config?.modelSelectionMode);
7554
+ const baseDescriptor = {
7555
+ icon: this.entry.icon ?? null,
7556
+ modelSelectionMode,
7557
+ runtimeDefaultThinking: normalizeModelThinkingCapability(this.entry.config?.runtimeDefaultThinking)
7558
+ };
7070
7559
  try {
7071
7560
  const config = resolver.resolve();
7072
7561
  if (!await resolveExecutablePath(config.command)) return {
7073
- icon: resolveEntryIcon(this.entry),
7562
+ ...baseDescriptor,
7074
7563
  ready: false,
7075
7564
  reason: "command_missing",
7076
7565
  reasonMessage: `Configured stdio command "${config.command}" is not available. Update the runtime entry command or install the required launcher first.`,
7077
7566
  cta: {
7078
7567
  kind: "settings",
7079
7568
  label: "Configure Stdio Runtime"
7080
- },
7081
- modelSelectionMode
7569
+ }
7082
7570
  };
7083
7571
  if (describeMode === "probe") try {
7084
7572
  await probeStdioRuntime(config);
7085
7573
  } catch (error) {
7086
7574
  return {
7087
- icon: resolveEntryIcon(this.entry),
7575
+ ...baseDescriptor,
7088
7576
  ready: false,
7089
7577
  reason: "probe_failed",
7090
7578
  reasonMessage: error instanceof Error ? error.message : "Configured stdio runtime could not complete the ACP probe.",
7091
7579
  cta: {
7092
7580
  kind: "settings",
7093
7581
  label: "Repair Stdio Runtime"
7094
- },
7095
- modelSelectionMode
7582
+ }
7096
7583
  };
7097
7584
  }
7098
7585
  return {
7099
- icon: resolveEntryIcon(this.entry),
7586
+ ...baseDescriptor,
7100
7587
  ready: true,
7101
7588
  reason: null,
7102
7589
  reasonMessage: null,
7103
- modelSelectionMode,
7104
7590
  cta: null
7105
7591
  };
7106
7592
  } catch (error) {
7107
7593
  return {
7108
- icon: resolveEntryIcon(this.entry),
7594
+ ...baseDescriptor,
7109
7595
  ready: false,
7110
7596
  reason: "command_missing",
7111
7597
  reasonMessage: error instanceof Error ? error.message : "Configure a stdio command before starting this runtime.",
7112
7598
  cta: {
7113
7599
  kind: "settings",
7114
7600
  label: "Configure Stdio Runtime"
7115
- },
7116
- modelSelectionMode
7601
+ }
7117
7602
  };
7118
7603
  }
7119
7604
  };
@@ -7184,7 +7669,6 @@ var BuiltinNarpRuntimeProviderService = class {
7184
7669
  const config = readRecord(entry.config) ?? {};
7185
7670
  return new StdioRuntimeNcpAgentRuntime({
7186
7671
  ...new StdioRuntimeConfigResolver(config).resolve(),
7187
- sessionId: runtimeParams.sessionId,
7188
7672
  resolveTools: runtimeParams.resolveTools,
7189
7673
  stateManager: runtimeParams.stateManager,
7190
7674
  resolveProviderRoute: (input) => buildProviderRoute({
@@ -7280,13 +7764,13 @@ var ProviderManagerNcpLLMApi = class {
7280
7764
  };
7281
7765
  //#endregion
7282
7766
  //#region src/features/native-runtime/tools/ncp-asset.tools.ts
7283
- function readOptionalString$5(value) {
7767
+ function readOptionalString$4(value) {
7284
7768
  if (typeof value !== "string") return null;
7285
7769
  const trimmed = value.trim();
7286
7770
  return trimmed.length > 0 ? trimmed : null;
7287
7771
  }
7288
7772
  function readOptionalBase64Bytes(value) {
7289
- const base64 = readOptionalString$5(value);
7773
+ const base64 = readOptionalString$4(value);
7290
7774
  if (!base64) return null;
7291
7775
  try {
7292
7776
  return Buffer.from(base64, "base64");
@@ -7337,18 +7821,18 @@ var AssetPutTool = class {
7337
7821
  this.contentBasePath = contentBasePath;
7338
7822
  }
7339
7823
  validateArgs = (args) => {
7340
- const path = readOptionalString$5(args.path);
7341
- const bytesBase64 = readOptionalString$5(args.bytesBase64);
7342
- const fileName = readOptionalString$5(args.fileName);
7824
+ const path = readOptionalString$4(args.path);
7825
+ const bytesBase64 = readOptionalString$4(args.bytesBase64);
7826
+ const fileName = readOptionalString$4(args.fileName);
7343
7827
  if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
7344
7828
  if (path) return [];
7345
7829
  if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
7346
7830
  return ["Provide either path, or bytesBase64 + fileName."];
7347
7831
  };
7348
7832
  execute = async (args) => {
7349
- const path = readOptionalString$5(args?.path);
7350
- const fileName = readOptionalString$5(args?.fileName);
7351
- const mimeType = readOptionalString$5(args?.mimeType);
7833
+ const path = readOptionalString$4(args?.path);
7834
+ const fileName = readOptionalString$4(args?.fileName);
7835
+ const mimeType = readOptionalString$4(args?.mimeType);
7352
7836
  const bytes = readOptionalBase64Bytes(args?.bytesBase64);
7353
7837
  if (path) return {
7354
7838
  ok: true,
@@ -7391,8 +7875,8 @@ var AssetExportTool = class {
7391
7875
  this.assetStore = assetStore;
7392
7876
  }
7393
7877
  execute = async (args) => {
7394
- const assetUri = readOptionalString$5(args?.assetUri);
7395
- const targetPath = readOptionalString$5(args?.targetPath);
7878
+ const assetUri = readOptionalString$4(args?.assetUri);
7879
+ const targetPath = readOptionalString$4(args?.targetPath);
7396
7880
  if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
7397
7881
  return {
7398
7882
  ok: true,
@@ -7418,7 +7902,7 @@ var AssetStatTool = class {
7418
7902
  this.contentBasePath = contentBasePath;
7419
7903
  }
7420
7904
  execute = async (args) => {
7421
- const assetUri = readOptionalString$5(args?.assetUri);
7905
+ const assetUri = readOptionalString$4(args?.assetUri);
7422
7906
  if (!assetUri) throw new Error("asset_stat requires assetUri.");
7423
7907
  const record = await this.assetStore.statRecord(assetUri);
7424
7908
  if (!record) return {
@@ -7695,7 +8179,8 @@ var NcpAgentRuntimeWrapper = class {
7695
8179
  runId: spec.runId,
7696
8180
  messages,
7697
8181
  correlationId: spec.correlationId,
7698
- metadata: this.buildMetadata(spec)
8182
+ metadata: this.buildMetadata(options.session, spec),
8183
+ executionContext: { cwd: options.session.workingDir }
7699
8184
  };
7700
8185
  for await (const event of this.getRuntime().run(input, { signal: options.signal })) yield await this.applyEvent(sessionRun, event);
7701
8186
  this.currentTools = [];
@@ -7720,10 +8205,10 @@ var NcpAgentRuntimeWrapper = class {
7720
8205
  correlationId: spec.correlationId
7721
8206
  }
7722
8207
  }));
7723
- buildMetadata = (spec) => ({
7724
- ...this.params.session.metadata,
8208
+ buildMetadata = (session, spec) => ({
8209
+ ...session.metadata,
7725
8210
  agentId: spec.agentId,
7726
- agentRuntimeId: this.params.session.agentRuntimeId,
8211
+ agentRuntimeId: session.agentRuntimeId,
7727
8212
  maxTokens: spec.maxTokens,
7728
8213
  model: spec.model,
7729
8214
  preferred_model: spec.model,
@@ -7787,20 +8272,16 @@ var AgentRunRuntimeContribution = class {
7787
8272
  describeSessionTypeForEntry: provider.describeSessionTypeForEntry,
7788
8273
  createRuntime: ({ entry, session }) => {
7789
8274
  if (!provider.createRuntimeForEntry) throw new Error(`Agent runtime provider does not support entries: ${provider.kind}`);
7790
- return new NcpAgentRuntimeWrapper({
7791
- session,
7792
- createRuntime: ({ resolveTools, stateManager }) => provider.createRuntimeForEntry({
7793
- entry,
7794
- runtimeParams: {
7795
- sessionId: session.sessionId,
7796
- ...session.agentId ? { agentId: session.agentId } : {},
7797
- resolveAssetContentPath: (assetUri) => this.kernel.assetStore.resolveContentPath(assetUri),
7798
- resolveTools,
7799
- sessionMetadata: session.metadata,
7800
- stateManager
7801
- }
7802
- })
7803
- });
8275
+ return new NcpAgentRuntimeWrapper({ createRuntime: ({ resolveTools, stateManager }) => provider.createRuntimeForEntry({
8276
+ entry,
8277
+ runtimeParams: {
8278
+ ...session.agentId ? { agentId: session.agentId } : {},
8279
+ resolveAssetContentPath: (assetUri) => this.kernel.assetStore.resolveContentPath(assetUri),
8280
+ resolveTools,
8281
+ sessionMetadata: session.metadata,
8282
+ stateManager
8283
+ }
8284
+ }) });
7804
8285
  }
7805
8286
  });
7806
8287
  };
@@ -7966,6 +8447,13 @@ const createToolCallStyleContextProvider = () => staticBlock([
7966
8447
  "Keep narration brief and value-dense; avoid repeating obvious steps.",
7967
8448
  "Use plain human language for narration unless in a technical context."
7968
8449
  ]);
8450
+ const createInlineInteractiveSurfaceContextProvider = () => staticBlock([
8451
+ "## Inline Interactive Surfaces",
8452
+ "Do not make every UI an inline card. Choose inline only when the intended result is a compact, immediately usable card or short interaction; use the side panel for normal Panel Apps, long reading, rich editing, file browsing, large tables, multi-page workflows, or sustained workspaces.",
8453
+ "When you choose an inline card, call `show_content` with `type=\"panel_app\"` and `placement=\"inline\"` so the user can try it directly in the chat. Do not wait for the user to say \"inline\" or \"placement\" after you have already chosen the card form.",
8454
+ "A Panel Card must be designed card-first: prefer a landscape composition where width carries the main information and the card is wider than it is tall; collapse to one column only in narrow containers. Core value must be visible in the first 220-420px, with no horizontal scrolling, no reliance on document-level internal scrolling, compact controls, at most one primary action, clear loading/empty/error states, and an obvious expand path for details.",
8455
+ "Typical Panel Card fits: weather cards, calculators, timers, checklists, pickers, compact forms, previews, and small dashboards. If the UI needs more space than a card, choose `placement=\"side_panel\"` instead. Inline hosts may pass `nextclawDisplayMode=card` and `nextclawPlacement=inline`; use those hints to render a compact card layout instead of a full page."
8456
+ ]);
7969
8457
  const createChatComposerTokensContextProvider = () => staticBlock([
7970
8458
  "## Chat Composer Tokens",
7971
8459
  "When a user message contains tokens like `$weather` or `$web-search`, treat each `$<skill-spec>` token as a user-visible marker that the corresponding skill was explicitly selected in the chat composer.",
@@ -8372,6 +8860,7 @@ var ContextProviderContribution = class {
8372
8860
  createAssistantIdentityContextProvider(),
8373
8861
  new ToolingContextProvider(context),
8374
8862
  createToolCallStyleContextProvider(),
8863
+ createInlineInteractiveSurfaceContextProvider(),
8375
8864
  createChatComposerTokensContextProvider(),
8376
8865
  createSafetyContextProvider(),
8377
8866
  createCliQuickReferenceContextProvider(),
@@ -8639,227 +9128,6 @@ var LearningLoopContribution = class {
8639
9128
  };
8640
9129
  };
8641
9130
  //#endregion
8642
- //#region src/contributions/session-activity-preview/utils/session-activity-preview-ncp-event.utils.ts
8643
- const PREVIEW_TEXT_MAX_LENGTH = 160;
8644
- function readSessionId(value) {
8645
- if (typeof value !== "string") return null;
8646
- const trimmed = value.trim();
8647
- return trimmed.length > 0 ? trimmed : null;
8648
- }
8649
- function compactPreviewText(value) {
8650
- return value.replace(/\s+/g, " ").trim();
8651
- }
8652
- function truncatePreviewText(value) {
8653
- const compacted = compactPreviewText(value);
8654
- if (compacted.length <= PREVIEW_TEXT_MAX_LENGTH) return compacted;
8655
- return compacted.slice(0, PREVIEW_TEXT_MAX_LENGTH - 1).trimEnd();
8656
- }
8657
- function readMessagePreviewText(message) {
8658
- const chunks = [];
8659
- for (const part of message.parts) if ((part.type === "text" || part.type === "rich-text") && part.text.trim()) chunks.push(part.text);
8660
- const previewText = truncatePreviewText(chunks.join(" "));
8661
- return previewText.length > 0 ? previewText : null;
8662
- }
8663
- function createProjection(sessionId, preview) {
8664
- if (!sessionId) return null;
8665
- return {
8666
- sessionId,
8667
- preview
8668
- };
8669
- }
8670
- function formatErrorStatus(error) {
8671
- if (typeof error === "string" && error.trim()) return `运行出错:${truncatePreviewText(error)}`;
8672
- if (error && typeof error === "object" && "message" in error) {
8673
- const message = error.message;
8674
- if (typeof message === "string" && message.trim()) return `运行出错:${truncatePreviewText(message)}`;
8675
- }
8676
- return "运行出错";
8677
- }
8678
- function readToolCallId(value) {
8679
- if (typeof value !== "string") return null;
8680
- const trimmed = value.trim();
8681
- return trimmed.length > 0 ? trimmed : null;
8682
- }
8683
- function formatToolDoneStatus(toolName) {
8684
- return toolName ? `工具调用完成:${toolName}` : "工具调用完成";
8685
- }
8686
- function createSessionActivityPreviewFromNcpEvent(event, timestamp, options = {}) {
8687
- switch (event.type) {
8688
- case NcpEventType.RunStarted: return createProjection(readSessionId(event.payload.sessionId), {
8689
- state: "running",
8690
- statusText: "正在思考",
8691
- timestamp
8692
- });
8693
- case NcpEventType.RunFinished: return createProjection(readSessionId(event.payload.sessionId), {
8694
- state: "completed",
8695
- timestamp
8696
- });
8697
- case NcpEventType.RunError: return createProjection(readSessionId(event.payload.sessionId), {
8698
- state: "failed",
8699
- statusText: formatErrorStatus(event.payload.error),
8700
- timestamp
8701
- });
8702
- case NcpEventType.MessageSent: {
8703
- const text = readMessagePreviewText(event.payload.message);
8704
- if (!text || event.payload.message.role !== "user") return null;
8705
- return createProjection(readSessionId(event.payload.sessionId), {
8706
- state: "running",
8707
- statusText: text,
8708
- timestamp: event.payload.message.timestamp || timestamp
8709
- });
8710
- }
8711
- case NcpEventType.MessageCompleted: {
8712
- const text = readMessagePreviewText(event.payload.message);
8713
- if (!text || event.payload.message.role !== "assistant") return null;
8714
- return createProjection(readSessionId(event.payload.sessionId), {
8715
- state: "completed",
8716
- replyText: text,
8717
- timestamp: event.payload.message.timestamp || timestamp
8718
- });
8719
- }
8720
- case NcpEventType.MessageFailed: return createProjection(readSessionId(event.payload.sessionId), {
8721
- state: "failed",
8722
- statusText: formatErrorStatus(event.payload.error),
8723
- timestamp
8724
- });
8725
- case NcpEventType.MessageToolCallStart: return createProjection(readSessionId(event.payload.sessionId), {
8726
- state: "running",
8727
- statusText: `正在调用工具:${event.payload.toolName}`,
8728
- timestamp
8729
- });
8730
- case NcpEventType.MessageToolCallEnd:
8731
- case NcpEventType.MessageToolCallResult: {
8732
- const sessionId = readSessionId(event.payload.sessionId);
8733
- const toolCallId = readToolCallId(event.payload.toolCallId);
8734
- return createProjection(sessionId, {
8735
- state: "running",
8736
- statusText: formatToolDoneStatus(sessionId && toolCallId ? options.readToolName?.(sessionId, toolCallId) ?? null : null),
8737
- timestamp
8738
- });
8739
- }
8740
- default: return null;
8741
- }
8742
- }
8743
- //#endregion
8744
- //#region src/contributions/session-activity-preview/utils/session-activity-preview-metadata.utils.ts
8745
- const SESSION_ACTIVITY_PREVIEW_METADATA_KEY = "last_activity_preview";
8746
- const SESSION_ACTIVITY_PREVIEW_STATES = new Set([
8747
- "running",
8748
- "completed",
8749
- "failed",
8750
- "idle"
8751
- ]);
8752
- function isRecord$3(value) {
8753
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8754
- }
8755
- function readOptionalString$4(value) {
8756
- if (typeof value !== "string") return;
8757
- const trimmed = value.trim();
8758
- return trimmed.length > 0 ? trimmed : void 0;
8759
- }
8760
- function readSessionActivityPreviewMetadata(value) {
8761
- if (!isRecord$3(value)) return null;
8762
- const state = value.state;
8763
- const timestamp = readOptionalString$4(value.timestamp);
8764
- if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
8765
- return {
8766
- state,
8767
- timestamp,
8768
- ...readOptionalString$4(value.statusText) ? { statusText: readOptionalString$4(value.statusText) } : {},
8769
- ...readOptionalString$4(value.replyText) ? { replyText: readOptionalString$4(value.replyText) } : {}
8770
- };
8771
- }
8772
- function compareIsoTimestamp(left, right) {
8773
- const leftTime = Date.parse(left);
8774
- const rightTime = Date.parse(right);
8775
- if (!Number.isFinite(leftTime) || !Number.isFinite(rightTime)) return left.localeCompare(right);
8776
- return leftTime - rightTime;
8777
- }
8778
- function mergeSessionActivityPreview(current, incoming) {
8779
- if (current && compareIsoTimestamp(incoming.timestamp, current.timestamp) < 0) return incoming.replyText && !current.replyText ? {
8780
- ...current,
8781
- replyText: incoming.replyText
8782
- } : current;
8783
- return {
8784
- state: incoming.state,
8785
- timestamp: incoming.timestamp,
8786
- ...incoming.statusText ?? (incoming.state === "completed" ? current?.statusText : void 0) ? { statusText: incoming.statusText ?? current?.statusText } : {},
8787
- ...incoming.replyText ?? current?.replyText ? { replyText: incoming.replyText ?? current?.replyText } : {}
8788
- };
8789
- }
8790
- function areSessionActivityPreviewsEqual(left, right) {
8791
- return Boolean(left) && left?.state === right.state && left.timestamp === right.timestamp && left.statusText === right.statusText && left.replyText === right.replyText;
8792
- }
8793
- function writeSessionActivityPreviewMetadata(metadata, projection) {
8794
- const current = readSessionActivityPreviewMetadata(metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY]);
8795
- const next = mergeSessionActivityPreview(current, projection.preview);
8796
- if (areSessionActivityPreviewsEqual(current, next)) return null;
8797
- return {
8798
- ...metadata ?? {},
8799
- [SESSION_ACTIVITY_PREVIEW_METADATA_KEY]: next
8800
- };
8801
- }
8802
- //#endregion
8803
- //#region src/contributions/session-activity-preview/index.ts
8804
- var SessionActivityPreviewContribution = class {
8805
- unsubscribeNcpEvent = null;
8806
- metadataWriteChains = /* @__PURE__ */ new Map();
8807
- toolNames = /* @__PURE__ */ new Map();
8808
- constructor(kernel) {
8809
- this.kernel = kernel;
8810
- }
8811
- start = () => {
8812
- if (this.unsubscribeNcpEvent) return;
8813
- this.unsubscribeNcpEvent = this.kernel.eventBus.on(eventKeys.ncpEvent, (event) => {
8814
- this.rememberToolName(event);
8815
- const projection = createSessionActivityPreviewFromNcpEvent(event, (/* @__PURE__ */ new Date()).toISOString(), { readToolName: this.readToolName });
8816
- this.clearFinishedRunToolNames(event);
8817
- if (!projection) return;
8818
- this.updatePreview(projection);
8819
- });
8820
- };
8821
- dispose = () => {
8822
- this.unsubscribeNcpEvent?.();
8823
- this.unsubscribeNcpEvent = null;
8824
- this.metadataWriteChains.clear();
8825
- this.toolNames.clear();
8826
- };
8827
- rememberToolName = (event) => {
8828
- if (event.type !== NcpEventType.MessageToolCallStart) return;
8829
- const sessionId = event.payload.sessionId.trim();
8830
- const toolCallId = event.payload.toolCallId.trim();
8831
- const toolName = event.payload.toolName.trim();
8832
- if (!sessionId || !toolCallId || !toolName) return;
8833
- this.toolNames.set(this.createToolNameKey(sessionId, toolCallId), toolName);
8834
- };
8835
- readToolName = (sessionId, toolCallId) => this.toolNames.get(this.createToolNameKey(sessionId, toolCallId)) ?? null;
8836
- clearFinishedRunToolNames = (event) => {
8837
- if (event.type !== NcpEventType.RunFinished && event.type !== NcpEventType.RunError) return;
8838
- const sessionId = this.readNonEmptyString(event.payload.sessionId);
8839
- if (!sessionId) return;
8840
- for (const key of this.toolNames.keys()) if (key.startsWith(`${sessionId}:`)) this.toolNames.delete(key);
8841
- };
8842
- readNonEmptyString = (value) => {
8843
- if (typeof value !== "string") return null;
8844
- const trimmed = value.trim();
8845
- return trimmed.length > 0 ? trimmed : null;
8846
- };
8847
- createToolNameKey = (sessionId, toolCallId) => `${sessionId}:${toolCallId}`;
8848
- updatePreview = (projection) => {
8849
- const next = (this.metadataWriteChains.get(projection.sessionId) ?? Promise.resolve()).then(() => this.updatePreviewMetadata(projection));
8850
- this.metadataWriteChains.set(projection.sessionId, next.catch(() => void 0));
8851
- next.catch((error) => {
8852
- const message = error instanceof Error ? error.stack ?? error.message : String(error);
8853
- console.error(`[session-activity-preview] failed to update ${projection.sessionId}: ${message}`);
8854
- });
8855
- };
8856
- updatePreviewMetadata = async (projection) => {
8857
- const nextMetadata = writeSessionActivityPreviewMetadata((await this.kernel.sessionManager.getSessionRecord(projection.sessionId))?.metadata, projection);
8858
- if (!nextMetadata) return;
8859
- await this.kernel.sessionManager.updateSessionMetadata(projection.sessionId, nextMetadata);
8860
- };
8861
- };
8862
- //#endregion
8863
9131
  //#region src/contributions/tool-provider/providers/asset-tool.provider.ts
8864
9132
  var AssetToolProvider = class {
8865
9133
  constructor(assetStore) {
@@ -9402,6 +9670,12 @@ function readPurpose(value) {
9402
9670
  if (normalized === "read" || normalized === "preview" || normalized === "edit" || normalized === "interact") return normalized;
9403
9671
  throw new Error("purpose must be \"read\", \"preview\", \"edit\", or \"interact\".");
9404
9672
  }
9673
+ function readPlacement(value) {
9674
+ const normalized = readOptionalString$1(value);
9675
+ if (!normalized) return;
9676
+ if (normalized === "inline" || normalized === "side_panel") return normalized;
9677
+ throw new Error("placement must be \"inline\" or \"side_panel\".");
9678
+ }
9405
9679
  function readPayload(params) {
9406
9680
  if (!isRecord$1(params.payload)) throw new Error("payload must be an object.");
9407
9681
  return params.payload;
@@ -9423,6 +9697,7 @@ function normalizeShowContentArgs(args) {
9423
9697
  const payload = readPayload(params);
9424
9698
  const title = readOptionalString$1(params.title);
9425
9699
  const purpose = readPurpose(params.purpose);
9700
+ const placement = readPlacement(params.placement);
9426
9701
  if (type === "file") return {
9427
9702
  target: {
9428
9703
  type,
@@ -9433,7 +9708,8 @@ function normalizeShowContentArgs(args) {
9433
9708
  }
9434
9709
  },
9435
9710
  title,
9436
- purpose
9711
+ purpose,
9712
+ placement
9437
9713
  };
9438
9714
  if (type === "url") return {
9439
9715
  target: {
@@ -9441,7 +9717,8 @@ function normalizeShowContentArgs(args) {
9441
9717
  payload: { url: readUrl(payload.url) }
9442
9718
  },
9443
9719
  title,
9444
- purpose
9720
+ purpose,
9721
+ placement
9445
9722
  };
9446
9723
  if (type === "panel_app") return {
9447
9724
  target: {
@@ -9449,7 +9726,8 @@ function normalizeShowContentArgs(args) {
9449
9726
  payload: { appId: readRequiredString(payload.appId, "payload.appId") }
9450
9727
  },
9451
9728
  title,
9452
- purpose
9729
+ purpose,
9730
+ placement
9453
9731
  };
9454
9732
  throw new Error("type must be \"file\", \"url\", or \"panel_app\".");
9455
9733
  }
@@ -9465,12 +9743,19 @@ function createShowContentEventPayload(request, context) {
9465
9743
  toolCallId,
9466
9744
  target: request.target,
9467
9745
  title: request.title,
9468
- purpose: request.purpose
9746
+ purpose: request.purpose,
9747
+ placement: request.placement
9469
9748
  };
9470
9749
  }
9471
9750
  var ShowContentTool = class {
9472
9751
  name = SHOW_CONTENT_TOOL_NAME;
9473
- description = "Show file, URL, or panel app content in the current chat UI.";
9752
+ description = [
9753
+ "Show file, URL, or panel app content in the current chat UI.",
9754
+ "placement=\"inline\" embeds a lightweight panel_app as an interactive chat card so the user can try it directly in the conversation.",
9755
+ "placement=\"side_panel\" opens content in the right side panel for larger reading, editing, or sustained workflows.",
9756
+ "Choose the placement yourself: after creating a lightweight Panel App such as a weather card, calculator, timer, checklist, picker, form, preview, or small dashboard, call this tool with placement=\"inline\" without waiting for the user to ask to see it.",
9757
+ "Omit placement only when preserving the existing default side panel behavior is intentional."
9758
+ ].join(" ");
9474
9759
  parameters = {
9475
9760
  type: "object",
9476
9761
  properties: {
@@ -9497,6 +9782,11 @@ var ShowContentTool = class {
9497
9782
  ],
9498
9783
  description: "Optional user intent for the content."
9499
9784
  },
9785
+ placement: {
9786
+ type: "string",
9787
+ enum: ["inline", "side_panel"],
9788
+ description: "Optional display placement. \"inline\" embeds a lightweight panel app as an interactive chat card; \"side_panel\" opens it in the right panel for larger workflows. Choose the appropriate placement yourself; defaults to the existing side panel behavior when omitted."
9789
+ },
9500
9790
  payload: {
9501
9791
  type: "object",
9502
9792
  description: "Type-specific fields: file={path,line,column}; url={url}; panel_app={appId}.",
@@ -9622,6 +9912,11 @@ function resolveKernelAutomationStorePath(options) {
9622
9912
  if (homeDir) return resolve(expandHome(homeDir), "cron", "jobs.json");
9623
9913
  return resolve(getDataDir(), "cron", "jobs.json");
9624
9914
  }
9915
+ function resolveKernelPreferenceStorePath(options) {
9916
+ const homeDir = options.homeDir?.trim();
9917
+ if (homeDir) return resolve(expandHome(homeDir), "preferences", "preferences.json");
9918
+ return resolve(getDataDir(), "preferences", "preferences.json");
9919
+ }
9625
9920
  var NextclawKernelControlManager = class {
9626
9921
  runtimeControl = null;
9627
9922
  installRuntimeControl = (runtimeControl) => {
@@ -9651,6 +9946,7 @@ var NextclawKernel = class {
9651
9946
  mcpManager;
9652
9947
  sessionManager;
9653
9948
  panelAppManager;
9949
+ preferenceManager;
9654
9950
  serviceAppManager;
9655
9951
  extensions;
9656
9952
  agentRuntimeManager = new AgentRuntimeManager();
@@ -9695,6 +9991,7 @@ var NextclawKernel = class {
9695
9991
  eventBus: this.eventBus,
9696
9992
  ingress: this.ingress
9697
9993
  });
9994
+ this.preferenceManager = new PreferenceManager({ storePath: resolveKernelPreferenceStorePath(options) });
9698
9995
  this.serviceAppManager = new ServiceAppManager({ configManager: this.configManager });
9699
9996
  this.extensions = new ExtensionManager({
9700
9997
  configManager: this.configManager,
@@ -9722,7 +10019,6 @@ var NextclawKernel = class {
9722
10019
  this.agentRunRequestManager = new AgentRunRequestManager(this.agentRuntimeManager, this.agents, this.configManager, this.contextProviderManager, this.eventBus, this.ingress, this.sessionManager, this.sessionRunManager, this.toolProviderManager);
9723
10020
  this.contributions = [
9724
10021
  new ToolProviderContribution(this),
9725
- new SessionActivityPreviewContribution(this),
9726
10022
  new LearningLoopContribution(this),
9727
10023
  new ContextProviderContribution(this),
9728
10024
  new AgentRunRuntimeContribution(this),
@@ -10359,6 +10655,6 @@ function resolveLegacyEventType(message) {
10359
10655
  return `message.${role || "other"}`;
10360
10656
  }
10361
10657
  //#endregion
10362
- export { AccessManager, AgentManager, AgentRunClient, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppAssetTokenService, PanelAppError, PanelAppManager, ProviderManagerNcpLLMApi, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionModelInput, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildNextclawNcpRunContext, buildServiceActionId, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, describeAgentRuntimeSessionTypes, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, waitForAgentRuntimeSessionReply };
10658
+ export { AccessManager, AgentManager, AgentRunClient, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_TIMELINE_KIND, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionPreflightService, ContextWindowPreviewManager, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, ExtensionManager, GatewayInboundProcessor, LlmProviderManager, LlmUsageManager, LlmUsageStore, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawKernel, PANEL_APP_AGENT_CAPABILITIES, PanelAppAssetTokenService, PanelAppError, PanelAppManager, PreferenceError, PreferenceManager, ProviderManagerNcpLLMApi, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppError, ServiceAppManager, SessionManager, SessionRequestManager, SkillManager, UpdateManifestReader, buildAgentRunSendPayload, buildContextCompactionModelInput, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildNextclawNcpRunContext, buildServiceActionId, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, describeAgentRuntimeSessionTypes, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isPreferenceError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, waitForAgentRuntimeSessionReply };
10363
10659
 
10364
10660
  //# sourceMappingURL=index.js.map