@epoch-agent/server 0.3.1 → 0.4.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 +55 -16
- package/dist/index.js +73 -1
- package/dist/web/assets/index-B8SadfSi.js +373 -0
- package/dist/web/assets/index-YkNh8xAS.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/index-C8_G1o8e.js +0 -373
- package/dist/web/assets/index-DtAA7lvj.css +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Lang, WireSkillImportFailure, WireSkillImportForm, WireSkillRemoveFailure, WireCapabilitiesResponse, WireSkillBodyResponse, EpochUserContent, AgentEvent, WireEnvelope, CustomCommandDef, ExpandedCommand, ModelRef, SetSelectionResult, WireCommandExpansion, WireCustomCommand, WireGoalPhase, WireGoalRefusal, WireTurnState, WireSessionFinish, ApprovalOutcome, QuestionAnswer, SessionSurfaceView, WireSessionReference, WireFileReference, ProviderType, ModelSelectionOrigin, WireModelCaveat, WireModelRejection, ContextBreakdown, PermissionLevel, WirePermissionRememberFailure, WirePluginSourceType, WirePluginRefuseReason, WirePluginEntry, WireModelSource, WireModelProbeStatus, ScheduleDefinition, ScheduleRun, ScheduleBackendKind, OperationType, ScheduleTrigger, WireScheduleIssue, ScheduleRunStatus, TrustLevel, WireSandboxReason, WireAuditOutcome, WireAuditCode, WireCachedApproval, WireCachedDecision, WireToolVerdict, WireToolGateAxis, WireSecurityResponse, WireRewindScope, WireRewindRequest, WireCheckpointSummary, WireRewindPreview, WireRewindResponse, ActiveAgentRole, WireSettingValue, WireSettingLayer, WireSettingWriteLayer, WireSettingFutile, WireSettingApply, WireSettingValueKind, WireSettingsResponse, EpochConfig, WireCompressionLine, WireProviderSummary, WireToolSummary, Diagnostic, WireReplayMessage, WireFileChange, WireAuthGuard, WireWorkspaceDiffResponse, BackgroundTaskInfo, WireTasksResponse, WireBackgroundTask, WireScheduleRow } from '@epoch-agent/protocol';
|
|
1
|
+
import { Lang, WireSkillImportFailure, WireSkillImportForm, WireSkillRemoveFailure, WireCapabilitiesResponse, WireSkillBodyResponse, EpochUserContent, AgentEvent, WireEnvelope, CustomCommandDef, ExpandedCommand, ModelRef, SetSelectionResult, WireCommandExpansion, WireCustomCommand, WireGoalPhase, WireGoalRefusal, WireTurnState, WireSessionFinish, ApprovalOutcome, QuestionAnswer, SessionSurfaceView, WireSessionReference, WireFileReference, ProviderType, ModelSelectionOrigin, WireModelCaveat, WireModelRejection, ContextBreakdown, PermissionLevel, WirePermissionRememberFailure, WirePluginSourceType, WirePluginRefuseReason, WirePluginEntry, WireModelSource, WireModelProbeStatus, ScheduleDefinition, ScheduleRun, ScheduleBackendKind, OperationType, ScheduleTrigger, WireScheduleIssue, ScheduleRunStatus, TrustLevel, WireSandboxReason, WireAuditOutcome, WireAuditCode, WireCachedApproval, WireCachedDecision, WireToolVerdict, WireToolGateAxis, WireSecurityResponse, WireRewindScope, WireRewindRequest, WireCheckpointSummary, WireRewindPreview, WireRewindResponse, ActiveAgentRole, WireSettingValue, WireSettingLayer, WireSettingWriteLayer, WireSettingFutile, WireSettingApply, WireSettingValueKind, WireSettingsResponse, EpochConfig, TokenUsage, WireCompressionLine, WireProviderSummary, WireToolSummary, Diagnostic, WireReplayMessage, WireFileChange, WireAuthGuard, WireWorkspaceDiffResponse, BackgroundTaskInfo, WireTasksResponse, WireBackgroundTask, WireScheduleRow } from '@epoch-agent/protocol';
|
|
2
2
|
import { SerializableApprovalRequest, SerializableQuestionRequest, ApprovalRevokeResult, LevelChangeResult, WorkspaceFilesView } from '@epoch-agent/runtime';
|
|
3
3
|
import { ServerResponse } from 'node:http';
|
|
4
4
|
|
|
@@ -2263,15 +2263,20 @@ interface RuntimeModel {
|
|
|
2263
2263
|
}
|
|
2264
2264
|
|
|
2265
2265
|
/**
|
|
2266
|
-
*
|
|
2266
|
+
* 插件那一页的十条端点(方案 59 §六 E2,2026-08-21;本地源与市场管理 2026-09-04
|
|
2267
|
+
* 补,判据在 protocol 的 `wire-plugin.ts` 文件头第一节那次**翻案**):
|
|
2267
2268
|
*
|
|
2268
2269
|
* ```
|
|
2269
|
-
* GET /api/plugins
|
|
2270
|
-
* POST /api/plugins/install/preview
|
|
2271
|
-
* POST /api/plugins/install
|
|
2272
|
-
* POST /api/plugins/
|
|
2273
|
-
* POST /api/plugins/
|
|
2274
|
-
* POST /api/plugins/
|
|
2270
|
+
* GET /api/plugins 装着的 + 市场里有什么 + 已加的市场 + pendingRestart
|
|
2271
|
+
* POST /api/plugins/install/preview {ref} → 将安装什么,一个字节都不写
|
|
2272
|
+
* POST /api/plugins/install {ref, token} → 真装
|
|
2273
|
+
* POST /api/plugins/install/local/preview {path} → 同上,来源是本机一条目录
|
|
2274
|
+
* POST /api/plugins/install/local {path, token} → 真装
|
|
2275
|
+
* POST /api/plugins/update/preview {name} → 更新会带来什么
|
|
2276
|
+
* POST /api/plugins/update {name, token} → 真更新
|
|
2277
|
+
* POST /api/plugins/uninstall {name} → 卸载
|
|
2278
|
+
* POST /api/plugins/marketplaces {source} → 加一个市场
|
|
2279
|
+
* POST /api/plugins/marketplaces/remove {name} → 移除一个市场
|
|
2275
2280
|
* ```
|
|
2276
2281
|
*
|
|
2277
2282
|
* ## ⚠️ 这一层**一条策略判断都没有**
|
|
@@ -2285,10 +2290,10 @@ interface RuntimeModel {
|
|
|
2285
2290
|
* 界面上是一条画成可点、点了却被拒的行(判据同 `PluginSearchHit.installable`
|
|
2286
2291
|
* 为什么不从结果里剔掉远程那条)。
|
|
2287
2292
|
*
|
|
2288
|
-
* ## ⚠️
|
|
2293
|
+
* ## ⚠️ 那一道闸:**九条 POST 在回环之外一律 403**,这是这个文件的正题
|
|
2289
2294
|
*
|
|
2290
2295
|
* 判据全文在 protocol 的 [wire-plugin.ts](../../protocol/src/wire-plugin.ts) 文件头
|
|
2291
|
-
*
|
|
2296
|
+
* 第二节,这里记它对这一层的五条直接后果:
|
|
2292
2297
|
*
|
|
2293
2298
|
* 1. **`ctx.lanExposed` 为真时 403 `plugin-write-lan-exposed`,一个字节都不写。**
|
|
2294
2299
|
* 装一包插件会落下 `hooks.json` 和 `mcp.json`,那两样**起子进程** ——
|
|
@@ -2297,8 +2302,12 @@ interface RuntimeModel {
|
|
|
2297
2302
|
* 2. **`install/preview` 也吃这道闸,虽然它一个字节都不写**:`allowRemote: true`
|
|
2298
2303
|
* 的部署上,预览一条远程条目会 spawn `git clone --depth 1` 到 staging。
|
|
2299
2304
|
* 按「写不写盘」切一刀会漏掉它;
|
|
2300
|
-
* 3.
|
|
2301
|
-
*
|
|
2305
|
+
* 3. **本地那两条同样挡**,虽然它们既不拉网也不起子进程。本地路径这一档的
|
|
2306
|
+
* **全部前提**是「网线另一头就是这台机器」,而 `lanExposed` 为真时那句前提是
|
|
2307
|
+
* 假的 —— 放行的话,LAN 上的人能指着这台机器上任意一个目录说「装它」,
|
|
2308
|
+
* 而那个目录里的 `hooks.json` 是谁写的他知道我们不知道;
|
|
2309
|
+
* 4. **那道闸在读请求体之前**,同 `addRole`:被拒的那一发连正文都不该被解析;
|
|
2310
|
+
* 5. **`GET` 刻意不挡。** 那一份里是插件名 / 版本 / 目录路径,和
|
|
2302
2311
|
* `GET /api/sessions/:id/capabilities` 早就在发的那些同一档 —— 而挡掉它的
|
|
2303
2312
|
* 唯一后果是那一页在 LAN 那一档下一片空白,
|
|
2304
2313
|
* 偏偏那时用户最想知道的就是「我装了什么、生效了没有」。
|
|
@@ -2437,13 +2446,27 @@ type ActionOutcomeView = {
|
|
|
2437
2446
|
ok: true;
|
|
2438
2447
|
detail: string;
|
|
2439
2448
|
} | RefusalView;
|
|
2449
|
+
/** `PluginMarketplaceEntry`(runtime)的镜像 */
|
|
2450
|
+
interface MarketplaceView {
|
|
2451
|
+
name: string;
|
|
2452
|
+
source: string;
|
|
2453
|
+
entries: number;
|
|
2454
|
+
addedAt: number;
|
|
2455
|
+
local: boolean;
|
|
2456
|
+
}
|
|
2457
|
+
/** 加 / 移除一个市场的结局。移除成功那一档没有 `marketplace` —— 它已经不在表里了 */
|
|
2458
|
+
type MarketOutcomeView = {
|
|
2459
|
+
ok: true;
|
|
2460
|
+
marketplace?: MarketplaceView;
|
|
2461
|
+
} | RefusalView;
|
|
2440
2462
|
/**
|
|
2441
|
-
* `PluginControl`(runtime)在服务端眼里的样子 ——
|
|
2463
|
+
* `PluginControl`(runtime)在服务端眼里的样子 —— **只有那十一个动词加一格布尔**。
|
|
2442
2464
|
*
|
|
2443
2465
|
* 镜像里只有它们,于是这个包**写不出** core 的 `setPluginEnabled`
|
|
2444
|
-
* (停用一个插件会静默拿掉别人正依赖的一批命令,正当性和「装 /
|
|
2445
|
-
*
|
|
2446
|
-
*
|
|
2466
|
+
* (停用一个插件会静默拿掉别人正依赖的一批命令,正当性和「装 / 卸」不是一回事);
|
|
2467
|
+
* 装进来的那两个动词也各自只表达得出一种来源 —— `install(ref)` 表达不出一条路径,
|
|
2468
|
+
* `installLocal(path)` 表达不出一个 `github:`(那不是靠 review 盯住的,是编译期的事,
|
|
2469
|
+
* 同 `SkillImportControlView` 只有两个动作、`RoleWriteControlView` 只有 `add`)。
|
|
2447
2470
|
*
|
|
2448
2471
|
* ⚠️ 每个方法都带 `lang?`。**镜像上漏一格不一定会红**(多一个可选参数是宽化,
|
|
2449
2472
|
* `EpochRuntime` 照样满足这份镜像),而漏了的表现是这一层递不出去、一声不吭
|
|
@@ -2455,9 +2478,14 @@ interface PluginControlView {
|
|
|
2455
2478
|
search(keyword?: string): readonly PluginHitView[];
|
|
2456
2479
|
preview(ref: string, lang?: Lang): Promise<PreviewOutcomeView>;
|
|
2457
2480
|
install(ref: string, token: string, lang?: Lang): Promise<InstallOutcomeView>;
|
|
2481
|
+
previewLocal(path: string, lang?: Lang): Promise<PreviewOutcomeView>;
|
|
2482
|
+
installLocal(path: string, token: string, lang?: Lang): Promise<InstallOutcomeView>;
|
|
2458
2483
|
previewUpdate(name: string, lang?: Lang): Promise<PreviewOutcomeView>;
|
|
2459
2484
|
update(name: string, token: string, lang?: Lang): Promise<InstallOutcomeView>;
|
|
2460
2485
|
uninstall(name: string, lang?: Lang): Promise<ActionOutcomeView>;
|
|
2486
|
+
marketplaces(): readonly MarketplaceView[];
|
|
2487
|
+
addMarketplace(source: string, lang?: Lang): Promise<MarketOutcomeView>;
|
|
2488
|
+
removeMarketplace(name: string, lang?: Lang): Promise<MarketOutcomeView>;
|
|
2461
2489
|
readonly pendingRestart: boolean;
|
|
2462
2490
|
}
|
|
2463
2491
|
/**
|
|
@@ -3965,6 +3993,17 @@ interface WebRuntimeView extends RuntimeCapabilities, RuntimeSecurity, RuntimeSe
|
|
|
3965
3993
|
*/
|
|
3966
3994
|
artifactsRoot: string;
|
|
3967
3995
|
usageScope: 'session' | 'run';
|
|
3996
|
+
/**
|
|
3997
|
+
* 一段会话到此刻的**累计**用量(2026-09-04)。`EpochRuntime.sessionUsage`
|
|
3998
|
+
* 结构上正好满足它。
|
|
3999
|
+
*
|
|
4000
|
+
* 收窄成一个函数而不是一份快照,理由和 `tools` 那个 getter 同一条:这本账
|
|
4001
|
+
* 在别的会话 / 别的进程里也会被写,拍一张快照的话第二个会话读到的是第一个的数。
|
|
4002
|
+
*
|
|
4003
|
+
* ⚠️ **它是「刷新之后总账没了」唯一的来路**,判据全文在
|
|
4004
|
+
* `WireMessageListResponse.usage` 上。`undefined` = 不知道,不是 0。
|
|
4005
|
+
*/
|
|
4006
|
+
sessionUsage(sessionId: string): TokenUsage | undefined;
|
|
3968
4007
|
/**
|
|
3969
4008
|
* 自动压缩那条线(决定 8 的第三个时刻,2026-08-16)。`EpochRuntime.compression`
|
|
3970
4009
|
* 结构上正好满足它 —— **对不上就是两边长歪了,装配那一行当场编译不过**。
|
package/dist/index.js
CHANGED
|
@@ -1449,6 +1449,7 @@ function config(ctx, res, lang) {
|
|
|
1449
1449
|
...runtime.config.budget?.maxCostUsd !== void 0 ? { maxCostUsd: runtime.config.budget.maxCostUsd } : {},
|
|
1450
1450
|
...runtime.config.brand !== void 0 ? { brand: runtime.config.brand } : {},
|
|
1451
1451
|
...runtime.config.sidebarMenu !== void 0 ? { sidebarMenu: runtime.config.sidebarMenu } : {},
|
|
1452
|
+
...runtime.config.blankCards !== void 0 ? { blankCards: runtime.config.blankCards } : {},
|
|
1452
1453
|
provider: runtime.providerInfo,
|
|
1453
1454
|
tools: runtime.tools,
|
|
1454
1455
|
diagnostics: (lang && runtime.diagnosticsIn?.(lang)) ?? runtime.diagnosticList,
|
|
@@ -1540,7 +1541,11 @@ function listMessages(ctx, res, sessionId, lang) {
|
|
|
1540
1541
|
return sendUnknownSession(res, sessionId, lang);
|
|
1541
1542
|
}
|
|
1542
1543
|
const messages = ctx.runtime.sessionStore?.loadMessages(sessionId) ?? [];
|
|
1543
|
-
|
|
1544
|
+
const usage = ctx.runtime.sessionUsage(sessionId);
|
|
1545
|
+
sendJson(res, 200, {
|
|
1546
|
+
messages,
|
|
1547
|
+
...usage ? { usage } : {}
|
|
1548
|
+
});
|
|
1544
1549
|
}
|
|
1545
1550
|
async function postMessage(ctx, req, res, sessionId, lang) {
|
|
1546
1551
|
if (!ctx.hub.has(sessionId)) {
|
|
@@ -2453,6 +2458,15 @@ function toWirePluginHit(hit, installedNames) {
|
|
|
2453
2458
|
installed: installedNames.has(hit.entry.name)
|
|
2454
2459
|
};
|
|
2455
2460
|
}
|
|
2461
|
+
function toWireMarketplace(market) {
|
|
2462
|
+
return {
|
|
2463
|
+
name: market.name,
|
|
2464
|
+
source: market.source,
|
|
2465
|
+
entries: market.entries,
|
|
2466
|
+
addedAt: market.addedAt,
|
|
2467
|
+
local: market.local
|
|
2468
|
+
};
|
|
2469
|
+
}
|
|
2456
2470
|
function toWirePreview2(preview) {
|
|
2457
2471
|
const { manifest, source, inventory } = preview;
|
|
2458
2472
|
return {
|
|
@@ -2505,6 +2519,7 @@ function listPlugins(ctx, res, lang) {
|
|
|
2505
2519
|
sendJson(res, 200, {
|
|
2506
2520
|
installed: installed.map(toWirePluginEntry),
|
|
2507
2521
|
hits: control.search().map((hit) => toWirePluginHit(hit, installedNames)),
|
|
2522
|
+
marketplaces: control.marketplaces().map(toWireMarketplace),
|
|
2508
2523
|
pendingRestart: control.pendingRestart
|
|
2509
2524
|
});
|
|
2510
2525
|
}
|
|
@@ -2534,6 +2549,14 @@ async function previewPluginInstall(ctx, req, res, lang) {
|
|
|
2534
2549
|
if (!body.ok) return sendError(res, body.status, "bad-body", body.message);
|
|
2535
2550
|
sendPreview(res, await control.preview(fieldOf(asRecord(body.value), "ref"), lang));
|
|
2536
2551
|
}
|
|
2552
|
+
async function previewLocalPluginInstall(ctx, req, res, lang) {
|
|
2553
|
+
if (refusedByLan(ctx, res, lang)) return;
|
|
2554
|
+
const control = controlOf(ctx, res, lang);
|
|
2555
|
+
if (!control) return;
|
|
2556
|
+
const body = await readJsonBody(req);
|
|
2557
|
+
if (!body.ok) return sendError(res, body.status, "bad-body", body.message);
|
|
2558
|
+
sendPreview(res, await control.previewLocal(fieldOf(asRecord(body.value), "path"), lang));
|
|
2559
|
+
}
|
|
2537
2560
|
async function previewPluginUpdate(ctx, req, res, lang) {
|
|
2538
2561
|
if (refusedByLan(ctx, res, lang)) return;
|
|
2539
2562
|
const control = controlOf(ctx, res, lang);
|
|
@@ -2574,6 +2597,19 @@ async function installPluginFromMarket(ctx, req, res, lang) {
|
|
|
2574
2597
|
await control.install(fieldOf(payload, "ref"), fieldOf(payload, "token"), lang)
|
|
2575
2598
|
);
|
|
2576
2599
|
}
|
|
2600
|
+
async function installLocalPlugin(ctx, req, res, lang) {
|
|
2601
|
+
if (refusedByLan(ctx, res, lang)) return;
|
|
2602
|
+
const control = controlOf(ctx, res, lang);
|
|
2603
|
+
if (!control) return;
|
|
2604
|
+
const body = await readJsonBody(req);
|
|
2605
|
+
if (!body.ok) return sendError(res, body.status, "bad-body", body.message);
|
|
2606
|
+
const payload = asRecord(body.value);
|
|
2607
|
+
sendAction(
|
|
2608
|
+
res,
|
|
2609
|
+
control,
|
|
2610
|
+
await control.installLocal(fieldOf(payload, "path"), fieldOf(payload, "token"), lang)
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2577
2613
|
async function updateInstalledPlugin(ctx, req, res, lang) {
|
|
2578
2614
|
if (refusedByLan(ctx, res, lang)) return;
|
|
2579
2615
|
const control = controlOf(ctx, res, lang);
|
|
@@ -2595,6 +2631,30 @@ async function uninstallPluginByName(ctx, req, res, lang) {
|
|
|
2595
2631
|
if (!body.ok) return sendError(res, body.status, "bad-body", body.message);
|
|
2596
2632
|
sendAction(res, control, await control.uninstall(fieldOf(asRecord(body.value), "name"), lang));
|
|
2597
2633
|
}
|
|
2634
|
+
function sendMarket(res, outcome) {
|
|
2635
|
+
sendJson(res, 200, {
|
|
2636
|
+
ok: outcome.ok,
|
|
2637
|
+
marketplace: outcome.ok && outcome.marketplace ? toWireMarketplace(outcome.marketplace) : null,
|
|
2638
|
+
reason: outcome.ok ? null : outcome.reason,
|
|
2639
|
+
detail: outcome.ok ? null : outcome.detail
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
async function addPluginMarketplace(ctx, req, res, lang) {
|
|
2643
|
+
if (refusedByLan(ctx, res, lang)) return;
|
|
2644
|
+
const control = controlOf(ctx, res, lang);
|
|
2645
|
+
if (!control) return;
|
|
2646
|
+
const body = await readJsonBody(req);
|
|
2647
|
+
if (!body.ok) return sendError(res, body.status, "bad-body", body.message);
|
|
2648
|
+
sendMarket(res, await control.addMarketplace(fieldOf(asRecord(body.value), "source"), lang));
|
|
2649
|
+
}
|
|
2650
|
+
async function removePluginMarketplace(ctx, req, res, lang) {
|
|
2651
|
+
if (refusedByLan(ctx, res, lang)) return;
|
|
2652
|
+
const control = controlOf(ctx, res, lang);
|
|
2653
|
+
if (!control) return;
|
|
2654
|
+
const body = await readJsonBody(req);
|
|
2655
|
+
if (!body.ok) return sendError(res, body.status, "bad-body", body.message);
|
|
2656
|
+
sendMarket(res, await control.removeMarketplace(fieldOf(asRecord(body.value), "name"), lang));
|
|
2657
|
+
}
|
|
2598
2658
|
function toWireProvider(option, lang) {
|
|
2599
2659
|
return {
|
|
2600
2660
|
type: option.type,
|
|
@@ -4185,6 +4245,12 @@ async function handleApi(opts, req, res, method, segments, lang) {
|
|
|
4185
4245
|
if (resource === "plugins" && first === "install" && second === void 0 && method === "POST") {
|
|
4186
4246
|
return installPluginFromMarket(ctx, req, res, lang);
|
|
4187
4247
|
}
|
|
4248
|
+
if (resource === "plugins" && first === "install" && second === "local" && detail === "preview" && method === "POST") {
|
|
4249
|
+
return previewLocalPluginInstall(ctx, req, res, lang);
|
|
4250
|
+
}
|
|
4251
|
+
if (resource === "plugins" && first === "install" && second === "local" && detail === void 0 && method === "POST") {
|
|
4252
|
+
return installLocalPlugin(ctx, req, res, lang);
|
|
4253
|
+
}
|
|
4188
4254
|
if (resource === "plugins" && first === "update" && second === "preview" && method === "POST") {
|
|
4189
4255
|
return previewPluginUpdate(ctx, req, res, lang);
|
|
4190
4256
|
}
|
|
@@ -4194,6 +4260,12 @@ async function handleApi(opts, req, res, method, segments, lang) {
|
|
|
4194
4260
|
if (resource === "plugins" && first === "uninstall" && second === void 0 && method === "POST") {
|
|
4195
4261
|
return uninstallPluginByName(ctx, req, res, lang);
|
|
4196
4262
|
}
|
|
4263
|
+
if (resource === "plugins" && first === "marketplaces" && second === "remove" && method === "POST") {
|
|
4264
|
+
return removePluginMarketplace(ctx, req, res, lang);
|
|
4265
|
+
}
|
|
4266
|
+
if (resource === "plugins" && first === "marketplaces" && second === void 0 && method === "POST") {
|
|
4267
|
+
return addPluginMarketplace(ctx, req, res, lang);
|
|
4268
|
+
}
|
|
4197
4269
|
if (resource === "providers" && first === void 0 && isRead(method)) {
|
|
4198
4270
|
return listProviders(ctx, res, lang);
|
|
4199
4271
|
}
|