lody 0.84.0 → 0.86.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/chunks/{directory-handle-OPjjCl3O.js → directory-handle-Bp47LF5g.js} +37 -35
- package/dist/chunks/{index-ddMw90Gr.js → index-Dd0J9MIK.js} +173 -210
- package/dist/chunks/methods-CvEDMahD.js +19 -0
- package/dist/chunks/{profile-RfMzWliN.js → profile-Cxxl5hCq.js} +18 -7
- package/dist/chunks/{review-viewer-BZC6lRid.js → review-viewer-DE7MFi1P.js} +6 -5
- package/dist/chunks/runtime-manifest-ByWJfM07.js +9 -0
- package/dist/claude-acp.js +347 -160
- package/dist/codex-acp.js +1 -1
- package/dist/deepseek-acp.js +222 -45
- package/dist/deepseek-agent-presets/code/agent.cordis.yml +4 -3
- package/dist/deepseek-agent-presets/cordis/agent.cordis.yml +4 -3
- package/dist/deepseek-agent-presets/cordis/skills/editing-cordis-compositions/SKILL.md +13 -2
- package/dist/deepseek-agent-presets/minimal/agent.cordis.yml +27 -1
- package/dist/deepseek-agent-presets/standard/agent.cordis.yml +4 -3
- package/dist/file-index-scan-worker.js +1 -1
- package/dist/grok-acp.js +284 -46
- package/dist/index.js +2474 -964
- package/package.json +2 -2
- package/dist/chunks/runtime-manifest-Fr5DEH54.js +0 -9
package/dist/codex-acp.js
CHANGED
package/dist/deepseek-acp.js
CHANGED
|
@@ -2,17 +2,22 @@ import { randomUUID, createHash } from "node:crypto";
|
|
|
2
2
|
import { isAbsolute } from "node:path";
|
|
3
3
|
import { Readable, Writable } from "node:stream";
|
|
4
4
|
import { n as ndJsonStream, A as AgentSideConnection, R as RequestError, P as PROTOCOL_VERSION } from "./chunks/acp-CrvzLY5A.js";
|
|
5
|
-
import {
|
|
5
|
+
import { D as DEEPSEEK_HARNESS_PERMISSION_MODES, c as DEEPSEEK_HARNESS_REASONING_OPTIONS, e as ACP_EXTENSION_DSH_VERSION, a as DEEPSEEK_HARNESS_AGENT_PRESETS } from "./chunks/profile-Cxxl5hCq.js";
|
|
6
6
|
import "./chunks/schemas-Du3qLZPS.js";
|
|
7
7
|
const name = "acp-extension-dsh";
|
|
8
8
|
const inject = [
|
|
9
9
|
"agents",
|
|
10
10
|
"agentPresets",
|
|
11
|
+
"attachments",
|
|
11
12
|
"loader",
|
|
13
|
+
"llm",
|
|
12
14
|
"permissionPresets",
|
|
13
15
|
"sessionPersistence",
|
|
14
16
|
"sessionQuery"
|
|
15
17
|
];
|
|
18
|
+
const LODY_CAPABILITIES = {
|
|
19
|
+
compaction: { version: 1 }
|
|
20
|
+
};
|
|
16
21
|
const MODEL_CONFIG_ID = "model";
|
|
17
22
|
const MODE_CONFIG_ID = "mode";
|
|
18
23
|
const REASONING_EFFORT_CONFIG_ID = "reasoning_effort";
|
|
@@ -22,7 +27,24 @@ const MCP_TOOL_CALL_TIMEOUT_MS = 6e4;
|
|
|
22
27
|
const MCP_SERVER_NAME_MAX_LENGTH = 32;
|
|
23
28
|
const MCP_SERVER_NAME_HASH_LENGTH = 8;
|
|
24
29
|
const INVALID_MCP_SERVER_NAME_CHARS = /[^A-Za-z0-9_-]/gu;
|
|
25
|
-
const
|
|
30
|
+
const IMAGE_MEDIA_TYPES = [
|
|
31
|
+
"image/png",
|
|
32
|
+
"image/jpeg",
|
|
33
|
+
"image/webp",
|
|
34
|
+
"image/gif"
|
|
35
|
+
];
|
|
36
|
+
const CANONICAL_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
|
|
37
|
+
const IMAGE_ADMISSION_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
38
|
+
"TOO_MANY_IMAGES",
|
|
39
|
+
"IMAGES_TOO_LARGE",
|
|
40
|
+
"UNSUPPORTED_IMAGE_TYPE",
|
|
41
|
+
"INVALID_IMAGE_BASE64",
|
|
42
|
+
"INVALID_IMAGE",
|
|
43
|
+
"IMAGE_TYPE_MISMATCH",
|
|
44
|
+
"IMAGE_TOO_LARGE",
|
|
45
|
+
"IMAGE_TOO_MANY_PIXELS",
|
|
46
|
+
"IMAGE_DIMENSION_TOO_LARGE"
|
|
47
|
+
]);
|
|
26
48
|
const PERMISSION_MODE_IDS = new Set(DEEPSEEK_HARNESS_PERMISSION_MODES.map((mode) => mode.id));
|
|
27
49
|
const REASONING_EFFORT_IDS = new Set(DEEPSEEK_HARNESS_REASONING_OPTIONS.map((effort) => effort.value));
|
|
28
50
|
function invalidParams(detail) {
|
|
@@ -38,9 +60,6 @@ function resolveAdapterConfig(config) {
|
|
|
38
60
|
const provider = nonEmptyString(config?.provider, "deepseek-official");
|
|
39
61
|
const model = nonEmptyString(config?.model, "deepseek-v4-pro");
|
|
40
62
|
const reasoningEffort = config?.reasoningEffort ?? "max";
|
|
41
|
-
if (!MODEL_IDS.has(model)) {
|
|
42
|
-
throw new Error(`acp-extension-dsh: unsupported model ${JSON.stringify(model)}`);
|
|
43
|
-
}
|
|
44
63
|
if (!REASONING_EFFORT_IDS.has(reasoningEffort)) {
|
|
45
64
|
throw new Error(`acp-extension-dsh: unsupported reasoning effort ${JSON.stringify(reasoningEffort)}`);
|
|
46
65
|
}
|
|
@@ -51,6 +70,27 @@ function resolveAdapterConfig(config) {
|
|
|
51
70
|
...config?.stream ? { stream: config.stream } : {}
|
|
52
71
|
};
|
|
53
72
|
}
|
|
73
|
+
async function loadHarnessModels(ctx, provider) {
|
|
74
|
+
const llm = ctx.get("llm");
|
|
75
|
+
if (!llm)
|
|
76
|
+
throw new Error("acp-extension-dsh: no Harness LLM catalog is mounted");
|
|
77
|
+
const listed = await llm.listModels(provider);
|
|
78
|
+
const models = [];
|
|
79
|
+
const ids = /* @__PURE__ */ new Set();
|
|
80
|
+
for (const model of listed) {
|
|
81
|
+
if (model.provider !== provider || !model.id.trim())
|
|
82
|
+
continue;
|
|
83
|
+
if (ids.has(model.id)) {
|
|
84
|
+
throw new Error(`acp-extension-dsh: duplicate model ${JSON.stringify(model.id)} for provider ${JSON.stringify(provider)}`);
|
|
85
|
+
}
|
|
86
|
+
ids.add(model.id);
|
|
87
|
+
models.push({
|
|
88
|
+
...model,
|
|
89
|
+
...model.inputModalities ? { inputModalities: [...model.inputModalities] } : {}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return models;
|
|
93
|
+
}
|
|
54
94
|
async function loadMcpClientPlugin(agentContext) {
|
|
55
95
|
const module = agentContext.loader.unwrapExports(await agentContext.loader.import(MCP_CLIENT_PACKAGE));
|
|
56
96
|
if (typeof module !== "object" || module === null || !("apply" in module) || typeof module.apply !== "function") {
|
|
@@ -202,9 +242,9 @@ function configOptions(record) {
|
|
|
202
242
|
category: "model",
|
|
203
243
|
type: "select",
|
|
204
244
|
currentValue: record.selection.current.model,
|
|
205
|
-
options:
|
|
206
|
-
value: model.
|
|
207
|
-
name: model.name,
|
|
245
|
+
options: record.models.map((model) => ({
|
|
246
|
+
value: model.id,
|
|
247
|
+
name: model.name ?? model.id,
|
|
208
248
|
description: model.description ?? null
|
|
209
249
|
}))
|
|
210
250
|
},
|
|
@@ -233,28 +273,97 @@ function modeState(record) {
|
|
|
233
273
|
}))
|
|
234
274
|
};
|
|
235
275
|
}
|
|
236
|
-
function
|
|
237
|
-
return
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
276
|
+
function modelSupportsImages(models, modelId) {
|
|
277
|
+
return models.some((model) => model.id === modelId && model.inputModalities?.includes("image"));
|
|
278
|
+
}
|
|
279
|
+
function imageMediaType(value) {
|
|
280
|
+
return IMAGE_MEDIA_TYPES.includes(value) ? value : void 0;
|
|
281
|
+
}
|
|
282
|
+
function decodePromptImage(block) {
|
|
283
|
+
const mediaType = imageMediaType(block.mimeType);
|
|
284
|
+
if (!mediaType) {
|
|
285
|
+
throw invalidParams("image mimeType must be image/png, image/jpeg, image/webp, or image/gif");
|
|
286
|
+
}
|
|
287
|
+
if (!block.data || !CANONICAL_BASE64.test(block.data)) {
|
|
288
|
+
throw invalidParams("image data must be canonical base64");
|
|
289
|
+
}
|
|
290
|
+
const decoded = Buffer.from(block.data, "base64");
|
|
291
|
+
if (decoded.toString("base64") !== block.data) {
|
|
292
|
+
throw invalidParams("image data must be canonical base64");
|
|
293
|
+
}
|
|
294
|
+
return { data: new Uint8Array(decoded), mediaType };
|
|
295
|
+
}
|
|
296
|
+
function isImageAdmissionError(error) {
|
|
297
|
+
return error instanceof Error && "code" in error && typeof error.code === "string" && IMAGE_ADMISSION_ERROR_CODES.has(error.code);
|
|
298
|
+
}
|
|
299
|
+
async function admitAcpPrompt(prompt, models, modelId, attachments) {
|
|
300
|
+
const images = [];
|
|
301
|
+
for (const block of prompt) {
|
|
302
|
+
switch (block.type) {
|
|
303
|
+
case "text":
|
|
304
|
+
case "resource_link":
|
|
305
|
+
break;
|
|
306
|
+
case "image":
|
|
307
|
+
if (!modelSupportsImages(models, modelId)) {
|
|
308
|
+
throw invalidParams(`model ${JSON.stringify(modelId)} does not support image input`);
|
|
309
|
+
}
|
|
310
|
+
images.push(decodePromptImage(block));
|
|
311
|
+
break;
|
|
312
|
+
case "audio":
|
|
313
|
+
throw invalidParams("audio prompt content is not supported");
|
|
314
|
+
case "resource":
|
|
315
|
+
throw invalidParams("embedded resource prompt content is not supported");
|
|
316
|
+
default:
|
|
317
|
+
throw invalidParams("unsupported ACP prompt content");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
let refs = [];
|
|
321
|
+
if (images.length > 0) {
|
|
322
|
+
if (!attachments)
|
|
323
|
+
throw internalError("no Harness attachment store is mounted");
|
|
324
|
+
try {
|
|
325
|
+
refs = await attachments.saveImages(images);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (isImageAdmissionError(error))
|
|
328
|
+
throw invalidParams(error.message);
|
|
329
|
+
throw internalError("unable to persist the prompt image batch");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const content = [];
|
|
333
|
+
let pendingText = "";
|
|
334
|
+
let imageIndex = 0;
|
|
335
|
+
const flushText = () => {
|
|
336
|
+
if (!pendingText)
|
|
337
|
+
return;
|
|
338
|
+
content.push({ type: "text", text: pendingText });
|
|
339
|
+
pendingText = "";
|
|
340
|
+
};
|
|
341
|
+
for (const block of prompt) {
|
|
342
|
+
if (block.type === "text") {
|
|
343
|
+
pendingText += block.text;
|
|
344
|
+
} else if (block.type === "resource_link") {
|
|
345
|
+
pendingText += `
|
|
243
346
|
[resource_link name=${JSON.stringify(block.name)} uri=${JSON.stringify(block.uri)}]
|
|
244
|
-
|
|
245
|
-
|
|
347
|
+
`;
|
|
348
|
+
} else if (block.type === "image") {
|
|
349
|
+
flushText();
|
|
350
|
+
const attachment = refs[imageIndex++];
|
|
351
|
+
if (!attachment)
|
|
352
|
+
throw internalError("the attachment store returned an incomplete image batch");
|
|
353
|
+
content.push({ type: "image", attachment });
|
|
246
354
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
355
|
+
}
|
|
356
|
+
flushText();
|
|
357
|
+
if (!content.some((block) => block.type === "image" || block.type === "text" && block.text.trim().length > 0)) {
|
|
358
|
+
throw invalidParams("empty prompt");
|
|
359
|
+
}
|
|
360
|
+
return content;
|
|
252
361
|
}
|
|
253
|
-
function createUserMessage(
|
|
362
|
+
function createUserMessage(id, content) {
|
|
254
363
|
return Object.freeze({
|
|
255
|
-
id
|
|
364
|
+
id,
|
|
256
365
|
role: "user",
|
|
257
|
-
content:
|
|
366
|
+
content: Object.freeze(content.map((block) => Object.freeze(block))),
|
|
258
367
|
source: Object.freeze({ kind: "user" })
|
|
259
368
|
});
|
|
260
369
|
}
|
|
@@ -412,6 +521,40 @@ function apply(ctx, rawConfig) {
|
|
|
412
521
|
});
|
|
413
522
|
}
|
|
414
523
|
}
|
|
524
|
+
} else if (event.type === "compaction/start" && event.data.compactionId) {
|
|
525
|
+
const activity = {
|
|
526
|
+
version: 1,
|
|
527
|
+
kind: "context_compaction",
|
|
528
|
+
automatic: event.data.turn !== null
|
|
529
|
+
};
|
|
530
|
+
notify({
|
|
531
|
+
sessionId: record.agent.session.id,
|
|
532
|
+
update: {
|
|
533
|
+
sessionUpdate: "tool_call",
|
|
534
|
+
toolCallId: `context-compaction:${event.data.compactionId}`,
|
|
535
|
+
title: "Compacting context",
|
|
536
|
+
kind: "think",
|
|
537
|
+
status: "in_progress",
|
|
538
|
+
_meta: { lody: { activity } }
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
} else if (event.type === "compaction/end" && event.data.compactionId) {
|
|
542
|
+
const activity = {
|
|
543
|
+
version: 1,
|
|
544
|
+
kind: "context_compaction",
|
|
545
|
+
automatic: event.data.turn !== null,
|
|
546
|
+
...event.data.error ? { failureReason: event.data.error } : {}
|
|
547
|
+
};
|
|
548
|
+
notify({
|
|
549
|
+
sessionId: record.agent.session.id,
|
|
550
|
+
update: {
|
|
551
|
+
sessionUpdate: "tool_call_update",
|
|
552
|
+
toolCallId: `context-compaction:${event.data.compactionId}`,
|
|
553
|
+
title: event.data.error ? "Context compaction failed" : "Context compacted",
|
|
554
|
+
status: event.data.error ? "failed" : "completed",
|
|
555
|
+
_meta: { lody: { activity } }
|
|
556
|
+
}
|
|
557
|
+
});
|
|
415
558
|
}
|
|
416
559
|
} finally {
|
|
417
560
|
const inflight = record.inflight;
|
|
@@ -482,7 +625,7 @@ function apply(ctx, rawConfig) {
|
|
|
482
625
|
throw invalidParams(`failed to select agent preset ${JSON.stringify(value)}: ${errorChain(error)}`);
|
|
483
626
|
});
|
|
484
627
|
} else if (params.configId === MODEL_CONFIG_ID) {
|
|
485
|
-
assertAllowed(value,
|
|
628
|
+
assertAllowed(value, new Set(record.models.map((model) => model.id)), "model");
|
|
486
629
|
record.selection.current = { ...record.selection.current, model: value };
|
|
487
630
|
} else if (params.configId === REASONING_EFFORT_CONFIG_ID) {
|
|
488
631
|
assertAllowed(value, REASONING_EFFORT_IDS, "reasoning effort");
|
|
@@ -498,17 +641,23 @@ function apply(ctx, rawConfig) {
|
|
|
498
641
|
const makeAgent = (connection) => {
|
|
499
642
|
conn = connection;
|
|
500
643
|
return {
|
|
501
|
-
initialize(_params) {
|
|
502
|
-
|
|
644
|
+
async initialize(_params) {
|
|
645
|
+
const models = await loadHarnessModels(ctx, config.provider);
|
|
646
|
+
return {
|
|
503
647
|
protocolVersion: PROTOCOL_VERSION,
|
|
504
648
|
agentInfo: { name: "acp-extension-dsh", version: ACP_EXTENSION_DSH_VERSION },
|
|
505
649
|
agentCapabilities: {
|
|
506
|
-
promptCapabilities: {
|
|
650
|
+
promptCapabilities: {
|
|
651
|
+
image: models.some((model) => modelSupportsImages(models, model.id)),
|
|
652
|
+
audio: false,
|
|
653
|
+
embeddedContext: false
|
|
654
|
+
},
|
|
507
655
|
mcpCapabilities: { http: true },
|
|
508
|
-
sessionCapabilities: { close: {} }
|
|
656
|
+
sessionCapabilities: { close: {} },
|
|
657
|
+
_meta: { lody: LODY_CAPABILITIES }
|
|
509
658
|
},
|
|
510
659
|
authMethods: []
|
|
511
|
-
}
|
|
660
|
+
};
|
|
512
661
|
},
|
|
513
662
|
authenticate(_params) {
|
|
514
663
|
return Promise.resolve();
|
|
@@ -516,6 +665,12 @@ function apply(ctx, rawConfig) {
|
|
|
516
665
|
async newSession(params) {
|
|
517
666
|
assertOpen();
|
|
518
667
|
validateSessionParams(params);
|
|
668
|
+
let models;
|
|
669
|
+
try {
|
|
670
|
+
models = await loadHarnessModels(ctx, config.provider);
|
|
671
|
+
} catch (error) {
|
|
672
|
+
throw internalError(`failed to list models: ${errorChain(error)}`);
|
|
673
|
+
}
|
|
519
674
|
const sessionId = randomUUID();
|
|
520
675
|
const selection = {
|
|
521
676
|
current: {
|
|
@@ -575,13 +730,22 @@ function apply(ctx, rawConfig) {
|
|
|
575
730
|
permissionMode,
|
|
576
731
|
agentPreset: mountedPreset,
|
|
577
732
|
agentPresetOptions,
|
|
733
|
+
models,
|
|
578
734
|
started: false
|
|
579
735
|
};
|
|
580
736
|
sessions.set(sessionId, record);
|
|
581
737
|
return {
|
|
582
738
|
sessionId,
|
|
583
739
|
modes: modeState(record),
|
|
584
|
-
configOptions: configOptions(record)
|
|
740
|
+
configOptions: configOptions(record),
|
|
741
|
+
models: {
|
|
742
|
+
currentModelId: record.selection.current.model,
|
|
743
|
+
availableModels: record.models.map((model) => ({
|
|
744
|
+
modelId: model.id,
|
|
745
|
+
name: model.name ?? model.id,
|
|
746
|
+
description: model.description ?? null
|
|
747
|
+
}))
|
|
748
|
+
}
|
|
585
749
|
};
|
|
586
750
|
},
|
|
587
751
|
setSessionMode(params) {
|
|
@@ -596,20 +760,29 @@ function apply(ctx, rawConfig) {
|
|
|
596
760
|
const record = requireSession(params.sessionId);
|
|
597
761
|
if (record.inflight)
|
|
598
762
|
throw invalidParams("a prompt is already in flight for this session");
|
|
599
|
-
if (promptHasUnsupportedContent(params.prompt)) {
|
|
600
|
-
throw invalidParams("only text and resource_link prompt content is supported");
|
|
601
|
-
}
|
|
602
|
-
const text = acpPromptToText(params.prompt);
|
|
603
|
-
if (!text.trim())
|
|
604
|
-
throw invalidParams("empty prompt");
|
|
605
763
|
if (ctx.agents.get(record.agent.id) !== record.agent) {
|
|
606
764
|
throw internalError("prompt was not queued: the agent was disposed outside the bridge");
|
|
607
765
|
}
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
766
|
+
const attachments = ctx.get("attachments");
|
|
767
|
+
const messageId = randomUUID();
|
|
768
|
+
let resolvePrompt;
|
|
769
|
+
let rejectPrompt;
|
|
770
|
+
const completion = new Promise((resolve, reject) => {
|
|
771
|
+
resolvePrompt = resolve;
|
|
772
|
+
rejectPrompt = reject;
|
|
773
|
+
});
|
|
774
|
+
const inflight = {
|
|
775
|
+
resolve: resolvePrompt,
|
|
776
|
+
reject: rejectPrompt,
|
|
777
|
+
messageId
|
|
778
|
+
};
|
|
779
|
+
record.inflight = inflight;
|
|
780
|
+
try {
|
|
781
|
+
const content = await admitAcpPrompt(params.prompt, record.models, record.selection.current.model, attachments);
|
|
782
|
+
if (record.inflight !== inflight)
|
|
783
|
+
return { stopReason: await completion };
|
|
784
|
+
const message = createUserMessage(messageId, content);
|
|
785
|
+
record.started = true;
|
|
613
786
|
try {
|
|
614
787
|
record.agent.followup(message);
|
|
615
788
|
} catch (error) {
|
|
@@ -624,8 +797,12 @@ function apply(ctx, rawConfig) {
|
|
|
624
797
|
const end = inflight.endReason;
|
|
625
798
|
inflight.resolve(end ? end.kind === "max-tokens" ? "end_turn" : turnEndToStopReason(end) : "cancelled");
|
|
626
799
|
});
|
|
627
|
-
})
|
|
628
|
-
|
|
800
|
+
} catch (error) {
|
|
801
|
+
if (record.inflight === inflight)
|
|
802
|
+
record.inflight = void 0;
|
|
803
|
+
throw error;
|
|
804
|
+
}
|
|
805
|
+
return { stopReason: await completion };
|
|
629
806
|
},
|
|
630
807
|
cancel(params) {
|
|
631
808
|
const record = sessions.get(params.sessionId);
|
|
@@ -198,9 +198,10 @@
|
|
|
198
198
|
toolName: subagent_fork
|
|
199
199
|
backgroundMode: continuable
|
|
200
200
|
|
|
201
|
-
# Production dsh does not install these optional providers.
|
|
202
|
-
#
|
|
203
|
-
#
|
|
201
|
+
# Production dsh does not install these optional providers. Install the
|
|
202
|
+
# matching Bundle in this Profile and restart the Host, then copy this
|
|
203
|
+
# preset and remove `disabled` from the matching tool row. Host availability
|
|
204
|
+
# alone grants no tool.
|
|
204
205
|
- id: tool-subagent-codex
|
|
205
206
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
206
207
|
disabled: true
|
|
@@ -185,9 +185,10 @@
|
|
|
185
185
|
toolName: subagent_fork
|
|
186
186
|
backgroundMode: continuable
|
|
187
187
|
|
|
188
|
-
# Production dsh does not install these optional providers.
|
|
189
|
-
#
|
|
190
|
-
#
|
|
188
|
+
# Production dsh does not install these optional providers. Install the
|
|
189
|
+
# matching Bundle in this Profile and restart the Host, then copy this
|
|
190
|
+
# preset and remove `disabled` from the matching tool row. Host availability
|
|
191
|
+
# alone grants no tool.
|
|
191
192
|
- id: tool-subagent-codex
|
|
192
193
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
193
194
|
disabled: true
|
|
@@ -123,7 +123,16 @@ After a clean mount-validation, ask the user to start a session on the new prese
|
|
|
123
123
|
|
|
124
124
|
## Native product subagents
|
|
125
125
|
|
|
126
|
-
Codex and Claude Code providers
|
|
126
|
+
Codex and Claude Code providers are independent optional Profile Bundles. Install only the products a Profile needs, then restart the Profile so its Host registers those providers:
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
dsh plugin --profile <name> add @deepseek-ai/dsh-subagent-codex
|
|
130
|
+
dsh plugin --profile <name> add @deepseek-ai/dsh-subagent-claude-code
|
|
131
|
+
dsh plugin --profile <name> remove @deepseek-ai/dsh-subagent-codex
|
|
132
|
+
dsh plugin --profile <name> remove @deepseek-ai/dsh-subagent-claude-code
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Each Bundle owns its Host availability; the preset separately grants one Agent its ordinary delegation tool. Never move a product provider into the preset and never add a product-specific settings field. Removing one package withdraws only that provider on the next Profile start.
|
|
127
136
|
|
|
128
137
|
Copy these disabled templates from a shipped full preset and remove `disabled` only for the products the user requested:
|
|
129
138
|
|
|
@@ -147,7 +156,9 @@ Copy these disabled templates from a shipped full preset and remove `disabled` o
|
|
|
147
156
|
maxDepth: provider-managed
|
|
148
157
|
```
|
|
149
158
|
|
|
150
|
-
|
|
159
|
+
For additional named Codex or Claude Code instances, mount a separate host-plane provider row for each instance with a unique `providerName`, then add a separate preset tool row whose `provider` exactly matches that name and whose `toolName` is also unique. Keep the shipped rows for the default `codex` and `claude-code` names; do not reuse one tool row for several providers or derive either name from permission or environment settings.
|
|
160
|
+
|
|
161
|
+
The two rows are independent. Leaving both disabled preserves the copied preset, enabling one exposes only that product tool, and enabling both exposes both. Production `dsh` does not install either optional provider: before enabling a row, install the matching `@deepseek-ai/dsh-subagent-codex` or `@deepseek-ai/dsh-subagent-claude-code` Bundle in the Profile and restart it. Each Bundle registers its dormant default provider and exclusively uses its pinned package-local platform CLI; additional named instances use extra host-plane rows from the same installed package. A preset cannot provide that host dependency. `backgroundMode: one-shot` keeps omitted or `false` calls in the foreground and lets explicit `run_in_background: true` return a generic Job id. Full presets already carry `tool-jobs`, while the base host carries the job registry; retain both so `job_output`, `job_list`, `job_kill`, cancellation, and completion notices stay available. Installing a Bundle or composing a preset row does not start a product, authenticate an account, select a model, probe credentials, or manage native product settings.
|
|
151
162
|
|
|
152
163
|
## What not to move into a preset
|
|
153
164
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
# The persona is the complete system prompt, so global identity, Web orientation,
|
|
4
4
|
# tool guidance, and later assembly listeners cannot add prompt text. Runtime
|
|
5
5
|
# context snapshots are suppressed for this preset, and the model composes only
|
|
6
|
-
# persistent `bash`
|
|
6
|
+
# the persistent shell (`bash` on POSIX, `pwsh` on win32) and
|
|
7
|
+
# `str_replace_editor`. Context compaction is absent.
|
|
7
8
|
|
|
8
9
|
- id: persona
|
|
9
10
|
name: '@deepseek-ai/dsh-persona'
|
|
@@ -15,6 +16,8 @@
|
|
|
15
16
|
# The PTY registry is an agent-owned service, so it lives in an entry-local
|
|
16
17
|
# realm. The backend still consumes the host sandbox policy and subprocess
|
|
17
18
|
# implementation, while the tool registers into this agent's scoped catalog.
|
|
19
|
+
# Exactly one shell stack mounts per host: the bash stack gates off win32 and
|
|
20
|
+
# its pwsh twin gates off POSIX, mirroring the one-shot shell rows.
|
|
18
21
|
- id: persistent-shell
|
|
19
22
|
name: cordis:group
|
|
20
23
|
group: true
|
|
@@ -26,11 +29,13 @@
|
|
|
26
29
|
|
|
27
30
|
- id: terminal-bash
|
|
28
31
|
name: '@deepseek-ai/dsh-terminal-bash'
|
|
32
|
+
disabled: !!js process.platform === 'win32'
|
|
29
33
|
config:
|
|
30
34
|
timeoutMs: 300000
|
|
31
35
|
|
|
32
36
|
- id: persistent-bash
|
|
33
37
|
name: '@deepseek-ai/dsh-tool-bash-persistent'
|
|
38
|
+
disabled: !!js process.platform === 'win32'
|
|
34
39
|
config:
|
|
35
40
|
timeoutMs: 300000
|
|
36
41
|
description: |-
|
|
@@ -43,6 +48,27 @@
|
|
|
43
48
|
* Please avoid commands that may produce a very large amount of output.
|
|
44
49
|
* Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.
|
|
45
50
|
|
|
51
|
+
- id: terminal-pwsh
|
|
52
|
+
name: '@deepseek-ai/dsh-terminal-bash'
|
|
53
|
+
disabled: !!js process.platform !== 'win32'
|
|
54
|
+
config:
|
|
55
|
+
shellDialect: pwsh
|
|
56
|
+
timeoutMs: 300000
|
|
57
|
+
|
|
58
|
+
- id: persistent-pwsh
|
|
59
|
+
name: '@deepseek-ai/dsh-tool-pwsh-persistent'
|
|
60
|
+
disabled: !!js process.platform !== 'win32'
|
|
61
|
+
config:
|
|
62
|
+
timeoutMs: 300000
|
|
63
|
+
description: |-
|
|
64
|
+
Run commands in a PowerShell shell
|
|
65
|
+
* When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped.
|
|
66
|
+
* You don't have access to the internet via this tool.
|
|
67
|
+
* State is persistent across command calls and discussions with the user.
|
|
68
|
+
* Use native Windows paths (C:\...) and $env:NAME variables; this is PowerShell, not bash.
|
|
69
|
+
* Please avoid commands that may produce a very large amount of output.
|
|
70
|
+
* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.
|
|
71
|
+
|
|
46
72
|
# The bare local filesystem shadows the host's sandboxed provider only for this
|
|
47
73
|
# preset. The editor shares that realm and requires absolute paths.
|
|
48
74
|
- id: filesystem
|
|
@@ -197,9 +197,10 @@
|
|
|
197
197
|
toolName: subagent_fork
|
|
198
198
|
backgroundMode: continuable
|
|
199
199
|
|
|
200
|
-
# Production dsh does not install these optional providers.
|
|
201
|
-
#
|
|
202
|
-
#
|
|
200
|
+
# Production dsh does not install these optional providers. Install the
|
|
201
|
+
# matching Bundle in this Profile and restart the Host, then copy this
|
|
202
|
+
# preset and remove `disabled` from the matching tool row. Host availability
|
|
203
|
+
# alone grants no tool.
|
|
203
204
|
- id: tool-subagent-codex
|
|
204
205
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
205
206
|
disabled: true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { opendir } from "node:fs/promises";
|
|
2
2
|
import path__default from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { z as buildCodeCollabFileIndexState, F as scanGitDirectoryEntries, H as joinWorkspacePath, I as isInsideGitWorktree, D as computeAllChanges, J as pathSegmentComparisonKey, G as closeDirectoryQuietly } from "./chunks/directory-handle-Bp47LF5g.js";
|
|
4
4
|
import "./chunks/schemas-Du3qLZPS.js";
|
|
5
5
|
import "node:child_process";
|
|
6
6
|
import "node:util";
|