dsh-remote 0.8.67 → 0.8.70
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 +389 -389
- package/README.md +462 -463
- package/lib/client.js +58 -47
- package/lib/exec-job.js +14 -0
- package/lib/index.js +4548 -4494
- package/lib/instructions-dynamic.js +80 -7
- package/lib/instructions.js +288 -288
- package/lib/openssh.js +40 -8
- package/lib/paths.js +27 -0
- package/package.json +2 -2
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
import { statSync, mkdirSync, writeFileSync, utimesSync } from 'node:fs'
|
|
32
32
|
import { createHash, randomUUID } from 'node:crypto'
|
|
33
|
+
import { createRequire } from 'node:module'
|
|
33
34
|
import path from 'node:path'
|
|
34
35
|
import { joinRemotePath, relPathUnder } from './paths.js'
|
|
35
36
|
import { INSTRUCTION_MAX_BYTES } from './instructions.js'
|
|
@@ -39,6 +40,77 @@ import { INSTRUCTION_MAX_BYTES } from './instructions.js'
|
|
|
39
40
|
* reconcile only claims messages carrying its own kind. */
|
|
40
41
|
export const REMOTE_INSTRUCTIONS_KIND = 'dsh-remote-instructions'
|
|
41
42
|
|
|
43
|
+
/**
|
|
44
|
+
* The user-message factory hanging off the `llm` service, when that service
|
|
45
|
+
* actually exposes one.
|
|
46
|
+
*
|
|
47
|
+
* DSH 0.2.1 keeps `createUserMessage` as a module export of
|
|
48
|
+
* `@deepseek-ai/dsh-llm`, not a method of the `LlmRuntime` service. Probing
|
|
49
|
+
* `ctx.get('llm')` therefore returns null on current Desktop builds, and the
|
|
50
|
+
* caller must fall through to {@link loadBundledUserMessageFactory}.
|
|
51
|
+
*
|
|
52
|
+
* @param {object|null|undefined} llm - `ctx.get('llm')`, or a test double.
|
|
53
|
+
* @returns {Function|null}
|
|
54
|
+
*/
|
|
55
|
+
export function pickUserMessageFactory(llm) {
|
|
56
|
+
if (llm && typeof llm.createUserMessage === 'function') {
|
|
57
|
+
return (input) => llm.createUserMessage(input)
|
|
58
|
+
}
|
|
59
|
+
const nested = llm && llm.default
|
|
60
|
+
if (nested && typeof nested.createUserMessage === 'function') {
|
|
61
|
+
return (input) => nested.createUserMessage(input)
|
|
62
|
+
}
|
|
63
|
+
return null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Module-level `createUserMessage` from the harness's dsh-llm, if resolvable. */
|
|
67
|
+
let bundledUserMessageFactory
|
|
68
|
+
/**
|
|
69
|
+
* Load `@deepseek-ai/dsh-llm`'s `createUserMessage`.
|
|
70
|
+
*
|
|
71
|
+
* The package is not a declared dependency of this plugin (the compatibility
|
|
72
|
+
* gate would then have to peer-range it). Inside a DSH profile it is a sibling
|
|
73
|
+
* in `node_modules`, and Node walks up from this file to find it. A missing
|
|
74
|
+
* package returns null so the built-in identified message is used instead.
|
|
75
|
+
*
|
|
76
|
+
* @returns {Function|null}
|
|
77
|
+
*/
|
|
78
|
+
export function loadBundledUserMessageFactory() {
|
|
79
|
+
if (bundledUserMessageFactory !== undefined) return bundledUserMessageFactory
|
|
80
|
+
try {
|
|
81
|
+
const req = createRequire(import.meta.url)
|
|
82
|
+
const mod = req('@deepseek-ai/dsh-llm')
|
|
83
|
+
bundledUserMessageFactory = mod && typeof mod.createUserMessage === 'function'
|
|
84
|
+
? mod.createUserMessage
|
|
85
|
+
: null
|
|
86
|
+
} catch {
|
|
87
|
+
bundledUserMessageFactory = null
|
|
88
|
+
}
|
|
89
|
+
return bundledUserMessageFactory
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Guarantee the session-restore invariant: `message.id` is a non-empty string.
|
|
94
|
+
*
|
|
95
|
+
* DSH 0.2.1 (`dsh-session` `assertMessageEventShape`) rejects the whole log
|
|
96
|
+
* with "lacks an identified message" when any user message has no id. A
|
|
97
|
+
* factory that already stamped one is returned unchanged.
|
|
98
|
+
*
|
|
99
|
+
* @param {object|null} message - a factory result, or null to use `fallback`.
|
|
100
|
+
* @param {object} fallback - `{ role, content, source }` used when `message` is empty.
|
|
101
|
+
* @returns {object}
|
|
102
|
+
*/
|
|
103
|
+
export function ensureMessageId(message, fallback) {
|
|
104
|
+
const base = message && typeof message === 'object' ? message : fallback
|
|
105
|
+
if (typeof base.id === 'string' && base.id !== '') return base
|
|
106
|
+
return {
|
|
107
|
+
...fallback,
|
|
108
|
+
...base,
|
|
109
|
+
role: base.role || fallback.role,
|
|
110
|
+
id: randomUUID(),
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
42
114
|
/** Total byte budget for one injected batch (the core's own budget is similar). */
|
|
43
115
|
export const INSTRUCTION_MESSAGE_MAX_BYTES = 16 * 1024
|
|
44
116
|
|
|
@@ -332,11 +404,12 @@ export function buildInstructionMessage(items, removed, opts = {}) {
|
|
|
332
404
|
].join('\n')
|
|
333
405
|
const source = { kind: REMOTE_INSTRUCTIONS_KIND, form: 'instructions', changes: sent.map((rel) => ({ path: rel, change: 'changed' })) }
|
|
334
406
|
const content = [{ type: 'text', text }]
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
//
|
|
341
|
-
|
|
407
|
+
const fallback = { role: 'user', content, source }
|
|
408
|
+
let built = null
|
|
409
|
+
if (factory) {
|
|
410
|
+
try { built = factory({ content, source }) } catch { built = null }
|
|
411
|
+
}
|
|
412
|
+
// Session restore requires message.id (issue #75). A factory that throws or
|
|
413
|
+
// omits id must not store a bare object — that rejects the whole log.
|
|
414
|
+
return ensureMessageId(built, fallback)
|
|
342
415
|
}
|