@nextclaw/kernel 0.12.3 → 0.13.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 +124 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1171 -370
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -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, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
13
|
+
import { access, appendFile, chmod, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
14
14
|
import { AppHomeService, AppInstallationService, AppInstanceInventoryService, AppInstanceStorageService, AppManifestService, AppPlatformTargetService, AppRegistryService, AppServiceLaunchService, FileLockService, isAppComponentManifestBundle } from "@nextclaw/app-runtime";
|
|
15
15
|
import { execFileSync, spawn } from "node:child_process";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
@@ -19,7 +19,6 @@ import { McpRegistryService, McpServerLifecycleManager, normalizeMcpServerName }
|
|
|
19
19
|
import { McpNcpToolRegistryAdapter } from "@nextclaw/ncp-mcp";
|
|
20
20
|
import { parse } from "yaml";
|
|
21
21
|
import { createInterface } from "node:readline";
|
|
22
|
-
import Database from "better-sqlite3";
|
|
23
22
|
import { HttpRuntimeConfigResolver, HttpRuntimeNcpAgentRuntime } from "@nextclaw/nextclaw-ncp-runtime-http-client";
|
|
24
23
|
import { StdioRuntimeConfigResolver, StdioRuntimeNcpAgentRuntime, probeStdioRuntime } from "@nextclaw/nextclaw-ncp-runtime-stdio-client";
|
|
25
24
|
import { DefaultNcpAgentRuntime } from "@nextclaw/ncp-agent-runtime-next";
|
|
@@ -1394,7 +1393,7 @@ const SESSION_ACTIVITY_PREVIEW_STATUS_KINDS = new Set([
|
|
|
1394
1393
|
"run-failed",
|
|
1395
1394
|
"run-interrupted"
|
|
1396
1395
|
]);
|
|
1397
|
-
function isRecord$
|
|
1396
|
+
function isRecord$19(value) {
|
|
1398
1397
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1399
1398
|
}
|
|
1400
1399
|
function readOptionalString$14(value) {
|
|
@@ -1403,7 +1402,7 @@ function readOptionalString$14(value) {
|
|
|
1403
1402
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
1404
1403
|
}
|
|
1405
1404
|
function readSessionActivityPreviewMetadata(value) {
|
|
1406
|
-
if (!isRecord$
|
|
1405
|
+
if (!isRecord$19(value)) return null;
|
|
1407
1406
|
const state = value.state;
|
|
1408
1407
|
const timestamp = readOptionalString$14(value.timestamp);
|
|
1409
1408
|
if (!SESSION_ACTIVITY_PREVIEW_STATES.has(state) || !timestamp) return null;
|
|
@@ -1497,7 +1496,7 @@ var SessionActivityPreviewEventService = class {
|
|
|
1497
1496
|
//#endregion
|
|
1498
1497
|
//#region src/managers/agent-run-session-command.manager.ts
|
|
1499
1498
|
const CONTINUATION_PROMPT = "Continue from where you stopped. Preserve completed work and avoid repeating it.";
|
|
1500
|
-
function isRecord$
|
|
1499
|
+
function isRecord$18(value) {
|
|
1501
1500
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1502
1501
|
}
|
|
1503
1502
|
function hasSendableMessageContent(message) {
|
|
@@ -1505,7 +1504,7 @@ function hasSendableMessageContent(message) {
|
|
|
1505
1504
|
}
|
|
1506
1505
|
function readSessionActivityState(metadata) {
|
|
1507
1506
|
const preview = metadata?.[SESSION_ACTIVITY_PREVIEW_METADATA_KEY];
|
|
1508
|
-
return isRecord$
|
|
1507
|
+
return isRecord$18(preview) && typeof preview.state === "string" ? preview.state : null;
|
|
1509
1508
|
}
|
|
1510
1509
|
var AgentRunSessionCommandManager = class {
|
|
1511
1510
|
pendingCommands = /* @__PURE__ */ new Map();
|
|
@@ -2186,7 +2185,7 @@ var AgentRuntimeRunObserverService = class {
|
|
|
2186
2185
|
};
|
|
2187
2186
|
//#endregion
|
|
2188
2187
|
//#region src/utils/agent-run-trigger.utils.ts
|
|
2189
|
-
function isRecord$
|
|
2188
|
+
function isRecord$17(value) {
|
|
2190
2189
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2191
2190
|
}
|
|
2192
2191
|
function readOptionalString$12(value) {
|
|
@@ -2194,7 +2193,7 @@ function readOptionalString$12(value) {
|
|
|
2194
2193
|
}
|
|
2195
2194
|
function readSourceRunSpec(message) {
|
|
2196
2195
|
const value = message.metadata?.[AGENT_RUN_MESSAGE_RUN_SPEC_METADATA_KEY];
|
|
2197
|
-
return isRecord$
|
|
2196
|
+
return isRecord$17(value) ? value : {};
|
|
2198
2197
|
}
|
|
2199
2198
|
const SOURCE_CONTEXT_KEYS = [
|
|
2200
2199
|
"channel",
|
|
@@ -2699,7 +2698,7 @@ const BUILTIN_RUNTIME_PRESENTATION = {
|
|
|
2699
2698
|
}
|
|
2700
2699
|
}
|
|
2701
2700
|
};
|
|
2702
|
-
function readString$
|
|
2701
|
+
function readString$10(value) {
|
|
2703
2702
|
if (typeof value !== "string") return;
|
|
2704
2703
|
return value.trim() || void 0;
|
|
2705
2704
|
}
|
|
@@ -2708,7 +2707,7 @@ function readRecord$3(value) {
|
|
|
2708
2707
|
return value;
|
|
2709
2708
|
}
|
|
2710
2709
|
function resolveBuiltinRuntimePresentation(value) {
|
|
2711
|
-
const normalized = readString$
|
|
2710
|
+
const normalized = readString$10(value)?.toLowerCase();
|
|
2712
2711
|
if (!normalized) return null;
|
|
2713
2712
|
if (!(normalized in BUILTIN_RUNTIME_PRESENTATION)) return null;
|
|
2714
2713
|
return BUILTIN_RUNTIME_PRESENTATION[normalized] ?? null;
|
|
@@ -2729,13 +2728,13 @@ function resolveAgentRuntimeEntries(params) {
|
|
|
2729
2728
|
entries.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, buildNativeRuntimeEntry(params.config));
|
|
2730
2729
|
for (const [rawId, rawEntry] of Object.entries(params.config.agents.runtimes.entries ?? {})) {
|
|
2731
2730
|
const id = rawId.trim().toLowerCase();
|
|
2732
|
-
const type = readString$
|
|
2731
|
+
const type = readString$10(rawEntry.type)?.toLowerCase();
|
|
2733
2732
|
if (!id || !type) continue;
|
|
2734
2733
|
const explicitIcon = normalizeAgentRuntimeSessionTypeIcon(rawEntry.icon);
|
|
2735
2734
|
const builtinPresentation = resolveBuiltinRuntimePresentation(id) ?? resolveBuiltinRuntimePresentation(type);
|
|
2736
2735
|
entries.set(id, {
|
|
2737
2736
|
id,
|
|
2738
|
-
label: readString$
|
|
2737
|
+
label: readString$10(rawEntry.label) ?? builtinPresentation?.label ?? id,
|
|
2739
2738
|
...explicitIcon ?? builtinPresentation?.icon ? { icon: explicitIcon ?? builtinPresentation?.icon } : {},
|
|
2740
2739
|
type,
|
|
2741
2740
|
enabled: rawEntry.enabled !== false,
|
|
@@ -3535,6 +3534,570 @@ var AppPackageOperationManager = class {
|
|
|
3535
3534
|
isMissingFileError = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
3536
3535
|
};
|
|
3537
3536
|
//#endregion
|
|
3537
|
+
//#region src/types/app-package.types.ts
|
|
3538
|
+
var AppPackageError = class extends Error {
|
|
3539
|
+
constructor(code, message) {
|
|
3540
|
+
super(message);
|
|
3541
|
+
this.code = code;
|
|
3542
|
+
this.name = "AppPackageError";
|
|
3543
|
+
}
|
|
3544
|
+
};
|
|
3545
|
+
function isAppPackageError(error) {
|
|
3546
|
+
return error instanceof AppPackageError;
|
|
3547
|
+
}
|
|
3548
|
+
//#endregion
|
|
3549
|
+
//#region src/utils/service-app-manifest.utils.ts
|
|
3550
|
+
const SERVICE_APP_ID_PATTERN$1 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
3551
|
+
const SERVICE_ACTION_RISKS = new Set([
|
|
3552
|
+
"read",
|
|
3553
|
+
"write",
|
|
3554
|
+
"external",
|
|
3555
|
+
"dangerous"
|
|
3556
|
+
]);
|
|
3557
|
+
const SERVICE_APP_MANIFEST_FILE_NAME = "service-app.json";
|
|
3558
|
+
function getServiceAppManifestPath(dirPath) {
|
|
3559
|
+
return join(dirPath, SERVICE_APP_MANIFEST_FILE_NAME);
|
|
3560
|
+
}
|
|
3561
|
+
async function readServiceAppManifest(dirPath, options) {
|
|
3562
|
+
return parseServiceAppManifest(await readFile(getServiceAppManifestPath(dirPath), "utf8"), options);
|
|
3563
|
+
}
|
|
3564
|
+
function parseServiceAppManifest(raw, options = {}) {
|
|
3565
|
+
let parsed;
|
|
3566
|
+
try {
|
|
3567
|
+
parsed = JSON.parse(raw);
|
|
3568
|
+
} catch (error) {
|
|
3569
|
+
throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
3570
|
+
}
|
|
3571
|
+
if (!isRecord$16(parsed)) throw new Error("service-app.json must contain an object.");
|
|
3572
|
+
const id = readRequiredString$8(parsed, "id");
|
|
3573
|
+
if (!SERVICE_APP_ID_PATTERN$1.test(id)) throw new Error("service app id must be kebab-case.");
|
|
3574
|
+
const protocol = readOptionalString$11(parsed, "protocol") ?? "mcp";
|
|
3575
|
+
if (protocol !== "mcp" && protocol !== "wasi-component") throw new Error("service app protocol must be mcp or wasi-component.");
|
|
3576
|
+
const launch = protocol === "mcp" ? new AppServiceLaunchService(options.platformTargetService).resolve(parsed, options.target) : void 0;
|
|
3577
|
+
const componentEntry = protocol === "wasi-component" ? readPortableComponentEntry(parsed) : void 0;
|
|
3578
|
+
const lifecycle = readServiceAppLifecycle(parsed.lifecycle);
|
|
3579
|
+
if (lifecycle.mode !== "action" && protocol !== "wasi-component") throw new Error(`${lifecycle.mode} service app lifecycle requires wasi-component protocol.`);
|
|
3580
|
+
const provides = readServiceAppProvides(parsed.provides);
|
|
3581
|
+
if (provides && lifecycle.mode !== "provider") throw new Error("service app provides requires provider lifecycle.");
|
|
3582
|
+
return {
|
|
3583
|
+
id,
|
|
3584
|
+
title: readRequiredString$8(parsed, "title"),
|
|
3585
|
+
description: readOptionalString$11(parsed, "description"),
|
|
3586
|
+
enabled: readOptionalBoolean$2(parsed, "enabled") ?? true,
|
|
3587
|
+
protocol,
|
|
3588
|
+
command: launch?.command,
|
|
3589
|
+
args: launch?.args,
|
|
3590
|
+
componentEntry,
|
|
3591
|
+
providerIds: readProviderIds(parsed.providers),
|
|
3592
|
+
lifecycle,
|
|
3593
|
+
requires: readServiceAppRequirements(parsed.requires),
|
|
3594
|
+
provides,
|
|
3595
|
+
actions: readManifestActions(parsed.actions)
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
function readServiceAppProvides(value) {
|
|
3599
|
+
if (value === void 0) return void 0;
|
|
3600
|
+
if (!isRecord$16(value)) throw new Error("service app provides must be an object.");
|
|
3601
|
+
if (value.capabilities === void 0) return void 0;
|
|
3602
|
+
if (!Array.isArray(value.capabilities)) throw new Error("service app provides.capabilities must be an array.");
|
|
3603
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3604
|
+
const capabilities = value.capabilities.map((entry, index) => {
|
|
3605
|
+
if (!isRecord$16(entry)) throw new Error(`service app provides.capabilities[${index}] must be an object.`);
|
|
3606
|
+
const id = readRequirementIdentifier(entry, "id", `provides.capabilities[${index}].id`);
|
|
3607
|
+
const version = readOptionalString$11(entry, "version");
|
|
3608
|
+
if (!version) throw new Error(`service app provides.capabilities[${index}].version is required.`);
|
|
3609
|
+
const key = `${id}@${version}`;
|
|
3610
|
+
if (seen.has(key)) throw new Error(`service app provides.capabilities contains duplicate ${key}.`);
|
|
3611
|
+
seen.add(key);
|
|
3612
|
+
return {
|
|
3613
|
+
id,
|
|
3614
|
+
version,
|
|
3615
|
+
resourceTypes: readCapabilityResourceTypes(entry.resourceTypes, index)
|
|
3616
|
+
};
|
|
3617
|
+
});
|
|
3618
|
+
return capabilities.length > 0 ? { capabilities } : void 0;
|
|
3619
|
+
}
|
|
3620
|
+
function readCapabilityResourceTypes(value, index) {
|
|
3621
|
+
if (value === void 0) return void 0;
|
|
3622
|
+
if (!Array.isArray(value)) throw new Error(`service app provides.capabilities[${index}].resourceTypes must be an array.`);
|
|
3623
|
+
const resourceTypes = value.map((entry, resourceIndex) => {
|
|
3624
|
+
if (typeof entry !== "string" || !entry.trim()) throw new Error(`service app provides.capabilities[${index}].resourceTypes[${resourceIndex}] must be a lowercase identifier.`);
|
|
3625
|
+
return entry.trim();
|
|
3626
|
+
});
|
|
3627
|
+
if (resourceTypes.some((entry) => !/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(entry))) throw new Error(`service app provides.capabilities[${index}].resourceTypes must contain lowercase identifiers.`);
|
|
3628
|
+
return Array.from(new Set(resourceTypes));
|
|
3629
|
+
}
|
|
3630
|
+
function readServiceAppRequirements(value) {
|
|
3631
|
+
if (value === void 0) return void 0;
|
|
3632
|
+
if (!isRecord$16(value)) throw new Error("service app requires must be an object.");
|
|
3633
|
+
const capabilities = readCapabilityRequirements(value.capabilities);
|
|
3634
|
+
const resources = readResourceRequirements(value.resources);
|
|
3635
|
+
return capabilities || resources ? {
|
|
3636
|
+
capabilities,
|
|
3637
|
+
resources
|
|
3638
|
+
} : void 0;
|
|
3639
|
+
}
|
|
3640
|
+
function readCapabilityRequirements(value) {
|
|
3641
|
+
if (value === void 0) return void 0;
|
|
3642
|
+
if (!Array.isArray(value)) throw new Error("service app requires.capabilities must be an array.");
|
|
3643
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3644
|
+
return value.map((entry, index) => {
|
|
3645
|
+
if (!isRecord$16(entry)) throw new Error(`service app requires.capabilities[${index}] must be an object.`);
|
|
3646
|
+
const id = readRequirementIdentifier(entry, "id", `requires.capabilities[${index}].id`);
|
|
3647
|
+
const version = readOptionalString$11(entry, "version");
|
|
3648
|
+
const key = `${id}@${version ?? "*"}`;
|
|
3649
|
+
if (seen.has(key)) throw new Error(`service app requires.capabilities contains duplicate ${key}.`);
|
|
3650
|
+
seen.add(key);
|
|
3651
|
+
return {
|
|
3652
|
+
id,
|
|
3653
|
+
version,
|
|
3654
|
+
title: readOptionalString$11(entry, "title"),
|
|
3655
|
+
description: readOptionalString$11(entry, "description"),
|
|
3656
|
+
remediation: readExternalRemediation(entry.remediation, `requires.capabilities[${index}]`)
|
|
3657
|
+
};
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
function readResourceRequirements(value) {
|
|
3661
|
+
if (value === void 0) return void 0;
|
|
3662
|
+
if (!Array.isArray(value)) throw new Error("service app requires.resources must be an array.");
|
|
3663
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3664
|
+
return value.map((entry, index) => {
|
|
3665
|
+
if (!isRecord$16(entry)) throw new Error(`service app requires.resources[${index}] must be an object.`);
|
|
3666
|
+
const binding = readRequirementIdentifier(entry, "binding", `requires.resources[${index}].binding`);
|
|
3667
|
+
if (seen.has(binding)) throw new Error(`service app requires.resources contains duplicate binding ${binding}.`);
|
|
3668
|
+
seen.add(binding);
|
|
3669
|
+
return {
|
|
3670
|
+
binding,
|
|
3671
|
+
type: readRequirementIdentifier(entry, "type", `requires.resources[${index}].type`),
|
|
3672
|
+
required: readOptionalBoolean$2(entry, "required") ?? true,
|
|
3673
|
+
title: readOptionalString$11(entry, "title"),
|
|
3674
|
+
description: readOptionalString$11(entry, "description"),
|
|
3675
|
+
remediation: readExternalRemediation(entry.remediation, `requires.resources[${index}]`)
|
|
3676
|
+
};
|
|
3677
|
+
});
|
|
3678
|
+
}
|
|
3679
|
+
function readRequirementIdentifier(record, key, fieldName) {
|
|
3680
|
+
const value = readOptionalString$11(record, key);
|
|
3681
|
+
if (!value || !/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(value)) throw new Error(`service app ${fieldName} must be a lowercase identifier.`);
|
|
3682
|
+
return value;
|
|
3683
|
+
}
|
|
3684
|
+
function readExternalRemediation(value, fieldPrefix) {
|
|
3685
|
+
if (value === void 0) return void 0;
|
|
3686
|
+
if (!isRecord$16(value) || value.kind !== "agent-setup") throw new Error(`service app ${fieldPrefix}.remediation.kind must be agent-setup.`);
|
|
3687
|
+
const summary = readOptionalString$11(value, "summary");
|
|
3688
|
+
if (!summary) throw new Error(`service app ${fieldPrefix}.remediation.summary is required.`);
|
|
3689
|
+
return {
|
|
3690
|
+
kind: "agent-setup",
|
|
3691
|
+
summary,
|
|
3692
|
+
requiresUserAction: readOptionalBoolean$2(value, "requiresUserAction")
|
|
3693
|
+
};
|
|
3694
|
+
}
|
|
3695
|
+
function readServiceAppLifecycle(value) {
|
|
3696
|
+
if (value === void 0) return { mode: "action" };
|
|
3697
|
+
if (!isRecord$16(value)) throw new Error("service app lifecycle must be an object.");
|
|
3698
|
+
const mode = readOptionalString$11(value, "mode") ?? "action";
|
|
3699
|
+
if (mode === "action") return { mode };
|
|
3700
|
+
if (mode === "provider") return { mode };
|
|
3701
|
+
if (mode !== "resident") throw new Error("service app lifecycle.mode must be action, resident or provider.");
|
|
3702
|
+
const eventIntervalMs = readOptionalNumber$1(value, "eventIntervalMs");
|
|
3703
|
+
if (eventIntervalMs === void 0 || !Number.isInteger(eventIntervalMs) || eventIntervalMs < 250 || eventIntervalMs > 6e4) throw new Error("resident service app lifecycle.eventIntervalMs must be an integer between 250 and 60000.");
|
|
3704
|
+
return {
|
|
3705
|
+
mode,
|
|
3706
|
+
eventIntervalMs
|
|
3707
|
+
};
|
|
3708
|
+
}
|
|
3709
|
+
function readProviderIds(value) {
|
|
3710
|
+
if (value === void 0) return [];
|
|
3711
|
+
if (!Array.isArray(value)) throw new Error("service app providers must be an array.");
|
|
3712
|
+
const providerIds = value.map((entry) => {
|
|
3713
|
+
if (typeof entry !== "string" || !SERVICE_APP_ID_PATTERN$1.test(entry.trim())) throw new Error("service app providers must contain kebab-case service app ids.");
|
|
3714
|
+
return entry.trim();
|
|
3715
|
+
});
|
|
3716
|
+
return Array.from(new Set(providerIds));
|
|
3717
|
+
}
|
|
3718
|
+
function readPortableComponentEntry(record) {
|
|
3719
|
+
const component = record.component;
|
|
3720
|
+
if (!isRecord$16(component)) throw new Error("service app component is required for wasi-component.");
|
|
3721
|
+
const entry = readRequiredString$8(component, "entry").replace(/\\/g, "/");
|
|
3722
|
+
if (path.isAbsolute(entry) || entry.includes("\0") || entry.split("/").includes("..")) throw new Error("service app component.entry must be a package-relative path.");
|
|
3723
|
+
if (!entry.endsWith(".wasm")) throw new Error("service app component.entry must reference a .wasm file.");
|
|
3724
|
+
return entry;
|
|
3725
|
+
}
|
|
3726
|
+
function readManifestActions(value) {
|
|
3727
|
+
if (value === void 0) throw new Error("service app actions are required.");
|
|
3728
|
+
if (!isRecord$16(value)) throw new Error("service app actions must be an object.");
|
|
3729
|
+
if (Object.keys(value).length === 0) throw new Error("service app actions cannot be empty.");
|
|
3730
|
+
const actions = {};
|
|
3731
|
+
for (const [name, action] of Object.entries(value)) {
|
|
3732
|
+
if (!name.trim()) throw new Error("service app action name cannot be empty.");
|
|
3733
|
+
if (!isRecord$16(action)) throw new Error(`service app action ${name} must be an object.`);
|
|
3734
|
+
const risk = readOptionalString$11(action, "risk");
|
|
3735
|
+
if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
|
|
3736
|
+
const inputSchema = action.inputSchema;
|
|
3737
|
+
if (inputSchema !== void 0 && !isRecord$16(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
|
|
3738
|
+
const timeoutMs = readOptionalNumber$1(action, "timeoutMs");
|
|
3739
|
+
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.`);
|
|
3740
|
+
actions[name] = {
|
|
3741
|
+
risk,
|
|
3742
|
+
title: readOptionalString$11(action, "title"),
|
|
3743
|
+
description: readOptionalString$11(action, "description"),
|
|
3744
|
+
inputSchema,
|
|
3745
|
+
timeoutMs
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3748
|
+
return actions;
|
|
3749
|
+
}
|
|
3750
|
+
function readRequiredString$8(record, key) {
|
|
3751
|
+
const value = readOptionalString$11(record, key);
|
|
3752
|
+
if (!value) throw new Error(`service app ${key} is required.`);
|
|
3753
|
+
return value;
|
|
3754
|
+
}
|
|
3755
|
+
function readOptionalString$11(record, key) {
|
|
3756
|
+
return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
|
|
3757
|
+
}
|
|
3758
|
+
function readOptionalBoolean$2(record, key) {
|
|
3759
|
+
if (record[key] === void 0) return;
|
|
3760
|
+
if (typeof record[key] !== "boolean") throw new Error(`service app ${key} must be boolean.`);
|
|
3761
|
+
return record[key];
|
|
3762
|
+
}
|
|
3763
|
+
function readOptionalNumber$1(record, key) {
|
|
3764
|
+
if (record[key] === void 0) return;
|
|
3765
|
+
if (typeof record[key] !== "number") throw new Error(`service app ${key} must be number.`);
|
|
3766
|
+
return record[key];
|
|
3767
|
+
}
|
|
3768
|
+
function isRecord$16(value) {
|
|
3769
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3770
|
+
}
|
|
3771
|
+
//#endregion
|
|
3772
|
+
//#region src/services/app-package-dependency.service.ts
|
|
3773
|
+
const STORE_FILE_NAME = "dependencies.json";
|
|
3774
|
+
const LOCK_FILE_NAME = ".dependencies.lock";
|
|
3775
|
+
const IDENTIFIER_PATTERN = /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/;
|
|
3776
|
+
/**
|
|
3777
|
+
* Owns non-sensitive Consumer-to-Provider bindings. The Provider catalog stays
|
|
3778
|
+
* outside this service, so activation and runtime ownership remain unchanged.
|
|
3779
|
+
*/
|
|
3780
|
+
var AppPackageDependencyService = class {
|
|
3781
|
+
fileLockService = new FileLockService();
|
|
3782
|
+
inspect = async (params) => {
|
|
3783
|
+
const [requirements, bindings] = await Promise.all([this.readRequirements(params.target.components), this.readBindings(params.target.storage)]);
|
|
3784
|
+
return this.toView(requirements, bindings, params.providers);
|
|
3785
|
+
};
|
|
3786
|
+
resolveStoredProviderIds = async (target) => {
|
|
3787
|
+
const [requirements, bindings] = await Promise.all([this.readRequirements(target.components), this.readBindings(target.storage)]);
|
|
3788
|
+
const result = {};
|
|
3789
|
+
for (const requirement of requirements) {
|
|
3790
|
+
const binding = this.findBinding(bindings, requirement);
|
|
3791
|
+
if (!binding) continue;
|
|
3792
|
+
const providerIds = result[requirement.componentId] ?? [];
|
|
3793
|
+
if (!providerIds.includes(binding.providerId)) providerIds.push(binding.providerId);
|
|
3794
|
+
result[requirement.componentId] = providerIds;
|
|
3795
|
+
}
|
|
3796
|
+
return result;
|
|
3797
|
+
};
|
|
3798
|
+
listBindings = async (target) => await this.readBindings(target.storage);
|
|
3799
|
+
setup = async (params) => await this.update(params, (requirements, bindings) => {
|
|
3800
|
+
const updated = [...bindings];
|
|
3801
|
+
for (const requirement of requirements) {
|
|
3802
|
+
if (this.findBinding(updated, requirement)) continue;
|
|
3803
|
+
const candidates = this.findCandidates(requirement, params.providers);
|
|
3804
|
+
if (candidates.length === 1) updated.push(this.toBinding(requirement, candidates[0].providerId));
|
|
3805
|
+
}
|
|
3806
|
+
return updated;
|
|
3807
|
+
});
|
|
3808
|
+
bind = async (params) => await this.update(params, (requirements, bindings) => {
|
|
3809
|
+
const requirement = this.requireRequirement(requirements, params.input);
|
|
3810
|
+
const provider = params.providers.find((entry) => entry.providerId === params.input.providerId);
|
|
3811
|
+
if (!provider || !this.providerMatches(requirement, provider)) throw new AppPackageError("APP_PACKAGE_NOT_READY", `Provider ${params.input.providerId} cannot satisfy ${this.requirementKey(requirement)}.`);
|
|
3812
|
+
return [...bindings.filter((entry) => !this.isBindingForRequirement(entry, requirement)), this.toBinding(requirement, provider.providerId)];
|
|
3813
|
+
});
|
|
3814
|
+
unbind = async (params) => await this.update(params, (requirements, bindings) => {
|
|
3815
|
+
const requirement = this.requireRequirement(requirements, params.input);
|
|
3816
|
+
return bindings.filter((entry) => !this.isBindingForRequirement(entry, requirement));
|
|
3817
|
+
});
|
|
3818
|
+
update = async (params, mutate) => await this.fileLockService.withLock(this.lockPath(params.target.storage), async () => {
|
|
3819
|
+
const [requirements, bindings] = await Promise.all([this.readRequirements(params.target.components), this.readBindings(params.target.storage)]);
|
|
3820
|
+
const updated = this.normalizeBindings(mutate(requirements, bindings));
|
|
3821
|
+
await this.writeBindings(params.target.storage, updated);
|
|
3822
|
+
return this.toView(requirements, updated, params.providers);
|
|
3823
|
+
});
|
|
3824
|
+
readRequirements = async (components) => (await Promise.all(components.filter((component) => component.kind === "service").map(async (component) => this.readComponentRequirements(component)))).flat();
|
|
3825
|
+
readComponentRequirements = async (component) => {
|
|
3826
|
+
const manifest = await readServiceAppManifest(component.componentDirectory);
|
|
3827
|
+
return this.toRequirements(component.id, manifest);
|
|
3828
|
+
};
|
|
3829
|
+
toRequirements = (componentId, manifest) => [...(manifest.requires?.capabilities ?? []).map((requirement) => ({
|
|
3830
|
+
componentId,
|
|
3831
|
+
kind: "capability",
|
|
3832
|
+
id: requirement.version ? `${requirement.id}@${requirement.version}` : requirement.id,
|
|
3833
|
+
title: requirement.title ?? requirement.id,
|
|
3834
|
+
description: requirement.description,
|
|
3835
|
+
remediation: requirement.remediation,
|
|
3836
|
+
capabilityId: requirement.id,
|
|
3837
|
+
capabilityVersion: requirement.version
|
|
3838
|
+
})), ...(manifest.requires?.resources ?? []).filter((requirement) => requirement.required !== false).map((requirement) => ({
|
|
3839
|
+
componentId,
|
|
3840
|
+
kind: "resource",
|
|
3841
|
+
id: requirement.binding,
|
|
3842
|
+
title: requirement.title ?? requirement.type,
|
|
3843
|
+
description: requirement.description,
|
|
3844
|
+
remediation: requirement.remediation,
|
|
3845
|
+
resourceType: requirement.type
|
|
3846
|
+
}))];
|
|
3847
|
+
toView = (requirements, bindings, providers) => {
|
|
3848
|
+
const candidates = requirements.map((requirement) => ({
|
|
3849
|
+
requirement: this.toReadinessRequirement(requirement),
|
|
3850
|
+
providers: this.findCandidates(requirement, providers)
|
|
3851
|
+
}));
|
|
3852
|
+
const readinessRequirements = candidates.filter(({ requirement, providers: candidatesForRequirement }) => {
|
|
3853
|
+
const source = this.toRequirement(requirement);
|
|
3854
|
+
const binding = this.findBinding(bindings, source);
|
|
3855
|
+
return !binding || !candidatesForRequirement.some((provider) => provider.providerId === binding.providerId);
|
|
3856
|
+
}).map(({ requirement }) => requirement);
|
|
3857
|
+
return {
|
|
3858
|
+
readiness: this.toReadiness(readinessRequirements),
|
|
3859
|
+
bindings,
|
|
3860
|
+
candidates,
|
|
3861
|
+
resolvedProviderIds: this.toResolvedProviderIds(requirements, bindings, providers)
|
|
3862
|
+
};
|
|
3863
|
+
};
|
|
3864
|
+
toReadiness = (requirements) => ({
|
|
3865
|
+
status: requirements.some((requirement) => requirement.kind === "capability") ? "needs-capability" : requirements.some((requirement) => requirement.kind === "configuration") ? "needs-configuration" : "ready",
|
|
3866
|
+
requirements
|
|
3867
|
+
});
|
|
3868
|
+
toResolvedProviderIds = (requirements, bindings, providers) => {
|
|
3869
|
+
const availableProviderIds = new Set(providers.map((provider) => provider.providerId));
|
|
3870
|
+
const result = {};
|
|
3871
|
+
for (const requirement of requirements) {
|
|
3872
|
+
const binding = this.findBinding(bindings, requirement);
|
|
3873
|
+
if (!binding || !availableProviderIds.has(binding.providerId)) continue;
|
|
3874
|
+
const providerIds = result[requirement.componentId] ?? [];
|
|
3875
|
+
if (!providerIds.includes(binding.providerId)) providerIds.push(binding.providerId);
|
|
3876
|
+
result[requirement.componentId] = providerIds;
|
|
3877
|
+
}
|
|
3878
|
+
return result;
|
|
3879
|
+
};
|
|
3880
|
+
findCandidates = (requirement, providers) => providers.filter((provider) => this.providerMatches(requirement, provider));
|
|
3881
|
+
providerMatches = (requirement, provider) => provider.capabilities.some((capability) => {
|
|
3882
|
+
if (requirement.kind === "capability") return capability.id === requirement.capabilityId && (!requirement.capabilityVersion || capability.version === requirement.capabilityVersion);
|
|
3883
|
+
return capability.resourceTypes?.includes(requirement.resourceType) ?? false;
|
|
3884
|
+
});
|
|
3885
|
+
requireRequirement = (requirements, input) => {
|
|
3886
|
+
const requirement = requirements.find((entry) => entry.componentId === input.componentId && entry.kind === input.requirementKind && entry.id === input.requirementId);
|
|
3887
|
+
if (!requirement) throw new AppPackageError("APP_PACKAGE_NOT_FOUND", `Dependency ${input.componentId}/${input.requirementKind}/${input.requirementId} was not declared by this App.`);
|
|
3888
|
+
return requirement;
|
|
3889
|
+
};
|
|
3890
|
+
toBinding = (requirement, providerId) => ({
|
|
3891
|
+
componentId: requirement.componentId,
|
|
3892
|
+
requirementKind: requirement.kind,
|
|
3893
|
+
requirementId: requirement.id,
|
|
3894
|
+
providerId
|
|
3895
|
+
});
|
|
3896
|
+
findBinding = (bindings, requirement) => bindings.find((entry) => this.isBindingForRequirement(entry, requirement));
|
|
3897
|
+
isBindingForRequirement = (binding, requirement) => binding.componentId === requirement.componentId && binding.requirementKind === requirement.kind && binding.requirementId === requirement.id;
|
|
3898
|
+
requirementKey = (requirement) => `${requirement.componentId}/${requirement.kind}/${requirement.id}`;
|
|
3899
|
+
toRequirement = (requirement) => ({
|
|
3900
|
+
componentId: requirement.componentId,
|
|
3901
|
+
kind: requirement.kind === "capability" ? "capability" : "resource",
|
|
3902
|
+
id: requirement.id,
|
|
3903
|
+
title: requirement.title,
|
|
3904
|
+
description: requirement.description,
|
|
3905
|
+
remediation: requirement.remediation
|
|
3906
|
+
});
|
|
3907
|
+
toReadinessRequirement = (requirement) => ({
|
|
3908
|
+
componentId: requirement.componentId,
|
|
3909
|
+
kind: requirement.kind === "capability" ? "capability" : "configuration",
|
|
3910
|
+
id: requirement.id,
|
|
3911
|
+
title: requirement.title,
|
|
3912
|
+
description: requirement.description,
|
|
3913
|
+
remediation: requirement.remediation
|
|
3914
|
+
});
|
|
3915
|
+
readBindings = async (storage) => {
|
|
3916
|
+
try {
|
|
3917
|
+
const parsed = JSON.parse(await readFile(this.storePath(storage), "utf8"));
|
|
3918
|
+
if (!this.isStore(parsed)) throw new Error("schema");
|
|
3919
|
+
return this.normalizeBindings(parsed.bindings);
|
|
3920
|
+
} catch (error) {
|
|
3921
|
+
if (this.isMissingFileError(error)) return [];
|
|
3922
|
+
throw new AppPackageError("APP_PACKAGE_OPERATION_FAILED", `App dependency bindings are invalid: ${error instanceof Error ? error.message : String(error)}.`);
|
|
3923
|
+
}
|
|
3924
|
+
};
|
|
3925
|
+
writeBindings = async (storage, bindings) => {
|
|
3926
|
+
await mkdir(storage.configDirectory, {
|
|
3927
|
+
recursive: true,
|
|
3928
|
+
mode: 448
|
|
3929
|
+
});
|
|
3930
|
+
const filePath = this.storePath(storage);
|
|
3931
|
+
const stagedPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
3932
|
+
await writeFile(stagedPath, `${JSON.stringify({
|
|
3933
|
+
schemaVersion: 1,
|
|
3934
|
+
bindings
|
|
3935
|
+
}, null, 2)}\n`, {
|
|
3936
|
+
encoding: "utf8",
|
|
3937
|
+
mode: 384
|
|
3938
|
+
});
|
|
3939
|
+
await rename(stagedPath, filePath);
|
|
3940
|
+
await chmod(filePath, 384);
|
|
3941
|
+
};
|
|
3942
|
+
normalizeBindings = (bindings) => {
|
|
3943
|
+
const unique = /* @__PURE__ */ new Map();
|
|
3944
|
+
for (const binding of bindings) {
|
|
3945
|
+
if (!this.isBinding(binding)) throw new Error("invalid binding");
|
|
3946
|
+
unique.set(`${binding.componentId}/${binding.requirementKind}/${binding.requirementId}`, binding);
|
|
3947
|
+
}
|
|
3948
|
+
return Array.from(unique.values()).sort((left, right) => this.bindingKey(left).localeCompare(this.bindingKey(right)));
|
|
3949
|
+
};
|
|
3950
|
+
bindingKey = (binding) => `${binding.componentId}/${binding.requirementKind}/${binding.requirementId}`;
|
|
3951
|
+
isStore = (value) => Boolean(value) && typeof value === "object" && value.schemaVersion === 1 && Array.isArray(value.bindings);
|
|
3952
|
+
isBinding = (value) => Boolean(value) && typeof value === "object" && IDENTIFIER_PATTERN.test(value.componentId) && (value.requirementKind === "capability" || value.requirementKind === "resource") && typeof value.requirementId === "string" && value.requirementId.length > 0 && IDENTIFIER_PATTERN.test(value.providerId);
|
|
3953
|
+
storePath = (storage) => path.join(storage.configDirectory, STORE_FILE_NAME);
|
|
3954
|
+
lockPath = (storage) => path.join(storage.configDirectory, LOCK_FILE_NAME);
|
|
3955
|
+
isMissingFileError = (error) => typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
3956
|
+
};
|
|
3957
|
+
//#endregion
|
|
3958
|
+
//#region src/services/app-package-dependency-coordinator.service.ts
|
|
3959
|
+
/**
|
|
3960
|
+
* Bridges the package lifecycle owner to dependency persistence. It keeps all
|
|
3961
|
+
* Provider queries and binding mutations on the one dependency service path.
|
|
3962
|
+
*/
|
|
3963
|
+
var AppPackageDependencyCoordinator = class {
|
|
3964
|
+
dependencyService;
|
|
3965
|
+
constructor(params) {
|
|
3966
|
+
this.params = params;
|
|
3967
|
+
this.dependencyService = params.dependencyService ?? new AppPackageDependencyService();
|
|
3968
|
+
}
|
|
3969
|
+
inspect = async (appId) => await this.inspectTarget(await this.getTarget(appId));
|
|
3970
|
+
verify = async (appId) => await this.inspect(appId);
|
|
3971
|
+
setup = async (appId) => await this.params.installationService.withAppOperation(appId, async () => {
|
|
3972
|
+
const info = await this.getMutableTargetInfo(appId);
|
|
3973
|
+
return await this.dependencyService.setup({
|
|
3974
|
+
target: this.targetForInfo(info),
|
|
3975
|
+
providers: await this.params.listCapabilityProviders()
|
|
3976
|
+
});
|
|
3977
|
+
});
|
|
3978
|
+
bind = async (appId, input) => await this.params.installationService.withAppOperation(appId, async () => {
|
|
3979
|
+
const info = await this.getMutableTargetInfo(appId);
|
|
3980
|
+
return await this.dependencyService.bind({
|
|
3981
|
+
target: this.targetForInfo(info),
|
|
3982
|
+
providers: await this.params.listCapabilityProviders(),
|
|
3983
|
+
input
|
|
3984
|
+
});
|
|
3985
|
+
});
|
|
3986
|
+
unbind = async (appId, input) => await this.params.installationService.withAppOperation(appId, async () => {
|
|
3987
|
+
const info = await this.getMutableTargetInfo(appId);
|
|
3988
|
+
return await this.dependencyService.unbind({
|
|
3989
|
+
target: this.targetForInfo(info),
|
|
3990
|
+
providers: await this.params.listCapabilityProviders(),
|
|
3991
|
+
input
|
|
3992
|
+
});
|
|
3993
|
+
});
|
|
3994
|
+
inspectTarget = async (target, providers) => await this.dependencyService.inspect({
|
|
3995
|
+
target,
|
|
3996
|
+
providers: providers ?? await this.params.listCapabilityProviders()
|
|
3997
|
+
});
|
|
3998
|
+
resolveStoredProviderIds = async (target) => await this.dependencyService.resolveStoredProviderIds(target);
|
|
3999
|
+
listBindings = async (target) => await this.dependencyService.listBindings(target);
|
|
4000
|
+
listActiveComponentSourcesWithDiagnostics = async () => {
|
|
4001
|
+
const records = await this.params.registryService.listApps();
|
|
4002
|
+
const results = await Promise.all(records.filter((record) => record.enabled).map(async (record) => {
|
|
4003
|
+
try {
|
|
4004
|
+
await this.params.installationService.assertVersionIntegrity(record.appId, record.activeVersion);
|
|
4005
|
+
const version = record.installedVersions[record.activeVersion];
|
|
4006
|
+
if (!version || version.manifestSchemaVersion !== 2) return { sources: [] };
|
|
4007
|
+
const target = this.target({
|
|
4008
|
+
appId: record.appId,
|
|
4009
|
+
storage: record.defaultInstance.storage,
|
|
4010
|
+
components: version.components ?? []
|
|
4011
|
+
});
|
|
4012
|
+
const resolvedProviderIds = await this.resolveStoredProviderIds(target);
|
|
4013
|
+
return { sources: (version.components ?? []).map((component) => ({
|
|
4014
|
+
kind: component.kind,
|
|
4015
|
+
id: component.id,
|
|
4016
|
+
packageId: record.appId,
|
|
4017
|
+
packageVersion: record.activeVersion,
|
|
4018
|
+
sourcePath: component.componentDirectory,
|
|
4019
|
+
manifestPath: component.manifestPath,
|
|
4020
|
+
dataDirectory: record.dataDirectory,
|
|
4021
|
+
instanceId: record.defaultInstance.id,
|
|
4022
|
+
storage: record.defaultInstance.storage,
|
|
4023
|
+
resolvedProviderIds: resolvedProviderIds[component.id],
|
|
4024
|
+
...this.params.resolveSecurity(version, record.appId)
|
|
4025
|
+
})) };
|
|
4026
|
+
} catch (error) {
|
|
4027
|
+
return {
|
|
4028
|
+
sources: [],
|
|
4029
|
+
unavailablePackage: {
|
|
4030
|
+
appId: record.appId,
|
|
4031
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4032
|
+
}
|
|
4033
|
+
};
|
|
4034
|
+
}
|
|
4035
|
+
}));
|
|
4036
|
+
return {
|
|
4037
|
+
sources: results.flatMap((result) => result.sources),
|
|
4038
|
+
unavailablePackages: results.flatMap((result) => result.unavailablePackage ?? [])
|
|
4039
|
+
};
|
|
4040
|
+
};
|
|
4041
|
+
assertNoEnabledDependents = async (provider) => {
|
|
4042
|
+
const providerIds = new Set(provider.components.filter((component) => component.kind === "service").map((component) => component.id));
|
|
4043
|
+
if (providerIds.size === 0) return;
|
|
4044
|
+
const records = await this.params.registryService.listApps();
|
|
4045
|
+
const dependentAppIds = (await Promise.all(records.filter((record) => record.enabled && record.appId !== provider.id).map(async (record) => {
|
|
4046
|
+
return (await this.listBindings(this.targetForInfo(await this.params.installationService.info(record.appId)))).some((binding) => providerIds.has(binding.providerId)) ? record.appId : void 0;
|
|
4047
|
+
}))).filter((entry) => Boolean(entry));
|
|
4048
|
+
if (dependentAppIds.length === 0) return;
|
|
4049
|
+
throw new AppPackageError("APP_PACKAGE_CONFLICT", `App ${provider.id} is required by enabled App${dependentAppIds.length === 1 ? "" : "s"}: ${dependentAppIds.join(", ")}. Unbind or disable those Apps first.`);
|
|
4050
|
+
};
|
|
4051
|
+
targetForInfo = (info, selectedVersion = info.activeVersion) => {
|
|
4052
|
+
const version = info.installedVersions.find((entry) => entry.version === selectedVersion);
|
|
4053
|
+
if (!version) throw new AppPackageError("APP_PACKAGE_OPERATION_FAILED", `应用 ${info.appId} 缺少版本 ${selectedVersion}。`);
|
|
4054
|
+
return this.target({
|
|
4055
|
+
appId: info.appId,
|
|
4056
|
+
storage: info.storage,
|
|
4057
|
+
components: version.components ?? []
|
|
4058
|
+
});
|
|
4059
|
+
};
|
|
4060
|
+
target = (params) => ({
|
|
4061
|
+
appId: params.appId,
|
|
4062
|
+
storage: params.storage,
|
|
4063
|
+
components: params.components.map((component) => ({
|
|
4064
|
+
id: component.id,
|
|
4065
|
+
kind: component.kind,
|
|
4066
|
+
componentDirectory: component.componentDirectory
|
|
4067
|
+
}))
|
|
4068
|
+
});
|
|
4069
|
+
assertReadyToEnable = (app) => {
|
|
4070
|
+
if (app.readiness.status === "ready") return;
|
|
4071
|
+
const required = app.readiness.requirements.map((requirement) => requirement.title).join(", ");
|
|
4072
|
+
const reason = app.readiness.status === "needs-capability" ? "an additional capability is required" : "external service setup is required";
|
|
4073
|
+
throw new AppPackageError("APP_PACKAGE_NOT_READY", `App ${app.id} is not ready to enable: ${reason}${required ? ` (${required})` : ""}.`);
|
|
4074
|
+
};
|
|
4075
|
+
getTarget = async (appId) => this.targetForInfo(await this.params.installationService.info(appId));
|
|
4076
|
+
getMutableTargetInfo = async (appId) => {
|
|
4077
|
+
const info = await this.params.installationService.info(appId);
|
|
4078
|
+
if (info.enabled) throw new AppPackageError("APP_PACKAGE_CONFLICT", `App ${appId} must be disabled before changing dependency bindings.`);
|
|
4079
|
+
return info;
|
|
4080
|
+
};
|
|
4081
|
+
};
|
|
4082
|
+
//#endregion
|
|
4083
|
+
//#region src/services/app-package-host-target.service.ts
|
|
4084
|
+
var AppPackageHostTargetService = class {
|
|
4085
|
+
platformTargetService = new AppPlatformTargetService();
|
|
4086
|
+
read = () => {
|
|
4087
|
+
try {
|
|
4088
|
+
const target = this.platformTargetService.readHostTarget();
|
|
4089
|
+
return {
|
|
4090
|
+
key: this.platformTargetService.toTargetKey(target),
|
|
4091
|
+
operatingSystem: target.os,
|
|
4092
|
+
architecture: target.arch,
|
|
4093
|
+
...target.os === "darwin" ? {} : { abi: target.abi }
|
|
4094
|
+
};
|
|
4095
|
+
} catch {
|
|
4096
|
+
return;
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
4099
|
+
};
|
|
4100
|
+
//#endregion
|
|
3538
4101
|
//#region src/services/app-package-presentation.service.ts
|
|
3539
4102
|
var AppPackagePresentationService = class {
|
|
3540
4103
|
readManifest = async (manifestPath) => {
|
|
@@ -3583,6 +4146,7 @@ var AppPackagePresentationService = class {
|
|
|
3583
4146
|
//#endregion
|
|
3584
4147
|
//#region src/services/app-package-runtime-activation.service.ts
|
|
3585
4148
|
const EMPTY_APP_PACKAGE_RUNTIME_HOOKS = {
|
|
4149
|
+
listCapabilityProviders: async () => [],
|
|
3586
4150
|
assertCanActivate: async () => void 0,
|
|
3587
4151
|
afterActivate: async () => void 0,
|
|
3588
4152
|
beforeDeactivate: async () => void 0,
|
|
@@ -3605,18 +4169,6 @@ var AppPackageRuntimeActivationService = class {
|
|
|
3605
4169
|
};
|
|
3606
4170
|
};
|
|
3607
4171
|
//#endregion
|
|
3608
|
-
//#region src/types/app-package.types.ts
|
|
3609
|
-
var AppPackageError = class extends Error {
|
|
3610
|
-
constructor(code, message) {
|
|
3611
|
-
super(message);
|
|
3612
|
-
this.code = code;
|
|
3613
|
-
this.name = "AppPackageError";
|
|
3614
|
-
}
|
|
3615
|
-
};
|
|
3616
|
-
function isAppPackageError(error) {
|
|
3617
|
-
return error instanceof AppPackageError;
|
|
3618
|
-
}
|
|
3619
|
-
//#endregion
|
|
3620
4172
|
//#region src/utils/app-engine-version.utils.ts
|
|
3621
4173
|
function satisfiesAppEngineVersion(version, range) {
|
|
3622
4174
|
const parsedVersion = parseVersion(version);
|
|
@@ -3726,8 +4278,9 @@ var AppPackageManager = class {
|
|
|
3726
4278
|
installationService;
|
|
3727
4279
|
manifestService = new AppManifestService();
|
|
3728
4280
|
operationManager;
|
|
3729
|
-
|
|
4281
|
+
hostTargetService = new AppPackageHostTargetService();
|
|
3730
4282
|
presentationService = new AppPackagePresentationService();
|
|
4283
|
+
dependencyCoordinator;
|
|
3731
4284
|
runtimeActivationService = new AppPackageRuntimeActivationService();
|
|
3732
4285
|
registryService;
|
|
3733
4286
|
runtimeHooks = EMPTY_APP_PACKAGE_RUNTIME_HOOKS;
|
|
@@ -3738,82 +4291,51 @@ var AppPackageManager = class {
|
|
|
3738
4291
|
this.appHomeService = new AppHomeService(params.appHomeDirectory);
|
|
3739
4292
|
this.installationService = new AppInstallationService(this.appHomeService);
|
|
3740
4293
|
this.registryService = new AppRegistryService(this.appHomeService);
|
|
4294
|
+
this.dependencyCoordinator = new AppPackageDependencyCoordinator({
|
|
4295
|
+
installationService: this.installationService,
|
|
4296
|
+
registryService: this.registryService,
|
|
4297
|
+
listCapabilityProviders: async () => await this.runtimeHooks.listCapabilityProviders(),
|
|
4298
|
+
resolveSecurity: this.resolveSecurity
|
|
4299
|
+
});
|
|
3741
4300
|
this.operationManager = new AppPackageOperationManager({
|
|
3742
4301
|
storePath: this.appHomeService.getOperationsPath(),
|
|
3743
4302
|
execute: this.executeOperation
|
|
3744
4303
|
});
|
|
3745
4304
|
}
|
|
3746
4305
|
installRuntimeHooks = (hooks) => {
|
|
3747
|
-
this.runtimeHooks =
|
|
4306
|
+
this.runtimeHooks = {
|
|
4307
|
+
...EMPTY_APP_PACKAGE_RUNTIME_HOOKS,
|
|
4308
|
+
...hooks
|
|
4309
|
+
};
|
|
3748
4310
|
};
|
|
3749
4311
|
start = async () => await this.ensureBuiltInPackages();
|
|
3750
4312
|
listPackages = async (options = {}) => {
|
|
3751
|
-
const records = await this.registryService.listApps();
|
|
4313
|
+
const [records, providers] = await Promise.all([this.registryService.listApps(), this.runtimeHooks.listCapabilityProviders()]);
|
|
4314
|
+
const entries = await Promise.all(records.map(async (record) => await this.toPackageView(await this.installationService.info(record.appId, { measureStorageUsage: options.includeStorageUsage !== false }), void 0, providers)));
|
|
3752
4315
|
return {
|
|
3753
|
-
hostTarget: this.
|
|
3754
|
-
entries
|
|
4316
|
+
hostTarget: this.hostTargetService.read(),
|
|
4317
|
+
entries
|
|
3755
4318
|
};
|
|
3756
4319
|
};
|
|
3757
|
-
readHostTarget = () => {
|
|
3758
|
-
try {
|
|
3759
|
-
const target = this.platformTargetService.readHostTarget();
|
|
3760
|
-
return {
|
|
3761
|
-
key: this.platformTargetService.toTargetKey(target),
|
|
3762
|
-
operatingSystem: target.os,
|
|
3763
|
-
architecture: target.arch,
|
|
3764
|
-
...target.os === "darwin" ? {} : { abi: target.abi }
|
|
3765
|
-
};
|
|
3766
|
-
} catch {
|
|
3767
|
-
return;
|
|
3768
|
-
}
|
|
3769
|
-
};
|
|
3770
4320
|
listInstalledDataOwners = async () => (await this.registryService.listApps()).map((record) => ({
|
|
3771
4321
|
id: record.appId,
|
|
3772
4322
|
name: record.name
|
|
3773
|
-
}));
|
|
3774
|
-
getPackage = async (appId) => {
|
|
3775
|
-
try {
|
|
3776
|
-
return await this.toPackageView(await this.installationService.info(appId));
|
|
3777
|
-
} catch (error) {
|
|
3778
|
-
if (error instanceof Error && error.message.includes("未找到已安装应用")) throw new AppPackageError("APP_PACKAGE_NOT_FOUND", error.message);
|
|
3779
|
-
throw error;
|
|
3780
|
-
}
|
|
3781
|
-
};
|
|
3782
|
-
listActiveComponentSources = async () => (await this.listActiveComponentSourcesWithDiagnostics()).sources;
|
|
3783
|
-
listActiveComponentSourcesWithDiagnostics = async () => {
|
|
3784
|
-
const records = await this.registryService.listApps();
|
|
3785
|
-
const results = await Promise.all(records.filter((record) => record.enabled).map(async (record) => {
|
|
3786
|
-
try {
|
|
3787
|
-
await this.installationService.assertVersionIntegrity(record.appId, record.activeVersion);
|
|
3788
|
-
const version = record.installedVersions[record.activeVersion];
|
|
3789
|
-
if (!version || version.manifestSchemaVersion !== 2) return { sources: [] };
|
|
3790
|
-
return { sources: (version.components ?? []).map((component) => ({
|
|
3791
|
-
kind: component.kind,
|
|
3792
|
-
id: component.id,
|
|
3793
|
-
packageId: record.appId,
|
|
3794
|
-
packageVersion: record.activeVersion,
|
|
3795
|
-
sourcePath: component.componentDirectory,
|
|
3796
|
-
manifestPath: component.manifestPath,
|
|
3797
|
-
dataDirectory: record.dataDirectory,
|
|
3798
|
-
instanceId: record.defaultInstance.id,
|
|
3799
|
-
storage: record.defaultInstance.storage,
|
|
3800
|
-
...this.resolveSecurity(version, record.appId)
|
|
3801
|
-
})) };
|
|
3802
|
-
} catch (error) {
|
|
3803
|
-
return {
|
|
3804
|
-
sources: [],
|
|
3805
|
-
unavailablePackage: {
|
|
3806
|
-
appId: record.appId,
|
|
3807
|
-
message: error instanceof Error ? error.message : String(error)
|
|
3808
|
-
}
|
|
3809
|
-
};
|
|
3810
|
-
}
|
|
3811
|
-
}));
|
|
3812
|
-
return {
|
|
3813
|
-
sources: results.flatMap((result) => result.sources),
|
|
3814
|
-
unavailablePackages: results.flatMap((result) => result.unavailablePackage ?? [])
|
|
3815
|
-
};
|
|
4323
|
+
}));
|
|
4324
|
+
getPackage = async (appId) => {
|
|
4325
|
+
try {
|
|
4326
|
+
return await this.toPackageView(await this.installationService.info(appId));
|
|
4327
|
+
} catch (error) {
|
|
4328
|
+
if (error instanceof Error && error.message.includes("未找到已安装应用")) throw new AppPackageError("APP_PACKAGE_NOT_FOUND", error.message);
|
|
4329
|
+
throw error;
|
|
4330
|
+
}
|
|
3816
4331
|
};
|
|
4332
|
+
inspectDependencies = async (appId) => await this.dependencyCoordinator.inspect(appId);
|
|
4333
|
+
verifyDependencies = async (appId) => await this.dependencyCoordinator.verify(appId);
|
|
4334
|
+
setupDependencies = async (appId) => await this.dependencyCoordinator.setup(appId);
|
|
4335
|
+
bindDependency = async (appId, input) => await this.dependencyCoordinator.bind(appId, input);
|
|
4336
|
+
unbindDependency = async (appId, input) => await this.dependencyCoordinator.unbind(appId, input);
|
|
4337
|
+
listActiveComponentSources = async () => (await this.listActiveComponentSourcesWithDiagnostics()).sources;
|
|
4338
|
+
listActiveComponentSourcesWithDiagnostics = async () => await this.dependencyCoordinator.listActiveComponentSourcesWithDiagnostics();
|
|
3817
4339
|
listOperations = async () => await this.operationManager.list();
|
|
3818
4340
|
startOperation = async (input) => {
|
|
3819
4341
|
await this.ensureBuiltInPackages();
|
|
@@ -3832,6 +4354,7 @@ var AppPackageManager = class {
|
|
|
3832
4354
|
const app = await this.getPackage(appId);
|
|
3833
4355
|
await this.installationService.assertVersionIntegrity(appId, app.activeVersion);
|
|
3834
4356
|
if (app.enabled) return app;
|
|
4357
|
+
this.dependencyCoordinator.assertReadyToEnable(app);
|
|
3835
4358
|
await this.assertEngineCompatibility(appId);
|
|
3836
4359
|
const sources = this.toComponentSources(app);
|
|
3837
4360
|
await this.runtimeHooks.assertCanActivate(sources);
|
|
@@ -3857,6 +4380,7 @@ var AppPackageManager = class {
|
|
|
3857
4380
|
return await this.installationService.withAppOperation(appId, async () => {
|
|
3858
4381
|
const app = await this.getPackage(appId);
|
|
3859
4382
|
if (!app.enabled) return app;
|
|
4383
|
+
await this.dependencyCoordinator.assertNoEnabledDependents(app);
|
|
3860
4384
|
await this.runtimeHooks.beforeDeactivate(this.toComponentSources(app));
|
|
3861
4385
|
await this.installationService.setEnabled(appId, false);
|
|
3862
4386
|
return await this.getPackage(appId);
|
|
@@ -3873,12 +4397,14 @@ var AppPackageManager = class {
|
|
|
3873
4397
|
package: current,
|
|
3874
4398
|
result
|
|
3875
4399
|
};
|
|
4400
|
+
await this.dependencyCoordinator.assertNoEnabledDependents(current);
|
|
3876
4401
|
let activated = false;
|
|
3877
4402
|
let deactivated = false;
|
|
3878
4403
|
try {
|
|
3879
4404
|
await this.assertEngineCompatibility(appId, result.version);
|
|
3880
4405
|
const candidate = await this.toPackageView(await this.installationService.info(appId), result.version);
|
|
3881
4406
|
if (current.enabled) {
|
|
4407
|
+
this.dependencyCoordinator.assertReadyToEnable(candidate);
|
|
3882
4408
|
await this.runtimeHooks.beforeDeactivate(this.toComponentSources(current));
|
|
3883
4409
|
deactivated = true;
|
|
3884
4410
|
await this.runtimeHooks.assertCanActivate(this.toComponentSources(candidate));
|
|
@@ -3914,12 +4440,14 @@ var AppPackageManager = class {
|
|
|
3914
4440
|
rolledBack: false
|
|
3915
4441
|
}
|
|
3916
4442
|
};
|
|
4443
|
+
await this.dependencyCoordinator.assertNoEnabledDependents(current);
|
|
3917
4444
|
await this.assertEngineCompatibility(appId, version);
|
|
3918
4445
|
const candidate = await this.toPackageView(await this.installationService.info(appId), version);
|
|
3919
4446
|
let deactivated = false;
|
|
3920
4447
|
let result;
|
|
3921
4448
|
try {
|
|
3922
4449
|
if (current.enabled) {
|
|
4450
|
+
this.dependencyCoordinator.assertReadyToEnable(candidate);
|
|
3923
4451
|
await this.runtimeHooks.beforeDeactivate(this.toComponentSources(current));
|
|
3924
4452
|
deactivated = true;
|
|
3925
4453
|
await this.runtimeHooks.assertCanActivate(this.toComponentSources(candidate));
|
|
@@ -3945,6 +4473,7 @@ var AppPackageManager = class {
|
|
|
3945
4473
|
uninstall = async (appId, purgeData) => {
|
|
3946
4474
|
return await this.installationService.withAppOperation(appId, async () => {
|
|
3947
4475
|
const current = await this.getPackage(appId);
|
|
4476
|
+
await this.dependencyCoordinator.assertNoEnabledDependents(current);
|
|
3948
4477
|
if (current.builtIn) await this.registryService.setBuiltInSuppressed(appId, true);
|
|
3949
4478
|
let rollbackRuntimeState;
|
|
3950
4479
|
try {
|
|
@@ -3985,7 +4514,7 @@ var AppPackageManager = class {
|
|
|
3985
4514
|
} });
|
|
3986
4515
|
}
|
|
3987
4516
|
};
|
|
3988
|
-
toPackageView = async (info, selectedVersion = info.activeVersion) => {
|
|
4517
|
+
toPackageView = async (info, selectedVersion = info.activeVersion, providers) => {
|
|
3989
4518
|
const activeVersion = info.installedVersions.find((version) => version.version === selectedVersion);
|
|
3990
4519
|
if (!activeVersion) throw new AppPackageError("APP_PACKAGE_OPERATION_FAILED", `应用 ${info.appId} 缺少版本 ${selectedVersion}。`);
|
|
3991
4520
|
const packagePresentation = await this.presentationService.readManifest(path.join(activeVersion.installDirectory, "manifest.json"));
|
|
@@ -3995,6 +4524,7 @@ var AppPackageManager = class {
|
|
|
3995
4524
|
isolation: manifestBundle.manifest.main.kind === "wasi-http-component" ? "host-mediated" : "sandboxed",
|
|
3996
4525
|
permissions: manifestBundle.manifest.permissions ?? {}
|
|
3997
4526
|
};
|
|
4527
|
+
const dependencies = await this.dependencyCoordinator.inspectTarget(this.dependencyCoordinator.targetForInfo(info, selectedVersion), providers);
|
|
3998
4528
|
return {
|
|
3999
4529
|
id: info.appId,
|
|
4000
4530
|
name: info.name,
|
|
@@ -4020,6 +4550,7 @@ var AppPackageManager = class {
|
|
|
4020
4550
|
runtimeProfile: security.runtimeProfile,
|
|
4021
4551
|
isolation: security.isolation,
|
|
4022
4552
|
permissions: security.permissions,
|
|
4553
|
+
resolvedProviderIds: dependencies.resolvedProviderIds[component.id],
|
|
4023
4554
|
...await this.presentationService.readManifest(component.manifestPath)
|
|
4024
4555
|
}))),
|
|
4025
4556
|
dataDirectory: info.dataDirectory,
|
|
@@ -4027,7 +4558,9 @@ var AppPackageManager = class {
|
|
|
4027
4558
|
storage: info.storage,
|
|
4028
4559
|
storageUsage: info.storageUsage,
|
|
4029
4560
|
runtimeProfile: security.runtimeProfile,
|
|
4030
|
-
isolation: security.isolation
|
|
4561
|
+
isolation: security.isolation,
|
|
4562
|
+
readiness: dependencies.readiness,
|
|
4563
|
+
dependencies
|
|
4031
4564
|
};
|
|
4032
4565
|
};
|
|
4033
4566
|
resolveSecurity = (version, appId) => {
|
|
@@ -4450,6 +4983,18 @@ function readExtensionProcessMemory(pid) {
|
|
|
4450
4983
|
pssBytes: toBytes(readMemoryKilobytes(rollup, "Pss"))
|
|
4451
4984
|
};
|
|
4452
4985
|
}
|
|
4986
|
+
if (process.platform === "win32") {
|
|
4987
|
+
const rssBytes = Number(execFileSync("powershell.exe", [
|
|
4988
|
+
"-NoProfile",
|
|
4989
|
+
"-NonInteractive",
|
|
4990
|
+
"-Command",
|
|
4991
|
+
`(Get-Process -Id ${pid}).WorkingSet64`
|
|
4992
|
+
], { encoding: "utf8" }).trim());
|
|
4993
|
+
return {
|
|
4994
|
+
rssBytes: Number.isFinite(rssBytes) ? rssBytes : null,
|
|
4995
|
+
pssBytes: null
|
|
4996
|
+
};
|
|
4997
|
+
}
|
|
4453
4998
|
const rssKilobytes = Number(execFileSync("ps", [
|
|
4454
4999
|
"-o",
|
|
4455
5000
|
"rss=",
|
|
@@ -4975,18 +5520,18 @@ var ExtensionLifecycleService = class {
|
|
|
4975
5520
|
};
|
|
4976
5521
|
//#endregion
|
|
4977
5522
|
//#region src/features/extension-runtime/utils/extension-runtime-payload.utils.ts
|
|
4978
|
-
function readString$
|
|
5523
|
+
function readString$9(value) {
|
|
4979
5524
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
4980
5525
|
}
|
|
4981
5526
|
function readRecord$2(value) {
|
|
4982
5527
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
4983
5528
|
}
|
|
4984
|
-
function readRequiredString$
|
|
4985
|
-
const trimmed = readString$
|
|
5529
|
+
function readRequiredString$7(value, name) {
|
|
5530
|
+
const trimmed = readString$9(value);
|
|
4986
5531
|
if (!trimmed) throw new Error(`${name} is required`);
|
|
4987
5532
|
return trimmed;
|
|
4988
5533
|
}
|
|
4989
|
-
function readOptionalNumber
|
|
5534
|
+
function readOptionalNumber(value) {
|
|
4990
5535
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4991
5536
|
}
|
|
4992
5537
|
function readTextContent(value) {
|
|
@@ -4997,24 +5542,24 @@ function readTextContent(value) {
|
|
|
4997
5542
|
function readInboundAttachments(value) {
|
|
4998
5543
|
if (!Array.isArray(value)) return [];
|
|
4999
5544
|
return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))).map((entry) => ({
|
|
5000
|
-
...readString$
|
|
5001
|
-
...readString$
|
|
5002
|
-
...readString$
|
|
5003
|
-
...readString$
|
|
5004
|
-
...readString$
|
|
5005
|
-
...readString$
|
|
5006
|
-
...readOptionalNumber
|
|
5007
|
-
...readString$
|
|
5545
|
+
...readString$9(entry.id) ? { id: readString$9(entry.id) } : {},
|
|
5546
|
+
...readString$9(entry.name) ? { name: readString$9(entry.name) } : {},
|
|
5547
|
+
...readString$9(entry.path) ? { path: readString$9(entry.path) } : {},
|
|
5548
|
+
...readString$9(entry.url) ? { url: readString$9(entry.url) } : {},
|
|
5549
|
+
...readString$9(entry.assetUri) ? { assetUri: readString$9(entry.assetUri) } : {},
|
|
5550
|
+
...readString$9(entry.mimeType) ? { mimeType: readString$9(entry.mimeType) } : {},
|
|
5551
|
+
...readOptionalNumber(entry.size) !== void 0 ? { size: readOptionalNumber(entry.size) } : {},
|
|
5552
|
+
...readString$9(entry.source) ? { source: readString$9(entry.source) } : {},
|
|
5008
5553
|
...entry.status === "ready" || entry.status === "remote-only" ? { status: entry.status } : {},
|
|
5009
|
-
...readString$
|
|
5554
|
+
...readString$9(entry.errorCode) ? { errorCode: readString$9(entry.errorCode) } : {}
|
|
5010
5555
|
}));
|
|
5011
5556
|
}
|
|
5012
5557
|
function toInboundMessage(value) {
|
|
5013
5558
|
const payload = readRecord$2(value);
|
|
5014
5559
|
return {
|
|
5015
|
-
channel: readRequiredString$
|
|
5016
|
-
chatId: readRequiredString$
|
|
5017
|
-
senderId: readRequiredString$
|
|
5560
|
+
channel: readRequiredString$7(payload.channelId, "channelId"),
|
|
5561
|
+
chatId: readRequiredString$7(payload.conversationId, "conversationId"),
|
|
5562
|
+
senderId: readRequiredString$7(payload.senderId, "senderId"),
|
|
5018
5563
|
content: readTextContent(payload.content),
|
|
5019
5564
|
timestamp: /* @__PURE__ */ new Date(),
|
|
5020
5565
|
attachments: readInboundAttachments(payload.attachments),
|
|
@@ -5036,10 +5581,10 @@ function normalizeAuthPollResult(value) {
|
|
|
5036
5581
|
if (!value) return null;
|
|
5037
5582
|
const record = readRecord$2(value);
|
|
5038
5583
|
return {
|
|
5039
|
-
channel: readRequiredString$
|
|
5584
|
+
channel: readRequiredString$7(record.channel, "channel"),
|
|
5040
5585
|
status: record.status,
|
|
5041
|
-
message: readString$
|
|
5042
|
-
nextPollMs: readOptionalNumber
|
|
5586
|
+
message: readString$9(record.message),
|
|
5587
|
+
nextPollMs: readOptionalNumber(record.nextPollMs),
|
|
5043
5588
|
accountId: typeof record.accountId === "string" ? record.accountId : null,
|
|
5044
5589
|
notes: Array.isArray(record.notes) ? record.notes.filter((note) => typeof note === "string") : [],
|
|
5045
5590
|
channelConfig: normalizeChannelConfigResult(record)
|
|
@@ -5068,16 +5613,16 @@ var ExtensionIngressDiagnosticsService = class {
|
|
|
5068
5613
|
recordExtensionEvent = (input, credential) => {
|
|
5069
5614
|
const payload = readRecord$2(input);
|
|
5070
5615
|
this.diagnostics.record({
|
|
5071
|
-
domain: readRequiredString$
|
|
5072
|
-
event: readRequiredString$
|
|
5073
|
-
component: readRequiredString$
|
|
5074
|
-
outcome: readRequiredString$
|
|
5075
|
-
correlationId: readString$
|
|
5076
|
-
parentCorrelationId: readString$
|
|
5077
|
-
reasonCode: readString$
|
|
5078
|
-
providerCode: readString$
|
|
5079
|
-
durationMs: readOptionalNumber
|
|
5080
|
-
attempt: readOptionalNumber
|
|
5616
|
+
domain: readRequiredString$7(payload.domain, "domain"),
|
|
5617
|
+
event: readRequiredString$7(payload.event, "event"),
|
|
5618
|
+
component: readRequiredString$7(payload.component, "component"),
|
|
5619
|
+
outcome: readRequiredString$7(payload.outcome, "outcome"),
|
|
5620
|
+
correlationId: readString$9(payload.correlationId),
|
|
5621
|
+
parentCorrelationId: readString$9(payload.parentCorrelationId),
|
|
5622
|
+
reasonCode: readString$9(payload.reasonCode),
|
|
5623
|
+
providerCode: readString$9(payload.providerCode),
|
|
5624
|
+
durationMs: readOptionalNumber(payload.durationMs),
|
|
5625
|
+
attempt: readOptionalNumber(payload.attempt),
|
|
5081
5626
|
facts: {
|
|
5082
5627
|
...readRecord$2(payload.facts),
|
|
5083
5628
|
extensionId: credential.extensionId,
|
|
@@ -5207,7 +5752,7 @@ var ExtensionAuthLeaseService = class {
|
|
|
5207
5752
|
}
|
|
5208
5753
|
updateAfterRequest = async (params, value, generation) => {
|
|
5209
5754
|
const { extensionId, kind, payload } = params;
|
|
5210
|
-
const channelId = readRequiredString$
|
|
5755
|
+
const channelId = readRequiredString$7(payload.channelId, "channelId");
|
|
5211
5756
|
if (kind === "channel.auth.start") {
|
|
5212
5757
|
await this.retainSession({
|
|
5213
5758
|
extensionId,
|
|
@@ -5217,14 +5762,14 @@ var ExtensionAuthLeaseService = class {
|
|
|
5217
5762
|
return;
|
|
5218
5763
|
}
|
|
5219
5764
|
if (kind === "channel.auth.poll") {
|
|
5220
|
-
const sessionId = readRequiredString$
|
|
5765
|
+
const sessionId = readRequiredString$7(payload.sessionId, "sessionId");
|
|
5221
5766
|
const result = value ? readRecord$2(value) : null;
|
|
5222
|
-
const status = result ? readString$
|
|
5767
|
+
const status = result ? readString$9(result.status) : null;
|
|
5223
5768
|
if (status === "authorized") await this.retainHandoff(extensionId, channelId, generation);
|
|
5224
5769
|
if (!result || status === "authorized" || status === "expired" || status === "error") this.releaseSession(extensionId, sessionId);
|
|
5225
5770
|
return;
|
|
5226
5771
|
}
|
|
5227
|
-
if (kind === "channel.auth.connect" && readString$
|
|
5772
|
+
if (kind === "channel.auth.connect" && readString$9(readRecord$2(value).status) === "authorized") {
|
|
5228
5773
|
await this.retainHandoff(extensionId, channelId, generation);
|
|
5229
5774
|
return;
|
|
5230
5775
|
}
|
|
@@ -5253,8 +5798,8 @@ var ExtensionAuthLeaseService = class {
|
|
|
5253
5798
|
retainSession = async (params) => {
|
|
5254
5799
|
const { extensionId, generation } = params;
|
|
5255
5800
|
const result = readRecord$2(params.result);
|
|
5256
|
-
const sessionId = readRequiredString$
|
|
5257
|
-
const expiresAt = readRequiredString$
|
|
5801
|
+
const sessionId = readRequiredString$7(result.sessionId, "sessionId");
|
|
5802
|
+
const expiresAt = readRequiredString$7(result.expiresAt, "expiresAt");
|
|
5258
5803
|
const expiresAtMs = Date.parse(expiresAt);
|
|
5259
5804
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now()) throw new Error("Extension auth session has an invalid expiresAt");
|
|
5260
5805
|
const endpoint = this.requireEndpoint("auth start");
|
|
@@ -5343,7 +5888,7 @@ const BUILTIN_EXTENSION_PACKAGES = [
|
|
|
5343
5888
|
"@nextclaw/channel-extension-weixin"
|
|
5344
5889
|
];
|
|
5345
5890
|
const runtimeRequire = createRequire(import.meta.url);
|
|
5346
|
-
function readString$
|
|
5891
|
+
function readString$8(value) {
|
|
5347
5892
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
5348
5893
|
}
|
|
5349
5894
|
function readStringArray$1(value) {
|
|
@@ -5392,16 +5937,16 @@ function toManifest(value, rootDir) {
|
|
|
5392
5937
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("extension manifest must be an object");
|
|
5393
5938
|
const record = value;
|
|
5394
5939
|
const server = readRecord$1(record.server);
|
|
5395
|
-
const id = readString$
|
|
5396
|
-
const command = readString$
|
|
5940
|
+
const id = readString$8(record.id);
|
|
5941
|
+
const command = readString$8(server.command);
|
|
5397
5942
|
if (!id) throw new Error("extension manifest id is required");
|
|
5398
5943
|
if (server.type !== "stdio") throw new Error("extension server.type must be stdio");
|
|
5399
5944
|
if (!command) throw new Error("extension server.command is required");
|
|
5400
5945
|
return {
|
|
5401
5946
|
id,
|
|
5402
5947
|
rootDir,
|
|
5403
|
-
...readString$
|
|
5404
|
-
...readString$
|
|
5948
|
+
...readString$8(record.name) ? { name: readString$8(record.name) } : {},
|
|
5949
|
+
...readString$8(record.version) ? { version: readString$8(record.version) } : {},
|
|
5405
5950
|
server: {
|
|
5406
5951
|
type: "stdio",
|
|
5407
5952
|
command,
|
|
@@ -5585,11 +6130,11 @@ var ExtensionObservationRuntimeService = class {
|
|
|
5585
6130
|
};
|
|
5586
6131
|
handleEvent = async (input) => {
|
|
5587
6132
|
const payload = readRecord$2(input.payload);
|
|
5588
|
-
const subscriptionId = readRequiredString$
|
|
6133
|
+
const subscriptionId = readRequiredString$7(payload.subscriptionId, "subscriptionId");
|
|
5589
6134
|
const event = readRecord$2(payload.event);
|
|
5590
|
-
const eventId = readRequiredString$
|
|
5591
|
-
const eventType = readRequiredString$
|
|
5592
|
-
const occurredAt = readRequiredString$
|
|
6135
|
+
const eventId = readRequiredString$7(event.eventId, "event.eventId");
|
|
6136
|
+
const eventType = readRequiredString$7(event.eventType, "event.eventType");
|
|
6137
|
+
const occurredAt = readRequiredString$7(event.occurredAt, "event.occurredAt");
|
|
5593
6138
|
return await this.options.onEvent?.({
|
|
5594
6139
|
extensionId: input.extensionId,
|
|
5595
6140
|
subscriptionId,
|
|
@@ -5597,13 +6142,13 @@ var ExtensionObservationRuntimeService = class {
|
|
|
5597
6142
|
eventId,
|
|
5598
6143
|
eventType,
|
|
5599
6144
|
occurredAt,
|
|
5600
|
-
observedAt: readString$
|
|
5601
|
-
...readString$
|
|
5602
|
-
...readString$
|
|
6145
|
+
observedAt: readString$9(event.observedAt) ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
6146
|
+
...readString$9(event.cursor) ? { cursor: readString$9(event.cursor) } : {},
|
|
6147
|
+
...readString$9(event.dedupeKey) ? { dedupeKey: readString$9(event.dedupeKey) } : {},
|
|
5603
6148
|
payload: event.payload,
|
|
5604
6149
|
...Array.isArray(event.sourceRefs) && event.sourceRefs.every((value) => typeof value === "string") ? { sourceRefs: event.sourceRefs } : {},
|
|
5605
|
-
...readString$
|
|
5606
|
-
...readString$
|
|
6150
|
+
...readString$9(event.causationId) ? { causationId: readString$9(event.causationId) } : {},
|
|
6151
|
+
...readString$9(event.correlationId) ? { correlationId: readString$9(event.correlationId) } : {}
|
|
5607
6152
|
}
|
|
5608
6153
|
}) ?? { accepted: false };
|
|
5609
6154
|
};
|
|
@@ -5717,16 +6262,32 @@ const SERVICE_APP_ERROR_CODES = new Set([
|
|
|
5717
6262
|
"SERVICE_APP_MANAGED_SOURCE",
|
|
5718
6263
|
"SERVICE_APP_NOT_FOUND",
|
|
5719
6264
|
"SERVICE_APP_READ_FAILED",
|
|
5720
|
-
"SERVICE_APP_RUNTIME_FAILED"
|
|
6265
|
+
"SERVICE_APP_RUNTIME_FAILED",
|
|
6266
|
+
"WASI_ABI_VERSION_MISMATCH",
|
|
6267
|
+
"WASI_CAPABILITY_DENIED",
|
|
6268
|
+
"WASI_COMPONENT_FAILED",
|
|
6269
|
+
"WASI_COMPONENT_TRAP",
|
|
6270
|
+
"WASI_GUEST_EXPORT_MISSING",
|
|
6271
|
+
"WASI_INPUT_SCHEMA_MISMATCH"
|
|
5721
6272
|
]);
|
|
5722
6273
|
var ServiceAppError = class extends Error {
|
|
5723
|
-
constructor(code, message) {
|
|
6274
|
+
constructor(code, message, details) {
|
|
5724
6275
|
super(message);
|
|
5725
6276
|
this.code = code;
|
|
6277
|
+
this.details = details;
|
|
5726
6278
|
this.name = "ServiceAppError";
|
|
5727
6279
|
}
|
|
5728
6280
|
};
|
|
5729
6281
|
const isServiceAppError = (error) => error instanceof ServiceAppError || typeof error === "object" && error !== null && error.name === "ServiceAppError" && typeof error.message === "string" && SERVICE_APP_ERROR_CODES.has(error.code);
|
|
6282
|
+
const toServiceAppRuntimeError = (error, appId, actionName) => {
|
|
6283
|
+
if (isPortableWasiError(error)) return new ServiceAppError(error.code, error.message, error.details);
|
|
6284
|
+
return new ServiceAppError("SERVICE_APP_RUNTIME_FAILED", `Service App ${appId} action ${actionName} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
6285
|
+
};
|
|
6286
|
+
const isPortableWasiError = (error) => {
|
|
6287
|
+
if (typeof error !== "object" || error === null) return false;
|
|
6288
|
+
const candidate = error;
|
|
6289
|
+
return candidate.name === "PortableServiceRunnerError" && typeof candidate.message === "string" && typeof candidate.code === "string" && candidate.code.startsWith("WASI_") && SERVICE_APP_ERROR_CODES.has(candidate.code);
|
|
6290
|
+
};
|
|
5730
6291
|
//#endregion
|
|
5731
6292
|
//#region src/utils/service-action.utils.ts
|
|
5732
6293
|
const DEFAULT_SERVICE_ACTION_RISK = "dangerous";
|
|
@@ -6650,10 +7211,10 @@ var DesktopNodeReplService = class {
|
|
|
6650
7211
|
}
|
|
6651
7212
|
async handleWorkerMessage(key, worker, value) {
|
|
6652
7213
|
const message = asRecord$1(value);
|
|
6653
|
-
const executionId = readString$
|
|
7214
|
+
const executionId = readString$7(message.executionId);
|
|
6654
7215
|
if (!executionId || !worker.pending.has(executionId)) return;
|
|
6655
7216
|
if (message.type === "desktop.request") {
|
|
6656
|
-
const requestId = readString$
|
|
7217
|
+
const requestId = readString$7(message.requestId);
|
|
6657
7218
|
if (!requestId) return;
|
|
6658
7219
|
try {
|
|
6659
7220
|
const result = await this.invokeDesktop(worker.pending.get(executionId).caller, message.operation, message.args);
|
|
@@ -6684,7 +7245,7 @@ var DesktopNodeReplService = class {
|
|
|
6684
7245
|
}
|
|
6685
7246
|
if (message.type === "error") {
|
|
6686
7247
|
const error = asRecord$1(message.error);
|
|
6687
|
-
this.reject(worker, executionId, replError(readString$
|
|
7248
|
+
this.reject(worker, executionId, replError(readString$7(error.code) ?? "repl_execution_failed", readString$7(error.message) ?? "node_repl execution failed."));
|
|
6688
7249
|
return;
|
|
6689
7250
|
}
|
|
6690
7251
|
this.stopWorker(key, worker);
|
|
@@ -6830,7 +7391,7 @@ function readKeyboardModifiers(value) {
|
|
|
6830
7391
|
if (new Set(value).size !== value.length) throw replError("invalid_tool_arguments", "modifiers cannot contain duplicates.");
|
|
6831
7392
|
return value;
|
|
6832
7393
|
}
|
|
6833
|
-
function readString$
|
|
7394
|
+
function readString$7(value) {
|
|
6834
7395
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
6835
7396
|
}
|
|
6836
7397
|
function trimOutput(value) {
|
|
@@ -7298,12 +7859,12 @@ var ExtensionDesktopRuntimeService = class {
|
|
|
7298
7859
|
return await this.capabilities.invoke({
|
|
7299
7860
|
extensionId: credential.extensionId,
|
|
7300
7861
|
generation: credential.generation,
|
|
7301
|
-
method: readRequiredString$
|
|
7862
|
+
method: readRequiredString$7(payload.method, "method"),
|
|
7302
7863
|
payload: readRecord$2(payload.payload),
|
|
7303
7864
|
caller: {
|
|
7304
|
-
...readString$
|
|
7305
|
-
...readString$
|
|
7306
|
-
...readString$
|
|
7865
|
+
...readString$9(caller.sessionId) ? { sessionId: readString$9(caller.sessionId) } : {},
|
|
7866
|
+
...readString$9(caller.agentRunId) ? { agentRunId: readString$9(caller.agentRunId) } : {},
|
|
7867
|
+
...readString$9(caller.subscriptionId) ? { subscriptionId: readString$9(caller.subscriptionId) } : {}
|
|
7307
7868
|
}
|
|
7308
7869
|
});
|
|
7309
7870
|
};
|
|
@@ -7444,7 +8005,7 @@ var ExtensionRuntimeService = class {
|
|
|
7444
8005
|
const desired = /* @__PURE__ */ new Map();
|
|
7445
8006
|
const channelConfig = readRecord$2(config.channels);
|
|
7446
8007
|
for (const manifest of this.manifests) for (const channel of manifest.contributes?.channels ?? []) {
|
|
7447
|
-
const channelId = readString$
|
|
8008
|
+
const channelId = readString$9(channel.id);
|
|
7448
8009
|
if (!channelId || readRecord$2(channelConfig[channelId]).enabled !== true) continue;
|
|
7449
8010
|
desired.set(this.persistentLeaseKey(manifest.id, channelId), {
|
|
7450
8011
|
manifest,
|
|
@@ -7488,7 +8049,7 @@ var ExtensionRuntimeService = class {
|
|
|
7488
8049
|
};
|
|
7489
8050
|
handleChannelConfigGet = (envelope, context) => {
|
|
7490
8051
|
this.assertAuthorized(envelope, context);
|
|
7491
|
-
const channelId = readRequiredString$
|
|
8052
|
+
const channelId = readRequiredString$7(readRecord$2(envelope.payload).channelId, "channelId");
|
|
7492
8053
|
return { config: this.options.getConfig().channels[channelId] ?? {} };
|
|
7493
8054
|
};
|
|
7494
8055
|
handleChannelMessageSubmit = async (envelope, context) => {
|
|
@@ -7510,9 +8071,9 @@ var ExtensionRuntimeService = class {
|
|
|
7510
8071
|
handleChannelCommandExecute = async (envelope, context) => {
|
|
7511
8072
|
this.assertAuthorized(envelope, context);
|
|
7512
8073
|
const payload = readRecord$2(envelope.payload);
|
|
7513
|
-
const channel = readRequiredString$
|
|
7514
|
-
const chatId = readRequiredString$
|
|
7515
|
-
const senderId = readRequiredString$
|
|
8074
|
+
const channel = readRequiredString$7(payload.channelId, "channelId");
|
|
8075
|
+
const chatId = readRequiredString$7(payload.conversationId, "conversationId");
|
|
8076
|
+
const senderId = readRequiredString$7(payload.senderId, "senderId");
|
|
7516
8077
|
const metadata = readRecord$2(payload.metadata);
|
|
7517
8078
|
const config = this.options.getConfig();
|
|
7518
8079
|
const registry = new CommandRegistry(config, this.options.sessionManager);
|
|
@@ -7521,15 +8082,15 @@ var ExtensionRuntimeService = class {
|
|
|
7521
8082
|
channel,
|
|
7522
8083
|
chatId,
|
|
7523
8084
|
senderId,
|
|
7524
|
-
content: readString$
|
|
8085
|
+
content: readString$9(payload.rawText) ?? readString$9(payload.commandName) ?? "",
|
|
7525
8086
|
timestamp: /* @__PURE__ */ new Date(),
|
|
7526
8087
|
attachments: [],
|
|
7527
8088
|
metadata
|
|
7528
8089
|
},
|
|
7529
|
-
forcedAgentId: readString$
|
|
7530
|
-
sessionKeyOverride: readString$
|
|
8090
|
+
forcedAgentId: readString$9(metadata.target_agent_id),
|
|
8091
|
+
sessionKeyOverride: readString$9(metadata.session_key_override)
|
|
7531
8092
|
});
|
|
7532
|
-
const rawText = readString$
|
|
8093
|
+
const rawText = readString$9(payload.rawText);
|
|
7533
8094
|
if (rawText) return await registry.executeText(rawText, {
|
|
7534
8095
|
channel,
|
|
7535
8096
|
chatId,
|
|
@@ -7539,7 +8100,7 @@ var ExtensionRuntimeService = class {
|
|
|
7539
8100
|
content: "",
|
|
7540
8101
|
ephemeral: true
|
|
7541
8102
|
};
|
|
7542
|
-
return await registry.execute(readRequiredString$
|
|
8103
|
+
return await registry.execute(readRequiredString$7(payload.commandName, "commandName"), readRecord$2(payload.args), {
|
|
7543
8104
|
channel,
|
|
7544
8105
|
chatId,
|
|
7545
8106
|
senderId,
|
|
@@ -7556,13 +8117,13 @@ var ExtensionRuntimeService = class {
|
|
|
7556
8117
|
handleExtensionResponse = (envelope, context) => {
|
|
7557
8118
|
const credential = this.assertAuthorized(envelope, context);
|
|
7558
8119
|
const payload = readRecord$2(envelope.payload);
|
|
7559
|
-
const requestId = readRequiredString$
|
|
8120
|
+
const requestId = readRequiredString$7(payload.requestId, "requestId");
|
|
7560
8121
|
const pending = this.pendingRequests.get(requestId);
|
|
7561
8122
|
if (!pending || pending.extensionId !== credential.extensionId || pending.generation !== credential.generation) return { accepted: false };
|
|
7562
8123
|
this.pendingRequests.delete(requestId);
|
|
7563
8124
|
pending.cleanup();
|
|
7564
8125
|
if (payload.ok === false) {
|
|
7565
|
-
const message = readString$
|
|
8126
|
+
const message = readString$9(readRecord$2(payload.error).message) ?? "Extension request failed";
|
|
7566
8127
|
pending.reject(new Error(message));
|
|
7567
8128
|
return { accepted: true };
|
|
7568
8129
|
}
|
|
@@ -7572,8 +8133,8 @@ var ExtensionRuntimeService = class {
|
|
|
7572
8133
|
handleRuntimeReady = async (envelope, context) => {
|
|
7573
8134
|
const credential = this.assertAuthorized(envelope, context);
|
|
7574
8135
|
const payload = readRecord$2(envelope.payload);
|
|
7575
|
-
const generation = readRequiredString$
|
|
7576
|
-
const pid = readOptionalNumber
|
|
8136
|
+
const generation = readRequiredString$7(payload.generation, "generation");
|
|
8137
|
+
const pid = readOptionalNumber(payload.pid);
|
|
7577
8138
|
if (generation !== credential.generation || pid === void 0 || !Number.isInteger(pid) || pid <= 0) throw new Error("Invalid extension runtime ready payload");
|
|
7578
8139
|
this.lifecycle.markReady({
|
|
7579
8140
|
extensionId: credential.extensionId,
|
|
@@ -7591,12 +8152,12 @@ var ExtensionRuntimeService = class {
|
|
|
7591
8152
|
const endpoint = this.endpoint;
|
|
7592
8153
|
if (!endpoint) throw new Error("Extension runtime is not started");
|
|
7593
8154
|
if (kind === "channel.outbound.sendText") {
|
|
7594
|
-
const channelId = readRequiredString$
|
|
8155
|
+
const channelId = readRequiredString$7(payload.channelId, "channelId");
|
|
7595
8156
|
if (!this.isChannelEnabled(channelId)) throw new Error(`Channel is disabled: ${channelId}`);
|
|
7596
8157
|
}
|
|
7597
8158
|
const manifest = this.findManifest(extensionId);
|
|
7598
8159
|
const requestId = randomUUID();
|
|
7599
|
-
const authSession = kind === "channel.auth.poll" ? this.authLeases.requireSession(extensionId, readRequiredString$
|
|
8160
|
+
const authSession = kind === "channel.auth.poll" ? this.authLeases.requireSession(extensionId, readRequiredString$7(payload.sessionId, "sessionId")) : null;
|
|
7600
8161
|
const requestLease = await this.lifecycle.acquire(manifest, {
|
|
7601
8162
|
endpoint,
|
|
7602
8163
|
...authSession ? { expectedGeneration: authSession.generation } : {},
|
|
@@ -7673,9 +8234,9 @@ var ExtensionRuntimeService = class {
|
|
|
7673
8234
|
};
|
|
7674
8235
|
assertAuthorized = (envelope, context) => {
|
|
7675
8236
|
const credential = this.lifecycle.authenticateCredential({
|
|
7676
|
-
extensionId: readString$
|
|
7677
|
-
generation: readString$
|
|
7678
|
-
token: readString$
|
|
8237
|
+
extensionId: readString$9(envelope.extensionId) ?? null,
|
|
8238
|
+
generation: readString$9(envelope.generation) ?? null,
|
|
8239
|
+
token: readString$9(context.token) ?? null
|
|
7679
8240
|
});
|
|
7680
8241
|
if (!credential) throw new Error("Unauthorized ingress token");
|
|
7681
8242
|
return credential;
|
|
@@ -9147,16 +9708,16 @@ function parsePanelAppFolderManifest(raw) {
|
|
|
9147
9708
|
throw new Error(`panel-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
9148
9709
|
}
|
|
9149
9710
|
if (!isRecord$12(parsed)) throw new Error("panel-app.json must contain an object.");
|
|
9150
|
-
const id = readOptionalString$
|
|
9711
|
+
const id = readOptionalString$10(parsed, "id");
|
|
9151
9712
|
if (id && !PANEL_APP_ID_PATTERN.test(id)) throw new Error("panel app id must be kebab-case.");
|
|
9152
9713
|
return {
|
|
9153
9714
|
id,
|
|
9154
|
-
title: readRequiredString$
|
|
9155
|
-
description: readOptionalString$
|
|
9156
|
-
icon: readOptionalString$
|
|
9157
|
-
entry: readRequiredString$
|
|
9715
|
+
title: readRequiredString$6(parsed, "title"),
|
|
9716
|
+
description: readOptionalString$10(parsed, "description"),
|
|
9717
|
+
icon: readOptionalString$10(parsed, "icon"),
|
|
9718
|
+
entry: readRequiredString$6(parsed, "entry"),
|
|
9158
9719
|
capabilities: readStringArray(parsed.capabilities, "capabilities"),
|
|
9159
|
-
client: readOptionalBoolean$
|
|
9720
|
+
client: readOptionalBoolean$1(parsed, "client"),
|
|
9160
9721
|
serviceActions: readStringArray(parsed.actions, "actions")
|
|
9161
9722
|
};
|
|
9162
9723
|
}
|
|
@@ -9214,15 +9775,15 @@ function parseTokenList(content) {
|
|
|
9214
9775
|
if (!content) return [];
|
|
9215
9776
|
return [...new Set(content.split(/[,\s]+/).map((entry) => entry.trim()).filter(Boolean))];
|
|
9216
9777
|
}
|
|
9217
|
-
function readRequiredString$
|
|
9218
|
-
const value = readOptionalString$
|
|
9778
|
+
function readRequiredString$6(record, key) {
|
|
9779
|
+
const value = readOptionalString$10(record, key);
|
|
9219
9780
|
if (!value) throw new Error(`panel app ${key} is required.`);
|
|
9220
9781
|
return value;
|
|
9221
9782
|
}
|
|
9222
|
-
function readOptionalString$
|
|
9783
|
+
function readOptionalString$10(record, key) {
|
|
9223
9784
|
return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
|
|
9224
9785
|
}
|
|
9225
|
-
function readOptionalBoolean$
|
|
9786
|
+
function readOptionalBoolean$1(record, key) {
|
|
9226
9787
|
const value = record[key];
|
|
9227
9788
|
if (value === void 0) return false;
|
|
9228
9789
|
if (typeof value !== "boolean") throw new Error(`panel app ${key} must be a boolean.`);
|
|
@@ -11554,12 +12115,12 @@ function parseSkillFrontmatter(raw) {
|
|
|
11554
12115
|
const summaryI18n = readLocalizedTextMap(parsed, "summaryi18n", "summary_i18n");
|
|
11555
12116
|
const descriptionI18n = readLocalizedTextMap(parsed, "descriptioni18n", "description_i18n");
|
|
11556
12117
|
return {
|
|
11557
|
-
name: readString$
|
|
11558
|
-
summary: readString$
|
|
11559
|
-
summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$
|
|
11560
|
-
description: readString$
|
|
11561
|
-
descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$
|
|
11562
|
-
author: readString$
|
|
12118
|
+
name: readString$6(parsed, "name"),
|
|
12119
|
+
summary: readString$6(parsed, "summary"),
|
|
12120
|
+
summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: readString$6(parsed, "summaryzh", "summary_zh") }),
|
|
12121
|
+
description: readString$6(parsed, "description"),
|
|
12122
|
+
descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: readString$6(parsed, "descriptionzh", "description_zh") }),
|
|
12123
|
+
author: readString$6(parsed, "author"),
|
|
11563
12124
|
tags: readTags(parsed)
|
|
11564
12125
|
};
|
|
11565
12126
|
}
|
|
@@ -11586,7 +12147,7 @@ function parseYamlFrontmatter(raw) {
|
|
|
11586
12147
|
throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
|
|
11587
12148
|
}
|
|
11588
12149
|
}
|
|
11589
|
-
function readString$
|
|
12150
|
+
function readString$6(record, ...names) {
|
|
11590
12151
|
const value = readValue(record, names);
|
|
11591
12152
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
11592
12153
|
}
|
|
@@ -11836,11 +12397,11 @@ function createAgentPeerSessionIdentity(params) {
|
|
|
11836
12397
|
}
|
|
11837
12398
|
function resolveAgentPeerScope(params) {
|
|
11838
12399
|
const metadata = params.metadata ?? {};
|
|
11839
|
-
const explicitScope = readOptionalString$
|
|
12400
|
+
const explicitScope = readOptionalString$9(metadata["agent_peer_scope"]) ?? readOptionalString$9(metadata.agentPeerScope);
|
|
11840
12401
|
if (explicitScope) return explicitScope;
|
|
11841
|
-
return `agent:${readOptionalString$
|
|
12402
|
+
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"}`;
|
|
11842
12403
|
}
|
|
11843
|
-
function readOptionalString$
|
|
12404
|
+
function readOptionalString$9(value) {
|
|
11844
12405
|
if (typeof value !== "string") return;
|
|
11845
12406
|
return value.trim() || void 0;
|
|
11846
12407
|
}
|
|
@@ -12730,7 +13291,7 @@ function applyLimit(items, limit) {
|
|
|
12730
13291
|
if (!Number.isFinite(limit) || typeof limit !== "number" || limit <= 0) return items;
|
|
12731
13292
|
return items.slice(0, Math.trunc(limit));
|
|
12732
13293
|
}
|
|
12733
|
-
function readOptionalString$
|
|
13294
|
+
function readOptionalString$8(value) {
|
|
12734
13295
|
if (typeof value !== "string") return null;
|
|
12735
13296
|
const trimmed = value.trim();
|
|
12736
13297
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -12791,7 +13352,7 @@ function mergeMetadataOverrides(metadata, overrides) {
|
|
|
12791
13352
|
}
|
|
12792
13353
|
function resolveSessionType(params) {
|
|
12793
13354
|
const { metadata, runtime, sessionType } = params;
|
|
12794
|
-
return readOptionalString$
|
|
13355
|
+
return readOptionalString$8(runtime) ?? readOptionalString$8(metadata.runtime) ?? readOptionalString$8(sessionType) ?? readOptionalString$8(metadata.session_type) ?? "native";
|
|
12795
13356
|
}
|
|
12796
13357
|
function applySessionOverrides(params) {
|
|
12797
13358
|
const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
|
|
@@ -12801,15 +13362,15 @@ function applySessionOverrides(params) {
|
|
|
12801
13362
|
metadata[CHILD_SESSION_LIFECYCLE_METADATA_KEY] = lifecycle;
|
|
12802
13363
|
if (parentSessionId) metadata[CHILD_SESSION_PARENT_METADATA_KEY] = parentSessionId;
|
|
12803
13364
|
if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
|
|
12804
|
-
if (readOptionalString$
|
|
13365
|
+
if (readOptionalString$8(model)) {
|
|
12805
13366
|
metadata.model = model?.trim();
|
|
12806
13367
|
metadata.preferred_model = model?.trim();
|
|
12807
13368
|
}
|
|
12808
|
-
if (readOptionalString$
|
|
13369
|
+
if (readOptionalString$8(thinkingLevel)) {
|
|
12809
13370
|
metadata.thinking = thinkingLevel?.trim();
|
|
12810
13371
|
metadata.preferred_thinking = thinkingLevel?.trim();
|
|
12811
13372
|
}
|
|
12812
|
-
if (readOptionalString$
|
|
13373
|
+
if (readOptionalString$8(projectRoot)) metadata.project_root = projectRoot?.trim();
|
|
12813
13374
|
}
|
|
12814
13375
|
//#endregion
|
|
12815
13376
|
//#region src/app/kernel-storage-paths.ts
|
|
@@ -13651,9 +14212,10 @@ var McpServiceAppRuntimeService = class {
|
|
|
13651
14212
|
//#region src/services/portable-service-runner-client.service.ts
|
|
13652
14213
|
const PORTABLE_RUNNER_PROTOCOL_VERSION = "0.1.0";
|
|
13653
14214
|
var PortableServiceRunnerError = class extends Error {
|
|
13654
|
-
constructor(code, message) {
|
|
14215
|
+
constructor(code, message, details) {
|
|
13655
14216
|
super(message);
|
|
13656
14217
|
this.code = code;
|
|
14218
|
+
this.details = details;
|
|
13657
14219
|
this.name = "PortableServiceRunnerError";
|
|
13658
14220
|
}
|
|
13659
14221
|
};
|
|
@@ -13661,6 +14223,7 @@ var PortableServiceRunnerClientService = class {
|
|
|
13661
14223
|
child;
|
|
13662
14224
|
pending = /* @__PURE__ */ new Map();
|
|
13663
14225
|
stderrTail = [];
|
|
14226
|
+
lastObservation;
|
|
13664
14227
|
constructor(params = {}) {
|
|
13665
14228
|
this.params = params;
|
|
13666
14229
|
}
|
|
@@ -13690,6 +14253,7 @@ var PortableServiceRunnerClientService = class {
|
|
|
13690
14253
|
input: event
|
|
13691
14254
|
}, 7e3);
|
|
13692
14255
|
stats = async () => this.request({ operation: "stats" }, 2e3);
|
|
14256
|
+
getLastObservation = () => this.lastObservation;
|
|
13693
14257
|
stop = async (app) => {
|
|
13694
14258
|
await this.request({
|
|
13695
14259
|
operation: "stop",
|
|
@@ -13736,7 +14300,10 @@ var PortableServiceRunnerClientService = class {
|
|
|
13736
14300
|
this.pending.set(requestId, {
|
|
13737
14301
|
resolve: (value) => resolve(value),
|
|
13738
14302
|
reject,
|
|
13739
|
-
timeout
|
|
14303
|
+
timeout,
|
|
14304
|
+
startedAt: Date.now(),
|
|
14305
|
+
operation: request.operation,
|
|
14306
|
+
appId: request.app?.id
|
|
13740
14307
|
});
|
|
13741
14308
|
child.stdin.write(`${JSON.stringify(payload)}\n`, (error) => {
|
|
13742
14309
|
if (!error) return;
|
|
@@ -13799,11 +14366,23 @@ var PortableServiceRunnerClientService = class {
|
|
|
13799
14366
|
if (!pending) return;
|
|
13800
14367
|
clearTimeout(pending.timeout);
|
|
13801
14368
|
this.pending.delete(response.requestId);
|
|
14369
|
+
const childPid = this.child?.pid ?? null;
|
|
14370
|
+
this.lastObservation = {
|
|
14371
|
+
operation: pending.operation,
|
|
14372
|
+
appId: pending.appId,
|
|
14373
|
+
durationMs: Date.now() - pending.startedAt,
|
|
14374
|
+
runnerPid: childPid,
|
|
14375
|
+
memory: childPid === null ? {
|
|
14376
|
+
rssBytes: null,
|
|
14377
|
+
pssBytes: null
|
|
14378
|
+
} : readExtensionProcessMemory(childPid),
|
|
14379
|
+
logs: [...this.stderrTail]
|
|
14380
|
+
};
|
|
13802
14381
|
if (response.ok) {
|
|
13803
14382
|
pending.resolve(response.result);
|
|
13804
14383
|
return;
|
|
13805
14384
|
}
|
|
13806
|
-
pending.reject(new PortableServiceRunnerError(response.error?.code ?? "PORTABLE_RUNTIME_FAILED", response.error?.message ?? "Portable runner request failed."));
|
|
14385
|
+
pending.reject(new PortableServiceRunnerError(response.error?.code ?? "PORTABLE_RUNTIME_FAILED", response.error?.message ?? "Portable runner request failed.", this.stderrTail.length > 0 ? { logs: [...this.stderrTail] } : void 0));
|
|
13807
14386
|
};
|
|
13808
14387
|
handleChildFailure = (error) => {
|
|
13809
14388
|
this.failAll(error);
|
|
@@ -13855,13 +14434,14 @@ var PortableServiceAppRuntimeService = class {
|
|
|
13855
14434
|
});
|
|
13856
14435
|
}
|
|
13857
14436
|
getStatus = (appId) => this.states.get(appId) ?? { status: "idle" };
|
|
14437
|
+
getLastObservation = () => this.runner.getLastObservation();
|
|
13858
14438
|
start = async ({ app, manifest }) => {
|
|
13859
14439
|
if (!app.enabled || !manifest.lifecycle || manifest.lifecycle.mode === "action") return;
|
|
13860
14440
|
this.persistentRegistrations.set(app.id, {
|
|
13861
14441
|
app,
|
|
13862
14442
|
manifest
|
|
13863
14443
|
});
|
|
13864
|
-
const runnerApp = this.toRunnerApp(app,
|
|
14444
|
+
const runnerApp = this.toRunnerApp(app, app.providerIds);
|
|
13865
14445
|
this.apps.set(app.id, runnerApp);
|
|
13866
14446
|
if (manifest.lifecycle.mode === "provider") {
|
|
13867
14447
|
if (this.providers.has(app.id)) return;
|
|
@@ -13918,7 +14498,7 @@ var PortableServiceAppRuntimeService = class {
|
|
|
13918
14498
|
};
|
|
13919
14499
|
listActions = async ({ app, manifest }) => {
|
|
13920
14500
|
if (!app.enabled) return [];
|
|
13921
|
-
const runnerApp = this.toRunnerApp(app,
|
|
14501
|
+
const runnerApp = this.toRunnerApp(app, app.providerIds);
|
|
13922
14502
|
this.apps.set(app.id, runnerApp);
|
|
13923
14503
|
const persistent = manifest.lifecycle?.mode === "resident" || manifest.lifecycle?.mode === "provider";
|
|
13924
14504
|
const lastStartedAt = persistent ? this.states.get(app.id)?.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -13956,7 +14536,7 @@ var PortableServiceAppRuntimeService = class {
|
|
|
13956
14536
|
app,
|
|
13957
14537
|
manifest
|
|
13958
14538
|
});
|
|
13959
|
-
const runnerApp = this.toRunnerApp(app,
|
|
14539
|
+
const runnerApp = this.toRunnerApp(app, app.providerIds);
|
|
13960
14540
|
this.apps.set(app.id, runnerApp);
|
|
13961
14541
|
if (manifest.lifecycle?.mode === "resident") try {
|
|
13962
14542
|
return await this.runner.invoke(runnerApp, actionName, input, manifest.actions[actionName]?.timeoutMs ?? 7e3);
|
|
@@ -14083,6 +14663,7 @@ var ServiceAppRuntimeService = class {
|
|
|
14083
14663
|
getStatus = (appId) => {
|
|
14084
14664
|
return this.protocols.get(appId) === "wasi-component" ? this.portable.getStatus(appId) : this.mcp.getStatus(appId);
|
|
14085
14665
|
};
|
|
14666
|
+
getLastObservation = () => this.portable.getLastObservation();
|
|
14086
14667
|
start = async (call) => {
|
|
14087
14668
|
this.protocols.set(call.app.id, call.manifest.protocol);
|
|
14088
14669
|
if (call.manifest.protocol === "wasi-component") await this.portable.start(call);
|
|
@@ -14108,128 +14689,6 @@ var ServiceAppRuntimeService = class {
|
|
|
14108
14689
|
};
|
|
14109
14690
|
};
|
|
14110
14691
|
//#endregion
|
|
14111
|
-
//#region src/utils/service-app-manifest.utils.ts
|
|
14112
|
-
const SERVICE_APP_ID_PATTERN$1 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
14113
|
-
const SERVICE_ACTION_RISKS = new Set([
|
|
14114
|
-
"read",
|
|
14115
|
-
"write",
|
|
14116
|
-
"external",
|
|
14117
|
-
"dangerous"
|
|
14118
|
-
]);
|
|
14119
|
-
const SERVICE_APP_MANIFEST_FILE_NAME = "service-app.json";
|
|
14120
|
-
function getServiceAppManifestPath(dirPath) {
|
|
14121
|
-
return join(dirPath, SERVICE_APP_MANIFEST_FILE_NAME);
|
|
14122
|
-
}
|
|
14123
|
-
async function readServiceAppManifest(dirPath, options) {
|
|
14124
|
-
return parseServiceAppManifest(await readFile(getServiceAppManifestPath(dirPath), "utf8"), options);
|
|
14125
|
-
}
|
|
14126
|
-
function parseServiceAppManifest(raw, options = {}) {
|
|
14127
|
-
let parsed;
|
|
14128
|
-
try {
|
|
14129
|
-
parsed = JSON.parse(raw);
|
|
14130
|
-
} catch (error) {
|
|
14131
|
-
throw new Error(`service-app.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
14132
|
-
}
|
|
14133
|
-
if (!isRecord$7(parsed)) throw new Error("service-app.json must contain an object.");
|
|
14134
|
-
const id = readRequiredString$6(parsed, "id");
|
|
14135
|
-
if (!SERVICE_APP_ID_PATTERN$1.test(id)) throw new Error("service app id must be kebab-case.");
|
|
14136
|
-
const protocol = readOptionalString$8(parsed, "protocol") ?? "mcp";
|
|
14137
|
-
if (protocol !== "mcp" && protocol !== "wasi-component") throw new Error("service app protocol must be mcp or wasi-component.");
|
|
14138
|
-
const launch = protocol === "mcp" ? new AppServiceLaunchService(options.platformTargetService).resolve(parsed, options.target) : void 0;
|
|
14139
|
-
const componentEntry = protocol === "wasi-component" ? readPortableComponentEntry(parsed) : void 0;
|
|
14140
|
-
const lifecycle = readServiceAppLifecycle(parsed.lifecycle);
|
|
14141
|
-
if (lifecycle.mode !== "action" && protocol !== "wasi-component") throw new Error(`${lifecycle.mode} service app lifecycle requires wasi-component protocol.`);
|
|
14142
|
-
return {
|
|
14143
|
-
id,
|
|
14144
|
-
title: readRequiredString$6(parsed, "title"),
|
|
14145
|
-
description: readOptionalString$8(parsed, "description"),
|
|
14146
|
-
enabled: readOptionalBoolean$1(parsed, "enabled") ?? true,
|
|
14147
|
-
protocol,
|
|
14148
|
-
command: launch?.command,
|
|
14149
|
-
args: launch?.args,
|
|
14150
|
-
componentEntry,
|
|
14151
|
-
providerIds: readProviderIds(parsed.providers),
|
|
14152
|
-
lifecycle,
|
|
14153
|
-
actions: readManifestActions(parsed.actions)
|
|
14154
|
-
};
|
|
14155
|
-
}
|
|
14156
|
-
function readServiceAppLifecycle(value) {
|
|
14157
|
-
if (value === void 0) return { mode: "action" };
|
|
14158
|
-
if (!isRecord$7(value)) throw new Error("service app lifecycle must be an object.");
|
|
14159
|
-
const mode = readOptionalString$8(value, "mode") ?? "action";
|
|
14160
|
-
if (mode === "action") return { mode };
|
|
14161
|
-
if (mode === "provider") return { mode };
|
|
14162
|
-
if (mode !== "resident") throw new Error("service app lifecycle.mode must be action, resident or provider.");
|
|
14163
|
-
const eventIntervalMs = readOptionalNumber(value, "eventIntervalMs");
|
|
14164
|
-
if (eventIntervalMs === void 0 || !Number.isInteger(eventIntervalMs) || eventIntervalMs < 250 || eventIntervalMs > 6e4) throw new Error("resident service app lifecycle.eventIntervalMs must be an integer between 250 and 60000.");
|
|
14165
|
-
return {
|
|
14166
|
-
mode,
|
|
14167
|
-
eventIntervalMs
|
|
14168
|
-
};
|
|
14169
|
-
}
|
|
14170
|
-
function readProviderIds(value) {
|
|
14171
|
-
if (value === void 0) return [];
|
|
14172
|
-
if (!Array.isArray(value)) throw new Error("service app providers must be an array.");
|
|
14173
|
-
const providerIds = value.map((entry) => {
|
|
14174
|
-
if (typeof entry !== "string" || !SERVICE_APP_ID_PATTERN$1.test(entry.trim())) throw new Error("service app providers must contain kebab-case service app ids.");
|
|
14175
|
-
return entry.trim();
|
|
14176
|
-
});
|
|
14177
|
-
return Array.from(new Set(providerIds));
|
|
14178
|
-
}
|
|
14179
|
-
function readPortableComponentEntry(record) {
|
|
14180
|
-
const component = record.component;
|
|
14181
|
-
if (!isRecord$7(component)) throw new Error("service app component is required for wasi-component.");
|
|
14182
|
-
const entry = readRequiredString$6(component, "entry").replace(/\\/g, "/");
|
|
14183
|
-
if (path.isAbsolute(entry) || entry.includes("\0") || entry.split("/").includes("..")) throw new Error("service app component.entry must be a package-relative path.");
|
|
14184
|
-
if (!entry.endsWith(".wasm")) throw new Error("service app component.entry must reference a .wasm file.");
|
|
14185
|
-
return entry;
|
|
14186
|
-
}
|
|
14187
|
-
function readManifestActions(value) {
|
|
14188
|
-
if (value === void 0) throw new Error("service app actions are required.");
|
|
14189
|
-
if (!isRecord$7(value)) throw new Error("service app actions must be an object.");
|
|
14190
|
-
if (Object.keys(value).length === 0) throw new Error("service app actions cannot be empty.");
|
|
14191
|
-
const actions = {};
|
|
14192
|
-
for (const [name, action] of Object.entries(value)) {
|
|
14193
|
-
if (!name.trim()) throw new Error("service app action name cannot be empty.");
|
|
14194
|
-
if (!isRecord$7(action)) throw new Error(`service app action ${name} must be an object.`);
|
|
14195
|
-
const risk = readOptionalString$8(action, "risk");
|
|
14196
|
-
if (risk !== void 0 && !SERVICE_ACTION_RISKS.has(risk)) throw new Error(`service app action ${name} has invalid risk.`);
|
|
14197
|
-
const inputSchema = action.inputSchema;
|
|
14198
|
-
if (inputSchema !== void 0 && !isRecord$7(inputSchema)) throw new Error(`service app action ${name} inputSchema must be an object.`);
|
|
14199
|
-
const timeoutMs = readOptionalNumber(action, "timeoutMs");
|
|
14200
|
-
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.`);
|
|
14201
|
-
actions[name] = {
|
|
14202
|
-
risk,
|
|
14203
|
-
title: readOptionalString$8(action, "title"),
|
|
14204
|
-
description: readOptionalString$8(action, "description"),
|
|
14205
|
-
inputSchema,
|
|
14206
|
-
timeoutMs
|
|
14207
|
-
};
|
|
14208
|
-
}
|
|
14209
|
-
return actions;
|
|
14210
|
-
}
|
|
14211
|
-
function readRequiredString$6(record, key) {
|
|
14212
|
-
const value = readOptionalString$8(record, key);
|
|
14213
|
-
if (!value) throw new Error(`service app ${key} is required.`);
|
|
14214
|
-
return value;
|
|
14215
|
-
}
|
|
14216
|
-
function readOptionalString$8(record, key) {
|
|
14217
|
-
return typeof record[key] === "string" && record[key].trim() ? record[key].trim() : void 0;
|
|
14218
|
-
}
|
|
14219
|
-
function readOptionalBoolean$1(record, key) {
|
|
14220
|
-
if (record[key] === void 0) return;
|
|
14221
|
-
if (typeof record[key] !== "boolean") throw new Error(`service app ${key} must be boolean.`);
|
|
14222
|
-
return record[key];
|
|
14223
|
-
}
|
|
14224
|
-
function readOptionalNumber(record, key) {
|
|
14225
|
-
if (record[key] === void 0) return;
|
|
14226
|
-
if (typeof record[key] !== "number") throw new Error(`service app ${key} must be number.`);
|
|
14227
|
-
return record[key];
|
|
14228
|
-
}
|
|
14229
|
-
function isRecord$7(value) {
|
|
14230
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
14231
|
-
}
|
|
14232
|
-
//#endregion
|
|
14233
14692
|
//#region src/services/service-app-lifecycle.service.ts
|
|
14234
14693
|
var ServiceAppLifecycleService = class {
|
|
14235
14694
|
constructor(params) {
|
|
@@ -14349,7 +14808,7 @@ var ServiceAppRecordService = class {
|
|
|
14349
14808
|
runtimeProfile: packageSource?.runtimeProfile ?? "native-process",
|
|
14350
14809
|
permissions: packageSource?.permissions ?? {},
|
|
14351
14810
|
componentPath: manifest.componentEntry ? join(dirPath, manifest.componentEntry) : void 0,
|
|
14352
|
-
providerIds: manifest.providerIds,
|
|
14811
|
+
providerIds: Array.from(new Set([...manifest.providerIds ?? [], ...packageSource?.resolvedProviderIds ?? []])),
|
|
14353
14812
|
lifecycle: manifest.lifecycle
|
|
14354
14813
|
};
|
|
14355
14814
|
};
|
|
@@ -14646,6 +15105,24 @@ var ServiceAppPackageRuntimeService = class {
|
|
|
14646
15105
|
};
|
|
14647
15106
|
};
|
|
14648
15107
|
//#endregion
|
|
15108
|
+
//#region src/services/service-app-capability-provider.service.ts
|
|
15109
|
+
function projectCapabilityProviders(entries) {
|
|
15110
|
+
return entries.flatMap(({ manifest, record }) => {
|
|
15111
|
+
if (manifest.lifecycle?.mode !== "provider" || !record.enabled || record.status !== "running") return [];
|
|
15112
|
+
const capabilities = manifest.provides?.capabilities ?? [];
|
|
15113
|
+
return capabilities.length === 0 ? [] : [{
|
|
15114
|
+
providerId: record.id,
|
|
15115
|
+
appId: record.packageId ?? record.id,
|
|
15116
|
+
componentId: record.id,
|
|
15117
|
+
capabilities: capabilities.map(({ id, version, resourceTypes }) => ({
|
|
15118
|
+
id,
|
|
15119
|
+
version,
|
|
15120
|
+
resourceTypes
|
|
15121
|
+
}))
|
|
15122
|
+
}];
|
|
15123
|
+
});
|
|
15124
|
+
}
|
|
15125
|
+
//#endregion
|
|
14649
15126
|
//#region src/utils/service-app-runtime-action.utils.ts
|
|
14650
15127
|
function listServiceAppManifestActions(record, manifest) {
|
|
14651
15128
|
if (!record.enabled) return [];
|
|
@@ -14736,6 +15213,7 @@ var ServiceAppManager = class {
|
|
|
14736
15213
|
entries: [...workspaceEntries, ...packageEntries].filter((entry) => Boolean(entry)).sort((left, right) => left.title.localeCompare(right.title))
|
|
14737
15214
|
};
|
|
14738
15215
|
};
|
|
15216
|
+
listCapabilityProviders = async () => projectCapabilityProviders(await this.listValidServiceApps());
|
|
14739
15217
|
getServiceApp = async (appId) => {
|
|
14740
15218
|
const { record } = await this.requireServiceApp(appId);
|
|
14741
15219
|
return record;
|
|
@@ -14775,7 +15253,7 @@ var ServiceAppManager = class {
|
|
|
14775
15253
|
})
|
|
14776
15254
|
};
|
|
14777
15255
|
} catch (error) {
|
|
14778
|
-
throw
|
|
15256
|
+
throw toServiceAppRuntimeError(error, record.id, actionName);
|
|
14779
15257
|
}
|
|
14780
15258
|
};
|
|
14781
15259
|
grantServiceAction = async (actionId, request) => {
|
|
@@ -14995,7 +15473,7 @@ function hasToolCall(message, toolCallId) {
|
|
|
14995
15473
|
return message.parts.some((part) => part.type === "tool-invocation" && part.toolCallId === toolCallId);
|
|
14996
15474
|
}
|
|
14997
15475
|
function findContextInheritanceAnchor(params) {
|
|
14998
|
-
const anchorToolCallId = readOptionalString$
|
|
15476
|
+
const anchorToolCallId = readOptionalString$8(params.anchorToolCallId);
|
|
14999
15477
|
if (!anchorToolCallId) return null;
|
|
15000
15478
|
const index = params.messages.findIndex((message) => hasToolCall(message, anchorToolCallId));
|
|
15001
15479
|
const message = index >= 0 ? params.messages[index] : void 0;
|
|
@@ -15035,7 +15513,7 @@ function createInheritedContextSnapshot(params) {
|
|
|
15035
15513
|
enabled: true,
|
|
15036
15514
|
sourceSessionId: sourceRecord.sessionId,
|
|
15037
15515
|
anchorKind: anchor ? "tool_call" : "latest_persisted",
|
|
15038
|
-
anchorToolCallId: readOptionalString$
|
|
15516
|
+
anchorToolCallId: readOptionalString$8(anchorToolCallId),
|
|
15039
15517
|
anchorMessageId: anchor?.message.id,
|
|
15040
15518
|
inheritedMessageCount: messages.length
|
|
15041
15519
|
}
|
|
@@ -15323,7 +15801,7 @@ var SessionWorkingDirResolver = class {
|
|
|
15323
15801
|
return this.resolveContext(params).effectiveWorkspace;
|
|
15324
15802
|
};
|
|
15325
15803
|
resolveContext = (params) => {
|
|
15326
|
-
const profile = this.agentManager.resolveAgentProfile(readOptionalString$
|
|
15804
|
+
const profile = this.agentManager.resolveAgentProfile(readOptionalString$8(params.agentId));
|
|
15327
15805
|
return resolveSessionProjectContext({
|
|
15328
15806
|
sessionMetadata: params.metadata,
|
|
15329
15807
|
workspace: profile.workspace
|
|
@@ -15371,10 +15849,10 @@ var SessionManager = class {
|
|
|
15371
15849
|
const { agentId: requestedAgentId, contextInheritance, metadataOverrides, model, parentSessionId: rawParentSessionId, projectRoot, requestId: rawRequestId, runtime, sessionId: requestedSessionId, sessionType: requestedSessionType, sourceSessionId, sourceSessionMetadata, task, thinkingLevel, title: requestedTitle } = params;
|
|
15372
15850
|
const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
|
|
15373
15851
|
const metadata = cloneInheritedMetadata(sourceSessionMetadata);
|
|
15374
|
-
const title = readOptionalString$
|
|
15375
|
-
const parentSessionId = readOptionalString$
|
|
15852
|
+
const title = readOptionalString$8(requestedTitle) ?? summarizeTask(task);
|
|
15853
|
+
const parentSessionId = readOptionalString$8(rawParentSessionId);
|
|
15376
15854
|
await assertCanCreateSessionFromLineage(parentSessionId, sourceRecord, metadataOverrides, this.getSessionRecord);
|
|
15377
|
-
const requestId = readOptionalString$
|
|
15855
|
+
const requestId = readOptionalString$8(rawRequestId);
|
|
15378
15856
|
const sessionType = resolveSessionType({
|
|
15379
15857
|
runtime,
|
|
15380
15858
|
sessionType: requestedSessionType,
|
|
@@ -15400,8 +15878,8 @@ var SessionManager = class {
|
|
|
15400
15878
|
if (normalizedProjectRoot) nextMetadata.project_root = normalizedProjectRoot;
|
|
15401
15879
|
else delete nextMetadata.project_root;
|
|
15402
15880
|
}
|
|
15403
|
-
const agentId = readOptionalString$
|
|
15404
|
-
const sessionId = readOptionalString$
|
|
15881
|
+
const agentId = readOptionalString$8(requestedAgentId) ?? readOptionalString$8(sourceRecord?.agentId) ?? BUILTIN_MAIN_AGENT_ID;
|
|
15882
|
+
const sessionId = readOptionalString$8(requestedSessionId) ?? buildSessionId();
|
|
15405
15883
|
const inheritedContext = createSessionContextInheritance({
|
|
15406
15884
|
childSessionId: sessionId,
|
|
15407
15885
|
contextInheritance,
|
|
@@ -15487,7 +15965,7 @@ var SessionManager = class {
|
|
|
15487
15965
|
listSessions = async (options) => {
|
|
15488
15966
|
const { limit, peerId: rawPeerId } = options ?? {};
|
|
15489
15967
|
const { journalStore } = this.options;
|
|
15490
|
-
const peerId = readOptionalString$
|
|
15968
|
+
const peerId = readOptionalString$8(rawPeerId);
|
|
15491
15969
|
const summaryReadOptions = !peerId && limit !== void 0 ? { limit } : void 0;
|
|
15492
15970
|
return applyLimit((await journalStore.listSessionSummaries(summaryReadOptions)).filter((summary) => !peerId || summary.peerId === peerId).map(this.workingDirResolver.withWorkingDir), limit);
|
|
15493
15971
|
};
|
|
@@ -15546,9 +16024,9 @@ var SessionManager = class {
|
|
|
15546
16024
|
};
|
|
15547
16025
|
createAgentRunSession = async (params) => {
|
|
15548
16026
|
const { agentId, agentRuntimeId: requestedAgentRuntimeId, channel, contextInheritance, metadata, model, parentSessionId: rawParentSessionId, peerId: rawPeerId, projectRoot, sessionId, sourceSessionId: rawSourceSessionId, sourceSessionMetadata: requestedSourceSessionMetadata, task, thinkingEffort } = params;
|
|
15549
|
-
const peerId = readOptionalString$
|
|
15550
|
-
const parentSessionId = readOptionalString$
|
|
15551
|
-
const sourceSessionId = readOptionalString$
|
|
16027
|
+
const peerId = readOptionalString$8(rawPeerId);
|
|
16028
|
+
const parentSessionId = readOptionalString$8(rawParentSessionId);
|
|
16029
|
+
const sourceSessionId = readOptionalString$8(rawSourceSessionId);
|
|
15552
16030
|
const sourceRecord = sourceSessionId ? await this.getSessionRecord(sourceSessionId) : null;
|
|
15553
16031
|
const sourceSessionMetadata = requestedSourceSessionMetadata ?? sourceRecord?.metadata ?? {};
|
|
15554
16032
|
const agentRuntimeId = requestedAgentRuntimeId ?? readAgentRuntimeId(sourceSessionMetadata) ?? "native";
|
|
@@ -15558,7 +16036,7 @@ var SessionManager = class {
|
|
|
15558
16036
|
metadata,
|
|
15559
16037
|
peerId
|
|
15560
16038
|
}) : void 0;
|
|
15561
|
-
const requestedSessionId = readOptionalString$
|
|
16039
|
+
const requestedSessionId = readOptionalString$8(sessionId);
|
|
15562
16040
|
const created = await this.createSession({
|
|
15563
16041
|
contextInheritance,
|
|
15564
16042
|
parentSessionId: parentSessionId ?? void 0,
|
|
@@ -17149,7 +17627,7 @@ function deduplicateNcpAgentSessionTailMessages(messages) {
|
|
|
17149
17627
|
function isNcpAgentSessionMessageProjectionMeta(value, sessionId) {
|
|
17150
17628
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
17151
17629
|
const meta = value;
|
|
17152
|
-
return meta.version === 7 && meta.sessionId === sessionId && Number.isSafeInteger(meta.total) && Number.isSafeInteger(meta.projectedJournalOffset) && Number.isSafeInteger(meta.dataBytes) && (meta.activeMessageId === null || typeof meta.activeMessageId === "string") && Array.isArray(meta.pendingCompactionMessageIds) && meta.pendingCompactionMessageIds.every((id) => typeof id === "string") && (meta.contextWindow === null || isRecord$
|
|
17630
|
+
return meta.version === 7 && meta.sessionId === sessionId && Number.isSafeInteger(meta.total) && Number.isSafeInteger(meta.projectedJournalOffset) && Number.isSafeInteger(meta.dataBytes) && (meta.activeMessageId === null || typeof meta.activeMessageId === "string") && Array.isArray(meta.pendingCompactionMessageIds) && meta.pendingCompactionMessageIds.every((id) => typeof id === "string") && (meta.contextWindow === null || isRecord$7(meta.contextWindow));
|
|
17153
17631
|
}
|
|
17154
17632
|
function readActiveAssistantMessageId(messages) {
|
|
17155
17633
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
@@ -17172,12 +17650,12 @@ function mergePendingCompactionMessageIds(current, messages) {
|
|
|
17172
17650
|
}
|
|
17173
17651
|
return pending;
|
|
17174
17652
|
}
|
|
17175
|
-
function isRecord$
|
|
17653
|
+
function isRecord$7(value) {
|
|
17176
17654
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17177
17655
|
}
|
|
17178
17656
|
function readCompactionStatus(message) {
|
|
17179
17657
|
const checkpoint = message.metadata?.checkpoint;
|
|
17180
|
-
if (message.metadata?.nextclaw_timeline_kind !== "context_compaction" || !isRecord$
|
|
17658
|
+
if (message.metadata?.nextclaw_timeline_kind !== "context_compaction" || !isRecord$7(checkpoint)) return null;
|
|
17181
17659
|
return typeof checkpoint.status === "string" ? checkpoint.status : null;
|
|
17182
17660
|
}
|
|
17183
17661
|
//#endregion
|
|
@@ -17685,6 +18163,151 @@ async function readLegacyRecords(journalDir, diagnostics) {
|
|
|
17685
18163
|
return /* @__PURE__ */ new Map();
|
|
17686
18164
|
}
|
|
17687
18165
|
//#endregion
|
|
18166
|
+
//#region src/stores/ncp-session-catalog-sqlite-driver.store.ts
|
|
18167
|
+
const require = createRequire(import.meta.url);
|
|
18168
|
+
const portableDatabases = /* @__PURE__ */ new Map();
|
|
18169
|
+
async function openSessionCatalogSqliteDatabase(databasePath) {
|
|
18170
|
+
try {
|
|
18171
|
+
return new (require("node:sqlite")).DatabaseSync(databasePath);
|
|
18172
|
+
} catch (error) {
|
|
18173
|
+
if (!isMissingNodeSqlite(error)) throw error;
|
|
18174
|
+
return await openPortableDatabase(databasePath);
|
|
18175
|
+
}
|
|
18176
|
+
}
|
|
18177
|
+
function runSessionCatalogSqliteTransaction(database, operation, mode = "DEFERRED") {
|
|
18178
|
+
database.exec(`BEGIN ${mode}`);
|
|
18179
|
+
try {
|
|
18180
|
+
const result = operation();
|
|
18181
|
+
database.exec("COMMIT");
|
|
18182
|
+
return result;
|
|
18183
|
+
} catch (error) {
|
|
18184
|
+
database.exec("ROLLBACK");
|
|
18185
|
+
throw error;
|
|
18186
|
+
}
|
|
18187
|
+
}
|
|
18188
|
+
function isMissingNodeSqlite(error) {
|
|
18189
|
+
const code = typeof error === "object" && error !== null ? error.code : void 0;
|
|
18190
|
+
return code === "ERR_UNKNOWN_BUILTIN_MODULE" || code === "MODULE_NOT_FOUND";
|
|
18191
|
+
}
|
|
18192
|
+
async function openPortableDatabase(databasePath) {
|
|
18193
|
+
const existing = portableDatabases.get(databasePath);
|
|
18194
|
+
if (existing) return (await existing).acquire();
|
|
18195
|
+
const opening = createPortableDatabase(databasePath).catch((error) => {
|
|
18196
|
+
portableDatabases.delete(databasePath);
|
|
18197
|
+
throw error;
|
|
18198
|
+
});
|
|
18199
|
+
portableDatabases.set(databasePath, opening);
|
|
18200
|
+
return (await opening).acquire();
|
|
18201
|
+
}
|
|
18202
|
+
async function createPortableDatabase(databasePath) {
|
|
18203
|
+
const initialize = (await import("sql.js")).default;
|
|
18204
|
+
const sqlite = await initialize({ locateFile: (file) => require.resolve(`sql.js/dist/${file}`) });
|
|
18205
|
+
return new PortableSessionCatalogSqliteDatabase(databasePath, existsSync(databasePath) ? new sqlite.Database(readFileSync(databasePath)) : new sqlite.Database());
|
|
18206
|
+
}
|
|
18207
|
+
var PortableSessionCatalogSqliteDatabase = class {
|
|
18208
|
+
inTransaction = false;
|
|
18209
|
+
dirty = false;
|
|
18210
|
+
leaseCount = 0;
|
|
18211
|
+
constructor(databasePath, database) {
|
|
18212
|
+
this.databasePath = databasePath;
|
|
18213
|
+
this.database = database;
|
|
18214
|
+
}
|
|
18215
|
+
acquire = () => {
|
|
18216
|
+
this.leaseCount += 1;
|
|
18217
|
+
return new PortableSessionCatalogSqliteLease(this);
|
|
18218
|
+
};
|
|
18219
|
+
exec = (sql) => {
|
|
18220
|
+
const command = sql.trim().toUpperCase();
|
|
18221
|
+
this.database.run(sql);
|
|
18222
|
+
if (command.startsWith("BEGIN")) {
|
|
18223
|
+
this.inTransaction = true;
|
|
18224
|
+
return;
|
|
18225
|
+
}
|
|
18226
|
+
if (command.startsWith("ROLLBACK")) {
|
|
18227
|
+
this.inTransaction = false;
|
|
18228
|
+
this.dirty = false;
|
|
18229
|
+
return;
|
|
18230
|
+
}
|
|
18231
|
+
if (command.startsWith("COMMIT")) {
|
|
18232
|
+
this.inTransaction = false;
|
|
18233
|
+
this.persistIfDirty();
|
|
18234
|
+
return;
|
|
18235
|
+
}
|
|
18236
|
+
if (!command.startsWith("PRAGMA")) this.markDirty();
|
|
18237
|
+
};
|
|
18238
|
+
prepare = (sql) => new PortableSessionCatalogSqliteStatement(this, sql);
|
|
18239
|
+
release = () => {
|
|
18240
|
+
this.leaseCount -= 1;
|
|
18241
|
+
if (this.leaseCount > 0) return;
|
|
18242
|
+
this.persistIfDirty();
|
|
18243
|
+
this.database.close();
|
|
18244
|
+
portableDatabases.delete(this.databasePath);
|
|
18245
|
+
};
|
|
18246
|
+
run = (sql, params) => {
|
|
18247
|
+
this.database.run(sql, normalizeParams(params));
|
|
18248
|
+
this.markDirty();
|
|
18249
|
+
};
|
|
18250
|
+
readRows = (sql, params) => {
|
|
18251
|
+
const statement = this.database.prepare(sql);
|
|
18252
|
+
try {
|
|
18253
|
+
bindStatement(statement, params);
|
|
18254
|
+
const rows = [];
|
|
18255
|
+
while (statement.step()) rows.push(statement.getAsObject());
|
|
18256
|
+
return rows;
|
|
18257
|
+
} finally {
|
|
18258
|
+
statement.free();
|
|
18259
|
+
}
|
|
18260
|
+
};
|
|
18261
|
+
markDirty = () => {
|
|
18262
|
+
this.dirty = true;
|
|
18263
|
+
if (!this.inTransaction) this.persistIfDirty();
|
|
18264
|
+
};
|
|
18265
|
+
persistIfDirty = () => {
|
|
18266
|
+
if (!this.dirty) return;
|
|
18267
|
+
const temporaryPath = `${this.databasePath}.tmp`;
|
|
18268
|
+
writeFileSync(temporaryPath, this.database.export());
|
|
18269
|
+
renameSync(temporaryPath, this.databasePath);
|
|
18270
|
+
this.dirty = false;
|
|
18271
|
+
};
|
|
18272
|
+
};
|
|
18273
|
+
var PortableSessionCatalogSqliteLease = class {
|
|
18274
|
+
closed = false;
|
|
18275
|
+
constructor(owner) {
|
|
18276
|
+
this.owner = owner;
|
|
18277
|
+
}
|
|
18278
|
+
close = () => {
|
|
18279
|
+
if (this.closed) return;
|
|
18280
|
+
this.closed = true;
|
|
18281
|
+
this.owner.release();
|
|
18282
|
+
};
|
|
18283
|
+
exec = (sql) => this.owner.exec(sql);
|
|
18284
|
+
prepare = (sql) => this.owner.prepare(sql);
|
|
18285
|
+
};
|
|
18286
|
+
var PortableSessionCatalogSqliteStatement = class {
|
|
18287
|
+
constructor(database, sql) {
|
|
18288
|
+
this.database = database;
|
|
18289
|
+
this.sql = sql;
|
|
18290
|
+
}
|
|
18291
|
+
all = (...params) => this.database.readRows(this.sql, params);
|
|
18292
|
+
get = (...params) => this.all(...params)[0];
|
|
18293
|
+
run = (...params) => {
|
|
18294
|
+
this.database.run(this.sql, params);
|
|
18295
|
+
return {};
|
|
18296
|
+
};
|
|
18297
|
+
};
|
|
18298
|
+
function bindStatement(statement, params) {
|
|
18299
|
+
const normalized = normalizeParams(params);
|
|
18300
|
+
if (Array.isArray(normalized) && normalized.length === 0) return;
|
|
18301
|
+
statement.bind(normalized);
|
|
18302
|
+
}
|
|
18303
|
+
function normalizeParams(params) {
|
|
18304
|
+
if (params.length !== 1 || !isRecord$6(params[0])) return params;
|
|
18305
|
+
return Object.fromEntries(Object.entries(params[0]).map(([key, value]) => [`@${key}`, value]));
|
|
18306
|
+
}
|
|
18307
|
+
function isRecord$6(value) {
|
|
18308
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18309
|
+
}
|
|
18310
|
+
//#endregion
|
|
17688
18311
|
//#region src/stores/ncp-agent-session-summary-index.store.ts
|
|
17689
18312
|
const SQLITE_DATABASE_FILE = ".ncp-agent-session-catalog.sqlite";
|
|
17690
18313
|
const CATALOG_SCHEMA_VERSION = 1;
|
|
@@ -17786,16 +18409,17 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
17786
18409
|
};
|
|
17787
18410
|
upsertForEvent = async (params) => {
|
|
17788
18411
|
await this.ensureReady();
|
|
17789
|
-
const sessionId =
|
|
18412
|
+
const { sessionId: rawSessionId, event, updatedAt } = params;
|
|
18413
|
+
const sessionId = normalizeNcpSessionId(rawSessionId);
|
|
17790
18414
|
const currentRow = this.db().prepare("SELECT * FROM sessions WHERE session_id = ? LIMIT 1").get(sessionId);
|
|
17791
18415
|
const row = summaryToRow({
|
|
17792
18416
|
...upsertNcpAgentSessionSummaryEvent({
|
|
17793
18417
|
current: currentRow && currentRow.deleted_at === null ? rowToSummary(currentRow) : void 0,
|
|
17794
18418
|
sessionId,
|
|
17795
|
-
event
|
|
17796
|
-
updatedAt
|
|
18419
|
+
event,
|
|
18420
|
+
updatedAt
|
|
17797
18421
|
}),
|
|
17798
|
-
messageCount: readEventMessage(
|
|
18422
|
+
messageCount: readEventMessage(event) ? 1 : 0
|
|
17799
18423
|
});
|
|
17800
18424
|
this.db().prepare(`INSERT INTO sessions (
|
|
17801
18425
|
session_id, peer_id, agent_id, created_at, updated_at,
|
|
@@ -17823,7 +18447,7 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
17823
18447
|
await this.ensureReady();
|
|
17824
18448
|
const normalizedSessionId = normalizeNcpSessionId(sessionId);
|
|
17825
18449
|
const deletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
17826
|
-
this.db()
|
|
18450
|
+
runSessionCatalogSqliteTransaction(this.db(), () => {
|
|
17827
18451
|
if (this.db().prepare("SELECT session_id FROM sessions WHERE session_id = ? LIMIT 1").get(normalizedSessionId)) {
|
|
17828
18452
|
this.db().prepare("UPDATE sessions SET deleted_at = ? WHERE session_id = ?").run(deletedAt, normalizedSessionId);
|
|
17829
18453
|
return;
|
|
@@ -17832,7 +18456,7 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
17832
18456
|
session_id, created_at, updated_at, message_count,
|
|
17833
18457
|
status, metadata_json, deleted_at
|
|
17834
18458
|
) VALUES (?, ?, ?, 0, 'idle', '{}', ?)`).run(normalizedSessionId, deletedAt, deletedAt, deletedAt);
|
|
17835
|
-
})
|
|
18459
|
+
}, "IMMEDIATE");
|
|
17836
18460
|
};
|
|
17837
18461
|
close = () => {
|
|
17838
18462
|
this.database?.close();
|
|
@@ -17848,10 +18472,13 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
17848
18472
|
};
|
|
17849
18473
|
initializeCatalog = async () => {
|
|
17850
18474
|
await mkdir(this.journalDir, { recursive: true });
|
|
17851
|
-
this.database =
|
|
17852
|
-
this.database.
|
|
17853
|
-
|
|
17854
|
-
|
|
18475
|
+
this.database = await openSessionCatalogSqliteDatabase(resolve(this.journalDir, SQLITE_DATABASE_FILE));
|
|
18476
|
+
this.database.exec(`
|
|
18477
|
+
PRAGMA busy_timeout = 10000;
|
|
18478
|
+
PRAGMA journal_mode = WAL;
|
|
18479
|
+
PRAGMA synchronous = NORMAL;
|
|
18480
|
+
PRAGMA foreign_keys = ON;
|
|
18481
|
+
`);
|
|
17855
18482
|
this.database.exec(`
|
|
17856
18483
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
17857
18484
|
session_id TEXT PRIMARY KEY,
|
|
@@ -17885,22 +18512,22 @@ var NcpAgentSessionSummaryIndexStore = class {
|
|
|
17885
18512
|
loadSession: (sessionId) => this.loadSession(sessionId),
|
|
17886
18513
|
loadSessionSummary: this.loadSessionSummary
|
|
17887
18514
|
});
|
|
17888
|
-
this.db()
|
|
18515
|
+
runSessionCatalogSqliteTransaction(this.db(), () => {
|
|
17889
18516
|
if (this.db().prepare("SELECT value FROM storage_meta WHERE key = ? LIMIT 1").get(MIGRATION_STATUS_KEY)?.value === MIGRATION_COMPLETE) {
|
|
17890
|
-
this.reconcileRecords(
|
|
18517
|
+
this.reconcileRecords(scan.records);
|
|
17891
18518
|
return;
|
|
17892
18519
|
}
|
|
17893
|
-
for (const record of
|
|
18520
|
+
for (const record of scan.records) {
|
|
17894
18521
|
if (this.db().prepare("SELECT deleted_at FROM sessions WHERE session_id = ? LIMIT 1").get(record.sessionId)?.deleted_at) continue;
|
|
17895
18522
|
this.writeSummary(summaryToRow(record), false);
|
|
17896
18523
|
}
|
|
17897
|
-
for (const diagnostic of
|
|
18524
|
+
for (const diagnostic of scan.diagnostics) this.db().prepare(`INSERT INTO migration_diagnostics (session_id, kind, detail_json, created_at)
|
|
17898
18525
|
VALUES (?, ?, ?, ?)`).run(diagnostic.sessionId ?? null, diagnostic.kind, JSON.stringify(diagnostic.detail), (/* @__PURE__ */ new Date()).toISOString());
|
|
17899
18526
|
this.db().prepare(`INSERT INTO storage_meta (key, value) VALUES (?, ?)
|
|
17900
18527
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(MIGRATION_STATUS_KEY, MIGRATION_COMPLETE);
|
|
17901
18528
|
this.db().prepare(`INSERT INTO storage_meta (key, value) VALUES ('schema_version', ?)
|
|
17902
18529
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(String(CATALOG_SCHEMA_VERSION));
|
|
17903
|
-
})
|
|
18530
|
+
}, "IMMEDIATE");
|
|
17904
18531
|
};
|
|
17905
18532
|
reconcileRecords = (records) => {
|
|
17906
18533
|
for (const record of records) if (!this.db().prepare("SELECT deleted_at FROM sessions WHERE session_id = ? LIMIT 1").get(record.sessionId)?.deleted_at) this.writeSummary(summaryToRow(record), false);
|
|
@@ -18293,14 +18920,14 @@ function readRecord(value) {
|
|
|
18293
18920
|
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
18294
18921
|
return value;
|
|
18295
18922
|
}
|
|
18296
|
-
function readString$
|
|
18923
|
+
function readString$5(value) {
|
|
18297
18924
|
if (typeof value !== "string") return;
|
|
18298
18925
|
return value.trim() || void 0;
|
|
18299
18926
|
}
|
|
18300
18927
|
function resolveRequestedModel(params) {
|
|
18301
18928
|
const { configuredModel, defaultModel, input, modelSelectionMode, sessionMetadata } = params;
|
|
18302
18929
|
if (modelSelectionMode === "runtime-default") return;
|
|
18303
|
-
const requestedModel = readString$
|
|
18930
|
+
const requestedModel = readString$5(readRecord(input.metadata)?.preferred_model) ?? readString$5(readRecord(input.metadata)?.preferredModel) ?? readString$5(readRecord(input.metadata)?.model) ?? readString$5(sessionMetadata.preferred_model) ?? readString$5(sessionMetadata.preferredModel) ?? readString$5(sessionMetadata.model);
|
|
18304
18931
|
if (isRuntimeDefaultModelValue(requestedModel)) return;
|
|
18305
18932
|
return requestedModel ?? configuredModel ?? (modelSelectionMode === "optional" ? void 0 : defaultModel);
|
|
18306
18933
|
}
|
|
@@ -18546,7 +19173,7 @@ var BuiltinNarpRuntimeProviderService = class {
|
|
|
18546
19173
|
input,
|
|
18547
19174
|
sessionMetadata: runtimeParams.sessionMetadata,
|
|
18548
19175
|
defaultModel: this.configManager.loadConfig().agents.defaults.model,
|
|
18549
|
-
configuredModel: readString$
|
|
19176
|
+
configuredModel: readString$5(config.model),
|
|
18550
19177
|
modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
|
|
18551
19178
|
})
|
|
18552
19179
|
});
|
|
@@ -18563,7 +19190,7 @@ var BuiltinNarpRuntimeProviderService = class {
|
|
|
18563
19190
|
input,
|
|
18564
19191
|
sessionMetadata: runtimeParams.sessionMetadata,
|
|
18565
19192
|
defaultModel: this.configManager.loadConfig().agents.defaults.model,
|
|
18566
|
-
configuredModel: readString$
|
|
19193
|
+
configuredModel: readString$5(config.model),
|
|
18567
19194
|
modelSelectionMode: normalizeRuntimeModelSelectionMode(config.modelSelectionMode)
|
|
18568
19195
|
})
|
|
18569
19196
|
});
|
|
@@ -19329,7 +19956,7 @@ const MAX_TOTAL_CONTEXT_CHARACTERS$1 = 96e3;
|
|
|
19329
19956
|
function isRecord$5(value) {
|
|
19330
19957
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
19331
19958
|
}
|
|
19332
|
-
function readString$
|
|
19959
|
+
function readString$4(value) {
|
|
19333
19960
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
19334
19961
|
}
|
|
19335
19962
|
function escapeAttribute$1(value) {
|
|
@@ -19342,10 +19969,10 @@ function readConversationExcerpts(metadata) {
|
|
|
19342
19969
|
const seen = /* @__PURE__ */ new Set();
|
|
19343
19970
|
for (const entry of entries) {
|
|
19344
19971
|
if (!isRecord$5(entry) || entry.kind !== CHAT_CONVERSATION_EXCERPT_TOKEN_KIND) continue;
|
|
19345
|
-
const key = readString$
|
|
19346
|
-
const messageId = readString$
|
|
19347
|
-
const label = readString$
|
|
19348
|
-
const excerpt = readString$
|
|
19972
|
+
const key = readString$4(entry.key);
|
|
19973
|
+
const messageId = readString$4(entry.messageId);
|
|
19974
|
+
const label = readString$4(entry.label);
|
|
19975
|
+
const excerpt = readString$4(entry.excerpt);
|
|
19349
19976
|
const role = entry.role;
|
|
19350
19977
|
if (!key || !messageId || !label || !excerpt || role !== "assistant" && role !== "user" || excerpt.length > MAX_EXCERPT_CHARACTERS$1 || seen.has(key)) continue;
|
|
19351
19978
|
seen.add(key);
|
|
@@ -20124,7 +20751,7 @@ var WorkspaceReferenceMaterializerService = class {
|
|
|
20124
20751
|
function isRecord$2(value) {
|
|
20125
20752
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
20126
20753
|
}
|
|
20127
|
-
function readString$
|
|
20754
|
+
function readString$3(value) {
|
|
20128
20755
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
20129
20756
|
}
|
|
20130
20757
|
function readLine(value) {
|
|
@@ -20139,19 +20766,19 @@ function readWorkspaceReferences(metadata) {
|
|
|
20139
20766
|
for (const rawToken of rawTokens) {
|
|
20140
20767
|
if (!isRecord$2(rawToken)) continue;
|
|
20141
20768
|
const kind = rawToken.kind === CHAT_WORKSPACE_FILE_TOKEN_KIND ? CHAT_WORKSPACE_FILE_TOKEN_KIND : rawToken.kind === CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND ? CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND : rawToken.kind === CHAT_WORKSPACE_EXCERPT_TOKEN_KIND ? CHAT_WORKSPACE_EXCERPT_TOKEN_KIND : rawToken.kind === CHAT_PROJECT_TOKEN_KIND ? CHAT_PROJECT_TOKEN_KIND : null;
|
|
20142
|
-
const key = readString$
|
|
20769
|
+
const key = readString$3(rawToken.key);
|
|
20143
20770
|
if (!kind || !key || seen.has(`${kind}:${key}`)) continue;
|
|
20144
20771
|
seen.add(`${kind}:${key}`);
|
|
20145
20772
|
if (kind === CHAT_WORKSPACE_EXCERPT_TOKEN_KIND) {
|
|
20146
|
-
const path = readString$
|
|
20147
|
-
const excerpt = readString$
|
|
20773
|
+
const path = readString$3(rawToken.path);
|
|
20774
|
+
const excerpt = readString$3(rawToken.excerpt);
|
|
20148
20775
|
if (!path || !excerpt) continue;
|
|
20149
20776
|
references.push({
|
|
20150
20777
|
kind,
|
|
20151
20778
|
key,
|
|
20152
20779
|
path,
|
|
20153
20780
|
excerpt,
|
|
20154
|
-
label: readString$
|
|
20781
|
+
label: readString$3(rawToken.label) ?? path,
|
|
20155
20782
|
startLine: readLine(rawToken.startLine),
|
|
20156
20783
|
endLine: readLine(rawToken.endLine)
|
|
20157
20784
|
});
|
|
@@ -20160,7 +20787,7 @@ function readWorkspaceReferences(metadata) {
|
|
|
20160
20787
|
references.push({
|
|
20161
20788
|
kind,
|
|
20162
20789
|
key,
|
|
20163
|
-
label: readString$
|
|
20790
|
+
label: readString$3(rawToken.label) ?? key
|
|
20164
20791
|
});
|
|
20165
20792
|
}
|
|
20166
20793
|
return references;
|
|
@@ -20763,7 +21390,7 @@ function toInt(value, fallback) {
|
|
|
20763
21390
|
const parsed = typeof value === "number" || typeof value === "string" ? Number(value) : NaN;
|
|
20764
21391
|
return Number.isFinite(parsed) ? Math.max(0, Math.trunc(parsed)) : fallback;
|
|
20765
21392
|
}
|
|
20766
|
-
function readString$
|
|
21393
|
+
function readString$2(value) {
|
|
20767
21394
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
20768
21395
|
}
|
|
20769
21396
|
function messageText(message) {
|
|
@@ -20791,7 +21418,7 @@ function capHistory(items) {
|
|
|
20791
21418
|
}];
|
|
20792
21419
|
}
|
|
20793
21420
|
function sessionLabel(summary) {
|
|
20794
|
-
return readString$
|
|
21421
|
+
return readString$2(summary.metadata?.label) ?? readString$2(summary.metadata?.session_label);
|
|
20795
21422
|
}
|
|
20796
21423
|
var SessionsListTool = class {
|
|
20797
21424
|
name = "sessions_list";
|
|
@@ -20820,7 +21447,7 @@ var SessionsListTool = class {
|
|
|
20820
21447
|
}
|
|
20821
21448
|
execute = async (args) => {
|
|
20822
21449
|
const { limit, messageLimit, sessionKey } = normalizeToolParams(args);
|
|
20823
|
-
const exactSessionKey = readString$
|
|
21450
|
+
const exactSessionKey = readString$2(sessionKey);
|
|
20824
21451
|
const summaries = exactSessionKey ? [await this.sessions.getSession(exactSessionKey)].filter((summary) => Boolean(summary)) : await this.sessions.listSessions();
|
|
20825
21452
|
const maxSessions = toInt(limit, DEFAULT_LIMIT);
|
|
20826
21453
|
const maxMessages = Math.min(toInt(messageLimit, 0), MAX_MESSAGE_LIMIT);
|
|
@@ -20869,7 +21496,7 @@ var SessionsHistoryTool = class {
|
|
|
20869
21496
|
}
|
|
20870
21497
|
execute = async (args) => {
|
|
20871
21498
|
const { includeTools, limit, sessionKey: rawSessionKey } = normalizeToolParams(args);
|
|
20872
|
-
const sessionKey = readString$
|
|
21499
|
+
const sessionKey = readString$2(rawSessionKey);
|
|
20873
21500
|
if (!sessionKey) return "Error: sessionKey is required";
|
|
20874
21501
|
const session = await this.resolveSession(sessionKey);
|
|
20875
21502
|
if (!session) return `Error: session '${sessionKey}' not found`;
|
|
@@ -22069,6 +22696,178 @@ function readInput(value) {
|
|
|
22069
22696
|
return value;
|
|
22070
22697
|
}
|
|
22071
22698
|
//#endregion
|
|
22699
|
+
//#region src/contributions/tool-provider/providers/app-package-dependency-tool.provider.ts
|
|
22700
|
+
const MUTATION_CONFIRMATION = {
|
|
22701
|
+
type: "object",
|
|
22702
|
+
properties: {
|
|
22703
|
+
appId: {
|
|
22704
|
+
type: "string",
|
|
22705
|
+
description: "Installed App id."
|
|
22706
|
+
},
|
|
22707
|
+
confirm: {
|
|
22708
|
+
type: "boolean",
|
|
22709
|
+
description: "Set true only after the user approves this local configuration change."
|
|
22710
|
+
}
|
|
22711
|
+
},
|
|
22712
|
+
required: ["appId"],
|
|
22713
|
+
additionalProperties: false
|
|
22714
|
+
};
|
|
22715
|
+
var AppPackageDependencyToolProvider = class {
|
|
22716
|
+
constructor(manager) {
|
|
22717
|
+
this.manager = manager;
|
|
22718
|
+
}
|
|
22719
|
+
provide = (_request) => [
|
|
22720
|
+
this.inspectTool(),
|
|
22721
|
+
this.verifyTool(),
|
|
22722
|
+
this.setupTool(),
|
|
22723
|
+
this.bindTool(),
|
|
22724
|
+
this.unbindTool()
|
|
22725
|
+
];
|
|
22726
|
+
inspectTool = () => ({
|
|
22727
|
+
name: "app_dependencies_inspect",
|
|
22728
|
+
description: "Inspect an installed App's declared dependencies, compatible trusted Providers, and non-sensitive bindings.",
|
|
22729
|
+
parameters: {
|
|
22730
|
+
type: "object",
|
|
22731
|
+
properties: { appId: { type: "string" } },
|
|
22732
|
+
required: ["appId"],
|
|
22733
|
+
additionalProperties: false
|
|
22734
|
+
},
|
|
22735
|
+
execute: async (args) => JSON.stringify(await this.manager.inspectDependencies(readAppId(args)), null, 2)
|
|
22736
|
+
});
|
|
22737
|
+
verifyTool = () => ({
|
|
22738
|
+
name: "app_dependencies_verify",
|
|
22739
|
+
description: "Verify whether an installed App's current capability and resource dependencies are satisfied.",
|
|
22740
|
+
parameters: {
|
|
22741
|
+
type: "object",
|
|
22742
|
+
properties: { appId: { type: "string" } },
|
|
22743
|
+
required: ["appId"],
|
|
22744
|
+
additionalProperties: false
|
|
22745
|
+
},
|
|
22746
|
+
execute: async (args) => JSON.stringify(await this.manager.verifyDependencies(readAppId(args)), null, 2)
|
|
22747
|
+
});
|
|
22748
|
+
setupTool = () => ({
|
|
22749
|
+
name: "app_dependencies_setup",
|
|
22750
|
+
description: "Set up dependency bindings only when each requirement has exactly one compatible trusted Provider. Run this only after the user has explicitly approved the local configuration change.",
|
|
22751
|
+
parameters: MUTATION_CONFIRMATION,
|
|
22752
|
+
execute: async (args) => await this.executeWithConfirmation(args, "setup", (appId) => this.manager.setupDependencies(appId))
|
|
22753
|
+
});
|
|
22754
|
+
bindTool = () => ({
|
|
22755
|
+
name: "app_dependency_bind",
|
|
22756
|
+
description: "Bind one declared dependency to an installed trusted Provider. Run this only after the user has explicitly approved the local configuration change.",
|
|
22757
|
+
parameters: {
|
|
22758
|
+
type: "object",
|
|
22759
|
+
properties: {
|
|
22760
|
+
appId: { type: "string" },
|
|
22761
|
+
componentId: { type: "string" },
|
|
22762
|
+
requirementKind: {
|
|
22763
|
+
type: "string",
|
|
22764
|
+
enum: ["capability", "resource"]
|
|
22765
|
+
},
|
|
22766
|
+
requirementId: { type: "string" },
|
|
22767
|
+
providerId: { type: "string" },
|
|
22768
|
+
confirm: { type: "boolean" }
|
|
22769
|
+
},
|
|
22770
|
+
required: [
|
|
22771
|
+
"appId",
|
|
22772
|
+
"componentId",
|
|
22773
|
+
"requirementKind",
|
|
22774
|
+
"requirementId",
|
|
22775
|
+
"providerId"
|
|
22776
|
+
],
|
|
22777
|
+
additionalProperties: false
|
|
22778
|
+
},
|
|
22779
|
+
execute: async (args) => {
|
|
22780
|
+
const input = readBinding(args);
|
|
22781
|
+
if (!readConfirmation(args)) return confirmationResult("bind", input.appId);
|
|
22782
|
+
return JSON.stringify(await this.manager.bindDependency(input.appId, input), null, 2);
|
|
22783
|
+
}
|
|
22784
|
+
});
|
|
22785
|
+
unbindTool = () => ({
|
|
22786
|
+
name: "app_dependency_unbind",
|
|
22787
|
+
description: "Remove one local dependency binding. Run this only after the user has explicitly approved the local configuration change.",
|
|
22788
|
+
parameters: {
|
|
22789
|
+
type: "object",
|
|
22790
|
+
properties: {
|
|
22791
|
+
appId: { type: "string" },
|
|
22792
|
+
componentId: { type: "string" },
|
|
22793
|
+
requirementKind: {
|
|
22794
|
+
type: "string",
|
|
22795
|
+
enum: ["capability", "resource"]
|
|
22796
|
+
},
|
|
22797
|
+
requirementId: { type: "string" },
|
|
22798
|
+
confirm: { type: "boolean" }
|
|
22799
|
+
},
|
|
22800
|
+
required: [
|
|
22801
|
+
"appId",
|
|
22802
|
+
"componentId",
|
|
22803
|
+
"requirementKind",
|
|
22804
|
+
"requirementId"
|
|
22805
|
+
],
|
|
22806
|
+
additionalProperties: false
|
|
22807
|
+
},
|
|
22808
|
+
execute: async (args) => {
|
|
22809
|
+
const input = readUnbind(args);
|
|
22810
|
+
if (!readConfirmation(args)) return confirmationResult("unbind", input.appId);
|
|
22811
|
+
return JSON.stringify(await this.manager.unbindDependency(input.appId, input), null, 2);
|
|
22812
|
+
}
|
|
22813
|
+
});
|
|
22814
|
+
executeWithConfirmation = async (args, action, execute) => {
|
|
22815
|
+
const params = normalizeToolParams(args);
|
|
22816
|
+
const appId = readAppId(params);
|
|
22817
|
+
if (!readConfirmation(params)) return confirmationResult(action, appId);
|
|
22818
|
+
return JSON.stringify(await execute(appId), null, 2);
|
|
22819
|
+
};
|
|
22820
|
+
};
|
|
22821
|
+
function readAppId(value) {
|
|
22822
|
+
const params = normalizeToolParams(value);
|
|
22823
|
+
if (typeof params.appId !== "string" || !params.appId.trim()) throw new Error("appId must be a non-empty string.");
|
|
22824
|
+
return params.appId.trim();
|
|
22825
|
+
}
|
|
22826
|
+
function readConfirmation(value) {
|
|
22827
|
+
return normalizeToolParams(value).confirm === true;
|
|
22828
|
+
}
|
|
22829
|
+
function readBinding(value) {
|
|
22830
|
+
const params = normalizeToolParams(value);
|
|
22831
|
+
const appId = readAppId(params);
|
|
22832
|
+
const componentId = readString$1(params.componentId, "componentId");
|
|
22833
|
+
const requirementId = readString$1(params.requirementId, "requirementId");
|
|
22834
|
+
const providerId = readString$1(params.providerId, "providerId");
|
|
22835
|
+
if (params.requirementKind !== "capability" && params.requirementKind !== "resource") throw new Error("requirementKind must be capability or resource.");
|
|
22836
|
+
return {
|
|
22837
|
+
appId,
|
|
22838
|
+
componentId,
|
|
22839
|
+
requirementKind: params.requirementKind,
|
|
22840
|
+
requirementId,
|
|
22841
|
+
providerId,
|
|
22842
|
+
confirm: params.confirm === true
|
|
22843
|
+
};
|
|
22844
|
+
}
|
|
22845
|
+
function readUnbind(value) {
|
|
22846
|
+
const binding = readBinding({
|
|
22847
|
+
...normalizeToolParams(value),
|
|
22848
|
+
providerId: "unused"
|
|
22849
|
+
});
|
|
22850
|
+
return {
|
|
22851
|
+
appId: binding.appId,
|
|
22852
|
+
componentId: binding.componentId,
|
|
22853
|
+
requirementKind: binding.requirementKind,
|
|
22854
|
+
requirementId: binding.requirementId,
|
|
22855
|
+
confirm: binding.confirm
|
|
22856
|
+
};
|
|
22857
|
+
}
|
|
22858
|
+
function readString$1(value, name) {
|
|
22859
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${name} must be a non-empty string.`);
|
|
22860
|
+
return value.trim();
|
|
22861
|
+
}
|
|
22862
|
+
function confirmationResult(action, appId) {
|
|
22863
|
+
return JSON.stringify({
|
|
22864
|
+
status: "requires_user_authorization",
|
|
22865
|
+
action,
|
|
22866
|
+
appId,
|
|
22867
|
+
message: "This changes local dependency configuration. Confirm that the user has approved it, then retry with confirm=true."
|
|
22868
|
+
}, null, 2);
|
|
22869
|
+
}
|
|
22870
|
+
//#endregion
|
|
22072
22871
|
//#region src/contributions/tool-provider/services/tool-provider-run-context.service.ts
|
|
22073
22872
|
var ToolProviderRunContextService = class {
|
|
22074
22873
|
constructor(sessionManager, agentManager, configManager) {
|
|
@@ -22126,6 +22925,7 @@ var ToolProviderContribution = class extends Contribution$1 {
|
|
|
22126
22925
|
new SessionToolProvider(runContextService, this.kernel.sessionManager, this.kernel.sessionRequests, this.kernel.sessionSearch),
|
|
22127
22926
|
new AssetToolProvider(this.kernel.assetStore),
|
|
22128
22927
|
new ServiceActionToolProvider(runContextService, this.kernel.serviceAppManager),
|
|
22928
|
+
new AppPackageDependencyToolProvider(this.kernel.appPackageManager),
|
|
22129
22929
|
new McpToolProvider(runContextService, this.kernel.mcpManager)
|
|
22130
22930
|
];
|
|
22131
22931
|
};
|
|
@@ -22225,6 +23025,7 @@ function createKernelContributions(kernel) {
|
|
|
22225
23025
|
function installKernelAppPackageRuntimeHooks(params) {
|
|
22226
23026
|
const { appPackageManager, panelAppManager, serviceAppManager } = params;
|
|
22227
23027
|
appPackageManager.installRuntimeHooks({
|
|
23028
|
+
listCapabilityProviders: serviceAppManager.listCapabilityProviders,
|
|
22228
23029
|
assertCanActivate: async (sources) => {
|
|
22229
23030
|
await panelAppManager.assertCanActivatePackageComponents(sources);
|
|
22230
23031
|
await serviceAppManager.assertCanActivatePackageComponents(sources);
|