@epoch-agent/server 0.2.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +204 -76
- package/dist/index.d.ts +376 -31
- package/dist/index.js +523 -16
- package/dist/web/assets/index-DDRS10ig.css +1 -0
- package/dist/web/assets/index-uicxKHU-.js +373 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/index-Bj3SdU3h.js +0 -366
- package/dist/web/assets/index-cRd3MeBE.css +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Lang, WireSkillImportFailure, WireSkillImportForm, 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, 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, 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
|
|
|
@@ -543,11 +543,18 @@ type ImportResultView<T> = ({
|
|
|
543
543
|
issues?: readonly IssueView[];
|
|
544
544
|
};
|
|
545
545
|
/**
|
|
546
|
-
* `SkillControl`(runtime)在服务端眼里的样子 ——
|
|
546
|
+
* `SkillControl`(runtime)在服务端眼里的样子 —— **只有导入那两个动作**。
|
|
547
547
|
*
|
|
548
|
-
* 镜像里只有它们,于是这个包**写不出** `SkillSystem`
|
|
549
|
-
* 也写不出会 `matchCount++` 的 `view()
|
|
550
|
-
*
|
|
548
|
+
* 镜像里只有它们,于是这个包**写不出** `SkillSystem` 上那几个写方法、
|
|
549
|
+
* 也写不出会 `matchCount++` 的 `view()`:那不是靠 review 盯住的,
|
|
550
|
+
* 是编译期的事(同 `McpControlView` 只有 reconnect)。
|
|
551
|
+
*
|
|
552
|
+
* ⚠️ **「删一条技能」不在这张镜像里,它自己有一张**
|
|
553
|
+
* ([skill-remove.ts](./skill-remove.js) 的 `SkillRemoveControlView`),
|
|
554
|
+
* 而 `RuntimeCapabilities.skillWrite` 声明成两张的**交集**。镜像跟着 handler
|
|
555
|
+
* 走、而不是跟着 runtime 那一格走,是这一套收窄能起作用的前提:一张把两件事
|
|
556
|
+
* 都装进来的镜像,等于任何一个 handler 都能顺手调另一件事 —— 判据同
|
|
557
|
+
* `capability.ts` 上 `mcp` 那一格。
|
|
551
558
|
*/
|
|
552
559
|
interface SkillImportControlView {
|
|
553
560
|
preview(source: string, lang?: Lang): Promise<ImportResultView<{
|
|
@@ -556,6 +563,83 @@ interface SkillImportControlView {
|
|
|
556
563
|
import(source: string, token: string, lang?: Lang): Promise<ImportResultView<ImportDoneView>>;
|
|
557
564
|
}
|
|
558
565
|
|
|
566
|
+
/**
|
|
567
|
+
* 删掉一条技能的那一条端点(2026-09-01):
|
|
568
|
+
*
|
|
569
|
+
* ```
|
|
570
|
+
* POST /api/skills/remove {name} → 递归删掉 ~/.epoch/skills/<分类>/<名字>
|
|
571
|
+
* ```
|
|
572
|
+
*
|
|
573
|
+
* 起因是一句话:**能加就得能删**。在这之前能力页技能那一栏只有「导入技能」,
|
|
574
|
+
* 拿掉一份得让用户自己去 `~/.epoch/skills/` 里翻目录 —— 而那一栏里的每一行
|
|
575
|
+
* 都是每一轮都在花钱的常驻开销(行尾那个 tokens 数就是它)。
|
|
576
|
+
*
|
|
577
|
+
* ## 一、为什么是 POST,为什么没有 token
|
|
578
|
+
*
|
|
579
|
+
* POST 和导入那两条同一条判据(`auth.ts` 的 Origin 校验只在非安全方法上要求,
|
|
580
|
+
* 而这条会在用户机器上真的删文件)。**但没有「预览 → 确认」那一对**,
|
|
581
|
+
* 而那不是省事:
|
|
582
|
+
*
|
|
583
|
+
* - 导入那个 token 防的是「用户看过的那一份」和「真装上的那一份」不是一份 ——
|
|
584
|
+
* 预览和导入之间目录可能被改过。删除这边没有这条缝:**要删掉的东西由名字
|
|
585
|
+
* 唯一确定**(技能名在 `SkillSystem` 里是全局唯一的 map 键),而不是由一次
|
|
586
|
+
* 扫描的结果确定;
|
|
587
|
+
* - 删除的风险不是「删错了一份」,是**不可撤销**(`rmSync(recursive)`,没有
|
|
588
|
+
* 回收站)。挡它的是另外两样东西:界面上那一步「再按一次确认」,
|
|
589
|
+
* 和回执里那个 `path` —— 用户得看得见自己刚销毁了盘上的哪一处。
|
|
590
|
+
*
|
|
591
|
+
* ## 二、⚠️ 这条**不吃 `refusedByLan`**,而那是一个判断
|
|
592
|
+
*
|
|
593
|
+
* 插件那几个写口和 `POST /api/roles` 都要求回环绑定才给写。这一条不要求,
|
|
594
|
+
* 判据是:**导入那条也不要求**。只给删除加一道闸的结果,是 `--host 0.0.0.0`
|
|
595
|
+
* 那一档下技能变成「只能加不能删」—— 那正是这次要修的病,换个地方原样长回来。
|
|
596
|
+
*
|
|
597
|
+
* 两条一起加闸不行(那是把已经在用的导入功能收回去),所以这一格的口径是
|
|
598
|
+
* 「和导入同档」。真要收,得两条一起收,而那是一次独立的决定 ——
|
|
599
|
+
* 别只改这半边。
|
|
600
|
+
*
|
|
601
|
+
* ## 三、只有**用户级**删得掉,而那道闸不在这一层
|
|
602
|
+
*
|
|
603
|
+
* 项目级 / 插件 / 宿主那三档 `SkillSystem.requireWritable()` 会抛,
|
|
604
|
+
* runtime 的 `SkillControl.remove` 把它翻成 `reason: 'readonly'` 加上 core
|
|
605
|
+
* 那句带路径的原话。这一层**不自己判 scope** —— 判两遍会有一天判得不一样,
|
|
606
|
+
* 而只有 core 那一遍碰得到磁盘。
|
|
607
|
+
*
|
|
608
|
+
* 界面上那颗按钮只画在用户级那一组的行上,但那是**体贴,不是安全性质**:
|
|
609
|
+
* 手搓一条 `POST /api/skills/remove {"name":"项目里那条"}` 会拿到 200 +
|
|
610
|
+
* `ok:false` + `readonly`。
|
|
611
|
+
*
|
|
612
|
+
* ## 四、失败是 200,判据在 `WireSkillRemoveResponse` 上
|
|
613
|
+
*
|
|
614
|
+
* 四个 `reason` 各对一个不同的下一步(那张表在 protocol 那个类型上)。
|
|
615
|
+
* `detail` 那句话在 **core / runtime** 里现渲染,所以 `lang` 要从这一层
|
|
616
|
+
* 一路递下去 —— 这条病 2026-08-18 在导入那一屏上实测见过一次
|
|
617
|
+
* (判据在 [skill-import.ts](./skill-import.js) 文件头倒数第三节)。
|
|
618
|
+
*/
|
|
619
|
+
|
|
620
|
+
/** 删成了那一下回的东西(runtime 的 `SkillRemoveDone`) */
|
|
621
|
+
interface RemoveDoneView {
|
|
622
|
+
name: string;
|
|
623
|
+
path: string;
|
|
624
|
+
}
|
|
625
|
+
type RemoveResultView = ({
|
|
626
|
+
ok: true;
|
|
627
|
+
} & RemoveDoneView) | {
|
|
628
|
+
ok: false;
|
|
629
|
+
reason: WireSkillRemoveFailure;
|
|
630
|
+
detail: string;
|
|
631
|
+
};
|
|
632
|
+
/**
|
|
633
|
+
* `SkillControl`(runtime)在服务端眼里的样子 —— **只有 `remove` 一个动作**。
|
|
634
|
+
*
|
|
635
|
+
* 和 [skill-import.ts](./skill-import.js) 那张镜像刻意分开,理由在那张镜像的
|
|
636
|
+
* ⚠️ 上:镜像跟着 handler 走,于是**这个文件里写不出 `import`**,
|
|
637
|
+
* 而 `RuntimeCapabilities.skillWrite` 是两张的交集(同 `mcp` 那一格)。
|
|
638
|
+
*/
|
|
639
|
+
interface SkillRemoveControlView {
|
|
640
|
+
remove(name: string, lang?: Lang): Promise<RemoveResultView>;
|
|
641
|
+
}
|
|
642
|
+
|
|
559
643
|
/**
|
|
560
644
|
* 能力页的取数与投影 —— `GET /api/sessions/:id/capabilities`(方案 42 PR-1),
|
|
561
645
|
* 外加技能正文那条下钻(方案 56 §1.2)。
|
|
@@ -694,12 +778,21 @@ interface RuntimeCapabilities {
|
|
|
694
778
|
*/
|
|
695
779
|
skillIndexResidency(role: string | null): ReadonlyMap<string, 'indexed' | 'capped' | 'role'>;
|
|
696
780
|
/**
|
|
697
|
-
*
|
|
781
|
+
* 技能目录的写口:从**本机目录**导入(方案 42 §六)+ 删掉一条用户级技能
|
|
782
|
+
* (2026-09-01)。**进程级**,同 {@link mcp}。
|
|
698
783
|
*
|
|
699
|
-
* ⚠️
|
|
784
|
+
* ⚠️ 导入收的是**路径**不是字节 —— 那是那条路上的安全性质本体,判据全文在
|
|
700
785
|
* [skill-import.ts](./skill-import.js) 的文件头。
|
|
786
|
+
*
|
|
787
|
+
* ⚠️ **交集,理由逐字同下面 {@link mcp} 那一格**:两个动作挂在同一个 runtime
|
|
788
|
+
* 对象上(`runtime.skillWrite`),分成两份声明是为了让镜像跟着 handler 走 ——
|
|
789
|
+
* 于是 `skill-import.ts` 里写不出 `remove`、`skill-remove.ts` 里写不出 `import`。
|
|
790
|
+
*
|
|
791
|
+
* ⚠️ **删除那条刻意不吃 `refusedByLan`**,和导入同档;那是一个判断而不是遗漏,
|
|
792
|
+
* 判据全文在 [skill-remove.ts](./skill-remove.js) 文件头第二节 ——
|
|
793
|
+
* 要收得两条一起收。
|
|
701
794
|
*/
|
|
702
|
-
readonly
|
|
795
|
+
readonly skillWrite: SkillImportControlView & SkillRemoveControlView;
|
|
703
796
|
/**
|
|
704
797
|
* MCP 的写口:重连一台(方案 56 §1.1)+ 加一台(2026-08-18)+ **那份文件的原文
|
|
705
798
|
* 读写与应用**(2026-08-18)。**全都是进程级**。
|
|
@@ -1870,7 +1963,16 @@ interface SessionPermissionsView {
|
|
|
1870
1963
|
managed(): {
|
|
1871
1964
|
bypassDisabled: boolean;
|
|
1872
1965
|
};
|
|
1873
|
-
|
|
1966
|
+
/**
|
|
1967
|
+
* @param opts.remember 这一发**算不算用户显式挑的**(2026-08-31)。
|
|
1968
|
+
* ⚠️ **照抄真身的必填形状**(runtime 的 `SessionPermissions.setLevel`),
|
|
1969
|
+
* 别在这份镜像上写成可选的:真身那边这个参数存在的理由是「定时任务和用户
|
|
1970
|
+
* 菜单共用同一个方法」,写成可选之后,漏传的那一方会静默拿到默认行为 ——
|
|
1971
|
+
* 而那正是这个参数要防的东西。三行表在 runtime 的 `DefaultLevelSlot` 上。
|
|
1972
|
+
*/
|
|
1973
|
+
setLevel(level: PermissionLevel, opts: {
|
|
1974
|
+
remember: boolean;
|
|
1975
|
+
}): SetLevelView;
|
|
1874
1976
|
}
|
|
1875
1977
|
/**
|
|
1876
1978
|
* 一次换档的结果。**只有码,没有句子** —— 措辞归浏览器的两份 catalog
|
|
@@ -1878,6 +1980,14 @@ interface SessionPermissionsView {
|
|
|
1878
1980
|
*/
|
|
1879
1981
|
type SetLevelView = {
|
|
1880
1982
|
ok: true;
|
|
1983
|
+
/**
|
|
1984
|
+
* 「换成了,但没记住」(2026-08-31)。**只在真没记住时有值** ——
|
|
1985
|
+
* 它直接转成 `WirePermissionSetResponse.notRemembered`,判据在那儿。
|
|
1986
|
+
*/
|
|
1987
|
+
notRemembered?: {
|
|
1988
|
+
reason: WirePermissionRememberFailure;
|
|
1989
|
+
path?: string;
|
|
1990
|
+
};
|
|
1881
1991
|
} | {
|
|
1882
1992
|
ok: false;
|
|
1883
1993
|
reason: 'managed-bypass-disabled';
|
|
@@ -2153,15 +2263,20 @@ interface RuntimeModel {
|
|
|
2153
2263
|
}
|
|
2154
2264
|
|
|
2155
2265
|
/**
|
|
2156
|
-
*
|
|
2266
|
+
* 插件那一页的十条端点(方案 59 §六 E2,2026-08-21;本地源与市场管理 2026-09-04
|
|
2267
|
+
* 补,判据在 protocol 的 `wire-plugin.ts` 文件头第一节那次**翻案**):
|
|
2157
2268
|
*
|
|
2158
2269
|
* ```
|
|
2159
|
-
* GET /api/plugins
|
|
2160
|
-
* POST /api/plugins/install/preview
|
|
2161
|
-
* POST /api/plugins/install
|
|
2162
|
-
* POST /api/plugins/
|
|
2163
|
-
* POST /api/plugins/
|
|
2164
|
-
* 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} → 移除一个市场
|
|
2165
2280
|
* ```
|
|
2166
2281
|
*
|
|
2167
2282
|
* ## ⚠️ 这一层**一条策略判断都没有**
|
|
@@ -2175,10 +2290,10 @@ interface RuntimeModel {
|
|
|
2175
2290
|
* 界面上是一条画成可点、点了却被拒的行(判据同 `PluginSearchHit.installable`
|
|
2176
2291
|
* 为什么不从结果里剔掉远程那条)。
|
|
2177
2292
|
*
|
|
2178
|
-
* ## ⚠️
|
|
2293
|
+
* ## ⚠️ 那一道闸:**九条 POST 在回环之外一律 403**,这是这个文件的正题
|
|
2179
2294
|
*
|
|
2180
2295
|
* 判据全文在 protocol 的 [wire-plugin.ts](../../protocol/src/wire-plugin.ts) 文件头
|
|
2181
|
-
*
|
|
2296
|
+
* 第二节,这里记它对这一层的五条直接后果:
|
|
2182
2297
|
*
|
|
2183
2298
|
* 1. **`ctx.lanExposed` 为真时 403 `plugin-write-lan-exposed`,一个字节都不写。**
|
|
2184
2299
|
* 装一包插件会落下 `hooks.json` 和 `mcp.json`,那两样**起子进程** ——
|
|
@@ -2187,8 +2302,12 @@ interface RuntimeModel {
|
|
|
2187
2302
|
* 2. **`install/preview` 也吃这道闸,虽然它一个字节都不写**:`allowRemote: true`
|
|
2188
2303
|
* 的部署上,预览一条远程条目会 spawn `git clone --depth 1` 到 staging。
|
|
2189
2304
|
* 按「写不写盘」切一刀会漏掉它;
|
|
2190
|
-
* 3.
|
|
2191
|
-
*
|
|
2305
|
+
* 3. **本地那两条同样挡**,虽然它们既不拉网也不起子进程。本地路径这一档的
|
|
2306
|
+
* **全部前提**是「网线另一头就是这台机器」,而 `lanExposed` 为真时那句前提是
|
|
2307
|
+
* 假的 —— 放行的话,LAN 上的人能指着这台机器上任意一个目录说「装它」,
|
|
2308
|
+
* 而那个目录里的 `hooks.json` 是谁写的他知道我们不知道;
|
|
2309
|
+
* 4. **那道闸在读请求体之前**,同 `addRole`:被拒的那一发连正文都不该被解析;
|
|
2310
|
+
* 5. **`GET` 刻意不挡。** 那一份里是插件名 / 版本 / 目录路径,和
|
|
2192
2311
|
* `GET /api/sessions/:id/capabilities` 早就在发的那些同一档 —— 而挡掉它的
|
|
2193
2312
|
* 唯一后果是那一页在 LAN 那一档下一片空白,
|
|
2194
2313
|
* 偏偏那时用户最想知道的就是「我装了什么、生效了没有」。
|
|
@@ -2327,13 +2446,27 @@ type ActionOutcomeView = {
|
|
|
2327
2446
|
ok: true;
|
|
2328
2447
|
detail: string;
|
|
2329
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;
|
|
2330
2462
|
/**
|
|
2331
|
-
* `PluginControl`(runtime)在服务端眼里的样子 ——
|
|
2463
|
+
* `PluginControl`(runtime)在服务端眼里的样子 —— **只有那十一个动词加一格布尔**。
|
|
2332
2464
|
*
|
|
2333
2465
|
* 镜像里只有它们,于是这个包**写不出** core 的 `setPluginEnabled`
|
|
2334
|
-
* (停用一个插件会静默拿掉别人正依赖的一批命令,正当性和「装 /
|
|
2335
|
-
*
|
|
2336
|
-
*
|
|
2466
|
+
* (停用一个插件会静默拿掉别人正依赖的一批命令,正当性和「装 / 卸」不是一回事);
|
|
2467
|
+
* 装进来的那两个动词也各自只表达得出一种来源 —— `install(ref)` 表达不出一条路径,
|
|
2468
|
+
* `installLocal(path)` 表达不出一个 `github:`(那不是靠 review 盯住的,是编译期的事,
|
|
2469
|
+
* 同 `SkillImportControlView` 只有两个动作、`RoleWriteControlView` 只有 `add`)。
|
|
2337
2470
|
*
|
|
2338
2471
|
* ⚠️ 每个方法都带 `lang?`。**镜像上漏一格不一定会红**(多一个可选参数是宽化,
|
|
2339
2472
|
* `EpochRuntime` 照样满足这份镜像),而漏了的表现是这一层递不出去、一声不吭
|
|
@@ -2345,9 +2478,14 @@ interface PluginControlView {
|
|
|
2345
2478
|
search(keyword?: string): readonly PluginHitView[];
|
|
2346
2479
|
preview(ref: string, lang?: Lang): Promise<PreviewOutcomeView>;
|
|
2347
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>;
|
|
2348
2483
|
previewUpdate(name: string, lang?: Lang): Promise<PreviewOutcomeView>;
|
|
2349
2484
|
update(name: string, token: string, lang?: Lang): Promise<InstallOutcomeView>;
|
|
2350
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>;
|
|
2351
2489
|
readonly pendingRestart: boolean;
|
|
2352
2490
|
}
|
|
2353
2491
|
/**
|
|
@@ -2361,10 +2499,10 @@ interface PluginControlView {
|
|
|
2361
2499
|
declare function toWirePluginEntry(entry: PluginEntryView): WirePluginEntry;
|
|
2362
2500
|
|
|
2363
2501
|
/**
|
|
2364
|
-
*
|
|
2365
|
-
* `POST /api/providers/:type/models`。
|
|
2502
|
+
* 「我们支持哪几家、这一家有哪些模型、给这一家配一把 key」 —— `GET /api/providers`、
|
|
2503
|
+
* `POST /api/providers/:type/models` 和 `POST /api/providers/:type/key`。
|
|
2366
2504
|
*
|
|
2367
|
-
* ## ⚠️
|
|
2505
|
+
* ## ⚠️ 这三条**进程级,URL 上一个 `:id` 都没有**
|
|
2368
2506
|
*
|
|
2369
2507
|
* 判据同 `POST /api/mcp/:name/reconnect` 和 `GET /api/workspaces/dirs`:
|
|
2370
2508
|
* provider 清单和模型清单**不属于某一段会话**。挂到 `/sessions/:id/` 底下会得到
|
|
@@ -2408,6 +2546,17 @@ declare function toWirePluginEntry(entry: PluginEntryView): WirePluginEntry;
|
|
|
2408
2546
|
* (`cli/src/commands/model.ts` 的 `describeDiscovery()`),照抄过来就能省一份
|
|
2409
2547
|
* catalog。不许 —— 那一句是给同进程宿主(终端)拼的一次渲染,
|
|
2410
2548
|
* 而且它只分两档(有没有 key),这一屏要分四档。
|
|
2549
|
+
*
|
|
2550
|
+
* ⚠️ 配 key 那一条上同一个诱惑又来了一遍,形状是 `SecretWriteResult.detail`
|
|
2551
|
+
* (「已写入系统钥匙串」那句现成的话)。**照旧不发**:下发的是
|
|
2552
|
+
* `backend` 这个码,措辞在浏览器那侧。判据逐字同上。
|
|
2553
|
+
*
|
|
2554
|
+
* ## ⚠️ 配 key 那一条是**单向**的:key 上得去,下不来
|
|
2555
|
+
*
|
|
2556
|
+
* 请求体里有裸 key,响应体里只有 `maskApiKey` 过的那份。
|
|
2557
|
+
* [§6.4 的第一条「绝不」](../../../docs/verify/VERIFY_RECORD-20-web.md)
|
|
2558
|
+
* 管的是**下行**,这一条一个字都没松 —— 而这个包在 `check-layers.mjs` 的
|
|
2559
|
+
* `LIBRARY_DIRS` 里(一处 console 都不许有),所以它也没有把 key 打进日志的口子。
|
|
2411
2560
|
*/
|
|
2412
2561
|
|
|
2413
2562
|
/** 一个可挑的 provider 在服务端眼里的样子。runtime 的 `ProviderOption` 满足它 */
|
|
@@ -2416,6 +2565,15 @@ interface ProviderOptionView {
|
|
|
2416
2565
|
label: string;
|
|
2417
2566
|
envVar: string | null;
|
|
2418
2567
|
hasKey: boolean;
|
|
2568
|
+
keyHint: string | null;
|
|
2569
|
+
}
|
|
2570
|
+
/** 一次配 key 的结果。runtime 的 `ProviderKeyWritten` 满足它 */
|
|
2571
|
+
interface ProviderKeyWrittenView {
|
|
2572
|
+
envVar: string;
|
|
2573
|
+
backend: string;
|
|
2574
|
+
encrypted: boolean;
|
|
2575
|
+
envPath: string | null;
|
|
2576
|
+
keyHint: string;
|
|
2419
2577
|
}
|
|
2420
2578
|
/** 探一家的结果。runtime 的 `ModelSuggestions` 满足它 */
|
|
2421
2579
|
interface ModelSuggestionsView {
|
|
@@ -2425,17 +2583,22 @@ interface ModelSuggestionsView {
|
|
|
2425
2583
|
status: WireModelProbeStatus;
|
|
2426
2584
|
}
|
|
2427
2585
|
/**
|
|
2428
|
-
* `ModelCatalogControl`(runtime)在服务端眼里的样子 ——
|
|
2586
|
+
* `ModelCatalogControl`(runtime)在服务端眼里的样子 —— **只有三个动词**。
|
|
2429
2587
|
*
|
|
2430
|
-
*
|
|
2588
|
+
* 镜像里只有这三个,于是这个包**写不出**「把 homeDir 拿来自己拼一个缓存路径」
|
|
2431
2589
|
* 或者「读一把裸 key」这种事:那两样在收窄口上压根不存在。
|
|
2432
2590
|
* 同 `McpControlView` 只有 `reconnect`、五份安全镜像各自漏掉一个中文字段。
|
|
2591
|
+
*
|
|
2592
|
+
* ⚠️ `setKey` 是**单向**的:裸 key 只往里走,回来的
|
|
2593
|
+
* {@link ProviderKeyWrittenView} 上只有脱敏串 —— 这个包因此**读不出**
|
|
2594
|
+
* 任何一把已经存着的 key,连自己刚写的那把都读不回来。
|
|
2433
2595
|
*/
|
|
2434
2596
|
interface ModelCatalogView {
|
|
2435
2597
|
providers(): readonly ProviderOptionView[];
|
|
2436
2598
|
discover(provider: ProviderType, opts?: {
|
|
2437
2599
|
refresh?: boolean;
|
|
2438
2600
|
}): Promise<ModelSuggestionsView>;
|
|
2601
|
+
setKey(provider: ProviderType, apiKey: string): Promise<ProviderKeyWrittenView>;
|
|
2439
2602
|
}
|
|
2440
2603
|
/**
|
|
2441
2604
|
* server 从 runtime 借的「provider 目录」那一片。`WebRuntimeView` 继承它。
|
|
@@ -3008,8 +3171,13 @@ interface PermissionsView {
|
|
|
3008
3171
|
* **当场编译不过**(同 `AuditRowView.code` 用 `WireAuditCode` 的机制)。
|
|
3009
3172
|
* 写成 `string` 的话,新码会被静默报成 `managed`,而界面照着它说一句
|
|
3010
3173
|
* 和真实原因无关的话。
|
|
3174
|
+
*
|
|
3175
|
+
* @param opts.remember 这一发算不算用户显式挑的(2026-08-31)。同 `SetLevelView`
|
|
3176
|
+
* 那份镜像:**照抄真身的必填形状,别写成可选的**,判据在那儿。
|
|
3011
3177
|
*/
|
|
3012
|
-
setLevel: (level: PermissionLevel
|
|
3178
|
+
setLevel: (level: PermissionLevel, opts: {
|
|
3179
|
+
remember: boolean;
|
|
3180
|
+
}) => LevelChangeResult;
|
|
3013
3181
|
/**
|
|
3014
3182
|
* ⚠️ 第七样,消费方也不在这个文件里 —— 是 [tools.ts](./tools.js)
|
|
3015
3183
|
* (设置 › 工具那一节)。摆在这儿的理由同上面 `setLevel` 那一段:
|
|
@@ -3667,6 +3835,15 @@ interface SettingRowView {
|
|
|
3667
3835
|
chain: readonly SettingStepView[];
|
|
3668
3836
|
overridable: boolean;
|
|
3669
3837
|
writes: readonly SettingWriteView[];
|
|
3838
|
+
/**
|
|
3839
|
+
* 界面画哪种输入控件。**钉成 {@link WireSettingValueKind} 而不是 `string`**,
|
|
3840
|
+
* 判据同 `layer` 那一处(文件头第 2 条):引擎那边多一档控件形态而忘了同步
|
|
3841
|
+
* wire 上这个联合,装配那一行当场编译不过 —— 写成 `string` 的话,那一档会
|
|
3842
|
+
* 一路发到浏览器,然后落进「认不出就当输入框」的兜底分支里,
|
|
3843
|
+
* 而那看起来只是「这个控件有点怪」,查不出来。
|
|
3844
|
+
*/
|
|
3845
|
+
valueKind?: WireSettingValueKind;
|
|
3846
|
+
choices?: readonly string[];
|
|
3670
3847
|
}
|
|
3671
3848
|
/** runtime 的 `SettingWriteReport` 的镜像。`reason` 是码,不是句子 —— 见文件头第 1 条 */
|
|
3672
3849
|
type SettingWriteReportView = {
|
|
@@ -3816,6 +3993,17 @@ interface WebRuntimeView extends RuntimeCapabilities, RuntimeSecurity, RuntimeSe
|
|
|
3816
3993
|
*/
|
|
3817
3994
|
artifactsRoot: string;
|
|
3818
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;
|
|
3819
4007
|
/**
|
|
3820
4008
|
* 自动压缩那条线(决定 8 的第三个时刻,2026-08-16)。`EpochRuntime.compression`
|
|
3821
4009
|
* 结构上正好满足它 —— **对不上就是两边长歪了,装配那一行当场编译不过**。
|
|
@@ -4084,8 +4272,49 @@ interface ApiContext {
|
|
|
4084
4272
|
* 今天的两个消费方:那条端点的 403,和 `GET /api/config` 上原样下发的那一格
|
|
4085
4273
|
* (界面据此在按下去之前把话说出来)。完整判据在 protocol 的
|
|
4086
4274
|
* `wire-agent-role.ts` 文件头。
|
|
4275
|
+
*
|
|
4276
|
+
* ⚠️ **2026-09-01 起它还是另一格的输入**:{@link nativeDirPicker} 由它算出来
|
|
4277
|
+
* (远程绑定时不许弹原生框)。那一格是**算出来的结论**,这一格是**事实** ——
|
|
4278
|
+
* 别把两者合成一个,判据在它自己那条 JSDoc 上。
|
|
4087
4279
|
*/
|
|
4088
4280
|
lanExposed: boolean;
|
|
4281
|
+
/**
|
|
4282
|
+
* 这个进程能不能替浏览器弹一个**系统目录选择框**(2026-09-01)。
|
|
4283
|
+
*
|
|
4284
|
+
* 真源是 `workspace/native-pick.ts` 的 `resolveNativeDirPicker()`,装配时算一次
|
|
4285
|
+
* (回环绑定 + 非 SSH + 平台在支持列表里,三件的合取;它继承的那个 `ssh -L`
|
|
4286
|
+
* 盲区也写在那儿)。
|
|
4287
|
+
*
|
|
4288
|
+
* ## ⚠️ 和 {@link lanExposed} 一样**必传**,理由却更硬一档
|
|
4289
|
+
*
|
|
4290
|
+
* 那一格忘了传的后果是「以为自己在本机」;这一格忘了传(默认成 `true`)的后果是
|
|
4291
|
+
* **一个远程用户点一下,框弹在服务器那台没人看着的机器上,而这一发 HTTP 就
|
|
4292
|
+
* 挂在那儿等一个永远不会有的答复**。所以它没有默认值,而且往「不能弹」那一侧落。
|
|
4293
|
+
*
|
|
4294
|
+
* 两个消费方,形状同上:`POST /api/workspaces/pick` 的 403,和
|
|
4295
|
+
* `GET /api/config` 上原样下发的那一格(界面据此决定那一下走原生框还是自绘
|
|
4296
|
+
* 那一屏)。完整判据在 protocol 的 `WirePickDirectoryResponse` 那一节。
|
|
4297
|
+
*/
|
|
4298
|
+
nativeDirPicker: boolean;
|
|
4299
|
+
/**
|
|
4300
|
+
* 浏览器多半就在这个服务进程的机器上吗(2026-09-02)。
|
|
4301
|
+
*
|
|
4302
|
+
* 真源是 `workspace/native-pick.ts` 的 `isSameMachine()` —— **和
|
|
4303
|
+
* {@link nativeDirPicker} 是同一个函数、同一批事实**,今天两格的值必然相等。
|
|
4304
|
+
*
|
|
4305
|
+
* ## 那为什么是两格,而不是一格
|
|
4306
|
+
*
|
|
4307
|
+
* 因为它们是**两个结论**,只是今天恰好共用一条判据:一格答「能不能弹目录框」
|
|
4308
|
+
* (要 osascript / PowerShell 那两套 UI 实现),一格答「能不能把文件交给系统
|
|
4309
|
+
* 默认应用」(要的是 `open` / `rundll32`)。合成一格之后,哪天有人给目录框
|
|
4310
|
+
* 补上 Linux 的 `zenity`,「用默认应用打开」会**跟着**在 Linux 上打开 ——
|
|
4311
|
+
* 而那一侧一次都没验过。判据在 `isSameMachine` 那条 📮 上。
|
|
4312
|
+
*
|
|
4313
|
+
* 消费方只有一个:`GET /api/sessions/:id/file-stat` 里 `openable` 那一格
|
|
4314
|
+
* (界面据此决定画不画那个按钮 —— 决定 20 ①)。⚠️ **`POST .../file-open`
|
|
4315
|
+
* 自己也要再查一遍**,别指望浏览器只在按钮亮着的时候才发那一下。
|
|
4316
|
+
*/
|
|
4317
|
+
sameMachine: boolean;
|
|
4089
4318
|
}
|
|
4090
4319
|
|
|
4091
4320
|
/**
|
|
@@ -4387,6 +4616,122 @@ interface WorkspaceDiffOptions {
|
|
|
4387
4616
|
*/
|
|
4388
4617
|
declare function collectWorkspaceDiff(opts: WorkspaceDiffOptions): Promise<WireWorkspaceDiffResponse>;
|
|
4389
4618
|
|
|
4619
|
+
/**
|
|
4620
|
+
* 在**服务进程那台机器**上弹一个系统目录选择框 —— `POST /api/workspaces/pick`
|
|
4621
|
+
* (2026-09-01)。
|
|
4622
|
+
*
|
|
4623
|
+
* ## 它推翻的是 [browse.ts](./browse.js) 文件头那四条里的一条半
|
|
4624
|
+
*
|
|
4625
|
+
* 那份文件头 2026-08-17 写着「为什么不弹原生对话框」四条,末尾那句是
|
|
4626
|
+
* 「哪天这个赌注被推翻了,回来读这一段,**别重新推一遍**」。这一份就是那一天,
|
|
4627
|
+
* 所以这里**只记这一轮新增的判据**,四条各自的下场逐条写在 protocol 的
|
|
4628
|
+
* `WirePickDirectoryResponse` 上(那儿是契约,也是判据的落点)。一句话版:
|
|
4629
|
+
* ① 远程那条**成立**,于是有了下面那道闸;④ 信任那条**作废**(方案 55 §2.6
|
|
4630
|
+
* 判掉了「新建目录默认信任」,今天所有目录一律未信任,裸路径什么都没丢)。
|
|
4631
|
+
*
|
|
4632
|
+
* ## 这道闸是**四件事的合取**,而其中第一件是一句推断
|
|
4633
|
+
*
|
|
4634
|
+
* {@link resolveNativeDirPicker} 那五行的形状照抄 deepseek-harness 的
|
|
4635
|
+
* `packages/host/directory-picker-auto/src/resolve.ts`(同一个形态:纯浏览器页 +
|
|
4636
|
+
* 本机 Node 服务端),判据也是同一条:**原生框弹在服务进程那台机器的屏幕上**,
|
|
4637
|
+
* 所以只有在「浏览器多半就在那台机器上」时它才是对的。
|
|
4638
|
+
*
|
|
4639
|
+
* ⚠️ **继承了它一个修不掉的盲区,如实记下**:`ssh -L` 端口转发时,请求从回环
|
|
4640
|
+
* 进来、`SSH_*` 又不在服务进程的环境里(服务是本机先起的),于是这道闸判成
|
|
4641
|
+
* 「能弹」——框弹在一台没人看着的机器上。harness 的 README 明写这一档
|
|
4642
|
+
* per-connection 适配也修不了,那种部署要直接钉死走自绘。我们这一侧的兜底是
|
|
4643
|
+
* 一样的:`epoch web` 起在一台会被远程访问的机器上时,用 `--host 0.0.0.0`
|
|
4644
|
+
* (那时这道闸自己就关了),别用回环 + 转发。
|
|
4645
|
+
*
|
|
4646
|
+
* ## ⚠️ 第二个盲区,这一个是 2026-09-01 真机量出来的
|
|
4647
|
+
*
|
|
4648
|
+
* **macOS 上,一个连不到 WindowServer 的进程调 `choose folder` 不会报错 ——
|
|
4649
|
+
* 它直接回那个进程的 cwd。** 现场(同一台机器,同一条命令):
|
|
4650
|
+
*
|
|
4651
|
+
* | 跑在哪儿 | `osascript … choose folder` 的结果 |
|
|
4652
|
+
* | ---------------------------- | ---------------------------------------------- |
|
|
4653
|
+
* | 普通终端会话 | 真弹框;取消回 `execution error: 用户已取消。 (-128)` |
|
|
4654
|
+
* | 被 seatbelt 关起来的子进程 | **1.5 秒后回一条路径**(就是 cwd),一个框都没有 |
|
|
4655
|
+
*
|
|
4656
|
+
* 也就是说那一档下用户会**拿到一个他从没挑过的目录**,而屏幕上没有任何东西
|
|
4657
|
+
* 说过这件事。**这道闸拦不住它**:那台机器上 `launchctl managername` 照样是
|
|
4658
|
+
* `Aqua`(实测),SSH 那两格也是空的 —— 会话元数据看着完全正常,被挡掉的是
|
|
4659
|
+
* 真正那次连接。
|
|
4660
|
+
*
|
|
4661
|
+
* **没有为它加探测**,判据是「加一个查不出这一档的探测,比不加更坏」:
|
|
4662
|
+
* 它会让下一个人以为这条缝已经堵上了。今天的形态是**如实记在这儿**,
|
|
4663
|
+
* 而现实里踩得到它的是「epoch web 被某个沙箱化的父进程拉起来」这一种 ——
|
|
4664
|
+
* 用户自己在终端里敲 `epoch web` 不在其中。
|
|
4665
|
+
*
|
|
4666
|
+
* 📮 真要堵它,能想到的唯一可靠做法是**让框自己说话**:给 `choose folder` 一个
|
|
4667
|
+
* `default location`(比如 home),那时「回的是 cwd」就成了一个可判的信号 ——
|
|
4668
|
+
* 但它同时也把「系统记住的上次位置」这件事顶掉了,那是原生框最值钱的东西之一。
|
|
4669
|
+
* 谁要收这张 📮,先量一遍那两件哪个更贵。
|
|
4670
|
+
*
|
|
4671
|
+
* ## 平台只写两个,而这不是「先做一半」
|
|
4672
|
+
*
|
|
4673
|
+
* AGENTS.md「支持平台」那一节只有 Windows 和 macOS。Linux 分支写了也没人验
|
|
4674
|
+
* (harness 那边是 `zenity → kdialog` 两级降级),所以这里**一个字都不写** ——
|
|
4675
|
+
* 那台机器上这道闸判成假,界面回落自绘那一屏,而那一屏在任何机器上都能用。
|
|
4676
|
+
* 这是「不做」,不是「没做完」:加 Linux 的人要连着加它的探测(`DISPLAY` /
|
|
4677
|
+
* `WAYLAND_DISPLAY` + PATH 上有没有那两个二进制),别只加一条命令。
|
|
4678
|
+
*
|
|
4679
|
+
* ## 三条实现上的规矩
|
|
4680
|
+
*
|
|
4681
|
+
* 1. **`execFile` 不过 shell**,全仓同一条(`cli/src/host-actions.ts` /
|
|
4682
|
+
* `workspace/git.ts`)。这一条在这儿尤其硬:Windows 那一支是一段脚本文本;
|
|
4683
|
+
* 2. **不设 timeout。** `git.ts` 那个 10 秒在这儿是错的 —— 一个对话框本来就可以
|
|
4684
|
+
* 开五分钟。取而代之的是 {@link PickOptions.signal}:HTTP 请求断开(用户关了
|
|
4685
|
+
* 标签页)就杀掉那个子进程,否则那个框会永远留在别人屏幕上;
|
|
4686
|
+
* 3. **同一进程只许一个框**({@link pickNativeDirectory} 的单飞闸)。两个框叠在
|
|
4687
|
+
* 一台机器上,用户答的那一个未必是浏览器还等着的那一个。
|
|
4688
|
+
*/
|
|
4689
|
+
/** 这台机器上能不能弹的四件事,全是**事实**不是结论 —— 判据在下面那个函数上 */
|
|
4690
|
+
interface NativePickerFacts {
|
|
4691
|
+
/** 服务绑在回环之外吗(`bind.ts` 的 `decideBinding().lanExposed`) */
|
|
4692
|
+
lanExposed: boolean;
|
|
4693
|
+
/** `process.platform` */
|
|
4694
|
+
platform: NodeJS.Platform;
|
|
4695
|
+
/** `process.env` 的一个子集 —— 只读这两格,见下 */
|
|
4696
|
+
env: Readonly<Partial<Record<'SSH_CONNECTION' | 'SSH_TTY', string>>>;
|
|
4697
|
+
}
|
|
4698
|
+
/**
|
|
4699
|
+
* 这个服务进程能不能替浏览器弹一个系统目录框。**纯函数,装配时算一次。**
|
|
4700
|
+
*
|
|
4701
|
+
* 四条缺一不可,每一条挡的是一种「框弹出来也没用 / 弹错地方」:
|
|
4702
|
+
*
|
|
4703
|
+
* | 条件 | 挡的是什么 |
|
|
4704
|
+
* | ------------------------ | --------------------------------------------------------- |
|
|
4705
|
+
* | 绑在回环上 | `--host 0.0.0.0` 那一档浏览器可能在别的机器上 |
|
|
4706
|
+
* | 没有 `SSH_CONNECTION` / `SSH_TTY` | 服务是被 ssh 进来的人起的 —— 框会弹在无人值守的服务器上 |
|
|
4707
|
+
* | 平台是 darwin / win32 | 别的平台这一份没有实现(见文件头「平台只写两个」) |
|
|
4708
|
+
*
|
|
4709
|
+
* ⚠️ **一律往「不能弹」那一侧落**:猜错成「能弹」的表现是用户点下去吃一个 403
|
|
4710
|
+
* 或者框弹在别人屏幕上,猜错成「不能弹」的表现只是他看到自绘那一屏 ——
|
|
4711
|
+
* 而那一屏在任何机器上都能用。
|
|
4712
|
+
*/
|
|
4713
|
+
declare function resolveNativeDirPicker(facts: NativePickerFacts): boolean;
|
|
4714
|
+
/**
|
|
4715
|
+
* 「浏览器多半就在服务进程这台机器上」—— 上面那个判断的**正身**。
|
|
4716
|
+
*
|
|
4717
|
+
* 2026-09-02 抽出来,因为有了第二个问同一句话的地方:Web UI 的
|
|
4718
|
+
* 「用默认应用打开」(`workspace/file-view.ts`)。它和弹目录框是**同一个赌注**
|
|
4719
|
+
* —— `open` / `rundll32` 起的那个窗口和 `choose folder` 弹的那个框,
|
|
4720
|
+
* 出现在同一块屏幕上;那块屏幕前面没人的话,两者一样白搭。
|
|
4721
|
+
*
|
|
4722
|
+
* ⚠️ **两处共用一份,不许各写各的。** 三条判据里最容易被漏掉的是 SSH 那两格
|
|
4723
|
+
* (它问的是「这个服务是被谁起的」,不是「这一发请求从哪儿来」),
|
|
4724
|
+
* 而漏掉它的表现不是报错,是**一个窗口弹在无人值守的服务器上**。
|
|
4725
|
+
*
|
|
4726
|
+
* ⚠️ 它继承 `resolveNativeDirPicker` 文件头记的那两个盲区,一个字都没少:
|
|
4727
|
+
* `ssh -L` 端口转发这道闸判不出来;macOS 上被沙箱关起来的进程也判不出来。
|
|
4728
|
+
*
|
|
4729
|
+
* 📮 平台那一条对这一格其实**偏严**了:`xdg-open` 在 Linux 上是有的,
|
|
4730
|
+
* 而目录框那一侧没有 Linux 实现。今天故意不放宽 —— AGENTS.md 的支持平台只有
|
|
4731
|
+
* Windows / macOS,放宽等于多一条没人验的分支。要放宽的人先去改那一节。
|
|
4732
|
+
*/
|
|
4733
|
+
declare function isSameMachine(facts: NativePickerFacts): boolean;
|
|
4734
|
+
|
|
4390
4735
|
/**
|
|
4391
4736
|
* 后台任务的取数与投影 —— `GET /api/sessions/:id/tasks`(方案 36 PR-2 的 Web 那半)。
|
|
4392
4737
|
*
|
|
@@ -4728,4 +5073,4 @@ type CreateWebServerResult = {
|
|
|
4728
5073
|
*/
|
|
4729
5074
|
declare function createWebServer(opts: CreateWebServerOptions): Promise<CreateWebServerResult>;
|
|
4730
5075
|
|
|
4731
|
-
export { type ApiContext, type AttachedMentions, type AuthGuardOptions, type BindDecision, type BindRequest, type BoundWorkspace, type CatalogDeletion, type CatalogHit, type CatalogRow, type CheckpointSummaryView, type CommandsView, type CreateSessionResult, type CreateWebServerOptions, type CreateWebServerResult, DEFAULT_MAX_ACTIVE_SESSIONS, DEFAULT_MAX_QUEUED_MESSAGES, DEFAULT_RING_CAPACITY, DEFAULT_WEB_HOST, DEFAULT_WEB_PORT, EnvelopeRing, type EpochWebServer, type ExpansionOutcome, type FrameSink, type HubSession, type HubSessionState, type LiveSessionView, MAX_CANDIDATES, MAX_DIFF_BYTES, MAX_DIFF_FILES, MAX_RECORDING_FRAMES, MAX_SKILL_BODY_BYTES, type ModelTurnsView, type PluginControlView, type QueuedMessage, type RewindFilePlanView, type RewindOutcomeView, type RewindPreviewView, type RewindResultView, type RuntimeCapabilities, type RuntimeCheckpoints, type RuntimeCommands, type RuntimeSecurity, type RuntimeSettings, type ScheduleCapabilityView, type ScheduleControlView, type ScheduleCreateView, type ScheduleFireView, type ScheduleRegisterView, type ScheduleSaveView, type ScheduleUpdateView, type SelectionView, type SessionCatalog, type SessionContextFacts, type SessionFactoryView, type SessionHistoryFacts, SessionHub, type SessionHubOptions, type SessionLoopView, type SessionModelView, type SessionPermissionsView, type SessionPlanView, type SessionReferencesView, type SessionRoleView, type SetLevelView, type SetSelectionView, type StartResult, TASK_TAIL_BYTES, type TaskRegistryView, type TrustView, type TurnDecorator, UI_LANG_PARAM, UI_THEME_PARAM, type UiLangPref, type UiPreset, type UiThemePref, type WebRuntimeView, type WorkspaceBindFailure, type WorkspaceBindOutcome, type WorkspaceCheckpoints, type WorkspaceDiffOptions, type WorkspaceView, attachMentions, collectCapabilities, collectSecurity, collectSettings, collectTasks, collectWorkspaceDiff, createAuthGuard, createWebServer, decideBinding, defaultWebRoot, expandUserContent, firstScreenUrl, generateToken, listFileCandidates, listReferenceCandidates, readRewindInput, resolveArtifactPath, toWireCheckpoint, toWireCommand, toWirePluginEntry, toWirePreview, toWireRewindResult, toWireRow, toWireSkillBody, toWireTask, unavailableToHttp };
|
|
5076
|
+
export { type ApiContext, type AttachedMentions, type AuthGuardOptions, type BindDecision, type BindRequest, type BoundWorkspace, type CatalogDeletion, type CatalogHit, type CatalogRow, type CheckpointSummaryView, type CommandsView, type CreateSessionResult, type CreateWebServerOptions, type CreateWebServerResult, DEFAULT_MAX_ACTIVE_SESSIONS, DEFAULT_MAX_QUEUED_MESSAGES, DEFAULT_RING_CAPACITY, DEFAULT_WEB_HOST, DEFAULT_WEB_PORT, EnvelopeRing, type EpochWebServer, type ExpansionOutcome, type FrameSink, type HubSession, type HubSessionState, type LiveSessionView, MAX_CANDIDATES, MAX_DIFF_BYTES, MAX_DIFF_FILES, MAX_RECORDING_FRAMES, MAX_SKILL_BODY_BYTES, type ModelTurnsView, type NativePickerFacts, type PluginControlView, type QueuedMessage, type RewindFilePlanView, type RewindOutcomeView, type RewindPreviewView, type RewindResultView, type RuntimeCapabilities, type RuntimeCheckpoints, type RuntimeCommands, type RuntimeSecurity, type RuntimeSettings, type ScheduleCapabilityView, type ScheduleControlView, type ScheduleCreateView, type ScheduleFireView, type ScheduleRegisterView, type ScheduleSaveView, type ScheduleUpdateView, type SelectionView, type SessionCatalog, type SessionContextFacts, type SessionFactoryView, type SessionHistoryFacts, SessionHub, type SessionHubOptions, type SessionLoopView, type SessionModelView, type SessionPermissionsView, type SessionPlanView, type SessionReferencesView, type SessionRoleView, type SetLevelView, type SetSelectionView, type StartResult, TASK_TAIL_BYTES, type TaskRegistryView, type TrustView, type TurnDecorator, UI_LANG_PARAM, UI_THEME_PARAM, type UiLangPref, type UiPreset, type UiThemePref, type WebRuntimeView, type WorkspaceBindFailure, type WorkspaceBindOutcome, type WorkspaceCheckpoints, type WorkspaceDiffOptions, type WorkspaceView, attachMentions, collectCapabilities, collectSecurity, collectSettings, collectTasks, collectWorkspaceDiff, createAuthGuard, createWebServer, decideBinding, defaultWebRoot, expandUserContent, firstScreenUrl, generateToken, isSameMachine, listFileCandidates, listReferenceCandidates, readRewindInput, resolveArtifactPath, resolveNativeDirPicker, toWireCheckpoint, toWireCommand, toWirePluginEntry, toWirePreview, toWireRewindResult, toWireRow, toWireSkillBody, toWireTask, unavailableToHttp };
|