newmark-agent 0.3.12 → 0.4.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 (60) hide show
  1. package/dist/cli-commands.d.ts +1 -0
  2. package/dist/cli-commands.js +11 -2
  3. package/dist/context/domain/types.d.ts +37 -0
  4. package/dist/context/services/context-orchestrator.js +2 -0
  5. package/dist/conversation-utility-host.bundle.cjs +1259 -132
  6. package/dist/conversation-utility-host.js +3 -0
  7. package/dist/core/agent.d.ts +139 -5
  8. package/dist/core/agent.js +964 -82
  9. package/dist/core/agentKernel/agent-loop.js +29 -3
  10. package/dist/core/agentKernel/types.d.ts +7 -0
  11. package/dist/core/agentKernelRunner.d.ts +2 -0
  12. package/dist/core/agentKernelRunner.js +121 -19
  13. package/dist/core/conversationKernel.d.ts +5 -0
  14. package/dist/core/conversationKernel.js +29 -0
  15. package/dist/core/dshCompatibility.d.ts +198 -0
  16. package/dist/core/dshCompatibility.js +600 -0
  17. package/dist/core/electronUtilityAgentClient.d.ts +4 -0
  18. package/dist/core/electronUtilityAgentClient.js +4 -0
  19. package/dist/core/electronUtilityRuntimePool.d.ts +8 -0
  20. package/dist/core/electronUtilityRuntimePool.js +14 -0
  21. package/dist/core/mcpManager.d.ts +1 -0
  22. package/dist/core/mcpManager.js +100 -10
  23. package/dist/core/subagent.d.ts +6 -0
  24. package/dist/core/subagent.js +22 -1
  25. package/dist/core/toolPolicy.d.ts +15 -0
  26. package/dist/core/toolPolicy.js +174 -1
  27. package/dist/core/types.d.ts +1 -1
  28. package/dist/core/utilityAgentProtocol.d.ts +8 -1
  29. package/dist/core/workspace.d.ts +9 -0
  30. package/dist/core/workspace.js +48 -1
  31. package/dist/core/wslAgentClient.d.ts +4 -0
  32. package/dist/core/wslAgentClient.js +4 -0
  33. package/dist/core/wslAgentProtocol.d.ts +8 -1
  34. package/dist/core/wslAgentRuntimePool.d.ts +8 -0
  35. package/dist/core/wslAgentRuntimePool.js +15 -0
  36. package/dist/launcher.js +8 -0
  37. package/dist/llm/provider.d.ts +1 -1
  38. package/dist/llm/provider.js +4 -3
  39. package/dist/main.js +163 -11
  40. package/dist/preload.js +11 -0
  41. package/dist/providers/chat-completions.adapter.js +41 -15
  42. package/dist/providers/provider-adapter.d.ts +3 -0
  43. package/dist/toolchain/registry/tool-registry.d.ts +13 -1
  44. package/dist/toolchain/registry/tool-registry.js +8 -0
  45. package/dist/toolchain/registry-seeder.js +52 -6
  46. package/dist/tools/index.d.ts +1 -0
  47. package/dist/tools/index.js +39 -2
  48. package/dist/tools/nativeTools.js +6 -1
  49. package/dist/tui/src/app.js +24 -0
  50. package/dist/tui/src/i18n.js +151 -0
  51. package/dist/tui/src/render.js +152 -61
  52. package/dist/tui/src/state.js +83 -0
  53. package/dist/ui/index.html +2669 -234
  54. package/dist/ui/lucide-sprite.svg +31 -0
  55. package/dist/wsl-agent-host.bundle.cjs +1259 -132
  56. package/dist/wsl-agent-host.js +3 -0
  57. package/package.json +6 -10
  58. package/Flow/Electron-Debug-Release.Flow.json +0 -43
  59. package/Flow/Flow.md +0 -9
  60. package/Flow/UI-Feature-Integration.Flow.json +0 -96
