@nextclaw/kernel 0.4.1-beta.0 → 0.4.2

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,7 +1,7 @@
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
3
  import { NcpEventType, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
4
- import { AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, ConfigSchema, ContextBuilder, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, EditFileTool, ExecTool, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SessionSearchManager, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, summarizeSessionRequestTask, toDisposable, toExtensionConfigView } from "@nextclaw/core";
4
+ import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ChannelManager, ChannelManager as ChannelManager$1, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, EditFileTool, ExecTool, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderRegistry, ReadFileTool, RequestedSkillsMetadataReader, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchManager, SkillsLoader, THINKING_LEVELS, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, expandHome, findEffectiveAgentProfile, getConfigPath, getDataDir, getDataPath, getSessionsPath, getWorkspacePath, getWorkspacePathFromConfig, loadConfig, mergeExtensionConfigView, modelSupportsVision, normalizeInlineSecretRefs, normalizeProviderModelConfig, normalizeToolParams, parseAgentScopedSessionKey, parseThinkingLevel, readCompressedContextCompactionCheckpoint, readOptionalString, readParentSessionId, readSessionProjectRoot, redactConfigObject, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveNextclawSelfManageGuidePaths, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, summarizeSessionRequestTask, toDisposable, toExtensionConfigView } from "@nextclaw/core";
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 } from "@nextclaw/shared";
@@ -3270,13 +3270,7 @@ function readMessageFromSummaryEvent(event) {
3270
3270
  if (event.type === NcpEventType.MessageSent || event.type === NcpEventType.MessageCompleted || event.type === "session.snapshot.message") return event.payload.message;
3271
3271
  }
3272
3272
  //#endregion
3273
- //#region src/managers/session.manager.ts
3274
- const DEFAULT_SESSION_TYPE = "native";
3275
- const DEFAULT_LIFECYCLE = "persistent";
3276
- const SESSION_METADATA_LABEL_KEY = "label";
3277
- const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3278
- const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3279
- const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3273
+ //#region src/utils/session-manager.utils.ts
3280
3274
  function normalizeSessionId(sessionId) {
3281
3275
  return sessionId.trim();
3282
3276
  }
