@khorsheed/dsh-file-preview 0.1.1 → 0.2.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/CHANGELOG.md +8 -0
- package/README.en.md +15 -11
- package/README.i18n.yaml +2 -2
- package/README.md +31 -27
- package/lib/index.js +99 -46
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typert.host.js +124 -44
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +4 -4
- package/lib/types/bash-writes.js +1 -1
- package/lib/types/fold.d.ts +8 -6
- package/lib/types/fold.d.ts.map +1 -1
- package/lib/types/fold.js +41 -18
- package/lib/types/index.d.ts +26 -8
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +81 -25
- package/package.json +14 -13
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,wBAAwB,CAAA;AAGlE,OAAO,EAAU,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAC9E,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAIxC,OAAO,KAAK,EAAE,iBAAiB,EAAoB,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAuB,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEnK,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,WAAW,EAAE,kBAAkB,CAAA;KAChC;CACF;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,wBAAwB,CAAA;AAGlE,OAAO,EAAU,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAC9E,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAIxC,OAAO,KAAK,EAAE,iBAAiB,EAAoB,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAuB,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEnK,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,WAAW,EAAE,kBAAkB,CAAA;KAChC;CACF;AAiJD;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,SAAQ,mBAAmB;IACzD,MAAM,CAAC,MAAM,WAAS;IAEtB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,iBAAiB,CAAC,CAKjC;IAEF,gDAAgD;IAChD,MAAM,CAAC,QAAQ,CAAC,WAAW,yBAAwB;IAEnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD;iFAC6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsD;IACnF,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkE;IAE5F;;;;;;OAMG;IACH,YACE,GAAG,EAAE,OAAO,EACZ,MAAM,GAAE,iBAAsB,EAC9B,IAAI,GAAE;QAAE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAO,EAoCnF;IAED,OAAO,KAAK,EAAE,GAEb;IAED;;;;;;OAMG;YACW,UAAU;IAmExB;;;;;;;;;;OAUG;YACW,cAAc;IAiB5B;;;;;;;;OAQG;IAEG,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,eAAe,CAAC,CAmBjD;IAED;;;;;;;;;;;;;;OAcG;IAEG,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyCzD;IAED;;;;;;;;OAQG;IAEG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CA6DpF;IAED;;;;;;;;;;;;OAYG;IAEG,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgCxF;CACF;eAEc,kBAAkB"}
|
package/lib/types/index.js
CHANGED
|
@@ -67,7 +67,8 @@ function registerArtifactSkill(ctx) {
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
try {
|
|
70
|
-
const
|
|
70
|
+
const skillDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'skills', '3d-artifact');
|
|
71
|
+
const skillFile = join(skillDir, 'SKILL.md');
|
|
71
72
|
const raw = readFileSync(skillFile, 'utf8');
|
|
72
73
|
const match = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(raw);
|
|
73
74
|
const name = /^name: (.+)$/m.exec(match?.[1] ?? '')?.[1]?.trim();
|
|
@@ -77,7 +78,16 @@ function registerArtifactSkill(ctx) {
|
|
|
77
78
|
ctx.logger.warn('file-preview: shipped SKILL.md is malformed — the 3d-artifact skill is not registered');
|
|
78
79
|
return;
|
|
79
80
|
}
|
|
80
|
-
ctx.effect(() => skills.register({
|
|
81
|
+
ctx.effect(() => skills.register({
|
|
82
|
+
name,
|
|
83
|
+
description,
|
|
84
|
+
content,
|
|
85
|
+
source: 'runtime',
|
|
86
|
+
provider: 'file-preview',
|
|
87
|
+
// Content-only (only SKILL.md in the bundle): no `resourceBase`, so the
|
|
88
|
+
// catalog renders a virtual single-SKILL.md node. Add `resourceBase`
|
|
89
|
+
// only when the bundle later gains scripts/assets beside SKILL.md.
|
|
90
|
+
}));
|
|
81
91
|
}
|
|
82
92
|
catch (error) {
|
|
83
93
|
ctx.logger.warn(`file-preview: shipped SKILL.md unreadable (${String(error)}) — the 3d-artifact skill is not registered`);
|
|
@@ -145,8 +155,9 @@ function readErrorMessage(error) {
|
|
|
145
155
|
}
|
|
146
156
|
/**
|
|
147
157
|
* The `filePreview` Remote service: session-scoped read-only file inspection
|
|
148
|
-
* for web surfaces. `list` is a
|
|
149
|
-
*
|
|
158
|
+
* for web surfaces. `list` is a fold over the session log, then filtered to the
|
|
159
|
+
* paths that still exist on disk (resolved against the session cwd and stat-ed
|
|
160
|
+
* per call); `read` resolves the path against the session cwd and serves current
|
|
150
161
|
* text content through `ctx.fs` (or a browser URL for images), capped by
|
|
151
162
|
* config. Image bytes ride a dedicated host route so the browser loads them
|
|
152
163
|
* natively without bloating the RPC channel.
|
|
@@ -310,31 +321,65 @@ let FilePreviewService = (() => {
|
|
|
310
321
|
});
|
|
311
322
|
res.end(Buffer.from(bytes));
|
|
312
323
|
}
|
|
324
|
+
/** Resolve the session's recorded display paths against its cwd and keep only
|
|
325
|
+
* those that currently exist as a regular file. The products surfaces fold
|
|
326
|
+
* the session log (which is history, not disk state): a path the log wrote
|
|
327
|
+
* may have been cleaned up since (a temp script the turn deleted), and such
|
|
328
|
+
* a path is not a product to list. Existence is checked fresh on every call
|
|
329
|
+
* (never cached), so a deletion that lands after a fold is visible on the
|
|
330
|
+
* next fetch. Unresolvable/unstat-able paths are treated as absent.
|
|
331
|
+
* @param agent - owning live agent; its session cwd anchors relative paths.
|
|
332
|
+
* @param paths - the display paths to probe.
|
|
333
|
+
* @returns the subset that resolves to an existing regular file.
|
|
334
|
+
*/
|
|
335
|
+
async retainExisting(agent, paths) {
|
|
336
|
+
if (paths.length === 0)
|
|
337
|
+
return new Set();
|
|
338
|
+
const cwd = agent.session.header.cwd;
|
|
339
|
+
const existing = new Set();
|
|
340
|
+
for (const path of paths) {
|
|
341
|
+
if (existing.has(path))
|
|
342
|
+
continue;
|
|
343
|
+
try {
|
|
344
|
+
const target = await this.fs.resolve(path, cwd === undefined ? {} : { cwd });
|
|
345
|
+
const info = await this.fs.stat(target);
|
|
346
|
+
if (info?.type === 'file')
|
|
347
|
+
existing.add(path);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// Unresolvable or stat failed: the path is not present to list.
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return existing;
|
|
354
|
+
}
|
|
313
355
|
/**
|
|
314
356
|
* List the files one session wrote or edited: the log fold plus any
|
|
315
357
|
* bash-written files the collector verified (the S2 seam), merged so a
|
|
316
|
-
* captured path the fold already knows keeps its log-derived entry.
|
|
358
|
+
* captured path the fold already knows keeps its log-derived entry. Only
|
|
359
|
+
* paths that currently exist on disk are returned — a file the session
|
|
360
|
+
* wrote and later deleted is history, not a product.
|
|
317
361
|
* @param agent - owning live agent; its session log is the data source.
|
|
318
|
-
* @returns first-seen files capped by `maxFiles`, with the log watermark.
|
|
362
|
+
* @returns existing first-seen files capped by `maxFiles`, with the log watermark.
|
|
319
363
|
*/
|
|
320
|
-
list(agent) {
|
|
321
|
-
const folded = foldFilePreview(agent.session.
|
|
364
|
+
async list(agent) {
|
|
365
|
+
const folded = foldFilePreview(agent.session.snapshotEvents(), this.resolved.maxFiles);
|
|
322
366
|
const captured = this.collector?.captured(agent.session.id);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
367
|
+
let entries = folded.entries;
|
|
368
|
+
if (captured !== undefined && captured.size > 0) {
|
|
369
|
+
const seen = new Set(entries.map(entry => entry.path));
|
|
370
|
+
const extra = [];
|
|
371
|
+
for (const [path, write] of captured) {
|
|
372
|
+
if (seen.has(path) || entries.length + extra.length >= this.resolved.maxFiles)
|
|
373
|
+
continue;
|
|
374
|
+
extra.push({ path, op: 'write', seq: write.seq, turn: write.turn, step: write.step, diffs: [] });
|
|
375
|
+
}
|
|
376
|
+
entries = [...entries, ...extra];
|
|
331
377
|
}
|
|
332
|
-
|
|
333
|
-
return folded;
|
|
378
|
+
const existing = await this.retainExisting(agent, entries.map(entry => entry.path));
|
|
334
379
|
return {
|
|
335
|
-
entries:
|
|
380
|
+
entries: entries.filter(entry => existing.has(entry.path)),
|
|
336
381
|
asOfSeq: folded.asOfSeq,
|
|
337
|
-
truncated: folded.truncated ||
|
|
382
|
+
truncated: folded.truncated || entries.length >= this.resolved.maxFiles,
|
|
338
383
|
};
|
|
339
384
|
}
|
|
340
385
|
/**
|
|
@@ -345,13 +390,16 @@ let FilePreviewService = (() => {
|
|
|
345
390
|
* result diff meta) and merging the collector's bash-written captures by
|
|
346
391
|
* their own turn. The fold is cached per session and invalidated by the log
|
|
347
392
|
* watermark, so repeated card fetches do not refold. A path touched in two
|
|
348
|
-
* turns appears in BOTH turn groups — per-turn attribution is exact.
|
|
393
|
+
* turns appears in BOTH turn groups — per-turn attribution is exact. Only
|
|
394
|
+
* paths that currently exist on disk are returned (a deleted temp script is
|
|
395
|
+
* history, not a product); existence is probed fresh on every call, so the
|
|
396
|
+
* cached fold is filtered per request rather than cached.
|
|
349
397
|
* @param agent - owning live agent; its session log is the data source.
|
|
350
|
-
* @returns per-turn file groups plus the scanned watermark.
|
|
398
|
+
* @returns existing per-turn file groups plus the scanned watermark.
|
|
351
399
|
*/
|
|
352
|
-
turnFiles(agent) {
|
|
400
|
+
async turnFiles(agent) {
|
|
353
401
|
const session = agent.session;
|
|
354
|
-
const events = session.
|
|
402
|
+
const events = session.snapshotEvents();
|
|
355
403
|
const asOfSeq = events.length === 0 ? -1 : events[events.length - 1].seq;
|
|
356
404
|
const cached = this.turnCache.get(session.id);
|
|
357
405
|
let byTurn;
|
|
@@ -386,7 +434,15 @@ let FilePreviewService = (() => {
|
|
|
386
434
|
continue;
|
|
387
435
|
turns.push({ turn, files: files.sort((a, b) => a.seq - b.seq) });
|
|
388
436
|
}
|
|
389
|
-
|
|
437
|
+
// Filter the assembled groups to paths that still exist on disk (fresh per
|
|
438
|
+
// call — the fold cache is by log watermark, existence moves independently).
|
|
439
|
+
const existing = await this.retainExisting(agent, turns.flatMap(group => group.files.map(file => file.path)));
|
|
440
|
+
return {
|
|
441
|
+
turns: turns
|
|
442
|
+
.map(group => ({ turn: group.turn, files: group.files.filter(file => existing.has(file.path)) }))
|
|
443
|
+
.filter(group => group.files.length > 0),
|
|
444
|
+
asOfSeq,
|
|
445
|
+
};
|
|
390
446
|
}
|
|
391
447
|
/**
|
|
392
448
|
* Read the current content of one recorded file, resolved against the
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"cordis",
|
|
8
8
|
"file-preview"
|
|
9
9
|
],
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.2.0",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"main": "lib/index.js",
|
|
13
13
|
"types": "lib/types/index.d.ts",
|
|
@@ -59,24 +59,25 @@
|
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
62
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
63
|
-
"@deepseek-ai/dsh-fs": "^0.1.
|
|
64
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
65
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
66
|
-
"@deepseek-ai/dsh-loader-smoke": "^0.1.
|
|
67
|
-
"@deepseek-ai/dsh-native-command": "^0.1.
|
|
68
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
69
|
-
"@deepseek-ai/dsh-skill": "^0.1.
|
|
70
|
-
"@deepseek-ai/dsh-tools": "^0.1.
|
|
71
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.
|
|
62
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-fs": "^0.1.2-rc.1",
|
|
64
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-rc.1",
|
|
65
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
|
|
66
|
+
"@deepseek-ai/dsh-loader-smoke": "^0.1.2-rc.1",
|
|
67
|
+
"@deepseek-ai/dsh-native-command": "^0.1.2-rc.1",
|
|
68
|
+
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
|
69
|
+
"@deepseek-ai/dsh-skill": "^0.1.2-rc.1",
|
|
70
|
+
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
|
|
71
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1",
|
|
72
|
+
"@deepseek-ai/dsh-util-values": "^0.1.2-rc.1"
|
|
72
73
|
},
|
|
73
74
|
"dsh": {
|
|
74
75
|
"bundle": {
|
|
75
76
|
"patch": "./cordis.patch.yml"
|
|
76
77
|
},
|
|
77
78
|
"compat": {
|
|
78
|
-
"minHost": "0.1.
|
|
79
|
-
"verifiedHost": "0.1.
|
|
79
|
+
"minHost": "0.1.2-rc.1",
|
|
80
|
+
"verifiedHost": "0.1.2-rc.1"
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
}
|