dsh-reference-anything 0.5.1 → 0.5.2

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.
Files changed (73) hide show
  1. package/LICENSE +22 -22
  2. package/NOTICE.md +110 -110
  3. package/README.md +472 -459
  4. package/cordis.patch.yml +136 -136
  5. package/docs/release/0.4.4/README.md +75 -0
  6. package/{release-notes → docs/release}/0.4.4/features.json +36 -36
  7. package/docs/release/0.5.0/README.md +148 -0
  8. package/{release-notes → docs/release}/0.5.0/features.json +65 -65
  9. package/docs/release/0.5.1/README.md +33 -0
  10. package/docs/release/0.5.2/README.md +51 -0
  11. package/docs/release/0.5.2/features.json +29 -0
  12. package/{release-notes → docs/release}/README.md +42 -38
  13. package/images/agents/LICENSE +22 -22
  14. package/images/agents/README.md +7 -3
  15. package/images/agents/antigravity.svg +1 -1
  16. package/images/agents/cline.svg +1 -1
  17. package/images/agents/continue.svg +1 -1
  18. package/images/agents/copilot.svg +27 -0
  19. package/images/agents/crush.svg +1 -1
  20. package/images/agents/doubao.svg +1 -0
  21. package/images/agents/goose.svg +1 -1
  22. package/images/agents/omp.svg +1 -0
  23. package/images/agents/reasonix.svg +5 -5
  24. package/images/agents/teleagent.svg +1 -1
  25. package/images/agents/trae.svg +1 -1
  26. package/images/agents/vibe.svg +1 -1
  27. package/images/agents/workbuddy.svg +37 -37
  28. package/images/agents/zed.svg +1 -1
  29. package/lib/chat-import-compatibility.js +8 -5
  30. package/lib/client.js +36526 -4
  31. package/lib/contract.d.ts +4 -0
  32. package/lib/host.d.ts +2 -2
  33. package/lib/local-conversation-reader.js +16 -11
  34. package/lib/render.js +21 -21
  35. package/lib/store/spec.d.ts +9 -1
  36. package/lib/tool.js +3 -2
  37. package/lib/wire.d.ts +13 -1
  38. package/lib/wire.js +5 -4
  39. package/locale/en.json +6 -6
  40. package/locale/zh.json +6 -6
  41. package/opencli-plugin/chatgpt.js +128 -128
  42. package/opencli-plugin/claude.js +138 -138
  43. package/opencli-plugin/common.js +452 -452
  44. package/opencli-plugin/deepseek.js +155 -155
  45. package/opencli-plugin/gemini.js +169 -169
  46. package/opencli-plugin/grok.js +124 -124
  47. package/opencli-plugin/kimi.js +126 -126
  48. package/opencli-plugin/opencli-plugin.json +6 -6
  49. package/opencli-plugin/package.json +8 -8
  50. package/opencli-plugin/since-guard.js +45 -45
  51. package/package.json +263 -262
  52. package/vendor/chat-import-reader/LICENSE +22 -22
  53. package/vendor/chat-import-reader/LICENSE.fzstd +20 -20
  54. package/vendor/chat-import-reader/README.md +54 -48
  55. package/vendor/chat-import-reader/availability-worker.mjs +119 -114
  56. package/vendor/chat-import-reader/parsers.d.mts +6 -6
  57. package/vendor/chat-import-reader/parsers.mjs +13069 -11168
  58. package/vendor/chat-import-reader/scan-worker.mjs +7 -7
  59. package/vendor/chat-import-reader/scanners.mjs +5523 -4286
  60. package/vendor/chat-import-reader/upstream-sha256.json +114 -101
  61. package/release-notes/0.4.4/commands.png +0 -0
  62. package/release-notes/0.4.4/demos/agent-import.gif +0 -0
  63. package/release-notes/0.4.4/demos/chat-import-upgrade.gif +0 -0
  64. package/release-notes/0.4.4/demos/folders.gif +0 -0
  65. package/release-notes/0.4.4/demos/local-plugins.gif +0 -0
  66. package/release-notes/0.4.4/demos/shortcuts.gif +0 -0
  67. package/release-notes/0.4.4/files.png +0 -0
  68. package/release-notes/0.5.0/demos/agent-import.gif +0 -0
  69. package/release-notes/0.5.0/demos/chat-import-upgrade.gif +0 -0
  70. package/release-notes/0.5.0/demos/folders.gif +0 -0
  71. package/release-notes/0.5.0/demos/local-plugins.gif +0 -0
  72. package/release-notes/0.5.0/demos/local-references.gif +0 -0
  73. package/release-notes/0.5.0/demos/shortcuts.gif +0 -0