@@ -3295,6 +3289,37 @@ function readOptionalMetadataString(value) {
3295
3289
  function readEventSessionId$1(event) {
3296
3290
  return "payload" in event && "sessionId" in event.payload ? readOptionalMetadataString(event.payload.sessionId) : void 0;
3297
3291
  }
3292
+ //#endregion
3293
+ //#region src/services/session-working-dir-resolver.service.ts
3294
+ var SessionWorkingDirResolver = class {
3295
+ constructor(configManager) {
3296
+ this.configManager = configManager;
3297
+ }
3298
+ withWorkingDir = (summary) => ({
3299
+ ...summary,
3300
+ workingDir: this.resolve({
3301
+ agentId: summary.agentId,
3302
+ metadata: summary.metadata
3303
+ })
3304
+ });
3305
+ resolve = (params) => {
3306
+ const config = this.configManager.loadConfig();
3307
+ const defaultAgentId = resolveDefaultAgentProfileId(config);
3308
+ const profile = findEffectiveAgentProfile(config, readOptionalString$7(params.agentId) ?? defaultAgentId) ?? findEffectiveAgentProfile(config, defaultAgentId);
3309
+ return resolveSessionWorkspacePath({
3310
+ sessionMetadata: params.metadata,
3311
+ workspace: profile?.workspace ?? config.agents.defaults.workspace
3312
+ });
3313
+ };
3314
+ };
3315
+ //#endregion
3316
+ //#region src/managers/session.manager.ts
3317
+ const DEFAULT_SESSION_TYPE = "native";
3318
+ const DEFAULT_LIFECYCLE = "persistent";
3319
+ const SESSION_METADATA_LABEL_KEY = "label";
3320
+ const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
3321
+ const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
3322
+ const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
3298
3323
  function isDurableSessionEvent(event) {
3299
3324
  return event.type !== NcpEventType.ContextWindowUpdated;
3300
3325
  }
@@ -3368,10 +3393,12 @@ function isSessionSummaryRefreshEvent(event) {
3368
3393
  var SessionManager = class {
3369
3394
  cleanups = [];
3370
3395
  contextWindowPreview;
3396
+ workingDirResolver;
3371
3397
  started = false;
3372
3398
  constructor(options) {
3373
3399
  this.options = options;
3374
3400
  this.contextWindowPreview = new ContextWindowPreviewManager({ configManager: options.configManager });
3401
+ this.workingDirResolver = new SessionWorkingDirResolver(options.configManager);
3375
3402
  }
3376
3403
  start = () => {
3377
3404
  if (this.started) return;
@@ -3489,7 +3516,7 @@ var SessionManager = class {
3489
3516
  };
3490
3517
  listSessions = async (options) => {
3491
3518
  const peerId = readOptionalString$7(options?.peerId);
3492
- return applyLimit((await this.options.journalStore.listSessionSummaries()).filter((summary) => !peerId || summary.peerId === peerId), options?.limit);
3519
+ return applyLimit((await this.options.journalStore.listSessionSummaries()).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), options?.limit);
3493
3520
  };
3494
3521
  listSessionMessages = async (sessionId, options) => {
3495
3522
  const normalizedSessionId = normalizeSessionId(sessionId);
@@ -3598,7 +3625,7 @@ var SessionManager = class {
3598
3625
  this.options.eventBus.emit(eventKeys.sessionSummaryDelete, { sessionKey: normalizedSessionKey });
3599
3626
  };
3600
3627
  createSummaryFromRecord = (record, includeContextWindow = false) => {
3601
- const summary = createNcpAgentSessionSummary(record);
3628
+ const summary = this.workingDirResolver.withWorkingDir(createNcpAgentSessionSummary(record));
3602
3629
  const contextWindow = includeContextWindow ? this.contextWindowPreview.preview({
3603
3630
  requestMetadata: record.metadata ?? {},
3604
3631
  sessionId: record.sessionId,
@@ -6995,7 +7022,7 @@ var BuiltinNarpRuntimeProviderService = class {
6995
7022
  };
6996
7023
  //#endregion
6997
7024
  //#region src/features/native-runtime/services/provider-manager-ncp-llm-api.service.ts
6998
- function normalizeModel(value) {
7025
+ function normalizeModel$1(value) {
6999
7026
  if (typeof value !== "string") return null;
7000
7027
  const trimmed = value.trim();
7001
7028
  return trimmed.length > 0 ? trimmed : null;
@@ -7037,7 +7064,7 @@ var ProviderManagerNcpLLMApi = class {
7037
7064
  this.providerManager = providerManager;
7038
7065
  }
7039
7066
  generate = async function* (input, options) {
7040
- const model = normalizeModel(input.model) ?? this.providerManager.get(null).getDefaultModel();
7067
+ const model = normalizeModel$1(input.model) ?? this.providerManager.get(null).getDefaultModel();
7041
7068
  const thinkingLevel = normalizeThinkingLevel(input.thinkingLevel);
7042
7069
  let sawTextDelta = false;
7043
7070
  let sawReasoningDelta = false;
@@ -7351,19 +7378,6 @@ function mergeRunMetadata(params) {
7351
7378
  ...requestMetadata ? structuredClone(requestMetadata) : {}
7352
7379
  };
7353
7380
  }
7354
- function buildSessionOrchestrationSection() {
7355
- return [
7356
- "## Session Orchestration",
7357
- "- Before passing a non-default `runtime` to `sessions_spawn` or agent creation/update flows, inspect the installed runtime kinds with `nextclaw agents runtimes --json`.",
7358
- "- `sessions_spawn` is the unified session-creation tool. Omit `scope` or use `scope=\"standalone\"` for a regular session, and use `scope=\"child\"` when the new session should be a child session of the current flow.",
7359
- "- `sessions_spawn` only creates the session by default. Add top-level `notify: \"none\" | \"final_reply\"` when the new session should start working immediately.",
7360
- "- When `sessions_spawn.scope=\"child\"` and `sessions_spawn.notify=\"final_reply\"`, the new child session starts right away and this session automatically continues after that child reaches its final reply.",
7361
- "- Use `sessions_spawn` without `notify` when the user wants a separate thread created now but does not need it to start working yet.",
7362
- "- Use `sessions_request` to send one task to an existing session, including a session that was just created by `sessions_spawn` or a previously created child session.",
7363
- "- `sessions_request.target` must be an object shaped like `{ \"session_id\": \"<target-session-id>\" }`. Do not pass a bare string.",
7364
- "- Prefer `notify=\"final_reply\"` when the current session should continue after the target session produces its final reply. Use `notify=\"none\"` when you only want the target session to run independently."
7365
- ].join("\n");
7366
- }
7367
7381
  function resolveNextclawNcpRunContext(params) {
7368
7382
  const { configManager, requestMetadata: inputRequestMetadata, sessionId, sessionMetadata: inputSessionMetadata, storedAgentId } = params;
7369
7383
  const config = configManager.loadConfig();
@@ -7829,6 +7843,454 @@ var AgentRunRuntimeContribution = class {
7829
7843
  });
7830
7844
  };
7831
7845
  //#endregion
7846
+ //#region src/contributions/context-provider/utils/context-text.utils.ts
7847
+ function truncateContextText(text, limit) {
7848
+ if (limit <= 0 || text.length <= limit) return text;
7849
+ const suffix = `\n\n...[truncated ${text.length - limit} chars]`;
7850
+ if (suffix.length >= limit) return text.slice(0, limit).trimEnd();
7851
+ return `${text.slice(0, limit - suffix.length).trimEnd()}${suffix}`;
7852
+ }
7853
+ //#endregion
7854
+ //#region src/contributions/context-provider/providers/agent-bootstrap-context.provider.ts
7855
+ var AgentBootstrapContextProvider = class {
7856
+ constructor(context) {
7857
+ this.context = context;
7858
+ }
7859
+ provide = async (request) => {
7860
+ const { contextConfig, projectContext, runContext } = await this.context.resolve(request);
7861
+ const budget = this.createReadBudget(contextConfig.bootstrap);
7862
+ const agentBootstrapRoot = projectContext.projectBootstrapRoot ?? projectContext.effectiveWorkspace;
7863
+ const projectBootstrap = this.loadBootstrapFiles({
7864
+ root: agentBootstrapRoot,
7865
+ config: contextConfig.bootstrap,
7866
+ sessionKey: runContext.sessionKey,
7867
+ budget
7868
+ });
7869
+ const hasDistinctHostWorkspace = projectContext.hostWorkspace !== agentBootstrapRoot;
7870
+ const workspaceBootstrap = hasDistinctHostWorkspace ? this.loadBootstrapFiles({
7871
+ root: projectContext.hostWorkspace,
7872
+ config: contextConfig.bootstrap,
7873
+ sessionKey: runContext.sessionKey,
7874
+ budget
7875
+ }) : "";
7876
+ const hasSoulFile = /##\s+SOUL\.md\b/i.test(`${projectBootstrap}\n${workspaceBootstrap}`);
7877
+ const sections = [this.buildBootstrapSection({
7878
+ content: projectBootstrap,
7879
+ emptyLabel: "No agent bootstrap files were found.",
7880
+ includeSoulRule: hasSoulFile,
7881
+ loadedLabel: "Agent bootstrap files loaded:",
7882
+ rootLine: `Agent bootstrap root: ${agentBootstrapRoot}`,
7883
+ title: "# Agent Bootstrap Context"
7884
+ })];
7885
+ if (hasDistinctHostWorkspace) sections.push(this.buildBootstrapSection({
7886
+ content: workspaceBootstrap,
7887
+ emptyLabel: "No bootstrap files were found in the NextClaw workspace directory.",
7888
+ loadedLabel: "NextClaw workspace bootstrap files loaded:",
7889
+ rootLine: `NextClaw workspace directory: ${projectContext.hostWorkspace}`,
7890
+ title: "# NextClaw Workspace Bootstrap Context"
7891
+ }));
7892
+ return [sections.filter(Boolean).join("\n\n")];
7893
+ };
7894
+ buildBootstrapSection = (params) => {
7895
+ const { content, emptyLabel, includeSoulRule, loadedLabel, rootLine, title } = params;
7896
+ const lines = [
7897
+ title,
7898
+ "",
7899
+ rootLine
7900
+ ];
7901
+ if (includeSoulRule) lines.push("If SOUL.md is present, embody its persona and tone unless higher-priority instructions override it.");
7902
+ if (content) lines.push("", loadedLabel, "", content);
7903
+ else lines.push("", emptyLabel);
7904
+ return lines.join("\n");
7905
+ };
7906
+ loadBootstrapFiles = (params) => {
7907
+ const { budget, config, root, sessionKey } = params;
7908
+ const parts = [];
7909
+ const fileList = this.selectBootstrapFiles(config, sessionKey);
7910
+ for (const filename of fileList) {
7911
+ const filePath = join(root, filename);
7912
+ if (!existsSync(filePath)) continue;
7913
+ const raw = readFileSync(filePath, "utf-8").trim();
7914
+ if (!raw) continue;
7915
+ const perFileLimit = config.perFileChars > 0 ? config.perFileChars : raw.length;
7916
+ const allowed = Math.min(perFileLimit, budget.remaining);
7917
+ if (allowed <= 0) break;
7918
+ const content = truncateContextText(raw, allowed);
7919
+ parts.push(`## ${filename}\n\n${content}`);
7920
+ budget.remaining -= content.length;
7921
+ if (budget.remaining <= 0) break;
7922
+ }
7923
+ return parts.join("\n\n");
7924
+ };
7925
+ createReadBudget = (config) => ({ remaining: config.totalChars > 0 ? config.totalChars : Number.POSITIVE_INFINITY });
7926
+ selectBootstrapFiles = (config, sessionKey) => {
7927
+ if (!sessionKey) return config.files;
7928
+ if (sessionKey.startsWith("cron:") || sessionKey.startsWith("subagent:")) return config.minimalFiles;
7929
+ return config.files;
7930
+ };
7931
+ };
7932
+ //#endregion
7933
+ //#region src/contributions/context-provider/providers/current-session-context.provider.ts
7934
+ var CurrentSessionContextProvider = class {
7935
+ constructor(context) {
7936
+ this.context = context;
7937
+ }
7938
+ provide = async (request) => {
7939
+ const { runContext } = await this.context.resolve(request);
7940
+ const lines = [
7941
+ "## Current Session",
7942
+ `Channel: ${runContext.channel}`,
7943
+ `Chat ID: ${runContext.chatId}`,
7944
+ `Session: ${runContext.sessionKey}`
7945
+ ];
7946
+ if (runContext.runtimeThinking) lines.push(`Thinking policy: ${runContext.runtimeThinking}`);
7947
+ return [lines.join("\n")];
7948
+ };
7949
+ };
7950
+ //#endregion
7951
+ //#region src/contributions/context-provider/providers/execution-policy-context.provider.ts
7952
+ function normalizeModel(model) {
7953
+ return model?.trim().toLowerCase() ?? "";
7954
+ }
7955
+ function isOpenAiOrCodexModel(model) {
7956
+ return /(gpt[-/ ]?5|gpt[-/ ]?4|gpt\b|chatgpt|openai|codex|\bo[134]\b)/i.test(normalizeModel(model));
7957
+ }
7958
+ function isGoogleModel(model) {
7959
+ return /(gemini|google)/i.test(normalizeModel(model));
7960
+ }
7961
+ function buildSection(title, lines) {
7962
+ return [title, ...lines].join("\n");
7963
+ }
7964
+ const TOOL_USE_ENFORCEMENT_LINES = [
7965
+ "- When you say you will inspect, run, read, search, edit, or verify something, call the matching tool in the same turn.",
7966
+ "- Do not stop at promises like 'I'll check' or 'I will do that' unless the tool call already happened in that turn.",
7967
+ "- If the task can still move forward with available tools, continue instead of ending early."
7968
+ ];
7969
+ const OPENAI_CODEX_DISCIPLINE_LINES = [
7970
+ "- Do not guess time, date, system state, file contents, git state, or other current facts. Check with tools first.",
7971
+ "- When the default scope is already clear, act on it before asking an avoidable clarification question.",
7972
+ "- If the first tool result is empty or incomplete, retry once with a different strategy before stopping."
7973
+ ];
7974
+ const GOOGLE_MODEL_GUIDANCE_LINES = [
7975
+ "- Batch independent reads when possible.",
7976
+ "- Read the surrounding context before editing files.",
7977
+ "- Use explicit file paths and keep the answer focused on results."
7978
+ ];
7979
+ function renderSystemExecutionPolicy(model) {
7980
+ const sections = [buildSection("## Tool Use Enforcement", TOOL_USE_ENFORCEMENT_LINES)];
7981
+ if (isOpenAiOrCodexModel(model)) sections.push(buildSection("## OpenAI/Codex Execution Discipline", OPENAI_CODEX_DISCIPLINE_LINES));
7982
+ else if (isGoogleModel(model)) sections.push(buildSection("## Google Model Operational Guidance", GOOGLE_MODEL_GUIDANCE_LINES));
7983
+ return sections.join("\n\n");
7984
+ }
7985
+ var ExecutionPolicyContextProvider = class {
7986
+ constructor(context) {
7987
+ this.context = context;
7988
+ }
7989
+ provide = async (request) => {
7990
+ const { runContext } = await this.context.resolve(request);
7991
+ return [renderSystemExecutionPolicy(runContext.effectiveModel)];
7992
+ };
7993
+ };
7994
+ //#endregion
7995
+ //#region src/contributions/context-provider/providers/native-static-context.provider.ts
7996
+ const block = (lines) => lines.join("\n");
7997
+ const staticProvider = (contextBlock) => ({ provide: () => [contextBlock] });
7998
+ const staticBlock = (lines) => staticProvider(block(lines));
7999
+ const createAssistantIdentityContextProvider = () => staticProvider(`You are a personal assistant running inside ${APP_NAME}.`);
8000
+ const createToolCallStyleContextProvider = () => staticBlock([
8001
+ "## Tool Call Style",
8002
+ "Default: do not narrate routine, low-risk tool calls (just call the tool).",
8003
+ "Narrate only when it helps: multi-step work, complex/challenging problems, sensitive actions (e.g., deletions), or when the user explicitly asks.",
8004
+ "Keep narration brief and value-dense; avoid repeating obvious steps.",
8005
+ "Use plain human language for narration unless in a technical context."
8006
+ ]);
8007
+ const createChatComposerTokensContextProvider = () => staticBlock([
8008
+ "## Chat Composer Tokens",
8009
+ "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.",
8010
+ "These tokens can appear inline with normal prose. Do not ignore them or reinterpret them as shell variables or currency unless the surrounding context clearly says otherwise."
8011
+ ]);
8012
+ const createSafetyContextProvider = () => staticBlock([
8013
+ "## Safety",
8014
+ "You have no independent goals: do not pursue self-preservation, replication, resource acquisition, or power-seeking; avoid long-term plans beyond the user's request.",
8015
+ "Prioritize safety and human oversight over completion; if instructions conflict, pause and ask; comply with stop/pause/audit requests and never bypass safeguards. (Inspired by Anthropic's constitution.)",
8016
+ "Do not manipulate or persuade anyone to expand access or disable safeguards. Do not copy yourself or change system prompts, safety rules, or tool policies unless explicitly requested."
8017
+ ]);
8018
+ const createCliQuickReferenceContextProvider = () => {
8019
+ const appLower = APP_NAME.toLowerCase();
8020
+ return staticBlock([
8021
+ `## ${APP_NAME} CLI Quick Reference`,
8022
+ `${APP_NAME} is controlled via subcommands. Do not invent commands.`,
8023
+ "To manage the Gateway daemon service (start/stop/restart):",
8024
+ `- ${appLower} gateway status`,
8025
+ `- ${appLower} gateway start`,
8026
+ `- ${appLower} gateway stop`,
8027
+ `- ${appLower} gateway restart`,
8028
+ `If unsure, ask the user to run \`${appLower} help\` (or \`${appLower} gateway --help\`) and paste the output.`
8029
+ ]);
8030
+ };
8031
+ const createSelfUpdateContextProvider = () => staticBlock([
8032
+ `## ${APP_NAME} Self-Update`,
8033
+ "Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
8034
+ "Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
8035
+ "Actions: config.get, config.schema, config.apply (validate + write full config, then restart), config.patch (merge + restart), update.run (update deps or git, then restart).",
8036
+ "When patching config, copy enum values exactly from config.schema; never invent new variants.",
8037
+ "session.dmScope legal values are exactly: main | per-peer | per-channel-peer | per-account-channel-peer.",
8038
+ "If an enum/path is uncertain, stop and call config.schema first; do not guess.",
8039
+ `After restart, ${APP_NAME} pings the last active session automatically.`
8040
+ ]);
8041
+ const createReplyTagsContextProvider = () => staticBlock([
8042
+ "## Reply Tags",
8043
+ "To request a native reply/quote on supported surfaces, include one tag in your reply:",
8044
+ "- Reply tags must be the very first token in the message (no leading text/newlines): [[reply_to_current]] your reply.",
8045
+ "- [[reply_to_current]] replies to the triggering message.",
8046
+ "- Prefer [[reply_to_current]]. Use [[reply_to:<id>]] only when an id was explicitly provided (e.g. by the user or a tool).",
8047
+ "Whitespace inside the tag is allowed (e.g. [[ reply_to_current ]] / [[ reply_to: 123 ]]).",
8048
+ "Tags are stripped before sending; support depends on the current channel config."
8049
+ ]);
8050
+ const createMessagingContextProvider = () => staticBlock([
8051
+ "## Messaging",
8052
+ "- Reply in current session → automatically routes to the source channel (Signal, Telegram, etc.)",
8053
+ "- Cross-session or cross-channel messaging → use message(action=send); use sessions_list first when you need to recover an existing route without guessing.",
8054
+ "- Sub-agent orchestration → use subagents(action=list|steer|kill)",
8055
+ "- `[System Message] ...` blocks are internal context and are not user-visible by default.",
8056
+ "- If a `[System Message]` reports completed cron/subagent work and asks for a user update, rewrite it in your normal assistant voice and send that update (do not forward raw system text or default to <noreply/>).",
8057
+ `- Never use exec/curl for provider messaging; ${APP_NAME} handles all routing internally.`,
8058
+ "",
8059
+ "### message tool",
8060
+ "- Use `message` for proactive sends + channel actions (polls, reactions, etc.).",
8061
+ "- For `action=send`, include `message` plus an explicit `to/chatId` whenever the destination is another channel or another conversation.",
8062
+ "- Omitting `to/chatId` only replies to the current conversation; if you set `channel` to a different channel than the current session, `to/chatId` is required.",
8063
+ "- If multiple channels are configured, pass `channel`.",
8064
+ "- If you use `message` (`action=send`) to deliver your user-visible reply, respond with ONLY two blank lines + <noreply/> (avoid duplicate replies)."
8065
+ ]);
8066
+ const createMemoryRecallContextProvider = () => staticBlock([
8067
+ "## Memory Recall",
8068
+ "Before answering anything about prior work, decisions, dates, people, preferences, or todos: run memory_search on MEMORY.md + memory/*.md; then use memory_get to pull only the needed lines. If low confidence after search, say you checked.",
8069
+ "Citations: include Source: <path#line> when it helps the user verify memory snippets."
8070
+ ]);
8071
+ const createSilentRepliesContextProvider = () => staticBlock([
8072
+ "## Silent Replies",
8073
+ `Silent marker token: ${SILENT_REPLY_TOKEN}`,
8074
+ "When you have nothing to say, respond with EXACTLY two blank lines followed by <noreply/>",
8075
+ "",
8076
+ "⚠️ Rules:",
8077
+ "- It must be your ENTIRE message — nothing else",
8078
+ "- If <noreply/> appears anywhere, the system will stop reply/output and subsequent processing",
8079
+ "- Never wrap it in markdown or code blocks",
8080
+ "",
8081
+ "❌ Wrong: \"Here's help... <noreply/>\"",
8082
+ "❌ Wrong: \"<noreply/>\"",
8083
+ "✅ Right: \"\\n\\n<noreply/>\""
8084
+ ]);
8085
+ const createRuntimeContextProvider = () => staticBlock([
8086
+ "## Runtime",
8087
+ `Runtime: ${process.platform} ${process.arch}, Node ${process.version}`,
8088
+ "Time handling: do not assume exact minute/second unless the user/tool explicitly provides it.",
8089
+ "When a turn includes a time hint, treat it as context for relative-time interpretation in that turn."
8090
+ ]);
8091
+ const createSelfManagementContextProvider = () => ({ provide: () => {
8092
+ const appLower = APP_NAME.toLowerCase();
8093
+ const selfManageGuide = resolveNextclawSelfManageGuidePaths();
8094
+ return [block([
8095
+ `## ${APP_NAME} Self-Management Guide`,
8096
+ `- For ${APP_NAME} self-management operations (version/status/doctor/service/channels/config/agents/cron/remote/update), read \`${selfManageGuide.primaryPath ?? "the built-in NextClaw self-management guide"}\` first.`,
8097
+ "- Treat these product-management intents as higher priority than generic skills with overlapping words such as create/install/publish.",
8098
+ "- Do not load unrelated generic skills before reading the built-in self-management guide for a self-management intent.",
8099
+ "- Workspace `USAGE.md` snapshots and copied built-in skills are deprecated artifacts; the built-in package guide is the source of truth.",
8100
+ ...selfManageGuide.repoDocsPath ? [`- In repo source checkouts, the authoring copy is \`${selfManageGuide.repoDocsPath}\`; only use it when the packaged guide path above is unavailable.`] : [],
8101
+ "- If no guide file is available, fall back to command help output.",
8102
+ `- For version lookup, use \`${appLower} --version\` exactly; do not infer version from status output.`,
8103
+ `- After mutating operations, validate with \`${appLower} status --json\` (and \`${appLower} doctor --json\` when needed).`,
8104
+ `- For Agent CRUD, use \`${appLower} agents list|new|update|remove --json\` for the normal path; do not directly edit \`config.json\` or \`agents.list\` for routine Agent management.`,
8105
+ "- When creating Agents, prefer explicit non-text avatars and avoid text/initial-based avatar styles such as DiceBear `initials` as the default recommendation."
8106
+ ])];
8107
+ } });
8108
+ const createSessionOrchestrationContextProvider = () => staticBlock([
8109
+ "## Session Orchestration",
8110
+ "- Before passing a non-default `runtime` to `sessions_spawn` or agent creation/update flows, inspect the installed runtime kinds with `nextclaw agents runtimes --json`.",
8111
+ "- `sessions_spawn` is the unified session-creation tool. Omit `scope` or use `scope=\"standalone\"` for a regular session, and use `scope=\"child\"` when the new session should be a child session of the current flow.",
8112
+ "- `sessions_spawn` only creates the session by default. Add top-level `notify: \"none\" | \"final_reply\"` when the new session should start working immediately.",
8113
+ "- When `sessions_spawn.scope=\"child\"` and `sessions_spawn.notify=\"final_reply\"`, the new child session starts right away and this session automatically continues after that child reaches its final reply.",
8114
+ "- Use `sessions_spawn` without `notify` when the user wants a separate thread created now but does not need it to start working yet.",
8115
+ "- Use `sessions_request` to send one task to an existing session, including a session that was just created by `sessions_spawn` or a previously created child session.",
8116
+ "- `sessions_request.target` must be an object shaped like `{ \"session_id\": \"<target-session-id>\" }`. Do not pass a bare string.",
8117
+ "- Prefer `notify=\"final_reply\"` when the current session should continue after the target session produces its final reply. Use `notify=\"none\"` when you only want the target session to run independently."
8118
+ ]);
8119
+ //#endregion
8120
+ //#region src/contributions/context-provider/providers/project-context.provider.ts
8121
+ var ProjectContextProvider = class {
8122
+ constructor(context) {
8123
+ this.context = context;
8124
+ }
8125
+ provide = async (request) => {
8126
+ const { projectContext } = await this.context.resolve(request);
8127
+ const repositoryIdentity = DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER.resolve(projectContext.effectiveWorkspace);
8128
+ return [this.buildProjectSection({
8129
+ projectContext,
8130
+ repositoryIdentity
8131
+ })];
8132
+ };
8133
+ buildProjectSection = (params) => {
8134
+ const { projectContext, repositoryIdentity } = params;
8135
+ const lines = [
8136
+ "# Project Context",
8137
+ "",
8138
+ `Active project directory: ${projectContext.effectiveWorkspace}`
8139
+ ];
8140
+ if (projectContext.projectRoot) lines.push(`Session-bound project root: ${projectContext.projectRoot}`, "This session is explicitly bound to that project directory. Use it as the primary repo and file-operation context for the user's work.");
8141
+ else lines.push("No explicit session project root is set. Use the active project directory as the primary repo and file-operation context for the user's work.");
8142
+ lines.push(...this.buildRepositoryIdentityLines(repositoryIdentity));
8143
+ return lines.join("\n");
8144
+ };
8145
+ buildRepositoryIdentityLines = (repositoryIdentity) => {
8146
+ if (!repositoryIdentity.repoRoot) return ["No Git repository metadata was detected for the active project directory. Do not assume external repository URLs refer to this project unless the user explicitly says so."];
8147
+ const lines = [`Repository root: ${repositoryIdentity.repoRoot}`];
8148
+ if (repositoryIdentity.canonicalWebUrl) lines.push(`Canonical repository: ${repositoryIdentity.canonicalWebUrl}`);
8149
+ else if (repositoryIdentity.canonicalRemoteUrl) {
8150
+ const remoteLabel = repositoryIdentity.canonicalRemoteName ? ` (${repositoryIdentity.canonicalRemoteName})` : "";
8151
+ lines.push(`Canonical git remote${remoteLabel}: ${repositoryIdentity.canonicalRemoteUrl}`);
8152
+ }
8153
+ lines.push("Repository identity rule: treat any other repository URL mentioned in this context as an external reference unless it exactly matches the canonical repository above.");
8154
+ return lines;
8155
+ };
8156
+ };
8157
+ //#endregion
8158
+ //#region src/contributions/context-provider/providers/reply-format-context.provider.ts
8159
+ var ReplyFormatContextProvider = class {
8160
+ provide = (_request) => [[
8161
+ "## Reply Formatting",
8162
+ "- When mentioning a local project file in a user-visible reply, prefer a Markdown link such as `[AGENTS.md](AGENTS.md)` or `[file](packages/example/file.ts)` so the user can open it.",
8163
+ "- Use project-relative links for files under the active/session-bound project root; use absolute links only for files outside it."
8164
+ ].join("\n")];
8165
+ };
8166
+ //#endregion
8167
+ //#region src/contributions/context-provider/providers/skills-context.provider.ts
8168
+ function wrapSkillTag(tagName, manifest) {
8169
+ return [
8170
+ `<${tagName}>`,
8171
+ manifest,
8172
+ `</${tagName}>`
8173
+ ].join("\n");
8174
+ }
8175
+ function renderActiveSkillsSection(skills, skillSelectors) {
8176
+ const manifest = skills.buildSkillsManifest(skillSelectors);
8177
+ if (!manifest) return "";
8178
+ return [
8179
+ "# Active Skills",
8180
+ "These always-on skills are already active for this session context.",
8181
+ "If an active skill covers the user's intent, follow it before considering unrelated available skills.",
8182
+ "For NextClaw self-management intents, read the built-in NextClaw self-management guide before loading any unrelated generic skill.",
8183
+ "Skill refs are unique identities; names may repeat.",
8184
+ "Read a SKILL.md from <location> only when you need its instructions.",
8185
+ "",
8186
+ wrapSkillTag("active_skills", manifest)
8187
+ ].join("\n\n");
8188
+ }
8189
+ function renderAvailableSkillsSection(skills) {
8190
+ const summary = skills.buildSkillsSummary();
8191
+ if (!summary) return "";
8192
+ return [
8193
+ "## Skills (mandatory)",
8194
+ "Always-on skills in <active_skills> take precedence over this list.",
8195
+ "Before replying: first check whether any entry in <available_skills> may be relevant to the user's intent, task type, or requested output. Do not skip this check just because the task seems familiar.",
8196
+ "- If one skill looks like the best relevant match, read its SKILL.md at <location> with `read_file`, then decide whether following it is actually helpful.",
8197
+ "- If a SKILL.md read says `Use offset=... to continue`, continue reading until the relevant trigger, required workflow, constraints, and output requirements are covered.",
8198
+ "- If the user is asking to manage NextClaw itself, read the built-in NextClaw self-management guide first and do not open unrelated generic skills before that.",
8199
+ "- If multiple skills share the same <name>, use <ref> to distinguish them. Never assume duplicate names mean the same skill.",
8200
+ "- If none clearly apply: do not read any SKILL.md.",
8201
+ "Constraints: never read more than one skill up front; only read after selecting.",
8202
+ "",
8203
+ "<available_skills>",
8204
+ summary,
8205
+ "</available_skills>"
8206
+ ].join("\n");
8207
+ }
8208
+ function renderSkillLearningSection() {
8209
+ return [
8210
+ "# Skill Learning Loop",
8211
+ "After non-trivial work, run a brief review before your final answer.",
8212
+ "- Summarize the reusable lesson, not the full transcript.",
8213
+ "- Decide exactly one outcome: `no_skill_change`, `patch_existing_skill`, or `create_new_skill`.",
8214
+ "- Prefer patching an existing skill when the lesson extends or corrects it; only create a new skill when the trigger and workflow are genuinely distinct.",
8215
+ "- Promote a lesson into a skill only when it has a clear trigger, repeatable steps, and failure signals/checks.",
8216
+ "- Do not create skills for one-off facts, narrow local quirks, or work that is not likely to recur.",
8217
+ "- Keep the review concise and action-oriented. Do not add user-visible review text unless it materially helps or the user asks for it."
8218
+ ].join("\n");
8219
+ }
8220
+ var SkillsContextProvider = class {
8221
+ constructor(context) {
8222
+ this.context = context;
8223
+ }
8224
+ provide = async (request) => {
8225
+ const { projectContext } = await this.context.resolve(request);
8226
+ const skills = new SkillsLoader({
8227
+ workspace: projectContext.hostWorkspace,
8228
+ projectRoot: projectContext.projectRoot
8229
+ });
8230
+ const blocks = [];
8231
+ const alwaysSkills = skills.getAlwaysSkills();
8232
+ if (alwaysSkills.length) {
8233
+ const activeSection = renderActiveSkillsSection(skills, alwaysSkills);
8234
+ if (activeSection) blocks.push(activeSection);
8235
+ }
8236
+ const availableSkillsSection = renderAvailableSkillsSection(skills);
8237
+ if (availableSkillsSection) blocks.push(availableSkillsSection);
8238
+ blocks.push(renderSkillLearningSection());
8239
+ return blocks;
8240
+ };
8241
+ };
8242
+ //#endregion
8243
+ //#region src/contributions/context-provider/providers/tooling-context.provider.ts
8244
+ var ToolingContextProvider = class {
8245
+ constructor(context) {
8246
+ this.context = context;
8247
+ }
8248
+ provide = async (request) => {
8249
+ const { toolCatalog } = await this.context.resolve(request);
8250
+ return [[
8251
+ "## Tooling",
8252
+ "Tool availability (filtered by policy):",
8253
+ "Tool names are case-sensitive. Call tools exactly as listed.",
8254
+ ...toolCatalog.length > 0 ? toolCatalog.map((tool) => `- ${tool.name}: ${tool.description ?? "No description available"}`) : ["- No tools available for this turn."],
8255
+ "TOOLS.md does not control tool availability; it is user guidance for how to use external tools.",
8256
+ "For long waits, avoid rapid poll loops: use exec with enough yieldMs.",
8257
+ "For relative time/date scheduling requests (for example 'in 5 minutes' / '1分钟后'), first check the current local time with an available tool such as exec/date, then convert it to an absolute ISO time with timezone. Do not guess.",
8258
+ "If a task is more complex or takes longer, spawn a sub-agent. Completion is push-based: it will auto-announce when done.",
8259
+ "Do not poll `subagents list` / `sessions_list` in a loop; only check status on-demand (for intervention, debugging, or when explicitly asked)."
8260
+ ].join("\n")];
8261
+ };
8262
+ };
8263
+ //#endregion
8264
+ //#region src/contributions/context-provider/providers/workspace-context.provider.ts
8265
+ var WorkspaceContextProvider = class {
8266
+ constructor(context) {
8267
+ this.context = context;
8268
+ }
8269
+ provide = async (request) => {
8270
+ const { runContext } = await this.context.resolve(request);
8271
+ return [[
8272
+ "## Workspace",
8273
+ `Your working directory is: ${runContext.effectiveWorkspace}`,
8274
+ "Treat this directory as the single global workspace for file operations unless explicitly instructed otherwise."
8275
+ ].join("\n")];
8276
+ };
8277
+ };
8278
+ //#endregion
8279
+ //#region src/contributions/context-provider/providers/workspace-memory-context.provider.ts
8280
+ var WorkspaceMemoryContextProvider = class {
8281
+ constructor(context) {
8282
+ this.context = context;
8283
+ }
8284
+ provide = async (request) => {
8285
+ const { contextConfig, projectContext } = await this.context.resolve(request);
8286
+ const memoryConfig = contextConfig.memory;
8287
+ if (!memoryConfig.enabled) return [];
8288
+ const memory = new MemoryStore(projectContext.hostWorkspace).getMemoryContext();
8289
+ if (!memory) return [];
8290
+ return [`# Memory\n\n${truncateContextText(memory, memoryConfig.maxChars)}`];
8291
+ };
8292
+ };
8293
+ //#endregion
7832
8294
  //#region src/utils/agent-run-request-metadata.utils.ts
7833
8295
  function normalizeString(value) {
7834
8296
  return value?.trim() || void 0;
@@ -7850,12 +8312,60 @@ function buildAgentRunRequestMetadata(params) {
7850
8312
  };
7851
8313
  }
7852
8314
  //#endregion
7853
- //#region src/contributions/context-provider/providers/kernel-context.provider.ts
7854
- var KernelContextProvider = class {
8315
+ //#region src/contributions/context-provider/utils/native-context-config.utils.ts
8316
+ const DEFAULT_NATIVE_CONTEXT_CONFIG = {
8317
+ bootstrap: {
8318
+ files: [
8319
+ "AGENTS.md",
8320
+ "SOUL.md",
8321
+ "USER.md",
8322
+ "IDENTITY.md",
8323
+ "TOOLS.md",
8324
+ "BOOT.md",
8325
+ "BOOTSTRAP.md"
8326
+ ],
8327
+ minimalFiles: [
8328
+ "AGENTS.md",
8329
+ "SOUL.md",
8330
+ "TOOLS.md",
8331
+ "IDENTITY.md"
8332
+ ],
8333
+ perFileChars: 4e3,
8334
+ totalChars: 12e3
8335
+ },
8336
+ memory: {
8337
+ enabled: true,
8338
+ maxChars: 8e3
8339
+ }
8340
+ };
8341
+ function mergeNativeContextConfig(contextConfig) {
8342
+ return {
8343
+ bootstrap: {
8344
+ ...DEFAULT_NATIVE_CONTEXT_CONFIG.bootstrap,
8345
+ ...contextConfig?.bootstrap ?? {}
8346
+ },
8347
+ memory: {
8348
+ ...DEFAULT_NATIVE_CONTEXT_CONFIG.memory,
8349
+ ...contextConfig?.memory ?? {}
8350
+ }
8351
+ };
8352
+ }
8353
+ //#endregion
8354
+ //#region src/contributions/context-provider/services/context-provider-run-context.service.ts
8355
+ var ContextProviderRunContextService = class {
8356
+ snapshots = /* @__PURE__ */ new WeakMap();
8357
+ projectContextResolver = new SessionProjectContextResolver();
7855
8358
  constructor(kernel) {
7856
8359
  this.kernel = kernel;
7857
8360
  }
7858
- provide = async (request) => {
8361
+ resolve = (request) => {
8362
+ const existing = this.snapshots.get(request);
8363
+ if (existing) return existing;
8364
+ const next = this.resolveSnapshot(request);
8365
+ this.snapshots.set(request, next);
8366
+ return next;
8367
+ };
8368
+ resolveSnapshot = async (request) => {
7859
8369
  const session = request.sessionId ? await this.kernel.sessionManager.getAgentRunSession(request.sessionId) : null;
7860
8370
  const sessionId = session?.sessionId ?? request.sessionId ?? request.message.sessionId ?? "";
7861
8371
  const requestMetadata = buildAgentRunRequestMetadata({
@@ -7870,45 +8380,60 @@ var KernelContextProvider = class {
7870
8380
  storedAgentId: request.agentId ?? session?.agentId
7871
8381
  });
7872
8382
  const tools = await this.kernel.toolProviderManager.buildTools(request);
7873
- return [this.buildSystemContextBlock({
7874
- availableTools: buildToolCatalogEntries(tools.map((tool) => ({
8383
+ const sessionProjectRoot = readSessionProjectRoot(runContext.sessionMetadata);
8384
+ const projectContext = this.projectContextResolver.resolve({
8385
+ sessionMetadata: sessionProjectRoot ? { project_root: sessionProjectRoot } : null,
8386
+ workspace: runContext.profile.workspace,
8387
+ defaultWorkspace: runContext.effectiveWorkspace
8388
+ });
8389
+ return {
8390
+ contextConfig: mergeNativeContextConfig(runContext.config.agents.context),
8391
+ projectContext,
8392
+ runContext,
8393
+ toolCatalog: buildToolCatalogEntries(tools.map((tool) => ({
7875
8394
  name: tool.name,
7876
- description: tool.description,
7877
- parameters: tool.parameters
7878
- }))),
7879
- runContext
7880
- })];
7881
- };
7882
- buildSystemContextBlock = (params) => {
7883
- const { availableTools, runContext } = params;
7884
- const lines = [
7885
- new ContextBuilder(runContext.effectiveWorkspace, runContext.config.agents.context, {
7886
- hostWorkspace: runContext.profile.workspace,
7887
- sessionProjectRoot: readSessionProjectRoot(runContext.sessionMetadata)
7888
- }).buildSystemPrompt(void 0, runContext.sessionKey, availableTools, [buildSessionOrchestrationSection(), buildMinimalSystemExecutionPrompt(runContext.effectiveModel)]),
7889
- "## Current Session",
7890
- `Channel: ${runContext.channel}`,
7891
- `Chat ID: ${runContext.chatId}`,
7892
- `Session: ${runContext.sessionKey}`
7893
- ];
7894
- if (runContext.runtimeThinking) lines.push(`Thinking policy: ${runContext.runtimeThinking}`);
7895
- return lines.join("\n");
8395
+ description: tool.description
8396
+ })))
8397
+ };
7896
8398
  };
7897
8399
  };
7898
8400
  //#endregion
7899
8401
  //#region src/contributions/context-provider/index.ts
7900
8402
  var ContextProviderContribution = class {
7901
- unregister = null;
8403
+ cleanups = [];
7902
8404
  constructor(kernel) {
7903
8405
  this.kernel = kernel;
7904
8406
  }
7905
8407
  start = () => {
7906
- if (this.unregister) return;
7907
- this.unregister = this.kernel.contextProviderManager.register(new KernelContextProvider(this.kernel));
8408
+ if (this.cleanups.length > 0) return;
8409
+ const context = new ContextProviderRunContextService(this.kernel);
8410
+ for (const provider of [
8411
+ createAssistantIdentityContextProvider(),
8412
+ new ToolingContextProvider(context),
8413
+ createToolCallStyleContextProvider(),
8414
+ createChatComposerTokensContextProvider(),
8415
+ createSafetyContextProvider(),
8416
+ createCliQuickReferenceContextProvider(),
8417
+ createSelfUpdateContextProvider(),
8418
+ new WorkspaceContextProvider(context),
8419
+ createReplyTagsContextProvider(),
8420
+ createMessagingContextProvider(),
8421
+ createMemoryRecallContextProvider(),
8422
+ createSilentRepliesContextProvider(),
8423
+ createRuntimeContextProvider(),
8424
+ createSelfManagementContextProvider(),
8425
+ new ProjectContextProvider(context),
8426
+ new AgentBootstrapContextProvider(context),
8427
+ new WorkspaceMemoryContextProvider(context),
8428
+ new SkillsContextProvider(context),
8429
+ createSessionOrchestrationContextProvider(),
8430
+ new ExecutionPolicyContextProvider(context),
8431
+ new CurrentSessionContextProvider(context),
8432
+ new ReplyFormatContextProvider()
8433
+ ]) this.cleanups.push(this.kernel.contextProviderManager.register(provider));
7908
8434
  };
7909
8435
  dispose = () => {
7910
- this.unregister?.();
7911
- this.unregister = null;
8436
+ while (this.cleanups.length > 0) this.cleanups.pop()?.();
7912
8437
  };
7913
8438
  };
7914
8439
  //#endregion
@@ -9712,6 +10237,6 @@ function resolveLegacyEventType(message) {
9712
10237
  return `message.${role || "other"}`;
9713
10238
  }
9714
10239
  //#endregion
9715
- export { AccessManager, AgentManager, AgentRunClient, AgentRuntimeRegistry, 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, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildServiceActionId, buildSessionOrchestrationSection, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
10240
+ export { AccessManager, AgentManager, AgentRunClient, AgentRuntimeRegistry, 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, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildServiceActionId, createAgentRuntimeSessionRequestDispatcher, createAssetTools, createContextCompactionMessageId, createContextWindowSignature, createLlmUsageRecord, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, getServiceActionName, getServiceAppManifestPath, getUnsignedUpdateManifest, hasLlmUsageTelemetry, isContextCompactionTimelineMessage, isContextWindowSnapshot, isPanelAppAgentCapability, isPanelAppError, isReplyCapableChannel, isServiceAppError, listExtensionChannelIds, listServiceAppManifestActions, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeLlmUsageModel, normalizeOptionalString, parseServiceAppManifest, parseSkillFrontmatter, projectNcpMessagesWithContextCompaction, readContextWindowEventSessionId, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceAppManifest, resolveAgentRuntimeEntries, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolveNextclawNcpRunContext, resolveSessionChannelContext, runGatewayInboundLoop, sanitizeLlmUsage, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, stripSkillFrontmatter, syncSessionThinkingPreference, toNcpMessages, upsertContextCompactionTimelineMessage, waitForAgentRuntimeSessionReply };
9716
10241
 
9717
10242
  //# sourceMappingURL=index.js.map