@@ -0,0 +1,600 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.discoverDshCompatibility = discoverDshCompatibility;
37
+ exports.dshCompactionRuntimeSemantics = dshCompactionRuntimeSemantics;
38
+ exports.dshToolLayerRuntimeSemantics = dshToolLayerRuntimeSemantics;
39
+ const fs = __importStar(require("fs"));
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ const REPOSITORY = 'https://github.com/deepseek-ai/deepseek-harness';
43
+ const DOCUMENTATION = `${REPOSITORY}/blob/master/docs/user/develop/basic/publish.md`;
44
+ const NPM = 'https://www.npmjs.com/package/@deepseek-ai/dsh';
45
+ const CONFIG_NAMES = ['cordis.patch.yml', 'cordis.yml'];
46
+ const MAX_JSON_BYTES = 2 * 1024 * 1024;
47
+ const MAX_CONFIG_BYTES = 4 * 1024 * 1024;
48
+ const MAX_PROFILES = 256;
49
+ const MAX_DIRECTORY_ENTRIES = 1024;
50
+ const DSH_PACKAGE_KEYS = new Set(['bundle', 'profile']);
51
+ const PACKAGE_KEYS = new Set([
52
+ 'name', 'version', 'private', 'description', 'keywords', 'homepage', 'bugs', 'license', 'author', 'contributors',
53
+ 'funding', 'files', 'main', 'module', 'types', 'typings', 'exports', 'bin', 'scripts', 'engines', 'os', 'cpu',
54
+ 'publishConfig', 'repository', 'dependencies', 'devDependencies', 'peerDependencies', 'peerDependenciesMeta',
55
+ 'optionalDependencies', 'bundledDependencies', 'bundleDependencies', 'workspaces', 'packageManager', 'type', 'sideEffects',
56
+ 'dsh',
57
+ ]);
58
+ function record(value) {
59
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
60
+ }
61
+ function readTextFile(filePath, maxBytes) {
62
+ try {
63
+ const stats = fs.statSync(filePath);
64
+ if (!stats.isFile() || stats.size > maxBytes)
65
+ return undefined;
66
+ const value = fs.readFileSync(filePath);
67
+ if (value.byteLength > maxBytes)
68
+ return undefined;
69
+ return value.toString('utf8').replace(/^\uFEFF/, '');
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ function readJson(filePath) {
76
+ try {
77
+ const text = readTextFile(filePath, MAX_JSON_BYTES);
78
+ return text === undefined ? undefined : record(JSON.parse(text));
79
+ }
80
+ catch {
81
+ return undefined;
82
+ }
83
+ }
84
+ function fileExists(filePath) {
85
+ try {
86
+ return fs.statSync(filePath).isFile();
87
+ }
88
+ catch {
89
+ return false;
90
+ }
91
+ }
92
+ function directoryExists(filePath) {
93
+ try {
94
+ return fs.statSync(filePath).isDirectory();
95
+ }
96
+ catch {
97
+ return false;
98
+ }
99
+ }
100
+ function pathEscapes(basePath, candidatePath) {
101
+ const relative = path.relative(path.resolve(basePath), path.resolve(candidatePath));
102
+ return relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative);
103
+ }
104
+ function confinedPatchPath(directory, patch) {
105
+ const clean = String(patch || '').trim();
106
+ if (!clean || path.isAbsolute(clean))
107
+ return undefined;
108
+ const candidate = path.resolve(directory, clean);
109
+ if (pathEscapes(directory, candidate))
110
+ return undefined;
111
+ if (fileExists(candidate)) {
112
+ try {
113
+ const realDirectory = fs.realpathSync(directory);
114
+ const realCandidate = fs.realpathSync(candidate);
115
+ if (pathEscapes(realDirectory, realCandidate))
116
+ return undefined;
117
+ }
118
+ catch {
119
+ return undefined;
120
+ }
121
+ }
122
+ return candidate;
123
+ }
124
+ function unique(values) {
125
+ return Array.from(new Set(values.filter(Boolean)));
126
+ }
127
+ function unknownPackageKeys(manifest) {
128
+ return Object.keys(manifest).filter(key => !PACKAGE_KEYS.has(key)).sort();
129
+ }
130
+ function unknownDshKeys(value) {
131
+ return Object.keys(record(value)).filter(key => !DSH_PACKAGE_KEYS.has(key)).sort();
132
+ }
133
+ function findDshCommand(pathValue, platform) {
134
+ const names = platform === 'win32' ? ['dsh.exe', 'dsh.cmd', 'dsh.bat'] : ['dsh'];
135
+ for (const directory of pathValue.split(path.delimiter).map(value => value.trim()).filter(Boolean).slice(0, 512)) {
136
+ for (const name of names) {
137
+ const candidate = path.resolve(directory.replace(/^"|"$/g, ''), name);
138
+ if (fileExists(candidate))
139
+ return candidate;
140
+ }
141
+ }
142
+ return undefined;
143
+ }
144
+ function packageManifestCandidates(root, dshHome, cliPath) {
145
+ const candidates = [
146
+ path.join(root, 'node_modules', '@deepseek-ai', 'dsh', 'package.json'),
147
+ path.join(dshHome, 'node_modules', '@deepseek-ai', 'dsh', 'package.json'),
148
+ ];
149
+ if (cliPath) {
150
+ const bin = path.dirname(cliPath);
151
+ candidates.push(path.join(bin, 'node_modules', '@deepseek-ai', 'dsh', 'package.json'), path.resolve(bin, '..', 'node_modules', '@deepseek-ai', 'dsh', 'package.json'), path.resolve(bin, '..', 'lib', 'node_modules', '@deepseek-ai', 'dsh', 'package.json'));
152
+ }
153
+ return unique(candidates.map(candidate => path.resolve(candidate)));
154
+ }
155
+ function manifestVersion(filePath) {
156
+ const value = filePath ? readJson(filePath) : undefined;
157
+ return typeof value?.version === 'string' ? value.version : undefined;
158
+ }
159
+ function bundleName(value) {
160
+ if (typeof value === 'string' && value.trim())
161
+ return value.trim();
162
+ const entry = record(value);
163
+ for (const key of ['name', 'package', 'id']) {
164
+ if (typeof entry[key] === 'string' && String(entry[key]).trim())
165
+ return String(entry[key]).trim();
166
+ }
167
+ return undefined;
168
+ }
169
+ function dependencyPath(profileRoot, name, spec) {
170
+ const paths = [path.join(profileRoot, 'node_modules', ...name.split('/'), 'package.json')];
171
+ if (typeof spec === 'string') {
172
+ const clean = spec.replace(/^(?:file:|link:)/, '');
173
+ if (clean !== spec || clean.startsWith('.') || path.isAbsolute(clean))
174
+ paths.unshift(path.resolve(profileRoot, clean, 'package.json'));
175
+ }
176
+ return unique(paths);
177
+ }
178
+ function bundleSnapshot(name, manifestPath, source) {
179
+ const manifest = readJson(manifestPath);
180
+ if (!manifest) {
181
+ return { name, source, manifestPath, patchExists: false, unknownKeys: [], resolved: false };
182
+ }
183
+ const dsh = record(manifest.dsh);
184
+ const bundle = record(dsh.bundle);
185
+ const patch = typeof bundle.patch === 'string' ? bundle.patch : undefined;
186
+ const patchPath = patch ? confinedPatchPath(path.dirname(manifestPath), patch) : undefined;
187
+ return {
188
+ name: typeof manifest.name === 'string' ? manifest.name : name,
189
+ version: typeof manifest.version === 'string' ? manifest.version : undefined,
190
+ source,
191
+ manifestPath,
192
+ patch,
193
+ patchPath,
194
+ patchExists: !!patchPath && fileExists(patchPath),
195
+ unknownKeys: unique(unknownPackageKeys(manifest).concat(unknownDshKeys(dsh), Object.keys(bundle).filter(key => key !== 'patch'))),
196
+ resolved: true,
197
+ };
198
+ }
199
+ function safeScalar(raw) {
200
+ const value = raw.trim().replace(/\s+#.*$/, '').trim();
201
+ if (!value || /^!!|[&*!]|\$\{|process\.|require\(|<%/i.test(value))
202
+ return undefined;
203
+ if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
204
+ try {
205
+ return value.startsWith('"') ? JSON.parse(value) : value.slice(1, -1).replace(/''/g, "'");
206
+ }
207
+ catch {
208
+ return undefined;
209
+ }
210
+ }
211
+ if (/^[A-Za-z0-9_@./:\\+ -]+$/.test(value))
212
+ return value;
213
+ return undefined;
214
+ }
215
+ function inlineStringArray(raw) {
216
+ const value = raw.trim();
217
+ if (!value.startsWith('[') || !value.endsWith(']') || /!!|process\.|\$\{|[&*!]/i.test(value))
218
+ return undefined;
219
+ try {
220
+ const json = value.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, (_match, inner) => JSON.stringify(inner.replace(/\\'/g, "'")));
221
+ const parsed = JSON.parse(json);
222
+ return Array.isArray(parsed)
223
+ && parsed.length <= 100
224
+ && parsed.every(item => typeof item === 'string' && item.length <= 4000 && !item.includes('\0'))
225
+ ? parsed
226
+ : undefined;
227
+ }
228
+ catch {
229
+ return undefined;
230
+ }
231
+ }
232
+ function indentation(line) {
233
+ return line.match(/^\s*/)?.[0].length || 0;
234
+ }
235
+ function collectNestedKeys(lines, start, parentIndent) {
236
+ const keys = [];
237
+ for (let index = start + 1; index < lines.length; index++) {
238
+ const line = lines[index];
239
+ if (!line.trim() || line.trim().startsWith('#'))
240
+ continue;
241
+ const indent = indentation(line);
242
+ if (indent <= parentIndent)
243
+ break;
244
+ const match = line.trim().match(/^([A-Za-z_][A-Za-z0-9_-]*):/);
245
+ if (match)
246
+ keys.push(match[1]);
247
+ }
248
+ return unique(keys).sort();
249
+ }
250
+ function findScalar(lines, start, end, key) {
251
+ for (let index = start; index < end; index++) {
252
+ const match = lines[index].trim().match(new RegExp(`^${key}:\\s*(.+)$`));
253
+ if (match)
254
+ return safeScalar(match[1]);
255
+ }
256
+ return undefined;
257
+ }
258
+ function discoverMcpCandidates(configPath) {
259
+ const text = readTextFile(configPath, MAX_CONFIG_BYTES);
260
+ if (text === undefined)
261
+ return [];
262
+ const lines = text.split(/\r?\n/);
263
+ const candidates = [];
264
+ for (let index = 0; index < lines.length; index++) {
265
+ if (!/^\s*name:\s*['"]?@deepseek-ai\/dsh-mcp-client['"]?\s*(?:#.*)?$/.test(lines[index]))
266
+ continue;
267
+ const itemIndent = (() => {
268
+ for (let cursor = index; cursor >= 0; cursor--)
269
+ if (/^\s*-\s+/.test(lines[cursor]))
270
+ return indentation(lines[cursor]);
271
+ return Math.max(0, indentation(lines[index]) - 2);
272
+ })();
273
+ let start = index;
274
+ while (start > 0 && !(indentation(lines[start]) === itemIndent && /^\s*-\s+/.test(lines[start])))
275
+ start--;
276
+ let end = index + 1;
277
+ while (end < lines.length && !(indentation(lines[end]) === itemIndent && /^\s*-\s+/.test(lines[end])))
278
+ end++;
279
+ const block = lines.slice(start, end);
280
+ const dynamicEndpoint = block.some(line => /^\s*(?:transport|command|url|args):.*(?:!!|process\.|\$\{|require\(|<%)/.test(line));
281
+ const serverName = findScalar(lines, start, end, 'serverName') || findScalar(lines, start, end, 'id') || `DSH MCP ${candidates.length + 1}`;
282
+ const transport = findScalar(lines, start, end, 'transport');
283
+ const command = findScalar(lines, start, end, 'command');
284
+ const url = findScalar(lines, start, end, 'url');
285
+ let args;
286
+ for (let cursor = start; cursor < end; cursor++) {
287
+ const match = lines[cursor].trim().match(/^args:\s*(.+)$/);
288
+ if (match)
289
+ args = inlineStringArray(match[1]);
290
+ }
291
+ const envIndex = lines.findIndex((line, cursor) => cursor >= start && cursor < end && /^\s*env:\s*$/.test(line));
292
+ const headerIndex = lines.findIndex((line, cursor) => cursor >= start && cursor < end && /^\s*headers:\s*$/.test(line));
293
+ const envKeys = envIndex >= 0 ? collectNestedKeys(lines, envIndex, indentation(lines[envIndex])) : [];
294
+ const headerKeys = headerIndex >= 0 ? collectNestedKeys(lines, headerIndex, indentation(lines[headerIndex])) : [];
295
+ const isHttp = transport === 'streamable-http' || transport === 'http';
296
+ const isStdio = !transport || transport === 'stdio';
297
+ const urlHasCredentials = (() => {
298
+ if (!isHttp || !url)
299
+ return false;
300
+ try {
301
+ const parsed = new URL(url);
302
+ return !!(parsed.username || parsed.password)
303
+ || Array.from(parsed.searchParams.keys()).some(key => /(?:api.?key|authorization|access.?token|secret|password|credential)/i.test(key));
304
+ }
305
+ catch {
306
+ return false;
307
+ }
308
+ })();
309
+ const argsContainCredentials = !!args && args.some((item, argIndex) => {
310
+ if (/(?:api.?key|authorization|access.?token|secret|password|credential)\s*[:=]\s*[^\s]/i.test(item))
311
+ return true;
312
+ return /^(?:--?|\/)(?:api[-_]?key|authorization|access[-_]?token|token|secret|password|credential)$/i.test(item)
313
+ && argIndex + 1 < args.length;
314
+ });
315
+ const sensitiveEndpoint = urlHasCredentials || argsContainCredentials;
316
+ const importable = !dynamicEndpoint && !sensitiveEndpoint && (isHttp ? !!url && /^https?:\/\//i.test(url) : isStdio && !!command);
317
+ const template = importable ? {
318
+ name: serverName,
319
+ enabled: false,
320
+ transport: isHttp ? 'http' : 'stdio',
321
+ command: isHttp ? undefined : command,
322
+ args: isHttp ? undefined : (args || []),
323
+ url: isHttp ? url : undefined,
324
+ } : undefined;
325
+ candidates.push({
326
+ name: serverName,
327
+ source: configPath,
328
+ importable,
329
+ reason: importable
330
+ ? undefined
331
+ : (dynamicEndpoint
332
+ ? 'Dynamic Cordis endpoint values are not evaluated; review this candidate in DSH.'
333
+ : (sensitiveEndpoint
334
+ ? 'Credentials embedded in an MCP URL or argument are not exposed; configure them manually with environment variables or headers.'
335
+ : 'No complete recognized static command or HTTP URL was found.')),
336
+ envKeys,
337
+ headerKeys,
338
+ template,
339
+ });
340
+ }
341
+ return candidates;
342
+ }
343
+ function workspaceBundleManifests(root) {
344
+ const output = [];
345
+ const ignored = new Set(['.git', 'node_modules', 'dist', 'release', 'archive', '.newmark-runtime', 'conversations']);
346
+ const visit = (directory, depth) => {
347
+ if (depth > 3 || output.length >= 256)
348
+ return;
349
+ const manifestPath = path.join(directory, 'package.json');
350
+ if (fileExists(manifestPath)) {
351
+ const manifest = readJson(manifestPath);
352
+ if (record(record(manifest?.dsh).bundle).patch)
353
+ output.push(manifestPath);
354
+ }
355
+ let entries = [];
356
+ try {
357
+ entries = fs.readdirSync(directory, { withFileTypes: true }).slice(0, MAX_DIRECTORY_ENTRIES);
358
+ }
359
+ catch {
360
+ return;
361
+ }
362
+ for (const entry of entries) {
363
+ if (!entry.isDirectory() || ignored.has(entry.name) || entry.name.startsWith('.'))
364
+ continue;
365
+ visit(path.join(directory, entry.name), depth + 1);
366
+ }
367
+ };
368
+ visit(root, 0);
369
+ return unique(output);
370
+ }
371
+ function discoverDshCompatibility(root, options = {}) {
372
+ const env = options.env || process.env;
373
+ const homeDir = options.homeDir || os.homedir();
374
+ const dshHome = path.resolve(String(env.DSH_HOME || '').trim() || path.join(homeDir, '.dsh'));
375
+ const homeSource = String(env.DSH_HOME || '').trim() ? 'DSH_HOME' : 'default';
376
+ const pathValue = options.pathValue ?? String(env.PATH || env.Path || '');
377
+ const cliPath = findDshCommand(pathValue, options.platform || process.platform);
378
+ const dshPackageManifest = packageManifestCandidates(root, dshHome, cliPath).find(fileExists);
379
+ const packageVersion = manifestVersion(dshPackageManifest);
380
+ const profiles = [];
381
+ const bundles = [];
382
+ const mcpCandidates = [];
383
+ const warnings = [
384
+ 'DSH is a developer preview. Newmark scans metadata only and does not install, update, import, execute, or rewrite DSH/plugin code.',
385
+ 'The @deepseek-ai/dsh update channel remains latest and unpinned; review compatibility warnings after every DSH update.',
386
+ ];
387
+ const unknownKeys = [];
388
+ const profileRoot = path.join(dshHome, 'profiles');
389
+ const homeConfigFiles = CONFIG_NAMES.map(name => path.join(dshHome, name)).filter(fileExists);
390
+ let profileEntries = [];
391
+ try {
392
+ profileEntries = fs.readdirSync(profileRoot, { withFileTypes: true });
393
+ }
394
+ catch { }
395
+ const directoryProfiles = profileEntries.filter(item => item.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
396
+ if (directoryProfiles.length > MAX_PROFILES)
397
+ warnings.push(`Only the first ${MAX_PROFILES} DSH profiles were inspected in this bounded read-only scan.`);
398
+ for (const entry of directoryProfiles.slice(0, MAX_PROFILES)) {
399
+ const source = path.join(profileRoot, entry.name);
400
+ const manifestPath = path.join(source, 'package.json');
401
+ const manifest = readJson(manifestPath);
402
+ if (!manifest) {
403
+ warnings.push(`Profile ${entry.name} has no readable package.json.`);
404
+ continue;
405
+ }
406
+ const dsh = record(manifest.dsh);
407
+ const profile = record(dsh.profile);
408
+ const rawBundles = Array.isArray(profile.bundles) ? profile.bundles : [];
409
+ const orderedBundles = rawBundles.map(bundleName).filter((name) => !!name);
410
+ const configFiles = CONFIG_NAMES.map(name => path.join(source, name)).filter(fileExists);
411
+ const layers = [];
412
+ const profileUnknown = unique(unknownPackageKeys(manifest).concat(unknownDshKeys(dsh), Object.keys(profile).filter(key => key !== 'bundles')));
413
+ profiles.push({
414
+ name: typeof manifest.name === 'string' ? manifest.name : entry.name,
415
+ source,
416
+ manifestPath,
417
+ bundles: orderedBundles,
418
+ unsupportedBundleEntries: Math.max(0, rawBundles.length - orderedBundles.length),
419
+ configFiles,
420
+ layers,
421
+ unknownKeys: profileUnknown,
422
+ });
423
+ unknownKeys.push(...profileUnknown.map(key => `${entry.name}:${key}`));
424
+ if (!Array.isArray(profile.bundles))
425
+ warnings.push(`Profile ${entry.name} does not expose dsh.profile.bundles as an array.`);
426
+ if (rawBundles.length !== orderedBundles.length)
427
+ warnings.push(`Profile ${entry.name} contains future or unsupported bundle entries; their order was not rewritten.`);
428
+ const dependencies = { ...record(manifest.dependencies), ...record(manifest.devDependencies), ...record(manifest.optionalDependencies) };
429
+ for (const name of orderedBundles) {
430
+ const candidates = dependencyPath(source, name, dependencies[name]);
431
+ const resolved = candidates.find(fileExists);
432
+ const snapshot = bundleSnapshot(name, resolved || candidates[0], source);
433
+ bundles.push(snapshot);
434
+ if (snapshot.patchPath && snapshot.patchExists) {
435
+ layers.push({ kind: 'bundle', name: snapshot.name, path: snapshot.patchPath, order: layers.length });
436
+ }
437
+ if (!snapshot.resolved)
438
+ warnings.push(`Bundle ${name} from profile ${entry.name} could not be resolved locally.`);
439
+ else if (!snapshot.patch)
440
+ warnings.push(`Bundle ${name} has no static dsh.bundle.patch declaration.`);
441
+ else if (!snapshot.patchExists)
442
+ warnings.push(`Bundle ${name} declares a missing patch file: ${snapshot.patch}`);
443
+ }
444
+ for (const configFile of configFiles) {
445
+ layers.push({ kind: 'profile', name: path.basename(configFile), path: configFile, order: layers.length });
446
+ }
447
+ for (const configFile of configFiles)
448
+ mcpCandidates.push(...discoverMcpCandidates(configFile));
449
+ }
450
+ for (const configFile of homeConfigFiles)
451
+ mcpCandidates.push(...discoverMcpCandidates(configFile));
452
+ for (const manifestPath of workspaceBundleManifests(root)) {
453
+ const manifest = readJson(manifestPath);
454
+ const name = typeof manifest?.name === 'string' ? manifest.name : path.basename(path.dirname(manifestPath));
455
+ if (!bundles.some(bundle => path.resolve(bundle.manifestPath) === path.resolve(manifestPath)))
456
+ bundles.push(bundleSnapshot(name, manifestPath, root));
457
+ }
458
+ for (const bundle of bundles) {
459
+ unknownKeys.push(...bundle.unknownKeys.map(key => `${bundle.name}:${key}`));
460
+ if (bundle.patchPath && bundle.patchExists)
461
+ mcpCandidates.push(...discoverMcpCandidates(bundle.patchPath));
462
+ }
463
+ if (!cliPath)
464
+ warnings.push('The dsh command was not found on PATH; this is informational and no command was executed.');
465
+ if (!dshPackageManifest)
466
+ warnings.push('@deepseek-ai/dsh was not found in the inspected local package roots.');
467
+ if (!profiles.length)
468
+ warnings.push(`No DSH profiles were found under ${profileRoot}.`);
469
+ const dedupedBundles = bundles.filter((bundle, index) => bundles.findIndex(other => path.resolve(other.manifestPath) === path.resolve(bundle.manifestPath)) === index);
470
+ const dedupedMcp = mcpCandidates.filter((candidate, index) => mcpCandidates.findIndex(other => other.name === candidate.name && other.source === candidate.source) === index);
471
+ const configFiles = unique(profiles.flatMap(profile => profile.configFiles).concat(dedupedBundles.flatMap(bundle => bundle.patchPath && bundle.patchExists ? [bundle.patchPath] : []), homeConfigFiles));
472
+ return {
473
+ id: 'deepseek-harness',
474
+ displayName: 'DeepSeek Harness (DSH)',
475
+ developerPreview: true,
476
+ detected: !!(cliPath || dshPackageManifest || directoryExists(dshHome) || profiles.length || dedupedBundles.length),
477
+ readOnly: true,
478
+ preservesUnknownFields: true,
479
+ dshHome,
480
+ home: { path: dshHome, source: homeSource, exists: directoryExists(dshHome) },
481
+ cli: { command: 'dsh', available: !!cliPath, path: cliPath, version: cliPath ? packageVersion : undefined, packageVersion },
482
+ package: { name: '@deepseek-ai/dsh', version: packageVersion, manifestPath: dshPackageManifest },
483
+ update: {
484
+ package: '@deepseek-ai/dsh',
485
+ channel: 'latest',
486
+ locked: false,
487
+ runCommand: 'npx @deepseek-ai/dsh web',
488
+ pluginCommand: 'dsh plugin --profile <name> add <package>',
489
+ repository: REPOSITORY,
490
+ documentation: DOCUMENTATION,
491
+ npm: NPM,
492
+ },
493
+ recognizedManifestKeys: ['dsh.bundle.patch', 'dsh.profile.bundles'],
494
+ profiles,
495
+ bundles: dedupedBundles,
496
+ mcpCandidates: dedupedMcp,
497
+ configFiles,
498
+ homeConfigFiles,
499
+ unknownKeys: unique(unknownKeys).sort(),
500
+ warnings: unique(warnings),
501
+ scannedAt: new Date().toISOString(),
502
+ compaction: dshCompactionRuntimeSemantics(),
503
+ toolLayer: dshToolLayerRuntimeSemantics(),
504
+ };
505
+ }
506
+ /**
507
+ * DSH dsh-compaction-basic 运行时 seam 到 Newmark 压缩系统的语义映射。
508
+ * 纯只读元数据:描述 DSH 各运行时入口如何映射到 Newmark 的原生等价实现,
509
+ * 既不 import 也不 execute 任何 DSH 插件代码。
510
+ */
511
+ function dshCompactionRuntimeSemantics() {
512
+ return {
513
+ plugin: '@deepseek-ai/dsh-compaction-basic',
514
+ execution: 'native-equivalent',
515
+ seams: {
516
+ apply: {
517
+ dsh: 'apply(ctx) 注册 automatic compaction(agent/pre-step 压力检测 + agent/request-error 溢出恢复)',
518
+ newmark: 'Agent.maybeCompress() + Agent.compressionBudget()(Build 70% / 长期 20% 触发)',
519
+ description: 'DSH 的 between-step 自动压缩注册机制,由 Newmark 原生 maybeCompress 承接。',
520
+ },
521
+ summarize: {
522
+ dsh: 'summarize(input, agent, signal) 单次摘要(复用主对话 system+tools+前缀消息命中 provider KV 缓存)',
523
+ newmark: 'Agent.compressMiddleMessages()(LLM 摘要 + localCompressionSummary 回退)',
524
+ description: 'DSH 的 prefix-cache 复用策略由 Newmark 以显式 system 前缀渲染承接(见 cacheReuse)。',
525
+ },
526
+ compactIfNeeded: {
527
+ dsh: 'compactIfNeeded(agent, trigger, signal) 压力/溢出触发,带重试回退',
528
+ newmark: 'Agent.maybeCompress(msgs, provider, signal, compressionModel, force)',
529
+ description: '触发判定 + 重试 + 阈值后置检查的运行时入口一一对应。',
530
+ },
531
+ compactNow: {
532
+ dsh: 'compactNow(agent, signal, sourceCommandId) 手工空闲会话压缩',
533
+ newmark: 'Agent.handleContextCompress()(context_compress 工具)',
534
+ description: 'DSH 的手工压缩命令入口对应 Newmark 的 context_compress/context_history_manage 工具。',
535
+ },
536
+ },
537
+ budget: {
538
+ buildBlockTriggerRatio: 0.70,
539
+ longHistoryTriggerRatio: 0.20,
540
+ buildRetainRatio: 0.16,
541
+ longHistoryRetainRatio: 0.05,
542
+ newmarkSource: 'Agent.compressionBudget(buildBlockTriggerTokens = maxTokens * 0.70, longHistoryTriggerTokens = maxTokens * 0.20)',
543
+ },
544
+ cacheReuse: {
545
+ dshStrategy: '压缩摘要调用重放主对话的 system prompt + tools + 前缀消息,仅把压缩指令作为最后一条 user 消息追加,复用 provider 的 warm prefix cache,避免 KV cache 失效。',
546
+ newmarkEquivalent: 'buildCompressionSummary 已落地 DSH 式前缀复用:system = buildSystemPrompt()(systemPromptCache 保证跨回合字节稳定),messages = 被压缩省略段原样前缀(含 tool/tool_calls,openAIChatMessages 自动修复工具配对) + 压缩指令尾 user 消息;历史图片降级为占位文本以保持前缀一致。',
547
+ note: '缓存命中来自 system 前缀稳定 + 省略段消息前缀复用两层;主对话的额外 bootstrap 段(第一次请求/压缩后各注入一次)不参与摘要前缀,因 provider 按连续前缀缓存,省略段消息前缀的命中已覆盖主要 token。',
548
+ },
549
+ toolPruning: {
550
+ dsh: 'ctx.get("toolResultPruner").pruneSession(session):压缩前先裁剪会话中的大工具结果,再测是否仍需压缩。',
551
+ newmark: 'buildCompressionSummary 在构建前缀消息时,对 role=tool/function 且 content 超过 TOOL_RESULT_PRUNE_CHARS(8000) 的结果调用 pruneToolResultContent() 裁剪为「头部结论 + 尾部证据」,避免巨型 read/grep/terminal 输出整段重放给摘要模型。',
552
+ thresholdChars: 8000,
553
+ },
554
+ };
555
+ }
556
+ /**
557
+ * DSH 工具层的运行时语义映射(纯只读元数据)。
558
+ * 描述 DSH 工具层各 seam 如何映射到 Newmark 原生工具执行层,并声明破坏性
559
+ * developer-preview schema 更新的 fail-soft 兼容策略。既不 import 也不 execute
560
+ * 任何 DSH 插件代码。
561
+ */
562
+ function dshToolLayerRuntimeSemantics() {
563
+ return {
564
+ plugin: '@deepseek-ai/dsh-tools',
565
+ execution: 'native-equivalent',
566
+ seams: {
567
+ register: {
568
+ dsh: 'defineTool(schema, execute, { isConcurrencySafe, presentCall, presentResult }) + ToolRuntime.register(definition)',
569
+ newmark: 'ToolExecutor.execute(name, args, wsPath, context) + compat.legacyToolToNewmark(def) + compat.inferSideEffects(name)',
570
+ description: 'DSH 的工具定义/注册运行时入口对应 Newmark 的 ToolExecutor + compat 工具规范化与副作用推断。',
571
+ },
572
+ concurrency: {
573
+ dsh: 'isConcurrencySafe(args): boolean 运行时分类,仅 true 才允许与兄弟调用并行;exclusive 形成屏障',
574
+ newmark: 'isConcurrencySafeTool(name) + AgentTool.concurrencySafe + agent-loop.executeToolCalls 分级调度(只读工具并行,副作用工具独占串行)',
575
+ description: 'DSH 的并发安全分级已落地为 Newmark 的 concurrencySafe 字段与分级调度器,避免盲目 Promise.all 导致副作用工具竞态。',
576
+ },
577
+ presentation: {
578
+ dsh: 'ToolPresentationMode: native(逐工具 schema)/ code(run_code 批量内联)/ both',
579
+ newmark: 'Newmark 原生 native 工具循环(chatStreamWithTools + 内联 toolResult 有界截断 boundInlineToolResult)',
580
+ description: 'Newmark 保持 native 呈现;DSH 的 code-mode 批量内联思想以内联工具结果有界截断承接,避免巨型结果撑爆 context。',
581
+ },
582
+ pluginDiscovery: {
583
+ dsh: 'cordis plugin loader 加载工具层插件(defineTool 注册)',
584
+ newmark: 'compat.discoverPluginManifests(root) 发现 components.tools;runOpenCodeTool 执行 OpenCode 工具',
585
+ description: 'DSH 工具层插件由 Newmark 的插件清单发现层以只读元数据承接;只有 OpenCode JS 工具经 compat-tool 显式执行。',
586
+ },
587
+ },
588
+ breakingChangeCompat: {
589
+ strategy: 'DSH 是 developer preview,manifest/tool schema 可能不兼容变更。Newmark 保持 fail-soft:每个 seam 独立版本化,未识别字段一律保留为元数据并降级为 opaque 展示,绝不因 DSH schema 演进而抛错、拒绝启动或改写外部 DSH 文件。',
590
+ mechanisms: [
591
+ 'unknownKeys 全量保留并上报(dshCompatibility 的 preservesUnknownFields: true + unknownKeys 数组)',
592
+ 'unresolved/未来 bundle 条目降级为 unsupportedBundleEntries 计数而非失败',
593
+ '动态 !!js / 凭据承载的 MCP 端点判为不可导入并附 reason,而非执行或暴露',
594
+ '工具层映射(register/concurrency/presentation)是元数据描述,不绑定 DSH 精确 schema,DSH 更新只增删描述不破坏 Newmark 运行',
595
+ ],
596
+ boundary: 'Newmark 永不 import/require/execute/spawn DSH 插件 main 模块或可执行标签,永不 install/update/rewrite DSH 文件;官方 dsh 命令是唯一写路径。',
597
+ },
598
+ };
599
+ }
600
+ //# sourceMappingURL=dshCompatibility.js.map
@@ -95,6 +95,10 @@ export declare class ElectronUtilityAgentClient {
95
95
  requestStop(runId?: string): Promise<UtilityAgentStopResult>;
96
96
  enqueueGuide(envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
97
97
  checkpoint(): Promise<Record<string, unknown>>;
98
+ contextCompress(options?: {
99
+ keepRecent?: number;
100
+ force?: boolean;
101
+ }): Promise<Record<string, unknown>>;
98
102
  rateAutoRoute(score: number, routeId?: string): Promise<UtilityAutoRouteRatingResult>;
99
103
  setWorkRunExpanded(runId: string, expanded: boolean): Promise<boolean>;
100
104
  setMode(mode: AgentMode): Promise<AgentMode>;
@@ -1027,6 +1027,10 @@ class ElectronUtilityAgentClient {
1027
1027
  await this.start();
1028
1028
  return await this.request('checkpoint', { target: this.target }, 5_000);
1029
1029
  }
1030
+ async contextCompress(options = {}) {
1031
+ await this.start();
1032
+ return await this.request('context_compress', { target: this.target, options }, 120_000);
1033
+ }
1030
1034
  async rateAutoRoute(score, routeId = '') {
1031
1035
  await this.start();
1032
1036
  return await this.request('rate_auto_route', {
@@ -11,6 +11,10 @@ export interface ElectronTargetRuntimeClient {
11
11
  requestStop(runId?: string): Promise<UtilityAgentStopResult>;
12
12
  enqueueGuide(envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
13
13
  checkpoint(): Promise<Record<string, unknown>>;
14
+ contextCompress?(options?: {
15
+ keepRecent?: number;
16
+ force?: boolean;
17
+ }): Promise<Record<string, unknown>>;
14
18
  rateAutoRoute?(score: number, routeId?: string): Promise<UtilityAutoRouteRatingResult>;
15
19
  setWorkRunExpanded(runId: string, expanded: boolean): Promise<boolean>;
16
20
  setMode?(mode: AgentMode): Promise<AgentMode>;
@@ -67,6 +71,10 @@ export declare class ElectronUtilityRuntimePool {
67
71
  requestStop(target: ConversationRuntimeTarget, runId?: string): Promise<ElectronPoolStopResult>;
68
72
  enqueueGuide(envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
69
73
  checkpoint(target: ConversationRuntimeTarget): Promise<Record<string, unknown>>;
74
+ contextCompress(target: ConversationRuntimeTarget, options?: {
75
+ keepRecent?: number;
76
+ force?: boolean;
77
+ }): Promise<Record<string, unknown>>;
70
78
  rateAutoRoute(target: ConversationRuntimeTarget, score: number, routeId?: string): Promise<UtilityAutoRouteRatingResult>;
71
79
  setWorkRunExpanded(target: ConversationRuntimeTarget, runId: string, expanded: boolean): Promise<boolean>;
72
80
  setInputMode(target: ConversationRuntimeTarget, mode: string): Promise<'guide' | 'next' | null>;
@@ -203,6 +203,20 @@ class ElectronUtilityRuntimePool {
203
203
  this.release(entry, true);
204
204
  }
205
205
  }
206
+ async contextCompress(target, options = {}) {
207
+ const entry = await this.acquire((0, conversationTarget_1.normalizeConversationTarget)(target));
208
+ try {
209
+ if (entry.stopIntent)
210
+ return { ok: false, error: 'Context compression is unavailable while this conversation is stopping.' };
211
+ if (!entry.client.contextCompress)
212
+ return { ok: false, error: 'Context compression is unavailable in this runtime.' };
213
+ entry.lastSnapshot = null;
214
+ return await entry.client.contextCompress(options);
215
+ }
216
+ finally {
217
+ this.release(entry, true);
218
+ }
219
+ }
206
220
  async rateAutoRoute(target, score, routeId = '') {
207
221
  const normalized = (0, conversationTarget_1.normalizeConversationTarget)(target);
208
222
  const entry = await this.acquireExisting(normalized);