@nextclaw/server 0.17.3 → 0.18.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 +67 -34
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +275 -50
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -64,13 +64,13 @@ async function readJson(req) {
|
|
|
64
64
|
return { ok: false };
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
function isRecord$
|
|
67
|
+
function isRecord$3(value) {
|
|
68
68
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
69
69
|
}
|
|
70
70
|
function readErrorMessage(value, fallback) {
|
|
71
|
-
if (!isRecord$
|
|
71
|
+
if (!isRecord$3(value)) return fallback;
|
|
72
72
|
const maybeError = value.error;
|
|
73
|
-
if (!isRecord$
|
|
73
|
+
if (!isRecord$3(maybeError)) return fallback;
|
|
74
74
|
return typeof maybeError.message === "string" && maybeError.message.trim().length > 0 ? maybeError.message : fallback;
|
|
75
75
|
}
|
|
76
76
|
function readNonEmptyString(value) {
|
|
@@ -477,7 +477,8 @@ const ingressKeys = {
|
|
|
477
477
|
channelCommandList: createTypedKey("extension.channel.command.list"),
|
|
478
478
|
channelCommandExecute: createTypedKey("extension.channel.command.execute"),
|
|
479
479
|
runtimeReady: createTypedKey("extension.runtime.ready"),
|
|
480
|
-
response: createTypedKey("extension.response")
|
|
480
|
+
response: createTypedKey("extension.response"),
|
|
481
|
+
observationEvent: createTypedKey("extension.observation.event")
|
|
481
482
|
},
|
|
482
483
|
agentRun: {
|
|
483
484
|
send: createTypedKey("agent-run.send"),
|
|
@@ -1456,7 +1457,7 @@ var ServerPathRoutesController = class {
|
|
|
1456
1457
|
watch = async (c) => {
|
|
1457
1458
|
if (!this.watchService) return c.json(err("SERVER_PATH_WATCH_UNAVAILABLE", "server path watch is unavailable"), 503);
|
|
1458
1459
|
const body = await readJson(c.req.raw);
|
|
1459
|
-
if (!body.ok || !isRecord$
|
|
1460
|
+
if (!body.ok || !isRecord$3(body.data) || !Array.isArray(body.data.directories) || !body.data.directories.every((path) => typeof path === "string")) return c.json(err("INVALID_SERVER_PATH_WATCH", "directories are required"), 400);
|
|
1460
1461
|
try {
|
|
1461
1462
|
const request = {
|
|
1462
1463
|
directories: body.data.directories,
|
|
@@ -1502,7 +1503,7 @@ var ServerPathRoutesController = class {
|
|
|
1502
1503
|
};
|
|
1503
1504
|
createDirectory = async (c) => {
|
|
1504
1505
|
const body = await readJson(c.req.raw);
|
|
1505
|
-
if (!body.ok || !isRecord$
|
|
1506
|
+
if (!body.ok || !isRecord$3(body.data)) return c.json(err("INVALID_SERVER_PATH_DIRECTORY", "directory input is required"), 400);
|
|
1506
1507
|
try {
|
|
1507
1508
|
return c.json(ok(await createServerPathDirectory({
|
|
1508
1509
|
basePath: body.data.basePath,
|
|
@@ -1539,7 +1540,7 @@ var ServerPathRoutesController = class {
|
|
|
1539
1540
|
};
|
|
1540
1541
|
createFile = async (c) => {
|
|
1541
1542
|
const body = await readJson(c.req.raw);
|
|
1542
|
-
if (!body.ok || !isRecord$
|
|
1543
|
+
if (!body.ok || !isRecord$3(body.data)) return c.json(err("INVALID_SERVER_PATH_FILE", "file input is required"), 400);
|
|
1543
1544
|
try {
|
|
1544
1545
|
return c.json(ok(await createServerPathFile({
|
|
1545
1546
|
basePath: body.data.basePath,
|
|
@@ -1553,7 +1554,7 @@ var ServerPathRoutesController = class {
|
|
|
1553
1554
|
};
|
|
1554
1555
|
renameEntry = async (c) => {
|
|
1555
1556
|
const body = await readJson(c.req.raw);
|
|
1556
|
-
if (!body.ok || !isRecord$
|
|
1557
|
+
if (!body.ok || !isRecord$3(body.data)) return c.json(err("INVALID_SERVER_PATH_RENAME", "rename input is required"), 400);
|
|
1557
1558
|
try {
|
|
1558
1559
|
return c.json(ok(await renameServerPathEntry({
|
|
1559
1560
|
basePath: body.data.basePath,
|
|
@@ -1905,20 +1906,62 @@ function buildFallbackBootstrapStatus() {
|
|
|
1905
1906
|
remote: { state: "pending" }
|
|
1906
1907
|
};
|
|
1907
1908
|
}
|
|
1909
|
+
function buildExtensionsView(options) {
|
|
1910
|
+
const manifests = options.kernel.extensions.getManifests();
|
|
1911
|
+
const statuses = options.kernel.extensions.getRuntimeStatus();
|
|
1912
|
+
const statusById = new Map(statuses.map((status) => [status.extensionId, status]));
|
|
1913
|
+
const extensions = manifests.map((manifest) => {
|
|
1914
|
+
const status = statusById.get(manifest.id);
|
|
1915
|
+
const observations = manifest.contributes?.observations;
|
|
1916
|
+
const channels = (manifest.contributes?.channels ?? []).map((channel) => ({
|
|
1917
|
+
id: channel.id,
|
|
1918
|
+
...channel.name ? { name: channel.name } : {},
|
|
1919
|
+
...typeof channel.meta?.description === "string" ? { description: channel.meta.description } : {}
|
|
1920
|
+
}));
|
|
1921
|
+
return {
|
|
1922
|
+
id: manifest.id,
|
|
1923
|
+
name: manifest.name?.trim() || manifest.id,
|
|
1924
|
+
...manifest.version ? { version: manifest.version } : {},
|
|
1925
|
+
state: status?.state ?? "stopped",
|
|
1926
|
+
...status?.generation ? { generation: status.generation } : {},
|
|
1927
|
+
...status?.pid ? { pid: status.pid } : {},
|
|
1928
|
+
...status?.startedAt ? { startedAt: status.startedAt } : {},
|
|
1929
|
+
leaseCount: status?.leaseReasons.length ?? 0,
|
|
1930
|
+
observations: {
|
|
1931
|
+
context: Boolean(observations?.read),
|
|
1932
|
+
events: Boolean(observations?.events)
|
|
1933
|
+
},
|
|
1934
|
+
channels
|
|
1935
|
+
};
|
|
1936
|
+
});
|
|
1937
|
+
return {
|
|
1938
|
+
extensions,
|
|
1939
|
+
counts: {
|
|
1940
|
+
total: extensions.length,
|
|
1941
|
+
running: extensions.filter((extension) => extension.state === "running").length,
|
|
1942
|
+
withObservations: extensions.filter((extension) => extension.observations.context || extension.observations.events).length,
|
|
1943
|
+
withChannels: extensions.filter((extension) => extension.channels.length > 0).length
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1908
1947
|
var AppRoutesController = class {
|
|
1909
1948
|
constructor(options) {
|
|
1910
1949
|
this.options = options;
|
|
1911
1950
|
}
|
|
1912
|
-
health = (c) =>
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1951
|
+
health = (c) => {
|
|
1952
|
+
const bootstrapStatus = this.options.bootstrapStatus?.getStatus() ?? buildFallbackBootstrapStatus();
|
|
1953
|
+
return c.json(ok({
|
|
1954
|
+
status: "ok",
|
|
1955
|
+
services: {
|
|
1956
|
+
ncpAgent: bootstrapStatus.ncpAgent.state,
|
|
1957
|
+
cronService: this.options.cron ? "ready" : "unavailable"
|
|
1958
|
+
}
|
|
1959
|
+
}));
|
|
1960
|
+
};
|
|
1919
1961
|
appMeta = (c) => c.json(ok(buildAppMetaView(this.options)));
|
|
1920
1962
|
bootstrapStatus = (c) => c.json(ok(this.options.bootstrapStatus?.getStatus() ?? buildFallbackBootstrapStatus()));
|
|
1921
|
-
extensionRuntimeStatus = (c) => c.json(ok(this.options.extensions
|
|
1963
|
+
extensionRuntimeStatus = (c) => c.json(ok(this.options.kernel.extensions.getRuntimeStatus()));
|
|
1964
|
+
extensionCatalog = (c) => c.json(ok(buildExtensionsView(this.options)));
|
|
1922
1965
|
};
|
|
1923
1966
|
//#endregion
|
|
1924
1967
|
//#region src/features/app-packages/controllers/app-packages.controller.ts
|
|
@@ -1930,7 +1973,7 @@ var AppPackagesRoutesController = class {
|
|
|
1930
1973
|
listOperations = async (c) => c.json(ok(await this.manager.listOperations()));
|
|
1931
1974
|
startInstallOperation = async (c) => {
|
|
1932
1975
|
const body = await readJson(c.req.raw);
|
|
1933
|
-
if (!body.ok || !isRecord$
|
|
1976
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.source !== "string") return c.json(err("INVALID_APP_PACKAGE_INSTALL", "source is required"), 400);
|
|
1934
1977
|
try {
|
|
1935
1978
|
return c.json(ok(await this.manager.startOperation({
|
|
1936
1979
|
action: "install",
|
|
@@ -1943,7 +1986,7 @@ var AppPackagesRoutesController = class {
|
|
|
1943
1986
|
};
|
|
1944
1987
|
startUpdateOperation = async (c) => {
|
|
1945
1988
|
const body = await readJson(c.req.raw);
|
|
1946
|
-
if (!body.ok || !isRecord$
|
|
1989
|
+
if (!body.ok || !isRecord$3(body.data)) return c.json(err("INVALID_APP_PACKAGE_UPDATE", "invalid update request"), 400);
|
|
1947
1990
|
try {
|
|
1948
1991
|
return c.json(ok(await this.manager.startOperation({
|
|
1949
1992
|
action: "update",
|
|
@@ -1957,7 +2000,7 @@ var AppPackagesRoutesController = class {
|
|
|
1957
2000
|
};
|
|
1958
2001
|
startRollbackOperation = async (c) => {
|
|
1959
2002
|
const body = await readJson(c.req.raw);
|
|
1960
|
-
if (!body.ok || !isRecord$
|
|
2003
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.version !== "string") return c.json(err("INVALID_APP_PACKAGE_ROLLBACK", "version is required"), 400);
|
|
1961
2004
|
try {
|
|
1962
2005
|
return c.json(ok(await this.manager.startOperation({
|
|
1963
2006
|
action: "rollback",
|
|
@@ -1970,7 +2013,7 @@ var AppPackagesRoutesController = class {
|
|
|
1970
2013
|
};
|
|
1971
2014
|
startUninstallOperation = async (c) => {
|
|
1972
2015
|
const body = await readJson(c.req.raw);
|
|
1973
|
-
const purgeData = body.ok && isRecord$
|
|
2016
|
+
const purgeData = body.ok && isRecord$3(body.data) && body.data.purgeData === true;
|
|
1974
2017
|
try {
|
|
1975
2018
|
return c.json(ok(await this.manager.startOperation({
|
|
1976
2019
|
action: "uninstall",
|
|
@@ -1990,7 +2033,7 @@ var AppPackagesRoutesController = class {
|
|
|
1990
2033
|
};
|
|
1991
2034
|
install = async (c) => {
|
|
1992
2035
|
const body = await readJson(c.req.raw);
|
|
1993
|
-
if (!body.ok || !isRecord$
|
|
2036
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.source !== "string") return c.json(err("INVALID_APP_PACKAGE_INSTALL", "source is required"), 400);
|
|
1994
2037
|
try {
|
|
1995
2038
|
return c.json(ok(await this.manager.install(body.data.source, typeof body.data.registryUrl === "string" ? body.data.registryUrl : void 0)));
|
|
1996
2039
|
} catch (error) {
|
|
@@ -2013,7 +2056,7 @@ var AppPackagesRoutesController = class {
|
|
|
2013
2056
|
};
|
|
2014
2057
|
update = async (c) => {
|
|
2015
2058
|
const body = await readJson(c.req.raw);
|
|
2016
|
-
if (!body.ok || !isRecord$
|
|
2059
|
+
if (!body.ok || !isRecord$3(body.data)) return c.json(err("INVALID_APP_PACKAGE_UPDATE", "invalid update request"), 400);
|
|
2017
2060
|
try {
|
|
2018
2061
|
return c.json(ok(await this.manager.update(c.req.param("appId"), {
|
|
2019
2062
|
version: typeof body.data.version === "string" ? body.data.version : void 0,
|
|
@@ -2025,7 +2068,7 @@ var AppPackagesRoutesController = class {
|
|
|
2025
2068
|
};
|
|
2026
2069
|
rollback = async (c) => {
|
|
2027
2070
|
const body = await readJson(c.req.raw);
|
|
2028
|
-
if (!body.ok || !isRecord$
|
|
2071
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.version !== "string") return c.json(err("INVALID_APP_PACKAGE_ROLLBACK", "version is required"), 400);
|
|
2029
2072
|
try {
|
|
2030
2073
|
return c.json(ok(await this.manager.rollback(c.req.param("appId"), body.data.version)));
|
|
2031
2074
|
} catch (error) {
|
|
@@ -2034,7 +2077,7 @@ var AppPackagesRoutesController = class {
|
|
|
2034
2077
|
};
|
|
2035
2078
|
uninstall = async (c) => {
|
|
2036
2079
|
const body = await readJson(c.req.raw);
|
|
2037
|
-
const purgeData = body.ok && isRecord$
|
|
2080
|
+
const purgeData = body.ok && isRecord$3(body.data) && body.data.purgeData === true;
|
|
2038
2081
|
try {
|
|
2039
2082
|
return c.json(ok(await this.manager.uninstall(c.req.param("appId"), purgeData)));
|
|
2040
2083
|
} catch (error) {
|
|
@@ -2060,7 +2103,7 @@ var AppDataRoutesController = class {
|
|
|
2060
2103
|
};
|
|
2061
2104
|
deleteRetained = async (c) => {
|
|
2062
2105
|
const body = await readJson(c.req.raw);
|
|
2063
|
-
if (!body.ok || !isRecord$
|
|
2106
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.confirmAppId !== "string" || !body.data.confirmAppId.trim()) return c.json(err("INVALID_APP_DATA_DELETE_REQUEST", "confirmAppId is required."), 400);
|
|
2064
2107
|
try {
|
|
2065
2108
|
return c.json(ok(await this.manager.deleteRetained(c.req.param("dataId"), body.data.confirmAppId.trim())));
|
|
2066
2109
|
} catch (error) {
|
|
@@ -2097,7 +2140,7 @@ var SystemObjectReferencesRoutesController = class {
|
|
|
2097
2140
|
};
|
|
2098
2141
|
resolve = async (c) => {
|
|
2099
2142
|
const body = await readJson(c.req.raw);
|
|
2100
|
-
if (!body.ok || !isRecord$
|
|
2143
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.uri !== "string" || !body.data.uri.trim()) return c.json(err("INVALID_SYSTEM_OBJECT_REFERENCE", "uri must be a non-empty string"), 400);
|
|
2101
2144
|
try {
|
|
2102
2145
|
return c.json(ok(await this.manager.resolveReference(body.data.uri)));
|
|
2103
2146
|
} catch (error) {
|
|
@@ -4492,7 +4535,7 @@ var InboxDeliveriesRoutesController = class {
|
|
|
4492
4535
|
};
|
|
4493
4536
|
updateState = async (c) => {
|
|
4494
4537
|
const body = await readJson(c.req.raw);
|
|
4495
|
-
if (!body.ok || !isRecord$
|
|
4538
|
+
if (!body.ok || !isRecord$3(body.data) || !isStateAction(body.data.action)) return c.json(err("INVALID_INBOX_DELIVERY_ACTION", "invalid inbox delivery action"), 400);
|
|
4496
4539
|
return await this.handleManagerAction(c, () => this.manager.updateDeliveryState(c.req.param("deliveryId"), body.data.action));
|
|
4497
4540
|
};
|
|
4498
4541
|
delete = async (c) => {
|
|
@@ -5472,21 +5515,19 @@ function isDeferrableMessage(message) {
|
|
|
5472
5515
|
function deferMessageToolPayload(message) {
|
|
5473
5516
|
const tools = message.parts.filter((part) => part.type === "tool-invocation");
|
|
5474
5517
|
const toolNames = [...new Set(tools.map((part) => part.toolName.trim()).filter(Boolean))].slice(0, SUMMARY_TOOL_NAME_LIMIT);
|
|
5475
|
-
const parts = [];
|
|
5476
5518
|
let keptRepresentative = false;
|
|
5477
|
-
|
|
5478
|
-
if (part.type !== "tool-invocation")
|
|
5479
|
-
|
|
5480
|
-
continue;
|
|
5481
|
-
}
|
|
5482
|
-
if (keptRepresentative) continue;
|
|
5519
|
+
const parts = message.parts.map((part) => {
|
|
5520
|
+
if (part.type !== "tool-invocation") return part;
|
|
5521
|
+
const isRepresentative = !keptRepresentative;
|
|
5483
5522
|
keptRepresentative = true;
|
|
5484
|
-
|
|
5523
|
+
return {
|
|
5485
5524
|
...part,
|
|
5525
|
+
...isRepresentative ? {} : { payloadDeferred: true },
|
|
5486
5526
|
args: void 0,
|
|
5487
|
-
result: void 0
|
|
5488
|
-
|
|
5489
|
-
|
|
5527
|
+
result: void 0,
|
|
5528
|
+
resultContentItems: void 0
|
|
5529
|
+
};
|
|
5530
|
+
});
|
|
5490
5531
|
return {
|
|
5491
5532
|
...message,
|
|
5492
5533
|
metadata: {
|
|
@@ -5499,6 +5540,20 @@ function deferMessageToolPayload(message) {
|
|
|
5499
5540
|
parts
|
|
5500
5541
|
};
|
|
5501
5542
|
}
|
|
5543
|
+
function sanitizeContextCompactionHistoryMessage(message) {
|
|
5544
|
+
const metadata = message.metadata;
|
|
5545
|
+
if (metadata?.nextclaw_timeline_kind !== "context_compaction") return message;
|
|
5546
|
+
const checkpoint = metadata.checkpoint;
|
|
5547
|
+
if (!checkpoint || typeof checkpoint !== "object" || Array.isArray(checkpoint)) return message;
|
|
5548
|
+
const { summary: _summary, summaryDiagnostics: _summaryDiagnostics, ...uiCheckpoint } = checkpoint;
|
|
5549
|
+
return {
|
|
5550
|
+
...message,
|
|
5551
|
+
metadata: {
|
|
5552
|
+
...metadata,
|
|
5553
|
+
checkpoint: uiCheckpoint
|
|
5554
|
+
}
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5502
5557
|
function buildSessionMessageHistoryPayloadView(params) {
|
|
5503
5558
|
const { messageBudgetBytes: requestedMessageBudgetBytes, messageDetailCursors, messages, messageToolCallBudget: requestedMessageToolCallBudget, pageBudgetBytes: requestedPageBudgetBytes, pageToolCallBudget: requestedPageToolCallBudget } = params;
|
|
5504
5559
|
const messageBudgetBytes = requestedMessageBudgetBytes ?? 262144;
|
|
@@ -5530,7 +5585,10 @@ function buildSessionMessageHistoryPayloadView(params) {
|
|
|
5530
5585
|
}
|
|
5531
5586
|
const deferredToolPayloads = Object.fromEntries([...deferredIds].map((messageId) => [messageId, { cursor: messageDetailCursors[messageId] }]));
|
|
5532
5587
|
return {
|
|
5533
|
-
messages: messages.map((message) =>
|
|
5588
|
+
messages: messages.map((message) => {
|
|
5589
|
+
const sanitized = sanitizeContextCompactionHistoryMessage(message);
|
|
5590
|
+
return deferredIds.has(message.id) ? deferMessageToolPayload(sanitized) : sanitized;
|
|
5591
|
+
}),
|
|
5534
5592
|
deferredToolPayloads
|
|
5535
5593
|
};
|
|
5536
5594
|
}
|
|
@@ -5538,7 +5596,14 @@ function compactSessionMessageHistoryPayloadView(params) {
|
|
|
5538
5596
|
const { view } = params;
|
|
5539
5597
|
const budgetBytes = params.budgetBytes ?? 24576;
|
|
5540
5598
|
const minimumMessages = Math.max(1, Math.trunc(params.minimumMessages ?? 5));
|
|
5541
|
-
let startIndex =
|
|
5599
|
+
let startIndex = view.messages.length;
|
|
5600
|
+
let conversationMessageCount = 0;
|
|
5601
|
+
while (startIndex > 0 && conversationMessageCount < minimumMessages) {
|
|
5602
|
+
startIndex -= 1;
|
|
5603
|
+
const message = view.messages[startIndex];
|
|
5604
|
+
if (message?.role === "user" || message?.role === "assistant") conversationMessageCount += 1;
|
|
5605
|
+
}
|
|
5606
|
+
if (startIndex === view.messages.length) startIndex = Math.max(0, view.messages.length - minimumMessages);
|
|
5542
5607
|
let bytes = view.messages.slice(startIndex).reduce((total, message) => total + serializedBytes(message), 0);
|
|
5543
5608
|
while (startIndex > 0) {
|
|
5544
5609
|
const previousBytes = serializedBytes(view.messages[startIndex - 1]);
|
|
@@ -5555,6 +5620,115 @@ function compactSessionMessageHistoryPayloadView(params) {
|
|
|
5555
5620
|
};
|
|
5556
5621
|
}
|
|
5557
5622
|
//#endregion
|
|
5623
|
+
//#region src/features/sessions/utils/session-observation-view.utils.ts
|
|
5624
|
+
const SENSITIVE_KEY_PATTERN = /(token|secret|password|cookie|api[-_]?key|credential|authorization)/i;
|
|
5625
|
+
const MAX_PREVIEW_ENTRIES = 6;
|
|
5626
|
+
const MAX_PREVIEW_VALUE_LENGTH = 80;
|
|
5627
|
+
function isRecord$2(value) {
|
|
5628
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5629
|
+
}
|
|
5630
|
+
function previewValue(key, value) {
|
|
5631
|
+
if (SENSITIVE_KEY_PATTERN.test(key)) return "••••••";
|
|
5632
|
+
if (value === null) return "null";
|
|
5633
|
+
if (typeof value === "string") {
|
|
5634
|
+
const normalized = value.trim();
|
|
5635
|
+
if (normalized.length <= MAX_PREVIEW_VALUE_LENGTH) return normalized || "空字符串";
|
|
5636
|
+
return `${normalized.slice(0, MAX_PREVIEW_VALUE_LENGTH - 1)}…`;
|
|
5637
|
+
}
|
|
5638
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
5639
|
+
if (Array.isArray(value)) return `[${value.length} 项]`;
|
|
5640
|
+
if (isRecord$2(value)) return "已配置";
|
|
5641
|
+
return "已配置";
|
|
5642
|
+
}
|
|
5643
|
+
function buildSafeConfigPreview(config) {
|
|
5644
|
+
if (!isRecord$2(config)) return config === void 0 ? void 0 : "已配置";
|
|
5645
|
+
const entries = Object.entries(config).slice(0, MAX_PREVIEW_ENTRIES);
|
|
5646
|
+
if (entries.length === 0) return void 0;
|
|
5647
|
+
const preview = entries.map(([key, value]) => `${key}: ${previewValue(key, value)}`);
|
|
5648
|
+
if (Object.keys(config).length > MAX_PREVIEW_ENTRIES) preview.push("…");
|
|
5649
|
+
return preview.join(" · ");
|
|
5650
|
+
}
|
|
5651
|
+
function buildDescriptorMap(descriptors) {
|
|
5652
|
+
return new Map(descriptors.map((descriptor) => [`${descriptor.kind}:${descriptor.extensionId}`, descriptor]));
|
|
5653
|
+
}
|
|
5654
|
+
function buildDeliveryCounts(deliveries) {
|
|
5655
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5656
|
+
for (const delivery of deliveries) {
|
|
5657
|
+
const current = counts.get(delivery.subscriptionId) ?? {
|
|
5658
|
+
pending: 0,
|
|
5659
|
+
failures: 0
|
|
5660
|
+
};
|
|
5661
|
+
if (delivery.status === "pending" || delivery.status === "submitted") current.pending += 1;
|
|
5662
|
+
if (delivery.status === "failed") current.failures += 1;
|
|
5663
|
+
counts.set(delivery.subscriptionId, current);
|
|
5664
|
+
}
|
|
5665
|
+
return counts;
|
|
5666
|
+
}
|
|
5667
|
+
function buildContextView(binding, descriptors) {
|
|
5668
|
+
const descriptor = descriptors.get(`context:${binding.extensionId}`);
|
|
5669
|
+
const safeConfigPreview = buildSafeConfigPreview(binding.config);
|
|
5670
|
+
return {
|
|
5671
|
+
id: binding.bindingId,
|
|
5672
|
+
kind: "context",
|
|
5673
|
+
extensionId: binding.extensionId,
|
|
5674
|
+
title: descriptor?.title ?? binding.extensionId,
|
|
5675
|
+
...descriptor?.description ? { description: descriptor.description } : {},
|
|
5676
|
+
status: binding.status,
|
|
5677
|
+
...binding.statusReason ? { statusReason: binding.statusReason } : {},
|
|
5678
|
+
createdAt: binding.createdAt,
|
|
5679
|
+
...binding.expiresAt ? { expiresAt: binding.expiresAt } : {},
|
|
5680
|
+
...binding.lastReadAt ? { lastReadAt: binding.lastReadAt } : {},
|
|
5681
|
+
...safeConfigPreview ? { safeConfigPreview } : {}
|
|
5682
|
+
};
|
|
5683
|
+
}
|
|
5684
|
+
function buildSubscriptionView(subscription, descriptors, deliveryCounts) {
|
|
5685
|
+
const descriptor = descriptors.get(`events:${subscription.extensionId}`);
|
|
5686
|
+
const counts = deliveryCounts.get(subscription.subscriptionId) ?? {
|
|
5687
|
+
pending: 0,
|
|
5688
|
+
failures: 0
|
|
5689
|
+
};
|
|
5690
|
+
const safeConfigPreview = buildSafeConfigPreview(subscription.config);
|
|
5691
|
+
return {
|
|
5692
|
+
id: subscription.subscriptionId,
|
|
5693
|
+
kind: "events",
|
|
5694
|
+
extensionId: subscription.extensionId,
|
|
5695
|
+
title: descriptor?.title ?? subscription.extensionId,
|
|
5696
|
+
...descriptor?.description ? { description: descriptor.description } : {},
|
|
5697
|
+
status: subscription.status,
|
|
5698
|
+
...subscription.statusReason ? { statusReason: subscription.statusReason } : {},
|
|
5699
|
+
createdAt: subscription.createdAt,
|
|
5700
|
+
...subscription.expiresAt ? { expiresAt: subscription.expiresAt } : {},
|
|
5701
|
+
...safeConfigPreview ? { safeConfigPreview } : {},
|
|
5702
|
+
pendingCount: counts.pending,
|
|
5703
|
+
...subscription.suppressedCount ? { suppressedCount: subscription.suppressedCount } : {},
|
|
5704
|
+
...counts.failures > 0 ? { deliveryFailureCount: counts.failures } : {},
|
|
5705
|
+
...subscription.lastSuppressionReason ? { lastSuppressionReason: subscription.lastSuppressionReason } : {},
|
|
5706
|
+
...subscription.lastGapAt ? { lastGapAt: subscription.lastGapAt } : {},
|
|
5707
|
+
...subscription.gapReason ? { gapReason: subscription.gapReason } : {},
|
|
5708
|
+
delivery: subscription.delivery
|
|
5709
|
+
};
|
|
5710
|
+
}
|
|
5711
|
+
function needsAttention(observation) {
|
|
5712
|
+
return observation.status !== "active" || (observation.deliveryFailureCount ?? 0) > 0 || Boolean(observation.lastGapAt);
|
|
5713
|
+
}
|
|
5714
|
+
function buildSessionObservationsView(input) {
|
|
5715
|
+
const descriptors = buildDescriptorMap(input.descriptors);
|
|
5716
|
+
const deliveryCounts = buildDeliveryCounts(input.deliveries);
|
|
5717
|
+
const bindings = input.bindings.map((binding) => buildContextView(binding, descriptors));
|
|
5718
|
+
const subscriptions = input.subscriptions.map((subscription) => buildSubscriptionView(subscription, descriptors, deliveryCounts));
|
|
5719
|
+
return {
|
|
5720
|
+
sessionId: input.sessionId,
|
|
5721
|
+
bindings,
|
|
5722
|
+
subscriptions,
|
|
5723
|
+
counts: {
|
|
5724
|
+
total: bindings.length + subscriptions.length,
|
|
5725
|
+
context: bindings.length,
|
|
5726
|
+
events: subscriptions.length,
|
|
5727
|
+
needsAttention: [...bindings, ...subscriptions].filter(needsAttention).length
|
|
5728
|
+
}
|
|
5729
|
+
};
|
|
5730
|
+
}
|
|
5731
|
+
//#endregion
|
|
5558
5732
|
//#region src/features/sessions/controllers/sessions.controller.ts
|
|
5559
5733
|
const DEFAULT_SESSION_MESSAGE_PAGE_SIZE = 40;
|
|
5560
5734
|
const MAX_SESSION_MESSAGE_PAGE_SIZE = 200;
|
|
@@ -5689,6 +5863,42 @@ var NcpSessionRoutesController = class {
|
|
|
5689
5863
|
if (!payload) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
|
|
5690
5864
|
return c.json(ok(payload));
|
|
5691
5865
|
};
|
|
5866
|
+
listSessionObservations = async (c) => {
|
|
5867
|
+
const sessionId = decodeURIComponent(c.req.param("sessionId"));
|
|
5868
|
+
if (!await this.options.kernel.sessionManager.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
|
|
5869
|
+
const payload = buildSessionObservationsView({
|
|
5870
|
+
sessionId,
|
|
5871
|
+
...await this.options.kernel.observations.listObservations(sessionId),
|
|
5872
|
+
descriptors: this.options.kernel.observations.discoverObservations()
|
|
5873
|
+
});
|
|
5874
|
+
return c.json(ok(payload));
|
|
5875
|
+
};
|
|
5876
|
+
updateSessionObservation = async (c) => {
|
|
5877
|
+
const sessionId = decodeURIComponent(c.req.param("sessionId"));
|
|
5878
|
+
const kind = c.req.param("kind");
|
|
5879
|
+
const id = decodeURIComponent(c.req.param("id"));
|
|
5880
|
+
if (!await this.options.kernel.sessionManager.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
|
|
5881
|
+
const body = await readJson(c.req.raw);
|
|
5882
|
+
const action = body.ok && body.data?.action;
|
|
5883
|
+
if (action !== "pause" && action !== "resume" && action !== "remove") return c.json(err("INVALID_BODY", "action must be pause, resume, or remove"), 400);
|
|
5884
|
+
if (kind !== "context" && kind !== "events") return c.json(err("NOT_FOUND", `observation kind not found: ${kind}`), 404);
|
|
5885
|
+
const ref = kind === "context" ? {
|
|
5886
|
+
kind: "context_binding",
|
|
5887
|
+
id
|
|
5888
|
+
} : {
|
|
5889
|
+
kind: "event_subscription",
|
|
5890
|
+
id
|
|
5891
|
+
};
|
|
5892
|
+
const observation = await this.options.kernel.observations.getObservation(ref);
|
|
5893
|
+
if (!observation || observation.target.sessionId !== sessionId) return c.json(err("NOT_FOUND", `observation not found in session: ${sessionId}`), 404);
|
|
5894
|
+
await this.options.kernel.observations.updateObservation(action, ref);
|
|
5895
|
+
const state = await this.options.kernel.observations.listObservations(sessionId);
|
|
5896
|
+
return c.json(ok(buildSessionObservationsView({
|
|
5897
|
+
sessionId,
|
|
5898
|
+
...state,
|
|
5899
|
+
descriptors: this.options.kernel.observations.discoverObservations()
|
|
5900
|
+
})));
|
|
5901
|
+
};
|
|
5692
5902
|
getSessionSkills = async (c) => {
|
|
5693
5903
|
const sessionManager = this.options.kernel.sessionManager;
|
|
5694
5904
|
const sessionId = decodeURIComponent(c.req.param("sessionId"));
|
|
@@ -6020,7 +6230,7 @@ var PanelAppsRoutesController = class {
|
|
|
6020
6230
|
};
|
|
6021
6231
|
updatePanelAppPreferences = async (c) => {
|
|
6022
6232
|
const body = await readJson(c.req.raw);
|
|
6023
|
-
if (!body.ok || !isRecord$
|
|
6233
|
+
if (!body.ok || !isRecord$3(body.data)) return c.json(err("INVALID_PANEL_APP_PREFERENCES", "invalid panel app preferences"), 400);
|
|
6024
6234
|
if (body.data.mainSidebar !== void 0 && typeof body.data.mainSidebar !== "boolean") return c.json(err("INVALID_PANEL_APP_PREFERENCES", "mainSidebar must be boolean"), 400);
|
|
6025
6235
|
try {
|
|
6026
6236
|
const preferences = {
|
|
@@ -6100,7 +6310,7 @@ var PanelAppsRoutesController = class {
|
|
|
6100
6310
|
};
|
|
6101
6311
|
createBridgeSession = async (c) => {
|
|
6102
6312
|
const body = await readJson(c.req.raw);
|
|
6103
|
-
if (!body.ok || !isRecord$
|
|
6313
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.panelAppId !== "string" && typeof body.data.appId !== "string") return c.json(err("INVALID_PANEL_APP_BRIDGE_SESSION", "invalid bridge session request"), 400);
|
|
6104
6314
|
const panelAppId = typeof body.data.appId === "string" ? body.data.appId : body.data.panelAppId;
|
|
6105
6315
|
if (typeof panelAppId !== "string") return c.json(err("INVALID_PANEL_APP_BRIDGE_SESSION", "invalid bridge session request"), 400);
|
|
6106
6316
|
try {
|
|
@@ -6137,7 +6347,7 @@ var PanelAppsRoutesController = class {
|
|
|
6137
6347
|
};
|
|
6138
6348
|
sendAgentMessage = async (c) => {
|
|
6139
6349
|
const body = await readJson(c.req.raw);
|
|
6140
|
-
if (!body.ok || !isRecord$
|
|
6350
|
+
if (!body.ok || !isRecord$3(body.data) || !isRecord$3(body.data.payload)) return c.json(err("INVALID_PANEL_APP_AGENT_REQUEST", "invalid agent send request"), 400);
|
|
6141
6351
|
try {
|
|
6142
6352
|
return c.json(ok(await this.panelAppManager.sendAgentMessage(this.requireBridgeSessionToken(c), body.data.payload)));
|
|
6143
6353
|
} catch (error) {
|
|
@@ -6146,7 +6356,7 @@ var PanelAppsRoutesController = class {
|
|
|
6146
6356
|
};
|
|
6147
6357
|
generateAgentObject = async (c) => {
|
|
6148
6358
|
const body = await readJson(c.req.raw);
|
|
6149
|
-
if (!body.ok || !isRecord$
|
|
6359
|
+
if (!body.ok || !isRecord$3(body.data) || !isRecord$3(body.data.input)) return c.json(err("INVALID_PANEL_APP_AGENT_REQUEST", "invalid generateObject request"), 400);
|
|
6150
6360
|
try {
|
|
6151
6361
|
return c.json(ok(await this.panelAppManager.generateAgentObject(this.requireBridgeSessionToken(c), body.data.input)));
|
|
6152
6362
|
} catch (error) {
|
|
@@ -6219,7 +6429,7 @@ var PreferencesRoutesController = class {
|
|
|
6219
6429
|
};
|
|
6220
6430
|
update = async (c) => {
|
|
6221
6431
|
const body = await readJson(c.req.raw);
|
|
6222
|
-
if (!body.ok || !isRecord$
|
|
6432
|
+
if (!body.ok || !isRecord$3(body.data) || !Object.hasOwn(body.data, "value")) return c.json(err("INVALID_PREFERENCE", "preference value is required"), 400);
|
|
6223
6433
|
try {
|
|
6224
6434
|
const entry = await this.preferenceManager.setPreference(c.req.param("key"), body.data.value);
|
|
6225
6435
|
return c.json(ok({
|
|
@@ -6262,7 +6472,7 @@ var ProjectsRoutesController = class {
|
|
|
6262
6472
|
};
|
|
6263
6473
|
create = async (c) => {
|
|
6264
6474
|
const body = await readJson(c.req.raw);
|
|
6265
|
-
if (!body.ok || !isRecord$
|
|
6475
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.name !== "string") return c.json(err("INVALID_PROJECT", "project name is required"), 400);
|
|
6266
6476
|
try {
|
|
6267
6477
|
return c.json(ok(await this.projectManager.createProject(body.data)), 201);
|
|
6268
6478
|
} catch (error) {
|
|
@@ -6272,7 +6482,7 @@ var ProjectsRoutesController = class {
|
|
|
6272
6482
|
};
|
|
6273
6483
|
addExisting = async (c) => {
|
|
6274
6484
|
const body = await readJson(c.req.raw);
|
|
6275
|
-
if (!body.ok || !isRecord$
|
|
6485
|
+
if (!body.ok || !isRecord$3(body.data) || typeof body.data.rootPath !== "string") return c.json(err("INVALID_PROJECT", "project directory is required"), 400);
|
|
6276
6486
|
try {
|
|
6277
6487
|
const project = await this.projectManager.registerExistingProject(body.data.rootPath);
|
|
6278
6488
|
if (!project) return c.json(err("PROJECT_PATH_IS_DEFAULT_WORKSPACE", "the default workspace cannot be registered as a project"), 400);
|
|
@@ -6334,13 +6544,13 @@ var ServiceAppsRoutesController = class {
|
|
|
6334
6544
|
};
|
|
6335
6545
|
invokeServiceAction = async (c) => {
|
|
6336
6546
|
const body = await readJson(c.req.raw);
|
|
6337
|
-
if (!body.ok || body.data !== void 0 && !isRecord$
|
|
6547
|
+
if (!body.ok || body.data !== void 0 && !isRecord$3(body.data)) return c.json(err("INVALID_SERVICE_ACTION_REQUEST", "invalid service action request"), 400);
|
|
6338
6548
|
try {
|
|
6339
6549
|
const bridgeSession = this.requireBridgeSession(c);
|
|
6340
6550
|
const payload = await this.params.serviceAppManager.invokeServiceAction(c.req.param("actionId"), {
|
|
6341
6551
|
caller: bridgeSession.caller,
|
|
6342
6552
|
declaredActions: bridgeSession.declaredActions,
|
|
6343
|
-
input: isRecord$
|
|
6553
|
+
input: isRecord$3(body.data.input) ? body.data.input : {}
|
|
6344
6554
|
});
|
|
6345
6555
|
return c.json(ok(payload));
|
|
6346
6556
|
} catch (error) {
|
|
@@ -6404,7 +6614,7 @@ var ServiceAppsRoutesController = class {
|
|
|
6404
6614
|
};
|
|
6405
6615
|
deleteServiceApp = async (c) => {
|
|
6406
6616
|
const body = await readJson(c.req.raw);
|
|
6407
|
-
const purgeData = body.ok && isRecord$
|
|
6617
|
+
const purgeData = body.ok && isRecord$3(body.data) && body.data.purgeData === true;
|
|
6408
6618
|
try {
|
|
6409
6619
|
return c.json(ok(await this.params.serviceAppManager.deleteServiceApp(c.req.param("appId"), purgeData)));
|
|
6410
6620
|
} catch (error) {
|
|
@@ -6658,6 +6868,16 @@ var UiRouteRegistry = class {
|
|
|
6658
6868
|
"/api/ncp/sessions/:sessionId/context/compact",
|
|
6659
6869
|
ncpSession.compactSessionContext
|
|
6660
6870
|
],
|
|
6871
|
+
[
|
|
6872
|
+
"get",
|
|
6873
|
+
"/api/ncp/sessions/:sessionId/observations",
|
|
6874
|
+
ncpSession.listSessionObservations
|
|
6875
|
+
],
|
|
6876
|
+
[
|
|
6877
|
+
"patch",
|
|
6878
|
+
"/api/ncp/sessions/:sessionId/observations/:kind/:id",
|
|
6879
|
+
ncpSession.updateSessionObservation
|
|
6880
|
+
],
|
|
6661
6881
|
[
|
|
6662
6882
|
"get",
|
|
6663
6883
|
"/api/ncp/sessions/:sessionId/usage",
|
|
@@ -7058,6 +7278,11 @@ var UiRouteRegistry = class {
|
|
|
7058
7278
|
"/api/runtime/extensions",
|
|
7059
7279
|
app.extensionRuntimeStatus
|
|
7060
7280
|
],
|
|
7281
|
+
[
|
|
7282
|
+
"get",
|
|
7283
|
+
"/api/runtime/extensions/catalog",
|
|
7284
|
+
app.extensionCatalog
|
|
7285
|
+
],
|
|
7061
7286
|
[
|
|
7062
7287
|
"get",
|
|
7063
7288
|
"/api/auth/status",
|