superun-ai-cli 0.1.33 → 0.1.34
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.en.md +1 -0
- package/README.md +4 -1
- package/dist/commands/shared.d.ts +4 -0
- package/dist/commands/shared.js +46 -28
- package/dist/commands/shared.js.map +1 -1
- package/dist/config/state-directory.d.ts +1 -0
- package/dist/config/state-directory.js +13 -0
- package/dist/config/state-directory.js.map +1 -0
- package/dist/interactions/draft-store.d.ts +8 -0
- package/dist/interactions/draft-store.js +163 -70
- package/dist/interactions/draft-store.js.map +1 -1
- package/dist/interactions/state-storage.d.ts +4 -0
- package/dist/interactions/state-storage.js +65 -0
- package/dist/interactions/state-storage.js.map +1 -0
- package/dist/output/exit-codes.d.ts +4 -0
- package/dist/output/exit-codes.js +4 -0
- package/dist/output/exit-codes.js.map +1 -1
- package/dist/program.js +4 -1
- package/dist/program.js.map +1 -1
- package/dist/session/binding.d.ts +6 -4
- package/dist/session/binding.js +68 -22
- package/dist/session/binding.js.map +1 -1
- package/dist/session/remember-worker.d.ts +1 -0
- package/dist/session/remember-worker.js +43 -0
- package/dist/session/remember-worker.js.map +1 -0
- package/dist/session/remember.d.ts +9 -0
- package/dist/session/remember.js +14 -0
- package/dist/session/remember.js.map +1 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -367,6 +367,7 @@ Business commands write one JSON result to stdout. Diagnostics and update progre
|
|
|
367
367
|
| 6 | Interaction unsupported by this CLI version |
|
|
368
368
|
| 7 | Timeout for an attachment or auxiliary operation |
|
|
369
369
|
| 8 | Network or response-protocol error |
|
|
370
|
+
| 9 | Local state permission, I/O, lock contention, or recovery error |
|
|
370
371
|
| 130 | Local command interrupted |
|
|
371
372
|
|
|
372
373
|
`OUTCOME_UNKNOWN` means a request may have been accepted. Do not immediately retry the write. Query the returned session ID first. If a create request did not return a session ID, check the project list before deciding what to do next.
|
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ superun-ai
|
|
|
125
125
|
|
|
126
126
|
## 恢复当前会话的项目
|
|
127
127
|
|
|
128
|
-
在可识别会话归属的 Codex、WorkBuddy / CodeBuddy 环境中,CLI
|
|
128
|
+
在可识别会话归属的 Codex、WorkBuddy / CodeBuddy 环境中,CLI 会记住当前会话正在创作的一个项目。新建项目会替换原绑定;显式项目操作直接使用传入的 ID,并在后台尝试保存绑定。列出项目、查询详情或等待任务不会改变绑定。
|
|
129
129
|
|
|
130
130
|
```bash
|
|
131
131
|
superun-ai session current
|
|
@@ -139,6 +139,8 @@ superun-ai session clear
|
|
|
139
139
|
|
|
140
140
|
`UNBOUND` 表示尚未绑定;`UNAVAILABLE` 表示无法识别宿主会话,此时继续显式传入 `sessionId`。若返回 `CREATING` 或 `CREATE_UNKNOWN`,先核对原创建请求,不要重复创建;确认已有项目后可用 `use` 恢复绑定。
|
|
141
141
|
|
|
142
|
+
如需自定义本地状态保存位置,可设置 `SUPERUN_STATE_DIR` 为持久化目录的绝对路径。默认路径不变;同一宿主的主代理、子代理及后续命令应使用相同配置。切换目录前请备份并迁移已有状态。
|
|
143
|
+
|
|
142
144
|
## PAT 登录
|
|
143
145
|
|
|
144
146
|
```bash
|
|
@@ -536,6 +538,7 @@ CLI 每次上传前读取 Glow 同源的服务端格式和大小限制。当前
|
|
|
536
538
|
| 6 | 当前版本不支持所需交互 |
|
|
537
539
|
| 7 | 附件等辅助操作等待超时 |
|
|
538
540
|
| 8 | 网络或响应协议错误 |
|
|
541
|
+
| 9 | 本地状态权限、读写、锁竞争或残留恢复错误 |
|
|
539
542
|
| 130 | 本地命令被中断 |
|
|
540
543
|
|
|
541
544
|
`OUTCOME_UNKNOWN` 表示请求可能已被接受,不能直接重试写操作。先使用返回的会话 ID 查询状态;创建请求若未取得会话 ID,应查询项目列表确认。
|
|
@@ -13,6 +13,8 @@ export type CommandContext = {
|
|
|
13
13
|
connection?: Promise<CredentialContext>;
|
|
14
14
|
sessionBinding?: Promise<SessionBinding | undefined>;
|
|
15
15
|
selectedSessionId?: string;
|
|
16
|
+
selectionRequestedAt?: string;
|
|
17
|
+
rememberSession?: (sessionId: string, requestedAt: string, creationRevision?: string) => void;
|
|
16
18
|
};
|
|
17
19
|
export type CredentialContext = {
|
|
18
20
|
service: CreationRuntime;
|
|
@@ -21,6 +23,8 @@ export type CredentialContext = {
|
|
|
21
23
|
/** 已有 PAT 直接复用;允许浏览器登录时自动补齐缺失的凭据。 */
|
|
22
24
|
export declare function requireCredentials(context: CommandContext, command: Command, allowBrowser?: boolean): Promise<CredentialContext>;
|
|
23
25
|
export declare function runtime(context: CommandContext, command: Command): Promise<CreationRuntime>;
|
|
26
|
+
/** 命令分发时启动后台保存;显式项目不读取本地绑定,也不等待辅助保存。 */
|
|
27
|
+
export declare function rememberExplicitSession(context: CommandContext, command: Command): void;
|
|
24
28
|
/** 绑定归属仅在公共层识别一次;宿主未提供可靠身份时保留显式调用能力。 */
|
|
25
29
|
export declare function sessionBinding(context: CommandContext, service: CreationRuntime): Promise<SessionBinding | undefined>;
|
|
26
30
|
export declare function positive(value: string): number;
|
package/dist/commands/shared.js
CHANGED
|
@@ -13,6 +13,7 @@ import { object, text } from '../contracts/value.js';
|
|
|
13
13
|
import { creditCode } from '../conversation/insufficient-credits.js';
|
|
14
14
|
import { SessionBinding } from '../session/binding.js';
|
|
15
15
|
import { detectHostContext } from '../session/host-context.js';
|
|
16
|
+
import { scheduleRemember } from '../session/remember.js';
|
|
16
17
|
async function loadCredentialContext(context, command, allowBrowser) {
|
|
17
18
|
const options = object(command.optsWithGlobals());
|
|
18
19
|
const config = runtimeConfig({
|
|
@@ -29,6 +30,14 @@ async function loadCredentialContext(context, command, allowBrowser) {
|
|
|
29
30
|
context.output.registerSecret(credential.pat);
|
|
30
31
|
const service = context.makeRuntime?.(config, credential.pat) ??
|
|
31
32
|
new CreationRuntime(new ApiClient(config, credential.pat, undefined, context.signal), context.output);
|
|
33
|
+
context.rememberSession = (sessionId, requestedAt, creationRevision) => scheduleRemember({
|
|
34
|
+
sessionId,
|
|
35
|
+
requestedAt,
|
|
36
|
+
endpoint: config.endpoint,
|
|
37
|
+
locale: config.locale,
|
|
38
|
+
credentialScope: service.client.interactionScope,
|
|
39
|
+
...(creationRevision ? { creationRevision } : {}),
|
|
40
|
+
});
|
|
32
41
|
return { service, credentialSource: credential.source };
|
|
33
42
|
}
|
|
34
43
|
/** 已有 PAT 直接复用;允许浏览器登录时自动补齐缺失的凭据。 */
|
|
@@ -42,6 +51,7 @@ const projectOperations = new Set([
|
|
|
42
51
|
'test',
|
|
43
52
|
'review',
|
|
44
53
|
'security',
|
|
54
|
+
'agent-friendly',
|
|
45
55
|
'stop',
|
|
46
56
|
'retry',
|
|
47
57
|
'demo',
|
|
@@ -58,7 +68,10 @@ const projectOperations = new Set([
|
|
|
58
68
|
'publish visibility',
|
|
59
69
|
]);
|
|
60
70
|
export async function runtime(context, command) {
|
|
61
|
-
|
|
71
|
+
return (await requireCredentials(context, command)).service;
|
|
72
|
+
}
|
|
73
|
+
/** 命令分发时启动后台保存;显式项目不读取本地绑定,也不等待辅助保存。 */
|
|
74
|
+
export function rememberExplicitSession(context, command) {
|
|
62
75
|
const path = [];
|
|
63
76
|
let parent = command;
|
|
64
77
|
while (parent?.parent && parent.name() !== 'chat') {
|
|
@@ -66,17 +79,18 @@ export async function runtime(context, command) {
|
|
|
66
79
|
parent = parent.parent;
|
|
67
80
|
}
|
|
68
81
|
const sessionId = command.processedArgs[0];
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
const options = object(command.opts());
|
|
83
|
+
if (path.join(' ') === 'agent-friendly' && (options.status || options.method || options.messageId))
|
|
84
|
+
return;
|
|
85
|
+
if (parent?.name() !== 'chat' ||
|
|
86
|
+
!projectOperations.has(path.join(' ')) ||
|
|
87
|
+
typeof sessionId !== 'string' ||
|
|
88
|
+
context.selectedSessionId === sessionId ||
|
|
89
|
+
!context.selectionRequestedAt ||
|
|
90
|
+
context.signal.aborted)
|
|
75
91
|
return;
|
|
76
|
-
const binding = await sessionBinding(context, service);
|
|
77
|
-
if (binding)
|
|
78
|
-
await binding.select(service, sessionId);
|
|
79
92
|
context.selectedSessionId = sessionId;
|
|
93
|
+
context.rememberSession?.(sessionId, context.selectionRequestedAt);
|
|
80
94
|
}
|
|
81
95
|
/** 绑定归属仅在公共层识别一次;宿主未提供可靠身份时保留显式调用能力。 */
|
|
82
96
|
export async function sessionBinding(context, service) {
|
|
@@ -133,12 +147,12 @@ export async function readInput(path) {
|
|
|
133
147
|
}
|
|
134
148
|
}
|
|
135
149
|
export async function businessWrite(context, service, sessionId, action) {
|
|
136
|
-
const binding = await sessionBinding(context, service);
|
|
137
|
-
if (!binding)
|
|
150
|
+
const binding = sessionId ? undefined : await sessionBinding(context, service);
|
|
151
|
+
if (!sessionId && !binding)
|
|
138
152
|
context.output.log('宿主未提供可确认归属的会话身份,本次不会自动保存当前项目;仍可显式传入 sessionId。');
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
const revision = !sessionId ? await binding?.beginCreation() : undefined;
|
|
153
|
+
if (sessionId)
|
|
154
|
+
context.selectedSessionId = sessionId;
|
|
155
|
+
const revision = !sessionId ? await binding?.beginCreation(context.selectionRequestedAt) : undefined;
|
|
142
156
|
let response;
|
|
143
157
|
try {
|
|
144
158
|
response = await action();
|
|
@@ -147,7 +161,12 @@ export async function businessWrite(context, service, sessionId, action) {
|
|
|
147
161
|
if (binding && revision) {
|
|
148
162
|
const rejected = error instanceof CliError &&
|
|
149
163
|
['BUSINESS_ERROR', 'AUTH_REQUIRED', 'INVALID_ARGUMENT'].includes(error.code);
|
|
150
|
-
|
|
164
|
+
try {
|
|
165
|
+
await binding.finishCreation(revision, rejected ? 'CREATE_FAILED' : 'CREATE_UNKNOWN');
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// 原 CREATING 仍阻止重复提交,不能用清理异常覆盖业务错误。
|
|
169
|
+
}
|
|
151
170
|
}
|
|
152
171
|
if (error instanceof CliError && creditCode(error.details.businessCode))
|
|
153
172
|
throw new CliError(error.code, error.message, {
|
|
@@ -175,24 +194,23 @@ export async function businessWrite(context, service, sessionId, action) {
|
|
|
175
194
|
throw new CliError('INTERRUPTED', '命令已中断,远端任务不受影响', { sessionId });
|
|
176
195
|
throw error;
|
|
177
196
|
}
|
|
178
|
-
if (
|
|
197
|
+
if (!sessionId) {
|
|
179
198
|
const createdSessionId = text(object(response).sessionId);
|
|
180
199
|
if (!createdSessionId) {
|
|
181
|
-
|
|
200
|
+
if (binding && revision) {
|
|
201
|
+
try {
|
|
202
|
+
await binding.finishCreation(revision, 'CREATE_UNKNOWN');
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// 保留未决创建保护,不覆盖缺少回执 ID 的原始结论。
|
|
206
|
+
}
|
|
207
|
+
}
|
|
182
208
|
throw new CliError('OUTCOME_UNKNOWN', '创建回执未包含 sessionId,请先核对结果,不要重复创建', {
|
|
183
209
|
retryable: false,
|
|
184
210
|
});
|
|
185
211
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
catch {
|
|
190
|
-
throw new CliError('PROTOCOL_ERROR', '项目已创建,但本地绑定保存失败;请保留 sessionId 继续查询,不要重复创建', {
|
|
191
|
-
sessionId: createdSessionId,
|
|
192
|
-
remoteAccepted: true,
|
|
193
|
-
retryable: false,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
212
|
+
// 已拿到真实项目 ID:返回业务回执,绑定及保护记录收尾交给后台处理。
|
|
213
|
+
context.rememberSession?.(createdSessionId, context.selectionRequestedAt ?? new Date().toISOString(), revision);
|
|
196
214
|
}
|
|
197
215
|
return response;
|
|
198
216
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function stateDirectory(kind: 'sessions' | 'interactions'): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** 各宿主共用的持久化状态目录,不影响凭据与安装缓存。@author xiuyu.yi */
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { isAbsolute, join, normalize } from 'node:path';
|
|
4
|
+
import { CliError } from '../output/exit-codes.js';
|
|
5
|
+
export function stateDirectory(kind) {
|
|
6
|
+
const configured = process.env.SUPERUN_STATE_DIR;
|
|
7
|
+
if (configured === undefined)
|
|
8
|
+
return join(homedir(), '.config/superun-ai-cli', kind);
|
|
9
|
+
if (!configured.trim() || !isAbsolute(configured))
|
|
10
|
+
throw new CliError('INVALID_ARGUMENT', 'SUPERUN_STATE_DIR 必须是宿主允许读写的持久化目录绝对路径');
|
|
11
|
+
return join(normalize(configured), kind);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=state-directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-directory.js","sourceRoot":"","sources":["../../src/config/state-directory.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,UAAU,cAAc,CAAC,IAAiC;IAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACjD,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,wBAAwB,EAAE,IAAI,CAAC,CAAC;IACrF,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAC/C,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,uCAAuC,CAAC,CAAC;IAClF,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -5,6 +5,14 @@ export declare class InteractionDraftStore {
|
|
|
5
5
|
constructor(scope: string, root?: string);
|
|
6
6
|
private path;
|
|
7
7
|
read(key: string): Promise<unknown>;
|
|
8
|
+
private remove;
|
|
9
|
+
private close;
|
|
10
|
+
private writeFile;
|
|
11
|
+
private prepare;
|
|
12
|
+
private checkDirectory;
|
|
8
13
|
write(key: string, value: unknown): Promise<void>;
|
|
14
|
+
private owner;
|
|
15
|
+
private alive;
|
|
16
|
+
private recoveryRequired;
|
|
9
17
|
locked<T>(key: string, run: () => Promise<T>): Promise<T>;
|
|
10
18
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/** 按环境和凭据隔离交互草稿,串行保存回答与创建进度。@author xiuyu.yi */
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { mkdir, open, readFile, rename, unlink } from 'node:fs/promises';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { stateDirectory } from '../config/state-directory.js';
|
|
6
6
|
import { CliError } from '../output/exit-codes.js';
|
|
7
|
+
import { filesystemCode, stateOperation, withStateCleanup } from './state-storage.js';
|
|
7
8
|
export const fingerprint = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
|
|
9
|
+
// 同一进程同一目录只检查一次;实际操作仍处理权限变化与磁盘异常。
|
|
10
|
+
const checkedDirectories = new Map();
|
|
8
11
|
export class InteractionDraftStore {
|
|
9
12
|
scope;
|
|
10
13
|
root;
|
|
11
|
-
constructor(scope, root =
|
|
14
|
+
constructor(scope, root = stateDirectory('interactions')) {
|
|
12
15
|
this.scope = scope;
|
|
13
16
|
this.root = root;
|
|
14
17
|
}
|
|
@@ -16,87 +19,177 @@ export class InteractionDraftStore {
|
|
|
16
19
|
return join(this.root, this.scope, `${fingerprint(key)}.json`);
|
|
17
20
|
}
|
|
18
21
|
async read(key) {
|
|
22
|
+
const path = this.path(key);
|
|
23
|
+
const content = await stateOperation('read', path, async () => {
|
|
24
|
+
try {
|
|
25
|
+
return await readFile(path, 'utf8');
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (filesystemCode(error) === 'ENOENT')
|
|
29
|
+
return undefined;
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
if (content === undefined)
|
|
34
|
+
return undefined;
|
|
19
35
|
try {
|
|
20
|
-
return JSON.parse(
|
|
36
|
+
return JSON.parse(content);
|
|
21
37
|
}
|
|
22
|
-
catch
|
|
23
|
-
|
|
24
|
-
return undefined;
|
|
25
|
-
throw new CliError('PROTOCOL_ERROR', '交互草稿无法读取,请保留文件排查,勿重复创建');
|
|
38
|
+
catch {
|
|
39
|
+
throw new CliError('PROTOCOL_ERROR', '本地状态文件格式无效,请保留文件排查,勿重复创建', { path });
|
|
26
40
|
}
|
|
27
41
|
}
|
|
42
|
+
remove(path) {
|
|
43
|
+
return stateOperation('unlink', path, async () => {
|
|
44
|
+
try {
|
|
45
|
+
await unlink(path);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (filesystemCode(error) !== 'ENOENT')
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
close(file, path) {
|
|
54
|
+
return stateOperation('close', path, () => file.close());
|
|
55
|
+
}
|
|
56
|
+
async writeFile(path, content) {
|
|
57
|
+
const file = await stateOperation('create', path, () => open(path, 'wx', 0o600));
|
|
58
|
+
await withStateCleanup(async () => {
|
|
59
|
+
await stateOperation('write', path, () => file.writeFile(content));
|
|
60
|
+
await stateOperation('fsync', path, () => file.sync());
|
|
61
|
+
}, [() => this.close(file, path)]);
|
|
62
|
+
}
|
|
63
|
+
prepare() {
|
|
64
|
+
const directory = resolve(this.root, this.scope);
|
|
65
|
+
let checked = checkedDirectories.get(directory);
|
|
66
|
+
if (!checked) {
|
|
67
|
+
checked = this.checkDirectory(directory).catch((error) => {
|
|
68
|
+
checkedDirectories.delete(directory);
|
|
69
|
+
throw error;
|
|
70
|
+
});
|
|
71
|
+
checkedDirectories.set(directory, checked);
|
|
72
|
+
}
|
|
73
|
+
return checked;
|
|
74
|
+
}
|
|
75
|
+
async checkDirectory(directory) {
|
|
76
|
+
await stateOperation('mkdir', directory, () => mkdir(directory, { recursive: true, mode: 0o700 }));
|
|
77
|
+
const temp = join(directory, `.state-probe-${randomUUID()}.tmp`);
|
|
78
|
+
const target = `${temp}.ready`;
|
|
79
|
+
// 检查失败最多留下诊断文件,不能先创建真实业务锁;清理失败保留路径。
|
|
80
|
+
await withStateCleanup(async () => {
|
|
81
|
+
await this.writeFile(temp, '{}');
|
|
82
|
+
await stateOperation('rename', temp, () => rename(temp, target));
|
|
83
|
+
// 同时验证覆盖已存在文件的原子改名,避免首次绑定成功、后续更新才失败。
|
|
84
|
+
await this.writeFile(temp, '{}');
|
|
85
|
+
await stateOperation('rename', temp, () => rename(temp, target));
|
|
86
|
+
}, [() => this.remove(temp), () => this.remove(target)]);
|
|
87
|
+
}
|
|
28
88
|
async write(key, value) {
|
|
29
|
-
await
|
|
89
|
+
await this.prepare();
|
|
30
90
|
const path = this.path(key), temp = `${path}.${randomUUID()}.tmp`;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
await
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
finally {
|
|
37
|
-
await file.close();
|
|
38
|
-
}
|
|
39
|
-
await rename(temp, path);
|
|
91
|
+
await withStateCleanup(async () => {
|
|
92
|
+
await this.writeFile(temp, JSON.stringify(value));
|
|
93
|
+
await stateOperation('rename', temp, () => rename(temp, path));
|
|
94
|
+
}, [() => this.remove(temp)]);
|
|
40
95
|
}
|
|
41
|
-
async
|
|
42
|
-
await
|
|
43
|
-
const path = `${this.path(key)}.lock`;
|
|
44
|
-
// 不回收无法确认归属的锁。已退出进程的遗留锁可在下一次操作恢复。
|
|
45
|
-
let lock;
|
|
46
|
-
try {
|
|
47
|
-
lock = await open(path, 'wx', 0o600);
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
if (error.code !== 'EEXIST')
|
|
51
|
-
throw error;
|
|
52
|
-
// 遗留锁回收也必须互斥,避免两个恢复进程误删对方刚取得的新锁。
|
|
53
|
-
const recoveryPath = `${path}.recovery`;
|
|
54
|
-
let recovery;
|
|
96
|
+
async owner(path) {
|
|
97
|
+
const content = await stateOperation('read-lock', path, async () => {
|
|
55
98
|
try {
|
|
56
|
-
|
|
99
|
+
return await readFile(path, 'utf8');
|
|
57
100
|
}
|
|
58
|
-
catch {
|
|
59
|
-
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (filesystemCode(error) === 'ENOENT')
|
|
103
|
+
throw new CliError('LOCAL_STATE_LOCKED', '本地状态锁已变化,请重新查询状态', { path });
|
|
104
|
+
throw error;
|
|
60
105
|
}
|
|
106
|
+
});
|
|
107
|
+
const pid = Number(content);
|
|
108
|
+
return Number.isSafeInteger(pid) && pid > 0 ? pid : undefined;
|
|
109
|
+
}
|
|
110
|
+
async alive(pid, path) {
|
|
111
|
+
return stateOperation('check-lock-owner', path, async () => {
|
|
61
112
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
113
|
+
process.kill(pid, 0);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (filesystemCode(error) === 'ESRCH')
|
|
118
|
+
return false;
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
recoveryRequired(path, lockPid) {
|
|
124
|
+
return new CliError('LOCAL_STATE_RECOVERY_REQUIRED', '本地状态锁无法安全自动回收;请先确认没有写入进程,再备份并恢复所列锁文件,不要反复重试或按文件年龄强制删除', { path, lockPid });
|
|
125
|
+
}
|
|
126
|
+
async locked(key, run) {
|
|
127
|
+
await this.prepare();
|
|
128
|
+
const path = `${this.path(key)}.lock`;
|
|
129
|
+
let lock;
|
|
130
|
+
const acquire = () => open(path, 'wx', 0o600);
|
|
131
|
+
return withStateCleanup(async () => {
|
|
132
|
+
// 恢复分支清理失败时,外层仍会释放刚取得的业务锁。
|
|
133
|
+
await stateOperation('acquire-lock', path, async () => {
|
|
80
134
|
try {
|
|
81
|
-
lock = await
|
|
135
|
+
lock = await acquire();
|
|
136
|
+
return;
|
|
82
137
|
}
|
|
83
|
-
catch {
|
|
84
|
-
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (filesystemCode(error) !== 'EEXIST')
|
|
140
|
+
throw error;
|
|
85
141
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
142
|
+
const recoveryPath = `${path}.recovery`;
|
|
143
|
+
const recovery = await stateOperation('acquire-recovery-lock', recoveryPath, async () => {
|
|
144
|
+
try {
|
|
145
|
+
return await open(recoveryPath, 'wx', 0o600);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (filesystemCode(error) !== 'EEXIST')
|
|
149
|
+
throw error;
|
|
150
|
+
const pid = await this.owner(recoveryPath);
|
|
151
|
+
if (pid !== undefined && (await this.alive(pid, recoveryPath)))
|
|
152
|
+
throw new CliError('LOCAL_STATE_LOCKED', '本地状态锁正在恢复,请等待持有进程结束', {
|
|
153
|
+
path: recoveryPath,
|
|
154
|
+
lockPid: pid,
|
|
155
|
+
});
|
|
156
|
+
// 旧空锁或已退出恢复进程的锁无法凭年龄判断归属,必须显式维护。
|
|
157
|
+
throw this.recoveryRequired(recoveryPath, pid);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
await withStateCleanup(async () => {
|
|
161
|
+
await stateOperation('write-lock-owner', recoveryPath, () => recovery.writeFile(String(process.pid)));
|
|
162
|
+
const pid = await this.owner(path);
|
|
163
|
+
if (pid === undefined)
|
|
164
|
+
throw this.recoveryRequired(path);
|
|
165
|
+
if (await this.alive(pid, path))
|
|
166
|
+
throw new CliError('LOCAL_STATE_LOCKED', '本地状态正在由其他进程更新,请等待该进程结束', {
|
|
167
|
+
path,
|
|
168
|
+
lockPid: pid,
|
|
169
|
+
});
|
|
170
|
+
await this.remove(path);
|
|
171
|
+
try {
|
|
172
|
+
lock = await acquire();
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (filesystemCode(error) !== 'EEXIST')
|
|
176
|
+
throw error;
|
|
177
|
+
throw new CliError('LOCAL_STATE_LOCKED', '其他进程已取得本地状态锁,请稍后查询', { path });
|
|
178
|
+
}
|
|
179
|
+
}, [() => this.close(recovery, recoveryPath), () => this.remove(recoveryPath)]);
|
|
180
|
+
});
|
|
181
|
+
await stateOperation('write-lock-owner', path, () => lock.writeFile(String(process.pid)));
|
|
182
|
+
return run();
|
|
183
|
+
}, [
|
|
184
|
+
async () => {
|
|
185
|
+
if (lock)
|
|
186
|
+
await this.close(lock, path);
|
|
187
|
+
},
|
|
188
|
+
async () => {
|
|
189
|
+
if (lock)
|
|
190
|
+
await this.remove(path);
|
|
191
|
+
},
|
|
192
|
+
]);
|
|
100
193
|
}
|
|
101
194
|
}
|
|
102
195
|
//# sourceMappingURL=draft-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft-store.js","sourceRoot":"","sources":["../../src/interactions/draft-store.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"draft-store.js","sourceRoot":"","sources":["../../src/interactions/draft-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function filesystemCode(error: unknown): string | undefined;
|
|
2
|
+
export declare function stateOperation<T>(operation: string, path: string, run: () => Promise<T>): Promise<T>;
|
|
3
|
+
/** 所有清理均尝试执行;清理异常不能覆盖首次异常。 */
|
|
4
|
+
export declare function withStateCleanup<T>(run: () => Promise<T>, cleanup: Array<() => Promise<unknown>>): Promise<T>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** 保留状态操作与清理失败的诊断信息,不输出状态内容。@author xiuyu.yi */
|
|
2
|
+
import { CliError } from '../output/exit-codes.js';
|
|
3
|
+
export function filesystemCode(error) {
|
|
4
|
+
return error && typeof error === 'object' && 'code' in error && typeof error.code === 'string'
|
|
5
|
+
? error.code
|
|
6
|
+
: undefined;
|
|
7
|
+
}
|
|
8
|
+
export async function stateOperation(operation, path, run) {
|
|
9
|
+
try {
|
|
10
|
+
return await run();
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error instanceof CliError)
|
|
14
|
+
throw error;
|
|
15
|
+
const code = filesystemCode(error);
|
|
16
|
+
const denied = code === 'EPERM' || code === 'EACCES';
|
|
17
|
+
throw new CliError(denied ? 'LOCAL_STATE_PERMISSION_DENIED' : 'LOCAL_STATE_IO_ERROR', denied
|
|
18
|
+
? '本地状态目录权限不足,请由宿主授权所需文件操作,或配置可用的持久化 SUPERUN_STATE_DIR;不要重复提交业务请求'
|
|
19
|
+
: '本地状态文件操作失败,请根据操作和路径排查;不要重复提交业务请求', { filesystemCode: code, operation, path });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** 所有清理均尝试执行;清理异常不能覆盖首次异常。 */
|
|
23
|
+
export async function withStateCleanup(run, cleanup) {
|
|
24
|
+
let failed = false;
|
|
25
|
+
let primary;
|
|
26
|
+
let result;
|
|
27
|
+
try {
|
|
28
|
+
result = await run();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
failed = true;
|
|
32
|
+
primary = error;
|
|
33
|
+
}
|
|
34
|
+
const errors = [];
|
|
35
|
+
for (const clean of cleanup) {
|
|
36
|
+
try {
|
|
37
|
+
await clean();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
errors.push(error instanceof CliError ? error : new CliError('LOCAL_STATE_IO_ERROR', '本地状态清理失败'));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (errors.length) {
|
|
44
|
+
const first = failed
|
|
45
|
+
? primary instanceof CliError
|
|
46
|
+
? primary
|
|
47
|
+
: new CliError('PROTOCOL_ERROR', '操作失败且本地状态清理失败,请保留现场排查')
|
|
48
|
+
: errors.shift();
|
|
49
|
+
throw new CliError(first.code, first.message, {
|
|
50
|
+
...first.details,
|
|
51
|
+
...(errors.length
|
|
52
|
+
? {
|
|
53
|
+
cleanupErrors: [
|
|
54
|
+
...(Array.isArray(first.details.cleanupErrors) ? first.details.cleanupErrors : []),
|
|
55
|
+
...errors.map((error) => ({ ...error.details, code: error.code })),
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
: {}),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (failed)
|
|
62
|
+
throw primary;
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=state-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-storage.js","sourceRoot":"","sources":["../../src/interactions/state-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,10 @@ export declare const EXIT_CODES: {
|
|
|
12
12
|
readonly UNSUPPORTED_INTERACTION: 6;
|
|
13
13
|
readonly LOCAL_WAIT_TIMEOUT: 7;
|
|
14
14
|
readonly PROTOCOL_ERROR: 8;
|
|
15
|
+
readonly LOCAL_STATE_PERMISSION_DENIED: 9;
|
|
16
|
+
readonly LOCAL_STATE_IO_ERROR: 9;
|
|
17
|
+
readonly LOCAL_STATE_LOCKED: 9;
|
|
18
|
+
readonly LOCAL_STATE_RECOVERY_REQUIRED: 9;
|
|
15
19
|
readonly INTERRUPTED: 130;
|
|
16
20
|
};
|
|
17
21
|
export type ErrorCode = keyof typeof EXIT_CODES;
|
|
@@ -12,6 +12,10 @@ export const EXIT_CODES = {
|
|
|
12
12
|
UNSUPPORTED_INTERACTION: 6,
|
|
13
13
|
LOCAL_WAIT_TIMEOUT: 7,
|
|
14
14
|
PROTOCOL_ERROR: 8,
|
|
15
|
+
LOCAL_STATE_PERMISSION_DENIED: 9,
|
|
16
|
+
LOCAL_STATE_IO_ERROR: 9,
|
|
17
|
+
LOCAL_STATE_LOCKED: 9,
|
|
18
|
+
LOCAL_STATE_RECOVERY_REQUIRED: 9,
|
|
15
19
|
INTERRUPTED: 130,
|
|
16
20
|
};
|
|
17
21
|
export class CliError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/output/exit-codes.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,gBAAgB,EAAE,CAAC;IACnB,aAAa,EAAE,CAAC;IAChB,eAAe,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC;IAChB,oBAAoB,EAAE,CAAC;IACvB,cAAc,EAAE,CAAC;IACjB,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,CAAC;IACxB,eAAe,EAAE,CAAC;IAClB,uBAAuB,EAAE,CAAC;IAC1B,kBAAkB,EAAE,CAAC;IACrB,cAAc,EAAE,CAAC;IACjB,WAAW,EAAE,GAAG;CACR,CAAC;AAIX,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB;IAEA;IAHX,YACW,IAAe,EACxB,OAAe,EACN,UAAmC,EAAE;QAE9C,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,SAAI,GAAJ,IAAI,CAAW;QAEf,YAAO,GAAP,OAAO,CAA8B;QAG9C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/output/exit-codes.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,gBAAgB,EAAE,CAAC;IACnB,aAAa,EAAE,CAAC;IAChB,eAAe,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC;IAChB,oBAAoB,EAAE,CAAC;IACvB,cAAc,EAAE,CAAC;IACjB,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,CAAC;IACxB,eAAe,EAAE,CAAC;IAClB,uBAAuB,EAAE,CAAC;IAC1B,kBAAkB,EAAE,CAAC;IACrB,cAAc,EAAE,CAAC;IACjB,6BAA6B,EAAE,CAAC;IAChC,oBAAoB,EAAE,CAAC;IACvB,kBAAkB,EAAE,CAAC;IACrB,6BAA6B,EAAE,CAAC;IAChC,WAAW,EAAE,GAAG;CACR,CAAC;AAIX,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB;IAEA;IAHX,YACW,IAAe,EACxB,OAAe,EACN,UAAmC,EAAE;QAE9C,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,SAAI,GAAJ,IAAI,CAAW;QAEf,YAAO,GAAP,OAAO,CAA8B;QAG9C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
package/dist/program.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** 命令树与公共选项。@author xiuyu.yi */
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { COMMAND_NAME, PACKAGE_VERSION } from './config/constants.js';
|
|
4
|
-
import { requireCredentials } from './commands/shared.js';
|
|
4
|
+
import { requireCredentials, rememberExplicitSession } from './commands/shared.js';
|
|
5
5
|
import { registerAuth } from './commands/auth/index.js';
|
|
6
6
|
import { registerSession } from './commands/session/index.js';
|
|
7
7
|
import { registerChat } from './commands/chat/index.js';
|
|
@@ -20,6 +20,8 @@ export function createProgram(context, hooks) {
|
|
|
20
20
|
context.connection = undefined;
|
|
21
21
|
context.sessionBinding = undefined;
|
|
22
22
|
context.selectedSessionId = undefined;
|
|
23
|
+
context.selectionRequestedAt = new Date().toISOString();
|
|
24
|
+
context.rememberSession = undefined;
|
|
23
25
|
const rootCommand = action.parent === program;
|
|
24
26
|
const authCommand = action.parent?.name() === 'auth' && action.parent.parent === program;
|
|
25
27
|
const offline = (rootCommand && (action.name() === 'version' || action.name() === 'update')) ||
|
|
@@ -29,6 +31,7 @@ export function createProgram(context, hooks) {
|
|
|
29
31
|
await hooks.beforeBusiness();
|
|
30
32
|
if (!(authCommand && action.name() === 'login'))
|
|
31
33
|
await requireCredentials(context, action, !authCommand);
|
|
34
|
+
rememberExplicitSession(context, action);
|
|
32
35
|
});
|
|
33
36
|
registerAuth(program, context);
|
|
34
37
|
registerSession(program, context);
|
package/dist/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,MAAM,UAAU,aAAa,CAC3B,OAAuB,EACvB,KAGC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;SAC1B,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CACV,iDAAiD,CAClD;SACA,OAAO,CAAC,eAAe,CAAC;SACxB,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC;SACpC,MAAM,CAAC,qBAAqB,EAAE,MAAM,EAAE,OAAO,CAAC;SAC9C,YAAY,EAAE;SACd,eAAe,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAChD,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;QAC/B,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;QACnC,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;QACtC,OAAO,CAAC,oBAAoB,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxD,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;QACpC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC;QAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC;QACzF,MAAM,OAAO,GACX,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,CAAC;YAC5E,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,CAAC;QAC9C,IAAI,OAAO,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO;QAC1C,MAAM,KAAK,CAAC,cAAc,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC;YAAE,MAAM,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,CAAC;QACzG,uBAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtD,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -33,14 +33,15 @@ declare const recordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
33
33
|
sessionId?: string | undefined;
|
|
34
34
|
}>;
|
|
35
35
|
type BindingRecord = z.infer<typeof recordSchema>;
|
|
36
|
-
type BindingValue = Pick<BindingRecord, 'state' | 'sessionId'>;
|
|
37
36
|
export declare class SessionBinding {
|
|
38
37
|
readonly host: HostContext;
|
|
39
38
|
private readonly store;
|
|
39
|
+
private readonly creationStore;
|
|
40
40
|
private readonly key;
|
|
41
41
|
constructor(host: HostContext, endpoint: string, userCode: string, root?: string);
|
|
42
|
-
static connect(service: CreationRuntime, host: HostContext): Promise<SessionBinding>;
|
|
42
|
+
static connect(service: Pick<CreationRuntime, 'client'>, host: HostContext): Promise<SessionBinding>;
|
|
43
43
|
private storage;
|
|
44
|
+
private readRecord;
|
|
44
45
|
read(): Promise<BindingRecord | undefined>;
|
|
45
46
|
current(): Promise<{
|
|
46
47
|
version: 1;
|
|
@@ -68,7 +69,8 @@ export declare class SessionBinding {
|
|
|
68
69
|
state: "UNBOUND" | "BOUND" | "CREATING" | "CREATE_FAILED" | "CREATE_UNKNOWN";
|
|
69
70
|
sessionId?: string | undefined;
|
|
70
71
|
}>;
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
remember(sessionId: string, requestedAt: string): Promise<void>;
|
|
73
|
+
beginCreation(requestedAt?: string): Promise<string>;
|
|
74
|
+
finishCreation(revision: string, state: 'CREATE_FAILED' | 'CREATE_UNKNOWN' | 'UNBOUND'): Promise<boolean>;
|
|
73
75
|
}
|
|
74
76
|
export {};
|
package/dist/session/binding.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** 当前宿主会话唯一的项目绑定;创建回执按修订号提交。@author xiuyu.yi */
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
3
|
import { join } from 'node:path';
|
|
4
|
+
import { stateDirectory } from '../config/state-directory.js';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { InteractionDraftStore, fingerprint } from '../interactions/draft-store.js';
|
|
7
7
|
import { CliError } from '../output/exit-codes.js';
|
|
@@ -19,10 +19,13 @@ const recordSchema = z
|
|
|
19
19
|
export class SessionBinding {
|
|
20
20
|
host;
|
|
21
21
|
store;
|
|
22
|
+
creationStore;
|
|
22
23
|
key;
|
|
23
|
-
constructor(host, endpoint, userCode, root =
|
|
24
|
+
constructor(host, endpoint, userCode, root = stateDirectory('sessions')) {
|
|
24
25
|
this.host = host;
|
|
25
|
-
|
|
26
|
+
const scope = fingerprint([endpoint, userCode]);
|
|
27
|
+
this.store = new InteractionDraftStore(scope, root);
|
|
28
|
+
this.creationStore = new InteractionDraftStore(scope, join(root, 'creation'));
|
|
26
29
|
this.key = `${host.host}:${host.conversationId}`;
|
|
27
30
|
}
|
|
28
31
|
static async connect(service, host) {
|
|
@@ -38,59 +41,102 @@ export class SessionBinding {
|
|
|
38
41
|
return await run();
|
|
39
42
|
}
|
|
40
43
|
catch (error) {
|
|
41
|
-
if (error instanceof CliError
|
|
44
|
+
if (error instanceof CliError)
|
|
42
45
|
throw error;
|
|
43
|
-
throw new CliError(
|
|
46
|
+
throw new CliError('PROTOCOL_ERROR', '当前会话的项目绑定格式无效,请保留状态文件排查;不要重复提交创作请求');
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
|
-
async
|
|
49
|
+
async readRecord(store) {
|
|
47
50
|
return this.storage(async () => {
|
|
48
|
-
const raw = await
|
|
51
|
+
const raw = await store.read(this.key);
|
|
49
52
|
if (raw === undefined)
|
|
50
53
|
return undefined;
|
|
51
54
|
return recordSchema.parse(raw);
|
|
52
55
|
});
|
|
53
56
|
}
|
|
57
|
+
async read() {
|
|
58
|
+
const creation = await this.readRecord(this.creationStore);
|
|
59
|
+
if (creation?.state === 'CREATING' || creation?.state === 'CREATE_UNKNOWN')
|
|
60
|
+
return creation;
|
|
61
|
+
const binding = await this.readRecord(this.store);
|
|
62
|
+
// 创建后的辅助保存尚未完成时,也不能重新暴露之前项目的旧绑定。
|
|
63
|
+
if (creation && (!binding || creation.updatedAt > binding.updatedAt))
|
|
64
|
+
return creation;
|
|
65
|
+
return binding;
|
|
66
|
+
}
|
|
54
67
|
async current() {
|
|
55
68
|
return { host: this.host, ...((await this.read()) ?? { state: 'UNBOUND' }) };
|
|
56
69
|
}
|
|
57
|
-
async save(value) {
|
|
70
|
+
async save(value, updatedAt = new Date().toISOString(), store = this.store) {
|
|
58
71
|
const record = recordSchema.parse({
|
|
59
72
|
version: 1,
|
|
60
73
|
revision: randomUUID(),
|
|
61
|
-
updatedAt
|
|
74
|
+
updatedAt,
|
|
62
75
|
...value,
|
|
63
76
|
});
|
|
64
|
-
await
|
|
77
|
+
await store.write(this.key, record);
|
|
65
78
|
return record;
|
|
66
79
|
}
|
|
67
80
|
async select(service, sessionId) {
|
|
68
|
-
const revision = (await this.
|
|
81
|
+
const revision = (await this.readRecord(this.store))?.revision;
|
|
82
|
+
const creation = await this.readRecord(this.creationStore);
|
|
69
83
|
const result = await service.conversation.recently(sessionId);
|
|
70
84
|
if (result.session.sessionId !== sessionId)
|
|
71
85
|
throw new CliError('PROTOCOL_ERROR', '项目校验返回了不同的 sessionId,未切换绑定');
|
|
72
|
-
|
|
73
|
-
if ((await this.
|
|
86
|
+
const selected = await this.storage(() => this.store.locked(this.key, async () => {
|
|
87
|
+
if ((await this.readRecord(this.store))?.revision !== revision)
|
|
74
88
|
throw new CliError('STALE_INTERACTION', '校验项目期间当前绑定已变化,请重新读取绑定后再操作');
|
|
89
|
+
if ((await this.readRecord(this.creationStore))?.revision !== creation?.revision)
|
|
90
|
+
throw new CliError('STALE_INTERACTION', '校验项目期间创建状态已变化,请先查询原创建结果');
|
|
75
91
|
return this.save({ state: 'BOUND', sessionId });
|
|
76
92
|
}));
|
|
93
|
+
if (creation && ['CREATING', 'CREATE_UNKNOWN'].includes(creation.state)) {
|
|
94
|
+
if (!(await this.finishCreation(creation.revision, 'UNBOUND')))
|
|
95
|
+
throw new CliError('STALE_INTERACTION', '恢复绑定期间创建状态已变化,请先查询原创建结果');
|
|
96
|
+
}
|
|
97
|
+
return selected;
|
|
77
98
|
}
|
|
78
99
|
async clear() {
|
|
79
|
-
return this.storage(() => this.store.locked(this.key, () => this.save({ state: 'UNBOUND' })));
|
|
80
|
-
}
|
|
81
|
-
async beginCreation() {
|
|
82
100
|
return this.storage(() => this.store.locked(this.key, async () => {
|
|
83
101
|
const current = await this.read();
|
|
84
102
|
if (current?.state === 'CREATING' || current?.state === 'CREATE_UNKNOWN')
|
|
85
|
-
throw new CliError('OUTCOME_UNKNOWN', '
|
|
86
|
-
return
|
|
103
|
+
throw new CliError('OUTCOME_UNKNOWN', '创建结果尚未确认,请先查询原请求;确认项目 ID 后可用 session use 恢复绑定');
|
|
104
|
+
return this.save({ state: 'UNBOUND' });
|
|
87
105
|
}));
|
|
88
106
|
}
|
|
89
|
-
async
|
|
107
|
+
async remember(sessionId, requestedAt) {
|
|
90
108
|
await this.storage(() => this.store.locked(this.key, async () => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
109
|
+
const current = await this.readRecord(this.store);
|
|
110
|
+
const creation = await this.readRecord(this.creationStore);
|
|
111
|
+
if (creation && creation.updatedAt > requestedAt)
|
|
112
|
+
return;
|
|
113
|
+
// 后台任务可能乱序完成;旧操作不能覆盖较新的选择、清除或创建状态。
|
|
114
|
+
if (current &&
|
|
115
|
+
(current.updatedAt >= requestedAt ||
|
|
116
|
+
current.state === 'CREATING' ||
|
|
117
|
+
current.state === 'CREATE_UNKNOWN'))
|
|
118
|
+
return;
|
|
119
|
+
await this.save({ state: 'BOUND', sessionId }, requestedAt);
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
async beginCreation(requestedAt = new Date().toISOString()) {
|
|
123
|
+
return this.storage(() => this.creationStore.locked(this.key, async () => {
|
|
124
|
+
const current = await this.readRecord(this.creationStore);
|
|
125
|
+
// 升级前的未决创建可能仍在旧绑定文件中,不能忽略后重新创建。
|
|
126
|
+
const legacy = await this.readRecord(this.store);
|
|
127
|
+
if ([current, legacy].some((record) => record?.state === 'CREATING' || record?.state === 'CREATE_UNKNOWN'))
|
|
128
|
+
throw new CliError('OUTCOME_UNKNOWN', '上次创建尚未确认结果,请先查询原请求;不要重复创建');
|
|
129
|
+
return (await this.save({ state: 'CREATING' }, requestedAt, this.creationStore)).revision;
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
async finishCreation(revision, state) {
|
|
133
|
+
return this.storage(() => this.creationStore.locked(this.key, async () => {
|
|
134
|
+
const current = await this.readRecord(this.creationStore);
|
|
135
|
+
if (current?.revision !== revision)
|
|
136
|
+
return false;
|
|
137
|
+
// 保护记录只保存创建状态,不保存项目 ID;时间保留原请求顺序。
|
|
138
|
+
await this.save({ state }, current.updatedAt, this.creationStore);
|
|
139
|
+
return true;
|
|
94
140
|
}));
|
|
95
141
|
}
|
|
96
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/session/binding.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/session/binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** 单次后台绑定保存;只查询身份与写本地状态,不执行创作或登录。@author xiuyu.yi */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { PatStore } from '../auth/pat-store.js';
|
|
4
|
+
import { runtimeConfig } from '../config/runtime-config.js';
|
|
5
|
+
import { ApiClient } from '../transport/api-client.js';
|
|
6
|
+
import { detectHostContext } from './host-context.js';
|
|
7
|
+
import { SessionBinding } from './binding.js';
|
|
8
|
+
import { ConversationApi } from '../api/conversation-api.js';
|
|
9
|
+
try {
|
|
10
|
+
const request = z
|
|
11
|
+
.object({
|
|
12
|
+
sessionId: z.string().trim().min(1).max(500),
|
|
13
|
+
requestedAt: z.string().datetime(),
|
|
14
|
+
endpoint: z.string(),
|
|
15
|
+
locale: z.string(),
|
|
16
|
+
credentialScope: z.string().regex(/^[a-f0-9]{64}$/),
|
|
17
|
+
creationRevision: z.string().uuid().optional(),
|
|
18
|
+
})
|
|
19
|
+
.strict()
|
|
20
|
+
.parse(JSON.parse(process.argv[2] ?? ''));
|
|
21
|
+
const host = await detectHostContext();
|
|
22
|
+
if (host) {
|
|
23
|
+
const credential = await new PatStore().readIfPresent();
|
|
24
|
+
if (credential) {
|
|
25
|
+
const config = { ...runtimeConfig(request), timeoutMs: 5_000 };
|
|
26
|
+
const client = new ApiClient(config, credential.pat, undefined, AbortSignal.timeout(5_000));
|
|
27
|
+
// 凭据可能在主命令结束后变更;不能把旧操作写入另一个账号的绑定。
|
|
28
|
+
if (client.interactionScope === request.credentialScope) {
|
|
29
|
+
const binding = await SessionBinding.connect({ client }, host);
|
|
30
|
+
const project = await new ConversationApi(client).recently(request.sessionId);
|
|
31
|
+
if (project.session.sessionId === request.sessionId) {
|
|
32
|
+
const resolved = !request.creationRevision || (await binding.finishCreation(request.creationRevision, 'UNBOUND'));
|
|
33
|
+
if (resolved)
|
|
34
|
+
await binding.remember(request.sessionId, request.requestedAt);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// 保存失败静默结束,不重新派发、不输出提示、不提交任何业务请求。
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=remember-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remember-worker.js","sourceRoot":"","sources":["../../src/session/remember-worker.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,IAAI,CAAC;IACH,MAAM,OAAO,GAAG,CAAC;SACd,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAClC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;QACnD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;KAC/C,CAAC;SACD,MAAM,EAAE;SACR,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACvC,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,UAAU,GAAG,MAAM,IAAI,QAAQ,EAAE,CAAC,aAAa,EAAE,CAAC;QACxD,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;YAC/D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5F,kCAAkC;YAClC,IAAI,MAAM,CAAC,gBAAgB,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC;gBACxD,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;gBAC/D,MAAM,OAAO,GAAG,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAC9E,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;oBACpD,MAAM,QAAQ,GACZ,CAAC,OAAO,CAAC,gBAAgB,IAAI,CAAC,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC;oBACnG,IAAI,QAAQ;wBAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;gBAC/E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAAC,MAAM,CAAC;IACP,kCAAkC;AACpC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** 后台保存辅助项目绑定,不占用业务命令的生命周期。@author xiuyu.yi */
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
export function scheduleRemember(request) {
|
|
5
|
+
try {
|
|
6
|
+
const child = spawn(process.execPath, [fileURLToPath(new URL('./remember-worker.js', import.meta.url)), JSON.stringify(request)], { detached: true, stdio: 'ignore', windowsHide: true });
|
|
7
|
+
child.once('error', () => undefined);
|
|
8
|
+
child.unref();
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
// 宿主不允许后台进程时放弃辅助保存,不改变业务结果,也不绕过权限。
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=remember.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remember.js","sourceRoot":"","sources":["../../src/session/remember.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAWzC,MAAM,UAAU,gBAAgB,CAAC,OAAwB;IACvD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CACjB,OAAO,CAAC,QAAQ,EAChB,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAC1F,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CACvD,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACrC,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;AACH,CAAC"}
|