@nextclaw/kernel 0.15.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +22 -175
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1046 -2032
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, getAutomaticUpdateCheckDelay, resolveAutomaticUpdateCheckIntervalMs } from "./utils/automatic-update-check.utils.js";
|
|
2
2
|
import { n as getUnsignedUpdateManifest, r as serializeUnsignedUpdateManifest, t as UpdateManifestReader } from "./update-manifest.types-C0qPrjGQ.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
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, DIAGNOSTIC_CORRELATION_METADATA_KEY, DiagnosticRuntime, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, LocalExecutionClaimService, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderModelDiscoveryService, ProviderRegistry, ReadFileTool, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, ViewImageTool, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, estimateInputTokens, 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, resolveRuntimeCommandLaunch, resolveSecretRef, resolveSessionProjectContext, resolveSessionWorkspacePath, resolveThinkingLevel, safeFilename, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
|
|
4
|
+
import { APP_NAME, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, CLEAR_THINKING_TOKENS, CONTEXT_COMPACTION_METADATA_KEY, ConfigSchema, ContextCompactionService, ContextWindowBudgetService, CronService, CronTool, DEFAULT_PANELS_DIR, DEFAULT_PROJECT_SKILLS_DIR_NAME, DEFAULT_SERVICE_APPS_DIR, DEFAULT_SESSION_SEARCH_LIMIT, DEFAULT_WORKSPACE_REPOSITORY_IDENTITY_RESOLVER, DIAGNOSTIC_CORRELATION_METADATA_KEY, DiagnosticRuntime, EditFileTool, ExecTool, ExtensionChannelAdapter, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, LiteLLMProvider, LocalExecutionClaimService, MAX_SESSION_SEARCH_LIMIT, MemoryGetTool, MemorySearchTool, MemoryStore, MessageBus, MessageTool, ProviderModelDiscoveryService, ProviderRegistry, ReadFileTool, SILENT_REPLY_TOKEN, SessionProjectContextResolver, SessionSearchService, SkillsLoader, THINKING_LEVELS, ViewImageTool, WebFetchTool, WebSearchTool, WriteFileTool, buildCompressingCompactionCheckpoint, buildConfigSchema, buildContextWindowSnapshot, buildReloadPlan, buildSessionRequestToolResult, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createCompletedSessionRequest, createFailedSessionRequest, createRunningSessionRequest, createRuntimeChildEnv, createTypingStopControlMessage, diffConfigPaths, ensureDir, estimateInputTokens, 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, resolveRuntimeCommandLaunch, resolveSecretRef, resolveSessionProjectContext, resolveSessionWorkspacePath, resolveThinkingLevel, safeFilename, sanitizeOutboundAssistantContent, saveConfig, summarizeSessionRequestTask, toExtensionConfigView, updateAgentProfile } from "@nextclaw/core";
|
|
5
5
|
import { NCP_AI_EXECUTION_METADATA_KEY, NCP_INTERNAL_VISIBILITY_METADATA_KEY, NCP_RUN_TRIGGER_METADATA_KEY, NcpEventType, OBSERVATION_EVENT_EXTENSION_TYPE, createUnavailableNcpAiExecutionMetadata, isHiddenNcpMessage, normalizeAssistantText, parseNcpRunTriggerInput, readNcpAiExecutionMetadata, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
|
|
6
6
|
import { LocalAssetStore, buildAssetContentPath, buildOpenAiFunctionTool, isTextLikeAsset, ncpMessageToOpenAiMessages, validateToolArgs } from "@nextclaw/ncp-agent-runtime";
|
|
7
7
|
import { CHAT_CONTINUATION_TARGET_MESSAGE_METADATA_KEY, CHAT_CONVERSATION_EXCERPT_TOKEN_KIND, CHAT_INLINE_TOKENS_METADATA_KEY, CHAT_INLINE_TOKENS_SCHEMA_VERSION, CHAT_PROJECT_TOKEN_KIND, CHAT_SESSION_MATERIALIZATION_METADATA_KEY, CHAT_SYSTEM_OBJECT_TOKEN_KIND, CHAT_UI_RESOURCE_TOKEN_KIND, CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND, CHAT_WORKSPACE_EXCERPT_TOKEN_KIND, CHAT_WORKSPACE_FILE_TOKEN_KIND, Contribution as Contribution$1, EventBus, EventBus as EventBus$1, Ingress, Ingress as Ingress$1, PANEL_APP_INLINE_HOST_CONTRACT, PANEL_APP_SCROLL_RESTORATION_CONTRACT, SYSTEM_OBJECT_REFERENCE_DEFAULT_LIMIT, SYSTEM_OBJECT_REFERENCE_MAX_LIMIT, SYSTEM_OBJECT_TYPE_CRON_JOB, SYSTEM_OBJECT_TYPE_INBOX_DELIVERY, UI_CONTENT_PARAMS_HOST_CONTRACT, classifyDiagnosticError, createSystemObjectReferenceUri, createTypedKey, eventKeys, eventKeys as eventKeys$1, ingressKeys, ingressKeys as ingressKeys$1, isRuntimeDefaultModelValue, isSilentReplyNcpMessage, normalizeRuntimeModelSelectionMode, parseSystemObjectReferenceUri, readChatUiResourceReference, readInlineContentHeight, readSystemObjectResolvedReference, readUiContentParams } from "@nextclaw/shared";
|
|
@@ -10,7 +10,7 @@ import { catchError, filter, from, lastValueFrom, tap } from "rxjs";
|
|
|
10
10
|
import { DefaultNcpAgentConversationStateManager, insertMessageByTimeline, mergeToolExecutionTiming } from "@nextclaw/ncp-toolkit";
|
|
11
11
|
import { accessSync, appendFileSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
12
12
|
import path, { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
13
|
-
import { access, appendFile, chmod,
|
|
13
|
+
import { access, appendFile, chmod, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
14
14
|
import { AppGrantService, AppHomeService, AppInstallationService, AppInstanceInventoryService, AppInstanceStorageService, AppManifestService, AppPlatformTargetService, AppRegistryService, AppServiceLaunchService, FileLockService, isAppComponentManifestBundle } from "@nextclaw/app-runtime";
|
|
15
15
|
import { execFileSync, spawn } from "node:child_process";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
@@ -1393,26 +1393,26 @@ const SESSION_ACTIVITY_PREVIEW_STATUS_KINDS = new Set([
|
|
|
1393
1393
|
"run-failed",
|
|
1394
1394
|
"run-interrupted"
|
|
1395
1395
|
]);
|
|
1396
|
-
function isRecord$
|
|
1396
|
+
function isRecord$20(value) {
|
|
1397
1397
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1398
1398
|
}
|
|
1399
|
-
function readOptionalString$
|
|
1399
|
+
function readOptionalString$14(value) {
|
|
1400
1400
|
if (typeof value !== "string") return;
|
|
1401
1401
|
const trimmed = value.trim();
|
|
1402
1402
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
1403
1403
|
}
|
|
1404
1404
|
function readSessionActivityPreviewMetadata(value) {
|
|
1405
|
-
if (!isRecord$
|
|
1405
|
+
if (!isRecord$20(value)) return null;
|
|
1406
1406
|
const state = value.state;
|
|
1407
|
-
const timestamp = readOptionalString$
|
|
1407
|
+
const timestamp = readOptionalString$14(value.timestamp);
|
|
1408
1408
|
if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
|
|
1409
|
-
const statusKind = readOptionalString$
|
|
1409
|
+
const statusKind = readOptionalString$14(value.statusKind);
|
|
1410
1410
|
return {
|
|
1411
1411
|
state,
|
|
1412
1412
|
timestamp,
|
|
1413
1413
|
statusKind: SESSION_ACTIVITY_PREVIEW_STATUS_KINDS.has(statusKind) ? statusKind : void 0,
|
|
1414
|
-
statusText: readOptionalString$
|
|
1415
|
-
replyText: readOptionalString$
|
|
1414
|
+
statusText: readOptionalString$14(value.statusText),
|
|
1415
|
+
replyText: readOptionalString$14(value.replyText)
|
|
1416
1416
|
};
|
|
1417
1417
|
}
|
|
1418
1418
|
function compareIsoTimestamp(left, right) {
|
|
@@ -1496,7 +1496,7 @@ var SessionActivityPreviewEventService = class {
|
|
|
1496
1496
|
//#endregion
|
|
1497
1497
|
//#region src/managers/agent-run-session-command.manager.ts
|
|
1498
1498
|
const CONTINUATION_PROMPT = "Continue from where you stopped. Preserve completed work and avoid repeating it.";
|
|
1499
|
-
function isRecord$
|
|
1499
|
+
function isRecord$19(value) {
|
|
1500
1500
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1501
1501
|
}
|
|
1502
1502
|
function hasSendableMessageContent(message) {
|
|
@@ -1504,7 +1504,7 @@ function hasSendableMessageContent(message) {
|
|
|
1504
1504
|
}
|
|
1505
1505
|
function readSessionActivityState(metadata) {
|
|
1506
1506
|
const preview = metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY];
|
|
1507
|
-
return isRecord$
|
|
1507
|
+
return isRecord$19(preview) && typeof preview.state === "string" ? preview.state : null;
|
|
1508
1508
|
}
|
|
1509
1509
|
var AgentRunSessionCommandManager = class {
|
|
1510
1510
|
pendingCommands = /* @__PURE__ */ new Map();
|
|
@@ -1879,13 +1879,13 @@ function buildRunMetadata(params) {
|
|
|
1879
1879
|
}
|
|
1880
1880
|
//#endregion
|
|
1881
1881
|
//#region src/utils/agent-run-request.utils.ts
|
|
1882
|
-
function readOptionalString$
|
|
1882
|
+
function readOptionalString$13(value) {
|
|
1883
1883
|
if (typeof value !== "string") return;
|
|
1884
1884
|
return value.trim() || void 0;
|
|
1885
1885
|
}
|
|
1886
1886
|
function toAgentRunRequest(envelope) {
|
|
1887
1887
|
const metadata = envelope.metadata ?? {};
|
|
1888
|
-
const peerId = readOptionalString$
|
|
1888
|
+
const peerId = readOptionalString$13(envelope.peerId);
|
|
1889
1889
|
const requestMetadata = {
|
|
1890
1890
|
agentRuntimeId: metadata.agentRuntimeId,
|
|
1891
1891
|
agentId: metadata.agentId,
|
|
@@ -1897,10 +1897,10 @@ function toAgentRunRequest(envelope) {
|
|
|
1897
1897
|
maxTokens: metadata.maxTokens,
|
|
1898
1898
|
thinkingEffort: metadata.thinkingEffort,
|
|
1899
1899
|
delivery: envelope.delivery,
|
|
1900
|
-
idempotencyKey: readOptionalString$
|
|
1900
|
+
idempotencyKey: readOptionalString$13(envelope.idempotencyKey)
|
|
1901
1901
|
};
|
|
1902
1902
|
if (Array.isArray(envelope.content)) {
|
|
1903
|
-
const sessionId = readOptionalString$
|
|
1903
|
+
const sessionId = readOptionalString$13(envelope.sessionId);
|
|
1904
1904
|
if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
|
|
1905
1905
|
return {
|
|
1906
1906
|
...requestMetadata,
|
|
@@ -1918,8 +1918,8 @@ function toAgentRunRequest(envelope) {
|
|
|
1918
1918
|
}
|
|
1919
1919
|
const sourceMessage = envelope.message;
|
|
1920
1920
|
if (!sourceMessage) throw new Error("Invalid agent run send request.");
|
|
1921
|
-
const envelopeSessionId = readOptionalString$
|
|
1922
|
-
const messageSessionId = readOptionalString$
|
|
1921
|
+
const envelopeSessionId = readOptionalString$13(envelope.sessionId);
|
|
1922
|
+
const messageSessionId = readOptionalString$13(sourceMessage.sessionId);
|
|
1923
1923
|
const sessionId = envelopeSessionId ?? messageSessionId;
|
|
1924
1924
|
if (sessionId && peerId) throw new Error("agent-run.send cannot accept both sessionId and peerId.");
|
|
1925
1925
|
return {
|
|
@@ -1980,7 +1980,7 @@ function readSessionMaterialization(metadata) {
|
|
|
1980
1980
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1981
1981
|
const materialization = value;
|
|
1982
1982
|
if (materialization.kind !== "child") throw new Error("session_materialization.kind must be \"child\".");
|
|
1983
|
-
const parentSessionId = readOptionalString$
|
|
1983
|
+
const parentSessionId = readOptionalString$13(materialization.parentSessionId);
|
|
1984
1984
|
if (!parentSessionId) throw new Error("session_materialization.parentSessionId is required.");
|
|
1985
1985
|
if (materialization.inheritContext !== true) throw new Error("session_materialization.inheritContext must be true.");
|
|
1986
1986
|
return {
|
|
@@ -2185,15 +2185,15 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2185
2185
|
};
|
|
2186
2186
|
//#endregion
|
|
2187
2187
|
//#region src/utils/agent-run-trigger.utils.ts
|
|
2188
|
-
function isRecord$
|
|
2188
|
+
function isRecord$18(value) {
|
|
2189
2189
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2190
2190
|
}
|
|
2191
|
-
function readOptionalString$
|
|
2191
|
+
function readOptionalString$12(value) {
|
|
2192
2192
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2193
2193
|
}
|
|
2194
2194
|
function readSourceRunSpec(message) {
|
|
2195
2195
|
const value = message.metadata?.[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY];
|
|
2196
|
-
return isRecord$
|
|
2196
|
+
return isRecord$18(value) ? value : {};
|
|
2197
2197
|
}
|
|
2198
2198
|
const SOURCE_CONTEXT_KEYS = [
|
|
2199
2199
|
"channel",
|
|
@@ -2222,9 +2222,9 @@ function readSourceContext(request) {
|
|
|
2222
2222
|
function createAgentToolRunTriggerInput(params) {
|
|
2223
2223
|
const { request, source } = params;
|
|
2224
2224
|
const runSpec = readSourceRunSpec(request.message);
|
|
2225
|
-
const sourceSessionId = readOptionalString$
|
|
2226
|
-
const sourceRunId = readOptionalString$
|
|
2227
|
-
const sourceModel = readOptionalString$
|
|
2225
|
+
const sourceSessionId = readOptionalString$12(request.sessionId);
|
|
2226
|
+
const sourceRunId = readOptionalString$12(runSpec.runId);
|
|
2227
|
+
const sourceModel = readOptionalString$12(runSpec.model);
|
|
2228
2228
|
const sourceContext = readSourceContext(request);
|
|
2229
2229
|
return {
|
|
2230
2230
|
actor: "agent",
|
|
@@ -2240,9 +2240,9 @@ function createAgentToolRunTriggerInput(params) {
|
|
|
2240
2240
|
function createIngressRunTriggerInput(params) {
|
|
2241
2241
|
const { request } = params;
|
|
2242
2242
|
const source = request.channel ? `channel:${request.channel}` : params.source.trim() || "internal";
|
|
2243
|
-
const sourceSessionId = readOptionalString$
|
|
2243
|
+
const sourceSessionId = readOptionalString$12(request.sessionId);
|
|
2244
2244
|
const sourceContext = readSourceContext(request);
|
|
2245
|
-
const cronJobId = readOptionalString$
|
|
2245
|
+
const cronJobId = readOptionalString$12(request.metadata?.cron_job_id);
|
|
2246
2246
|
const isCron = request.metadata?.session_origin === "cron" || Boolean(cronJobId);
|
|
2247
2247
|
return {
|
|
2248
2248
|
actor: isCron ? "automation" : request.message.role === "user" ? "human" : request.message.role === "service" ? "automation" : "system",
|
|
@@ -2296,7 +2296,7 @@ function createRunTriggerMetadataEvent(params) {
|
|
|
2296
2296
|
};
|
|
2297
2297
|
}
|
|
2298
2298
|
function attachSourceToolCall(trigger, sourceToolCallId) {
|
|
2299
|
-
const normalizedToolCallId = readOptionalString$
|
|
2299
|
+
const normalizedToolCallId = readOptionalString$12(sourceToolCallId);
|
|
2300
2300
|
return {
|
|
2301
2301
|
...structuredClone(trigger),
|
|
2302
2302
|
...normalizedToolCallId ? { sourceToolCallId: normalizedToolCallId } : {}
|
|
@@ -2698,7 +2698,7 @@ const BUILTIN_RUNTIME_PRESENTATION = {
|
|
|
2698
2698
|
}
|
|
2699
2699
|
}
|
|
2700
2700
|
};
|
|
2701
|
-
function readString$
|
|
2701
|
+
function readString$11(value) {
|
|
2702
2702
|
if (typeof value !== "string") return;
|
|
2703
2703
|
return value.trim() || void 0;
|
|
2704
2704
|
}
|
|
@@ -2707,7 +2707,7 @@ function readRecord$3(value) {
|
|
|
2707
2707
|
return value;
|
|
2708
2708
|
}
|
|
2709
2709
|
function resolveBuiltinRuntimePresentation(value) {
|
|
2710
|
-
const normalized = readString$
|
|
2710
|
+
const normalized = readString$11(value)?.toLowerCase();
|
|
2711
2711
|
if (!normalized) return null;
|
|
2712
2712
|
if (!(normalized in BUILTIN_RUNTIME_PRESENTATION)) return null;
|
|
2713
2713
|
return BUILTIN_RUNTIME_PRESENTATION[normalized] ?? null;
|
|
@@ -2728,13 +2728,13 @@ function resolveAgentRuntimeEntries(params) {
|
|
|
2728
2728
|
entries.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, buildNativeRuntimeEntry(params.config));
|
|
2729
2729
|
for (const [rawId, rawEntry] of Object.entries(params.config.agents.runtimes.entries ?? {})) {
|
|
2730
2730
|
const id = rawId.trim().toLowerCase();
|
|
2731
|
-
const type = readString$
|
|
2731
|
+
const type = readString$11(rawEntry.type)?.toLowerCase();
|
|
2732
2732
|
if (!id || !type) continue;
|
|
2733
2733
|
const explicitIcon = normalizeAgentRuntimeSessionTypeIcon(rawEntry.icon);
|
|
2734
2734
|
const builtinPresentation = resolveBuiltinRuntimePresentation(id) ?? resolveBuiltinRuntimePresentation(type);
|
|
2735
2735
|
entries.set(id, {
|
|
2736
2736
|
id,
|
|
2737
|
-
label: readString$
|
|
2737
|
+
label: readString$11(rawEntry.label) ?? builtinPresentation?.label ?? id,
|
|
2738
2738
|
...explicitIcon ?? builtinPresentation?.icon ? { icon: explicitIcon ?? builtinPresentation?.icon } : {},
|
|
2739
2739
|
type,
|
|
2740
2740
|
enabled: rawEntry.enabled !== false,
|
|
@@ -3812,10 +3812,10 @@ function parseServiceAppManifest(raw, options = {}) {
|
|
|
3812
3812
|
} catch (error) {
|
|
3813
3813
|
throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
3814
3814
|
}
|
|
3815
|
-
if (!isRecord$
|
|
3815
|
+
if (!isRecord$17(parsed)) throw new Error("service-app.json must contain an object.");
|
|
3816
3816
|
const id = readRequiredString$8(parsed, "id");
|
|
3817
3817
|
if (!SERVICE_APP_ID_PATTERN$1.test(id)) throw new Error("service app id must be kebab-case.");
|
|
3818
|
-
const protocol = readOptionalString$
|
|
3818
|
+
const protocol = readOptionalString$11(parsed, "protocol") ?? "mcp";
|
|
3819
3819
|
if (protocol !== "mcp" && protocol !== "wasi-component") throw new Error("service app protocol must be mcp or wasi-component.");
|
|
3820
3820
|
const launch = protocol === "mcp" ? new AppServiceLaunchService(options.platformTargetService).resolve(parsed, options.target) : void 0;
|
|
3821
3821
|
const componentEntry = protocol === "wasi-component" ? readPortableComponentEntry(parsed) : void 0;
|
|
@@ -3826,7 +3826,7 @@ function parseServiceAppManifest(raw, options = {}) {
|
|
|
3826
3826
|
return {
|
|
3827
3827
|
id,
|
|
3828
3828
|
title: readRequiredString$8(parsed, "title"),
|
|
3829
|
-
description: readOptionalString$
|
|
3829
|
+
description: readOptionalString$11(parsed, "description"),
|
|
3830
3830
|
enabled: readOptionalBoolean$2(parsed, "enabled") ?? true,
|
|
3831
3831
|
protocol,
|
|
3832
3832
|
command: launch?.command,
|
|
@@ -3841,14 +3841,14 @@ function parseServiceAppManifest(raw, options = {}) {
|
|
|
3841
3841
|
}
|
|
3842
3842
|
function readServiceAppProvides(value) {
|
|
3843
3843
|
if (value === void 0) return void 0;
|
|
3844
|
-
if (!isRecord$
|
|
3844
|
+
if (!isRecord$17(value)) throw new Error("service app provides must be an object.");
|
|
3845
3845
|
if (value.capabilities === void 0) return void 0;
|
|
3846
3846
|
if (!Array.isArray(value.capabilities)) throw new Error("service app provides.capabilities must be an array.");
|
|
3847
3847
|
const seen = /* @__PURE__ */ new Set();
|
|
3848
3848
|
const capabilities = value.capabilities.map((entry, index) => {
|
|
3849
|
-
if (!isRecord$
|
|
3849
|
+
if (!isRecord$17(entry)) throw new Error(`service app provides.capabilities[${index}] must be an object.`);
|
|
3850
3850
|
const id = readRequirementIdentifier(entry, "id", `provides.capabilities[${index}].id`);
|
|
3851
|
-
const version = readOptionalString$
|
|
3851
|
+
const version = readOptionalString$11(entry, "version");
|
|
3852
3852
|
if (!version) throw new Error(`service app provides.capabilities[${index}].version is required.`);
|
|
3853
3853
|
const key = `${id}@${version}`;
|
|
3854
3854
|
if (seen.has(key)) throw new Error(`service app provides.capabilities contains duplicate ${key}.`);
|
|
@@ -3874,7 +3874,7 @@ function readCapabilityResourceTypes(value, index) {
|
|
|
3874
3874
|
}
|
|
3875
3875
|
function readServiceAppRequirements(value, protocol) {
|
|
3876
3876
|
if (value === void 0) return void 0;
|
|
3877
|
-
if (!isRecord$
|
|
3877
|
+
if (!isRecord$17(value)) throw new Error("service app requires must be an object.");
|
|
3878
3878
|
const capabilities = readCapabilityRequirements(value.capabilities, protocol);
|
|
3879
3879
|
const resources = readResourceRequirements(value.resources);
|
|
3880
3880
|
const modelSlots = readModelCapabilitySlots(value.modelSlots);
|
|
@@ -3898,7 +3898,7 @@ function readCapabilitySlots(value, name, hasModelLimits) {
|
|
|
3898
3898
|
const seen = /* @__PURE__ */ new Set();
|
|
3899
3899
|
return value.map((entry, index) => {
|
|
3900
3900
|
const field = `requires.${name}[${index}]`;
|
|
3901
|
-
if (!isRecord$
|
|
3901
|
+
if (!isRecord$17(entry)) throw new Error(`service app ${field} must be an object.`);
|
|
3902
3902
|
const allowed = hasModelLimits ? [
|
|
3903
3903
|
"id",
|
|
3904
3904
|
"title",
|
|
@@ -3940,9 +3940,9 @@ function readCapabilityRequirements(value, protocol) {
|
|
|
3940
3940
|
if (!Array.isArray(value)) throw new Error("service app requires.capabilities must be an array.");
|
|
3941
3941
|
const seen = /* @__PURE__ */ new Set();
|
|
3942
3942
|
return value.map((entry, index) => {
|
|
3943
|
-
if (!isRecord$
|
|
3943
|
+
if (!isRecord$17(entry)) throw new Error(`service app requires.capabilities[${index}] must be an object.`);
|
|
3944
3944
|
const id = readRequirementIdentifier(entry, "id", `requires.capabilities[${index}].id`);
|
|
3945
|
-
const version = readOptionalString$
|
|
3945
|
+
const version = readOptionalString$11(entry, "version");
|
|
3946
3946
|
const key = `${id}@${version ?? "*"}`;
|
|
3947
3947
|
if (seen.has(key)) throw new Error(`service app requires.capabilities contains duplicate ${key}.`);
|
|
3948
3948
|
seen.add(key);
|
|
@@ -3955,19 +3955,19 @@ function readCapabilityRequirements(value, protocol) {
|
|
|
3955
3955
|
version,
|
|
3956
3956
|
provider,
|
|
3957
3957
|
wit,
|
|
3958
|
-
title: readOptionalString$
|
|
3959
|
-
description: readOptionalString$
|
|
3958
|
+
title: readOptionalString$11(entry, "title"),
|
|
3959
|
+
description: readOptionalString$11(entry, "description"),
|
|
3960
3960
|
remediation: readExternalRemediation(entry.remediation, `requires.capabilities[${index}]`)
|
|
3961
3961
|
};
|
|
3962
3962
|
});
|
|
3963
3963
|
}
|
|
3964
3964
|
function readWitContract(value, fieldName, role) {
|
|
3965
3965
|
if (value === void 0) return void 0;
|
|
3966
|
-
if (!isRecord$
|
|
3967
|
-
const packageName = readOptionalString$
|
|
3966
|
+
if (!isRecord$17(value)) throw new Error(`service app ${fieldName} must be an object.`);
|
|
3967
|
+
const packageName = readOptionalString$11(value, "package");
|
|
3968
3968
|
if (!packageName || !WIT_PACKAGE_PATTERN.test(packageName)) throw new Error(`service app ${fieldName}.package must be a WIT package identifier.`);
|
|
3969
3969
|
const interfaceName = readRequirementIdentifier(value, "interface", `${fieldName}.interface`);
|
|
3970
|
-
const version = readOptionalString$
|
|
3970
|
+
const version = readOptionalString$11(value, "version");
|
|
3971
3971
|
if (!version) throw new Error(`service app ${fieldName}.version is required.`);
|
|
3972
3972
|
if (role === "provider" && !SEMVER_VERSION_PATTERN.test(version)) throw new Error(`service app ${fieldName}.version must be an exact semver version for a Provider.`);
|
|
3973
3973
|
if (role === "consumer" && !isSemverRange(version)) throw new Error(`service app ${fieldName}.version must be a semver range for a Consumer.`);
|
|
@@ -3990,7 +3990,7 @@ function readResourceRequirements(value) {
|
|
|
3990
3990
|
if (!Array.isArray(value)) throw new Error("service app requires.resources must be an array.");
|
|
3991
3991
|
const seen = /* @__PURE__ */ new Set();
|
|
3992
3992
|
return value.map((entry, index) => {
|
|
3993
|
-
if (!isRecord$
|
|
3993
|
+
if (!isRecord$17(entry)) throw new Error(`service app requires.resources[${index}] must be an object.`);
|
|
3994
3994
|
const binding = readRequirementIdentifier(entry, "binding", `requires.resources[${index}].binding`);
|
|
3995
3995
|
if (seen.has(binding)) throw new Error(`service app requires.resources contains duplicate binding ${binding}.`);
|
|
3996
3996
|
seen.add(binding);
|
|
@@ -3998,21 +3998,21 @@ function readResourceRequirements(value) {
|
|
|
3998
3998
|
binding,
|
|
3999
3999
|
type: readRequirementIdentifier(entry, "type", `requires.resources[${index}].type`),
|
|
4000
4000
|
required: readOptionalBoolean$2(entry, "required") ?? true,
|
|
4001
|
-
title: readOptionalString$
|
|
4002
|
-
description: readOptionalString$
|
|
4001
|
+
title: readOptionalString$11(entry, "title"),
|
|
4002
|
+
description: readOptionalString$11(entry, "description"),
|
|
4003
4003
|
remediation: readExternalRemediation(entry.remediation, `requires.resources[${index}]`)
|
|
4004
4004
|
};
|
|
4005
4005
|
});
|
|
4006
4006
|
}
|
|
4007
4007
|
function readRequirementIdentifier(record, key, fieldName) {
|
|
4008
|
-
const value = readOptionalString$
|
|
4008
|
+
const value = readOptionalString$11(record, key);
|
|
4009
4009
|
if (!value || !/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(value)) throw new Error(`service app ${fieldName} must be a lowercase identifier.`);
|
|
4010
4010
|
return value;
|
|
4011
4011
|
}
|
|
4012
4012
|
function readExternalRemediation(value, fieldPrefix) {
|
|
4013
4013
|
if (value === void 0) return void 0;
|
|
4014
|
-
if (!isRecord$
|
|
4015
|
-
const summary = readOptionalString$
|
|
4014
|
+
if (!isRecord$17(value) || value.kind !== "agent-setup") throw new Error(`service app ${fieldPrefix}.remediation.kind must be agent-setup.`);
|
|
4015
|
+
const summary = readOptionalString$11(value, "summary");
|
|
4016
4016
|
if (!summary) throw new Error(`service app ${fieldPrefix}.remediation.summary is required.`);
|
|
4017
4017
|
return {
|
|
4018
4018
|
kind: "agent-setup",
|
|
@@ -4022,8 +4022,8 @@ function readExternalRemediation(value, fieldPrefix) {
|
|
|
4022
4022
|
}
|
|
4023
4023
|
function readServiceAppLifecycle(value) {
|
|
4024
4024
|
if (value === void 0) return { mode: "action" };
|
|
4025
|
-
if (!isRecord$
|
|
4026
|
-
const mode = readOptionalString$
|
|
4025
|
+
if (!isRecord$17(value)) throw new Error("service app lifecycle must be an object.");
|
|
4026
|
+
const mode = readOptionalString$11(value, "mode") ?? "action";
|
|
4027
4027
|
if (mode === "action") return { mode };
|
|
4028
4028
|
if (mode === "provider") return { mode };
|
|
4029
4029
|
if (mode !== "resident") throw new Error("service app lifecycle.mode must be action, resident or provider.");
|
|
@@ -4044,13 +4044,13 @@ function readProviderIds(value) {
|
|
|
4044
4044
|
return Array.from(new Set(providerIds));
|
|
4045
4045
|
}
|
|
4046
4046
|
function readServiceAppId(record, key, fieldName) {
|
|
4047
|
-
const value = readOptionalString$
|
|
4047
|
+
const value = readOptionalString$11(record, key);
|
|
4048
4048
|
if (!value || !SERVICE_APP_ID_PATTERN$1.test(value)) throw new Error(`service app ${fieldName} must be a kebab-case service app id.`);
|
|
4049
4049
|
return value;
|
|
4050
4050
|
}
|
|
4051
4051
|
function readPortableComponentEntry(record) {
|
|
4052
4052
|
const component = record.component;
|
|
4053
|
-
if (!isRecord$
|
|
4053
|
+
if (!isRecord$17(component)) throw new Error("service app component is required for wasi-component.");
|
|
4054
4054
|
const entry = readRequiredString$8(component, "entry").replace(/\\/g, "/");
|
|
4055
4055
|
if (path.isAbsolute(entry) || entry.includes("\0") || entry.split("/").includes("..")) throw new Error("service app component.entry must be a package-relative path.");
|
|
4056
4056
|
if (!entry.endsWith(".wasm")) throw new Error("service app component.entry must reference a .wasm file.");
|
|
@@ -4058,22 +4058,22 @@ function readPortableComponentEntry(record) {
|
|
|
4058
4058
|
}
|
|
4059
4059
|
function readManifestActions(value) {
|
|
4060
4060
|
if (value === void 0) throw new Error("service app actions are required.");
|
|
4061
|
-
if (!isRecord$
|
|
4061
|
+
if (!isRecord$17(value)) throw new Error("service app actions must be an object.");
|
|
4062
4062
|
if (Object.keys(value).length === 0) throw new Error("service app actions cannot be empty.");
|
|
4063
4063
|
const actions = {};
|
|
4064
4064
|
for (const [name, action] of Object.entries(value)) {
|
|
4065
4065
|
if (!name.trim()) throw new Error("service app action name cannot be empty.");
|
|
4066
|
-
if (!isRecord$
|
|
4067
|
-
const risk = readOptionalString$
|
|
4066
|
+
if (!isRecord$17(action)) throw new Error(`service app action ${name} must be an object.`);
|
|
4067
|
+
const risk = readOptionalString$11(action, "risk");
|
|
4068
4068
|
if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
|
|
4069
4069
|
const inputSchema = action.inputSchema;
|
|
4070
|
-
if (inputSchema !== void 0 && !isRecord$
|
|
4070
|
+
if (inputSchema !== void 0 && !isRecord$17(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
|
|
4071
4071
|
const timeoutMs = readOptionalNumber$1(action, "timeoutMs");
|
|
4072
4072
|
if (timeoutMs !== void 0 && (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 3e5)) throw new Error(`service app action ${name} timeoutMs must be an integer between 100 and 300000.`);
|
|
4073
4073
|
actions[name] = {
|
|
4074
4074
|
risk,
|
|
4075
|
-
title: readOptionalString$
|
|
4076
|
-
description: readOptionalString$
|
|
4075
|
+
title: readOptionalString$11(action, "title"),
|
|
4076
|
+
description: readOptionalString$11(action, "description"),
|
|
4077
4077
|
inputSchema,
|
|
4078
4078
|
timeoutMs
|
|
4079
4079
|
};
|
|
@@ -4081,7 +4081,7 @@ function readManifestActions(value) {
|
|
|
4081
4081
|
return actions;
|
|
4082
4082
|
}
|
|
4083
4083
|
function readRequiredString$8(record, key) {
|
|
4084
|
-
const value = readOptionalString$
|
|
4084
|
+
const value = readOptionalString$11(record, key);
|
|
4085
4085
|
if (!value) throw new Error(`service app ${key} is required.`);
|
|
4086
4086
|
return value;
|
|
4087
4087
|
}
|
|
@@ -4089,7 +4089,7 @@ function readRequiredBoolean(record, key) {
|
|
|
4089
4089
|
if (typeof record[key] !== "boolean") throw new Error(`service app ${key} is required and must be a boolean.`);
|
|
4090
4090
|
return record[key];
|
|
4091
4091
|
}
|
|
4092
|
-
function readOptionalString$
|
|
4092
|
+
function readOptionalString$11(record, key) {
|
|
4093
4093
|
return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
|
|
4094
4094
|
}
|
|
4095
4095
|
function readOptionalBoolean$2(record, key) {
|
|
@@ -4102,7 +4102,7 @@ function readOptionalNumber$1(record, key) {
|
|
|
4102
4102
|
if (typeof record[key] !== "number") throw new Error(`service app ${key} must be number.`);
|
|
4103
4103
|
return record[key];
|
|
4104
4104
|
}
|
|
4105
|
-
function isRecord$
|
|
4105
|
+
function isRecord$17(value) {
|
|
4106
4106
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4107
4107
|
}
|
|
4108
4108
|
//#endregion
|
|
@@ -6019,14 +6019,14 @@ var ExtensionLifecycleService = class {
|
|
|
6019
6019
|
};
|
|
6020
6020
|
//#endregion
|
|
6021
6021
|
//#region src/features/extension-runtime/utils/extension-runtime-payload.utils.ts
|
|
6022
|
-
function readString$
|
|
6022
|
+
function readString$10(value) {
|
|
6023
6023
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6024
6024
|
}
|
|
6025
6025
|
function readRecord$2(value) {
|
|
6026
6026
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
6027
6027
|
}
|
|
6028
6028
|
function readRequiredString$7(value, name) {
|
|
6029
|
-
const trimmed = readString$
|
|
6029
|
+
const trimmed = readString$10(value);
|
|
6030
6030
|
if (!trimmed) throw new Error(`${name} is required`);
|
|
6031
6031
|
return trimmed;
|
|
6032
6032
|
}
|
|
@@ -6041,16 +6041,16 @@ function readTextContent(value) {
|
|
|
6041
6041
|
function readInboundAttachments(value) {
|
|
6042
6042
|
if (!Array.isArray(value)) return [];
|
|
6043
6043
|
return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))).map((entry) => ({
|
|
6044
|
-
...readString$
|
|
6045
|
-
...readString$
|
|
6046
|
-
...readString$
|
|
6047
|
-
...readString$
|
|
6048
|
-
...readString$
|
|
6049
|
-
...readString$
|
|
6044
|
+
...readString$10(entry.id) ? { id: readString$10(entry.id) } : {},
|
|
6045
|
+
...readString$10(entry.name) ? { name: readString$10(entry.name) } : {},
|
|
6046
|
+
...readString$10(entry.path) ? { path: readString$10(entry.path) } : {},
|
|
6047
|
+
...readString$10(entry.url) ? { url: readString$10(entry.url) } : {},
|
|
6048
|
+
...readString$10(entry.assetUri) ? { assetUri: readString$10(entry.assetUri) } : {},
|
|
6049
|
+
...readString$10(entry.mimeType) ? { mimeType: readString$10(entry.mimeType) } : {},
|
|
6050
6050
|
...readOptionalNumber(entry.size) !== void 0 ? { size: readOptionalNumber(entry.size) } : {},
|
|
6051
|
-
...readString$
|
|
6051
|
+
...readString$10(entry.source) ? { source: readString$10(entry.source) } : {},
|
|
6052
6052
|
...entry.status === "ready" || entry.status === "remote-only" ? { status: entry.status } : {},
|
|
6053
|
-
...readString$
|
|
6053
|
+
...readString$10(entry.errorCode) ? { errorCode: readString$10(entry.errorCode) } : {}
|
|
6054
6054
|
}));
|
|
6055
6055
|
}
|
|
6056
6056
|
function toInboundMessage(value) {
|
|
@@ -6082,7 +6082,7 @@ function normalizeAuthPollResult(value) {
|
|
|
6082
6082
|
return {
|
|
6083
6083
|
channel: readRequiredString$7(record.channel, "channel"),
|
|
6084
6084
|
status: record.status,
|
|
6085
|
-
message: readString$
|
|
6085
|
+
message: readString$10(record.message),
|
|
6086
6086
|
nextPollMs: readOptionalNumber(record.nextPollMs),
|
|
6087
6087
|
accountId: typeof record.accountId === "string" ? record.accountId : null,
|
|
6088
6088
|
notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
|
|
@@ -6116,10 +6116,10 @@ var ExtensionIngressDiagnosticsService = class {
|
|
|
6116
6116
|
event: readRequiredString$7(payload.event, "event"),
|
|
6117
6117
|
component: readRequiredString$7(payload.component, "component"),
|
|
6118
6118
|
outcome: readRequiredString$7(payload.outcome, "outcome"),
|
|
6119
|
-
correlationId: readString$
|
|
6120
|
-
parentCorrelationId: readString$
|
|
6121
|
-
reasonCode: readString$
|
|
6122
|
-
providerCode: readString$
|
|
6119
|
+
correlationId: readString$10(payload.correlationId),
|
|
6120
|
+
parentCorrelationId: readString$10(payload.parentCorrelationId),
|
|
6121
|
+
reasonCode: readString$10(payload.reasonCode),
|
|
6122
|
+
providerCode: readString$10(payload.providerCode),
|
|
6123
6123
|
durationMs: readOptionalNumber(payload.durationMs),
|
|
6124
6124
|
attempt: readOptionalNumber(payload.attempt),
|
|
6125
6125
|
facts: {
|
|
@@ -6263,12 +6263,12 @@ var ExtensionAuthLeaseService = class {
|
|
|
6263
6263
|
if (kind === "channel.auth.poll") {
|
|
6264
6264
|
const sessionId = readRequiredString$7(payload.sessionId, "sessionId");
|
|
6265
6265
|
const result = value ? readRecord$2(value) : null;
|
|
6266
|
-
const status = result ? readString$
|
|
6266
|
+
const status = result ? readString$10(result.status) : null;
|
|
6267
6267
|
if (status === "authorized") await this.retainHandoff(extensionId, channelId, generation);
|
|
6268
6268
|
if (!result || status === "authorized" || status === "expired" || status === "error") this.releaseSession(extensionId, sessionId);
|
|
6269
6269
|
return;
|
|
6270
6270
|
}
|
|
6271
|
-
if (kind === "channel.auth.connect" && readString$
|
|
6271
|
+
if (kind === "channel.auth.connect" && readString$10(readRecord$2(value).status) === "authorized") {
|
|
6272
6272
|
await this.retainHandoff(extensionId, channelId, generation);
|
|
6273
6273
|
return;
|
|
6274
6274
|
}
|
|
@@ -6387,7 +6387,7 @@ const BUILTIN_EXTENSION_PACKAGES = [
|
|
|
6387
6387
|
"@nextclaw/channel-extension-weixin"
|
|
6388
6388
|
];
|
|
6389
6389
|
const runtimeRequire = createRequire(import.meta.url);
|
|
6390
|
-
function readString$
|
|
6390
|
+
function readString$9(value) {
|
|
6391
6391
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6392
6392
|
}
|
|
6393
6393
|
function readStringArray$1(value) {
|
|
@@ -6436,16 +6436,16 @@ function toManifest(value, rootDir) {
|
|
|
6436
6436
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("extension manifest must be an object");
|
|
6437
6437
|
const record = value;
|
|
6438
6438
|
const server = readRecord$1(record.server);
|
|
6439
|
-
const id = readString$
|
|
6440
|
-
const command = readString$
|
|
6439
|
+
const id = readString$9(record.id);
|
|
6440
|
+
const command = readString$9(server.command);
|
|
6441
6441
|
if (!id) throw new Error("extension manifest id is required");
|
|
6442
6442
|
if (server.type !== "stdio") throw new Error("extension server.type must be stdio");
|
|
6443
6443
|
if (!command) throw new Error("extension server.command is required");
|
|
6444
6444
|
return {
|
|
6445
6445
|
id,
|
|
6446
6446
|
rootDir,
|
|
6447
|
-
...readString$
|
|
6448
|
-
...readString$
|
|
6447
|
+
...readString$9(record.name) ? { name: readString$9(record.name) } : {},
|
|
6448
|
+
...readString$9(record.version) ? { version: readString$9(record.version) } : {},
|
|
6449
6449
|
server: {
|
|
6450
6450
|
type: "stdio",
|
|
6451
6451
|
command,
|
|
@@ -6641,13 +6641,13 @@ var ExtensionObservationRuntimeService = class {
|
|
|
6641
6641
|
eventId,
|
|
6642
6642
|
eventType,
|
|
6643
6643
|
occurredAt,
|
|
6644
|
-
observedAt: readString$
|
|
6645
|
-
...readString$
|
|
6646
|
-
...readString$
|
|
6644
|
+
observedAt: readString$10(event.observedAt) ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
6645
|
+
...readString$10(event.cursor) ? { cursor: readString$10(event.cursor) } : {},
|
|
6646
|
+
...readString$10(event.dedupeKey) ? { dedupeKey: readString$10(event.dedupeKey) } : {},
|
|
6647
6647
|
payload: event.payload,
|
|
6648
6648
|
...Array.isArray(event.sourceRefs) && event.sourceRefs.every((value) => typeof value === "string") ? { sourceRefs: event.sourceRefs } : {},
|
|
6649
|
-
...readString$
|
|
6650
|
-
...readString$
|
|
6649
|
+
...readString$10(event.causationId) ? { causationId: readString$10(event.causationId) } : {},
|
|
6650
|
+
...readString$10(event.correlationId) ? { correlationId: readString$10(event.correlationId) } : {}
|
|
6651
6651
|
}
|
|
6652
6652
|
}) ?? { accepted: false };
|
|
6653
6653
|
};
|
|
@@ -6732,13 +6732,13 @@ function stableStringify(value) {
|
|
|
6732
6732
|
}
|
|
6733
6733
|
function sortValue(value) {
|
|
6734
6734
|
if (Array.isArray(value)) return value.map(sortValue);
|
|
6735
|
-
if (!isRecord$
|
|
6735
|
+
if (!isRecord$16(value)) return value;
|
|
6736
6736
|
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortValue(value[key])]));
|
|
6737
6737
|
}
|
|
6738
6738
|
function normalizeJsonValue(value) {
|
|
6739
6739
|
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return value;
|
|
6740
6740
|
if (Array.isArray(value)) return value.map(normalizeJsonValue);
|
|
6741
|
-
if (isRecord$
|
|
6741
|
+
if (isRecord$16(value)) return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalizeJsonValue(item)]));
|
|
6742
6742
|
throw new Error("Capability grant target must be JSON-compatible.");
|
|
6743
6743
|
}
|
|
6744
6744
|
function requireString$1(value, field) {
|
|
@@ -6746,7 +6746,7 @@ function requireString$1(value, field) {
|
|
|
6746
6746
|
if (!normalized) throw new Error(`Capability grant ${field} is required.`);
|
|
6747
6747
|
return normalized;
|
|
6748
6748
|
}
|
|
6749
|
-
function isRecord$
|
|
6749
|
+
function isRecord$16(value) {
|
|
6750
6750
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
6751
6751
|
}
|
|
6752
6752
|
//#endregion
|
|
@@ -7229,10 +7229,10 @@ function toGrantRecord(grants) {
|
|
|
7229
7229
|
}));
|
|
7230
7230
|
}
|
|
7231
7231
|
function normalizeStoreData(value) {
|
|
7232
|
-
if (!isRecord$
|
|
7232
|
+
if (!isRecord$15(value) || value.version !== 1 || !isRecord$15(value.grants)) throw new Error("Capability grant store is invalid.");
|
|
7233
7233
|
const grants = [];
|
|
7234
7234
|
for (const grant of Object.values(value.grants)) {
|
|
7235
|
-
if (!isRecord$
|
|
7235
|
+
if (!isRecord$15(grant) || !isRecord$15(grant.subject) || !isRecord$15(grant.resource) || !Array.isArray(grant.access) || !grant.access.every((item) => typeof item === "string") || typeof grant.declarationFingerprint !== "string" || typeof grant.grantedAt !== "string") throw new Error("Capability grant store contains an invalid grant.");
|
|
7236
7236
|
const request = normalizeCapabilityGrantRequest({
|
|
7237
7237
|
subject: {
|
|
7238
7238
|
type: String(grant.subject.type ?? ""),
|
|
@@ -7256,11 +7256,11 @@ function normalizeStoreData(value) {
|
|
|
7256
7256
|
grants: toGrantRecord(grants)
|
|
7257
7257
|
};
|
|
7258
7258
|
}
|
|
7259
|
-
function isRecord$
|
|
7259
|
+
function isRecord$15(value) {
|
|
7260
7260
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
7261
7261
|
}
|
|
7262
7262
|
function isMissingFileError$1(error) {
|
|
7263
|
-
return isRecord$
|
|
7263
|
+
return isRecord$15(error) && error.code === "ENOENT";
|
|
7264
7264
|
}
|
|
7265
7265
|
//#endregion
|
|
7266
7266
|
//#region src/features/capability-grants/managers/capability-grant.manager.ts
|
|
@@ -7764,10 +7764,10 @@ var DesktopNodeReplService = class {
|
|
|
7764
7764
|
}
|
|
7765
7765
|
async handleWorkerMessage(key, worker, value) {
|
|
7766
7766
|
const message = asRecord$1(value);
|
|
7767
|
-
const executionId = readString$
|
|
7767
|
+
const executionId = readString$8(message.executionId);
|
|
7768
7768
|
if (!executionId || !worker.pending.has(executionId)) return;
|
|
7769
7769
|
if (message.type === "desktop.request") {
|
|
7770
|
-
const requestId = readString$
|
|
7770
|
+
const requestId = readString$8(message.requestId);
|
|
7771
7771
|
if (!requestId) return;
|
|
7772
7772
|
try {
|
|
7773
7773
|
const result = await this.invokeDesktop(worker.pending.get(executionId).caller, message.operation, message.args);
|
|
@@ -7798,7 +7798,7 @@ var DesktopNodeReplService = class {
|
|
|
7798
7798
|
}
|
|
7799
7799
|
if (message.type === "error") {
|
|
7800
7800
|
const error = asRecord$1(message.error);
|
|
7801
|
-
this.reject(worker, executionId, replError(readString$
|
|
7801
|
+
this.reject(worker, executionId, replError(readString$8(error.code) ?? "repl_execution_failed", readString$8(error.message) ?? "node_repl execution failed."));
|
|
7802
7802
|
return;
|
|
7803
7803
|
}
|
|
7804
7804
|
this.stopWorker(key, worker);
|
|
@@ -7944,7 +7944,7 @@ function readKeyboardModifiers(value) {
|
|
|
7944
7944
|
if (new Set(value).size !== value.length) throw replError("invalid_tool_arguments", "modifiers cannot contain duplicates.");
|
|
7945
7945
|
return value;
|
|
7946
7946
|
}
|
|
7947
|
-
function readString$
|
|
7947
|
+
function readString$8(value) {
|
|
7948
7948
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
7949
7949
|
}
|
|
7950
7950
|
function trimOutput(value) {
|
|
@@ -8415,9 +8415,9 @@ var ExtensionDesktopRuntimeService = class {
|
|
|
8415
8415
|
method: readRequiredString$7(payload.method, "method"),
|
|
8416
8416
|
payload: readRecord$2(payload.payload),
|
|
8417
8417
|
caller: {
|
|
8418
|
-
...readString$
|
|
8419
|
-
...readString$
|
|
8420
|
-
...readString$
|
|
8418
|
+
...readString$10(caller.sessionId) ? { sessionId: readString$10(caller.sessionId) } : {},
|
|
8419
|
+
...readString$10(caller.agentRunId) ? { agentRunId: readString$10(caller.agentRunId) } : {},
|
|
8420
|
+
...readString$10(caller.subscriptionId) ? { subscriptionId: readString$10(caller.subscriptionId) } : {}
|
|
8421
8421
|
}
|
|
8422
8422
|
});
|
|
8423
8423
|
};
|
|
@@ -8558,7 +8558,7 @@ var ExtensionRuntimeService = class {
|
|
|
8558
8558
|
const desired = /* @__PURE__ */ new Map();
|
|
8559
8559
|
const channelConfig = readRecord$2(config.channels);
|
|
8560
8560
|
for (const manifest of this.manifests) for (const channel of manifest.contributes?.channels ?? []) {
|
|
8561
|
-
const channelId = readString$
|
|
8561
|
+
const channelId = readString$10(channel.id);
|
|
8562
8562
|
if (!channelId || readRecord$2(channelConfig[channelId]).enabled !== true) continue;
|
|
8563
8563
|
desired.set(this.persistentLeaseKey(manifest.id, channelId), {
|
|
8564
8564
|
manifest,
|
|
@@ -8635,15 +8635,15 @@ var ExtensionRuntimeService = class {
|
|
|
8635
8635
|
channel,
|
|
8636
8636
|
chatId,
|
|
8637
8637
|
senderId,
|
|
8638
|
-
content: readString$
|
|
8638
|
+
content: readString$10(payload.rawText) ?? readString$10(payload.commandName) ?? "",
|
|
8639
8639
|
timestamp: /* @__PURE__ */ new Date(),
|
|
8640
8640
|
attachments: [],
|
|
8641
8641
|
metadata
|
|
8642
8642
|
},
|
|
8643
|
-
forcedAgentId: readString$
|
|
8644
|
-
sessionKeyOverride: readString$
|
|
8643
|
+
forcedAgentId: readString$10(metadata.target_agent_id),
|
|
8644
|
+
sessionKeyOverride: readString$10(metadata.session_key_override)
|
|
8645
8645
|
});
|
|
8646
|
-
const rawText = readString$
|
|
8646
|
+
const rawText = readString$10(payload.rawText);
|
|
8647
8647
|
if (rawText) return await registry.executeText(rawText, {
|
|
8648
8648
|
channel,
|
|
8649
8649
|
chatId,
|
|
@@ -8676,7 +8676,7 @@ var ExtensionRuntimeService = class {
|
|
|
8676
8676
|
this.pendingRequests.delete(requestId);
|
|
8677
8677
|
pending.cleanup();
|
|
8678
8678
|
if (payload.ok === false) {
|
|
8679
|
-
const message = readString$
|
|
8679
|
+
const message = readString$10(readRecord$2(payload.error).message) ?? "Extension request failed";
|
|
8680
8680
|
pending.reject(new Error(message));
|
|
8681
8681
|
return { accepted: true };
|
|
8682
8682
|
}
|
|
@@ -8787,9 +8787,9 @@ var ExtensionRuntimeService = class {
|
|
|
8787
8787
|
};
|
|
8788
8788
|
assertAuthorized = (envelope, context) => {
|
|
8789
8789
|
const credential = this.lifecycle.authenticateCredential({
|
|
8790
|
-
extensionId: readString$
|
|
8791
|
-
generation: readString$
|
|
8792
|
-
token: readString$
|
|
8790
|
+
extensionId: readString$10(envelope.extensionId) ?? null,
|
|
8791
|
+
generation: readString$10(envelope.generation) ?? null,
|
|
8792
|
+
token: readString$10(context.token) ?? null
|
|
8793
8793
|
});
|
|
8794
8794
|
if (!credential) throw new Error("Unauthorized ingress token");
|
|
8795
8795
|
return credential;
|
|
@@ -8931,11 +8931,11 @@ var ExtensionManager = class {
|
|
|
8931
8931
|
//#endregion
|
|
8932
8932
|
//#region src/utils/model-message-vision.utils.ts
|
|
8933
8933
|
const IMAGE_OMITTED_TEXT = "[Image omitted: the selected model is not configured for vision input.]";
|
|
8934
|
-
function isRecord$
|
|
8934
|
+
function isRecord$14(value) {
|
|
8935
8935
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8936
8936
|
}
|
|
8937
8937
|
function isImageContentPart(value) {
|
|
8938
|
-
if (!isRecord$
|
|
8938
|
+
if (!isRecord$14(value)) return false;
|
|
8939
8939
|
const type = value.type;
|
|
8940
8940
|
return type === "image_url" || type === "input_image";
|
|
8941
8941
|
}
|
|
@@ -8951,7 +8951,7 @@ function normalizeContentWithoutVision(content) {
|
|
|
8951
8951
|
};
|
|
8952
8952
|
});
|
|
8953
8953
|
if (!sawImage) return content;
|
|
8954
|
-
const textParts = parts.filter((part) => isRecord$
|
|
8954
|
+
const textParts = parts.filter((part) => isRecord$14(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean);
|
|
8955
8955
|
if (textParts.length === parts.length) return textParts.join("\n\n");
|
|
8956
8956
|
return parts;
|
|
8957
8957
|
}
|
|
@@ -10510,14 +10510,14 @@ function parsePanelAppFolderManifest(raw) {
|
|
|
10510
10510
|
} catch (error) {
|
|
10511
10511
|
throw new Error(`panel-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
10512
10512
|
}
|
|
10513
|
-
if (!isRecord$
|
|
10514
|
-
const id = readOptionalString$
|
|
10513
|
+
if (!isRecord$13(parsed)) throw new Error("panel-app.json must contain an object.");
|
|
10514
|
+
const id = readOptionalString$10(parsed, "id");
|
|
10515
10515
|
if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
|
|
10516
10516
|
return {
|
|
10517
10517
|
id,
|
|
10518
10518
|
title: readRequiredString$6(parsed, "title"),
|
|
10519
|
-
description: readOptionalString$
|
|
10520
|
-
icon: readOptionalString$
|
|
10519
|
+
description: readOptionalString$10(parsed, "description"),
|
|
10520
|
+
icon: readOptionalString$10(parsed, "icon"),
|
|
10521
10521
|
entry: readRequiredString$6(parsed, "entry"),
|
|
10522
10522
|
capabilities: readStringArray(parsed.capabilities, "capabilities"),
|
|
10523
10523
|
client: readOptionalBoolean$1(parsed, "client"),
|
|
@@ -10579,11 +10579,11 @@ function parseTokenList(content) {
|
|
|
10579
10579
|
return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
|
|
10580
10580
|
}
|
|
10581
10581
|
function readRequiredString$6(record, key) {
|
|
10582
|
-
const value = readOptionalString$
|
|
10582
|
+
const value = readOptionalString$10(record, key);
|
|
10583
10583
|
if (!value) throw new Error(`panel app ${key} is required.`);
|
|
10584
10584
|
return value;
|
|
10585
10585
|
}
|
|
10586
|
-
function readOptionalString$
|
|
10586
|
+
function readOptionalString$10(record, key) {
|
|
10587
10587
|
return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
|
|
10588
10588
|
}
|
|
10589
10589
|
function readOptionalBoolean$1(record, key) {
|
|
@@ -10597,7 +10597,7 @@ function readStringArray(value, key) {
|
|
|
10597
10597
|
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(`panel app ${key} must be a string array.`);
|
|
10598
10598
|
return [...new Set(value.map((entry) => entry.trim()).filter(Boolean))];
|
|
10599
10599
|
}
|
|
10600
|
-
function isRecord$
|
|
10600
|
+
function isRecord$13(value) {
|
|
10601
10601
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
10602
10602
|
}
|
|
10603
10603
|
function normalizeTextValue(value) {
|
|
@@ -11120,7 +11120,7 @@ const PANEL_APP_AGENT_MAX_CONTEXT_CHARS = 8e4;
|
|
|
11120
11120
|
function normalizePanelAppGenerateObjectInput(input) {
|
|
11121
11121
|
const peerId = input.peerId.trim();
|
|
11122
11122
|
const prompt = input.prompt.trim();
|
|
11123
|
-
if (!peerId || !prompt || !isRecord$
|
|
11123
|
+
if (!peerId || !prompt || !isRecord$12(input.schema)) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "invalid generateObject request");
|
|
11124
11124
|
if (prompt.length > PANEL_APP_AGENT_MAX_PROMPT_CHARS) throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "generateObject prompt is too large");
|
|
11125
11125
|
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");
|
|
11126
11126
|
return {
|
|
@@ -11261,7 +11261,7 @@ function readStructuredResultEvent(event, resultToolCallId) {
|
|
|
11261
11261
|
};
|
|
11262
11262
|
}
|
|
11263
11263
|
function assertToolResultContent(content) {
|
|
11264
|
-
if (!isRecord$
|
|
11264
|
+
if (!isRecord$12(content) || content.ok !== false || !isRecord$12(content.error)) return;
|
|
11265
11265
|
if (content.error.code === "invalid_tool_arguments") throw new PanelAppError("AGENT_OBJECT_RESULT_SCHEMA_INVALID", "agent object result did not match the schema");
|
|
11266
11266
|
throw new PanelAppError("AGENT_OBJECT_REQUEST_FAILED", typeof content.error.message === "string" ? content.error.message : "agent object request failed");
|
|
11267
11267
|
}
|
|
@@ -11277,7 +11277,7 @@ function stringifyJsonValue(value) {
|
|
|
11277
11277
|
throw new PanelAppError("PANEL_APP_AGENT_REQUEST_INVALID", "value is not JSON serializable");
|
|
11278
11278
|
}
|
|
11279
11279
|
}
|
|
11280
|
-
function isRecord$
|
|
11280
|
+
function isRecord$12(value) {
|
|
11281
11281
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
11282
11282
|
}
|
|
11283
11283
|
//#endregion
|
|
@@ -12701,12 +12701,12 @@ function parseSkillFrontmatter(raw) {
|
|
|
12701
12701
|
const summaryI18n = readLocalizedTextMap(parsed, "summaryi18n", "summary_i18n");
|
|
12702
12702
|
const descriptionI18n = readLocalizedTextMap(parsed, "descriptioni18n", "description_i18n");
|
|
12703
12703
|
return {
|
|
12704
|
-
name: readString$
|
|
12705
|
-
summary: readString$
|
|
12706
|
-
summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$
|
|
12707
|
-
description: readString$
|
|
12708
|
-
descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$
|
|
12709
|
-
author: readString$
|
|
12704
|
+
name: readString$7(parsed, "name"),
|
|
12705
|
+
summary: readString$7(parsed, "summary"),
|
|
12706
|
+
summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$7(parsed, "summaryzh", "summary_zh") }),
|
|
12707
|
+
description: readString$7(parsed, "description"),
|
|
12708
|
+
descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$7(parsed, "descriptionzh", "description_zh") }),
|
|
12709
|
+
author: readString$7(parsed, "author"),
|
|
12710
12710
|
tags: readTags(parsed)
|
|
12711
12711
|
};
|
|
12712
12712
|
}
|
|
@@ -12727,19 +12727,19 @@ function parseFrontmatterBlock(raw) {
|
|
|
12727
12727
|
function parseYamlFrontmatter(raw) {
|
|
12728
12728
|
try {
|
|
12729
12729
|
const parsed = parse(raw);
|
|
12730
|
-
return isRecord$
|
|
12730
|
+
return isRecord$11(parsed) ? parsed : {};
|
|
12731
12731
|
} catch (error) {
|
|
12732
12732
|
const message = error instanceof Error ? error.message : String(error);
|
|
12733
12733
|
throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
|
|
12734
12734
|
}
|
|
12735
12735
|
}
|
|
12736
|
-
function readString$
|
|
12736
|
+
function readString$7(record, ...names) {
|
|
12737
12737
|
const value = readValue(record, names);
|
|
12738
12738
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
12739
12739
|
}
|
|
12740
12740
|
function readLocalizedTextMap(record, ...names) {
|
|
12741
12741
|
const value = readValue(record, names);
|
|
12742
|
-
if (!isRecord$
|
|
12742
|
+
if (!isRecord$11(value)) return;
|
|
12743
12743
|
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()]));
|
|
12744
12744
|
return Object.keys(localized).length > 0 ? localized : void 0;
|
|
12745
12745
|
}
|
|
@@ -12763,7 +12763,7 @@ function normalizeFrontmatterKey(raw) {
|
|
|
12763
12763
|
function normalizeLocaleTag(raw) {
|
|
12764
12764
|
return raw.trim().toLowerCase();
|
|
12765
12765
|
}
|
|
12766
|
-
function isRecord$
|
|
12766
|
+
function isRecord$11(value) {
|
|
12767
12767
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12768
12768
|
}
|
|
12769
12769
|
//#endregion
|
|
@@ -12983,11 +12983,11 @@ function createAgentPeerSessionIdentity(params) {
|
|
|
12983
12983
|
}
|
|
12984
12984
|
function resolveAgentPeerScope(params) {
|
|
12985
12985
|
const metadata = params.metadata ?? {};
|
|
12986
|
-
const explicitScope = readOptionalString$
|
|
12986
|
+
const explicitScope = readOptionalString$9(metadata["agent_peer_scope"]) ?? readOptionalString$9(metadata.agentPeerScope);
|
|
12987
12987
|
if (explicitScope) return explicitScope;
|
|
12988
|
-
return `agent:${readOptionalString$
|
|
12988
|
+
return `agent:${readOptionalString$9(params.agentId) ?? BUILTIN_MAIN_AGENT_ID}:${readOptionalString$9(params.channel) ?? readOptionalString$9(metadata.channel) ?? "agent-run"}:${readOptionalString$9(metadata.accountId) ?? readOptionalString$9(metadata.account_id) ?? "default"}`;
|
|
12989
12989
|
}
|
|
12990
|
-
function readOptionalString$
|
|
12990
|
+
function readOptionalString$9(value) {
|
|
12991
12991
|
if (typeof value !== "string") return;
|
|
12992
12992
|
return value.trim() || void 0;
|
|
12993
12993
|
}
|
|
@@ -13047,20 +13047,20 @@ function readEventMessageId(event) {
|
|
|
13047
13047
|
if (event.type === "session.snapshot.message") return null;
|
|
13048
13048
|
const streamingMessageId = readStreamingMessageId(event);
|
|
13049
13049
|
if (streamingMessageId) return streamingMessageId;
|
|
13050
|
-
const messageId = ("payload" in event && isRecord$
|
|
13050
|
+
const messageId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.messageId;
|
|
13051
13051
|
if (typeof messageId === "string" && messageId.trim()) return messageId.trim();
|
|
13052
13052
|
return null;
|
|
13053
13053
|
}
|
|
13054
13054
|
function readEventRunId(event) {
|
|
13055
13055
|
if (isJournalOnlyEvent(event)) return null;
|
|
13056
13056
|
if (event.type === "session.snapshot.message") return null;
|
|
13057
|
-
const runId = ("payload" in event && isRecord$
|
|
13057
|
+
const runId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.runId;
|
|
13058
13058
|
if (typeof runId === "string" && runId.trim()) return runId.trim();
|
|
13059
13059
|
return null;
|
|
13060
13060
|
}
|
|
13061
13061
|
function readEventToolCallId(event) {
|
|
13062
13062
|
if (isJournalOnlyEvent(event)) return null;
|
|
13063
|
-
const toolCallId = ("payload" in event && isRecord$
|
|
13063
|
+
const toolCallId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.toolCallId;
|
|
13064
13064
|
return typeof toolCallId === "string" && toolCallId.trim() ? toolCallId.trim() : null;
|
|
13065
13065
|
}
|
|
13066
13066
|
function createReplayEvent(event, toolResultsByCallId) {
|
|
@@ -13105,7 +13105,7 @@ function mergeReplayCompletedToolResults(message, toolResultsByCallId) {
|
|
|
13105
13105
|
} : message;
|
|
13106
13106
|
}
|
|
13107
13107
|
function readLegacyContextCompactionMessageId(message) {
|
|
13108
|
-
const checkpoint = isRecord$
|
|
13108
|
+
const checkpoint = isRecord$10(message?.metadata?.checkpoint) ? message.metadata.checkpoint : null;
|
|
13109
13109
|
const checkpointId = typeof checkpoint?.id === "string" ? checkpoint.id : "";
|
|
13110
13110
|
const coveredCount = checkpoint?.coveredSessionMessageCount;
|
|
13111
13111
|
const legacyId = `${message?.sessionId}:service:context-compaction:${checkpointId}`;
|
|
@@ -13137,11 +13137,11 @@ function readReplayMessageId(event) {
|
|
|
13137
13137
|
return readMessageFromSummaryEvent$1(event)?.id ?? null;
|
|
13138
13138
|
}
|
|
13139
13139
|
function readEventSessionId$1(event) {
|
|
13140
|
-
const sessionId = ("payload" in event && isRecord$
|
|
13140
|
+
const sessionId = ("payload" in event && isRecord$10(event.payload) ? event.payload : null)?.sessionId;
|
|
13141
13141
|
return typeof sessionId === "string" ? sessionId : "";
|
|
13142
13142
|
}
|
|
13143
13143
|
function readReplayPayloadTimestamp(event) {
|
|
13144
|
-
const payload = "payload" in event && isRecord$
|
|
13144
|
+
const payload = "payload" in event && isRecord$10(event.payload) ? event.payload : null;
|
|
13145
13145
|
const timestamp = typeof payload?.timestamp === "string" ? payload.timestamp : "";
|
|
13146
13146
|
return Number.isFinite(Date.parse(timestamp)) ? new Date(timestamp).toISOString() : null;
|
|
13147
13147
|
}
|
|
@@ -13162,7 +13162,7 @@ function readStreamingMessageId(event) {
|
|
|
13162
13162
|
function isJournalOnlyEvent(event) {
|
|
13163
13163
|
return event.type === "session.request.accepted" || event.type === "session.request.completed" || event.type === "session.request.failed";
|
|
13164
13164
|
}
|
|
13165
|
-
function isRecord$
|
|
13165
|
+
function isRecord$10(value) {
|
|
13166
13166
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13167
13167
|
}
|
|
13168
13168
|
function readMessageFromSummaryEvent$1(event) {
|
|
@@ -13269,7 +13269,7 @@ function safeNcpSessionFilename(value) {
|
|
|
13269
13269
|
function normalizeNcpAgentId(agentId) {
|
|
13270
13270
|
return agentId?.trim().toLowerCase() || void 0;
|
|
13271
13271
|
}
|
|
13272
|
-
function isRecord$
|
|
13272
|
+
function isRecord$9(value) {
|
|
13273
13273
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13274
13274
|
}
|
|
13275
13275
|
function toIsoString(value, fallback) {
|
|
@@ -13756,211 +13756,6 @@ var FeatureControlsService = class {
|
|
|
13756
13756
|
};
|
|
13757
13757
|
};
|
|
13758
13758
|
//#endregion
|
|
13759
|
-
//#region src/types/session.types.ts
|
|
13760
|
-
var SessionMessageCursorError = class extends Error {
|
|
13761
|
-
constructor(message = "Invalid session message cursor.") {
|
|
13762
|
-
super(message);
|
|
13763
|
-
this.name = "SessionMessageCursorError";
|
|
13764
|
-
}
|
|
13765
|
-
};
|
|
13766
|
-
function isSessionMessageCursorError(error) {
|
|
13767
|
-
return error instanceof SessionMessageCursorError;
|
|
13768
|
-
}
|
|
13769
|
-
var SessionSettingsError = class extends Error {
|
|
13770
|
-
constructor(code, message) {
|
|
13771
|
-
super(message);
|
|
13772
|
-
this.code = code;
|
|
13773
|
-
this.name = "SessionSettingsError";
|
|
13774
|
-
}
|
|
13775
|
-
};
|
|
13776
|
-
function isSessionSettingsError(error) {
|
|
13777
|
-
return error instanceof SessionSettingsError;
|
|
13778
|
-
}
|
|
13779
|
-
//#endregion
|
|
13780
|
-
//#region src/utils/session-manager.utils.ts
|
|
13781
|
-
function hasPatchField(patch, field) {
|
|
13782
|
-
return Object.prototype.hasOwnProperty.call(patch, field);
|
|
13783
|
-
}
|
|
13784
|
-
function readPatchString(value) {
|
|
13785
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
13786
|
-
}
|
|
13787
|
-
function setOptionalMetadataValue(metadata, key, value) {
|
|
13788
|
-
const normalized = readPatchString(value);
|
|
13789
|
-
if (normalized) return {
|
|
13790
|
-
...metadata,
|
|
13791
|
-
[key]: normalized
|
|
13792
|
-
};
|
|
13793
|
-
const nextMetadata = { ...metadata };
|
|
13794
|
-
delete nextMetadata[key];
|
|
13795
|
-
return nextMetadata;
|
|
13796
|
-
}
|
|
13797
|
-
function applySessionPreferencePatch(metadata, patch) {
|
|
13798
|
-
let nextMetadata = metadata;
|
|
13799
|
-
if (hasPatchField(patch, "label")) nextMetadata = setOptionalMetadataValue(nextMetadata, "label", patch.label);
|
|
13800
|
-
if (hasPatchField(patch, "preferredModel")) {
|
|
13801
|
-
const model = readPatchString(patch.preferredModel);
|
|
13802
|
-
nextMetadata = setOptionalMetadataValue(nextMetadata, "preferred_model", model);
|
|
13803
|
-
nextMetadata = setOptionalMetadataValue(nextMetadata, "model", model);
|
|
13804
|
-
}
|
|
13805
|
-
if (!hasPatchField(patch, "preferredThinking")) return nextMetadata;
|
|
13806
|
-
const thinking = readPatchString(patch.preferredThinking);
|
|
13807
|
-
if (!thinking) {
|
|
13808
|
-
const { preferred_thinking: _removed, ...remainingMetadata } = nextMetadata;
|
|
13809
|
-
return remainingMetadata;
|
|
13810
|
-
}
|
|
13811
|
-
const normalizedThinking = parseThinkingLevel(thinking);
|
|
13812
|
-
if (!normalizedThinking) throw new SessionSettingsError("PREFERRED_THINKING_INVALID", "preferredThinking must be a supported thinking level");
|
|
13813
|
-
return {
|
|
13814
|
-
...nextMetadata,
|
|
13815
|
-
preferred_thinking: normalizedThinking
|
|
13816
|
-
};
|
|
13817
|
-
}
|
|
13818
|
-
function applySessionRuntimePatch(metadata, patch) {
|
|
13819
|
-
let nextMetadata = metadata;
|
|
13820
|
-
if (hasPatchField(patch, "sessionType")) {
|
|
13821
|
-
const sessionType = readPatchString(patch.sessionType);
|
|
13822
|
-
const { sessionType: _removed, ...metadataWithoutCamelSessionType } = nextMetadata;
|
|
13823
|
-
if (sessionType) nextMetadata = {
|
|
13824
|
-
...metadataWithoutCamelSessionType,
|
|
13825
|
-
session_type: sessionType,
|
|
13826
|
-
runtime: sessionType
|
|
13827
|
-
};
|
|
13828
|
-
else {
|
|
13829
|
-
const { runtime: _runtime, session_type: _sessionType, ...metadataWithoutSessionType } = metadataWithoutCamelSessionType;
|
|
13830
|
-
nextMetadata = metadataWithoutSessionType;
|
|
13831
|
-
}
|
|
13832
|
-
}
|
|
13833
|
-
if (hasPatchField(patch, "uiReadAt")) nextMetadata = setOptionalMetadataValue(nextMetadata, "ui_last_read_at", patch.uiReadAt);
|
|
13834
|
-
return nextMetadata;
|
|
13835
|
-
}
|
|
13836
|
-
function applySessionSettingsMetadataPatch(currentMetadata, patch) {
|
|
13837
|
-
return applySessionRuntimePatch(applySessionPreferencePatch(structuredClone(currentMetadata), patch), patch);
|
|
13838
|
-
}
|
|
13839
|
-
async function applySessionProjectMetadataPatch(metadata, patch, normalizeProjectContext) {
|
|
13840
|
-
if (!Object.prototype.hasOwnProperty.call(patch, "projectRoot")) return metadata;
|
|
13841
|
-
const project = await normalizeProjectContext(patch.projectRoot);
|
|
13842
|
-
const { projectRoot: _legacyProjectRoot, projectId: _legacyProjectId, project_root: _projectRoot, project_id: _projectId, ...nextMetadata } = metadata;
|
|
13843
|
-
return project ? {
|
|
13844
|
-
...nextMetadata,
|
|
13845
|
-
project_id: project.projectId,
|
|
13846
|
-
project_root: project.rootPath
|
|
13847
|
-
} : nextMetadata;
|
|
13848
|
-
}
|
|
13849
|
-
function publishSessionMetadataChanged(eventBus, sessionKey, metadata, mode) {
|
|
13850
|
-
eventBus.emit(eventKeys$1.sessionMetadataChanged, {
|
|
13851
|
-
sessionKey,
|
|
13852
|
-
mode,
|
|
13853
|
-
metadata: structuredClone(metadata)
|
|
13854
|
-
}, {
|
|
13855
|
-
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13856
|
-
source: "ncp-session"
|
|
13857
|
-
});
|
|
13858
|
-
}
|
|
13859
|
-
function normalizeSessionId(sessionId) {
|
|
13860
|
-
return sessionId.trim();
|
|
13861
|
-
}
|
|
13862
|
-
function buildSessionId() {
|
|
13863
|
-
return `ncp-${Date.now().toString(36)}-${randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
13864
|
-
}
|
|
13865
|
-
function isSessionSummaryRefreshEvent(event) {
|
|
13866
|
-
switch (event.type) {
|
|
13867
|
-
case NcpEventType.MessageSent:
|
|
13868
|
-
case NcpEventType.MessageCompleted:
|
|
13869
|
-
case NcpEventType.MessageAbort:
|
|
13870
|
-
case NcpEventType.RunFinished:
|
|
13871
|
-
case NcpEventType.RunError: return true;
|
|
13872
|
-
default: return false;
|
|
13873
|
-
}
|
|
13874
|
-
}
|
|
13875
|
-
function applyLimit(items, limit) {
|
|
13876
|
-
if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
|
|
13877
|
-
return items.slice(0, Math.trunc(limit));
|
|
13878
|
-
}
|
|
13879
|
-
function readOptionalString$10(value) {
|
|
13880
|
-
if (typeof value !== "string") return null;
|
|
13881
|
-
const trimmed = value.trim();
|
|
13882
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
13883
|
-
}
|
|
13884
|
-
function readOptionalMetadataString(value) {
|
|
13885
|
-
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
13886
|
-
}
|
|
13887
|
-
function readEventSessionId(event) {
|
|
13888
|
-
return "payload" in event && "sessionId" in event.payload ? readOptionalMetadataString(event.payload.sessionId) : void 0;
|
|
13889
|
-
}
|
|
13890
|
-
const DEFAULT_SESSION_LIFECYCLE = "persistent";
|
|
13891
|
-
const SESSION_METADATA_LABEL_KEY = "label";
|
|
13892
|
-
const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
|
|
13893
|
-
const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
|
|
13894
|
-
const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
|
|
13895
|
-
async function assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, getSessionRecord) {
|
|
13896
|
-
if (Object.prototype.hasOwnProperty.call(metadataOverrides ?? {}, CHILD_SESSION_PARENT_METADATA_KEY)) throw new Error("Session parent must be set through parentSessionId.");
|
|
13897
|
-
if (readOptionalMetadataString(sourceRecord?.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Source session: ${sourceRecord?.sessionId}.`);
|
|
13898
|
-
if (!parentSessionId) return;
|
|
13899
|
-
const parentRecord = sourceRecord?.sessionId === parentSessionId ? sourceRecord : await getSessionRecord(parentSessionId);
|
|
13900
|
-
if (!parentRecord) throw new Error(`Parent session not found: ${parentSessionId}`);
|
|
13901
|
-
if (readOptionalMetadataString(parentRecord.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Parent session: ${parentSessionId}.`);
|
|
13902
|
-
}
|
|
13903
|
-
function readThinkingEffort(metadata) {
|
|
13904
|
-
return readOptionalMetadataString(metadata?.thinkingEffort) ?? readOptionalMetadataString(metadata?.preferred_thinking) ?? readOptionalMetadataString(metadata?.thinking) ?? null;
|
|
13905
|
-
}
|
|
13906
|
-
function readProjectRoot(metadata) {
|
|
13907
|
-
return readOptionalMetadataString(metadata?.project_root) ?? readOptionalMetadataString(metadata?.projectRoot);
|
|
13908
|
-
}
|
|
13909
|
-
function readProjectId(metadata) {
|
|
13910
|
-
return readOptionalMetadataString(metadata?.project_id) ?? readOptionalMetadataString(metadata?.projectId);
|
|
13911
|
-
}
|
|
13912
|
-
function readAgentRuntimeId(metadata) {
|
|
13913
|
-
return readOptionalMetadataString(metadata?.agentRuntimeId) ?? readOptionalMetadataString(metadata?.runtime) ?? readOptionalMetadataString(metadata?.session_type);
|
|
13914
|
-
}
|
|
13915
|
-
function summarizeTask(task) {
|
|
13916
|
-
const normalized = task.trim().replace(/\s+/g, " ");
|
|
13917
|
-
if (!normalized) return "Session";
|
|
13918
|
-
return normalized.length <= 72 ? normalized : `${normalized.slice(0, 69)}...`;
|
|
13919
|
-
}
|
|
13920
|
-
function cloneInheritedMetadata(sourceMetadata) {
|
|
13921
|
-
const nextMetadata = {};
|
|
13922
|
-
for (const key of [
|
|
13923
|
-
"runtime",
|
|
13924
|
-
"session_type",
|
|
13925
|
-
"preferred_model",
|
|
13926
|
-
"preferred_thinking",
|
|
13927
|
-
"project_root",
|
|
13928
|
-
"project_id",
|
|
13929
|
-
"codex_runtime_backend",
|
|
13930
|
-
"reasoningNormalizationMode",
|
|
13931
|
-
"reasoning_normalization_mode"
|
|
13932
|
-
]) if (Object.prototype.hasOwnProperty.call(sourceMetadata, key)) nextMetadata[key] = structuredClone(sourceMetadata[key]);
|
|
13933
|
-
return nextMetadata;
|
|
13934
|
-
}
|
|
13935
|
-
function mergeMetadataOverrides(metadata, overrides) {
|
|
13936
|
-
return overrides && Object.keys(overrides).length > 0 ? {
|
|
13937
|
-
...metadata,
|
|
13938
|
-
...structuredClone(overrides)
|
|
13939
|
-
} : metadata;
|
|
13940
|
-
}
|
|
13941
|
-
function resolveSessionType(params) {
|
|
13942
|
-
const { metadata, runtime, sessionType } = params;
|
|
13943
|
-
return readOptionalString$10(runtime) ?? readOptionalString$10(metadata.runtime) ?? readOptionalString$10(sessionType) ?? readOptionalString$10(metadata.session_type) ?? "native";
|
|
13944
|
-
}
|
|
13945
|
-
function applySessionOverrides(params) {
|
|
13946
|
-
const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
|
|
13947
|
-
metadata.session_type = sessionType;
|
|
13948
|
-
metadata.runtime = sessionType;
|
|
13949
|
-
metadata[SESSION_METADATA_LABEL_KEY] = title;
|
|
13950
|
-
metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
|
|
13951
|
-
if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
|
|
13952
|
-
if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
|
|
13953
|
-
if (readOptionalString$10(model)) {
|
|
13954
|
-
metadata.model = model?.trim();
|
|
13955
|
-
metadata.preferred_model = model?.trim();
|
|
13956
|
-
}
|
|
13957
|
-
if (readOptionalString$10(thinkingLevel)) {
|
|
13958
|
-
metadata.thinking = thinkingLevel?.trim();
|
|
13959
|
-
metadata.preferred_thinking = thinkingLevel?.trim();
|
|
13960
|
-
}
|
|
13961
|
-
if (readOptionalString$10(projectRoot)) metadata.project_root = projectRoot?.trim();
|
|
13962
|
-
}
|
|
13963
|
-
//#endregion
|
|
13964
13759
|
//#region src/app/kernel-storage-paths.ts
|
|
13965
13760
|
function resolveKernelAppHomeDirectory(options) {
|
|
13966
13761
|
const homeDir = options.homeDir?.trim();
|
|
@@ -13976,10 +13771,10 @@ function resolveKernelAutomationStorePath(options) {
|
|
|
13976
13771
|
function resolveKernelPreferenceStorePath(options) {
|
|
13977
13772
|
return resolveKernelDataPath(options, "preferences", "preferences.json");
|
|
13978
13773
|
}
|
|
13979
|
-
function
|
|
13774
|
+
function resolveKernelLegacyProjectStorePath(options) {
|
|
13980
13775
|
return resolveKernelDataPath(options, "projects", "projects.json");
|
|
13981
13776
|
}
|
|
13982
|
-
function
|
|
13777
|
+
function resolveKernelProjectDatabasePath(options) {
|
|
13983
13778
|
return resolveKernelDataPath(options, "projects", "work-items.db");
|
|
13984
13779
|
}
|
|
13985
13780
|
function resolveKernelInboxDeliveryStorePath(options) {
|
|
@@ -16252,7 +16047,7 @@ var ServiceAppAiCapabilityService = class {
|
|
|
16252
16047
|
const payload = requireHostCallObject(call.request.input);
|
|
16253
16048
|
if (call.request.capability === "model-complete") {
|
|
16254
16049
|
const messages = payload.messages;
|
|
16255
|
-
if (!Array.isArray(messages) || !messages.every(isRecord$
|
|
16050
|
+
if (!Array.isArray(messages) || !messages.every(isRecord$8)) throw new ServiceAppError("SERVICE_APP_RUNTIME_FAILED", "AI model messages must be an array of objects.");
|
|
16256
16051
|
return await this.modelComplete({
|
|
16257
16052
|
app: call.app,
|
|
16258
16053
|
manifest: call.manifest,
|
|
@@ -16264,7 +16059,7 @@ var ServiceAppAiCapabilityService = class {
|
|
|
16264
16059
|
}
|
|
16265
16060
|
if (call.request.capability === "agent-start") {
|
|
16266
16061
|
const input = payload.input;
|
|
16267
|
-
if (!isRecord$
|
|
16062
|
+
if (!isRecord$8(input)) throw new ServiceAppError("SERVICE_APP_RUNTIME_FAILED", "AI Agent input must be an object.");
|
|
16268
16063
|
const execution = await this.agentStart({
|
|
16269
16064
|
app: call.app,
|
|
16270
16065
|
manifest: call.manifest,
|
|
@@ -16389,11 +16184,11 @@ var ServiceAppAiCapabilityService = class {
|
|
|
16389
16184
|
};
|
|
16390
16185
|
};
|
|
16391
16186
|
};
|
|
16392
|
-
function isRecord$
|
|
16187
|
+
function isRecord$8(value) {
|
|
16393
16188
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16394
16189
|
}
|
|
16395
16190
|
function requireHostCallObject(value) {
|
|
16396
|
-
if (!isRecord$
|
|
16191
|
+
if (!isRecord$8(value)) throw new ServiceAppError("SERVICE_APP_RUNTIME_FAILED", "Portable host call input must be an object.");
|
|
16397
16192
|
return value;
|
|
16398
16193
|
}
|
|
16399
16194
|
function requireHostCallString(value, key) {
|
|
@@ -18824,24 +18619,229 @@ var PortableRuntimeAcceptanceManager = class {
|
|
|
18824
18619
|
});
|
|
18825
18620
|
};
|
|
18826
18621
|
//#endregion
|
|
18827
|
-
//#region src/
|
|
18828
|
-
|
|
18829
|
-
|
|
18830
|
-
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
}
|
|
18834
|
-
function
|
|
18835
|
-
|
|
18836
|
-
if (!anchorToolCallId) return null;
|
|
18837
|
-
const index = params.messages.findIndex((message) => hasToolCall(message, anchorToolCallId));
|
|
18838
|
-
const message = index >= 0 ? params.messages[index] : void 0;
|
|
18839
|
-
return message ? {
|
|
18840
|
-
index,
|
|
18841
|
-
message
|
|
18842
|
-
} : null;
|
|
18622
|
+
//#region src/types/session.types.ts
|
|
18623
|
+
var SessionMessageCursorError = class extends Error {
|
|
18624
|
+
constructor(message = "Invalid session message cursor.") {
|
|
18625
|
+
super(message);
|
|
18626
|
+
this.name = "SessionMessageCursorError";
|
|
18627
|
+
}
|
|
18628
|
+
};
|
|
18629
|
+
function isSessionMessageCursorError(error) {
|
|
18630
|
+
return error instanceof SessionMessageCursorError;
|
|
18843
18631
|
}
|
|
18844
|
-
|
|
18632
|
+
var SessionSettingsError = class extends Error {
|
|
18633
|
+
constructor(code, message) {
|
|
18634
|
+
super(message);
|
|
18635
|
+
this.code = code;
|
|
18636
|
+
this.name = "SessionSettingsError";
|
|
18637
|
+
}
|
|
18638
|
+
};
|
|
18639
|
+
function isSessionSettingsError(error) {
|
|
18640
|
+
return error instanceof SessionSettingsError;
|
|
18641
|
+
}
|
|
18642
|
+
//#endregion
|
|
18643
|
+
//#region src/utils/session-manager.utils.ts
|
|
18644
|
+
function hasPatchField(patch, field) {
|
|
18645
|
+
return Object.prototype.hasOwnProperty.call(patch, field);
|
|
18646
|
+
}
|
|
18647
|
+
function readPatchString(value) {
|
|
18648
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
18649
|
+
}
|
|
18650
|
+
function setOptionalMetadataValue(metadata, key, value) {
|
|
18651
|
+
const normalized = readPatchString(value);
|
|
18652
|
+
if (normalized) return {
|
|
18653
|
+
...metadata,
|
|
18654
|
+
[key]: normalized
|
|
18655
|
+
};
|
|
18656
|
+
const nextMetadata = { ...metadata };
|
|
18657
|
+
delete nextMetadata[key];
|
|
18658
|
+
return nextMetadata;
|
|
18659
|
+
}
|
|
18660
|
+
function applySessionPreferencePatch(metadata, patch) {
|
|
18661
|
+
let nextMetadata = metadata;
|
|
18662
|
+
if (hasPatchField(patch, "label")) nextMetadata = setOptionalMetadataValue(nextMetadata, "label", patch.label);
|
|
18663
|
+
if (hasPatchField(patch, "preferredModel")) {
|
|
18664
|
+
const model = readPatchString(patch.preferredModel);
|
|
18665
|
+
nextMetadata = setOptionalMetadataValue(nextMetadata, "preferred_model", model);
|
|
18666
|
+
nextMetadata = setOptionalMetadataValue(nextMetadata, "model", model);
|
|
18667
|
+
}
|
|
18668
|
+
if (!hasPatchField(patch, "preferredThinking")) return nextMetadata;
|
|
18669
|
+
const thinking = readPatchString(patch.preferredThinking);
|
|
18670
|
+
if (!thinking) {
|
|
18671
|
+
const { preferred_thinking: _removed, ...remainingMetadata } = nextMetadata;
|
|
18672
|
+
return remainingMetadata;
|
|
18673
|
+
}
|
|
18674
|
+
const normalizedThinking = parseThinkingLevel(thinking);
|
|
18675
|
+
if (!normalizedThinking) throw new SessionSettingsError("PREFERRED_THINKING_INVALID", "preferredThinking must be a supported thinking level");
|
|
18676
|
+
return {
|
|
18677
|
+
...nextMetadata,
|
|
18678
|
+
preferred_thinking: normalizedThinking
|
|
18679
|
+
};
|
|
18680
|
+
}
|
|
18681
|
+
function applySessionRuntimePatch(metadata, patch) {
|
|
18682
|
+
let nextMetadata = metadata;
|
|
18683
|
+
if (hasPatchField(patch, "sessionType")) {
|
|
18684
|
+
const sessionType = readPatchString(patch.sessionType);
|
|
18685
|
+
const { sessionType: _removed, ...metadataWithoutCamelSessionType } = nextMetadata;
|
|
18686
|
+
if (sessionType) nextMetadata = {
|
|
18687
|
+
...metadataWithoutCamelSessionType,
|
|
18688
|
+
session_type: sessionType,
|
|
18689
|
+
runtime: sessionType
|
|
18690
|
+
};
|
|
18691
|
+
else {
|
|
18692
|
+
const { runtime: _runtime, session_type: _sessionType, ...metadataWithoutSessionType } = metadataWithoutCamelSessionType;
|
|
18693
|
+
nextMetadata = metadataWithoutSessionType;
|
|
18694
|
+
}
|
|
18695
|
+
}
|
|
18696
|
+
if (hasPatchField(patch, "uiReadAt")) nextMetadata = setOptionalMetadataValue(nextMetadata, "ui_last_read_at", patch.uiReadAt);
|
|
18697
|
+
return nextMetadata;
|
|
18698
|
+
}
|
|
18699
|
+
function applySessionSettingsMetadataPatch(currentMetadata, patch) {
|
|
18700
|
+
return applySessionRuntimePatch(applySessionPreferencePatch(structuredClone(currentMetadata), patch), patch);
|
|
18701
|
+
}
|
|
18702
|
+
async function applySessionProjectMetadataPatch(metadata, patch, normalizeProjectContext) {
|
|
18703
|
+
if (!Object.prototype.hasOwnProperty.call(patch, "projectRoot")) return metadata;
|
|
18704
|
+
const project = await normalizeProjectContext(patch.projectRoot);
|
|
18705
|
+
const { projectRoot: _legacyProjectRoot, projectId: _legacyProjectId, project_root: _projectRoot, project_id: _projectId, ...nextMetadata } = metadata;
|
|
18706
|
+
return project ? {
|
|
18707
|
+
...nextMetadata,
|
|
18708
|
+
project_id: project.projectId,
|
|
18709
|
+
project_root: project.rootPath
|
|
18710
|
+
} : nextMetadata;
|
|
18711
|
+
}
|
|
18712
|
+
function publishSessionMetadataChanged(eventBus, sessionKey, metadata, mode) {
|
|
18713
|
+
eventBus.emit(eventKeys$1.sessionMetadataChanged, {
|
|
18714
|
+
sessionKey,
|
|
18715
|
+
mode,
|
|
18716
|
+
metadata: structuredClone(metadata)
|
|
18717
|
+
}, {
|
|
18718
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18719
|
+
source: "ncp-session"
|
|
18720
|
+
});
|
|
18721
|
+
}
|
|
18722
|
+
function normalizeSessionId(sessionId) {
|
|
18723
|
+
return sessionId.trim();
|
|
18724
|
+
}
|
|
18725
|
+
function buildSessionId() {
|
|
18726
|
+
return `ncp-${Date.now().toString(36)}-${randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
18727
|
+
}
|
|
18728
|
+
function isSessionSummaryRefreshEvent(event) {
|
|
18729
|
+
switch (event.type) {
|
|
18730
|
+
case NcpEventType.MessageSent:
|
|
18731
|
+
case NcpEventType.MessageCompleted:
|
|
18732
|
+
case NcpEventType.MessageAbort:
|
|
18733
|
+
case NcpEventType.RunFinished:
|
|
18734
|
+
case NcpEventType.RunError: return true;
|
|
18735
|
+
default: return false;
|
|
18736
|
+
}
|
|
18737
|
+
}
|
|
18738
|
+
function applyLimit(items, limit) {
|
|
18739
|
+
if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
|
|
18740
|
+
return items.slice(0, Math.trunc(limit));
|
|
18741
|
+
}
|
|
18742
|
+
function readOptionalString$8(value) {
|
|
18743
|
+
if (typeof value !== "string") return null;
|
|
18744
|
+
const trimmed = value.trim();
|
|
18745
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
18746
|
+
}
|
|
18747
|
+
function readOptionalMetadataString(value) {
|
|
18748
|
+
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
18749
|
+
}
|
|
18750
|
+
function readEventSessionId(event) {
|
|
18751
|
+
return "payload" in event && "sessionId" in event.payload ? readOptionalMetadataString(event.payload.sessionId) : void 0;
|
|
18752
|
+
}
|
|
18753
|
+
const DEFAULT_SESSION_LIFECYCLE = "persistent";
|
|
18754
|
+
const SESSION_METADATA_LABEL_KEY = "label";
|
|
18755
|
+
const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
|
|
18756
|
+
const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
|
|
18757
|
+
const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
|
|
18758
|
+
async function assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, getSessionRecord) {
|
|
18759
|
+
if (Object.prototype.hasOwnProperty.call(metadataOverrides ?? {}, CHILD_SESSION_PARENT_METADATA_KEY)) throw new Error("Session parent must be set through parentSessionId.");
|
|
18760
|
+
if (readOptionalMetadataString(sourceRecord?.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Source session: ${sourceRecord?.sessionId}.`);
|
|
18761
|
+
if (!parentSessionId) return;
|
|
18762
|
+
const parentRecord = sourceRecord?.sessionId === parentSessionId ? sourceRecord : await getSessionRecord(parentSessionId);
|
|
18763
|
+
if (!parentRecord) throw new Error(`Parent session not found: ${parentSessionId}`);
|
|
18764
|
+
if (readOptionalMetadataString(parentRecord.metadata?.[CHILD_SESSION_PARENT_METADATA_KEY])) throw new Error(`Child sessions cannot create additional sessions. Parent session: ${parentSessionId}.`);
|
|
18765
|
+
}
|
|
18766
|
+
function readThinkingEffort(metadata) {
|
|
18767
|
+
return readOptionalMetadataString(metadata?.thinkingEffort) ?? readOptionalMetadataString(metadata?.preferred_thinking) ?? readOptionalMetadataString(metadata?.thinking) ?? null;
|
|
18768
|
+
}
|
|
18769
|
+
function readProjectRoot(metadata) {
|
|
18770
|
+
return readOptionalMetadataString(metadata?.project_root) ?? readOptionalMetadataString(metadata?.projectRoot);
|
|
18771
|
+
}
|
|
18772
|
+
function readProjectId(metadata) {
|
|
18773
|
+
return readOptionalMetadataString(metadata?.project_id) ?? readOptionalMetadataString(metadata?.projectId);
|
|
18774
|
+
}
|
|
18775
|
+
function readAgentRuntimeId(metadata) {
|
|
18776
|
+
return readOptionalMetadataString(metadata?.agentRuntimeId) ?? readOptionalMetadataString(metadata?.runtime) ?? readOptionalMetadataString(metadata?.session_type);
|
|
18777
|
+
}
|
|
18778
|
+
function summarizeTask(task) {
|
|
18779
|
+
const normalized = task.trim().replace(/\s+/g, " ");
|
|
18780
|
+
if (!normalized) return "Session";
|
|
18781
|
+
return normalized.length <= 72 ? normalized : `${normalized.slice(0, 69)}...`;
|
|
18782
|
+
}
|
|
18783
|
+
function cloneInheritedMetadata(sourceMetadata) {
|
|
18784
|
+
const nextMetadata = {};
|
|
18785
|
+
for (const key of [
|
|
18786
|
+
"runtime",
|
|
18787
|
+
"session_type",
|
|
18788
|
+
"preferred_model",
|
|
18789
|
+
"preferred_thinking",
|
|
18790
|
+
"project_root",
|
|
18791
|
+
"project_id",
|
|
18792
|
+
"codex_runtime_backend",
|
|
18793
|
+
"reasoningNormalizationMode",
|
|
18794
|
+
"reasoning_normalization_mode"
|
|
18795
|
+
]) if (Object.prototype.hasOwnProperty.call(sourceMetadata, key)) nextMetadata[key] = structuredClone(sourceMetadata[key]);
|
|
18796
|
+
return nextMetadata;
|
|
18797
|
+
}
|
|
18798
|
+
function mergeMetadataOverrides(metadata, overrides) {
|
|
18799
|
+
return overrides && Object.keys(overrides).length > 0 ? {
|
|
18800
|
+
...metadata,
|
|
18801
|
+
...structuredClone(overrides)
|
|
18802
|
+
} : metadata;
|
|
18803
|
+
}
|
|
18804
|
+
function resolveSessionType(params) {
|
|
18805
|
+
const { metadata, runtime, sessionType } = params;
|
|
18806
|
+
return readOptionalString$8(runtime) ?? readOptionalString$8(metadata.runtime) ?? readOptionalString$8(sessionType) ?? readOptionalString$8(metadata.session_type) ?? "native";
|
|
18807
|
+
}
|
|
18808
|
+
function applySessionOverrides(params) {
|
|
18809
|
+
const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
|
|
18810
|
+
metadata.session_type = sessionType;
|
|
18811
|
+
metadata.runtime = sessionType;
|
|
18812
|
+
metadata[SESSION_METADATA_LABEL_KEY] = title;
|
|
18813
|
+
metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
|
|
18814
|
+
if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
|
|
18815
|
+
if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
|
|
18816
|
+
if (readOptionalString$8(model)) {
|
|
18817
|
+
metadata.model = model?.trim();
|
|
18818
|
+
metadata.preferred_model = model?.trim();
|
|
18819
|
+
}
|
|
18820
|
+
if (readOptionalString$8(thinkingLevel)) {
|
|
18821
|
+
metadata.thinking = thinkingLevel?.trim();
|
|
18822
|
+
metadata.preferred_thinking = thinkingLevel?.trim();
|
|
18823
|
+
}
|
|
18824
|
+
if (readOptionalString$8(projectRoot)) metadata.project_root = projectRoot?.trim();
|
|
18825
|
+
}
|
|
18826
|
+
//#endregion
|
|
18827
|
+
//#region src/utils/session-context-inheritance.utils.ts
|
|
18828
|
+
const CONTEXT_INHERITANCE_METADATA_KEY = "context_inheritance";
|
|
18829
|
+
const INHERITED_FROM_SESSION_METADATA_KEY$1 = "inherited_from_session_id";
|
|
18830
|
+
const INHERITED_FROM_MESSAGE_METADATA_KEY = "inherited_from_message_id";
|
|
18831
|
+
function hasToolCall(message, toolCallId) {
|
|
18832
|
+
return message.parts.some((part) => part.type === "tool-invocation" && part.toolCallId === toolCallId);
|
|
18833
|
+
}
|
|
18834
|
+
function findContextInheritanceAnchor(params) {
|
|
18835
|
+
const anchorToolCallId = readOptionalString$8(params.anchorToolCallId);
|
|
18836
|
+
if (!anchorToolCallId) return null;
|
|
18837
|
+
const index = params.messages.findIndex((message) => hasToolCall(message, anchorToolCallId));
|
|
18838
|
+
const message = index >= 0 ? params.messages[index] : void 0;
|
|
18839
|
+
return message ? {
|
|
18840
|
+
index,
|
|
18841
|
+
message
|
|
18842
|
+
} : null;
|
|
18843
|
+
}
|
|
18844
|
+
function createInheritedContextMessage(params) {
|
|
18845
18845
|
const { childSessionId, index, sourceMessage, sourceSessionId } = params;
|
|
18846
18846
|
const message = structuredClone(sourceMessage);
|
|
18847
18847
|
const metadata = structuredClone(message.metadata ?? {});
|
|
@@ -18872,7 +18872,7 @@ function createInheritedContextSnapshot(params) {
|
|
|
18872
18872
|
enabled: true,
|
|
18873
18873
|
sourceSessionId: sourceRecord.sessionId,
|
|
18874
18874
|
anchorKind: anchor ? "tool_call" : "latest_persisted",
|
|
18875
|
-
anchorToolCallId: readOptionalString$
|
|
18875
|
+
anchorToolCallId: readOptionalString$8(anchorToolCallId),
|
|
18876
18876
|
anchorMessageId: anchor?.message.id,
|
|
18877
18877
|
inheritedMessageCount: messages.length
|
|
18878
18878
|
}
|
|
@@ -19160,7 +19160,7 @@ var SessionWorkingDirResolver = class {
|
|
|
19160
19160
|
return this.resolveContext(params).effectiveWorkspace;
|
|
19161
19161
|
};
|
|
19162
19162
|
resolveContext = (params) => {
|
|
19163
|
-
const profile = this.agentManager.resolveAgentProfile(readOptionalString$
|
|
19163
|
+
const profile = this.agentManager.resolveAgentProfile(readOptionalString$8(params.agentId));
|
|
19164
19164
|
return resolveSessionProjectContext({
|
|
19165
19165
|
sessionMetadata: params.metadata,
|
|
19166
19166
|
workspace: profile.workspace
|
|
@@ -19208,10 +19208,10 @@ var SessionManager = class {
|
|
|
19208
19208
|
const { agentId: requestedAgentId, contextInheritance, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
|
|
19209
19209
|
const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
|
|
19210
19210
|
const metadata = cloneInheritedMetadata(sourceSessionMetadata);
|
|
19211
|
-
const title = readOptionalString$
|
|
19212
|
-
const parentSessionId = readOptionalString$
|
|
19211
|
+
const title = readOptionalString$8(requestedTitle) ?? summarizeTask(task);
|
|
19212
|
+
const parentSessionId = readOptionalString$8(rawParentSessionId);
|
|
19213
19213
|
await assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, this.getSessionRecord);
|
|
19214
|
-
const requestId = readOptionalString$
|
|
19214
|
+
const requestId = readOptionalString$8(rawRequestId);
|
|
19215
19215
|
const sessionType = resolveSessionType({
|
|
19216
19216
|
runtime,
|
|
19217
19217
|
sessionType: requestedSessionType,
|
|
@@ -19232,8 +19232,8 @@ var SessionManager = class {
|
|
|
19232
19232
|
let nextMetadata = mergeMetadataOverrides(metadata, metadataOverrides);
|
|
19233
19233
|
const requestedProjectRoot = projectRoot !== void 0 ? projectRoot : readProjectRoot(nextMetadata);
|
|
19234
19234
|
if (requestedProjectRoot !== void 0) nextMetadata = await applySessionProjectMetadataPatch(nextMetadata, { projectRoot: requestedProjectRoot }, this.options.projectManager.normalizeSessionProjectContext);
|
|
19235
|
-
const agentId = readOptionalString$
|
|
19236
|
-
const sessionId = readOptionalString$
|
|
19235
|
+
const agentId = readOptionalString$8(requestedAgentId) ?? readOptionalString$8(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
|
|
19236
|
+
const sessionId = readOptionalString$8(requestedSessionId) ?? buildSessionId();
|
|
19237
19237
|
const inheritedContext = createSessionContextInheritance({
|
|
19238
19238
|
childSessionId: sessionId,
|
|
19239
19239
|
contextInheritance,
|
|
@@ -19319,7 +19319,7 @@ var SessionManager = class {
|
|
|
19319
19319
|
listSessions = async (options) => {
|
|
19320
19320
|
const { limit, peerId: rawPeerId } = options ?? {};
|
|
19321
19321
|
const { journalStore } = this.options;
|
|
19322
|
-
const peerId = readOptionalString$
|
|
19322
|
+
const peerId = readOptionalString$8(rawPeerId);
|
|
19323
19323
|
const summaryReadOptions = !peerId && limit !== void 0 ? { limit } : void 0;
|
|
19324
19324
|
return applyLimit((await journalStore.listSessionSummaries(summaryReadOptions)).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), limit);
|
|
19325
19325
|
};
|
|
@@ -19378,9 +19378,9 @@ var SessionManager = class {
|
|
|
19378
19378
|
};
|
|
19379
19379
|
createAgentRunSession = async (params) => {
|
|
19380
19380
|
const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, contextInheritance, metadata, model, parentSessionId: rawParentSessionId, peerId: rawPeerId, projectRoot, sessionId, sourceSessionId: rawSourceSessionId, sourceSessionMetadata: requestedSourceSessionMetadata, task, thinkingEffort } = params;
|
|
19381
|
-
const peerId = readOptionalString$
|
|
19382
|
-
const parentSessionId = readOptionalString$
|
|
19383
|
-
const sourceSessionId = readOptionalString$
|
|
19381
|
+
const peerId = readOptionalString$8(rawPeerId);
|
|
19382
|
+
const parentSessionId = readOptionalString$8(rawParentSessionId);
|
|
19383
|
+
const sourceSessionId = readOptionalString$8(rawSourceSessionId);
|
|
19384
19384
|
const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
|
|
19385
19385
|
const sourceSessionMetadata = requestedSourceSessionMetadata ?? sourceRecord?.metadata ?? {};
|
|
19386
19386
|
const agentRuntimeId = requestedAgentRuntimeId ?? readAgentRuntimeId(sourceSessionMetadata) ?? "native";
|
|
@@ -19390,7 +19390,7 @@ var SessionManager = class {
|
|
|
19390
19390
|
metadata,
|
|
19391
19391
|
peerId
|
|
19392
19392
|
}) : void 0;
|
|
19393
|
-
const requestedSessionId = readOptionalString$
|
|
19393
|
+
const requestedSessionId = readOptionalString$8(sessionId);
|
|
19394
19394
|
const created = await this.createSession({
|
|
19395
19395
|
contextInheritance,
|
|
19396
19396
|
parentSessionId: parentSessionId ?? void 0,
|
|
@@ -20426,109 +20426,295 @@ var ObservationManager = class {
|
|
|
20426
20426
|
};
|
|
20427
20427
|
};
|
|
20428
20428
|
//#endregion
|
|
20429
|
-
//#region src/
|
|
20430
|
-
const
|
|
20431
|
-
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
|
|
20437
|
-
|
|
20429
|
+
//#region src/stores/sqlite-database.store.ts
|
|
20430
|
+
const require = createRequire(import.meta.url);
|
|
20431
|
+
const portableDatabases = /* @__PURE__ */ new Map();
|
|
20432
|
+
async function openSqliteDatabase(databasePath) {
|
|
20433
|
+
try {
|
|
20434
|
+
return new (require("node:sqlite")).DatabaseSync(databasePath);
|
|
20435
|
+
} catch (error) {
|
|
20436
|
+
if (!isMissingNodeSqlite(error)) throw error;
|
|
20437
|
+
return await openPortableDatabase(databasePath);
|
|
20438
20438
|
}
|
|
20439
|
-
}
|
|
20440
|
-
|
|
20441
|
-
|
|
20442
|
-
|
|
20439
|
+
}
|
|
20440
|
+
function runSqliteTransaction(database, operation, mode = "DEFERRED") {
|
|
20441
|
+
database.exec(`BEGIN ${mode}`);
|
|
20442
|
+
try {
|
|
20443
|
+
const result = operation();
|
|
20444
|
+
database.exec("COMMIT");
|
|
20445
|
+
return result;
|
|
20446
|
+
} catch (error) {
|
|
20447
|
+
database.exec("ROLLBACK");
|
|
20448
|
+
throw error;
|
|
20443
20449
|
}
|
|
20444
|
-
|
|
20445
|
-
|
|
20446
|
-
|
|
20447
|
-
|
|
20448
|
-
|
|
20449
|
-
|
|
20450
|
-
|
|
20451
|
-
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
|
|
20455
|
-
|
|
20456
|
-
|
|
20457
|
-
|
|
20458
|
-
|
|
20459
|
-
|
|
20460
|
-
|
|
20461
|
-
|
|
20462
|
-
|
|
20463
|
-
|
|
20464
|
-
|
|
20465
|
-
|
|
20466
|
-
|
|
20450
|
+
}
|
|
20451
|
+
function isMissingNodeSqlite(error) {
|
|
20452
|
+
const code = typeof error === "object" && error !== null ? error.code : void 0;
|
|
20453
|
+
return code === "ERR_UNKNOWN_BUILTIN_MODULE" || code === "MODULE_NOT_FOUND";
|
|
20454
|
+
}
|
|
20455
|
+
async function openPortableDatabase(databasePath) {
|
|
20456
|
+
const existing = portableDatabases.get(databasePath);
|
|
20457
|
+
if (existing) return (await existing).acquire();
|
|
20458
|
+
const opening = createPortableDatabase(databasePath).catch((error) => {
|
|
20459
|
+
portableDatabases.delete(databasePath);
|
|
20460
|
+
throw error;
|
|
20461
|
+
});
|
|
20462
|
+
portableDatabases.set(databasePath, opening);
|
|
20463
|
+
return (await opening).acquire();
|
|
20464
|
+
}
|
|
20465
|
+
async function createPortableDatabase(databasePath) {
|
|
20466
|
+
const initialize = (await import("sql.js")).default;
|
|
20467
|
+
const sqlite = await initialize({ locateFile: resolveSqlJsAsset });
|
|
20468
|
+
return new PortableSqliteDatabase(databasePath, existsSync(databasePath) ? new sqlite.Database(readFileSync(databasePath)) : new sqlite.Database());
|
|
20469
|
+
}
|
|
20470
|
+
function resolveSqlJsAsset(file) {
|
|
20471
|
+
try {
|
|
20472
|
+
return require.resolve(`sql.js/dist/${file}`);
|
|
20473
|
+
} catch (error) {
|
|
20474
|
+
const bundledAssetPath = fileURLToPath(new URL(file, import.meta.url));
|
|
20475
|
+
if (file === "sql-wasm.wasm" && existsSync(bundledAssetPath)) return bundledAssetPath;
|
|
20476
|
+
throw error;
|
|
20477
|
+
}
|
|
20478
|
+
}
|
|
20479
|
+
var PortableSqliteDatabase = class {
|
|
20480
|
+
inTransaction = false;
|
|
20481
|
+
dirty = false;
|
|
20482
|
+
leaseCount = 0;
|
|
20483
|
+
constructor(databasePath, database) {
|
|
20484
|
+
this.databasePath = databasePath;
|
|
20485
|
+
this.database = database;
|
|
20486
|
+
}
|
|
20487
|
+
acquire = () => {
|
|
20488
|
+
this.leaseCount += 1;
|
|
20489
|
+
return new PortableSqliteLease(this);
|
|
20490
|
+
};
|
|
20491
|
+
exec = (sql) => {
|
|
20492
|
+
const command = sql.trim().toUpperCase();
|
|
20493
|
+
this.database.run(sql);
|
|
20494
|
+
if (command.startsWith("BEGIN")) {
|
|
20495
|
+
this.inTransaction = true;
|
|
20496
|
+
return;
|
|
20467
20497
|
}
|
|
20468
|
-
if (
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
|
|
20472
|
-
}
|
|
20473
|
-
|
|
20498
|
+
if (command.startsWith("ROLLBACK")) {
|
|
20499
|
+
this.inTransaction = false;
|
|
20500
|
+
this.dirty = false;
|
|
20501
|
+
return;
|
|
20502
|
+
}
|
|
20503
|
+
if (command.startsWith("COMMIT")) {
|
|
20504
|
+
this.inTransaction = false;
|
|
20505
|
+
this.persistIfDirty();
|
|
20506
|
+
return;
|
|
20507
|
+
}
|
|
20508
|
+
if (!command.startsWith("PRAGMA")) this.markDirty();
|
|
20474
20509
|
};
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20510
|
+
prepare = (sql) => new PortableSqliteStatement(this, sql);
|
|
20511
|
+
release = () => {
|
|
20512
|
+
this.leaseCount -= 1;
|
|
20513
|
+
if (this.leaseCount > 0) return;
|
|
20514
|
+
this.persistIfDirty();
|
|
20515
|
+
this.database.close();
|
|
20516
|
+
portableDatabases.delete(this.databasePath);
|
|
20517
|
+
};
|
|
20518
|
+
run = (sql, params) => {
|
|
20519
|
+
this.database.run(sql, normalizeParams(params));
|
|
20520
|
+
this.markDirty();
|
|
20521
|
+
};
|
|
20522
|
+
readRows = (sql, params) => {
|
|
20523
|
+
const statement = this.database.prepare(sql);
|
|
20483
20524
|
try {
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20487
|
-
|
|
20488
|
-
|
|
20525
|
+
bindStatement(statement, params);
|
|
20526
|
+
const rows = [];
|
|
20527
|
+
while (statement.step()) rows.push(statement.getAsObject());
|
|
20528
|
+
return rows;
|
|
20529
|
+
} finally {
|
|
20530
|
+
statement.free();
|
|
20489
20531
|
}
|
|
20490
20532
|
};
|
|
20533
|
+
markDirty = () => {
|
|
20534
|
+
this.dirty = true;
|
|
20535
|
+
if (!this.inTransaction) this.persistIfDirty();
|
|
20536
|
+
};
|
|
20537
|
+
persistIfDirty = () => {
|
|
20538
|
+
if (!this.dirty) return;
|
|
20539
|
+
const temporaryPath = `${this.databasePath}.tmp`;
|
|
20540
|
+
writeFileSync(temporaryPath, this.database.export());
|
|
20541
|
+
renameSync(temporaryPath, this.databasePath);
|
|
20542
|
+
this.dirty = false;
|
|
20543
|
+
};
|
|
20544
|
+
};
|
|
20545
|
+
var PortableSqliteLease = class {
|
|
20546
|
+
closed = false;
|
|
20547
|
+
constructor(owner) {
|
|
20548
|
+
this.owner = owner;
|
|
20549
|
+
}
|
|
20550
|
+
close = () => {
|
|
20551
|
+
if (this.closed) return;
|
|
20552
|
+
this.closed = true;
|
|
20553
|
+
this.owner.release();
|
|
20554
|
+
};
|
|
20555
|
+
exec = (sql) => this.owner.exec(sql);
|
|
20556
|
+
prepare = (sql) => this.owner.prepare(sql);
|
|
20557
|
+
};
|
|
20558
|
+
var PortableSqliteStatement = class {
|
|
20559
|
+
constructor(database, sql) {
|
|
20560
|
+
this.database = database;
|
|
20561
|
+
this.sql = sql;
|
|
20562
|
+
}
|
|
20563
|
+
all = (...params) => this.database.readRows(this.sql, params);
|
|
20564
|
+
get = (...params) => this.all(...params)[0];
|
|
20565
|
+
run = (...params) => {
|
|
20566
|
+
this.database.run(this.sql, params);
|
|
20567
|
+
return {};
|
|
20568
|
+
};
|
|
20569
|
+
};
|
|
20570
|
+
function bindStatement(statement, params) {
|
|
20571
|
+
const normalized = normalizeParams(params);
|
|
20572
|
+
if (Array.isArray(normalized) && normalized.length === 0) return;
|
|
20573
|
+
statement.bind(normalized);
|
|
20574
|
+
}
|
|
20575
|
+
function normalizeParams(params) {
|
|
20576
|
+
if (params.length !== 1 || !isRecord$7(params[0])) return params;
|
|
20577
|
+
return Object.fromEntries(Object.entries(params[0]).map(([key, value]) => [`@${key}`, value]));
|
|
20578
|
+
}
|
|
20579
|
+
function isRecord$7(value) {
|
|
20580
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20581
|
+
}
|
|
20582
|
+
//#endregion
|
|
20583
|
+
//#region src/features/projects/stores/project.store.ts
|
|
20584
|
+
const PROJECT_STORE_VERSION = 3;
|
|
20585
|
+
const LEGACY_PROJECTS_MIGRATION_ID = "projects-json-to-sqlite-v1";
|
|
20586
|
+
function createProjectId() {
|
|
20587
|
+
return randomBytes(9).toString("base64url");
|
|
20588
|
+
}
|
|
20589
|
+
var ProjectStoreError = class extends Error {
|
|
20590
|
+
constructor(message) {
|
|
20591
|
+
super(message);
|
|
20592
|
+
this.name = "ProjectStoreError";
|
|
20593
|
+
}
|
|
20594
|
+
};
|
|
20595
|
+
var ProjectStore = class {
|
|
20596
|
+
database = null;
|
|
20597
|
+
readyPromise = null;
|
|
20598
|
+
constructor(options) {
|
|
20599
|
+
this.options = options;
|
|
20600
|
+
}
|
|
20601
|
+
initialize = async () => await this.ensureReady();
|
|
20602
|
+
close = () => {
|
|
20603
|
+
this.database?.close();
|
|
20604
|
+
this.database = null;
|
|
20605
|
+
this.readyPromise = null;
|
|
20606
|
+
};
|
|
20607
|
+
list = async () => {
|
|
20608
|
+
await this.ensureReady();
|
|
20609
|
+
return this.db().prepare("SELECT * FROM projects WHERE removed_at IS NULL").all().map(toProjectRecord);
|
|
20610
|
+
};
|
|
20611
|
+
add = async (project) => {
|
|
20612
|
+
await this.ensureReady();
|
|
20613
|
+
this.insertProject(project, null);
|
|
20614
|
+
};
|
|
20491
20615
|
remove = async (projectId) => {
|
|
20492
|
-
|
|
20493
|
-
const
|
|
20494
|
-
if (!
|
|
20495
|
-
|
|
20496
|
-
return
|
|
20616
|
+
await this.ensureReady();
|
|
20617
|
+
const row = this.db().prepare("SELECT * FROM projects WHERE id = ? AND removed_at IS NULL LIMIT 1").get(projectId);
|
|
20618
|
+
if (!row) return null;
|
|
20619
|
+
this.db().prepare("UPDATE projects SET removed_at = ? WHERE id = ?").run((/* @__PURE__ */ new Date()).toISOString(), projectId);
|
|
20620
|
+
return toProjectRecord(row);
|
|
20497
20621
|
};
|
|
20498
20622
|
restoreByRootPath = async (rootPath, updatedAt) => {
|
|
20499
|
-
|
|
20500
|
-
const
|
|
20501
|
-
if (!
|
|
20502
|
-
|
|
20503
|
-
|
|
20623
|
+
await this.ensureReady();
|
|
20624
|
+
const row = this.db().prepare("SELECT * FROM projects WHERE root_path = ? AND removed_at IS NOT NULL LIMIT 1").get(rootPath);
|
|
20625
|
+
if (!row) return null;
|
|
20626
|
+
this.db().prepare("UPDATE projects SET removed_at = NULL, updated_at = ? WHERE id = ?").run(updatedAt, row.id);
|
|
20627
|
+
return {
|
|
20628
|
+
...toProjectRecord(row),
|
|
20504
20629
|
updatedAt
|
|
20505
20630
|
};
|
|
20506
|
-
await this.save([...storeFile.projects, restored], storeFile.removedProjects.filter((entry) => entry.id !== project.id));
|
|
20507
|
-
return structuredClone(restored);
|
|
20508
20631
|
};
|
|
20509
|
-
isRemovedRootPath = async (rootPath) =>
|
|
20510
|
-
|
|
20632
|
+
isRemovedRootPath = async (rootPath) => {
|
|
20633
|
+
await this.ensureReady();
|
|
20634
|
+
return Boolean(this.db().prepare("SELECT id FROM projects WHERE root_path = ? AND removed_at IS NOT NULL LIMIT 1").get(rootPath));
|
|
20635
|
+
};
|
|
20636
|
+
ensureReady = async () => {
|
|
20637
|
+
this.readyPromise ??= this.open();
|
|
20638
|
+
await this.readyPromise;
|
|
20639
|
+
};
|
|
20640
|
+
open = async () => {
|
|
20641
|
+
await mkdir(dirname(this.options.databasePath), { recursive: true });
|
|
20642
|
+
this.database = await openSqliteDatabase(this.options.databasePath);
|
|
20511
20643
|
try {
|
|
20512
|
-
|
|
20644
|
+
this.database.exec(`
|
|
20645
|
+
PRAGMA busy_timeout = 10000;
|
|
20646
|
+
PRAGMA journal_mode = WAL;
|
|
20647
|
+
PRAGMA synchronous = NORMAL;
|
|
20648
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
20649
|
+
id TEXT PRIMARY KEY,
|
|
20650
|
+
name TEXT NOT NULL,
|
|
20651
|
+
root_path TEXT NOT NULL UNIQUE,
|
|
20652
|
+
template TEXT CHECK(template IS NULL OR template IN ('empty', 'knowledge-base')),
|
|
20653
|
+
created_at TEXT NOT NULL,
|
|
20654
|
+
updated_at TEXT NOT NULL,
|
|
20655
|
+
removed_at TEXT
|
|
20656
|
+
);
|
|
20657
|
+
CREATE TABLE IF NOT EXISTS project_storage_migrations (
|
|
20658
|
+
id TEXT PRIMARY KEY,
|
|
20659
|
+
completed_at TEXT NOT NULL
|
|
20660
|
+
);
|
|
20661
|
+
CREATE INDEX IF NOT EXISTS projects_active_updated_idx
|
|
20662
|
+
ON projects(removed_at, updated_at);
|
|
20663
|
+
`);
|
|
20664
|
+
await this.migrateLegacyRegistry();
|
|
20513
20665
|
} catch (error) {
|
|
20514
|
-
|
|
20515
|
-
|
|
20516
|
-
projects: [],
|
|
20517
|
-
removedProjects: []
|
|
20518
|
-
};
|
|
20519
|
-
if (error instanceof SyntaxError) throw new ProjectStoreError("project registry contains invalid JSON");
|
|
20666
|
+
this.database.close();
|
|
20667
|
+
this.database = null;
|
|
20520
20668
|
throw error;
|
|
20521
20669
|
}
|
|
20522
20670
|
};
|
|
20523
|
-
|
|
20524
|
-
|
|
20525
|
-
|
|
20671
|
+
migrateLegacyRegistry = async () => {
|
|
20672
|
+
if (this.db().prepare("SELECT id FROM project_storage_migrations WHERE id = ? LIMIT 1").get(LEGACY_PROJECTS_MIGRATION_ID)) return;
|
|
20673
|
+
const legacy = await this.readLegacyStoreFile();
|
|
20674
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20675
|
+
runSqliteTransaction(this.db(), () => {
|
|
20676
|
+
if (legacy) {
|
|
20677
|
+
for (const project of legacy.projects) this.insertProject(project, null);
|
|
20678
|
+
for (const project of legacy.removedProjects) this.insertProject(project, completedAt);
|
|
20679
|
+
}
|
|
20680
|
+
this.db().prepare("INSERT INTO project_storage_migrations (id, completed_at) VALUES (?, ?)").run(LEGACY_PROJECTS_MIGRATION_ID, completedAt);
|
|
20681
|
+
}, "IMMEDIATE");
|
|
20682
|
+
if (legacy) console.log(`[project-store] migrated ${legacy.projects.length + legacy.removedProjects.length} project records from legacy JSON to SQLite`);
|
|
20683
|
+
};
|
|
20684
|
+
readLegacyStoreFile = async () => {
|
|
20685
|
+
let source;
|
|
20686
|
+
try {
|
|
20687
|
+
source = await readFile(this.options.legacyStorePath, "utf8");
|
|
20688
|
+
} catch (error) {
|
|
20689
|
+
if (this.isMissingFileError(error)) return null;
|
|
20690
|
+
throw error;
|
|
20691
|
+
}
|
|
20692
|
+
let storeFile;
|
|
20693
|
+
try {
|
|
20694
|
+
storeFile = this.parseStoredFile(source);
|
|
20695
|
+
} catch (error) {
|
|
20696
|
+
if (error instanceof SyntaxError) throw new ProjectStoreError("project registry contains invalid JSON");
|
|
20697
|
+
throw error;
|
|
20698
|
+
}
|
|
20699
|
+
if (storeFile.version === 1) return {
|
|
20700
|
+
version: PROJECT_STORE_VERSION,
|
|
20701
|
+
projects: storeFile.projects.map((project) => ({
|
|
20702
|
+
id: createProjectId(),
|
|
20703
|
+
...project
|
|
20704
|
+
})),
|
|
20705
|
+
removedProjects: []
|
|
20706
|
+
};
|
|
20526
20707
|
return {
|
|
20527
20708
|
version: PROJECT_STORE_VERSION,
|
|
20528
|
-
projects:
|
|
20529
|
-
removedProjects:
|
|
20709
|
+
projects: storeFile.projects,
|
|
20710
|
+
removedProjects: storeFile.version === PROJECT_STORE_VERSION ? storeFile.removedProjects : []
|
|
20530
20711
|
};
|
|
20531
20712
|
};
|
|
20713
|
+
insertProject = (project, removedAt) => {
|
|
20714
|
+
this.db().prepare(`INSERT INTO projects
|
|
20715
|
+
(id, name, root_path, template, created_at, updated_at, removed_at)
|
|
20716
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(project.id, project.name, project.rootPath, project.template ?? null, project.createdAt, project.updatedAt, removedAt);
|
|
20717
|
+
};
|
|
20532
20718
|
parseStoredFile = (source) => {
|
|
20533
20719
|
const value = JSON.parse(source);
|
|
20534
20720
|
if (!this.isRecord(value) || !Array.isArray(value.projects)) throw new ProjectStoreError("project registry has an unsupported structure");
|
|
@@ -20561,7 +20747,21 @@ var ProjectStore = class {
|
|
|
20561
20747
|
};
|
|
20562
20748
|
isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20563
20749
|
isMissingFileError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
20750
|
+
db = () => {
|
|
20751
|
+
if (!this.database) throw new Error("Project database is not initialized.");
|
|
20752
|
+
return this.database;
|
|
20753
|
+
};
|
|
20564
20754
|
};
|
|
20755
|
+
function toProjectRecord(row) {
|
|
20756
|
+
return {
|
|
20757
|
+
id: row.id,
|
|
20758
|
+
name: row.name,
|
|
20759
|
+
rootPath: row.root_path,
|
|
20760
|
+
...row.template ? { template: row.template } : {},
|
|
20761
|
+
createdAt: row.created_at,
|
|
20762
|
+
updatedAt: row.updated_at
|
|
20763
|
+
};
|
|
20764
|
+
}
|
|
20565
20765
|
//#endregion
|
|
20566
20766
|
//#region src/features/projects/types/project.types.ts
|
|
20567
20767
|
const PROJECT_TEMPLATE_IDS = ["empty", "knowledge-base"];
|
|
@@ -20590,10 +20790,14 @@ var ProjectManager = class {
|
|
|
20590
20790
|
store;
|
|
20591
20791
|
constructor(options) {
|
|
20592
20792
|
this.options = options;
|
|
20593
|
-
this.store = new ProjectStore(
|
|
20793
|
+
this.store = new ProjectStore({
|
|
20794
|
+
databasePath: options.databasePath,
|
|
20795
|
+
legacyStorePath: options.legacyStorePath
|
|
20796
|
+
});
|
|
20594
20797
|
}
|
|
20798
|
+
initialize = async () => await this.store.initialize();
|
|
20799
|
+
dispose = () => this.store.close();
|
|
20595
20800
|
listProjects = async () => (await this.store.list()).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt) || left.name.localeCompare(right.name));
|
|
20596
|
-
migrateLegacyProjects = async () => await this.store.migrateLegacyRecords();
|
|
20597
20801
|
getProjectById = async (projectId) => {
|
|
20598
20802
|
const project = (await this.store.list()).find((entry) => entry.id === projectId);
|
|
20599
20803
|
return project ? structuredClone(project) : null;
|
|
@@ -20676,25 +20880,8 @@ var ProjectManager = class {
|
|
|
20676
20880
|
if (!(await stat(canonicalPath)).isDirectory()) throw new ProjectError("PROJECT_PATH_NOT_DIRECTORY", "project path must point to a directory");
|
|
20677
20881
|
return await this.isDefaultWorkspace(canonicalPath) ? null : canonicalPath;
|
|
20678
20882
|
};
|
|
20679
|
-
importSessionProjects = async (projectRoots) => {
|
|
20680
|
-
for (const projectRoot of projectRoots) {
|
|
20681
|
-
if (projectRoot == null || typeof projectRoot === "string" && !projectRoot.trim()) continue;
|
|
20682
|
-
try {
|
|
20683
|
-
const canonicalPath = await this.resolveExistingProjectRoot(projectRoot);
|
|
20684
|
-
if (!canonicalPath || await this.store.isRemovedRootPath(canonicalPath)) continue;
|
|
20685
|
-
await this.upsertProject({
|
|
20686
|
-
name: basename(canonicalPath),
|
|
20687
|
-
rootPath: canonicalPath
|
|
20688
|
-
});
|
|
20689
|
-
} catch (error) {
|
|
20690
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
20691
|
-
console.warn(`[project-manager] skipped historical project root: ${message}`);
|
|
20692
|
-
}
|
|
20693
|
-
}
|
|
20694
|
-
};
|
|
20695
20883
|
upsertProject = async (input, options = {}) => {
|
|
20696
|
-
const
|
|
20697
|
-
const existing = projects.find((project) => project.rootPath === input.rootPath);
|
|
20884
|
+
const existing = (await this.store.list()).find((project) => project.rootPath === input.rootPath);
|
|
20698
20885
|
if (existing) return existing;
|
|
20699
20886
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
20700
20887
|
if (options.restoreRemoved) {
|
|
@@ -20712,7 +20899,7 @@ var ProjectManager = class {
|
|
|
20712
20899
|
createdAt: now,
|
|
20713
20900
|
updatedAt: now
|
|
20714
20901
|
};
|
|
20715
|
-
await this.store.
|
|
20902
|
+
await this.store.add(project);
|
|
20716
20903
|
await this.options.onProjectRegistered?.(structuredClone(project));
|
|
20717
20904
|
return structuredClone(project);
|
|
20718
20905
|
};
|
|
@@ -20771,164 +20958,10 @@ var ProjectManager = class {
|
|
|
20771
20958
|
isMissingFileError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
20772
20959
|
};
|
|
20773
20960
|
//#endregion
|
|
20774
|
-
//#region src/stores/
|
|
20775
|
-
|
|
20776
|
-
|
|
20777
|
-
|
|
20778
|
-
try {
|
|
20779
|
-
return new (require("node:sqlite")).DatabaseSync(databasePath);
|
|
20780
|
-
} catch (error) {
|
|
20781
|
-
if (!isMissingNodeSqlite(error)) throw error;
|
|
20782
|
-
return await openPortableDatabase(databasePath);
|
|
20783
|
-
}
|
|
20784
|
-
}
|
|
20785
|
-
function runSqliteTransaction(database, operation, mode = "DEFERRED") {
|
|
20786
|
-
database.exec(`BEGIN ${mode}`);
|
|
20787
|
-
try {
|
|
20788
|
-
const result = operation();
|
|
20789
|
-
database.exec("COMMIT");
|
|
20790
|
-
return result;
|
|
20791
|
-
} catch (error) {
|
|
20792
|
-
database.exec("ROLLBACK");
|
|
20793
|
-
throw error;
|
|
20794
|
-
}
|
|
20795
|
-
}
|
|
20796
|
-
function isMissingNodeSqlite(error) {
|
|
20797
|
-
const code = typeof error === "object" && error !== null ? error.code : void 0;
|
|
20798
|
-
return code === "ERR_UNKNOWN_BUILTIN_MODULE" || code === "MODULE_NOT_FOUND";
|
|
20799
|
-
}
|
|
20800
|
-
async function openPortableDatabase(databasePath) {
|
|
20801
|
-
const existing = portableDatabases.get(databasePath);
|
|
20802
|
-
if (existing) return (await existing).acquire();
|
|
20803
|
-
const opening = createPortableDatabase(databasePath).catch((error) => {
|
|
20804
|
-
portableDatabases.delete(databasePath);
|
|
20805
|
-
throw error;
|
|
20806
|
-
});
|
|
20807
|
-
portableDatabases.set(databasePath, opening);
|
|
20808
|
-
return (await opening).acquire();
|
|
20809
|
-
}
|
|
20810
|
-
async function createPortableDatabase(databasePath) {
|
|
20811
|
-
const initialize = (await import("sql.js")).default;
|
|
20812
|
-
const sqlite = await initialize({ locateFile: resolveSqlJsAsset });
|
|
20813
|
-
return new PortableSqliteDatabase(databasePath, existsSync(databasePath) ? new sqlite.Database(readFileSync(databasePath)) : new sqlite.Database());
|
|
20814
|
-
}
|
|
20815
|
-
function resolveSqlJsAsset(file) {
|
|
20816
|
-
try {
|
|
20817
|
-
return require.resolve(`sql.js/dist/${file}`);
|
|
20818
|
-
} catch (error) {
|
|
20819
|
-
const bundledAssetPath = fileURLToPath(new URL(file, import.meta.url));
|
|
20820
|
-
if (file === "sql-wasm.wasm" && existsSync(bundledAssetPath)) return bundledAssetPath;
|
|
20821
|
-
throw error;
|
|
20822
|
-
}
|
|
20823
|
-
}
|
|
20824
|
-
var PortableSqliteDatabase = class {
|
|
20825
|
-
inTransaction = false;
|
|
20826
|
-
dirty = false;
|
|
20827
|
-
leaseCount = 0;
|
|
20828
|
-
constructor(databasePath, database) {
|
|
20829
|
-
this.databasePath = databasePath;
|
|
20830
|
-
this.database = database;
|
|
20831
|
-
}
|
|
20832
|
-
acquire = () => {
|
|
20833
|
-
this.leaseCount += 1;
|
|
20834
|
-
return new PortableSqliteLease(this);
|
|
20835
|
-
};
|
|
20836
|
-
exec = (sql) => {
|
|
20837
|
-
const command = sql.trim().toUpperCase();
|
|
20838
|
-
this.database.run(sql);
|
|
20839
|
-
if (command.startsWith("BEGIN")) {
|
|
20840
|
-
this.inTransaction = true;
|
|
20841
|
-
return;
|
|
20842
|
-
}
|
|
20843
|
-
if (command.startsWith("ROLLBACK")) {
|
|
20844
|
-
this.inTransaction = false;
|
|
20845
|
-
this.dirty = false;
|
|
20846
|
-
return;
|
|
20847
|
-
}
|
|
20848
|
-
if (command.startsWith("COMMIT")) {
|
|
20849
|
-
this.inTransaction = false;
|
|
20850
|
-
this.persistIfDirty();
|
|
20851
|
-
return;
|
|
20852
|
-
}
|
|
20853
|
-
if (!command.startsWith("PRAGMA")) this.markDirty();
|
|
20854
|
-
};
|
|
20855
|
-
prepare = (sql) => new PortableSqliteStatement(this, sql);
|
|
20856
|
-
release = () => {
|
|
20857
|
-
this.leaseCount -= 1;
|
|
20858
|
-
if (this.leaseCount > 0) return;
|
|
20859
|
-
this.persistIfDirty();
|
|
20860
|
-
this.database.close();
|
|
20861
|
-
portableDatabases.delete(this.databasePath);
|
|
20862
|
-
};
|
|
20863
|
-
run = (sql, params) => {
|
|
20864
|
-
this.database.run(sql, normalizeParams(params));
|
|
20865
|
-
this.markDirty();
|
|
20866
|
-
};
|
|
20867
|
-
readRows = (sql, params) => {
|
|
20868
|
-
const statement = this.database.prepare(sql);
|
|
20869
|
-
try {
|
|
20870
|
-
bindStatement(statement, params);
|
|
20871
|
-
const rows = [];
|
|
20872
|
-
while (statement.step()) rows.push(statement.getAsObject());
|
|
20873
|
-
return rows;
|
|
20874
|
-
} finally {
|
|
20875
|
-
statement.free();
|
|
20876
|
-
}
|
|
20877
|
-
};
|
|
20878
|
-
markDirty = () => {
|
|
20879
|
-
this.dirty = true;
|
|
20880
|
-
if (!this.inTransaction) this.persistIfDirty();
|
|
20881
|
-
};
|
|
20882
|
-
persistIfDirty = () => {
|
|
20883
|
-
if (!this.dirty) return;
|
|
20884
|
-
const temporaryPath = `${this.databasePath}.tmp`;
|
|
20885
|
-
writeFileSync(temporaryPath, this.database.export());
|
|
20886
|
-
renameSync(temporaryPath, this.databasePath);
|
|
20887
|
-
this.dirty = false;
|
|
20888
|
-
};
|
|
20889
|
-
};
|
|
20890
|
-
var PortableSqliteLease = class {
|
|
20891
|
-
closed = false;
|
|
20892
|
-
constructor(owner) {
|
|
20893
|
-
this.owner = owner;
|
|
20894
|
-
}
|
|
20895
|
-
close = () => {
|
|
20896
|
-
if (this.closed) return;
|
|
20897
|
-
this.closed = true;
|
|
20898
|
-
this.owner.release();
|
|
20899
|
-
};
|
|
20900
|
-
exec = (sql) => this.owner.exec(sql);
|
|
20901
|
-
prepare = (sql) => this.owner.prepare(sql);
|
|
20902
|
-
};
|
|
20903
|
-
var PortableSqliteStatement = class {
|
|
20904
|
-
constructor(database, sql) {
|
|
20905
|
-
this.database = database;
|
|
20906
|
-
this.sql = sql;
|
|
20907
|
-
}
|
|
20908
|
-
all = (...params) => this.database.readRows(this.sql, params);
|
|
20909
|
-
get = (...params) => this.all(...params)[0];
|
|
20910
|
-
run = (...params) => {
|
|
20911
|
-
this.database.run(this.sql, params);
|
|
20912
|
-
return {};
|
|
20913
|
-
};
|
|
20914
|
-
};
|
|
20915
|
-
function bindStatement(statement, params) {
|
|
20916
|
-
const normalized = normalizeParams(params);
|
|
20917
|
-
if (Array.isArray(normalized) && normalized.length === 0) return;
|
|
20918
|
-
statement.bind(normalized);
|
|
20919
|
-
}
|
|
20920
|
-
function normalizeParams(params) {
|
|
20921
|
-
if (params.length !== 1 || !isRecord$9(params[0])) return params;
|
|
20922
|
-
return Object.fromEntries(Object.entries(params[0]).map(([key, value]) => [`@${key}`, value]));
|
|
20923
|
-
}
|
|
20924
|
-
function isRecord$9(value) {
|
|
20925
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20926
|
-
}
|
|
20927
|
-
//#endregion
|
|
20928
|
-
//#region src/features/projects/stores/project-work-activity.store.ts
|
|
20929
|
-
var ProjectWorkActivityStore = class {
|
|
20930
|
-
constructor(db) {
|
|
20931
|
-
this.db = db;
|
|
20961
|
+
//#region src/features/projects/stores/project-work-activity.store.ts
|
|
20962
|
+
var ProjectWorkActivityStore = class {
|
|
20963
|
+
constructor(db) {
|
|
20964
|
+
this.db = db;
|
|
20932
20965
|
}
|
|
20933
20966
|
listActivities = async (projectId, workItemId, options) => {
|
|
20934
20967
|
const { cursor, limit } = options;
|
|
@@ -21073,9 +21106,13 @@ var ProjectWorkQueryStore = class {
|
|
|
21073
21106
|
updatedAt: row.updated_at
|
|
21074
21107
|
};
|
|
21075
21108
|
};
|
|
21076
|
-
|
|
21077
|
-
const { cursor, limit, projectId } = params;
|
|
21078
|
-
const
|
|
21109
|
+
listArtifacts = (params) => {
|
|
21110
|
+
const { cursor, limit, projectId, query } = params;
|
|
21111
|
+
const queryCondition = query ? "AND instr(lower(path), lower(?)) > 0" : "";
|
|
21112
|
+
const queryValues = query ? [query] : [];
|
|
21113
|
+
const total = Number(this.db().prepare(`SELECT COUNT(DISTINCT path) AS count
|
|
21114
|
+
FROM project_work_artifact_links
|
|
21115
|
+
WHERE project_id = ? ${queryCondition}`).get(projectId, ...queryValues).count);
|
|
21079
21116
|
const cursorCondition = cursor ? "AND (created_at < ? OR (created_at = ? AND id < ?))" : "";
|
|
21080
21117
|
const rows = this.db().prepare(`WITH ranked AS (
|
|
21081
21118
|
SELECT links.id, links.path, links.label, links.work_item_id,
|
|
@@ -21091,9 +21128,9 @@ var ProjectWorkQueryStore = class {
|
|
|
21091
21128
|
)
|
|
21092
21129
|
SELECT id, path, label, work_item_id, work_item_title, created_at
|
|
21093
21130
|
FROM ranked
|
|
21094
|
-
WHERE path_rank = 1 ${cursorCondition}
|
|
21131
|
+
WHERE path_rank = 1 ${queryCondition} ${cursorCondition}
|
|
21095
21132
|
ORDER BY created_at DESC, id DESC
|
|
21096
|
-
LIMIT ?`).all(projectId, ...cursor ? [
|
|
21133
|
+
LIMIT ?`).all(projectId, ...queryValues, ...cursor ? [
|
|
21097
21134
|
cursor.createdAt,
|
|
21098
21135
|
cursor.createdAt,
|
|
21099
21136
|
cursor.id
|
|
@@ -21531,14 +21568,16 @@ var ProjectWorkQueryService = class {
|
|
|
21531
21568
|
await this.ensureProject(projectId);
|
|
21532
21569
|
return this.store.queries.summarizeItems(projectId);
|
|
21533
21570
|
};
|
|
21534
|
-
|
|
21571
|
+
listArtifacts = async (projectId, input = {}) => {
|
|
21535
21572
|
const project = await this.requireProject(projectId);
|
|
21536
21573
|
await this.store.ensureProject(projectId);
|
|
21537
21574
|
const limit = this.requirePageLimit(input.limit);
|
|
21538
21575
|
const cursor = input.cursor ? this.decodeCursor(input.cursor, "project artifact", "createdAt") : void 0;
|
|
21539
|
-
const
|
|
21576
|
+
const query = input.query?.trim();
|
|
21577
|
+
const page = this.store.queries.listArtifacts({
|
|
21540
21578
|
projectId,
|
|
21541
21579
|
limit,
|
|
21580
|
+
...query ? { query } : {},
|
|
21542
21581
|
...cursor ? { cursor } : {}
|
|
21543
21582
|
});
|
|
21544
21583
|
const artifacts = await Promise.all(page.artifacts.map(async (artifact) => ({
|
|
@@ -21633,7 +21672,7 @@ var ProjectWorkManager = class {
|
|
|
21633
21672
|
};
|
|
21634
21673
|
list = async (projectId, input = {}) => await this.queries.list(projectId, input);
|
|
21635
21674
|
summary = async (projectId) => await this.queries.summary(projectId);
|
|
21636
|
-
listRecentArtifacts = async (projectId, input = {}) => await this.queries.
|
|
21675
|
+
listRecentArtifacts = async (projectId, input = {}) => await this.queries.listArtifacts(projectId, input);
|
|
21637
21676
|
get = async (projectId, workItemId) => {
|
|
21638
21677
|
await this.ensureProject(projectId);
|
|
21639
21678
|
const item = await this.store.getItem(projectId, workItemId);
|
|
@@ -21727,1342 +21766,165 @@ var ProjectWorkManager = class {
|
|
|
21727
21766
|
};
|
|
21728
21767
|
updateState = async (projectId, stateId, input) => {
|
|
21729
21768
|
await this.ensureProject(projectId);
|
|
21730
|
-
const normalizedInput = {
|
|
21731
|
-
...input,
|
|
21732
|
-
...input.name !== void 0 ? { name: this.requireName(input.name, "state name") } : {}
|
|
21733
|
-
};
|
|
21734
|
-
if (normalizedInput.category !== void 0) this.assertCategory(normalizedInput.category);
|
|
21735
|
-
const current = await this.store.getState(projectId, stateId);
|
|
21736
|
-
if (!current) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "work item state was not found");
|
|
21737
|
-
if (current.isDefault && normalizedInput.isDefault === false) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "choose another default state before clearing this one");
|
|
21738
|
-
if (normalizedInput.name && (await this.store.listStates(projectId)).some((state) => state.id !== stateId && state.name.toLocaleLowerCase() === normalizedInput.name.toLocaleLowerCase())) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "state name is already in use");
|
|
21739
|
-
const state = await this.store.updateState(projectId, stateId, normalizedInput);
|
|
21740
|
-
if (!state) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "work item state was not found");
|
|
21741
|
-
await this.emit(projectId, "state-config");
|
|
21742
|
-
return state;
|
|
21743
|
-
};
|
|
21744
|
-
deleteState = async (projectId, stateId, migrateToStateId, actor) => {
|
|
21745
|
-
await this.ensureProject(projectId);
|
|
21746
|
-
const states = await this.store.listStates(projectId);
|
|
21747
|
-
if (states.length <= 1) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "a project must keep at least one state");
|
|
21748
|
-
if (migrateToStateId === stateId) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "migration target must be a different state");
|
|
21749
|
-
if (migrateToStateId && !states.some((state) => state.id === migrateToStateId)) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "migration target state was not found");
|
|
21750
|
-
try {
|
|
21751
|
-
if (!await this.store.deleteState(projectId, stateId, migrateToStateId, this.normalizeActor(actor))) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "work item state was not found");
|
|
21752
|
-
} catch (error) {
|
|
21753
|
-
if (error instanceof Error && error.message === "PROJECT_WORK_STATE_IN_USE") throw new ProjectWorkError("PROJECT_WORK_STATE_IN_USE", "state is used by work items; choose a migration target");
|
|
21754
|
-
throw error;
|
|
21755
|
-
}
|
|
21756
|
-
await this.emit(projectId, "state-config");
|
|
21757
|
-
};
|
|
21758
|
-
linkArtifact = async (params) => {
|
|
21759
|
-
const { actor, label, path, projectId, workItemId } = params;
|
|
21760
|
-
const project = await this.requireProject(projectId);
|
|
21761
|
-
await this.get(projectId, workItemId);
|
|
21762
|
-
const artifactPath = await this.normalizeArtifactPath(project.rootPath, path);
|
|
21763
|
-
const existing = (await this.store.listArtifacts(projectId, workItemId)).find((link) => link.path === artifactPath);
|
|
21764
|
-
if (existing) return existing;
|
|
21765
|
-
const link = await this.store.linkArtifact({
|
|
21766
|
-
projectId,
|
|
21767
|
-
workItemId,
|
|
21768
|
-
path: artifactPath,
|
|
21769
|
-
label: label?.trim() || void 0,
|
|
21770
|
-
actor: this.normalizeActor(actor)
|
|
21771
|
-
});
|
|
21772
|
-
await this.emit(projectId, "artifact", workItemId);
|
|
21773
|
-
return link;
|
|
21774
|
-
};
|
|
21775
|
-
unlinkArtifact = async (params) => {
|
|
21776
|
-
const { actor, artifactLinkId, projectId, workItemId } = params;
|
|
21777
|
-
await this.get(projectId, workItemId);
|
|
21778
|
-
if (!await this.store.unlinkArtifact({
|
|
21779
|
-
projectId,
|
|
21780
|
-
workItemId,
|
|
21781
|
-
artifactLinkId,
|
|
21782
|
-
actor: this.normalizeActor(actor)
|
|
21783
|
-
})) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_NOT_FOUND", "artifact link was not found");
|
|
21784
|
-
await this.emit(projectId, "artifact", workItemId);
|
|
21785
|
-
};
|
|
21786
|
-
setDeleted = async (projectId, workItemId, deleted, actor) => {
|
|
21787
|
-
await this.ensureProject(projectId);
|
|
21788
|
-
const current = await this.get(projectId, workItemId);
|
|
21789
|
-
if (current.deletedAt !== null === deleted) return current;
|
|
21790
|
-
if (!await this.store.setDeleted({
|
|
21791
|
-
projectId,
|
|
21792
|
-
workItemId,
|
|
21793
|
-
deleted,
|
|
21794
|
-
actor: this.normalizeActor(actor)
|
|
21795
|
-
})) throw new ProjectWorkError("PROJECT_WORK_ITEM_NOT_FOUND", "work item was not found");
|
|
21796
|
-
await this.emit(projectId, deleted ? "deleted" : "restored", workItemId);
|
|
21797
|
-
return await this.get(projectId, workItemId);
|
|
21798
|
-
};
|
|
21799
|
-
requireProject = async (projectId) => {
|
|
21800
|
-
const normalized = projectId.trim();
|
|
21801
|
-
const project = normalized ? await this.options.projectManager.getProjectById(normalized) : null;
|
|
21802
|
-
if (!project) throw new ProjectWorkError("PROJECT_NOT_FOUND", "project was not found");
|
|
21803
|
-
return project;
|
|
21804
|
-
};
|
|
21805
|
-
requireName = (value, label) => {
|
|
21806
|
-
const normalized = typeof value === "string" ? value.trim() : "";
|
|
21807
|
-
if (!normalized) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", `${label} is required`);
|
|
21808
|
-
if (normalized.length > 200) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", `${label} is too long`);
|
|
21809
|
-
return normalized;
|
|
21810
|
-
};
|
|
21811
|
-
assertAttention = (value) => {
|
|
21812
|
-
if (!PROJECT_WORK_ATTENTION_VALUES.some((entry) => entry === value)) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", "work item attention is invalid");
|
|
21813
|
-
};
|
|
21814
|
-
assertCategory = (value) => {
|
|
21815
|
-
if (!PROJECT_WORK_STATE_CATEGORIES.some((entry) => entry === value)) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", "work item state category is invalid");
|
|
21816
|
-
};
|
|
21817
|
-
normalizeActor = (actor) => ({
|
|
21818
|
-
kind: actor.kind,
|
|
21819
|
-
...actor.id?.trim() ? { id: actor.id.trim() } : {},
|
|
21820
|
-
...actor.sessionId?.trim() ? { sessionId: actor.sessionId.trim() } : {}
|
|
21821
|
-
});
|
|
21822
|
-
normalizeArtifactPath = async (rootPath, inputPath) => {
|
|
21823
|
-
const requested = inputPath.trim();
|
|
21824
|
-
if (!requested) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_INVALID", "artifact path is required");
|
|
21825
|
-
const canonicalRoot = await realpath(rootPath);
|
|
21826
|
-
const candidate = await realpath(isAbsolute(requested) ? requested : resolve(canonicalRoot, requested)).catch(() => null);
|
|
21827
|
-
if (!candidate) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_NOT_FOUND", "artifact file does not exist");
|
|
21828
|
-
const relativePath = relative(canonicalRoot, candidate);
|
|
21829
|
-
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_INVALID", "artifact must be a file inside the project root");
|
|
21830
|
-
if (!(await stat(candidate)).isFile()) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_INVALID", "artifact must be a file");
|
|
21831
|
-
return relativePath.split(sep).join("/");
|
|
21832
|
-
};
|
|
21833
|
-
emit = async (projectId, change, workItemId) => {
|
|
21834
|
-
await this.options.eventBus.emit(eventKeys$1.projectWorkChanged, {
|
|
21835
|
-
projectId,
|
|
21836
|
-
change,
|
|
21837
|
-
...workItemId ? { workItemId } : {}
|
|
21838
|
-
});
|
|
21839
|
-
};
|
|
21840
|
-
};
|
|
21841
|
-
//#endregion
|
|
21842
|
-
//#region src/features/projects/types/project-observation.types.ts
|
|
21843
|
-
const PROJECT_OBSERVATION_PROTOCOL = "nextclaw.project/v1";
|
|
21844
|
-
var ProjectObservationError = class extends Error {
|
|
21845
|
-
constructor(code, message) {
|
|
21846
|
-
super(message);
|
|
21847
|
-
this.code = code;
|
|
21848
|
-
this.name = "ProjectObservationError";
|
|
21849
|
-
}
|
|
21850
|
-
};
|
|
21851
|
-
function isProjectObservationError(error) {
|
|
21852
|
-
return error instanceof ProjectObservationError;
|
|
21853
|
-
}
|
|
21854
|
-
//#endregion
|
|
21855
|
-
//#region src/features/projects/utils/project-observation-config.utils.ts
|
|
21856
|
-
const isRecord$8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21857
|
-
const readString$7 = (value) => {
|
|
21858
|
-
if (typeof value !== "string") return null;
|
|
21859
|
-
return value.trim() || null;
|
|
21860
|
-
};
|
|
21861
|
-
const collectUnknownKeyIssues = (value, allowed, owner) => Object.keys(value).flatMap((key) => allowed.includes(key) ? [] : [{
|
|
21862
|
-
code: "PROJECT_CONFIG_UNKNOWN_FIELD",
|
|
21863
|
-
message: `${owner} contains unknown field '${key}'.`
|
|
21864
|
-
}]);
|
|
21865
|
-
function parseContext(value) {
|
|
21866
|
-
if (value === void 0) return {
|
|
21867
|
-
value: [],
|
|
21868
|
-
issues: []
|
|
21869
|
-
};
|
|
21870
|
-
if (!Array.isArray(value)) return {
|
|
21871
|
-
value: [],
|
|
21872
|
-
issues: [{
|
|
21873
|
-
code: "PROJECT_CONFIG_CONTEXT_INVALID",
|
|
21874
|
-
message: "project.context must be an array."
|
|
21875
|
-
}]
|
|
21876
|
-
};
|
|
21877
|
-
const issues = [];
|
|
21878
|
-
return {
|
|
21879
|
-
value: value.flatMap((entry, index) => {
|
|
21880
|
-
if (!isRecord$8(entry)) {
|
|
21881
|
-
issues.push({
|
|
21882
|
-
code: "PROJECT_CONFIG_CONTEXT_INVALID",
|
|
21883
|
-
message: `project.context[${index}] must be an object.`
|
|
21884
|
-
});
|
|
21885
|
-
return [];
|
|
21886
|
-
}
|
|
21887
|
-
issues.push(...collectUnknownKeyIssues(entry, [
|
|
21888
|
-
"id",
|
|
21889
|
-
"role",
|
|
21890
|
-
"source"
|
|
21891
|
-
], `project.context[${index}]`));
|
|
21892
|
-
const id = readString$7(entry.id);
|
|
21893
|
-
const role = readString$7(entry.role);
|
|
21894
|
-
const source = readString$7(entry.source);
|
|
21895
|
-
if (!id || !role || !source) {
|
|
21896
|
-
issues.push({
|
|
21897
|
-
code: "PROJECT_CONFIG_CONTEXT_INVALID",
|
|
21898
|
-
message: `project.context[${index}] requires id, role and source.`
|
|
21899
|
-
});
|
|
21900
|
-
return [];
|
|
21901
|
-
}
|
|
21902
|
-
return [{
|
|
21903
|
-
id,
|
|
21904
|
-
role,
|
|
21905
|
-
source
|
|
21906
|
-
}];
|
|
21907
|
-
}),
|
|
21908
|
-
issues
|
|
21909
|
-
};
|
|
21910
|
-
}
|
|
21911
|
-
function parseWorkflows(value) {
|
|
21912
|
-
if (value === void 0) return {
|
|
21913
|
-
value: [],
|
|
21914
|
-
issues: []
|
|
21915
|
-
};
|
|
21916
|
-
if (!Array.isArray(value)) return {
|
|
21917
|
-
value: [],
|
|
21918
|
-
issues: [{
|
|
21919
|
-
code: "PROJECT_CONFIG_WORKFLOWS_INVALID",
|
|
21920
|
-
message: "workflows must be an array."
|
|
21921
|
-
}]
|
|
21922
|
-
};
|
|
21923
|
-
const issues = [];
|
|
21924
|
-
return {
|
|
21925
|
-
value: value.flatMap((entry, workflowIndex) => {
|
|
21926
|
-
if (!isRecord$8(entry) || !Array.isArray(entry.stages)) {
|
|
21927
|
-
issues.push({
|
|
21928
|
-
code: "PROJECT_CONFIG_WORKFLOW_INVALID",
|
|
21929
|
-
message: `workflows[${workflowIndex}] requires a stages array.`
|
|
21930
|
-
});
|
|
21931
|
-
return [];
|
|
21932
|
-
}
|
|
21933
|
-
issues.push(...collectUnknownKeyIssues(entry, [
|
|
21934
|
-
"id",
|
|
21935
|
-
"label",
|
|
21936
|
-
"stages"
|
|
21937
|
-
], `workflows[${workflowIndex}]`));
|
|
21938
|
-
const id = readString$7(entry.id);
|
|
21939
|
-
const label = readString$7(entry.label);
|
|
21940
|
-
const stages = entry.stages.flatMap((stage, stageIndex) => {
|
|
21941
|
-
if (!isRecord$8(stage)) {
|
|
21942
|
-
issues.push({
|
|
21943
|
-
code: "PROJECT_CONFIG_STAGE_INVALID",
|
|
21944
|
-
message: `workflows[${workflowIndex}].stages[${stageIndex}] must be an object.`
|
|
21945
|
-
});
|
|
21946
|
-
return [];
|
|
21947
|
-
}
|
|
21948
|
-
issues.push(...collectUnknownKeyIssues(stage, ["id", "label"], `workflows[${workflowIndex}].stages[${stageIndex}]`));
|
|
21949
|
-
const stageId = readString$7(stage.id);
|
|
21950
|
-
const stageLabel = readString$7(stage.label);
|
|
21951
|
-
if (!stageId || !stageLabel) {
|
|
21952
|
-
issues.push({
|
|
21953
|
-
code: "PROJECT_CONFIG_STAGE_INVALID",
|
|
21954
|
-
message: `workflows[${workflowIndex}].stages[${stageIndex}] requires id and label.`
|
|
21955
|
-
});
|
|
21956
|
-
return [];
|
|
21957
|
-
}
|
|
21958
|
-
return [{
|
|
21959
|
-
id: stageId,
|
|
21960
|
-
label: stageLabel
|
|
21961
|
-
}];
|
|
21962
|
-
});
|
|
21963
|
-
if (!id || !label) {
|
|
21964
|
-
issues.push({
|
|
21965
|
-
code: "PROJECT_CONFIG_WORKFLOW_INVALID",
|
|
21966
|
-
message: `workflows[${workflowIndex}] requires id and label.`
|
|
21967
|
-
});
|
|
21968
|
-
return [];
|
|
21969
|
-
}
|
|
21970
|
-
return [{
|
|
21971
|
-
id,
|
|
21972
|
-
label,
|
|
21973
|
-
stages
|
|
21974
|
-
}];
|
|
21975
|
-
}),
|
|
21976
|
-
issues
|
|
21977
|
-
};
|
|
21978
|
-
}
|
|
21979
|
-
function parseArtifactCategories(value) {
|
|
21980
|
-
if (value === void 0) return {
|
|
21981
|
-
value: [],
|
|
21982
|
-
issues: []
|
|
21983
|
-
};
|
|
21984
|
-
if (!Array.isArray(value)) return {
|
|
21985
|
-
value: [],
|
|
21986
|
-
issues: [{
|
|
21987
|
-
code: "PROJECT_CONFIG_ARTIFACTS_INVALID",
|
|
21988
|
-
message: "observation.artifacts must be an array."
|
|
21989
|
-
}]
|
|
21990
|
-
};
|
|
21991
|
-
const issues = [];
|
|
21992
|
-
return {
|
|
21993
|
-
value: value.flatMap((entry, index) => {
|
|
21994
|
-
if (!isRecord$8(entry) || !Array.isArray(entry.include)) {
|
|
21995
|
-
issues.push({
|
|
21996
|
-
code: "PROJECT_CONFIG_ARTIFACT_INVALID",
|
|
21997
|
-
message: `observation.artifacts[${index}] requires an include array.`
|
|
21998
|
-
});
|
|
21999
|
-
return [];
|
|
22000
|
-
}
|
|
22001
|
-
issues.push(...collectUnknownKeyIssues(entry, [
|
|
22002
|
-
"id",
|
|
22003
|
-
"label",
|
|
22004
|
-
"include"
|
|
22005
|
-
], `observation.artifacts[${index}]`));
|
|
22006
|
-
const id = readString$7(entry.id);
|
|
22007
|
-
const label = readString$7(entry.label);
|
|
22008
|
-
const include = entry.include.map(readString$7).filter((pattern) => pattern !== null);
|
|
22009
|
-
if (!id || !label || include.length !== entry.include.length || include.length === 0) {
|
|
22010
|
-
issues.push({
|
|
22011
|
-
code: "PROJECT_CONFIG_ARTIFACT_INVALID",
|
|
22012
|
-
message: `observation.artifacts[${index}] requires id, label and non-empty string patterns.`
|
|
22013
|
-
});
|
|
22014
|
-
return [];
|
|
22015
|
-
}
|
|
22016
|
-
return [{
|
|
22017
|
-
id,
|
|
22018
|
-
label,
|
|
22019
|
-
include
|
|
22020
|
-
}];
|
|
22021
|
-
}),
|
|
22022
|
-
issues
|
|
22023
|
-
};
|
|
22024
|
-
}
|
|
22025
|
-
function parseSkillRoots(value) {
|
|
22026
|
-
if (value === void 0) return {
|
|
22027
|
-
value: [".agents/skills"],
|
|
22028
|
-
issues: []
|
|
22029
|
-
};
|
|
22030
|
-
if (!Array.isArray(value)) return {
|
|
22031
|
-
value: [],
|
|
22032
|
-
issues: [{
|
|
22033
|
-
code: "PROJECT_CONFIG_SKILLS_INVALID",
|
|
22034
|
-
message: "observation.skills must be an array."
|
|
22035
|
-
}]
|
|
22036
|
-
};
|
|
22037
|
-
const issues = [];
|
|
22038
|
-
return {
|
|
22039
|
-
value: value.flatMap((entry, index) => {
|
|
22040
|
-
if (!isRecord$8(entry)) {
|
|
22041
|
-
issues.push({
|
|
22042
|
-
code: "PROJECT_CONFIG_SKILL_INVALID",
|
|
22043
|
-
message: `observation.skills[${index}] must be an object.`
|
|
22044
|
-
});
|
|
22045
|
-
return [];
|
|
22046
|
-
}
|
|
22047
|
-
issues.push(...collectUnknownKeyIssues(entry, ["root"], `observation.skills[${index}]`));
|
|
22048
|
-
const root = readString$7(entry.root);
|
|
22049
|
-
if (!root) {
|
|
22050
|
-
issues.push({
|
|
22051
|
-
code: "PROJECT_CONFIG_SKILL_INVALID",
|
|
22052
|
-
message: `observation.skills[${index}] requires root.`
|
|
22053
|
-
});
|
|
22054
|
-
return [];
|
|
22055
|
-
}
|
|
22056
|
-
return [root];
|
|
22057
|
-
}),
|
|
22058
|
-
issues
|
|
22059
|
-
};
|
|
22060
|
-
}
|
|
22061
|
-
function parseProjectObservationConfig(source) {
|
|
22062
|
-
const issues = [];
|
|
22063
|
-
let parsed;
|
|
22064
|
-
try {
|
|
22065
|
-
parsed = parse(source);
|
|
22066
|
-
} catch (error) {
|
|
22067
|
-
return {
|
|
22068
|
-
config: null,
|
|
22069
|
-
issues: [{
|
|
22070
|
-
code: "PROJECT_CONFIG_YAML_INVALID",
|
|
22071
|
-
message: error instanceof Error ? error.message : "project.yaml is invalid YAML."
|
|
22072
|
-
}]
|
|
22073
|
-
};
|
|
22074
|
-
}
|
|
22075
|
-
if (!isRecord$8(parsed)) return {
|
|
22076
|
-
config: null,
|
|
22077
|
-
issues: [{
|
|
22078
|
-
code: "PROJECT_CONFIG_INVALID",
|
|
22079
|
-
message: "project.yaml must contain an object."
|
|
22080
|
-
}]
|
|
22081
|
-
};
|
|
22082
|
-
issues.push(...collectUnknownKeyIssues(parsed, [
|
|
22083
|
-
"schema_version",
|
|
22084
|
-
"project",
|
|
22085
|
-
"workflows",
|
|
22086
|
-
"observation"
|
|
22087
|
-
], "project.yaml"));
|
|
22088
|
-
if (parsed.schema_version !== 1) return {
|
|
22089
|
-
config: null,
|
|
22090
|
-
issues: [{
|
|
22091
|
-
code: "PROJECT_CONFIG_VERSION_UNSUPPORTED",
|
|
22092
|
-
message: "Only schema_version 1 is supported."
|
|
22093
|
-
}, ...issues]
|
|
22094
|
-
};
|
|
22095
|
-
const project = isRecord$8(parsed.project) ? parsed.project : {};
|
|
22096
|
-
const observation = isRecord$8(parsed.observation) ? parsed.observation : {};
|
|
22097
|
-
if (parsed.project !== void 0 && !isRecord$8(parsed.project)) issues.push({
|
|
22098
|
-
code: "PROJECT_CONFIG_PROJECT_INVALID",
|
|
22099
|
-
message: "project must be an object."
|
|
22100
|
-
});
|
|
22101
|
-
if (parsed.observation !== void 0 && !isRecord$8(parsed.observation)) issues.push({
|
|
22102
|
-
code: "PROJECT_CONFIG_OBSERVATION_INVALID",
|
|
22103
|
-
message: "observation must be an object."
|
|
22104
|
-
});
|
|
22105
|
-
issues.push(...collectUnknownKeyIssues(project, ["summary", "context"], "project"));
|
|
22106
|
-
issues.push(...collectUnknownKeyIssues(observation, [
|
|
22107
|
-
"markers",
|
|
22108
|
-
"work_items",
|
|
22109
|
-
"artifacts",
|
|
22110
|
-
"skills"
|
|
22111
|
-
], "observation"));
|
|
22112
|
-
if (observation.markers !== void 0) {
|
|
22113
|
-
if (!(Array.isArray(observation.markers) ? observation.markers : []).some((marker) => isRecord$8(marker) && marker.protocol === "nextclaw.project/v1")) issues.push({
|
|
22114
|
-
code: "PROJECT_CONFIG_MARKERS_INVALID",
|
|
22115
|
-
message: `observation.markers must enable protocol '${PROJECT_OBSERVATION_PROTOCOL}'.`
|
|
22116
|
-
});
|
|
22117
|
-
}
|
|
22118
|
-
const context = parseContext(project.context);
|
|
22119
|
-
const workflows = parseWorkflows(parsed.workflows);
|
|
22120
|
-
const artifactCategories = parseArtifactCategories(observation.artifacts);
|
|
22121
|
-
const skillRoots = parseSkillRoots(observation.skills);
|
|
22122
|
-
issues.push(...context.issues, ...workflows.issues, ...artifactCategories.issues, ...skillRoots.issues);
|
|
22123
|
-
return {
|
|
22124
|
-
config: {
|
|
22125
|
-
...readString$7(project.summary) ? { summary: readString$7(project.summary) } : {},
|
|
22126
|
-
context: context.value,
|
|
22127
|
-
workflows: workflows.value,
|
|
22128
|
-
artifactCategories: artifactCategories.value,
|
|
22129
|
-
skillRoots: skillRoots.value
|
|
22130
|
-
},
|
|
22131
|
-
issues
|
|
22132
|
-
};
|
|
22133
|
-
}
|
|
22134
|
-
//#endregion
|
|
22135
|
-
//#region src/features/projects/utils/project-observation-files.utils.ts
|
|
22136
|
-
const IGNORED_DIRECTORIES = new Set([
|
|
22137
|
-
".git",
|
|
22138
|
-
".hg",
|
|
22139
|
-
".svn",
|
|
22140
|
-
"node_modules"
|
|
22141
|
-
]);
|
|
22142
|
-
const MAX_ARTIFACT_FILES = 1e4;
|
|
22143
|
-
const MAX_DEPTH = 12;
|
|
22144
|
-
const toPortablePath = (value) => value.split(sep).join("/");
|
|
22145
|
-
function globSearchBase(pattern) {
|
|
22146
|
-
const segments = pattern.split("/");
|
|
22147
|
-
const firstDynamicSegment = segments.findIndex((segment) => segment.includes("*") || segment.includes("?"));
|
|
22148
|
-
if (firstDynamicSegment >= 0) return segments.slice(0, firstDynamicSegment).join("/");
|
|
22149
|
-
return segments.slice(0, -1).join("/");
|
|
22150
|
-
}
|
|
22151
|
-
function shouldVisitDirectory(relativeDirectory, searchBases) {
|
|
22152
|
-
if (!relativeDirectory) return true;
|
|
22153
|
-
return searchBases.some((base) => !base || base === relativeDirectory || base.startsWith(`${relativeDirectory}/`) || relativeDirectory.startsWith(`${base}/`));
|
|
22154
|
-
}
|
|
22155
|
-
function compareFileRecency(left, right) {
|
|
22156
|
-
return left.updatedAt.localeCompare(right.updatedAt) || left.relativePath.localeCompare(right.relativePath);
|
|
22157
|
-
}
|
|
22158
|
-
function siftOldestFileDown(files, index) {
|
|
22159
|
-
let parent = index;
|
|
22160
|
-
while (true) {
|
|
22161
|
-
const left = parent * 2 + 1;
|
|
22162
|
-
const right = left + 1;
|
|
22163
|
-
let oldest = parent;
|
|
22164
|
-
if (left < files.length && compareFileRecency(files[left], files[oldest]) < 0) oldest = left;
|
|
22165
|
-
if (right < files.length && compareFileRecency(files[right], files[oldest]) < 0) oldest = right;
|
|
22166
|
-
if (oldest === parent) return;
|
|
22167
|
-
[files[parent], files[oldest]] = [files[oldest], files[parent]];
|
|
22168
|
-
parent = oldest;
|
|
22169
|
-
}
|
|
22170
|
-
}
|
|
22171
|
-
function keepMostRecentArtifactFile(files, file, maxArtifactFiles) {
|
|
22172
|
-
if (files.length < maxArtifactFiles) {
|
|
22173
|
-
files.push(file);
|
|
22174
|
-
let child = files.length - 1;
|
|
22175
|
-
while (child > 0) {
|
|
22176
|
-
const parent = Math.floor((child - 1) / 2);
|
|
22177
|
-
if (compareFileRecency(files[child], files[parent]) >= 0) break;
|
|
22178
|
-
[files[child], files[parent]] = [files[parent], files[child]];
|
|
22179
|
-
child = parent;
|
|
22180
|
-
}
|
|
22181
|
-
return;
|
|
22182
|
-
}
|
|
22183
|
-
if (compareFileRecency(file, files[0]) <= 0) return;
|
|
22184
|
-
files[0] = file;
|
|
22185
|
-
siftOldestFileDown(files, 0);
|
|
22186
|
-
}
|
|
22187
|
-
function normalizeProjectRelativePath(value) {
|
|
22188
|
-
const normalized = value.trim().replaceAll("\\", "/").replace(/^\.\//, "");
|
|
22189
|
-
if (!normalized || normalized.startsWith("/") || isAbsolute(normalized)) return null;
|
|
22190
|
-
const segments = normalized.split("/");
|
|
22191
|
-
if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) return null;
|
|
22192
|
-
return segments.join("/");
|
|
22193
|
-
}
|
|
22194
|
-
function resolveInsideProject(rootPath, projectRelativePath) {
|
|
22195
|
-
const normalized = normalizeProjectRelativePath(projectRelativePath);
|
|
22196
|
-
if (!normalized) return null;
|
|
22197
|
-
const target = resolve(rootPath, normalized);
|
|
22198
|
-
const targetRelative = relative(rootPath, target);
|
|
22199
|
-
return targetRelative && !targetRelative.startsWith(`..${sep}`) && targetRelative !== ".." ? target : null;
|
|
22200
|
-
}
|
|
22201
|
-
async function observeProjectFile(rootPath, projectRelativePath) {
|
|
22202
|
-
const target = resolveInsideProject(rootPath, projectRelativePath);
|
|
22203
|
-
if (!target) return null;
|
|
22204
|
-
try {
|
|
22205
|
-
const targetLstat = await lstat(target);
|
|
22206
|
-
if (targetLstat.isSymbolicLink() || !targetLstat.isFile()) return null;
|
|
22207
|
-
const canonicalRoot = await realpath(rootPath);
|
|
22208
|
-
const canonicalTarget = await realpath(target);
|
|
22209
|
-
const canonicalRelative = relative(canonicalRoot, canonicalTarget);
|
|
22210
|
-
if (canonicalRelative.startsWith(`..${sep}`) || canonicalRelative === "..") return null;
|
|
22211
|
-
const targetStat = await stat(canonicalTarget);
|
|
22212
|
-
return {
|
|
22213
|
-
createdAt: targetStat.birthtime.toISOString(),
|
|
22214
|
-
relativePath: normalizeProjectRelativePath(projectRelativePath),
|
|
22215
|
-
size: targetStat.size,
|
|
22216
|
-
updatedAt: targetStat.mtime.toISOString()
|
|
22217
|
-
};
|
|
22218
|
-
} catch {
|
|
22219
|
-
return null;
|
|
22220
|
-
}
|
|
22221
|
-
}
|
|
22222
|
-
function globToRegExp(pattern) {
|
|
22223
|
-
const normalized = normalizeProjectRelativePath(pattern);
|
|
22224
|
-
if (!normalized) return null;
|
|
22225
|
-
let source = "^";
|
|
22226
|
-
for (let index = 0; index < normalized.length; index += 1) {
|
|
22227
|
-
const character = normalized[index];
|
|
22228
|
-
const next = normalized[index + 1];
|
|
22229
|
-
if (character === "*" && next === "*") {
|
|
22230
|
-
const after = normalized[index + 2];
|
|
22231
|
-
source += after === "/" ? "(?:.*/)?" : ".*";
|
|
22232
|
-
index += after === "/" ? 2 : 1;
|
|
22233
|
-
continue;
|
|
22234
|
-
}
|
|
22235
|
-
if (character === "*") {
|
|
22236
|
-
source += "[^/]*";
|
|
22237
|
-
continue;
|
|
22238
|
-
}
|
|
22239
|
-
if (character === "?") {
|
|
22240
|
-
source += "[^/]";
|
|
22241
|
-
continue;
|
|
22242
|
-
}
|
|
22243
|
-
source += /[|\\{}()[\]^$+?.]/.test(character) ? `\\${character}` : character;
|
|
22244
|
-
}
|
|
22245
|
-
return new RegExp(`${source}$`);
|
|
22246
|
-
}
|
|
22247
|
-
async function scanProjectArtifactFiles(rootPath, categories, options = {}) {
|
|
22248
|
-
const issues = [];
|
|
22249
|
-
const compiled = categories.flatMap((category) => category.include.flatMap((pattern) => {
|
|
22250
|
-
const matcher = globToRegExp(pattern);
|
|
22251
|
-
if (!matcher) {
|
|
22252
|
-
issues.push({
|
|
22253
|
-
code: "PROJECT_ARTIFACT_PATTERN_INVALID",
|
|
22254
|
-
message: `Artifact pattern '${pattern}' is not a safe project-relative glob.`,
|
|
22255
|
-
projectRelativePath: pattern
|
|
22256
|
-
});
|
|
22257
|
-
return [];
|
|
22258
|
-
}
|
|
22259
|
-
return [{
|
|
22260
|
-
...category,
|
|
22261
|
-
pattern,
|
|
22262
|
-
matcher
|
|
22263
|
-
}];
|
|
22264
|
-
}));
|
|
22265
|
-
if (compiled.length === 0) return {
|
|
22266
|
-
matches: [],
|
|
22267
|
-
issues
|
|
22268
|
-
};
|
|
22269
|
-
const files = [];
|
|
22270
|
-
let matchedFileCount = 0;
|
|
22271
|
-
const maxArtifactFiles = options.maxArtifactFiles ?? MAX_ARTIFACT_FILES;
|
|
22272
|
-
const searchBases = [...new Set(compiled.map((rule) => globSearchBase(rule.pattern)))];
|
|
22273
|
-
const visit = async (directory, depth) => {
|
|
22274
|
-
if (depth > MAX_DEPTH) return;
|
|
22275
|
-
const entries = await readdir(directory, { withFileTypes: true });
|
|
22276
|
-
for (const entry of entries) {
|
|
22277
|
-
if (entry.isSymbolicLink()) continue;
|
|
22278
|
-
const absolutePath = resolve(directory, entry.name);
|
|
22279
|
-
if (entry.isDirectory()) {
|
|
22280
|
-
const relativeDirectory = toPortablePath(relative(rootPath, absolutePath));
|
|
22281
|
-
if (!IGNORED_DIRECTORIES.has(entry.name) && shouldVisitDirectory(relativeDirectory, searchBases)) await visit(absolutePath, depth + 1);
|
|
22282
|
-
continue;
|
|
22283
|
-
}
|
|
22284
|
-
if (!entry.isFile()) continue;
|
|
22285
|
-
const relativePath = toPortablePath(relative(rootPath, absolutePath));
|
|
22286
|
-
if (!compiled.some((rule) => rule.matcher.test(relativePath))) continue;
|
|
22287
|
-
const fileStat = await stat(absolutePath);
|
|
22288
|
-
matchedFileCount += 1;
|
|
22289
|
-
keepMostRecentArtifactFile(files, {
|
|
22290
|
-
createdAt: fileStat.birthtime.toISOString(),
|
|
22291
|
-
relativePath,
|
|
22292
|
-
size: fileStat.size,
|
|
22293
|
-
updatedAt: fileStat.mtime.toISOString()
|
|
22294
|
-
}, maxArtifactFiles);
|
|
22295
|
-
}
|
|
22296
|
-
};
|
|
22297
|
-
try {
|
|
22298
|
-
await visit(rootPath, 0);
|
|
22299
|
-
} catch (error) {
|
|
22300
|
-
issues.push({
|
|
22301
|
-
code: "PROJECT_ARTIFACT_SCAN_FAILED",
|
|
22302
|
-
message: error instanceof Error ? error.message : "Project artifact scan failed."
|
|
22303
|
-
});
|
|
22304
|
-
}
|
|
22305
|
-
if (matchedFileCount > maxArtifactFiles) issues.push({
|
|
22306
|
-
code: "PROJECT_ARTIFACT_SCAN_LIMIT",
|
|
22307
|
-
message: `Showing the ${maxArtifactFiles} most recently updated files out of ${matchedFileCount} matched artifacts.`
|
|
22308
|
-
});
|
|
22309
|
-
const matchesByPath = /* @__PURE__ */ new Map();
|
|
22310
|
-
for (const rule of compiled) for (const file of files) {
|
|
22311
|
-
if (!rule.matcher.test(file.relativePath) || matchesByPath.has(file.relativePath)) continue;
|
|
22312
|
-
matchesByPath.set(file.relativePath, {
|
|
22313
|
-
...file,
|
|
22314
|
-
categoryId: rule.id,
|
|
22315
|
-
categoryLabel: rule.label
|
|
22316
|
-
});
|
|
22317
|
-
}
|
|
22318
|
-
return {
|
|
22319
|
-
matches: [...matchesByPath.values()],
|
|
22320
|
-
issues
|
|
22321
|
-
};
|
|
22322
|
-
}
|
|
22323
|
-
//#endregion
|
|
22324
|
-
//#region src/features/projects/utils/project-observation-projection.utils.ts
|
|
22325
|
-
const projectObservationConfigReference = (asOf) => ({
|
|
22326
|
-
kind: "project-config",
|
|
22327
|
-
label: "项目配置",
|
|
22328
|
-
observedAt: asOf,
|
|
22329
|
-
projectRelativePath: ".nextclaw/project.yaml"
|
|
22330
|
-
});
|
|
22331
|
-
const projectObservationFileReference = (path, observedAt) => ({
|
|
22332
|
-
kind: "file-observation",
|
|
22333
|
-
label: "文件观测",
|
|
22334
|
-
observedAt,
|
|
22335
|
-
projectRelativePath: path
|
|
22336
|
-
});
|
|
22337
|
-
const markerReference = (marker) => ({
|
|
22338
|
-
kind: "ai-report",
|
|
22339
|
-
label: "AI 报告",
|
|
22340
|
-
observedAt: marker.timestamp,
|
|
22341
|
-
sessionId: marker.sessionId,
|
|
22342
|
-
messageId: marker.messageId
|
|
22343
|
-
});
|
|
22344
|
-
const markerActivityMessage = (marker) => {
|
|
22345
|
-
switch (marker.kind) {
|
|
22346
|
-
case "work-item": return `AI 报告工作项“${marker.name}”为 ${marker.status}`;
|
|
22347
|
-
case "artifact": return `AI 报告产物 ${marker.path}`;
|
|
22348
|
-
case "schedule": return `AI 报告 ${marker.itemId} 的计划信息`;
|
|
22349
|
-
case "signal": return marker.message;
|
|
22350
|
-
case "request": return marker.prompt;
|
|
22351
|
-
}
|
|
22352
|
-
};
|
|
22353
|
-
const readOptionalString$9 = (value) => {
|
|
22354
|
-
if (typeof value !== "string") return void 0;
|
|
22355
|
-
return value.trim() || void 0;
|
|
22356
|
-
};
|
|
22357
|
-
const readProjectRunState = (session) => {
|
|
22358
|
-
const state = (session.metadata?.last_activity_preview)?.state;
|
|
22359
|
-
if (state === "running" || state === "completed" || state === "failed" || state === "cancelled" || state === "idle") return state;
|
|
22360
|
-
return session.status === "running" ? "running" : "idle";
|
|
22361
|
-
};
|
|
22362
|
-
function projectObservedRuns(sessions, markers) {
|
|
22363
|
-
const latestWorkItemIdBySession = /* @__PURE__ */ new Map();
|
|
22364
|
-
for (const marker of markers) if (marker.kind === "work-item") latestWorkItemIdBySession.set(marker.sessionId, marker.id);
|
|
22365
|
-
return sessions.map((session) => {
|
|
22366
|
-
const preview = session.metadata?.last_activity_preview;
|
|
22367
|
-
const updatedAt = readOptionalString$9(preview?.timestamp) ?? session.lastMessageAt ?? session.updatedAt;
|
|
22368
|
-
const model = readOptionalString$9(session.metadata?.preferred_model) ?? readOptionalString$9(session.metadata?.preferredModel) ?? readOptionalString$9(session.metadata?.model);
|
|
22369
|
-
const label = readOptionalString$9(session.metadata?.label);
|
|
22370
|
-
const statusText = readOptionalString$9(preview?.statusText);
|
|
22371
|
-
const workItemId = latestWorkItemIdBySession.get(session.sessionId);
|
|
22372
|
-
return {
|
|
22373
|
-
sessionId: session.sessionId,
|
|
22374
|
-
state: readProjectRunState(session),
|
|
22375
|
-
updatedAt,
|
|
22376
|
-
...session.agentId ? { agentId: session.agentId } : {},
|
|
22377
|
-
...model ? { model } : {},
|
|
22378
|
-
...label ? { label } : {},
|
|
22379
|
-
...statusText ? { statusText } : {},
|
|
22380
|
-
...workItemId ? { workItemId } : {},
|
|
22381
|
-
reference: {
|
|
22382
|
-
kind: "system-record",
|
|
22383
|
-
label: "会话运行",
|
|
22384
|
-
observedAt: updatedAt,
|
|
22385
|
-
sessionId: session.sessionId
|
|
22386
|
-
}
|
|
22387
|
-
};
|
|
22388
|
-
}).sort((left, right) => {
|
|
22389
|
-
return Number(right.state === "running") - Number(left.state === "running") || right.updatedAt.localeCompare(left.updatedAt);
|
|
22390
|
-
});
|
|
22391
|
-
}
|
|
22392
|
-
function projectObservedWorkItems(markers, workflows, addDiagnostic) {
|
|
22393
|
-
const workItems = /* @__PURE__ */ new Map();
|
|
22394
|
-
const schedules = /* @__PURE__ */ new Map();
|
|
22395
|
-
for (const marker of markers) {
|
|
22396
|
-
if (marker.kind === "work-item") workItems.set(marker.id, marker);
|
|
22397
|
-
if (marker.kind === "schedule") schedules.set(marker.itemId, marker);
|
|
22398
|
-
}
|
|
22399
|
-
return [...workItems.values()].map((marker) => {
|
|
22400
|
-
const inferredWorkflows = marker.stageId ? workflows.filter((entry) => entry.stages.some((stage) => stage.id === marker.stageId)) : [];
|
|
22401
|
-
const workflow = marker.workflowId ? workflows.find((entry) => entry.id === marker.workflowId) : inferredWorkflows.length === 1 ? inferredWorkflows[0] : void 0;
|
|
22402
|
-
if (marker.workflowId && !workflow) addDiagnostic("sessions", "warning", "PROJECT_MARKER_WORKFLOW_UNKNOWN", `Work item '${marker.id}' references unknown workflow '${marker.workflowId}'.`, {
|
|
22403
|
-
sessionId: marker.sessionId,
|
|
22404
|
-
messageId: marker.messageId
|
|
22405
|
-
});
|
|
22406
|
-
if (marker.stageId && (!workflow || !workflow.stages.some((stage) => stage.id === marker.stageId))) addDiagnostic("sessions", "warning", "PROJECT_MARKER_STAGE_UNKNOWN", `Work item '${marker.id}' references unknown stage '${marker.stageId}'.`, {
|
|
22407
|
-
sessionId: marker.sessionId,
|
|
22408
|
-
messageId: marker.messageId
|
|
22409
|
-
});
|
|
22410
|
-
const schedule = schedules.get(marker.id);
|
|
22411
|
-
return {
|
|
22412
|
-
id: marker.id,
|
|
22413
|
-
name: marker.name,
|
|
22414
|
-
status: marker.status,
|
|
22415
|
-
...workflow ? { workflowId: workflow.id } : {},
|
|
22416
|
-
...workflow && marker.stageId && workflow.stages.some((stage) => stage.id === marker.stageId) ? { stageId: marker.stageId } : {},
|
|
22417
|
-
...schedule ? { schedule: {
|
|
22418
|
-
...schedule.start ? { start: schedule.start } : {},
|
|
22419
|
-
...schedule.end ? { end: schedule.end } : {},
|
|
22420
|
-
milestone: schedule.milestone,
|
|
22421
|
-
dependsOn: schedule.dependsOn
|
|
22422
|
-
} } : {},
|
|
22423
|
-
updatedAt: marker.timestamp,
|
|
22424
|
-
reference: markerReference(marker)
|
|
22425
|
-
};
|
|
22426
|
-
}).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
22427
|
-
}
|
|
22428
|
-
async function mergeProjectObservedArtifacts(rootPath, observed, config, markers, addDiagnostic) {
|
|
22429
|
-
const artifacts = new Map(observed.map((artifact) => [`${artifact.categoryId}:${artifact.path}`, artifact]));
|
|
22430
|
-
for (const marker of markers) {
|
|
22431
|
-
if (marker.kind !== "artifact") continue;
|
|
22432
|
-
const category = config?.artifactCategories.find((entry) => entry.id === marker.categoryId);
|
|
22433
|
-
const path = normalizeProjectRelativePath(marker.path);
|
|
22434
|
-
const file = path ? await observeProjectFile(rootPath, path) : null;
|
|
22435
|
-
if (!category) addDiagnostic("sessions", "warning", "PROJECT_MARKER_CATEGORY_UNKNOWN", `Artifact marker references unknown category '${marker.categoryId}'.`, {
|
|
22436
|
-
sessionId: marker.sessionId,
|
|
22437
|
-
messageId: marker.messageId
|
|
22438
|
-
});
|
|
22439
|
-
if (!file) addDiagnostic("files", "warning", "PROJECT_MARKER_ARTIFACT_UNAVAILABLE", `Artifact '${marker.path}' is missing or outside the project.`, {
|
|
22440
|
-
projectRelativePath: marker.path,
|
|
22441
|
-
sessionId: marker.sessionId,
|
|
22442
|
-
messageId: marker.messageId
|
|
22443
|
-
});
|
|
22444
|
-
const normalizedPath = path ?? marker.path;
|
|
22445
|
-
const key = `${marker.categoryId}:${normalizedPath}`;
|
|
22446
|
-
const existing = artifacts.get(key);
|
|
22447
|
-
if (existing) {
|
|
22448
|
-
artifacts.set(key, {
|
|
22449
|
-
...existing,
|
|
22450
|
-
itemId: marker.itemId,
|
|
22451
|
-
references: [...existing.references, markerReference(marker)]
|
|
22452
|
-
});
|
|
22453
|
-
continue;
|
|
22454
|
-
}
|
|
22455
|
-
artifacts.set(key, {
|
|
22456
|
-
id: key,
|
|
22457
|
-
path: normalizedPath,
|
|
22458
|
-
categoryId: marker.categoryId,
|
|
22459
|
-
categoryLabel: category?.label ?? marker.categoryId,
|
|
22460
|
-
exists: file !== null,
|
|
22461
|
-
itemId: marker.itemId,
|
|
22462
|
-
...file ? {
|
|
22463
|
-
size: file.size,
|
|
22464
|
-
fileCreatedAt: file.createdAt,
|
|
22465
|
-
fileUpdatedAt: file.updatedAt
|
|
22466
|
-
} : {},
|
|
22467
|
-
references: [markerReference(marker), ...file ? [projectObservationFileReference(file.relativePath, file.updatedAt)] : []]
|
|
22468
|
-
});
|
|
22469
|
-
}
|
|
22470
|
-
return [...artifacts.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
22471
|
-
}
|
|
22472
|
-
function projectObservedSignals(markers) {
|
|
22473
|
-
const signals = /* @__PURE__ */ new Map();
|
|
22474
|
-
for (const marker of markers) if (marker.kind === "signal") signals.set(marker.id, marker);
|
|
22475
|
-
return [...signals.values()].map((marker) => ({
|
|
22476
|
-
id: marker.id,
|
|
22477
|
-
...marker.itemId ? { itemId: marker.itemId } : {},
|
|
22478
|
-
status: marker.status,
|
|
22479
|
-
level: marker.level,
|
|
22480
|
-
message: marker.message,
|
|
22481
|
-
updatedAt: marker.timestamp,
|
|
22482
|
-
reference: markerReference(marker)
|
|
22483
|
-
})).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
22484
|
-
}
|
|
22485
|
-
function projectObservedRequests(markers, responses) {
|
|
22486
|
-
const requests = /* @__PURE__ */ new Map();
|
|
22487
|
-
for (const marker of markers) if (marker.kind === "request") requests.set(marker.id, marker);
|
|
22488
|
-
return [...requests.values()].map((marker) => ({
|
|
22489
|
-
id: marker.id,
|
|
22490
|
-
...marker.itemId ? { itemId: marker.itemId } : {},
|
|
22491
|
-
status: marker.status,
|
|
22492
|
-
response: marker.response,
|
|
22493
|
-
prompt: marker.prompt,
|
|
22494
|
-
updatedAt: marker.timestamp,
|
|
22495
|
-
...responses.get(marker.id) ? { reply: responses.get(marker.id) } : {},
|
|
22496
|
-
reference: markerReference(marker)
|
|
22497
|
-
})).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
22498
|
-
}
|
|
22499
|
-
const projectObservedActivity = (markers) => markers.map((marker) => ({
|
|
22500
|
-
id: `${marker.messageId}:${marker.line}:${marker.kind}`,
|
|
22501
|
-
kind: marker.kind,
|
|
22502
|
-
message: markerActivityMessage(marker),
|
|
22503
|
-
at: marker.timestamp,
|
|
22504
|
-
...marker.kind === "work-item" ? { itemId: marker.id } : marker.kind === "artifact" || marker.kind === "schedule" ? { itemId: marker.itemId } : marker.itemId ? { itemId: marker.itemId } : {},
|
|
22505
|
-
reference: markerReference(marker)
|
|
22506
|
-
})).sort((left, right) => right.at.localeCompare(left.at));
|
|
22507
|
-
//#endregion
|
|
22508
|
-
//#region src/features/projects/utils/project-observation-marker.utils.ts
|
|
22509
|
-
function createProjectObservationMarkerParseState() {
|
|
22510
|
-
return {
|
|
22511
|
-
currentWorkItemIdBySession: /* @__PURE__ */ new Map(),
|
|
22512
|
-
requestsById: /* @__PURE__ */ new Map(),
|
|
22513
|
-
workItemsById: /* @__PURE__ */ new Map()
|
|
22514
|
-
};
|
|
22515
|
-
}
|
|
22516
|
-
const ID_VALUE = "[a-z0-9][a-z0-9._-]*";
|
|
22517
|
-
const ID = `(${ID_VALUE})`;
|
|
22518
|
-
const OPTIONAL_ID = `(${ID_VALUE}|none)`;
|
|
22519
|
-
const TEXT = "([^\"\\]\\r\\n]{1,240})";
|
|
22520
|
-
const DATE = "(\\d{4}-\\d{2}-\\d{2}|none)";
|
|
22521
|
-
const PREFIX = "\\[nextclaw\\.project/v1 ";
|
|
22522
|
-
const LEGACY_WORK_ITEM_PATTERN = new RegExp(`^${PREFIX}kind=work-item id=${ID} title="${TEXT}" workflow=${OPTIONAL_ID} stage=${OPTIONAL_ID} status=(active|blocked|completed|cancelled)\\]$`);
|
|
22523
|
-
const LEGACY_ARTIFACT_PATTERN = new RegExp(`^${PREFIX}kind=artifact item=${ID} path="${TEXT}" category=${ID}\\]$`);
|
|
22524
|
-
const LEGACY_SCHEDULE_PATTERN = new RegExp(`^${PREFIX}kind=schedule item=${ID} start=${DATE} end=${DATE} milestone=(true|false) depends-on=([a-z0-9._,-]+|none)\\]$`);
|
|
22525
|
-
const LEGACY_SIGNAL_PATTERN = new RegExp(`^${PREFIX}kind=signal id=${ID} item=${OPTIONAL_ID} status=(open|resolved) level=(info|attention|warning) message="${TEXT}"\\]$`);
|
|
22526
|
-
const LEGACY_REQUEST_PATTERN = new RegExp(`^${PREFIX}kind=request id=${ID} item=${OPTIONAL_ID} status=(open|resolved|expired) response=(confirm-reject|open-session) prompt="${TEXT}"\\]$`);
|
|
22527
|
-
const ID_PATTERN = new RegExp(`^${ID_VALUE}$`);
|
|
22528
|
-
const FIELD_PATTERN = /([a-z][a-z-]*)=(?:"([^"\\\]\r\n]{1,240})"|([^\s\]]+))/y;
|
|
22529
|
-
const WORK_ITEM_STATUSES = new Set([
|
|
22530
|
-
"active",
|
|
22531
|
-
"blocked",
|
|
22532
|
-
"completed",
|
|
22533
|
-
"cancelled"
|
|
22534
|
-
]);
|
|
22535
|
-
const REQUEST_STATUSES = new Set([
|
|
22536
|
-
"open",
|
|
22537
|
-
"resolved",
|
|
22538
|
-
"expired"
|
|
22539
|
-
]);
|
|
22540
|
-
const REQUEST_RESPONSES = new Set(["confirm-reject", "open-session"]);
|
|
22541
|
-
const optional = (value) => value === "none" ? void 0 : value;
|
|
22542
|
-
function parseFields(value) {
|
|
22543
|
-
const fields = /* @__PURE__ */ new Map();
|
|
22544
|
-
let cursor = 0;
|
|
22545
|
-
while (cursor < value.length) {
|
|
22546
|
-
FIELD_PATTERN.lastIndex = cursor;
|
|
22547
|
-
const match = FIELD_PATTERN.exec(value);
|
|
22548
|
-
if (!match || fields.has(match[1])) return null;
|
|
22549
|
-
fields.set(match[1], match[2] ?? match[3]);
|
|
22550
|
-
cursor = FIELD_PATTERN.lastIndex;
|
|
22551
|
-
if (cursor === value.length) break;
|
|
22552
|
-
if (value[cursor] !== " ") return null;
|
|
22553
|
-
cursor += 1;
|
|
22554
|
-
}
|
|
22555
|
-
return fields;
|
|
22556
|
-
}
|
|
22557
|
-
function hasOnlyFields(fields, allowed) {
|
|
22558
|
-
const allowedSet = new Set(allowed);
|
|
22559
|
-
return [...fields.keys()].every((key) => allowedSet.has(key));
|
|
22560
|
-
}
|
|
22561
|
-
function rememberWorkItem(marker, state) {
|
|
22562
|
-
state.currentWorkItemIdBySession.set(marker.sessionId, marker.id);
|
|
22563
|
-
state.workItemsById.set(marker.id, {
|
|
22564
|
-
id: marker.id,
|
|
22565
|
-
name: marker.name,
|
|
22566
|
-
...marker.workflowId ? { workflowId: marker.workflowId } : {},
|
|
22567
|
-
...marker.stageId ? { stageId: marker.stageId } : {},
|
|
22568
|
-
status: marker.status
|
|
22569
|
-
});
|
|
22570
|
-
}
|
|
22571
|
-
function rememberRequest(marker, state) {
|
|
22572
|
-
state.requestsById.set(marker.id, {
|
|
22573
|
-
id: marker.id,
|
|
22574
|
-
...marker.itemId ? { itemId: marker.itemId } : {},
|
|
22575
|
-
status: marker.status,
|
|
22576
|
-
response: marker.response,
|
|
22577
|
-
prompt: marker.prompt
|
|
22578
|
-
});
|
|
22579
|
-
}
|
|
22580
|
-
function parseLegacyMarkerLine(line, source, state) {
|
|
22581
|
-
let match = LEGACY_WORK_ITEM_PATTERN.exec(line);
|
|
22582
|
-
if (match) {
|
|
22583
|
-
const marker = {
|
|
22584
|
-
...source,
|
|
22585
|
-
kind: "work-item",
|
|
22586
|
-
id: match[1],
|
|
22587
|
-
name: match[2],
|
|
22588
|
-
...optional(match[3]) ? { workflowId: optional(match[3]) } : {},
|
|
22589
|
-
...optional(match[4]) ? { stageId: optional(match[4]) } : {},
|
|
22590
|
-
status: match[5]
|
|
22591
|
-
};
|
|
22592
|
-
rememberWorkItem(marker, state);
|
|
22593
|
-
return marker;
|
|
22594
|
-
}
|
|
22595
|
-
match = LEGACY_ARTIFACT_PATTERN.exec(line);
|
|
22596
|
-
if (match) return {
|
|
22597
|
-
...source,
|
|
22598
|
-
kind: "artifact",
|
|
22599
|
-
itemId: match[1],
|
|
22600
|
-
path: match[2],
|
|
22601
|
-
categoryId: match[3]
|
|
22602
|
-
};
|
|
22603
|
-
match = LEGACY_SCHEDULE_PATTERN.exec(line);
|
|
22604
|
-
if (match) return {
|
|
22605
|
-
...source,
|
|
22606
|
-
kind: "schedule",
|
|
22607
|
-
itemId: match[1],
|
|
22608
|
-
...optional(match[2]) ? { start: optional(match[2]) } : {},
|
|
22609
|
-
...optional(match[3]) ? { end: optional(match[3]) } : {},
|
|
22610
|
-
milestone: match[4] === "true",
|
|
22611
|
-
dependsOn: match[5] === "none" ? [] : match[5].split(",")
|
|
22612
|
-
};
|
|
22613
|
-
match = LEGACY_SIGNAL_PATTERN.exec(line);
|
|
22614
|
-
if (match) return {
|
|
22615
|
-
...source,
|
|
22616
|
-
kind: "signal",
|
|
22617
|
-
id: match[1],
|
|
22618
|
-
...optional(match[2]) ? { itemId: optional(match[2]) } : {},
|
|
22619
|
-
status: match[3],
|
|
22620
|
-
level: match[4],
|
|
22621
|
-
message: match[5]
|
|
22622
|
-
};
|
|
22623
|
-
match = LEGACY_REQUEST_PATTERN.exec(line);
|
|
22624
|
-
if (match) {
|
|
22625
|
-
const marker = {
|
|
22626
|
-
...source,
|
|
22627
|
-
kind: "request",
|
|
22628
|
-
id: match[1],
|
|
22629
|
-
...optional(match[2]) ? { itemId: optional(match[2]) } : {},
|
|
22630
|
-
status: match[3],
|
|
22631
|
-
response: match[4],
|
|
22632
|
-
prompt: match[5]
|
|
22633
|
-
};
|
|
22634
|
-
rememberRequest(marker, state);
|
|
22635
|
-
return marker;
|
|
22636
|
-
}
|
|
22637
|
-
return null;
|
|
22638
|
-
}
|
|
22639
|
-
function parseCompactWorkItem(body, source, state) {
|
|
22640
|
-
const fields = parseFields(body);
|
|
22641
|
-
if (!fields || fields.size === 0 || !hasOnlyFields(fields, [
|
|
22642
|
-
"id",
|
|
22643
|
-
"name",
|
|
22644
|
-
"workflow",
|
|
22645
|
-
"stage",
|
|
22646
|
-
"status"
|
|
22647
|
-
])) return null;
|
|
22648
|
-
const explicitId = fields.get("id");
|
|
22649
|
-
if (explicitId && !ID_PATTERN.test(explicitId)) return null;
|
|
22650
|
-
const id = explicitId ?? state.currentWorkItemIdBySession.get(source.sessionId);
|
|
22651
|
-
if (!id) return null;
|
|
22652
|
-
const previous = state.workItemsById.get(id);
|
|
22653
|
-
const explicitName = fields.get("name");
|
|
22654
|
-
if (!previous && (!explicitName || !fields.has("stage"))) return null;
|
|
22655
|
-
if (previous && explicitName && explicitName !== previous.name) return null;
|
|
22656
|
-
const statusValue = fields.get("status");
|
|
22657
|
-
if (statusValue && !WORK_ITEM_STATUSES.has(statusValue)) return null;
|
|
22658
|
-
const workflowValue = fields.get("workflow");
|
|
22659
|
-
const stageValue = fields.get("stage");
|
|
22660
|
-
if (workflowValue && workflowValue !== "none" && !ID_PATTERN.test(workflowValue) || stageValue && stageValue !== "none" && !ID_PATTERN.test(stageValue)) return null;
|
|
22661
|
-
const workflowId = workflowValue === void 0 ? previous?.workflowId : optional(workflowValue);
|
|
22662
|
-
const stageId = stageValue === void 0 ? previous?.stageId : optional(stageValue);
|
|
22663
|
-
const marker = {
|
|
22664
|
-
...source,
|
|
22665
|
-
kind: "work-item",
|
|
22666
|
-
id,
|
|
22667
|
-
name: explicitName ?? previous.name,
|
|
22668
|
-
...workflowId ? { workflowId } : {},
|
|
22669
|
-
...stageId ? { stageId } : {},
|
|
22670
|
-
status: statusValue ?? (fields.has("stage") ? "active" : previous?.status ?? "active")
|
|
22671
|
-
};
|
|
22672
|
-
rememberWorkItem(marker, state);
|
|
22673
|
-
return marker;
|
|
22674
|
-
}
|
|
22675
|
-
function parseCompactArtifact(body, source, state) {
|
|
22676
|
-
const fields = parseFields(body);
|
|
22677
|
-
if (!fields || !hasOnlyFields(fields, [
|
|
22678
|
-
"path",
|
|
22679
|
-
"category",
|
|
22680
|
-
"work-id"
|
|
22681
|
-
])) return null;
|
|
22682
|
-
const path = fields.get("path");
|
|
22683
|
-
const categoryId = fields.get("category");
|
|
22684
|
-
const itemId = fields.get("work-id") ?? state.currentWorkItemIdBySession.get(source.sessionId);
|
|
22685
|
-
if (!path || !categoryId || !itemId || !ID_PATTERN.test(categoryId) || !ID_PATTERN.test(itemId)) return null;
|
|
22686
|
-
return {
|
|
22687
|
-
...source,
|
|
22688
|
-
kind: "artifact",
|
|
22689
|
-
itemId,
|
|
22690
|
-
path,
|
|
22691
|
-
categoryId
|
|
22692
|
-
};
|
|
22693
|
-
}
|
|
22694
|
-
function parseCompactRequest(body, source, state) {
|
|
22695
|
-
const fields = parseFields(body);
|
|
22696
|
-
if (!fields || !hasOnlyFields(fields, [
|
|
22697
|
-
"request",
|
|
22698
|
-
"work-id",
|
|
22699
|
-
"status",
|
|
22700
|
-
"response",
|
|
22701
|
-
"prompt"
|
|
22702
|
-
])) return null;
|
|
22703
|
-
const id = fields.get("request");
|
|
22704
|
-
if (!id || !ID_PATTERN.test(id)) return null;
|
|
22705
|
-
const previous = state.requestsById.get(id);
|
|
22706
|
-
const itemId = fields.get("work-id") ?? previous?.itemId ?? state.currentWorkItemIdBySession.get(source.sessionId);
|
|
22707
|
-
const statusValue = fields.get("status") ?? previous?.status ?? "open";
|
|
22708
|
-
const responseValue = fields.get("response") ?? previous?.response;
|
|
22709
|
-
const prompt = fields.get("prompt") ?? previous?.prompt;
|
|
22710
|
-
if (!responseValue || !prompt || !REQUEST_STATUSES.has(statusValue) || !REQUEST_RESPONSES.has(responseValue) || itemId && !ID_PATTERN.test(itemId)) return null;
|
|
22711
|
-
const marker = {
|
|
22712
|
-
...source,
|
|
22713
|
-
kind: "request",
|
|
22714
|
-
id,
|
|
22715
|
-
...itemId ? { itemId } : {},
|
|
22716
|
-
status: statusValue,
|
|
22717
|
-
response: responseValue,
|
|
22718
|
-
prompt
|
|
22719
|
-
};
|
|
22720
|
-
rememberRequest(marker, state);
|
|
22721
|
-
return marker;
|
|
22722
|
-
}
|
|
22723
|
-
function parseCompactMarkerLine(line, source, state) {
|
|
22724
|
-
const prefix = `[${PROJECT_OBSERVATION_PROTOCOL} `;
|
|
22725
|
-
if (!line.startsWith(prefix) || !line.endsWith("]")) return null;
|
|
22726
|
-
const body = line.slice(prefix.length, -1);
|
|
22727
|
-
if (body.startsWith("artifact ")) return parseCompactArtifact(body.slice(9), source, state);
|
|
22728
|
-
if (body.startsWith("request=")) return parseCompactRequest(body, source, state);
|
|
22729
|
-
return parseCompactWorkItem(body, source, state);
|
|
22730
|
-
}
|
|
22731
|
-
function parseProjectObservationMarkers(params) {
|
|
22732
|
-
const markers = [];
|
|
22733
|
-
const issues = [];
|
|
22734
|
-
const state = params.state ?? createProjectObservationMarkerParseState();
|
|
22735
|
-
let insideFencedCodeBlock = false;
|
|
22736
|
-
params.text.split(/\r?\n/).forEach((rawLine, index) => {
|
|
22737
|
-
const line = rawLine.trim();
|
|
22738
|
-
if (line.startsWith("```")) {
|
|
22739
|
-
insideFencedCodeBlock = !insideFencedCodeBlock;
|
|
22740
|
-
return;
|
|
22741
|
-
}
|
|
22742
|
-
if (insideFencedCodeBlock) return;
|
|
22743
|
-
if (!line.startsWith(`[nextclaw.project/v1`)) return;
|
|
22744
|
-
const source = {
|
|
22745
|
-
sessionId: params.sessionId,
|
|
22746
|
-
messageId: params.messageId,
|
|
22747
|
-
timestamp: params.timestamp,
|
|
22748
|
-
line: index + 1
|
|
21769
|
+
const normalizedInput = {
|
|
21770
|
+
...input,
|
|
21771
|
+
...input.name !== void 0 ? { name: this.requireName(input.name, "state name") } : {}
|
|
22749
21772
|
};
|
|
22750
|
-
|
|
22751
|
-
|
|
22752
|
-
|
|
22753
|
-
|
|
21773
|
+
if (normalizedInput.category !== void 0) this.assertCategory(normalizedInput.category);
|
|
21774
|
+
const current = await this.store.getState(projectId, stateId);
|
|
21775
|
+
if (!current) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "work item state was not found");
|
|
21776
|
+
if (current.isDefault && normalizedInput.isDefault === false) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "choose another default state before clearing this one");
|
|
21777
|
+
if (normalizedInput.name && (await this.store.listStates(projectId)).some((state) => state.id !== stateId && state.name.toLocaleLowerCase() === normalizedInput.name.toLocaleLowerCase())) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "state name is already in use");
|
|
21778
|
+
const state = await this.store.updateState(projectId, stateId, normalizedInput);
|
|
21779
|
+
if (!state) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "work item state was not found");
|
|
21780
|
+
await this.emit(projectId, "state-config");
|
|
21781
|
+
return state;
|
|
21782
|
+
};
|
|
21783
|
+
deleteState = async (projectId, stateId, migrateToStateId, actor) => {
|
|
21784
|
+
await this.ensureProject(projectId);
|
|
21785
|
+
const states = await this.store.listStates(projectId);
|
|
21786
|
+
if (states.length <= 1) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "a project must keep at least one state");
|
|
21787
|
+
if (migrateToStateId === stateId) throw new ProjectWorkError("PROJECT_WORK_STATE_INVALID", "migration target must be a different state");
|
|
21788
|
+
if (migrateToStateId && !states.some((state) => state.id === migrateToStateId)) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "migration target state was not found");
|
|
21789
|
+
try {
|
|
21790
|
+
if (!await this.store.deleteState(projectId, stateId, migrateToStateId, this.normalizeActor(actor))) throw new ProjectWorkError("PROJECT_WORK_STATE_NOT_FOUND", "work item state was not found");
|
|
21791
|
+
} catch (error) {
|
|
21792
|
+
if (error instanceof Error && error.message === "PROJECT_WORK_STATE_IN_USE") throw new ProjectWorkError("PROJECT_WORK_STATE_IN_USE", "state is used by work items; choose a migration target");
|
|
21793
|
+
throw error;
|
|
22754
21794
|
}
|
|
22755
|
-
|
|
22756
|
-
|
|
22757
|
-
|
|
22758
|
-
|
|
21795
|
+
await this.emit(projectId, "state-config");
|
|
21796
|
+
};
|
|
21797
|
+
linkArtifact = async (params) => {
|
|
21798
|
+
const { actor, label, path, projectId, workItemId } = params;
|
|
21799
|
+
const project = await this.requireProject(projectId);
|
|
21800
|
+
await this.get(projectId, workItemId);
|
|
21801
|
+
const artifactPath = await this.normalizeArtifactPath(project.rootPath, path);
|
|
21802
|
+
const existing = (await this.store.listArtifacts(projectId, workItemId)).find((link) => link.path === artifactPath);
|
|
21803
|
+
if (existing) return existing;
|
|
21804
|
+
const link = await this.store.linkArtifact({
|
|
21805
|
+
projectId,
|
|
21806
|
+
workItemId,
|
|
21807
|
+
path: artifactPath,
|
|
21808
|
+
label: label?.trim() || void 0,
|
|
21809
|
+
actor: this.normalizeActor(actor)
|
|
22759
21810
|
});
|
|
22760
|
-
|
|
22761
|
-
|
|
22762
|
-
markers,
|
|
22763
|
-
issues
|
|
21811
|
+
await this.emit(projectId, "artifact", workItemId);
|
|
21812
|
+
return link;
|
|
22764
21813
|
};
|
|
22765
|
-
|
|
22766
|
-
const
|
|
22767
|
-
|
|
22768
|
-
|
|
22769
|
-
|
|
22770
|
-
|
|
22771
|
-
|
|
22772
|
-
|
|
22773
|
-
|
|
21814
|
+
unlinkArtifact = async (params) => {
|
|
21815
|
+
const { actor, artifactLinkId, projectId, workItemId } = params;
|
|
21816
|
+
await this.get(projectId, workItemId);
|
|
21817
|
+
if (!await this.store.unlinkArtifact({
|
|
21818
|
+
projectId,
|
|
21819
|
+
workItemId,
|
|
21820
|
+
artifactLinkId,
|
|
21821
|
+
actor: this.normalizeActor(actor)
|
|
21822
|
+
})) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_NOT_FOUND", "artifact link was not found");
|
|
21823
|
+
await this.emit(projectId, "artifact", workItemId);
|
|
22774
21824
|
};
|
|
22775
|
-
|
|
22776
|
-
|
|
22777
|
-
|
|
22778
|
-
|
|
22779
|
-
|
|
22780
|
-
|
|
22781
|
-
|
|
22782
|
-
|
|
22783
|
-
|
|
22784
|
-
|
|
22785
|
-
|
|
22786
|
-
|
|
22787
|
-
};
|
|
22788
|
-
const readSessionProjectRoot$1 = (session) => readOptionalString$8(session.metadata?.project_root) ?? readOptionalString$8(session.metadata?.projectRoot);
|
|
22789
|
-
const readMessageText = (message) => message.parts.flatMap((part) => part.type === "text" || part.type === "rich-text" ? [part.text] : []).join("\n");
|
|
22790
|
-
const compareMarkerSource = (left, right) => left.timestamp.localeCompare(right.timestamp) || left.sessionId.localeCompare(right.sessionId) || left.messageId.localeCompare(right.messageId) || left.line - right.line;
|
|
22791
|
-
const markerConflictKey = (marker) => {
|
|
22792
|
-
switch (marker.kind) {
|
|
22793
|
-
case "work-item":
|
|
22794
|
-
case "signal":
|
|
22795
|
-
case "request": return `${marker.kind}:${marker.id}`;
|
|
22796
|
-
case "schedule": return `${marker.kind}:${marker.itemId}`;
|
|
22797
|
-
case "artifact": return null;
|
|
22798
|
-
}
|
|
22799
|
-
};
|
|
22800
|
-
const markerSemanticValue = (marker) => {
|
|
22801
|
-
const { line: _line, messageId: _messageId, sessionId: _sessionId, timestamp: _timestamp, ...semantic } = marker;
|
|
22802
|
-
return JSON.stringify(semantic);
|
|
22803
|
-
};
|
|
22804
|
-
const parseProjectSessionMessage = (sessionId, message, state) => {
|
|
22805
|
-
if (message.role === "assistant") {
|
|
22806
|
-
const parsed = parseProjectObservationMarkers({
|
|
22807
|
-
text: readMessageText(message),
|
|
22808
|
-
sessionId,
|
|
22809
|
-
messageId: message.id,
|
|
22810
|
-
timestamp: message.timestamp,
|
|
22811
|
-
reportInvalid: message.status === "final" || message.status === "error",
|
|
22812
|
-
state
|
|
22813
|
-
});
|
|
22814
|
-
return {
|
|
22815
|
-
markers: parsed.markers,
|
|
22816
|
-
markerIssues: parsed.issues
|
|
22817
|
-
};
|
|
22818
|
-
}
|
|
22819
|
-
if (message.role !== "user") return {
|
|
22820
|
-
markers: [],
|
|
22821
|
-
markerIssues: []
|
|
21825
|
+
setDeleted = async (projectId, workItemId, deleted, actor) => {
|
|
21826
|
+
await this.ensureProject(projectId);
|
|
21827
|
+
const current = await this.get(projectId, workItemId);
|
|
21828
|
+
if (current.deletedAt !== null === deleted) return current;
|
|
21829
|
+
if (!await this.store.setDeleted({
|
|
21830
|
+
projectId,
|
|
21831
|
+
workItemId,
|
|
21832
|
+
deleted,
|
|
21833
|
+
actor: this.normalizeActor(actor)
|
|
21834
|
+
})) throw new ProjectWorkError("PROJECT_WORK_ITEM_NOT_FOUND", "work item was not found");
|
|
21835
|
+
await this.emit(projectId, deleted ? "deleted" : "restored", workItemId);
|
|
21836
|
+
return await this.get(projectId, workItemId);
|
|
22822
21837
|
};
|
|
22823
|
-
|
|
22824
|
-
|
|
22825
|
-
|
|
22826
|
-
|
|
22827
|
-
|
|
22828
|
-
|
|
22829
|
-
|
|
22830
|
-
|
|
22831
|
-
|
|
22832
|
-
|
|
21838
|
+
requireProject = async (projectId) => {
|
|
21839
|
+
const normalized = projectId.trim();
|
|
21840
|
+
const project = normalized ? await this.options.projectManager.getProjectById(normalized) : null;
|
|
21841
|
+
if (!project) throw new ProjectWorkError("PROJECT_NOT_FOUND", "project was not found");
|
|
21842
|
+
return project;
|
|
21843
|
+
};
|
|
21844
|
+
requireName = (value, label) => {
|
|
21845
|
+
const normalized = typeof value === "string" ? value.trim() : "";
|
|
21846
|
+
if (!normalized) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", `${label} is required`);
|
|
21847
|
+
if (normalized.length > 200) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", `${label} is too long`);
|
|
21848
|
+
return normalized;
|
|
21849
|
+
};
|
|
21850
|
+
assertAttention = (value) => {
|
|
21851
|
+
if (!PROJECT_WORK_ATTENTION_VALUES.some((entry) => entry === value)) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", "work item attention is invalid");
|
|
21852
|
+
};
|
|
21853
|
+
assertCategory = (value) => {
|
|
21854
|
+
if (!PROJECT_WORK_STATE_CATEGORIES.some((entry) => entry === value)) throw new ProjectWorkError("PROJECT_WORK_VALIDATION_FAILED", "work item state category is invalid");
|
|
21855
|
+
};
|
|
21856
|
+
normalizeActor = (actor) => ({
|
|
21857
|
+
kind: actor.kind,
|
|
21858
|
+
...actor.id?.trim() ? { id: actor.id.trim() } : {},
|
|
21859
|
+
...actor.sessionId?.trim() ? { sessionId: actor.sessionId.trim() } : {}
|
|
21860
|
+
});
|
|
21861
|
+
normalizeArtifactPath = async (rootPath, inputPath) => {
|
|
21862
|
+
const requested = inputPath.trim();
|
|
21863
|
+
if (!requested) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_INVALID", "artifact path is required");
|
|
21864
|
+
const canonicalRoot = await realpath(rootPath);
|
|
21865
|
+
const candidate = await realpath(isAbsolute(requested) ? requested : resolve(canonicalRoot, requested)).catch(() => null);
|
|
21866
|
+
if (!candidate) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_NOT_FOUND", "artifact file does not exist");
|
|
21867
|
+
const relativePath = relative(canonicalRoot, candidate);
|
|
21868
|
+
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_INVALID", "artifact must be a file inside the project root");
|
|
21869
|
+
if (!(await stat(candidate)).isFile()) throw new ProjectWorkError("PROJECT_WORK_ARTIFACT_INVALID", "artifact must be a file");
|
|
21870
|
+
return relativePath.split(sep).join("/");
|
|
21871
|
+
};
|
|
21872
|
+
emit = async (projectId, change, workItemId) => {
|
|
21873
|
+
await this.options.eventBus.emit(eventKeys$1.projectWorkChanged, {
|
|
21874
|
+
projectId,
|
|
21875
|
+
change,
|
|
21876
|
+
...workItemId ? { workItemId } : {}
|
|
21877
|
+
});
|
|
22833
21878
|
};
|
|
22834
21879
|
};
|
|
22835
|
-
|
|
22836
|
-
|
|
22837
|
-
|
|
22838
|
-
|
|
22839
|
-
const { requestId, ...value } = response;
|
|
22840
|
-
next.set(requestId, value);
|
|
22841
|
-
}
|
|
22842
|
-
return next;
|
|
22843
|
-
};
|
|
22844
|
-
var ProjectObservationService = class {
|
|
22845
|
-
now;
|
|
21880
|
+
//#endregion
|
|
21881
|
+
//#region src/features/projects/services/project-material.service.ts
|
|
21882
|
+
const PROJECT_AGREEMENT_PATH = "AGENTS.md";
|
|
21883
|
+
var ProjectMaterialService = class {
|
|
22846
21884
|
constructor(options) {
|
|
22847
21885
|
this.options = options;
|
|
22848
|
-
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
22849
21886
|
}
|
|
22850
|
-
|
|
22851
|
-
|
|
22852
|
-
try {
|
|
22853
|
-
project = await this.options.projectManager.getRegisteredProject(rootPath);
|
|
22854
|
-
} catch (error) {
|
|
22855
|
-
throw new ProjectObservationError("PROJECT_OBSERVATION_INVALID_ROOT", error instanceof Error ? error.message : "Project root is invalid.");
|
|
22856
|
-
}
|
|
22857
|
-
if (!project) throw new ProjectObservationError("PROJECT_NOT_REGISTERED", "Project is not registered.");
|
|
22858
|
-
const asOf = this.now().toISOString();
|
|
22859
|
-
const diagnostics = [];
|
|
22860
|
-
const sourceCounts = /* @__PURE__ */ new Map();
|
|
22861
|
-
const sourceErrors = /* @__PURE__ */ new Set();
|
|
22862
|
-
const addDiagnostic = (source, level, code, message, details = {}) => {
|
|
22863
|
-
if (level === "error") sourceErrors.add(source);
|
|
22864
|
-
diagnostics.push({
|
|
22865
|
-
id: `${source}:${code}:${diagnostics.filter((entry) => entry.source === source && entry.code === code).length + 1}`,
|
|
22866
|
-
source,
|
|
22867
|
-
level,
|
|
22868
|
-
code,
|
|
22869
|
-
message,
|
|
22870
|
-
...details
|
|
22871
|
-
});
|
|
22872
|
-
};
|
|
22873
|
-
const addSourceCount = (source, count) => {
|
|
22874
|
-
sourceCounts.set(source, (sourceCounts.get(source) ?? 0) + count);
|
|
22875
|
-
};
|
|
22876
|
-
const config = await this.readConfig(project.rootPath, addDiagnostic);
|
|
22877
|
-
const context = await this.observeContext(project.rootPath, config, asOf, addDiagnostic);
|
|
22878
|
-
addSourceCount("config", (config ? 1 : 0) + context.length + (config?.workflows.length ?? 0));
|
|
22879
|
-
const artifacts = await this.observeArtifacts(project.rootPath, config, asOf, addDiagnostic);
|
|
22880
|
-
addSourceCount("files", artifacts.length);
|
|
22881
|
-
const sessionObservation = await this.observeSessions(project.rootPath, addDiagnostic);
|
|
22882
|
-
addSourceCount("sessions", sessionObservation.sessions.length);
|
|
22883
|
-
const skills = this.observeSkills(project.rootPath, config, asOf, addDiagnostic);
|
|
22884
|
-
addSourceCount("skills", skills.length);
|
|
22885
|
-
const workflows = (config?.workflows ?? []).map((workflow) => ({
|
|
22886
|
-
...workflow,
|
|
22887
|
-
reference: projectObservationConfigReference(asOf)
|
|
22888
|
-
}));
|
|
22889
|
-
const workItems = projectObservedWorkItems(sessionObservation.markers, workflows, addDiagnostic);
|
|
22890
|
-
const runs = projectObservedRuns(sessionObservation.sessions, sessionObservation.markers);
|
|
22891
|
-
const mergedArtifacts = await mergeProjectObservedArtifacts(project.rootPath, artifacts, config, sessionObservation.markers, addDiagnostic);
|
|
22892
|
-
const signals = projectObservedSignals(sessionObservation.markers);
|
|
22893
|
-
const requests = projectObservedRequests(sessionObservation.markers, sessionObservation.responses);
|
|
22894
|
-
const activity = projectObservedActivity(sessionObservation.markers);
|
|
22895
|
-
const sources = Object.keys(SOURCE_LABELS).map((source) => this.createSourceStatus(source, asOf, sourceCounts.get(source) ?? 0, sourceErrors.has(source), diagnostics));
|
|
22896
|
-
const errorSourceCount = sources.filter((source) => source.status === "error").length;
|
|
21887
|
+
getAgreement = async (projectId) => {
|
|
21888
|
+
const project = await this.requireProject(projectId);
|
|
22897
21889
|
return {
|
|
22898
|
-
|
|
22899
|
-
|
|
22900
|
-
name: project.name,
|
|
22901
|
-
rootPath: project.rootPath,
|
|
22902
|
-
...config?.summary ? { summary: config.summary } : {},
|
|
22903
|
-
context
|
|
22904
|
-
},
|
|
22905
|
-
sources,
|
|
22906
|
-
workflows,
|
|
22907
|
-
runs,
|
|
22908
|
-
workItems,
|
|
22909
|
-
artifactCategories: (config?.artifactCategories ?? []).map(({ id, label }) => ({
|
|
22910
|
-
id,
|
|
22911
|
-
label
|
|
22912
|
-
})),
|
|
22913
|
-
artifacts: mergedArtifacts,
|
|
22914
|
-
signals,
|
|
22915
|
-
requests,
|
|
22916
|
-
activity,
|
|
22917
|
-
skills,
|
|
22918
|
-
diagnostics,
|
|
22919
|
-
dataQuality: errorSourceCount === sources.length ? "unavailable" : diagnostics.some((entry) => entry.level === "error" || entry.level === "warning") ? "partial" : "complete"
|
|
21890
|
+
path: PROJECT_AGREEMENT_PATH,
|
|
21891
|
+
available: await this.isFile(join(project.rootPath, PROJECT_AGREEMENT_PATH))
|
|
22920
21892
|
};
|
|
22921
21893
|
};
|
|
22922
|
-
|
|
22923
|
-
const
|
|
22924
|
-
|
|
22925
|
-
|
|
22926
|
-
|
|
22927
|
-
|
|
22928
|
-
|
|
22929
|
-
|
|
22930
|
-
|
|
22931
|
-
|
|
22932
|
-
|
|
22933
|
-
|
|
22934
|
-
return
|
|
22935
|
-
|
|
21894
|
+
listSkills = async (projectId) => {
|
|
21895
|
+
const project = await this.requireProject(projectId);
|
|
21896
|
+
const loader = new SkillsLoader({
|
|
21897
|
+
workspace: project.rootPath,
|
|
21898
|
+
projectRoot: project.rootPath,
|
|
21899
|
+
projectSkillsDirName: DEFAULT_PROJECT_SKILLS_DIR_NAME,
|
|
21900
|
+
includeBuiltin: false,
|
|
21901
|
+
includeWorkspace: false,
|
|
21902
|
+
includeGlobal: false
|
|
21903
|
+
});
|
|
21904
|
+
return loader.listSkills(false).filter((skill) => skill.scope === "project").map((skill) => {
|
|
21905
|
+
const metadata = loader.getSkillMetadata(skill) ?? {};
|
|
21906
|
+
return {
|
|
21907
|
+
ref: skill.ref,
|
|
21908
|
+
name: skill.name,
|
|
21909
|
+
...metadata.description ? { description: metadata.description } : {},
|
|
21910
|
+
path: relative(project.rootPath, skill.path).split(sep).join("/")
|
|
21911
|
+
};
|
|
21912
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
22936
21913
|
};
|
|
22937
|
-
|
|
22938
|
-
const
|
|
22939
|
-
const
|
|
22940
|
-
if (!
|
|
22941
|
-
return
|
|
22942
|
-
...entry,
|
|
22943
|
-
accessible: observed !== null,
|
|
22944
|
-
reference: observed ? projectObservationFileReference(observed.relativePath, asOf) : projectObservationConfigReference(asOf)
|
|
22945
|
-
};
|
|
22946
|
-
}));
|
|
22947
|
-
observeArtifacts = async (rootPath, config, asOf, addDiagnostic) => {
|
|
22948
|
-
const result = await scanProjectArtifactFiles(rootPath, config?.artifactCategories ?? []);
|
|
22949
|
-
for (const issue of result.issues) addDiagnostic("files", "warning", issue.code, issue.message, { ...issue.projectRelativePath ? { projectRelativePath: issue.projectRelativePath } : {} });
|
|
22950
|
-
return result.matches.map((match) => ({
|
|
22951
|
-
id: `${match.categoryId}:${match.relativePath}`,
|
|
22952
|
-
path: match.relativePath,
|
|
22953
|
-
categoryId: match.categoryId,
|
|
22954
|
-
categoryLabel: match.categoryLabel,
|
|
22955
|
-
exists: true,
|
|
22956
|
-
size: match.size,
|
|
22957
|
-
fileCreatedAt: match.createdAt,
|
|
22958
|
-
fileUpdatedAt: match.updatedAt,
|
|
22959
|
-
references: [projectObservationFileReference(match.relativePath, asOf)]
|
|
22960
|
-
}));
|
|
21914
|
+
requireProject = async (projectId) => {
|
|
21915
|
+
const normalized = projectId.trim();
|
|
21916
|
+
const project = normalized ? await this.options.projectManager.getProjectById(normalized) : null;
|
|
21917
|
+
if (!project) throw new ProjectError("PROJECT_NOT_FOUND", "project was not found");
|
|
21918
|
+
return project;
|
|
22961
21919
|
};
|
|
22962
|
-
|
|
22963
|
-
const markers = [];
|
|
22964
|
-
let responses = /* @__PURE__ */ new Map();
|
|
22965
|
-
let sessions;
|
|
21920
|
+
isFile = async (path) => {
|
|
22966
21921
|
try {
|
|
22967
|
-
|
|
22968
|
-
} catch (error) {
|
|
22969
|
-
addDiagnostic("sessions", "error", "PROJECT_SESSIONS_READ_FAILED", error instanceof Error ? error.message : "Project sessions could not be listed.");
|
|
22970
|
-
return {
|
|
22971
|
-
markers,
|
|
22972
|
-
responses,
|
|
22973
|
-
sessions: []
|
|
22974
|
-
};
|
|
22975
|
-
}
|
|
22976
|
-
const messages = [];
|
|
22977
|
-
for (const session of sessions) try {
|
|
22978
|
-
messages.push(...(await this.options.sessionManager.listSessionMessages(session.sessionId)).map((message) => ({
|
|
22979
|
-
message,
|
|
22980
|
-
sessionId: session.sessionId
|
|
22981
|
-
})));
|
|
21922
|
+
return (await stat(path)).isFile();
|
|
22982
21923
|
} catch (error) {
|
|
22983
|
-
|
|
22984
|
-
|
|
22985
|
-
messages.sort((left, right) => left.message.timestamp.localeCompare(right.message.timestamp) || left.sessionId.localeCompare(right.sessionId) || left.message.id.localeCompare(right.message.id));
|
|
22986
|
-
const parseState = createProjectObservationMarkerParseState();
|
|
22987
|
-
for (const { message, sessionId } of messages) {
|
|
22988
|
-
const parsed = parseProjectSessionMessage(sessionId, message, parseState);
|
|
22989
|
-
markers.push(...parsed.markers);
|
|
22990
|
-
for (const issue of parsed.markerIssues) addDiagnostic("sessions", "warning", issue.code, issue.message, {
|
|
22991
|
-
sessionId,
|
|
22992
|
-
messageId: message.id
|
|
22993
|
-
});
|
|
22994
|
-
if (parsed.response) responses = mergeLatestResponse(responses, parsed.response);
|
|
22995
|
-
}
|
|
22996
|
-
markers.sort(compareMarkerSource);
|
|
22997
|
-
this.addMarkerConflictDiagnostics(markers, addDiagnostic);
|
|
22998
|
-
return {
|
|
22999
|
-
markers,
|
|
23000
|
-
responses,
|
|
23001
|
-
sessions
|
|
23002
|
-
};
|
|
23003
|
-
};
|
|
23004
|
-
addMarkerConflictDiagnostics = (markers, addDiagnostic) => {
|
|
23005
|
-
const latestAtByKey = /* @__PURE__ */ new Map();
|
|
23006
|
-
for (const marker of markers) {
|
|
23007
|
-
const key = markerConflictKey(marker);
|
|
23008
|
-
if (!key) continue;
|
|
23009
|
-
const current = latestAtByKey.get(key);
|
|
23010
|
-
const value = markerSemanticValue(marker);
|
|
23011
|
-
if (current?.timestamp === marker.timestamp && (current.sessionId !== marker.sessionId || current.messageId !== marker.messageId) && current.value !== value) addDiagnostic("sessions", "warning", "PROJECT_MARKER_CONFLICT", `Conflicting '${key}' markers share the same observation time; a deterministic source order was used.`, {
|
|
23012
|
-
sessionId: marker.sessionId,
|
|
23013
|
-
messageId: marker.messageId
|
|
23014
|
-
});
|
|
23015
|
-
latestAtByKey.set(key, {
|
|
23016
|
-
messageId: marker.messageId,
|
|
23017
|
-
sessionId: marker.sessionId,
|
|
23018
|
-
timestamp: marker.timestamp,
|
|
23019
|
-
value
|
|
23020
|
-
});
|
|
23021
|
-
}
|
|
23022
|
-
};
|
|
23023
|
-
observeSkills = (rootPath, config, asOf, addDiagnostic) => {
|
|
23024
|
-
const output = /* @__PURE__ */ new Map();
|
|
23025
|
-
for (const skillRoot of config?.skillRoots ?? [".agents/skills"]) {
|
|
23026
|
-
const normalizedRoot = normalizeProjectRelativePath(skillRoot);
|
|
23027
|
-
if (!normalizedRoot) {
|
|
23028
|
-
addDiagnostic("skills", "warning", "PROJECT_SKILL_ROOT_INVALID", `Skill root '${skillRoot}' is outside the project.`, { projectRelativePath: skillRoot });
|
|
23029
|
-
continue;
|
|
23030
|
-
}
|
|
23031
|
-
try {
|
|
23032
|
-
const loader = new SkillsLoader({
|
|
23033
|
-
workspace: this.options.workspacePath,
|
|
23034
|
-
projectRoot: rootPath,
|
|
23035
|
-
projectSkillsDirName: normalizedRoot,
|
|
23036
|
-
includeBuiltin: false,
|
|
23037
|
-
includeGlobal: false
|
|
23038
|
-
});
|
|
23039
|
-
for (const skill of loader.listSkills(false).filter((entry) => entry.scope === "project")) {
|
|
23040
|
-
const metadata = loader.getSkillMetadata(skill) ?? {};
|
|
23041
|
-
const relativePath = normalizeProjectRelativePath(skill.path.slice(rootPath.length + 1)) ?? `${normalizedRoot}/${skill.name}/SKILL.md`;
|
|
23042
|
-
output.set(skill.ref, {
|
|
23043
|
-
ref: skill.ref,
|
|
23044
|
-
name: skill.name,
|
|
23045
|
-
...metadata.description ? { description: metadata.description } : {},
|
|
23046
|
-
source: "project",
|
|
23047
|
-
path: relativePath,
|
|
23048
|
-
readable: true,
|
|
23049
|
-
reference: projectObservationFileReference(relativePath, asOf)
|
|
23050
|
-
});
|
|
23051
|
-
}
|
|
23052
|
-
} catch (error) {
|
|
23053
|
-
addDiagnostic("skills", "error", "PROJECT_SKILLS_READ_FAILED", error instanceof Error ? error.message : "Project skills could not be read.", { projectRelativePath: normalizedRoot });
|
|
23054
|
-
}
|
|
21924
|
+
if (error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) return false;
|
|
21925
|
+
throw error;
|
|
23055
21926
|
}
|
|
23056
|
-
return [...output.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
23057
21927
|
};
|
|
23058
|
-
createSourceStatus = (source, asOf, itemCount, hasError, diagnostics) => ({
|
|
23059
|
-
id: source,
|
|
23060
|
-
label: SOURCE_LABELS[source],
|
|
23061
|
-
status: hasError ? "error" : itemCount > 0 ? "available" : "empty",
|
|
23062
|
-
itemCount,
|
|
23063
|
-
observedAt: asOf,
|
|
23064
|
-
diagnosticIds: diagnostics.filter((entry) => entry.source === source).map((entry) => entry.id)
|
|
23065
|
-
});
|
|
23066
21928
|
};
|
|
23067
21929
|
//#endregion
|
|
23068
21930
|
//#region src/stores/ncp-agent-session-journal-summary-recovery.store.ts
|
|
@@ -23145,18 +22007,18 @@ function applyJournalSummaryLine(state, line) {
|
|
|
23145
22007
|
if (parsed._type === "metadata") {
|
|
23146
22008
|
state.createdAt = toIsoString(parsed.created_at, state.createdAt);
|
|
23147
22009
|
state.agentId = typeof parsed.agent_id === "string" ? parsed.agent_id : state.agentId;
|
|
23148
|
-
if (isRecord$
|
|
22010
|
+
if (isRecord$9(parsed.metadata)) state.metadata = structuredClone(parsed.metadata);
|
|
23149
22011
|
return;
|
|
23150
22012
|
}
|
|
23151
|
-
if (parsed._type !== "event" || !isRecord$
|
|
22013
|
+
if (parsed._type !== "event" || !isRecord$9(parsed.event)) return;
|
|
23152
22014
|
const event = parsed.event;
|
|
23153
|
-
const payload = isRecord$
|
|
23154
|
-
const message = payload && isRecord$
|
|
22015
|
+
const payload = isRecord$9(event.payload) ? event.payload : null;
|
|
22016
|
+
const message = payload && isRecord$9(payload.message) ? payload.message : null;
|
|
23155
22017
|
const messageId = typeof message?.id === "string" ? message.id : typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
23156
22018
|
if (!isMessageStartEvent(event.type) || !messageId || state.messageIds.has(messageId)) return;
|
|
23157
22019
|
state.messageIds.add(messageId);
|
|
23158
22020
|
state.messageCount += 1;
|
|
23159
|
-
if (isRecord$
|
|
22021
|
+
if (isRecord$9(message?.metadata) && message.metadata.nextclaw_timeline_kind === "context_compaction") state.requiresReplay = true;
|
|
23160
22022
|
if (!isFinalMessageEvent(event.type)) return;
|
|
23161
22023
|
const timestamp = toIsoString(message?.timestamp, "");
|
|
23162
22024
|
if (timestamp && (!state.lastMessageAt || timestamp > state.lastMessageAt)) state.lastMessageAt = timestamp;
|
|
@@ -23165,7 +22027,7 @@ function parseJournalLine(line) {
|
|
|
23165
22027
|
if (!line.trim()) return null;
|
|
23166
22028
|
try {
|
|
23167
22029
|
const parsed = JSON.parse(line);
|
|
23168
|
-
return isRecord$
|
|
22030
|
+
return isRecord$9(parsed) ? parsed : null;
|
|
23169
22031
|
} catch {
|
|
23170
22032
|
return null;
|
|
23171
22033
|
}
|
|
@@ -23178,6 +22040,9 @@ function isFinalMessageEvent(type) {
|
|
|
23178
22040
|
}
|
|
23179
22041
|
//#endregion
|
|
23180
22042
|
//#region src/utils/ncp-agent-unfinished-run.utils.ts
|
|
22043
|
+
function isNcpAgentRunLifecycleEvent(event) {
|
|
22044
|
+
return event.type === NcpEventType.RunStarted || event.type === NcpEventType.RunFinished || event.type === NcpEventType.RunError || event.type === NcpEventType.MessageAbort;
|
|
22045
|
+
}
|
|
23181
22046
|
function applyNcpAgentRunLifecycleEvent(sessionId, activeRun, event) {
|
|
23182
22047
|
if (event.type === NcpEventType.RunStarted) return {
|
|
23183
22048
|
sessionId,
|
|
@@ -23190,48 +22055,108 @@ function applyNcpAgentRunLifecycleEvent(sessionId, activeRun, event) {
|
|
|
23190
22055
|
}
|
|
23191
22056
|
//#endregion
|
|
23192
22057
|
//#region src/stores/ncp-agent-unfinished-run.store.ts
|
|
22058
|
+
const REVERSE_READ_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
22059
|
+
const RUN_LIFECYCLE_EVENT_NEEDLES = [
|
|
22060
|
+
`"type":"${NcpEventType.RunStarted}"`,
|
|
22061
|
+
`"type":"${NcpEventType.RunFinished}"`,
|
|
22062
|
+
`"type":"${NcpEventType.RunError}"`,
|
|
22063
|
+
`"type":"${NcpEventType.MessageAbort}"`
|
|
22064
|
+
];
|
|
23193
22065
|
var NcpAgentUnfinishedRunStore = class {
|
|
23194
|
-
constructor(journalDir,
|
|
22066
|
+
constructor(journalDir, listCheckpoints, writeCheckpoint) {
|
|
23195
22067
|
this.journalDir = journalDir;
|
|
23196
|
-
this.
|
|
22068
|
+
this.listCheckpoints = listCheckpoints;
|
|
22069
|
+
this.writeCheckpoint = writeCheckpoint;
|
|
23197
22070
|
}
|
|
23198
22071
|
list = async () => {
|
|
23199
22072
|
const runs = [];
|
|
23200
|
-
for (const
|
|
23201
|
-
const run = await this.read(
|
|
22073
|
+
for (const checkpoint of await this.listCheckpoints()) {
|
|
22074
|
+
const run = await this.read(checkpoint);
|
|
23202
22075
|
if (run) runs.push(run);
|
|
23203
22076
|
}
|
|
23204
22077
|
return runs;
|
|
23205
22078
|
};
|
|
23206
|
-
read = async (
|
|
23207
|
-
const
|
|
22079
|
+
read = async (checkpoint) => {
|
|
22080
|
+
const { sessionId } = checkpoint;
|
|
22081
|
+
const file = await open(this.sessionPath(sessionId), "r").catch(() => null);
|
|
22082
|
+
if (!file) return null;
|
|
22083
|
+
try {
|
|
22084
|
+
const fileSize = (await file.stat()).size;
|
|
22085
|
+
const checkpointOffset = checkpoint.journalOffset !== null && checkpoint.journalOffset >= 0 && checkpoint.journalOffset <= fileSize ? checkpoint.journalOffset : null;
|
|
22086
|
+
if (checkpointOffset === fileSize) return checkpoint.activeRun;
|
|
22087
|
+
const activeRun = checkpointOffset === null ? await this.readLatestRunFromEnd(sessionId, file, fileSize) : await this.readRunTail(sessionId, checkpoint.activeRun, checkpointOffset);
|
|
22088
|
+
await this.writeCheckpoint({
|
|
22089
|
+
sessionId,
|
|
22090
|
+
journalOffset: fileSize,
|
|
22091
|
+
activeRun
|
|
22092
|
+
});
|
|
22093
|
+
return activeRun;
|
|
22094
|
+
} catch {
|
|
22095
|
+
return null;
|
|
22096
|
+
} finally {
|
|
22097
|
+
await file.close();
|
|
22098
|
+
}
|
|
22099
|
+
};
|
|
22100
|
+
readLatestRunFromEnd = async (sessionId, file, fileSize) => {
|
|
22101
|
+
const terminalEvents = [];
|
|
22102
|
+
let position = fileSize;
|
|
22103
|
+
let lineSuffix = "";
|
|
22104
|
+
while (position > 0) {
|
|
22105
|
+
const length = Math.min(REVERSE_READ_CHUNK_BYTES, position);
|
|
22106
|
+
position -= length;
|
|
22107
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
22108
|
+
const { bytesRead } = await file.read(buffer, 0, length, position);
|
|
22109
|
+
const lines = `${buffer.toString("utf8", 0, bytesRead)}${lineSuffix}`.split("\n");
|
|
22110
|
+
lineSuffix = position > 0 ? lines.shift() ?? "" : "";
|
|
22111
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
22112
|
+
const event = readRunLifecycleEvent(lines[index] ?? "");
|
|
22113
|
+
if (!event) continue;
|
|
22114
|
+
if (event.type === NcpEventType.RunStarted) return resolveUnfinishedRun(sessionId, event, terminalEvents);
|
|
22115
|
+
terminalEvents.push(event);
|
|
22116
|
+
}
|
|
22117
|
+
}
|
|
22118
|
+
return null;
|
|
22119
|
+
};
|
|
22120
|
+
readRunTail = async (sessionId, initialRun, journalOffset) => {
|
|
22121
|
+
const stream = createReadStream(this.sessionPath(sessionId), {
|
|
22122
|
+
encoding: "utf-8",
|
|
22123
|
+
start: journalOffset
|
|
22124
|
+
});
|
|
23208
22125
|
const lines = createInterface({
|
|
23209
|
-
input,
|
|
22126
|
+
input: stream,
|
|
23210
22127
|
crlfDelay: Infinity
|
|
23211
22128
|
});
|
|
23212
|
-
let activeRun =
|
|
22129
|
+
let activeRun = initialRun;
|
|
23213
22130
|
try {
|
|
23214
22131
|
for await (const line of lines) {
|
|
23215
|
-
|
|
23216
|
-
|
|
23217
|
-
try {
|
|
23218
|
-
parsed = JSON.parse(line);
|
|
23219
|
-
} catch {
|
|
23220
|
-
continue;
|
|
23221
|
-
}
|
|
23222
|
-
if (!isRecord$11(parsed) || parsed._type !== "event" || !isRecord$11(parsed.event)) continue;
|
|
23223
|
-
activeRun = applyNcpAgentRunLifecycleEvent(sessionId, activeRun, parsed.event);
|
|
22132
|
+
const event = readRunLifecycleEvent(line);
|
|
22133
|
+
if (event) activeRun = applyNcpAgentRunLifecycleEvent(sessionId, activeRun, event);
|
|
23224
22134
|
}
|
|
23225
22135
|
return activeRun;
|
|
23226
|
-
} catch {
|
|
23227
|
-
return null;
|
|
23228
22136
|
} finally {
|
|
23229
22137
|
lines.close();
|
|
23230
|
-
|
|
22138
|
+
stream.destroy();
|
|
23231
22139
|
}
|
|
23232
22140
|
};
|
|
23233
22141
|
sessionPath = (sessionId) => join(this.journalDir, `${safeNcpSessionFilename(sessionId.replace(/:/g, "_"))}.jsonl`);
|
|
23234
22142
|
};
|
|
22143
|
+
function readRunLifecycleEvent(line) {
|
|
22144
|
+
if (!line.trim() || !RUN_LIFECYCLE_EVENT_NEEDLES.some((needle) => line.includes(needle))) return null;
|
|
22145
|
+
let parsed;
|
|
22146
|
+
try {
|
|
22147
|
+
parsed = JSON.parse(line);
|
|
22148
|
+
} catch {
|
|
22149
|
+
return null;
|
|
22150
|
+
}
|
|
22151
|
+
if (!isRecord$9(parsed) || parsed._type !== "event" || !isRecord$9(parsed.event)) return null;
|
|
22152
|
+
const event = parsed.event;
|
|
22153
|
+
return event.type === NcpEventType.RunStarted || event.type === NcpEventType.RunFinished || event.type === NcpEventType.RunError || event.type === NcpEventType.MessageAbort ? event : null;
|
|
22154
|
+
}
|
|
22155
|
+
function resolveUnfinishedRun(sessionId, startedEvent, reverseTerminalEvents) {
|
|
22156
|
+
let activeRun = applyNcpAgentRunLifecycleEvent(sessionId, null, startedEvent);
|
|
22157
|
+
for (let index = reverseTerminalEvents.length - 1; index >= 0 && activeRun; index -= 1) activeRun = applyNcpAgentRunLifecycleEvent(sessionId, activeRun, reverseTerminalEvents[index]);
|
|
22158
|
+
return activeRun;
|
|
22159
|
+
}
|
|
23235
22160
|
//#endregion
|
|
23236
22161
|
//#region src/utils/ncp-agent-session-journal-entry.utils.ts
|
|
23237
22162
|
function isNcpAgentSessionMessageProjectionBoundaryEvent(event) {
|
|
@@ -23240,11 +22165,11 @@ function isNcpAgentSessionMessageProjectionBoundaryEvent(event) {
|
|
|
23240
22165
|
function serializeNcpAgentSessionJournalEntry(entry) {
|
|
23241
22166
|
const serialized = JSON.stringify(entry);
|
|
23242
22167
|
if (!serialized) throw new Error("ncp agent session journal entry serialization produced empty output");
|
|
23243
|
-
if (!isRecord$
|
|
22168
|
+
if (!isRecord$9(JSON.parse(serialized))) throw new Error("ncp agent session journal entry serialization produced a non-object entry");
|
|
23244
22169
|
return serialized;
|
|
23245
22170
|
}
|
|
23246
22171
|
function attachNcpAgentSessionJournalTimestamp(event, timestamp) {
|
|
23247
|
-
if (!("payload" in event) || !isRecord$
|
|
22172
|
+
if (!("payload" in event) || !isRecord$9(event.payload)) return event;
|
|
23248
22173
|
return {
|
|
23249
22174
|
...event,
|
|
23250
22175
|
payload: {
|
|
@@ -23269,7 +22194,7 @@ var NcpAgentSessionJournalParser = class {
|
|
|
23269
22194
|
this.applyMetadata(parsed);
|
|
23270
22195
|
return;
|
|
23271
22196
|
}
|
|
23272
|
-
if (parsed._type === "event" && isRecord$
|
|
22197
|
+
if (parsed._type === "event" && isRecord$9(parsed.event)) this.applyEvent(parsed, lineEndOffset);
|
|
23273
22198
|
};
|
|
23274
22199
|
finish = () => ({
|
|
23275
22200
|
metadata: this.metadata,
|
|
@@ -23283,14 +22208,14 @@ var NcpAgentSessionJournalParser = class {
|
|
|
23283
22208
|
parseLine = (line, index) => {
|
|
23284
22209
|
try {
|
|
23285
22210
|
const parsed = JSON.parse(line);
|
|
23286
|
-
return isRecord$
|
|
22211
|
+
return isRecord$9(parsed) ? parsed : null;
|
|
23287
22212
|
} catch (error) {
|
|
23288
22213
|
console.warn(`[ncp-agent-session-journal] skipped corrupted journal line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
|
|
23289
22214
|
return null;
|
|
23290
22215
|
}
|
|
23291
22216
|
};
|
|
23292
22217
|
applyMetadata = (entry) => {
|
|
23293
|
-
this.metadata = isRecord$
|
|
22218
|
+
this.metadata = isRecord$9(entry.metadata) ? structuredClone(entry.metadata) : {};
|
|
23294
22219
|
this.agentId = normalizeNcpAgentId(typeof entry.agent_id === "string" ? entry.agent_id : void 0);
|
|
23295
22220
|
this.createdAt = toIsoString(entry.created_at, this.createdAt);
|
|
23296
22221
|
this.updatedAt = toIsoString(entry.updated_at, this.updatedAt);
|
|
@@ -23337,7 +22262,7 @@ var NcpAgentSessionMetadataStore = class {
|
|
|
23337
22262
|
read = async (sessionId, activitySnapshot) => {
|
|
23338
22263
|
try {
|
|
23339
22264
|
const parsed = JSON.parse(await readFile(this.metadataPath(sessionId), "utf-8"));
|
|
23340
|
-
if (!isRecord$
|
|
22265
|
+
if (!isRecord$9(parsed) || parsed._type !== "metadata" || !isRecord$9(parsed.metadata)) throw new Error(`invalid ncp agent session metadata sidecar: ${sessionId}`);
|
|
23341
22266
|
const createdAt = toIsoString(parsed.created_at, activitySnapshot.createdAt);
|
|
23342
22267
|
const agentId = normalizeNcpAgentId(typeof parsed.agent_id === "string" ? parsed.agent_id : void 0);
|
|
23343
22268
|
return {
|
|
@@ -23879,6 +22804,11 @@ async function scanNcpAgentSessionCatalogJournals(params) {
|
|
|
23879
22804
|
};
|
|
23880
22805
|
}
|
|
23881
22806
|
for (const entry of entries) {
|
|
22807
|
+
const sessionId = readJournalSessionId(entry);
|
|
22808
|
+
if (sessionId && params.knownSessionIds?.has(sessionId)) {
|
|
22809
|
+
journalSessionIds.add(sessionId);
|
|
22810
|
+
continue;
|
|
22811
|
+
}
|
|
23882
22812
|
const item = await scanJournalEntry(params, entry, legacyRecords);
|
|
23883
22813
|
if (!item) continue;
|
|
23884
22814
|
journalSessionIds.add(item.sessionId);
|
|
@@ -23900,9 +22830,13 @@ async function scanNcpAgentSessionCatalogJournals(params) {
|
|
|
23900
22830
|
diagnostics
|
|
23901
22831
|
};
|
|
23902
22832
|
}
|
|
23903
|
-
|
|
22833
|
+
function readJournalSessionId(entry) {
|
|
23904
22834
|
if (!entry.endsWith(".jsonl")) return null;
|
|
23905
|
-
|
|
22835
|
+
return normalizeNcpSessionId(entry.replace(/\.jsonl$/, "").replace(/_/g, ":"));
|
|
22836
|
+
}
|
|
22837
|
+
async function scanJournalEntry(params, entry, legacyRecords) {
|
|
22838
|
+
const sessionId = readJournalSessionId(entry);
|
|
22839
|
+
if (!sessionId) return null;
|
|
23906
22840
|
const lightweight = params.loadSessionSummary ? await params.loadSessionSummary(sessionId) : null;
|
|
23907
22841
|
if (lightweight) return {
|
|
23908
22842
|
sessionId,
|
|
@@ -23943,9 +22877,78 @@ async function readLegacyRecords(journalDir, diagnostics) {
|
|
|
23943
22877
|
return /* @__PURE__ */ new Map();
|
|
23944
22878
|
}
|
|
23945
22879
|
//#endregion
|
|
22880
|
+
//#region src/stores/ncp-agent-run-recovery-index.store.ts
|
|
22881
|
+
var NcpAgentRunRecoveryIndexStore = class {
|
|
22882
|
+
constructor(db, ensureReady) {
|
|
22883
|
+
this.db = db;
|
|
22884
|
+
this.ensureReady = ensureReady;
|
|
22885
|
+
}
|
|
22886
|
+
initializeSchema = () => {
|
|
22887
|
+
this.db().exec(`
|
|
22888
|
+
CREATE TABLE IF NOT EXISTS run_recovery (
|
|
22889
|
+
session_id TEXT PRIMARY KEY,
|
|
22890
|
+
journal_offset INTEGER NOT NULL,
|
|
22891
|
+
active_run_json TEXT,
|
|
22892
|
+
FOREIGN KEY (session_id) REFERENCES sessions(session_id) ON DELETE CASCADE
|
|
22893
|
+
);
|
|
22894
|
+
`);
|
|
22895
|
+
};
|
|
22896
|
+
list = async () => {
|
|
22897
|
+
await this.ensureReady();
|
|
22898
|
+
return this.db().prepare(`
|
|
22899
|
+
SELECT sessions.session_id, run_recovery.journal_offset, run_recovery.active_run_json
|
|
22900
|
+
FROM sessions
|
|
22901
|
+
LEFT JOIN run_recovery ON run_recovery.session_id = sessions.session_id
|
|
22902
|
+
WHERE sessions.deleted_at IS NULL
|
|
22903
|
+
`).all().map((row) => ({
|
|
22904
|
+
sessionId: row.session_id,
|
|
22905
|
+
journalOffset: row.journal_offset,
|
|
22906
|
+
activeRun: parseUnfinishedRun(row.active_run_json)
|
|
22907
|
+
}));
|
|
22908
|
+
};
|
|
22909
|
+
write = async (checkpoint) => {
|
|
22910
|
+
await this.ensureReady();
|
|
22911
|
+
this.db().prepare(`
|
|
22912
|
+
INSERT INTO run_recovery (session_id, journal_offset, active_run_json)
|
|
22913
|
+
VALUES (?, ?, ?)
|
|
22914
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
22915
|
+
journal_offset = excluded.journal_offset,
|
|
22916
|
+
active_run_json = excluded.active_run_json
|
|
22917
|
+
`).run(checkpoint.sessionId, checkpoint.journalOffset, checkpoint.activeRun ? JSON.stringify(checkpoint.activeRun) : null);
|
|
22918
|
+
};
|
|
22919
|
+
recordEvent = async (params) => {
|
|
22920
|
+
const { event, journalOffset, sessionId } = params;
|
|
22921
|
+
if (!isNcpAgentRunLifecycleEvent(event)) return;
|
|
22922
|
+
await this.ensureReady();
|
|
22923
|
+
const row = this.db().prepare(`
|
|
22924
|
+
SELECT active_run_json FROM run_recovery WHERE session_id = ? LIMIT 1
|
|
22925
|
+
`).get(sessionId);
|
|
22926
|
+
await this.write({
|
|
22927
|
+
sessionId,
|
|
22928
|
+
journalOffset,
|
|
22929
|
+
activeRun: applyNcpAgentRunLifecycleEvent(sessionId, parseUnfinishedRun(row?.active_run_json ?? null), event)
|
|
22930
|
+
});
|
|
22931
|
+
};
|
|
22932
|
+
};
|
|
22933
|
+
function parseUnfinishedRun(value) {
|
|
22934
|
+
if (!value) return null;
|
|
22935
|
+
try {
|
|
22936
|
+
const parsed = JSON.parse(value);
|
|
22937
|
+
if (!parsed || typeof parsed.sessionId !== "string") return null;
|
|
22938
|
+
return {
|
|
22939
|
+
sessionId: parsed.sessionId,
|
|
22940
|
+
...typeof parsed.messageId === "string" ? { messageId: parsed.messageId } : {},
|
|
22941
|
+
...typeof parsed.runId === "string" ? { runId: parsed.runId } : {},
|
|
22942
|
+
...typeof parsed.startedAt === "string" ? { startedAt: parsed.startedAt } : {}
|
|
22943
|
+
};
|
|
22944
|
+
} catch {
|
|
22945
|
+
return null;
|
|
22946
|
+
}
|
|
22947
|
+
}
|
|
22948
|
+
//#endregion
|
|
23946
22949
|
//#region src/stores/ncp-agent-session-summary-index.store.ts
|
|
23947
22950
|
const SQLITE_DATABASE_FILE = ".ncp-agent-session-catalog.sqlite";
|
|
23948
|
-
const CATALOG_SCHEMA_VERSION =
|
|
22951
|
+
const CATALOG_SCHEMA_VERSION = 2;
|
|
23949
22952
|
const MIGRATION_STATUS_KEY = "migration_status";
|
|
23950
22953
|
const MIGRATION_COMPLETE = "complete";
|
|
23951
22954
|
function buildCatalogFilter(query) {
|
|
@@ -24003,6 +23006,7 @@ function rowToSummary(row) {
|
|
|
24003
23006
|
var NcpAgentSessionSummaryIndexStore = class {
|
|
24004
23007
|
database = null;
|
|
24005
23008
|
readyPromise = null;
|
|
23009
|
+
runRecovery = new NcpAgentRunRecoveryIndexStore(() => this.db(), () => this.ensureReady());
|
|
24006
23010
|
constructor(journalDir, loadSession, loadSessionSummary) {
|
|
24007
23011
|
this.journalDir = journalDir;
|
|
24008
23012
|
this.loadSession = loadSession;
|
|
@@ -24078,6 +23082,9 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
24078
23082
|
status = excluded.status
|
|
24079
23083
|
WHERE sessions.deleted_at IS NULL`).run(upsertParams);
|
|
24080
23084
|
};
|
|
23085
|
+
listRunRecoveryCheckpoints = this.runRecovery.list;
|
|
23086
|
+
writeRunRecoveryCheckpoint = this.runRecovery.write;
|
|
23087
|
+
recordRunRecoveryEvent = this.runRecovery.recordEvent;
|
|
24081
23088
|
remove = async (sessionId) => {
|
|
24082
23089
|
await this.ensureReady();
|
|
24083
23090
|
const normalizedSessionId = normalizeNcpSessionId(sessionId);
|
|
@@ -24141,13 +23148,19 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
24141
23148
|
CREATE INDEX IF NOT EXISTS sessions_activity_idx
|
|
24142
23149
|
ON sessions (deleted_at, last_message_at, created_at, updated_at);
|
|
24143
23150
|
`);
|
|
23151
|
+
this.runRecovery.initializeSchema();
|
|
23152
|
+
this.db().prepare(`INSERT INTO storage_meta (key, value) VALUES ('schema_version', ?)
|
|
23153
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(String(CATALOG_SCHEMA_VERSION));
|
|
23154
|
+
const migrationComplete = this.db().prepare("SELECT value FROM storage_meta WHERE key = ? LIMIT 1").get(MIGRATION_STATUS_KEY)?.value === MIGRATION_COMPLETE;
|
|
23155
|
+
const knownSessionIds = migrationComplete ? new Set(this.db().prepare("SELECT session_id FROM sessions").all().map((row) => row.session_id)) : void 0;
|
|
24144
23156
|
const scan = await scanNcpAgentSessionCatalogJournals({
|
|
24145
23157
|
journalDir: this.journalDir,
|
|
24146
23158
|
loadSession: (sessionId) => this.loadSession(sessionId),
|
|
24147
|
-
loadSessionSummary: this.loadSessionSummary
|
|
23159
|
+
loadSessionSummary: this.loadSessionSummary,
|
|
23160
|
+
knownSessionIds
|
|
24148
23161
|
});
|
|
24149
23162
|
runSqliteTransaction(this.db(), () => {
|
|
24150
|
-
if (
|
|
23163
|
+
if (migrationComplete) {
|
|
24151
23164
|
this.reconcileRecords(scan.records);
|
|
24152
23165
|
return;
|
|
24153
23166
|
}
|
|
@@ -24159,8 +23172,6 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
24159
23172
|
VALUES (?, ?, ?, ?)`).run(diagnostic.sessionId ?? null, diagnostic.kind, JSON.stringify(diagnostic.detail), (/* @__PURE__ */ new Date()).toISOString());
|
|
24160
23173
|
this.db().prepare(`INSERT INTO storage_meta (key, value) VALUES (?, ?)
|
|
24161
23174
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(MIGRATION_STATUS_KEY, MIGRATION_COMPLETE);
|
|
24162
|
-
this.db().prepare(`INSERT INTO storage_meta (key, value) VALUES ('schema_version', ?)
|
|
24163
|
-
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(String(CATALOG_SCHEMA_VERSION));
|
|
24164
23175
|
}, "IMMEDIATE");
|
|
24165
23176
|
};
|
|
24166
23177
|
reconcileRecords = (records) => {
|
|
@@ -24320,7 +23331,7 @@ var NcpAgentSessionJournalStore = class {
|
|
|
24320
23331
|
readMetadata: (sessionId, fallback) => this.metadataStore.read(sessionId, fallback),
|
|
24321
23332
|
readProjectedMessageCount: async (sessionId) => (await this.messageProjectionStore.readMeta(sessionId))?.total ?? null
|
|
24322
23333
|
});
|
|
24323
|
-
this.unfinishedRunStore = new NcpAgentUnfinishedRunStore(journalDir,
|
|
23334
|
+
this.unfinishedRunStore = new NcpAgentUnfinishedRunStore(journalDir, this.summaryIndexStore.listRunRecoveryCheckpoints, this.summaryIndexStore.writeRunRecoveryCheckpoint);
|
|
24324
23335
|
}
|
|
24325
23336
|
initialize = async () => await this.summaryIndexStore.initialize();
|
|
24326
23337
|
close = () => this.summaryIndexStore.close();
|
|
@@ -24504,11 +23515,12 @@ var NcpAgentSessionJournalStore = class {
|
|
|
24504
23515
|
await this.appendJournalEntry(path, entry);
|
|
24505
23516
|
this.nextSeqBySession.set(sessionId, nextSeq + 1);
|
|
24506
23517
|
this.sessions.delete(sessionId);
|
|
23518
|
+
let journalOffset = null;
|
|
24507
23519
|
if (isNcpAgentSessionMessageProjectionBoundaryEvent(event)) {
|
|
24508
|
-
|
|
23520
|
+
journalOffset = (await stat(path)).size;
|
|
24509
23521
|
await this.messageProjectionStore.synchronizeJournalTail({
|
|
24510
23522
|
sessionId,
|
|
24511
|
-
journalOffset
|
|
23523
|
+
journalOffset
|
|
24512
23524
|
});
|
|
24513
23525
|
}
|
|
24514
23526
|
await this.summaryIndexStore.upsertForEvent({
|
|
@@ -24516,6 +23528,11 @@ var NcpAgentSessionJournalStore = class {
|
|
|
24516
23528
|
event,
|
|
24517
23529
|
updatedAt
|
|
24518
23530
|
});
|
|
23531
|
+
if (isNcpAgentRunLifecycleEvent(event)) await this.summaryIndexStore.recordRunRecoveryEvent({
|
|
23532
|
+
sessionId,
|
|
23533
|
+
event,
|
|
23534
|
+
journalOffset: journalOffset ?? (await stat(path)).size
|
|
23535
|
+
});
|
|
24519
23536
|
};
|
|
24520
23537
|
loadSession = async (sessionId) => {
|
|
24521
23538
|
let raw;
|
|
@@ -25910,7 +24927,7 @@ const createSilentRepliesContextProvider = () => staticBlock([
|
|
|
25910
24927
|
"",
|
|
25911
24928
|
"⚠️ Rules:",
|
|
25912
24929
|
"- It must be your ENTIRE message — nothing else",
|
|
25913
|
-
"-
|
|
24930
|
+
"- Only an entire reply matching <noreply/> is silent; mentioning the token in normal content remains visible",
|
|
25914
24931
|
"- Never wrap it in markdown or code blocks",
|
|
25915
24932
|
"",
|
|
25916
24933
|
"❌ Wrong: \"Here's help... <noreply/>\"",
|
|
@@ -29193,7 +28210,7 @@ function createPortableRuntimeAcceptanceServices(params) {
|
|
|
29193
28210
|
};
|
|
29194
28211
|
}
|
|
29195
28212
|
function createKernelSessionManagers(params) {
|
|
29196
|
-
const { agentContextWindowManager, agentManager, configManager, eventBus, ingress, observationStorePath,
|
|
28213
|
+
const { agentContextWindowManager, agentManager, configManager, eventBus, ingress, observationStorePath, legacyProjectStorePath, projectDatabasePath, sessionsDir } = params;
|
|
29197
28214
|
const sessionSearch = new SessionSearchService({
|
|
29198
28215
|
databasePath: resolve(getDataDir(), "session-search.db"),
|
|
29199
28216
|
sessionsDir
|
|
@@ -29201,14 +28218,15 @@ function createKernelSessionManagers(params) {
|
|
|
29201
28218
|
const journalStore = new NcpAgentSessionJournalStore(resolve(sessionsDir, ".ncp-agent-journal"));
|
|
29202
28219
|
const projectWorkOwner = { current: null };
|
|
29203
28220
|
const projectManager = new ProjectManager({
|
|
29204
|
-
|
|
28221
|
+
databasePath: projectDatabasePath,
|
|
28222
|
+
legacyStorePath: legacyProjectStorePath,
|
|
29205
28223
|
getDefaultWorkspacePath: () => getWorkspacePathFromConfig(configManager.config),
|
|
29206
28224
|
onProjectRegistered: async (project) => {
|
|
29207
28225
|
await projectWorkOwner.current?.ensureProject(project.id);
|
|
29208
28226
|
}
|
|
29209
28227
|
});
|
|
29210
28228
|
const projectWorkManager = new ProjectWorkManager({
|
|
29211
|
-
databasePath:
|
|
28229
|
+
databasePath: projectDatabasePath,
|
|
29212
28230
|
eventBus,
|
|
29213
28231
|
projectManager
|
|
29214
28232
|
});
|
|
@@ -29234,17 +28252,13 @@ function createKernelSessionManagers(params) {
|
|
|
29234
28252
|
ingress,
|
|
29235
28253
|
eventBus
|
|
29236
28254
|
});
|
|
29237
|
-
const
|
|
29238
|
-
projectManager,
|
|
29239
|
-
sessionManager,
|
|
29240
|
-
workspacePath: getWorkspacePathFromConfig(configManager.config)
|
|
29241
|
-
});
|
|
28255
|
+
const projectMaterials = new ProjectMaterialService({ projectManager });
|
|
29242
28256
|
observationOwner.current = observations;
|
|
29243
28257
|
return {
|
|
29244
28258
|
journalStore,
|
|
29245
28259
|
observations,
|
|
29246
28260
|
projectManager,
|
|
29247
|
-
|
|
28261
|
+
projectMaterials,
|
|
29248
28262
|
projectWorkManager,
|
|
29249
28263
|
sessionManager,
|
|
29250
28264
|
sessionSearch
|
|
@@ -29345,7 +28359,7 @@ var NextclawKernel = class {
|
|
|
29345
28359
|
panelAppManager;
|
|
29346
28360
|
preferenceManager;
|
|
29347
28361
|
projectManager;
|
|
29348
|
-
|
|
28362
|
+
projectMaterials;
|
|
29349
28363
|
projectWorkManager;
|
|
29350
28364
|
serviceAppManager;
|
|
29351
28365
|
extensions;
|
|
@@ -29392,15 +28406,15 @@ var NextclawKernel = class {
|
|
|
29392
28406
|
homeDir: options.homeDir
|
|
29393
28407
|
});
|
|
29394
28408
|
this.capabilityGrantLegacyMigration = this.createCapabilityGrantLegacyMigration(options);
|
|
29395
|
-
({journalStore: this.ncpAgentSessionJournalStore, observations: this.observations, projectManager: this.projectManager,
|
|
28409
|
+
({journalStore: this.ncpAgentSessionJournalStore, observations: this.observations, projectManager: this.projectManager, projectMaterials: this.projectMaterials, projectWorkManager: this.projectWorkManager, sessionManager: this.sessionManager, sessionSearch: this.sessionSearch} = createKernelSessionManagers({
|
|
29396
28410
|
agentContextWindowManager: this.agentContextWindowManager,
|
|
29397
28411
|
agentManager: this.agents,
|
|
29398
28412
|
configManager: this.configManager,
|
|
29399
28413
|
eventBus: this.eventBus,
|
|
29400
28414
|
ingress: this.ingress,
|
|
29401
28415
|
observationStorePath: resolveKernelObservationStorePath(options),
|
|
29402
|
-
|
|
29403
|
-
|
|
28416
|
+
legacyProjectStorePath: resolveKernelLegacyProjectStorePath(options),
|
|
28417
|
+
projectDatabasePath: resolveKernelProjectDatabasePath(options),
|
|
29404
28418
|
sessionsDir
|
|
29405
28419
|
}));
|
|
29406
28420
|
this.inboxDeliveryManager = new InboxDeliveryManager({
|
|
@@ -29500,8 +28514,7 @@ var NextclawKernel = class {
|
|
|
29500
28514
|
this.sessionSearch.start();
|
|
29501
28515
|
this.mcpManager.start();
|
|
29502
28516
|
this.providerModelCatalog.start();
|
|
29503
|
-
await this.projectManager.
|
|
29504
|
-
await this.projectManager.importSessionProjects((await this.sessionManager.listSessions()).map((session) => readProjectRoot(session.metadata)));
|
|
28517
|
+
await this.projectManager.initialize();
|
|
29505
28518
|
await this.projectWorkManager.initialize();
|
|
29506
28519
|
await this.sessionManager.start();
|
|
29507
28520
|
for (const contribution of this.contributions) await contribution.start();
|
|
@@ -29523,6 +28536,7 @@ var NextclawKernel = class {
|
|
|
29523
28536
|
await this.serviceAppManager.dispose();
|
|
29524
28537
|
await this.sessionSearch.dispose();
|
|
29525
28538
|
this.projectWorkManager.dispose();
|
|
28539
|
+
this.projectManager.dispose();
|
|
29526
28540
|
};
|
|
29527
28541
|
};
|
|
29528
28542
|
//#endregion
|
|
@@ -30665,6 +29679,6 @@ function resolveLegacyEventType(message) {
|
|
|
30665
29679
|
return `message.${role || "other"}`;
|
|
30666
29680
|
}
|
|
30667
29681
|
//#endregion
|
|
30668
|
-
export { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, AccessManager, AgentManager, AgentRunClient, AppDataError, AppDataManager, AppPackageError, AppPackageManager, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_CONTINUATION_TEXT, CONTEXT_COMPACTION_PROJECTION_KIND, CONTEXT_COMPACTION_PROJECTION_METADATA_KEY, CONTEXT_COMPACTION_SYSTEM_PREAMBLE, CONTEXT_COMPACTION_TIMELINE_KIND, CapabilityGrantLegacyMigrationService, CapabilityGrantManager, CapabilityGrantStore, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionJournalRecoveryService, ContextCompactionPreflightService, Contribution, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, DESKTOP_HOST_ACCESS, DESKTOP_HOST_PROTOCOL_VERSION, DesktopHostCapabilityManager, DesktopNodeReplService, DesktopSessionStateService, EventBus, ExtensionManager, FeatureControlsService, GatewayInboundProcessor, InboxDeliveryError, InboxDeliveryManager, Ingress, LlmProviderManager, LlmUsageManager, LlmUsageStore, MAX_INBOX_DELIVERY_CONTENT_LENGTH, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawHarness, NextclawHarnessError, NextclawKernel, ObservationManager, PANEL_APP_AGENT_CAPABILITIES, PORTABLE_RUNTIME_ACCEPTANCE_CONTRACT, PORTABLE_RUNTIME_ACCEPTANCE_CONTRACT_FINGERPRINT, PORTABLE_RUNTIME_ACCEPTANCE_LOCALES, PORTABLE_RUNTIME_ACCEPTANCE_PLATFORMS, PORTABLE_RUNTIME_ACCEPTANCE_PRESENTATION, PORTABLE_RUNTIME_ACCEPTANCE_REFERENCE_APP_ID,
|
|
29682
|
+
export { AUTOMATIC_UPDATE_CHECK_INTERVAL_MS, AccessManager, AgentManager, AgentRunClient, AppDataError, AppDataManager, AppPackageError, AppPackageManager, AutomationManager, BuiltinNarpRuntimeProviderService, CONTEXT_COMPACTION_CONTINUATION_TEXT, CONTEXT_COMPACTION_PROJECTION_KIND, CONTEXT_COMPACTION_PROJECTION_METADATA_KEY, CONTEXT_COMPACTION_SYSTEM_PREAMBLE, CONTEXT_COMPACTION_TIMELINE_KIND, CapabilityGrantLegacyMigrationService, CapabilityGrantManager, CapabilityGrantStore, ChannelManager, CommandRegistry, ConfigManager, ContextCompactionJournalRecoveryService, ContextCompactionPreflightService, Contribution, DEFAULT_AGENT_RUNTIME_ENTRY_ID, DEFAULT_SERVICE_ACTION_RISK, DESKTOP_HOST_ACCESS, DESKTOP_HOST_PROTOCOL_VERSION, DesktopHostCapabilityManager, DesktopNodeReplService, DesktopSessionStateService, EventBus, ExtensionManager, FeatureControlsService, GatewayInboundProcessor, InboxDeliveryError, InboxDeliveryManager, Ingress, LlmProviderManager, LlmUsageManager, LlmUsageStore, MAX_INBOX_DELIVERY_CONTENT_LENGTH, McpManager, McpServiceAppRuntimeService, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, NEXTCLAW_TIMELINE_KIND_METADATA_KEY, NcpAgentSessionJournalStore, NextclawHarness, NextclawHarnessError, NextclawKernel, ObservationManager, PANEL_APP_AGENT_CAPABILITIES, PORTABLE_RUNTIME_ACCEPTANCE_CONTRACT, PORTABLE_RUNTIME_ACCEPTANCE_CONTRACT_FINGERPRINT, PORTABLE_RUNTIME_ACCEPTANCE_LOCALES, PORTABLE_RUNTIME_ACCEPTANCE_PLATFORMS, PORTABLE_RUNTIME_ACCEPTANCE_PRESENTATION, PORTABLE_RUNTIME_ACCEPTANCE_REFERENCE_APP_ID, PROJECT_TEMPLATE_IDS, PROJECT_WORK_ATTENTION_VALUES, PROJECT_WORK_STATE_CATEGORIES, PROVIDER_MODEL_CATALOG_REFRESH_INTERVAL_MS, PanelAppAssetTokenService, PanelAppError, PanelAppManager, PortableRuntimeAcceptanceIdentityService, PortableRuntimeAcceptanceManager, PreferenceError, PreferenceManager, ProjectError, ProjectManager, ProjectMaterialService, ProjectWorkError, ProjectWorkManager, ProviderManagerNcpLLMApi, ProviderModelCatalogManager, SERVICE_APP_MANIFEST_FILE_NAME, ServiceAppAiCapabilityService, ServiceAppError, ServiceAppJobJournalService, ServiceAppManager, ServiceAppResidentEventInboxService, ServiceAppRuntimeService, SessionContextCompactionError, SessionContextCompactionManager, SessionManager, SessionMessageCursorError, SessionRequestManager, SessionSettingsError, SkillManager, SystemObjectReferenceError, SystemObjectReferenceManager, UnavailableDesktopHost, UpdateManifestReader, VerificationRecordService, assertObservationJsonValue, assertObservationPredicate, buildAgentRunSendPayload, buildContextCompactionModelProjection, buildContextCompactionTimelineNcpMessage, buildLlmUsageSummary, buildLocalizedTextMap, buildNextclawNcpRunContext, buildObservationEventModelMessage, buildServiceActionId, buildSessionRequestCompletionMessage, capabilityGrantCovers, createAgentRuntimeSessionRequestDispatcher, createAgentRuntimeSessionRequestSourceNotifier, createAssetTools, createCapabilityDeclarationFingerprint, createContextCompactionMessageId, createContextWindowSignature, createCronJobSystemObjectProvider, createDesktopHostError, createInboxDeliverySystemObjectProvider, createLlmUsageRecord, createPanelAppAgentGrantRequest, createPanelAppClientGrantRequest, createServiceActionGrantRequest, createServiceAppAgentSlotGrantRequest, createServiceAppModelSlotGrantRequest, createTypedKey, describeAgentRuntimeSessionTypes, dispatchAgentRuntimeSessionRequest, dispatchChannelReplyRoute, dispatchPromptOverNcp, dispatchPromptOverNcpResult, evaluateObservationEventAdmission, evaluatePortableRuntimeAcceptance, evaluatePortableRuntimeAcceptanceArtifact, eventKeys, getAutomaticUpdateCheckDelay, getCapabilityGrantKey, getServiceActionName, getServiceAppManifestPath, getUiContentParamsBootstrapScript, getUnsignedUpdateManifest, hasLlmUsageTelemetry, ingressKeys, injectUiContentParamsBootstrap, isAppDataError, isAppPackageError, isContextCompactionProjectionMessage, isContextCompactionTimelineMessage, isContextWindowSnapshot, isInboxDeliveryError, isPanelAppAgentCapability, isPanelAppError, isPreferenceError, isProjectError, isProjectWorkError, isReplyCapableChannel, isServiceAppError, isSessionContextCompactionError, isSessionMessageCursorError, isSessionSettingsError, isSystemObjectReferenceError, listExtensionChannelIds, listServiceAppManifestActions, matchesCapabilityGrantFilter, matchesObservationPredicate, mergeServiceAppRuntimeActions, normalizeAgentRuntimeSessionTypeIcon, normalizeCapabilityGrantRequest, normalizeLlmUsageModel, normalizeOptionalString, normalizePortableRuntimeEnvironment, parseObservationDuration, parsePortableRuntimeAcceptanceEvidenceArtifact, parseServiceAppManifest, parseSkillFrontmatter, presentPortableRuntimeAcceptanceDefinition, readContextCompactionCheckpoint, readContextWindowEventSessionId, readJsonPointer, readLatestContextCompactionCheckpoint, readLearningLoopRuntimeConfig, readMetadataModel, readMetadataThinking, readServiceActionTargetId, readServiceAppManifest, readServiceAppSlotTarget, resolveAgentRuntimeEntries, resolveAutomaticUpdateCheckIntervalMs, resolveChannelReplyRoute, resolveEffectiveModel, resolveLegacyEventType, resolvePortableRuntimeAcceptanceLocale, resolveSessionChannelContext, runGatewayInboundLoop, runNextclawTask, sanitizeLlmUsage, serializeContextTail, serializeUnsignedUpdateManifest, shouldRefreshContextWindowDuringStream, shouldRefreshContextWindowImmediately, startPromptOverNcpExecution, stripSkillFrontmatter, syncSessionThinkingPreference, toBoundedJson, toNcpMessages, waitForAgentRuntimeSessionReply };
|
|
30669
29683
|
|
|
30670
29684
|
//# sourceMappingURL=index.js.map
|