superun-ai-cli 0.1.33 → 0.1.35
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/chat/publish.js +3 -2
- package/dist/commands/chat/publish.js.map +1 -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 +14 -0
- package/dist/config/state-directory.js.map +1 -0
- package/dist/conversation/agent-friendly.js +3 -2
- package/dist/conversation/agent-friendly.js.map +1 -1
- package/dist/conversation/next-actions.js +2 -0
- package/dist/conversation/next-actions.js.map +1 -1
- package/dist/conversation/user-choice-guidance.d.ts +2 -0
- package/dist/conversation/user-choice-guidance.js +3 -0
- package/dist/conversation/user-choice-guidance.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 +14 -61
- package/dist/session/binding.js +65 -60
- package/dist/session/binding.js.map +1 -1
- package/dist/session/project-bindings.d.ts +8 -0
- package/dist/session/project-bindings.js +57 -0
- package/dist/session/project-bindings.js.map +1 -0
- package/dist/session/remember-worker.d.ts +1 -0
- package/dist/session/remember-worker.js +46 -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/dist/session/binding.js
CHANGED
|
@@ -1,97 +1,102 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** 辅助项目映射与无项目 ID 时的创建保护彼此独立。@author xiuyu.yi */
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import { z } from 'zod';
|
|
5
|
+
import { stateDirectory } from '../config/state-directory.js';
|
|
6
6
|
import { InteractionDraftStore, fingerprint } from '../interactions/draft-store.js';
|
|
7
7
|
import { CliError } from '../output/exit-codes.js';
|
|
8
8
|
import { object, text } from '../contracts/value.js';
|
|
9
|
-
|
|
9
|
+
import { ProjectBindings } from './project-bindings.js';
|
|
10
|
+
const creationSchema = z
|
|
10
11
|
.object({
|
|
11
|
-
version: z.literal(1),
|
|
12
12
|
revision: z.string().uuid(),
|
|
13
|
-
|
|
14
|
-
state: z.enum(['
|
|
15
|
-
sessionId: z.string().trim().min(1).optional(),
|
|
13
|
+
requestedAt: z.string().datetime(),
|
|
14
|
+
state: z.enum(['CREATING', 'CREATE_UNKNOWN', 'CREATE_FAILED', 'RESOLVED']),
|
|
16
15
|
})
|
|
17
|
-
.strict()
|
|
18
|
-
.refine((record) => (record.state === 'BOUND') === !!record.sessionId);
|
|
16
|
+
.strict();
|
|
19
17
|
export class SessionBinding {
|
|
20
18
|
host;
|
|
21
|
-
|
|
19
|
+
creationStore;
|
|
20
|
+
bindings;
|
|
22
21
|
key;
|
|
23
|
-
constructor(host, endpoint, userCode, root =
|
|
22
|
+
constructor(host, endpoint, userCode, root = stateDirectory()) {
|
|
24
23
|
this.host = host;
|
|
25
|
-
|
|
24
|
+
const scope = fingerprint([endpoint, userCode]);
|
|
25
|
+
this.bindings = new ProjectBindings(join(root, 'sessions.json'), scope);
|
|
26
|
+
this.creationStore = new InteractionDraftStore(scope, join(root, 'creation'));
|
|
26
27
|
this.key = `${host.host}:${host.conversationId}`;
|
|
27
28
|
}
|
|
28
29
|
static async connect(service, host) {
|
|
29
|
-
// 使用登录用户的稳定身份;不保存 PAT,同账号更换 PAT 后仍可恢复。
|
|
30
30
|
const account = object(await service.client.call('/api/uxa-center/support/UserAccount/queryAccount', { product: 13 }));
|
|
31
31
|
const userCode = text(account.userCode);
|
|
32
32
|
if (!userCode)
|
|
33
33
|
throw new CliError('PROTOCOL_ERROR', '无法确认当前登录身份,未读取或修改项目绑定');
|
|
34
34
|
return new SessionBinding(host, service.client.config.endpoint, userCode);
|
|
35
35
|
}
|
|
36
|
-
async
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
async read() {
|
|
47
|
-
return this.storage(async () => {
|
|
48
|
-
const raw = await this.store.read(this.key);
|
|
49
|
-
if (raw === undefined)
|
|
50
|
-
return undefined;
|
|
51
|
-
return recordSchema.parse(raw);
|
|
52
|
-
});
|
|
36
|
+
async creation() {
|
|
37
|
+
const raw = await this.creationStore.read(this.key);
|
|
38
|
+
if (raw === undefined)
|
|
39
|
+
return;
|
|
40
|
+
const record = creationSchema.safeParse(raw);
|
|
41
|
+
if (!record.success)
|
|
42
|
+
throw new CliError('LOCAL_STATE_RECOVERY_REQUIRED', '创建保护记录无法读取,请先确认原创建结果');
|
|
43
|
+
return record.data;
|
|
53
44
|
}
|
|
54
45
|
async current() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
...
|
|
63
|
-
}
|
|
64
|
-
await this.store.write(this.key, record);
|
|
65
|
-
return record;
|
|
46
|
+
const creation = await this.creation();
|
|
47
|
+
if (creation?.state === 'CREATING' || creation?.state === 'CREATE_UNKNOWN')
|
|
48
|
+
return { host: this.host, ...creation };
|
|
49
|
+
const sessionId = await this.bindings.read(this.key);
|
|
50
|
+
return {
|
|
51
|
+
host: this.host,
|
|
52
|
+
state: sessionId ? 'BOUND' : 'UNBOUND',
|
|
53
|
+
...(sessionId ? { sessionId } : {}),
|
|
54
|
+
};
|
|
66
55
|
}
|
|
67
56
|
async select(service, sessionId) {
|
|
68
|
-
const
|
|
57
|
+
const creation = await this.creation();
|
|
69
58
|
const result = await service.conversation.recently(sessionId);
|
|
70
59
|
if (result.session.sessionId !== sessionId)
|
|
71
|
-
throw new CliError('PROTOCOL_ERROR', '项目校验返回了不同的 sessionId
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
60
|
+
throw new CliError('PROTOCOL_ERROR', '项目校验返回了不同的 sessionId');
|
|
61
|
+
await this.bindings.write(this.key, sessionId);
|
|
62
|
+
if (creation && ['CREATING', 'CREATE_UNKNOWN'].includes(creation.state)) {
|
|
63
|
+
if (!(await this.finishCreation(creation.revision, 'RESOLVED')))
|
|
64
|
+
throw new CliError('STALE_INTERACTION', '创建状态已变化,请先查询原创建结果');
|
|
65
|
+
}
|
|
77
66
|
}
|
|
78
67
|
async clear() {
|
|
79
|
-
|
|
68
|
+
const creation = await this.creation();
|
|
69
|
+
if (creation?.state === 'CREATING' || creation?.state === 'CREATE_UNKNOWN')
|
|
70
|
+
throw new CliError('OUTCOME_UNKNOWN', '创建结果尚未确认,请先核对原请求;确认项目 ID 后可用 session use 恢复');
|
|
71
|
+
await this.bindings.write(this.key);
|
|
72
|
+
}
|
|
73
|
+
async remember(sessionId, requestedAt) {
|
|
74
|
+
const creation = await this.creation();
|
|
75
|
+
if (creation && creation.requestedAt > requestedAt)
|
|
76
|
+
return;
|
|
77
|
+
await this.bindings.write(this.key, sessionId);
|
|
80
78
|
}
|
|
81
|
-
async beginCreation() {
|
|
82
|
-
return this.
|
|
83
|
-
const current = await this.
|
|
79
|
+
async beginCreation(requestedAt = new Date().toISOString()) {
|
|
80
|
+
return this.creationStore.locked(this.key, async () => {
|
|
81
|
+
const current = await this.creation();
|
|
84
82
|
if (current?.state === 'CREATING' || current?.state === 'CREATE_UNKNOWN')
|
|
85
83
|
throw new CliError('OUTCOME_UNKNOWN', '上次创建尚未确认结果,请先查询原请求;不要重复创建');
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
const revision = randomUUID();
|
|
85
|
+
await this.creationStore.write(this.key, { revision, requestedAt, state: 'CREATING' });
|
|
86
|
+
return revision;
|
|
87
|
+
});
|
|
88
88
|
}
|
|
89
|
-
async
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
async matchesCreation(revision) {
|
|
90
|
+
return (await this.creation())?.revision === revision;
|
|
91
|
+
}
|
|
92
|
+
async finishCreation(revision, state) {
|
|
93
|
+
return this.creationStore.locked(this.key, async () => {
|
|
94
|
+
const current = await this.creation();
|
|
95
|
+
if (current?.revision !== revision)
|
|
96
|
+
return false;
|
|
97
|
+
await this.creationStore.write(this.key, { ...current, revision: randomUUID(), state });
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
//# sourceMappingURL=binding.js.map
|
|
@@ -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,57 @@
|
|
|
1
|
+
/** 通用辅助会话映射:单文件直接写入,不加锁、不改名、不删除。@author xiuyu.yi */
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import { object } from '../contracts/value.js';
|
|
5
|
+
import { filesystemCode, stateOperation } from '../interactions/state-storage.js';
|
|
6
|
+
export class ProjectBindings {
|
|
7
|
+
path;
|
|
8
|
+
scope;
|
|
9
|
+
constructor(path, scope) {
|
|
10
|
+
this.path = path;
|
|
11
|
+
this.scope = scope;
|
|
12
|
+
}
|
|
13
|
+
async load() {
|
|
14
|
+
const content = await stateOperation('read', this.path, async () => {
|
|
15
|
+
try {
|
|
16
|
+
return await readFile(this.path, 'utf8');
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (filesystemCode(error) === 'ENOENT')
|
|
20
|
+
return '';
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
// 这是辅助缓存。直接覆盖过程中的不完整内容不阻断显式项目操作。
|
|
25
|
+
try {
|
|
26
|
+
const value = object(JSON.parse(content));
|
|
27
|
+
const bindings = Object.create(null);
|
|
28
|
+
for (const [scope, entries] of Object.entries(value)) {
|
|
29
|
+
bindings[scope] = Object.create(null);
|
|
30
|
+
for (const [key, sessionId] of Object.entries(object(entries))) {
|
|
31
|
+
if (typeof sessionId === 'string' && sessionId.trim())
|
|
32
|
+
bindings[scope][key] = sessionId;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return bindings;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async read(key) {
|
|
42
|
+
return (await this.load())[this.scope]?.[key];
|
|
43
|
+
}
|
|
44
|
+
async write(key, sessionId) {
|
|
45
|
+
const bindings = await this.load();
|
|
46
|
+
const entries = bindings[this.scope] ?? (bindings[this.scope] = Object.create(null));
|
|
47
|
+
if (entries[key] === sessionId)
|
|
48
|
+
return;
|
|
49
|
+
if (sessionId)
|
|
50
|
+
entries[key] = sessionId;
|
|
51
|
+
else
|
|
52
|
+
delete entries[key];
|
|
53
|
+
await stateOperation('mkdir', dirname(this.path), () => mkdir(dirname(this.path), { recursive: true, mode: 0o700 }));
|
|
54
|
+
await stateOperation('write', this.path, () => writeFile(this.path, JSON.stringify(bindings, null, 2) + '\n', { mode: 0o600 }));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=project-bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-bindings.js","sourceRoot":"","sources":["../../src/session/project-bindings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
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 current = !request.creationRevision || (await binding.matchesCreation(request.creationRevision));
|
|
33
|
+
if (current) {
|
|
34
|
+
await binding.remember(request.sessionId, request.requestedAt);
|
|
35
|
+
if (request.creationRevision)
|
|
36
|
+
await binding.finishCreation(request.creationRevision, 'RESOLVED');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// 保存失败静默结束,不重新派发、不输出提示、不提交任何业务请求。
|
|
45
|
+
}
|
|
46
|
+
//# 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,OAAO,GACX,CAAC,OAAO,CAAC,gBAAgB,IAAI,CAAC,MAAM,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;oBACzF,IAAI,OAAO,EAAE,CAAC;wBACZ,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;wBAC/D,IAAI,OAAO,CAAC,gBAAgB;4BAAE,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;oBACnG,CAAC;gBACH,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"}
|