@dsh-workbench/adapter-profile 1.0.0-beta.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config-sync.d.ts +2 -3
- package/dist/config-sync.js +30 -68
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/profile-create.js +1 -23
- package/package.json +3 -3
package/dist/config-sync.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PostResource, RouteHandler } from '@dsh-workbench/shared/host';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ConfigSyncRow, ConfigSyncSnapshot } from '@dsh-workbench/shared/contract/protocol/config-sync';
|
|
3
3
|
export interface PatchBlock {
|
|
4
4
|
readonly key: string;
|
|
5
5
|
readonly id: string;
|
|
@@ -9,7 +9,7 @@ export interface PatchBlock {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function patchBlocks(text: string): PatchBlock[];
|
|
11
11
|
export declare function normalizeBlock(body: string): string;
|
|
12
|
-
export declare function syncRows(source: readonly PatchBlock[], own: readonly PatchBlock[], missing: (block: PatchBlock) => readonly string[]
|
|
12
|
+
export declare function syncRows(source: readonly PatchBlock[], own: readonly PatchBlock[], missing: (block: PatchBlock) => readonly string[]): ConfigSyncRow[];
|
|
13
13
|
export declare function mergeBlocks(ownText: string, incoming: readonly PatchBlock[], overwrite: ReadonlySet<string>): {
|
|
14
14
|
ok: true;
|
|
15
15
|
text: string;
|
|
@@ -40,7 +40,6 @@ export declare function configSyncApply(deps: ConfigSyncDeps, payload: unknown):
|
|
|
40
40
|
ok: true;
|
|
41
41
|
written: string[];
|
|
42
42
|
skipped: string[];
|
|
43
|
-
files: string[];
|
|
44
43
|
verified: boolean;
|
|
45
44
|
} | {
|
|
46
45
|
ok: false;
|
package/dist/config-sync.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { CONFIG_SYNC_RESOURCE } from '@dsh-workbench/shared/contract/protocol/config-sync';
|
|
4
|
-
import { assetMapOf, assetsOf, cleanupFiles, copyPlans, planCopies } from './config-sync-assets.js';
|
|
5
4
|
const ID_LINE = /^- id:[ \t]*"?([^"\s#]+)/;
|
|
6
5
|
const INSERT_LINE = /^- insert:[ \t]*$/;
|
|
7
6
|
const NESTED_ID = /^[ \t]+-[ \t]*id:[ \t]*"?([^"\s#]+)/;
|
|
@@ -73,24 +72,25 @@ function rewriteForTarget(body, self) {
|
|
|
73
72
|
return body;
|
|
74
73
|
return body.replace(/(dshHomePath\(\s*['"])workbench(?=[/'"])/g, `$1${self}`);
|
|
75
74
|
}
|
|
76
|
-
|
|
75
|
+
function syncable(block) {
|
|
76
|
+
return !block.insert && !ISOLATION_IDS.has(block.id);
|
|
77
|
+
}
|
|
78
|
+
export function syncRows(source, own, missing) {
|
|
77
79
|
const mine = new Map(own.map((block) => [block.key, block]));
|
|
78
80
|
const rows = [];
|
|
79
81
|
for (const block of source) {
|
|
82
|
+
if (!syncable(block))
|
|
83
|
+
continue;
|
|
80
84
|
const here = mine.get(block.key);
|
|
81
|
-
|
|
82
|
-
const found = assets(block);
|
|
83
|
-
if (same && found.every((asset) => asset.state === 'same'))
|
|
85
|
+
if (here !== undefined && normalizeBlock(here.body) === normalizeBlock(block.body))
|
|
84
86
|
continue;
|
|
85
87
|
rows.push({
|
|
86
88
|
key: block.key,
|
|
87
89
|
id: block.id,
|
|
88
|
-
|
|
89
|
-
state: here === undefined ? 'new' : same ? 'same' : 'differs',
|
|
90
|
+
state: here === undefined ? 'new' : 'differs',
|
|
90
91
|
body: block.body,
|
|
91
92
|
ownBody: here === undefined ? null : here.body,
|
|
92
93
|
missing: missing(block),
|
|
93
|
-
assets: found,
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
96
|
return rows;
|
|
@@ -211,23 +211,29 @@ export function configSyncSnapshot(deps, asked) {
|
|
|
211
211
|
home: deps.home,
|
|
212
212
|
};
|
|
213
213
|
if (deps.profileDir === null) {
|
|
214
|
-
return {
|
|
214
|
+
return {
|
|
215
|
+
...base,
|
|
216
|
+
source: '',
|
|
217
|
+
profiles: [],
|
|
218
|
+
rows: [],
|
|
219
|
+
emptyProviders: false,
|
|
220
|
+
reason: '拿不到当前 profile 目录',
|
|
221
|
+
};
|
|
215
222
|
}
|
|
216
223
|
const own = readPatchBlocks(join(deps.profileDir, 'cordis.patch.yml'));
|
|
217
224
|
const emptyProviders = own.ok && !own.blocks.some((block) => block.key.startsWith('id:llm-'));
|
|
218
225
|
const ownBlocks = own.ok ? own.blocks : [];
|
|
219
226
|
const profiles = others.map((name) => {
|
|
220
227
|
const read = readPatchBlocks(join(profilesDir, name, 'cordis.patch.yml'));
|
|
221
|
-
const assetsFor = (block) => assetsOf(block, join(profilesDir, name), deps.profileDir ?? '');
|
|
222
228
|
const blocks = read.ok
|
|
223
229
|
? read.blocks
|
|
224
|
-
.filter(
|
|
230
|
+
.filter(syncable)
|
|
225
231
|
.map((block) => ({ ...block, body: rewriteForTarget(block.body, deps.self) }))
|
|
226
232
|
: [];
|
|
227
233
|
return {
|
|
228
234
|
name,
|
|
229
235
|
readable: read.ok,
|
|
230
|
-
candidates: read.ok ? syncRows(blocks, ownBlocks, () => []
|
|
236
|
+
candidates: read.ok ? syncRows(blocks, ownBlocks, () => []).length : 0,
|
|
231
237
|
};
|
|
232
238
|
});
|
|
233
239
|
if (others.length === 0) {
|
|
@@ -251,11 +257,10 @@ export function configSyncSnapshot(deps, asked) {
|
|
|
251
257
|
}
|
|
252
258
|
const declared = profileDependencies(sourceDir);
|
|
253
259
|
const modulesDir = join(deps.profileDir, 'node_modules');
|
|
254
|
-
const assetsFor = (block) => assetsOf(block, sourceDir, deps.profileDir ?? '');
|
|
255
260
|
const sourceBlocks = read.blocks
|
|
256
|
-
.filter(
|
|
261
|
+
.filter(syncable)
|
|
257
262
|
.map((block) => ({ ...block, body: rewriteForTarget(block.body, deps.self) }));
|
|
258
|
-
const rows = syncRows(sourceBlocks, own.blocks, (block) => block.names.filter((name) => declared.has(name) && !existsSync(join(modulesDir, name)))
|
|
263
|
+
const rows = syncRows(sourceBlocks, own.blocks, (block) => block.names.filter((name) => declared.has(name) && !existsSync(join(modulesDir, name))));
|
|
259
264
|
return { ...base, source, profiles, rows, emptyProviders };
|
|
260
265
|
}
|
|
261
266
|
export async function configSyncApply(deps, payload) {
|
|
@@ -265,10 +270,8 @@ export async function configSyncApply(deps, payload) {
|
|
|
265
270
|
const source = textOf(body['source']);
|
|
266
271
|
const keys = new Set((Array.isArray(body['keys']) ? body['keys'] : []).map((item) => textOf(item)).filter((item) => item !== ''));
|
|
267
272
|
const overwrite = new Set((Array.isArray(body['overwrite']) ? body['overwrite'] : []).map((item) => textOf(item)));
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (source === '' || (keys.size === 0 && assetKeys.size === 0)) {
|
|
271
|
-
return { ok: false, text: '没说清从哪个 profile 搬哪几行' };
|
|
273
|
+
if (source === '' || keys.size === 0) {
|
|
274
|
+
return { ok: false, text: '没说清从哪个 profile 同步哪几行' };
|
|
272
275
|
}
|
|
273
276
|
const profilesDir = join(deps.home, 'profiles');
|
|
274
277
|
if (!profileNames(profilesDir).includes(source))
|
|
@@ -282,65 +285,34 @@ export async function configSyncApply(deps, payload) {
|
|
|
282
285
|
const own = readPatchBlocks(join(deps.profileDir, 'cordis.patch.yml'));
|
|
283
286
|
if (!own.ok)
|
|
284
287
|
return { ok: false, text: `读不到工作台自己的配置:${own.reason}` };
|
|
288
|
+
if (read.blocks.some((block) => block.insert && keys.has(block.key))) {
|
|
289
|
+
return { ok: false, text: '插件行不同步:先把插件装到工作台这边,再同步它的设置' };
|
|
290
|
+
}
|
|
285
291
|
const picked = read.blocks
|
|
286
|
-
.filter((block) => keys.has(block.key) &&
|
|
292
|
+
.filter((block) => keys.has(block.key) && syncable(block))
|
|
287
293
|
.map((block) => ({ ...block, body: rewriteForTarget(block.body, deps.self) }));
|
|
288
|
-
if (
|
|
294
|
+
if (picked.length === 0) {
|
|
289
295
|
return { ok: false, text: '选中的行在来源里已经找不到了,重新读一遍再试' };
|
|
290
296
|
}
|
|
291
|
-
const available = assetMapOf(read.blocks, sourceDir, deps.profileDir);
|
|
292
|
-
const pickedAssets = [];
|
|
293
|
-
for (const key of assetKeys) {
|
|
294
|
-
const asset = available.get(key);
|
|
295
|
-
if (asset === undefined)
|
|
296
|
-
return { ok: false, text: '选中的文件在来源里已经找不到了,重新读一遍再试' };
|
|
297
|
-
pickedAssets.push(asset);
|
|
298
|
-
}
|
|
299
297
|
const merged = mergeBlocks(own.text, picked, overwrite);
|
|
300
298
|
if (!merged.ok)
|
|
301
299
|
return { ok: false, text: merged.reason };
|
|
302
|
-
const planned = planCopies(pickedAssets, sourceDir, deps.profileDir, overwriteAssets);
|
|
303
|
-
if (!planned.ok)
|
|
304
|
-
return { ok: false, text: planned.text };
|
|
305
300
|
const patchPath = join(deps.profileDir, 'cordis.patch.yml');
|
|
306
|
-
let copied = null;
|
|
307
|
-
if (planned.plans.length > 0) {
|
|
308
|
-
const outcome = copyPlans(planned.plans);
|
|
309
|
-
if (!outcome.ok) {
|
|
310
|
-
cleanupFiles(outcome.created, outcome.backups);
|
|
311
|
-
return { ok: false, text: outcome.text };
|
|
312
|
-
}
|
|
313
|
-
copied = { files: outcome.files, created: outcome.created, backups: outcome.backups };
|
|
314
|
-
}
|
|
315
301
|
const patchChanged = merged.text !== own.text;
|
|
316
302
|
try {
|
|
317
303
|
if (patchChanged)
|
|
318
304
|
writePatchFile(patchPath, merged.text);
|
|
319
305
|
}
|
|
320
306
|
catch (error) {
|
|
321
|
-
if (copied !== null)
|
|
322
|
-
cleanupFiles(copied.created, copied.backups);
|
|
323
307
|
return { ok: false, text: `写不进去:${error instanceof Error ? error.message : String(error)}` };
|
|
324
308
|
}
|
|
325
309
|
if (deps.reconcile === undefined) {
|
|
326
|
-
return {
|
|
327
|
-
ok: true,
|
|
328
|
-
written: merged.written,
|
|
329
|
-
skipped: merged.skipped,
|
|
330
|
-
files: copied?.files ?? [],
|
|
331
|
-
verified: false,
|
|
332
|
-
};
|
|
310
|
+
return { ok: true, written: merged.written, skipped: merged.skipped, verified: false };
|
|
333
311
|
}
|
|
334
312
|
try {
|
|
335
313
|
const verified = await deps.reconcile();
|
|
336
314
|
if (verified === false) {
|
|
337
|
-
return {
|
|
338
|
-
ok: true,
|
|
339
|
-
written: merged.written,
|
|
340
|
-
skipped: merged.skipped,
|
|
341
|
-
files: copied?.files ?? [],
|
|
342
|
-
verified: false,
|
|
343
|
-
};
|
|
315
|
+
return { ok: true, written: merged.written, skipped: merged.skipped, verified: false };
|
|
344
316
|
}
|
|
345
317
|
}
|
|
346
318
|
catch (error) {
|
|
@@ -349,13 +321,9 @@ export async function configSyncApply(deps, payload) {
|
|
|
349
321
|
writePatchFile(patchPath, own.text);
|
|
350
322
|
}
|
|
351
323
|
catch {
|
|
352
|
-
if (copied !== null)
|
|
353
|
-
cleanupFiles(copied.created, copied.backups);
|
|
354
324
|
return { ok: false, text: `写进去了,但启动检查没通过:${error instanceof Error ? error.message : String(error)}。原来的设置没能恢复,手动检查一下` };
|
|
355
325
|
}
|
|
356
326
|
}
|
|
357
|
-
if (copied !== null)
|
|
358
|
-
cleanupFiles(copied.created, copied.backups);
|
|
359
327
|
try {
|
|
360
328
|
await deps.reconcile();
|
|
361
329
|
}
|
|
@@ -364,13 +332,7 @@ export async function configSyncApply(deps, payload) {
|
|
|
364
332
|
}
|
|
365
333
|
return { ok: false, text: `写进去了,但启动检查没通过:${error instanceof Error ? error.message : String(error)}。已恢复原来的设置` };
|
|
366
334
|
}
|
|
367
|
-
return {
|
|
368
|
-
ok: true,
|
|
369
|
-
written: merged.written,
|
|
370
|
-
skipped: merged.skipped,
|
|
371
|
-
files: copied?.files ?? [],
|
|
372
|
-
verified: true,
|
|
373
|
-
};
|
|
335
|
+
return { ok: true, written: merged.written, skipped: merged.skipped, verified: true };
|
|
374
336
|
}
|
|
375
337
|
export function configSyncAction(deps) {
|
|
376
338
|
return {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/profile-create.js
CHANGED
|
@@ -70,9 +70,6 @@ export async function profileCreateApply(deps, payload) {
|
|
|
70
70
|
const copy = typeof body['copy'] === 'object' && body['copy'] !== null ? body['copy'] : {};
|
|
71
71
|
const flags = {
|
|
72
72
|
settings: copy['settings'] === true,
|
|
73
|
-
plugins: copy['plugins'] === true,
|
|
74
|
-
projects: copy['projects'] === true,
|
|
75
|
-
sessions: copy['sessions'] === true,
|
|
76
73
|
};
|
|
77
74
|
if (!PROFILE_NAME.test(profile))
|
|
78
75
|
return { ok: false, text: '新工作台的名字不合法:只用字母、数字、点、下划线或短横线' };
|
|
@@ -87,33 +84,14 @@ export async function profileCreateApply(deps, payload) {
|
|
|
87
84
|
return { ok: false, text: `已经有一个叫 ${profile} 的 profile` };
|
|
88
85
|
const targetHome = join(deps.home, profile);
|
|
89
86
|
if (existsSync(targetHome))
|
|
90
|
-
return { ok: false, text:
|
|
91
|
-
const sourceCandidate = join(deps.home, source);
|
|
92
|
-
const sourcePatch = (() => {
|
|
93
|
-
try {
|
|
94
|
-
return readFileSync(join(profilesDir, source, 'cordis.patch.yml'), 'utf8');
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
return '';
|
|
98
|
-
}
|
|
99
|
-
})();
|
|
100
|
-
const sourceHasIsolation = /id:\s*session-persistence-jsonl/.test(sourcePatch);
|
|
101
|
-
const sourceHome = !sourceHasIsolation
|
|
102
|
-
? deps.home
|
|
103
|
-
: sourcePatch.includes('DSH_WORKBENCH_HOME') && source !== 'workbench'
|
|
104
|
-
? sourceCandidate
|
|
105
|
-
: join(deps.home, 'workbench');
|
|
87
|
+
return { ok: false, text: `运行时目录已经存在:${targetHome}` };
|
|
106
88
|
const env = {
|
|
107
89
|
DSH_HOME: deps.home,
|
|
108
90
|
DSH_WORKBENCH_HOME: targetHome,
|
|
109
91
|
WORKBENCH_PROFILE: profile,
|
|
110
92
|
WORKBENCH_SOURCE_PROFILE: source,
|
|
111
93
|
WB_CLONE: '1',
|
|
112
|
-
WB_SOURCE_HOME: sourceHome,
|
|
113
94
|
WB_COPY_SETTINGS: flags.settings ? '1' : '0',
|
|
114
|
-
WB_COPY_PLUGINS: flags.plugins ? '1' : '0',
|
|
115
|
-
WB_COPY_PROJECTS: flags.projects ? '1' : '0',
|
|
116
|
-
WB_COPY_SESSIONS: flags.sessions ? '1' : '0',
|
|
117
95
|
};
|
|
118
96
|
const setup = deps.runSetup ?? ((next) => defaultRunSetup(deps.packageRoot, next));
|
|
119
97
|
const cleanup = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/adapter-profile",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Workbench profile adapter package.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"execa": "^10.2.0",
|
|
33
33
|
"proper-lockfile": "^4.1.2",
|
|
34
34
|
"write-file-atomic": "^8.0.0",
|
|
35
|
-
"@dsh-workbench/adapter-runtime": "1.0.0
|
|
36
|
-
"@dsh-workbench/shared": "1.0.0
|
|
35
|
+
"@dsh-workbench/adapter-runtime": "1.0.0",
|
|
36
|
+
"@dsh-workbench/shared": "1.0.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsc -p tsconfig.json",
|