@fa-software/semi2-dsh 0.0.10-preview.20260920042705
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/cordis.patch.yml +5 -0
- package/lib/client.js +351 -0
- package/lib/client.js.map +1 -0
- package/lib/codegraph/cli.js +142 -0
- package/lib/codegraph/config.js +22 -0
- package/lib/codegraph/ensure.js +25 -0
- package/lib/codegraph/guide.js +21 -0
- package/lib/codegraph/index.js +97 -0
- package/lib/codegraph/tools.js +227 -0
- package/lib/codegraph/workspace.js +52 -0
- package/lib/configuration/compile.js +177 -0
- package/lib/configuration/credentials.js +104 -0
- package/lib/configuration/generated/graphql.js +1 -0
- package/lib/configuration/generated/schema.js +95 -0
- package/lib/configuration/graphql.js +193 -0
- package/lib/configuration/index.js +29 -0
- package/lib/configuration/login.js +96 -0
- package/lib/configuration/runtime.js +1100 -0
- package/lib/configuration/skill-resources.js +218 -0
- package/lib/configuration/skills.js +185 -0
- package/lib/configuration/status.js +57 -0
- package/lib/configuration/workspace.js +55 -0
- package/lib/configuration/workspaces.js +169 -0
- package/lib/contract.js +42 -0
- package/lib/index.js +14 -0
- package/lib/types/codegraph/cli.d.ts +20 -0
- package/lib/types/codegraph/config.d.ts +10 -0
- package/lib/types/codegraph/ensure.d.ts +3 -0
- package/lib/types/codegraph/guide.d.ts +4 -0
- package/lib/types/codegraph/index.d.ts +5 -0
- package/lib/types/codegraph/tools.d.ts +17 -0
- package/lib/types/codegraph/workspace.d.ts +8 -0
- package/lib/types/configuration/compile.d.ts +81 -0
- package/lib/types/configuration/credentials.d.ts +35 -0
- package/lib/types/configuration/generated/graphql.d.ts +100 -0
- package/lib/types/configuration/generated/schema.d.ts +1003 -0
- package/lib/types/configuration/graphql.d.ts +46 -0
- package/lib/types/configuration/index.d.ts +9 -0
- package/lib/types/configuration/login.d.ts +22 -0
- package/lib/types/configuration/runtime.d.ts +320 -0
- package/lib/types/configuration/skill-resources.d.ts +14 -0
- package/lib/types/configuration/skills.d.ts +8 -0
- package/lib/types/configuration/status.d.ts +9 -0
- package/lib/types/configuration/workspace.d.ts +7 -0
- package/lib/types/configuration/workspaces.d.ts +96 -0
- package/lib/types/contract.d.ts +32 -0
- package/lib/types/index.d.ts +11 -0
- package/lib/types/web/index.d.ts +2 -0
- package/lib/types/web/login.d.ts +2 -0
- package/lib/types/web/loopback-bridge.d.ts +8 -0
- package/lib/types/web/preview-proxy.d.ts +17 -0
- package/lib/types/web/runtime.d.ts +8 -0
- package/lib/types/web/welcome-ack.d.ts +33 -0
- package/lib/web/index.js +38 -0
- package/lib/web/login.js +79 -0
- package/lib/web/loopback-bridge.js +12 -0
- package/lib/web/preview-proxy.js +201 -0
- package/lib/web/runtime.js +19 -0
- package/lib/web/welcome-ack.js +51 -0
- package/package.json +81 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** 只承载 code,绝不把上游内容插值进 message。 */
|
|
2
|
+
export declare class ConfigurationError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
constructor(code: string);
|
|
5
|
+
}
|
|
6
|
+
/** 启动装配:五个用户级领域问题一个文档(项目绑定按工作区另行按需取,见下)。 */
|
|
7
|
+
export declare const RUNTIME_BOOT_DOCUMENT = "query RuntimeBoot {\n runtimeViewer {\n id\n username\n displayName\n }\n runtimeModels {\n id\n upstreamId\n displayName\n metadata { contextWindow maxTokens input reasoningLevels }\n connection { id provider protocol baseUrl }\n }\n runtimeDefaultModelId\n runtimeModelCredentials {\n connectionId\n value\n }\n runtimeSkills {\n id\n projectId\n name\n description\n whenToUse\n content\n version\n files {\n path\n sizeBytes\n mimeType\n isExecutable\n }\n fileCount\n filesBytes\n }\n}";
|
|
8
|
+
/**
|
|
9
|
+
* 技能附属资源字节:boot 文档只带清单(避免目录膨胀),真正加载某个技能时才按需取这一条。
|
|
10
|
+
* 可空根字段:读取者不可见 / 不存在回空数组(权威「没有」),领域失败回 null(降级,不物化)。
|
|
11
|
+
*/
|
|
12
|
+
export declare const RUNTIME_SKILL_FILES_DOCUMENT = "query RuntimeSkillFiles($skillId: ID!) {\n runtimeSkillFiles(skillId: $skillId) {\n path\n content\n encoding\n sizeBytes\n mimeType\n isExecutable\n }\n}";
|
|
13
|
+
/**
|
|
14
|
+
* 项目绑定按 slug 取:只问已登记工作区命中的那几个项目,绝不把整张项目表拉回本地。
|
|
15
|
+
* `slugs` 是读范围之上的过滤(不是绕过),空数组 = 空集合。
|
|
16
|
+
*/
|
|
17
|
+
export declare const RUNTIME_WORKSPACE_PROJECTS_DOCUMENT = "query RuntimeWorkspaceProjects($slugs: [String!]) {\n runtimeProjects(slugs: $slugs) {\n id slug name enabled planModelId executeModelId\n }\n}";
|
|
18
|
+
/** 密钥重取(「重新加载」时只刷新密钥)。 */
|
|
19
|
+
export declare const RUNTIME_MODEL_CREDENTIALS_DOCUMENT = "query RuntimeModelCredentials($connectionIds: [ID!]) {\n runtimeModelCredentials(connectionIds: $connectionIds) {\n connectionId\n value\n }\n}";
|
|
20
|
+
/** semi2-hub 根地址:生产/预览都是 https;development 下额外放行回环 http。 */
|
|
21
|
+
export declare function consoleEndpoint(value: string, nodeEnv?: string): URL;
|
|
22
|
+
export interface GraphqlClientOptions {
|
|
23
|
+
/** semi2-hub GraphQL 端点(由连接凭据的地址构造)。 */
|
|
24
|
+
endpoint: URL;
|
|
25
|
+
token: string;
|
|
26
|
+
/** CNB 面:环境创建者的外部用户 id(平台注入 CNB_BUILD_USER_ID),供 hub 决定读取身份。 */
|
|
27
|
+
creator?: string;
|
|
28
|
+
fetchImpl?: typeof fetch;
|
|
29
|
+
}
|
|
30
|
+
export interface GraphqlRequest {
|
|
31
|
+
operationName: string;
|
|
32
|
+
document: string;
|
|
33
|
+
/** 省略即不带变量(GraphQL 把缺省变量当未提供)。 */
|
|
34
|
+
variables?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export interface GraphqlResponse<TData> {
|
|
37
|
+
/** 信封里的 data;整份读取失败(含非空根字段错误向上传播)为 null。 */
|
|
38
|
+
data: TData | null;
|
|
39
|
+
/** `errors[].extensions.code` 的首个非空码;无错误为 null。 */
|
|
40
|
+
errorCode: string | null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 传输层失败抛 `ConfigurationError`;服务端领域失败回落在返回值的 errorCode 上(HTTP 200 +
|
|
44
|
+
* `errors[].extensions.code`),由调用方决定降级。
|
|
45
|
+
*/
|
|
46
|
+
export declare function postGraphql<TData>(client: GraphqlClientOptions, request: GraphqlRequest): Promise<GraphqlResponse<TData>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type ConfigurationOptions, type Semi2Config } from './runtime.js';
|
|
3
|
+
export type { Semi2Config, Semi2ConfigState, Semi2Surface, } from './runtime.js';
|
|
4
|
+
export type { SkillsInstall } from './skills.js';
|
|
5
|
+
/**
|
|
6
|
+
* 同步发布 `ctx.semi2Config`,首次领取在后台——不阻塞插件树 settle,失败只 warn 绝不 reject
|
|
7
|
+
*(读 state.error 诊断);缺任一连接凭据即不做任何注入。
|
|
8
|
+
*/
|
|
9
|
+
export declare function installConfiguration(ctx: Context, options?: ConfigurationOptions): Semi2Config;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ConsoleLoginInput {
|
|
2
|
+
url: string;
|
|
3
|
+
username: string;
|
|
4
|
+
password: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ConsoleLoginOutcome {
|
|
7
|
+
userName: string;
|
|
8
|
+
token: string;
|
|
9
|
+
url: string;
|
|
10
|
+
}
|
|
11
|
+
/** semi2-hub 根地址:https(development 下额外放行回环 http),不允许凭据/查询串。 */
|
|
12
|
+
export declare function consoleOrigin(value: string, nodeEnv?: string): string;
|
|
13
|
+
/** 失败抛 `ConfigurationError`(code 由 UI 透传展示)。 */
|
|
14
|
+
export declare function loginToConsole(input: ConsoleLoginInput, fetchImpl?: typeof fetch): Promise<ConsoleLoginOutcome>;
|
|
15
|
+
/** CNB 运行面:平台注入的短期 CNB_TOKEN 换 hub 用户密钥(服务端到服务端,无 Origin/CSRF)。 */
|
|
16
|
+
export declare function exchangeCnbToken(input: {
|
|
17
|
+
url: string;
|
|
18
|
+
token: string;
|
|
19
|
+
}, fetchImpl?: typeof fetch): Promise<{
|
|
20
|
+
userName: string;
|
|
21
|
+
token: string;
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type Semi2Platform } from '../contract.js';
|
|
3
|
+
import { type RuntimeProject } from './compile.js';
|
|
4
|
+
import { type WorkspaceEntry } from './workspaces.js';
|
|
5
|
+
export type { RuntimeProject } from './compile.js';
|
|
6
|
+
export type { WorkspaceEntry } from './workspaces.js';
|
|
7
|
+
/** local = 未配凭据;ready 允许部分领域降级。 */
|
|
8
|
+
export type ConfigStatus = 'local' | 'loading' | 'ready' | 'failed';
|
|
9
|
+
/** 运行面平台:契约缺席(宿主直跑)为 `host`;契约未解析时为 null(不谎报 host)。 */
|
|
10
|
+
export type Semi2Surface = Semi2Platform | 'host';
|
|
11
|
+
/** 运行面下发的技能附件清单条目(不含字节;字节在加载该技能时按需取)。 */
|
|
12
|
+
export interface RuntimeSkillFileFact {
|
|
13
|
+
/** 相对 `files/` 的 posix 路径,例 `scripts/run.sh`。 */
|
|
14
|
+
path: string;
|
|
15
|
+
sizeBytes: number;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
isExecutable: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** 运行面按需读取的附件内容:文本类 UTF8(content 是原文)、其余 BASE64。 */
|
|
20
|
+
export interface RuntimeSkillFileContentFact {
|
|
21
|
+
path: string;
|
|
22
|
+
content: string;
|
|
23
|
+
encoding: 'UTF8' | 'BASE64';
|
|
24
|
+
sizeBytes: number;
|
|
25
|
+
mimeType: string;
|
|
26
|
+
isExecutable: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** 运行面下发的技能事实;`content` 是正文(frontmatter 已剥),是否对本 cwd 生效由 provider 裁定。 */
|
|
29
|
+
export interface RuntimeSkillFact {
|
|
30
|
+
id: string;
|
|
31
|
+
/** null = 全局技能(在所有已登记工作区共享);否则只对解析到该项目的 cwd 生效。 */
|
|
32
|
+
projectId: string | null;
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
whenToUse: string | null;
|
|
36
|
+
content: string;
|
|
37
|
+
version: number;
|
|
38
|
+
/** 附件清单(boot 只给清单,字节走 `skillFiles`);无附件为空数组。 */
|
|
39
|
+
files: RuntimeSkillFileFact[];
|
|
40
|
+
}
|
|
41
|
+
/** 运行面读取者 = hub 里当前账户;身份由服务端按凭据解析,任何环境都返回同一用户。 */
|
|
42
|
+
export interface RuntimeIdentity {
|
|
43
|
+
id: string;
|
|
44
|
+
username: string;
|
|
45
|
+
displayName: string;
|
|
46
|
+
}
|
|
47
|
+
export interface Semi2ConfigState {
|
|
48
|
+
status: ConfigStatus;
|
|
49
|
+
/** 最近一次成功读取的时间(ISO),未成功过为 null。 */
|
|
50
|
+
loadedAt: string | null;
|
|
51
|
+
/** 最近一次失败码,成功或未尝试为 null(部分降级时保留首个码供诊断)。 */
|
|
52
|
+
error: string | null;
|
|
53
|
+
consoleUrl: string | null;
|
|
54
|
+
/** 本次以谁的身份读取(hub 当前用户);未就绪或服务端未下发为 null。 */
|
|
55
|
+
identity: RuntimeIdentity | null;
|
|
56
|
+
model: {
|
|
57
|
+
id: string;
|
|
58
|
+
provider: string;
|
|
59
|
+
} | null;
|
|
60
|
+
/** 控制台技能目录;null = 没拿到权威目录(≠ 空目录),provider 据此报 complete:false。 */
|
|
61
|
+
skills: RuntimeSkillFact[] | null;
|
|
62
|
+
/** 已登记工作区命中的项目(含生效绑定,按 slug 现取并缓存);会话按 cwd 经 `projectFor` 匹配。 */
|
|
63
|
+
projects: RuntimeProject[];
|
|
64
|
+
/** 已登记工作区(dsh 工作区 → git 项目映射);未接入工作区服务时为单条隐式条目。 */
|
|
65
|
+
workspaces: WorkspaceEntry[];
|
|
66
|
+
}
|
|
67
|
+
/** 服务面:运行面按它读配置,不读本地 env 或配置文件。 */
|
|
68
|
+
export interface Semi2Config {
|
|
69
|
+
readonly state: Semi2ConfigState;
|
|
70
|
+
/** 首次读取结束(成功、未配凭据或失败都已 settle,读 state.error)。 */
|
|
71
|
+
readonly ready: Promise<void>;
|
|
72
|
+
readonly platform: Semi2Surface | null;
|
|
73
|
+
/** 手动重新读取并应用(设置页 Semi2 分区);返回最新状态,失败不抛。 */
|
|
74
|
+
reload(): Promise<Semi2ConfigState>;
|
|
75
|
+
/** 按会话 cwd 解析其关联项目;未关联/未就绪返回 null。 */
|
|
76
|
+
projectFor(session: {
|
|
77
|
+
header?: {
|
|
78
|
+
cwd?: string;
|
|
79
|
+
};
|
|
80
|
+
}): Promise<RuntimeProject | null>;
|
|
81
|
+
/** 同上,但直接取 cwd(技能目录等只有 cwd、没有会话对象的接缝)。 */
|
|
82
|
+
projectForCwd(cwd: string | undefined): Promise<RuntimeProject | null>;
|
|
83
|
+
/** 已登记工作区命中的项目(去重);状态展示与技能作用域按它取。 */
|
|
84
|
+
workspaceProjects(): RuntimeProject[];
|
|
85
|
+
/**
|
|
86
|
+
* 某技能 head 版本的附件内容(技能 provider 物化资源用)。
|
|
87
|
+
* 领域失败 / 降级 / 传输异常一律返回 null(调用方据此放弃物化,正文照旧可用);
|
|
88
|
+
* 读取者不可见或技能不存在返回空数组(权威「没有附件」)。
|
|
89
|
+
*/
|
|
90
|
+
skillFiles(skillId: string): Promise<RuntimeSkillFileContentFact[] | null>;
|
|
91
|
+
/** workmode 选 execute、否则 plan,缺失回落全局默认;必须在官方 runner 读取 `agentDefaultModel.currentSelection()` 之前调用。 */
|
|
92
|
+
selectHeadlessModel(input: {
|
|
93
|
+
workmode: boolean;
|
|
94
|
+
cwd?: string;
|
|
95
|
+
}): Promise<void>;
|
|
96
|
+
/** 一步换取用户密钥 → 写入 dsh credentials 存储 → 立即重新读取;失败抛(code 由 UI 展示)。 */
|
|
97
|
+
login(input: {
|
|
98
|
+
url: string;
|
|
99
|
+
username: string;
|
|
100
|
+
password: string;
|
|
101
|
+
}): Promise<{
|
|
102
|
+
userName: string;
|
|
103
|
+
}>;
|
|
104
|
+
/** 清掉登录凭据,并把本插件写过的本地条目(路由 / 密钥 / 覆盖 / 默认模型 / 工作区解析)整体回收;部署面凭据不受影响。 */
|
|
105
|
+
logout(): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
declare module '@deepseek-ai/cordis' {
|
|
108
|
+
interface Events {
|
|
109
|
+
/** 每次读取/重载结束(成功或失败)后广播最新状态。 */
|
|
110
|
+
'semi2/config-updated'(state: Semi2ConfigState): void;
|
|
111
|
+
/** dsh 工作区列表变化并完成该项目同步后广播(技能 provider 据此丢弃按 cwd 的目录缓存)。 */
|
|
112
|
+
'semi2/workspaces-updated'(state: Semi2ConfigState): void;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** 安装选项;超时是测试缝,让用例不必真等默认窗口。 */
|
|
116
|
+
export interface ConfigurationOptions {
|
|
117
|
+
contractTimeoutMs?: number;
|
|
118
|
+
}
|
|
119
|
+
export declare class Semi2ConfigRuntime implements Semi2Config {
|
|
120
|
+
private readonly ctx;
|
|
121
|
+
private current;
|
|
122
|
+
private readonly settled;
|
|
123
|
+
/** 构造时冻结的进程 env:用于项目反解兜底(CNB_REPO_SLUG)与回环 http 判定(NODE_ENV)。 */
|
|
124
|
+
private readonly environment;
|
|
125
|
+
/** 当前连接凭据(契约或 dsh credentials 存储);未配置为 null。 */
|
|
126
|
+
private connection;
|
|
127
|
+
/** 运行面契约:适配器 provide 优先,缺席 = 宿主直跑;未解析为 undefined。 */
|
|
128
|
+
private contract;
|
|
129
|
+
private contractResolved;
|
|
130
|
+
private readonly contractTimeoutMs;
|
|
131
|
+
private settings;
|
|
132
|
+
/** 最近一次成功编译的模型目录(headless 角色选择按它解析)。 */
|
|
133
|
+
private compiled;
|
|
134
|
+
private defaultModelId;
|
|
135
|
+
private reloadToken;
|
|
136
|
+
/** 工作区登记表(dsh 工作区 → git 项目映射)。 */
|
|
137
|
+
private readonly book;
|
|
138
|
+
/** hub 明确没有的 slug(不在可读范围内):负缓存,免得每次会话都去问一遍。 */
|
|
139
|
+
private readonly missingProjects;
|
|
140
|
+
/** 工作区同步串行队列:feed 帧与「同步」可能并发,串起来才不会互相覆盖。 */
|
|
141
|
+
private workspaceTail;
|
|
142
|
+
private resolveSettled;
|
|
143
|
+
constructor(ctx: Context, environment: NodeJS.ProcessEnv, options?: ConfigurationOptions);
|
|
144
|
+
get state(): Semi2ConfigState;
|
|
145
|
+
get ready(): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* 解析连接凭据;非 CNB 面先把启动环境的连接令牌摘掉再解析。
|
|
148
|
+
* 那枚令牌只属 CNB 面(`runtimeFromCnbEnv` 从 secret imports 注入的 env 取),宿主 / 容器面认了它
|
|
149
|
+
* 就再没有登录入口:dsh 的启动环境层只读(set/unset 都被拒)又排在临时存储之前,登录写进去的令牌
|
|
150
|
+
* 也读不回来。地址不是密钥、还是登录表单的预填来源,照旧留给 `SEMI2_CONFIG_URL`。
|
|
151
|
+
*/
|
|
152
|
+
private connectionFields;
|
|
153
|
+
/** 契约解析完成后才给出答案;缺席即宿主直跑。 */
|
|
154
|
+
get platform(): Semi2Surface | null;
|
|
155
|
+
reload(): Promise<Semi2ConfigState>;
|
|
156
|
+
projectFor(session: {
|
|
157
|
+
header?: {
|
|
158
|
+
cwd?: string;
|
|
159
|
+
};
|
|
160
|
+
}): Promise<RuntimeProject | null>;
|
|
161
|
+
/**
|
|
162
|
+
* 两层解析:已登记工作区按其解析结果取项目;未登记目录回落 git slug,并**按需**问一次
|
|
163
|
+
* 那一个项目(不拉全量项目表)。未就绪时项目表是空的,答了也是错的。
|
|
164
|
+
*/
|
|
165
|
+
projectForCwd(cwd: string | undefined): Promise<RuntimeProject | null>;
|
|
166
|
+
/** 已登记工作区命中的项目(按 id 去重):状态展示与技能作用域按它取,没工作区的项目不进这个集合。 */
|
|
167
|
+
workspaceProjects(): RuntimeProject[];
|
|
168
|
+
/** 状态展示与持久化的工作区集合:未成 git 项目的目录直接忽略(簿记里仍留着等重解析)。 */
|
|
169
|
+
private trackedWorkspaces;
|
|
170
|
+
/**
|
|
171
|
+
* 技能附件字节:boot 文档只有清单,字节在真正加载该技能时按需取。
|
|
172
|
+
* 三次降级口径与其余领域一致——可空根字段为 null(领域失败)、传输异常、没连 hub 都返回 null,
|
|
173
|
+
* 由调用方放弃物化;只有「字段在场且为数组」才算权威答案(空数组 = 没有附件)。
|
|
174
|
+
*/
|
|
175
|
+
skillFiles(skillId: string): Promise<RuntimeSkillFileContentFact[] | null>;
|
|
176
|
+
selectHeadlessModel(input: {
|
|
177
|
+
workmode: boolean;
|
|
178
|
+
cwd?: string;
|
|
179
|
+
}): Promise<void>;
|
|
180
|
+
/**
|
|
181
|
+
* 首次加载;未配凭据或失败只落到 state.error,绝不 throw,也不注入任何配置。
|
|
182
|
+
* 未登录(只有地址、没有令牌)时仍回报地址:登录表单靠它预填。
|
|
183
|
+
*/
|
|
184
|
+
start(): Promise<void>;
|
|
185
|
+
private service;
|
|
186
|
+
/** settings 服务缺失(非 web/headless 宿主)时不阻塞启动,5s 后放弃。 */
|
|
187
|
+
private settingsService;
|
|
188
|
+
/** 运行面契约只解析一次(适配器在 apply 里同步 provide)。 */
|
|
189
|
+
private ensureContract;
|
|
190
|
+
private resolveContract;
|
|
191
|
+
/** credentials 存储首次读盘可能晚于插件启动:有界窗口内重试,仍无凭据即按「未配置」处理。 */
|
|
192
|
+
private resolveConnectionWithRetry;
|
|
193
|
+
/**
|
|
194
|
+
* CNB 面:把平台注入的短期 CNB_TOKEN 换成 hub 用户密钥(一次兑换,之后一律用换来的密钥)。
|
|
195
|
+
* 兑换失败按现有降级口径:本次不注入配置,不阻断会话。其它面 / 登录态原样返回。
|
|
196
|
+
*/
|
|
197
|
+
private exchangeCnbCredential;
|
|
198
|
+
private installStatusSection;
|
|
199
|
+
/**
|
|
200
|
+
* 工作区登记 = dsh 工作区列表变化即同步:新增/改名解析该项目并落库,移除即撤下。
|
|
201
|
+
* 服务缺席(headless 面)时回调不执行,由隐式条目兜底;配置未就绪时只记列表、不解析。
|
|
202
|
+
*/
|
|
203
|
+
private installWorkspaceSubscription;
|
|
204
|
+
/**
|
|
205
|
+
* headless 面(NPC / 无 web 服务的宿主)没有 dsh 工作区服务:启动目录就是唯一工作区。
|
|
206
|
+
* 有服务时不播——基线帧稍后给出权威列表,多一条隐式条目反而会被状态与技能作用域当成真工作区。
|
|
207
|
+
*/
|
|
208
|
+
private ensureImplicitWorkspace;
|
|
209
|
+
/** 工作区同步串行:feed 帧与「同步」交错时按到达顺序逐条落定。 */
|
|
210
|
+
private enqueueWorkspace;
|
|
211
|
+
/** 全量工作区解析(启动、「同步」、基线帧共用):一个都不在列表里时什么都不做。 */
|
|
212
|
+
private syncWorkspaces;
|
|
213
|
+
/** 单个工作区解析(upsert 帧):映射失败也要写回 error,UI 才看得出「为什么没同步」。 */
|
|
214
|
+
private syncWorkspace;
|
|
215
|
+
private applyResolved;
|
|
216
|
+
/** 反解失败与非 git 目录一样不可映射:只 warn(诊断留日志),条目按未命中处理。 */
|
|
217
|
+
private lookupSlug;
|
|
218
|
+
/**
|
|
219
|
+
* 反解不出 slug(非 git / 无 origin)与 hub 里查无此项目都不算失败:该目录不归
|
|
220
|
+
* semi2-hub 管——只落 slug 供诊断,项目三件套留空,由 `trackedWorkspaces` 挡在状态外。
|
|
221
|
+
*/
|
|
222
|
+
private resolveEntry;
|
|
223
|
+
/**
|
|
224
|
+
* 按 slug 取项目绑定并并入缓存(幂等):只问点名的 slug,hub 那边再叠一层读范围过滤。
|
|
225
|
+
* 结果空 = 该 slug 确实不在可读范围内,记进负缓存免得每次会话都重问。
|
|
226
|
+
*/
|
|
227
|
+
private fetchProjects;
|
|
228
|
+
private persistWorkspaces;
|
|
229
|
+
private publishWorkspaces;
|
|
230
|
+
private readSetting;
|
|
231
|
+
private readReloadToken;
|
|
232
|
+
private publishStatus;
|
|
233
|
+
private updateNamespace;
|
|
234
|
+
/**
|
|
235
|
+
* 权威写入:把用户段整体替换成给定内容。
|
|
236
|
+
* `update` 是**递归合并**(dsh-settings 的 mergeLayers),只增不减——服务端撤掉的条目
|
|
237
|
+
* 会在本地留成残渣,provider 路由尤其致命:目录里已不存在的模型继续可选。
|
|
238
|
+
* 所以凡是本插件全权决定的段(`llm-pi-ai` 只此一个键)都走替换。
|
|
239
|
+
*/
|
|
240
|
+
private replaceNamespace;
|
|
241
|
+
/** 按路径删除本插件写过的键(合并写入删不掉)。 */
|
|
242
|
+
private clearKeys;
|
|
243
|
+
/** 等命名空间注册完成再写(settings 服务与各 bundle 的注册有先后)。 */
|
|
244
|
+
private writeNamespace;
|
|
245
|
+
/** 读取一次运行配置;整体失败只落 state.error,绝不 throw(start/reload 均可重试)。 */
|
|
246
|
+
private load;
|
|
247
|
+
/** 启动装配:五个用户级领域问题一个文档(项目绑定按工作区另行按需取)。 */
|
|
248
|
+
private fetchBoot;
|
|
249
|
+
/**
|
|
250
|
+
* 运行面读取:身份就是连接凭据换来的用户密钥本人;读取者事实由 `runtimeViewer`
|
|
251
|
+
* 领域下发(密码登录 / hub 接入密钥 / CNB 令牌兑换都返回服务器里同一账户),请求不带 subject。
|
|
252
|
+
* operation 名同时选中结果类型,调用侧不必再断言;`variables` 是本操作自己的入参。
|
|
253
|
+
*/
|
|
254
|
+
private requestDomain;
|
|
255
|
+
/** `runtimeModels` 降级时返回 null:不动任何模型相关设置,其余领域照常。 */
|
|
256
|
+
private applyModels;
|
|
257
|
+
/**
|
|
258
|
+
* 默认模型:semi2-hub 是唯一来源,总是写(会话内的临时选择记在 session log,不受影响)。
|
|
259
|
+
*
|
|
260
|
+
* 服务端不给可用默认模型、且现行默认正指向**本轮被回收**的路由时必须把它让回组合层:
|
|
261
|
+
* 路由已从 `llm-pi-ai` 撤下,该选择就成了悬空引用,下一轮请求会以 `NO_ADAPTER` 失败
|
|
262
|
+
* (dsh-llm 的 registration 查不到适配器直接抛)。
|
|
263
|
+
*/
|
|
264
|
+
private applyDefaultModel;
|
|
265
|
+
/**
|
|
266
|
+
* 现行默认模型选择:dsh 服务优先(它读到的是含用户层的有效值),
|
|
267
|
+
* 服务缺席或没有读口时回落 `agent-default-model` 段——插件自己写进去的那一份就在那里。
|
|
268
|
+
*/
|
|
269
|
+
private currentSelection;
|
|
270
|
+
/**
|
|
271
|
+
* 写入 `llm-pi-ai.providers`:本插件的路由完全对齐服务端现状(含回收),用户自己写的条目原样保留。
|
|
272
|
+
*
|
|
273
|
+
* 预设路由键就是 dsh 的提供方 id,与用户手写 profile 同名时以用户为准(改用自铸路由),
|
|
274
|
+
* 否则会把人家配置里的 `anthropic:` 段整段替换掉。
|
|
275
|
+
*
|
|
276
|
+
* @returns 实际落地的路由表(原路由键 → 最终路由键),调用侧据此改写默认模型与项目选择——
|
|
277
|
+
* 让位后若仍按原路由键选模型,`agent-default-model` 会指向一条属于用户的 profile。
|
|
278
|
+
*/
|
|
279
|
+
private applyProviders;
|
|
280
|
+
private readProviders;
|
|
281
|
+
private readOwned;
|
|
282
|
+
/**
|
|
283
|
+
* 连接级密钥 → dsh credentials;`runtimeModelCredentials` 降级时整体跳过(返回 null)。
|
|
284
|
+
*
|
|
285
|
+
* `reconcile`(模型目录同时读到了)时才回收服务端已撤下连接的密钥:此时「服务端没有它」
|
|
286
|
+
* 是确定的,否则与「这次没读到」不可区分,只能连归属表一起原样保留。
|
|
287
|
+
*
|
|
288
|
+
* @returns 归属表该记的密钥名(本轮写过 ∪ 上次写过)。
|
|
289
|
+
*/
|
|
290
|
+
private applyModelCredentials;
|
|
291
|
+
/**
|
|
292
|
+
* 控制台技能目录:`runtimeSkills` 为 null/undefined 都算「没拿到权威目录」——返回 null 只降级该块,
|
|
293
|
+
* 状态里 null ≠ 空数组(provider 据此报 complete:false,dsh 才不把抖动缓存成空目录)。
|
|
294
|
+
*/
|
|
295
|
+
private applySkills;
|
|
296
|
+
private applied;
|
|
297
|
+
login(input: {
|
|
298
|
+
url: string;
|
|
299
|
+
username: string;
|
|
300
|
+
password: string;
|
|
301
|
+
}): Promise<{
|
|
302
|
+
userName: string;
|
|
303
|
+
}>;
|
|
304
|
+
logout(): Promise<void>;
|
|
305
|
+
/**
|
|
306
|
+
* 登出 = 回到「从未登录」:本地不留任何 semi2-hub 下发的运行配置。
|
|
307
|
+
* 残留不是显示问题——路由与密钥还在,会话就继续用着一个已登出账号的模型,
|
|
308
|
+
* 默认模型甚至指向目录里已不存在的条目(选中即 `NO_ADAPTER`)。
|
|
309
|
+
*
|
|
310
|
+
* 只删归属表记着的条目:用户自己写的 provider profile、`llm-deepseek` 键、
|
|
311
|
+
* 组合层默认模型都不属于我们。回收失败只 warn,登出本身必须成功。
|
|
312
|
+
*/
|
|
313
|
+
private reclaim;
|
|
314
|
+
/** 回收模型密钥(按归属表、以及归属表外自铸路由自带的引用);单条失败只 warn。 */
|
|
315
|
+
private reclaimCredentials;
|
|
316
|
+
private publish;
|
|
317
|
+
/** 记一条领域降级码并返回它(调用方收集,首个作为 state.error)。 */
|
|
318
|
+
private noteFailure;
|
|
319
|
+
private warn;
|
|
320
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RuntimeSkillFact, RuntimeSkillFileContentFact } from './runtime.js';
|
|
2
|
+
export interface SkillResourceStore {
|
|
3
|
+
/** 物化该技能当前版本的附件;无附件或任何失败返回 null(调用方降级为不带 resourceBase)。 */
|
|
4
|
+
materialize(skill: RuntimeSkillFact): Promise<string | null>;
|
|
5
|
+
/** 丢掉不在当前 `(skillId, version)` 集合里的缓存目录(best-effort,不抛)。 */
|
|
6
|
+
reconcile(skills: readonly RuntimeSkillFact[] | null): void;
|
|
7
|
+
}
|
|
8
|
+
export interface SkillResourceStoreOptions {
|
|
9
|
+
/** 附件字节取用口(`Semi2Config.skillFiles`);领域失败回 null。 */
|
|
10
|
+
readFiles: (skillId: string) => Promise<RuntimeSkillFileContentFact[] | null>;
|
|
11
|
+
environment: Record<string, string | undefined>;
|
|
12
|
+
warn: (message: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function createSkillResourceStore(options: SkillResourceStoreOptions): SkillResourceStore;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Semi2Config } from './runtime.js';
|
|
3
|
+
/** 装配句柄:dispose 收 provider;invalidate 丢 dsh 的按 cwd 目录缓存。 */
|
|
4
|
+
export interface SkillsInstall {
|
|
5
|
+
dispose: () => void;
|
|
6
|
+
invalidate: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function installSkills(ctx: Context, config: Semi2Config, warn: (message: string) => void): SkillsInstall;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Semi2ConfigState, Semi2Surface } from './runtime.js';
|
|
2
|
+
/** 设置命名空间 `semi2` 的状态字段(顺序 = UI 展示顺序);`reload` 由 UI 写,不在此列。 */
|
|
3
|
+
export declare const STATUS_FIELDS: readonly ["status", "error", "loadedAt", "consoleUrl", "identity", "credentialSource", "platform", "startupDir", "workspaceCount", "workspaces", "projectCount", "projects", "model", "skills"];
|
|
4
|
+
/** 不由运行面提供的事实;未决一律落空串。 */
|
|
5
|
+
export interface StatusFacts {
|
|
6
|
+
credentialSource?: string | null;
|
|
7
|
+
platform?: Semi2Surface | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function statusFields(state: Semi2ConfigState, facts?: StatusFacts): Record<string, string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RuntimeProject } from './compile.js';
|
|
2
|
+
/** 从 git remote URL 提取 org/repo(https 与 scp 风格皆可),小写规范化。 */
|
|
3
|
+
export declare function slugFromRemoteUrl(url: string): string | null;
|
|
4
|
+
/** 在 config.state.projects 里按 slug 精确匹配。 */
|
|
5
|
+
export declare function matchProject(projects: RuntimeProject[], slug: string | null): RuntimeProject | null;
|
|
6
|
+
/** cwd → git origin slug;进程内按 cwd 缓存。 */
|
|
7
|
+
export declare function workspaceSlug(cwd: string | undefined, env: NodeJS.ProcessEnv): Promise<string | null>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
/** dsh 工作区投影(结构类型:不为一个可选服务引入 @deepseek-ai/* 依赖)。 */
|
|
3
|
+
export interface WorkspaceViewLike {
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
/** dsh registry 存的已是 realpath canonical 拼写。 */
|
|
6
|
+
path: string;
|
|
7
|
+
title: string;
|
|
8
|
+
}
|
|
9
|
+
/** `workspaceController.follow` 的帧;order / archived 与本插件无关。 */
|
|
10
|
+
export type WorkspaceFrameLike = {
|
|
11
|
+
type: 'baseline';
|
|
12
|
+
value: {
|
|
13
|
+
items: readonly WorkspaceViewLike[];
|
|
14
|
+
};
|
|
15
|
+
} | {
|
|
16
|
+
type: 'upsert';
|
|
17
|
+
workspace: WorkspaceViewLike;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'remove';
|
|
20
|
+
workspaceId: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'order';
|
|
23
|
+
} | {
|
|
24
|
+
type: 'archived';
|
|
25
|
+
};
|
|
26
|
+
export interface WorkspaceControllerLike {
|
|
27
|
+
follow(signal: AbortSignal): AsyncIterable<WorkspaceFrameLike>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 一个已登记工作区及其项目映射。**没有失败态**:反解不出 slug(非 git / 无 origin)或
|
|
31
|
+
* hub 里没有对应项目,都只是「不归 semi2-hub 管」——不报错、不进状态、不落库。
|
|
32
|
+
*/
|
|
33
|
+
export interface WorkspaceEntry {
|
|
34
|
+
path: string;
|
|
35
|
+
title: string;
|
|
36
|
+
/** git origin 反解出的 org/repo;无 origin / 非 git 为 null。 */
|
|
37
|
+
slug: string | null;
|
|
38
|
+
/** 命中的 semi2-hub 项目 id;反解不出或 hub 没这个项目都为 null。 */
|
|
39
|
+
projectId: string | null;
|
|
40
|
+
name: string | null;
|
|
41
|
+
syncedAt: string | null;
|
|
42
|
+
/** true = dsh 工作区服务缺席时按 cwd 造的条目,不参与持久化。 */
|
|
43
|
+
implicit: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** 未解析条目的起点:映射三件套留空,等一次同步填。 */
|
|
46
|
+
export declare function pendingEntry(path: string, title: string, implicit?: boolean): WorkspaceEntry;
|
|
47
|
+
/** headless 面没有 dsh 工作区服务:启动目录就是唯一工作区。 */
|
|
48
|
+
export declare function implicitWorkspace(cwd: string): WorkspaceEntry;
|
|
49
|
+
/**
|
|
50
|
+
* 参与状态展示与持久化的工作区:只有命中 hub 项目的才算数。反解不出 slug(非 git)与
|
|
51
|
+
* hub 里查无此项目一样,都是「不归我们管」——簿记里留着等一次重解析(git init / 加
|
|
52
|
+
* remote / hub 补建项目都能上账),但不占状态、不入库。
|
|
53
|
+
*/
|
|
54
|
+
export declare function trackedWorkspaces(entries: readonly WorkspaceEntry[]): WorkspaceEntry[];
|
|
55
|
+
export declare function canonicalPath(directory: string): Promise<string>;
|
|
56
|
+
/**
|
|
57
|
+
* 工作区登记表:canonical path 为键,另记 workspaceId → path 以便 remove / 改名定位。
|
|
58
|
+
* 只由配置运行时单线程驱动(feed 帧与同步排在同一条队列上),故不做并发保护。
|
|
59
|
+
*/
|
|
60
|
+
export declare class WorkspaceBook {
|
|
61
|
+
private readonly byPath;
|
|
62
|
+
private readonly pathById;
|
|
63
|
+
/** 播下 dsh 基线:registry 是权威列表,不在基线里的陈旧条目(隐式条目除外)撤下。 */
|
|
64
|
+
applyBaseline(items: readonly WorkspaceViewLike[]): void;
|
|
65
|
+
/** 新增或改名:保留既有解析结果(同步很贵),只换标题。 */
|
|
66
|
+
upsertWorkspace(view: WorkspaceViewLike): WorkspaceEntry;
|
|
67
|
+
/** 移除一个工作区;未知 id 返回 undefined(幂等)。 */
|
|
68
|
+
removeWorkspace(workspaceId: string): WorkspaceEntry | undefined;
|
|
69
|
+
/** 隐式工作区:同路径已有条目就保留(不把已解析结果降级回未解析)。 */
|
|
70
|
+
ensureImplicit(cwd: string): WorkspaceEntry;
|
|
71
|
+
/** 从持久化事实恢复(启动一次);解析结果保留,项目绑定等一次同步补齐。 */
|
|
72
|
+
restore(entries: readonly WorkspaceEntry[]): void;
|
|
73
|
+
get(path: string): WorkspaceEntry | undefined;
|
|
74
|
+
set(entry: WorkspaceEntry): void;
|
|
75
|
+
entries(): WorkspaceEntry[];
|
|
76
|
+
}
|
|
77
|
+
/** 持久化形状:空值统一落空串(YAML 标量),项目绑定每次同步从 hub 重取,不入库。 */
|
|
78
|
+
export interface PersistedWorkspace {
|
|
79
|
+
path: string;
|
|
80
|
+
title: string;
|
|
81
|
+
slug: string;
|
|
82
|
+
projectId: string;
|
|
83
|
+
name: string;
|
|
84
|
+
syncedAt: string;
|
|
85
|
+
}
|
|
86
|
+
export declare function persistedWorkspaces(entries: readonly WorkspaceEntry[]): PersistedWorkspace[];
|
|
87
|
+
export interface WorkspaceFeedHandlers {
|
|
88
|
+
baseline(items: readonly WorkspaceViewLike[]): void | Promise<void>;
|
|
89
|
+
upsert(view: WorkspaceViewLike): void | Promise<void>;
|
|
90
|
+
remove(workspaceId: string): void | Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 订阅 dsh 工作区变更。服务缺席(headless 面)时回调永不执行,由调用方播一条隐式工作区兜底;
|
|
94
|
+
* 消费异常只 warn——已登记的工作区继续可用,绝不因订阅中断阻断会话。
|
|
95
|
+
*/
|
|
96
|
+
export declare function installWorkspaceFeed(ctx: Context, handlers: WorkspaceFeedHandlers, warn: (message: string) => void): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** 连接 semi2-hub 的凭据;两项齐备才算可连。 */
|
|
2
|
+
export interface Semi2Credentials {
|
|
3
|
+
configUrl?: string;
|
|
4
|
+
accessToken?: string;
|
|
5
|
+
}
|
|
6
|
+
/** 运行面平台:适配器声明的事实;宿主直跑(无契约)由插件判为 `host`。 */
|
|
7
|
+
export type Semi2Platform = 'cnb' | 'container';
|
|
8
|
+
export interface Semi2Runtime {
|
|
9
|
+
/** 由 runtimeFrom*Env 工厂盖章(适配器不自己填)。 */
|
|
10
|
+
platform: Semi2Platform;
|
|
11
|
+
/** semi2-hub 连接凭据;缺省 = 回落 dsh credentials 登录存储。 */
|
|
12
|
+
credentials?: Semi2Credentials;
|
|
13
|
+
}
|
|
14
|
+
/** cordis 服务名(适配器 provide / 插件 get 共用同一常量)。 */
|
|
15
|
+
export declare const SEMI2_RUNTIME_SERVICE = "semi2Runtime";
|
|
16
|
+
declare module '@deepseek-ai/cordis' {
|
|
17
|
+
interface Context {
|
|
18
|
+
semi2Runtime: Semi2Runtime;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* CNB 运行面:优先用 secret import 注入的 hub 接入密钥(`SEMI2_ACCESS_TOKEN`),
|
|
23
|
+
* 缺失时才回退平台短期 `CNB_TOKEN`(插件启动时换成 hub 用户密钥)。
|
|
24
|
+
*/
|
|
25
|
+
export declare function runtimeFromCnbEnv(env: NodeJS.ProcessEnv): Semi2Runtime;
|
|
26
|
+
/**
|
|
27
|
+
* 容器运行面:**只盖章,不给凭据也不给身份**——本地容器靠登录(设置页账号密码换用户密钥)。
|
|
28
|
+
* 契约一旦提供 `credentials`,插件的 `login()` 会以 `CREDENTIAL_SOURCE_READONLY` 拒绝登录
|
|
29
|
+
* (部署面地址不可被交互改写),所以这里刻意留空。
|
|
30
|
+
* CNB 面相反:身份取平台注入的触发 env、凭据取 secret 注入的 env,见 `runtimeFromCnbEnv`。
|
|
31
|
+
*/
|
|
32
|
+
export declare function runtimeFromContainerEnv(_env: NodeJS.ProcessEnv): Semi2Runtime;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import z from '@deepseek-ai/schemastery';
|
|
3
|
+
export type { RuntimeProject, Semi2Config, Semi2ConfigState, Semi2Surface, } from './configuration/runtime.js';
|
|
4
|
+
export { SEMI2_RUNTIME_SERVICE, runtimeFromCnbEnv, runtimeFromContainerEnv, } from './contract.js';
|
|
5
|
+
export type { Semi2Credentials, Semi2Platform, Semi2Runtime, } from './contract.js';
|
|
6
|
+
export declare const name = "semi2-dsh";
|
|
7
|
+
/** 三个运行面都存在(dsh-base 的 tools / skills 行);其它服务一律走作用域注入。 */
|
|
8
|
+
export declare const inject: string[];
|
|
9
|
+
export declare const Config: z<Schemastery.ObjectS<{}>, Schemastery.ObjectT<{}>>;
|
|
10
|
+
export type Config = Schemastery.TypeT<typeof Config>;
|
|
11
|
+
export declare function apply(ctx: Context, _config: Config): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { IndexInjection } from '@deepseek-ai/dsh-host-webserver';
|
|
3
|
+
/**
|
|
4
|
+
* dsh-client-connection 优先看 __DSH_TRANSPORT__:ownsHost:true 即「页面骑在拥有 host 会话的传输上」(由
|
|
5
|
+
* dsh-host-webserver 渲染进 <head> 最前),浏览器端 settings scope 因此 durable;fetch/openStream 故意留空。
|
|
6
|
+
*/
|
|
7
|
+
export declare function loopbackTransportRow(): IndexInjection;
|
|
8
|
+
export declare function installLoopbackBridge(ctx: Context): void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type IncomingHttpHeaders, type OutgoingHttpHeaders } from 'node:http';
|
|
3
|
+
import type { WorkstationRuntime } from './runtime.ts';
|
|
4
|
+
/** 代理面向浏览器/CNB 的连接保持的空闲窗口(ms)。 */
|
|
5
|
+
export declare const KEEP_ALIVE_TIMEOUT_MS = 72000;
|
|
6
|
+
/**
|
|
7
|
+
* 把信任边界头改写成固定的环回上游 authority:dsh 的 /api 信任栅栏只接受环回 Host 或预声明 authority,
|
|
8
|
+
* 且会话 cookie 绑定请求 Host(CNB 边缘的 authority 拼写会漂);Origin 一并归一为同源、sec-fetch-site 钉 same-origin。
|
|
9
|
+
*/
|
|
10
|
+
export declare function rewriteHeaders(headers: IncomingHttpHeaders, upstreamHost: string): OutgoingHttpHeaders;
|
|
11
|
+
/**
|
|
12
|
+
* 干净 `GET /` 不带有效 cookie 会被 dsh 弹 401(cookie 只在 `?token=` 交换时签发),故代理代用户把裸 `/`
|
|
13
|
+
* 转发成 `/?token=…`(token 不出服务端);已持 cookie 的后续请求绝不能再重放(否则 303 打转),非 index 原样转发。
|
|
14
|
+
*/
|
|
15
|
+
export declare function indexProxyPath(requestUrl: string, authenticatedIndexUrl: string, shouldReplay: boolean): string;
|
|
16
|
+
/** 安装入口:`ws` 惰性加载——headless 面永不执行到这里,也就永不加载 ws。 */
|
|
17
|
+
export declare function installPreviewProxy(ctx: Context, runtime: WorkstationRuntime): Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface WorkstationRuntime {
|
|
2
|
+
cwd: string;
|
|
3
|
+
dshPort: number;
|
|
4
|
+
previewPort: number;
|
|
5
|
+
pingIntervalMs: number;
|
|
6
|
+
}
|
|
7
|
+
/** cwd 对齐 /workspace 并同步 HOME(dsh 新会话默认目录取 homedir);dshPort 取官方 webServer 监听端口。 */
|
|
8
|
+
export declare function createWorkstationRuntime(dshPort: number): WorkstationRuntime;
|