@@ -1,48 +1,54 @@
1
- # Bundled conversation scanners and readers
2
-
3
- Derived from [dsh-chat-import](https://github.com/Nwflower/dsh-chat-import), npm
4
- 0.26.1 (MIT). `upstream-sha256.json` records the exact version and source hashes.
5
- Both generated bundles include fzstd (MIT); `LICENSE` and `LICENSE.fzstd` ship
6
- with the package. Upstream paths in comments are not runtime dependencies.
7
-
8
- `parsers.mjs` exposes preview-based text/image reading and default roots.
9
- `scanners.mjs` reuses all upstream source descriptors and SQLite summary readers.
10
- The scan entry provides filesystem-only access and runs in `scan-worker.mjs`,
11
- without plugin registration or session mutations. The host caches metadata for
12
- 30 seconds; missing paths are empty, while permission/database errors are warnings.
13
- Import status is not inferred locally: Reference Anything asks the optional
14
- Chat Import API separately. Import and summaries also remain API operations.
15
-
16
- Local patches expose preview content, preserve Trae message parts, export the
17
- upstream database-summary table, and replace a dynamic Trae scanner import with
18
- a static named import so mutation code can be removed by tree shaking.
19
- The generator rejects leaked mutation code and changed patch anchors.
20
- Antigravity IDE typed tool results (directory/file reads, code actions,
21
- subagents, commands and searches) are matched by tool name rather than discarded
22
- as missing background output; GENERIC results keep their existing handling.
23
- Async sidecar reports only supplement GENERIC results, never replace typed output.
24
- Hermes SQLite and JSONL reads preserve tool-only assistant messages, OpenAI-style
25
- function calls, and role=tool results. Results are associated by call ID, including
26
- parallel calls; string arguments and result text remain unchanged.
27
-
28
- ## Update from upstream
29
-
30
- 1. Download/build the desired upstream version in a separate directory (or use
31
- an installed npm package directory). Do not overwrite the running Desktop plugin.
32
- 2. Run `npm run vendor:sync -- <built-dsh-chat-import-directory>` from this repository.
33
- This regenerates both bundles and their shared version/hash manifest. Normal
34
- builds never download upstream or inspect another installed plugin.
35
- 3. Review source/version/license changes, then run `npm run agent:verify` and
36
- test the Web profile with Chat Import disabled and enabled. The catalog test
37
- detects new upstream formats that need settings/icon/type support here.
38
- 4. Ship the verified snapshot in a new Reference Anything release. Users receive
39
- upstream changes when updating Reference Anything, not automatically at runtime.
40
-
41
- Parsing a reference may read its whole source before returning a page. Images
42
- require recoverable bytes or a valid attachment; unavailable images are reported.
43
-
44
- The structured read projection numbers body messages independently of tools,
45
- links tool records and images to those numbers, and hashes normalized source
46
- content before applying presentation budgets. The host adds original-file
47
- fingerprints/version checks. This projection is used for automatic send-time
48
- previews and numeric read/search/image calls; it retains no parsed-body cache.
1
+ # Bundled conversation scanners and readers
2
+
3
+ Derived from [dsh-chat-import](https://github.com/Nwflower/dsh-chat-import), npm
4
+ 0.26.3 (MIT). `upstream-sha256.json` records the exact version and source hashes.
5
+ Both generated bundles include fzstd (MIT); `LICENSE` and `LICENSE.fzstd` ship
6
+ with the package. Upstream paths in comments are not runtime dependencies.
7
+
8
+ `parsers.mjs` exposes preview-based text/image reading and default roots.
9
+ `scanners.mjs` reuses all upstream source descriptors and SQLite summary readers.
10
+ The scan entry provides filesystem-only access and runs in `scan-worker.mjs`,
11
+ without plugin registration or session mutations. The host caches metadata for
12
+ 30 seconds; missing paths are empty, while permission/database errors are warnings.
13
+ Import status is not inferred locally: Reference Anything asks the optional
14
+ Chat Import API separately. Import and summaries also remain API operations.
15
+
16
+ Local patches expose preview content, preserve Trae message parts, export the
17
+ upstream database-summary table, and replace a dynamic Trae scanner import with
18
+ a static named import so mutation code can be removed by tree shaking.
19
+ The generator rejects leaked mutation code and changed patch anchors.
20
+ Antigravity IDE typed tool results (directory/file reads, code actions,
21
+ subagents, commands and searches) are matched by tool name rather than discarded
22
+ as missing background output; GENERIC results keep their existing handling.
23
+ Async sidecar reports only supplement GENERIC results, never replace typed output.
24
+ Hermes SQLite and JSONL reads preserve tool-only assistant messages, OpenAI-style
25
+ function calls, and role=tool results. Results are associated by call ID, including
26
+ parallel calls; string arguments and result text remain unchanged.
27
+
28
+ The 0.26.3 snapshot adds Copilot VS Code, Copilot CLI and Doubao Desktop.
29
+ Doubao reads cached local IndexedDB bodies only. Its directory entries must be
30
+ regular files, and child-file fingerprints invalidate revisions and availability
31
+ checks when the database changes. Background availability checks leave databases
32
+ larger than 8 MiB unknown instead of eagerly parsing them.
33
+
34
+ ## Update from upstream
35
+
36
+ 1. Download/build the desired upstream version in a separate directory (or use
37
+ an installed npm package directory). Do not overwrite the running Desktop plugin.
38
+ 2. Run `npm run vendor:sync -- <built-dsh-chat-import-directory>` from this repository.
39
+ This regenerates both bundles and their shared version/hash manifest. Normal
40
+ builds never download upstream or inspect another installed plugin.
41
+ 3. Review source/version/license changes, then run `npm run agent:verify` and
42
+ test the Web profile with Chat Import disabled and enabled. The catalog test
43
+ detects new upstream formats that need settings/icon/type support here.
44
+ 4. Ship the verified snapshot in a new Reference Anything release. Users receive
45
+ upstream changes when updating Reference Anything, not automatically at runtime.
46
+
47
+ Parsing a reference may read its whole source before returning a page. Images
48
+ require recoverable bytes or a valid attachment; unavailable images are reported.
49
+
50
+ The structured read projection numbers body messages independently of tools,
51
+ links tool records and images to those numbers, and hashes normalized source
52
+ content before applying presentation budgets. The host adds original-file
53
+ fingerprints/version checks. This projection is used for automatic send-time
54
+ previews and numeric read/search/image calls; it retains no parsed-body cache.
@@ -1,114 +1,119 @@
1
- import { parentPort } from 'node:worker_threads'
2
- import { readFile, readdir, stat } from 'node:fs/promises'
3
- import { join, resolve } from 'node:path'
4
- import { homedir } from 'node:os'
5
- import { readConversation } from './parsers.mjs'
6
- const channel = parentPort || { on: (...args) => process.on(...args), postMessage: value => process.send(value) }
7
- if (!parentPort) process.on('disconnect', () => process.exit(0))
8
-
9
- // Parsing stays off the picker thread. Only states and file fingerprints cross back.
10
- channel.on('message', async ({ id, target }) => {
11
- const dependencies = new Map()
12
- const inspect = async path => {
13
- try {
14
- const s = await stat(path)
15
- dependencies.set(path, `${s.size}:${s.mtimeMs}:${s.ctimeMs}`)
16
- return { type: s.isDirectory() ? 'directory' : 'file', size: s.size, mtimeMs: s.mtimeMs }
17
- } catch (error) {
18
- if (error.code !== 'ENOENT') throw error
19
- dependencies.set(path, 'missing')
20
- return undefined
21
- }
22
- }
23
- const fs = {
24
- resolve: async path => ({ displayPath: resolve(path) }),
25
- processPath: value => value.displayPath,
26
- stat: async value => inspect(value.displayPath),
27
- readText: async value => {
28
- const info = await inspect(value.displayPath)
29
- // shortcut: large sources stay unknown; use streaming probes before raising this background budget.
30
- if (info?.size > 8 * 1024 * 1024) throw new Error('Background validation budget exceeded')
31
- const raw = await readFile(value.displayPath, 'utf8')
32
- // A tolerant converter may skip broken lines; that must never prove emptiness.
33
- if (/\.jsonl$/i.test(value.displayPath)) for (const line of raw.split(/\r?\n/)) if (line.trim()) JSON.parse(line)
34
- return raw
35
- },
36
- listDir: async value => {
37
- await inspect(value.displayPath)
38
- return (await readdir(value.displayPath, { withFileTypes: true })).map(e => ({
39
- name: e.name, type: e.isDirectory() ? 'directory' : 'file', target: { displayPath: join(value.displayPath, e.name) },
40
- }))
41
- },
42
- }
43
- let state = 'unknown'
44
- try {
45
- const info = await inspect(target.path)
46
- if (!info || (info.type === 'file' && info.size === 0)) state = 'empty'
47
- else if (target.format === 'claude' && /\.json$/i.test(target.path)) {
48
- const meta = JSON.parse(await fs.readText({ displayPath: target.path }))
49
- if (meta.cliSessionId && !meta.messages) {
50
- // Match the exact CLI identity; never substitute another chat in the project.
51
- const root = join(homedir(), '.claude', 'projects')
52
- let found = false
53
- const walk = async dir => {
54
- await inspect(dir)
55
- for (const e of await readdir(dir, { withFileTypes: true })) {
56
- if (e.isDirectory()) await walk(join(dir, e.name))
57
- else if (e.name === `${meta.cliSessionId}.jsonl`) found = true
58
- }
59
- }
60
- if (await inspect(root)) await walk(root)
61
- state = found ? 'unknown' : 'empty'
62
- }
63
- } else {
64
- if (info.type === 'directory' && ['grokbuild', 'vibe', 'kimi'].includes(target.format)) {
65
- const names = target.format === 'grokbuild' ? ['chat_history.jsonl']
66
- : target.format === 'vibe' ? ['messages.jsonl'] : ['wire.jsonl', 'agents/main/wire.jsonl']
67
- const bodies = await Promise.all(names.map(name => inspect(join(target.path, name))))
68
- if (bodies.every(body => !body || body.size === 0)) {
69
- channel.postMessage({ id, state: 'empty', dependencies: [...dependencies] })
70
- return
71
- }
72
- }
73
- if (/\.(?:db|vscdb)$/i.test(target.path)) {
74
- await inspect(target.path + '-wal')
75
- await inspect(target.path + '-shm')
76
- const schemas = {
77
- opencode: ['session', 'message'], mimocode: ['session', 'message'], kilocode: ['session', 'message'],
78
- teleagent: ['session', 'message'], zcode: ['session', 'message'],
79
- hermes: ['sessions', 'messages'], goose: ['sessions', 'messages'], crush: ['sessions', 'messages'],
80
- }
81
- let schema = schemas[target.format]
82
- if (schema) {
83
- const { DatabaseSync } = await import('node:sqlite')
84
- const db = new DatabaseSync(target.path, { readOnly: true })
85
- try {
86
- const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all().map(r => r.name))
87
- if (schema[0] === 'session' && tables.has('session_v2')) schema = ['session_v2', 'session_message']
88
- if (tables.has(schema[0]) && tables.has(schema[1])
89
- && db.prepare(`SELECT 1 FROM ${schema[0]} WHERE id = ? LIMIT 1`).get(target.sessionId)
90
- && !db.prepare(`SELECT 1 FROM ${schema[1]} WHERE session_id = ? LIMIT 1`).get(target.sessionId)) {
91
- channel.postMessage({ id, state: 'empty', dependencies: [...dependencies] })
92
- return
93
- }
94
- } finally { db.close() }
95
- }
96
- }
97
- if (target.format === 'chatgpt') {
98
- const exported = JSON.parse(await fs.readText({ displayPath: target.path }))
99
- const chat = Array.isArray(exported) ? exported.find(c => c.id === target.sessionId) : null
100
- if (chat?.mapping && Object.values(chat.mapping).every(node => node && !node.message)) {
101
- channel.postMessage({ id, state: 'empty', dependencies: [...dependencies] })
102
- return
103
- }
104
- }
105
- state = await readConversation(fs, { ...target, limit: 1, detail: 'full', probe: true })
106
- if (state === 'unknown' && ['pi', 'codex', 'openclaw', 'hermes', 'dsh', 'dsh4'].includes(target.format) && info.type === 'file' && !/\.(db|vscdb|zstd)$/i.test(target.path)) {
107
- const records = (await fs.readText({ displayPath: target.path })).split(/\r?\n/).filter(line => line.trim()).map(line => JSON.parse(line))
108
- const allowed = target.format === 'codex' ? ['session_meta'] : ['session', 'session_info', 'session/title']
109
- if (records.length && records.every(r => allowed.includes(r.type))) state = 'empty'
110
- }
111
- }
112
- } catch { state = 'unknown' }
113
- channel.postMessage({ id, state, dependencies: [...dependencies] })
114
- })
1
+ import { parentPort } from 'node:worker_threads'
2
+ import { readFile, readdir, stat } from 'node:fs/promises'
3
+ import { join, resolve } from 'node:path'
4
+ import { homedir } from 'node:os'
5
+ import { readConversation } from './parsers.mjs'
6
+ const channel = parentPort || { on: (...args) => process.on(...args), postMessage: value => process.send(value) }
7
+ if (!parentPort) process.on('disconnect', () => process.exit(0))
8
+
9
+ // Parsing stays off the picker thread. Only states and file fingerprints cross back.
10
+ channel.on('message', async ({ id, target }) => {
11
+ const dependencies = new Map()
12
+ const inspect = async path => {
13
+ try {
14
+ const s = await stat(path)
15
+ dependencies.set(path, `${s.size}:${s.mtimeMs}:${s.ctimeMs}`)
16
+ return { type: s.isDirectory() ? 'directory' : 'file', size: s.size, mtimeMs: s.mtimeMs }
17
+ } catch (error) {
18
+ if (error.code !== 'ENOENT') throw error
19
+ dependencies.set(path, 'missing')
20
+ return undefined
21
+ }
22
+ }
23
+ const fs = {
24
+ resolve: async path => ({ displayPath: resolve(path) }),
25
+ processPath: value => value.displayPath,
26
+ stat: async value => inspect(value.displayPath),
27
+ readText: async value => {
28
+ const info = await inspect(value.displayPath)
29
+ // shortcut: large sources stay unknown; use streaming probes before raising this background budget.
30
+ if (info?.size > 8 * 1024 * 1024) throw new Error('Background validation budget exceeded')
31
+ const raw = await readFile(value.displayPath, 'utf8')
32
+ // A tolerant converter may skip broken lines; that must never prove emptiness.
33
+ if (/\.jsonl$/i.test(value.displayPath)) for (const line of raw.split(/\r?\n/)) if (line.trim()) JSON.parse(line)
34
+ return raw
35
+ },
36
+ listDir: async value => {
37
+ await inspect(value.displayPath)
38
+ return (await readdir(value.displayPath, { withFileTypes: true })).map(e => ({
39
+ name: e.name, type: e.isDirectory() ? 'directory' : 'file', target: { displayPath: join(value.displayPath, e.name) },
40
+ }))
41
+ },
42
+ }
43
+ let state = 'unknown'
44
+ try {
45
+ const info = await inspect(target.path)
46
+ if (!info || (info.type === 'file' && info.size === 0)) state = 'empty'
47
+ else if (target.format === 'claude' && /\.json$/i.test(target.path)) {
48
+ const meta = JSON.parse(await fs.readText({ displayPath: target.path }))
49
+ if (meta.cliSessionId && !meta.messages) {
50
+ // Match the exact CLI identity; never substitute another chat in the project.
51
+ const root = join(homedir(), '.claude', 'projects')
52
+ let found = false
53
+ const walk = async dir => {
54
+ await inspect(dir)
55
+ for (const e of await readdir(dir, { withFileTypes: true })) {
56
+ if (e.isDirectory()) await walk(join(dir, e.name))
57
+ else if (e.name === `${meta.cliSessionId}.jsonl`) found = true
58
+ }
59
+ }
60
+ if (await inspect(root)) await walk(root)
61
+ state = found ? 'unknown' : 'empty'
62
+ }
63
+ } else {
64
+ if (info.type === 'directory' && target.format === 'doubao') {
65
+ const names = (await readdir(target.path)).filter(name => /\.(ldb|log)$/.test(name))
66
+ const files = await Promise.all(names.map(name => inspect(join(target.path, name))))
67
+ if (files.reduce((sum, file) => sum + (file?.size || 0), 0) > 8 * 1024 * 1024) throw new Error('Background validation budget exceeded')
68
+ }
69
+ if (info.type === 'directory' && ['grokbuild', 'vibe', 'kimi'].includes(target.format)) {
70
+ const names = target.format === 'grokbuild' ? ['chat_history.jsonl']
71
+ : target.format === 'vibe' ? ['messages.jsonl'] : ['wire.jsonl', 'agents/main/wire.jsonl']
72
+ const bodies = await Promise.all(names.map(name => inspect(join(target.path, name))))
73
+ if (bodies.every(body => !body || body.size === 0)) {
74
+ channel.postMessage({ id, state: 'empty', dependencies: [...dependencies] })
75
+ return
76
+ }
77
+ }
78
+ if (/\.(?:db|vscdb)$/i.test(target.path)) {
79
+ await inspect(target.path + '-wal')
80
+ await inspect(target.path + '-shm')
81
+ const schemas = {
82
+ opencode: ['session', 'message'], mimocode: ['session', 'message'], kilocode: ['session', 'message'],
83
+ teleagent: ['session', 'message'], zcode: ['session', 'message'],
84
+ hermes: ['sessions', 'messages'], goose: ['sessions', 'messages'], crush: ['sessions', 'messages'],
85
+ }
86
+ let schema = schemas[target.format]
87
+ if (schema) {
88
+ const { DatabaseSync } = await import('node:sqlite')
89
+ const db = new DatabaseSync(target.path, { readOnly: true })
90
+ try {
91
+ const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all().map(r => r.name))
92
+ if (schema[0] === 'session' && tables.has('session_v2')) schema = ['session_v2', 'session_message']
93
+ if (tables.has(schema[0]) && tables.has(schema[1])
94
+ && db.prepare(`SELECT 1 FROM ${schema[0]} WHERE id = ? LIMIT 1`).get(target.sessionId)
95
+ && !db.prepare(`SELECT 1 FROM ${schema[1]} WHERE session_id = ? LIMIT 1`).get(target.sessionId)) {
96
+ channel.postMessage({ id, state: 'empty', dependencies: [...dependencies] })
97
+ return
98
+ }
99
+ } finally { db.close() }
100
+ }
101
+ }
102
+ if (target.format === 'chatgpt') {
103
+ const exported = JSON.parse(await fs.readText({ displayPath: target.path }))
104
+ const chat = Array.isArray(exported) ? exported.find(c => c.id === target.sessionId) : null
105
+ if (chat?.mapping && Object.values(chat.mapping).every(node => node && !node.message)) {
106
+ channel.postMessage({ id, state: 'empty', dependencies: [...dependencies] })
107
+ return
108
+ }
109
+ }
110
+ state = await readConversation(fs, { ...target, limit: 1, detail: 'full', probe: true })
111
+ if (state === 'unknown' && ['pi', 'codex', 'openclaw', 'hermes', 'dsh', 'dsh4'].includes(target.format) && info.type === 'file' && !/\.(db|vscdb|zstd)$/i.test(target.path)) {
112
+ const records = (await fs.readText({ displayPath: target.path })).split(/\r?\n/).filter(line => line.trim()).map(line => JSON.parse(line))
113
+ const allowed = target.format === 'codex' ? ['session_meta'] : ['session', 'session_info', 'session/title']
114
+ if (records.length && records.every(r => allowed.includes(r.type))) state = 'empty'
115
+ }
116
+ }
117
+ } catch { state = 'unknown' }
118
+ channel.postMessage({ id, state, dependencies: [...dependencies] })
119
+ })
@@ -1,6 +1,6 @@
1
- export function defaultRoots(): Record<string, string | string[] | null>
2
- export function readConversation(fs: unknown, input: {
3
- format: string; path: string; sessionId: string; limit: number;
4
- before?: number; revision?: string; detail: 'summary' | 'full';
5
- probe?: boolean; structured?: boolean;
6
- }, signal?: AbortSignal): Promise<unknown>
1
+ export function defaultRoots(): Record<string, string | string[] | null>
2
+ export function readConversation(fs: unknown, input: {
3
+ format: string; path: string; sessionId: string; limit: number;
4
+ before?: number; revision?: string; detail: 'summary' | 'full';
5
+ probe?: boolean; structured?: boolean;
6
+ }, signal?: AbortSignal): Promise<unknown>