@norman-else/dsh-claude 0.1.5 → 0.1.7
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/INSTALL.md +55 -46
- package/LICENSE +21 -21
- package/README.md +191 -183
- package/cordis.patch.yml +12 -12
- package/legacy-preset/agent.cordis.yml +11 -11
- package/legacy-preset/preset.yml +4 -4
- package/lib/bin.mjs +1 -1
- package/lib/bin.mjs.map +1 -1
- package/lib/client.d.ts +5 -0
- package/lib/client.js +80 -149
- package/lib/client.js.map +1 -1
- package/lib/{events-qlmU1KrH.mjs → events-DP0Ov_Re.mjs} +3 -8
- package/lib/events-DP0Ov_Re.mjs.map +1 -0
- package/lib/index.d.mts +12 -2
- package/lib/index.mjs +163 -19
- package/lib/index.mjs.map +1 -1
- package/lib/{presenters-DbfG-9KQ.mjs → presenters-YMR2WMjn.mjs} +2 -2
- package/lib/presenters-YMR2WMjn.mjs.map +1 -0
- package/lib/{preset-installer-D8q3_-wJ.mjs → preset-installer-BKw-SdOm.mjs} +5 -20
- package/lib/preset-installer-BKw-SdOm.mjs.map +1 -0
- package/lib/preset-route.mjs +2 -2
- package/lib/preset-route.mjs.map +1 -1
- package/package.json +3 -1
- package/preset/claude/agent.cordis.yml +11 -11
- package/preset/claude/preset.yml +4 -4
- package/lib/events-qlmU1KrH.mjs.map +0 -1
- package/lib/presenters-DbfG-9KQ.mjs.map +0 -1
- package/lib/preset-installer-D8q3_-wJ.mjs.map +0 -1
package/lib/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as latestClaudeTasks,
|
|
2
|
-
import { a as ClaudeCommandBridge, i as CLAUDE_COMMANDS_SERVICE, r as dynamicPresenterDefinition, t as CLAUDE_PRESENTER_NAMES } from "./presenters-
|
|
3
|
-
import { a as resolveClaudeExecutable,
|
|
1
|
+
import { a as latestClaudeTasks, c as normalizeTasksEvent, d as CLAUDE_ACTIVITY_EVENT, f as CLAUDE_CODE_PRESET_ID, g as CLAUDE_PROJECTION_PATH, h as CLAUDE_DOCTOR_PATH, i as latestClaudeSessionBinding, l as redactText, m as CLAUDE_CODE_PROVIDER_IDS, n as currentClaudeActivityCursor, o as normalizeActivity, p as CLAUDE_CODE_PROVIDER, r as latestClaudeContextUsage, s as normalizeContextUsage, t as boundText, u as safeDetail, v as TASK_TOOL_NAMES } from "./events-DP0Ov_Re.mjs";
|
|
2
|
+
import { a as ClaudeCommandBridge, i as CLAUDE_COMMANDS_SERVICE, r as dynamicPresenterDefinition, t as CLAUDE_PRESENTER_NAMES } from "./presenters-YMR2WMjn.mjs";
|
|
3
|
+
import { a as resolveClaudeExecutable, n as ensureManagedPreset, o as runClaudeDoctor, t as ManagedPresetConflictError } from "./preset-installer-BKw-SdOm.mjs";
|
|
4
4
|
import z from "@deepseek-ai/schemastery";
|
|
5
5
|
import { CallId, LlmAdapter, ReasoningEffortId, createToolResultMessage, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
@@ -45,6 +45,7 @@ const ACTIVITY_KINDS = /* @__PURE__ */ new Set([
|
|
|
45
45
|
"tool-call",
|
|
46
46
|
"tool-result",
|
|
47
47
|
"permission",
|
|
48
|
+
"question",
|
|
48
49
|
"subagent",
|
|
49
50
|
"usage",
|
|
50
51
|
"warning",
|
|
@@ -336,8 +337,14 @@ function mapApprovalOutcome(outcome, input, toolUseID) {
|
|
|
336
337
|
decisionClassification: "user_reject"
|
|
337
338
|
};
|
|
338
339
|
}
|
|
339
|
-
function createPermissionBridge(approval, activeContext) {
|
|
340
|
+
function createPermissionBridge(approval, activeContext, userQuestion) {
|
|
340
341
|
return async (toolName, input, options) => {
|
|
342
|
+
if (toolName === "AskUserQuestion") return userQuestion === void 0 ? {
|
|
343
|
+
behavior: "deny",
|
|
344
|
+
message: "DeepSeek Harness user questions are unavailable; the question was cancelled.",
|
|
345
|
+
toolUseID: options.toolUseID,
|
|
346
|
+
decisionClassification: "user_reject"
|
|
347
|
+
} : userQuestion(input, options);
|
|
341
348
|
const active = activeContext();
|
|
342
349
|
if (active === void 0) return {
|
|
343
350
|
behavior: "deny",
|
|
@@ -357,21 +364,24 @@ function createPermissionBridge(approval, activeContext) {
|
|
|
357
364
|
summary: options.title ?? options.description ?? reason,
|
|
358
365
|
detail: input
|
|
359
366
|
});
|
|
360
|
-
const
|
|
367
|
+
const alreadyFullAccess = await active.hasFullAccess?.() === true;
|
|
368
|
+
const outcome = alreadyFullAccess ? "allowed-once" : await approval.request({
|
|
361
369
|
agent: active.agent,
|
|
362
370
|
toolName,
|
|
363
371
|
reason,
|
|
364
372
|
signal: options.signal
|
|
365
373
|
});
|
|
366
|
-
const
|
|
374
|
+
const fullAccess = alreadyFullAccess || await active.hasFullAccess?.() === true;
|
|
375
|
+
const effectiveOutcome = fullAccess ? "allowed-once" : outcome;
|
|
376
|
+
const result = mapApprovalOutcome(effectiveOutcome, input, options.toolUseID);
|
|
367
377
|
if (result.behavior === "deny") active.recordDenial?.(options.toolUseID);
|
|
368
378
|
await active.appendActivity({
|
|
369
379
|
kind: "permission",
|
|
370
|
-
phase:
|
|
380
|
+
phase: effectiveOutcome === "allowed-once" ? "completed" : "denied",
|
|
371
381
|
toolUseId: options.toolUseID,
|
|
372
382
|
toolName,
|
|
373
383
|
title: options.displayName ?? toolName,
|
|
374
|
-
summary:
|
|
384
|
+
summary: fullAccess ? "Allowed by Full access in DeepSeek Harness" : effectiveOutcome === "allowed-once" ? "Allowed once in DeepSeek Harness" : denialMessage(effectiveOutcome)
|
|
375
385
|
});
|
|
376
386
|
return result;
|
|
377
387
|
} catch (error) {
|
|
@@ -398,6 +408,120 @@ function createPermissionBridge(approval, activeContext) {
|
|
|
398
408
|
};
|
|
399
409
|
}
|
|
400
410
|
//#endregion
|
|
411
|
+
//#region src/user-question.ts
|
|
412
|
+
const FAILURE_MESSAGE = "DeepSeek Harness could not collect an answer; the question was cancelled.";
|
|
413
|
+
const INVALID_MESSAGE = "Claude Code sent an invalid user-question request; the question was cancelled.";
|
|
414
|
+
function failureMessage(error) {
|
|
415
|
+
const code = error !== null && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
416
|
+
return typeof code === "string" && /^[A-Z][A-Z0-9_]*$/.test(code) ? `${FAILURE_MESSAGE} (${code})` : FAILURE_MESSAGE;
|
|
417
|
+
}
|
|
418
|
+
function deny(message, toolUseID) {
|
|
419
|
+
return {
|
|
420
|
+
behavior: "deny",
|
|
421
|
+
message,
|
|
422
|
+
toolUseID,
|
|
423
|
+
decisionClassification: "user_reject"
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function optionalText(value) {
|
|
427
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
428
|
+
}
|
|
429
|
+
function parseQuestions(input, toolUseID) {
|
|
430
|
+
if (!Array.isArray(input.questions) || input.questions.length === 0 || input.questions.length > 20) return void 0;
|
|
431
|
+
const seen = /* @__PURE__ */ new Set();
|
|
432
|
+
const questions = [];
|
|
433
|
+
for (const [index, value] of input.questions.entries()) {
|
|
434
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
435
|
+
const item = value;
|
|
436
|
+
if (typeof item.question !== "string" || item.question.length === 0 || seen.has(item.question)) return void 0;
|
|
437
|
+
seen.add(item.question);
|
|
438
|
+
if (item.options !== void 0 && !Array.isArray(item.options)) return void 0;
|
|
439
|
+
const options = (item.options ?? []).map((option) => {
|
|
440
|
+
if (option === null || typeof option !== "object" || Array.isArray(option)) return void 0;
|
|
441
|
+
const record = option;
|
|
442
|
+
if (typeof record.label !== "string" || record.label.length === 0) return void 0;
|
|
443
|
+
const description = optionalText(record.description);
|
|
444
|
+
return {
|
|
445
|
+
label: record.label,
|
|
446
|
+
...description === void 0 ? {} : { description }
|
|
447
|
+
};
|
|
448
|
+
});
|
|
449
|
+
if (options.some((option) => option === void 0)) return void 0;
|
|
450
|
+
const header = optionalText(item.header);
|
|
451
|
+
questions.push({
|
|
452
|
+
id: `${toolUseID}:${index}`,
|
|
453
|
+
question: item.question,
|
|
454
|
+
...header === void 0 ? {} : { header },
|
|
455
|
+
options,
|
|
456
|
+
multiSelect: item.multiSelect === true
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
return questions;
|
|
460
|
+
}
|
|
461
|
+
function answerText(answer, multiSelect) {
|
|
462
|
+
if (answer === void 0) return "";
|
|
463
|
+
const custom = optionalText(answer.custom);
|
|
464
|
+
if (!multiSelect && custom !== void 0) return custom;
|
|
465
|
+
return [...answer.selected, ...custom === void 0 ? [] : [custom]].join(", ");
|
|
466
|
+
}
|
|
467
|
+
function createUserQuestionBridge(userQuestions, activeContext) {
|
|
468
|
+
return async (input, options) => {
|
|
469
|
+
const active = activeContext();
|
|
470
|
+
if (active === void 0) return deny("No active DeepSeek Harness turn owns this Claude Code question.", options.toolUseID);
|
|
471
|
+
const questions = parseQuestions(input, options.toolUseID);
|
|
472
|
+
if (questions === void 0) return deny(INVALID_MESSAGE, options.toolUseID);
|
|
473
|
+
active.markActivity?.();
|
|
474
|
+
try {
|
|
475
|
+
await active.appendActivity({
|
|
476
|
+
kind: "question",
|
|
477
|
+
phase: "started",
|
|
478
|
+
toolUseId: options.toolUseID,
|
|
479
|
+
toolName: "AskUserQuestion",
|
|
480
|
+
title: "Claude asked a question",
|
|
481
|
+
summary: questions.length === 1 ? questions[0].question : `Claude asked ${questions.length} questions`
|
|
482
|
+
});
|
|
483
|
+
const response = await userQuestions.ask({
|
|
484
|
+
questions,
|
|
485
|
+
agent: active.agent,
|
|
486
|
+
signal: options.signal
|
|
487
|
+
});
|
|
488
|
+
const answersById = new Map(response.answers.map((answer) => [answer.id, answer]));
|
|
489
|
+
const answers = Object.fromEntries(questions.map((question) => [question.question, answerText(answersById.get(question.id), question.multiSelect === true)]));
|
|
490
|
+
await active.appendActivity({
|
|
491
|
+
kind: "question",
|
|
492
|
+
phase: "completed",
|
|
493
|
+
toolUseId: options.toolUseID,
|
|
494
|
+
toolName: "AskUserQuestion",
|
|
495
|
+
title: "Claude asked a question",
|
|
496
|
+
summary: "Answered in DeepSeek Harness"
|
|
497
|
+
});
|
|
498
|
+
return {
|
|
499
|
+
behavior: "allow",
|
|
500
|
+
updatedInput: {
|
|
501
|
+
...input,
|
|
502
|
+
answers
|
|
503
|
+
},
|
|
504
|
+
toolUseID: options.toolUseID,
|
|
505
|
+
decisionClassification: "user_temporary"
|
|
506
|
+
};
|
|
507
|
+
} catch (error) {
|
|
508
|
+
const message = failureMessage(error);
|
|
509
|
+
try {
|
|
510
|
+
await active.appendActivity({
|
|
511
|
+
kind: "question",
|
|
512
|
+
phase: "failed",
|
|
513
|
+
toolUseId: options.toolUseID,
|
|
514
|
+
toolName: "AskUserQuestion",
|
|
515
|
+
title: "Claude asked a question",
|
|
516
|
+
summary: message,
|
|
517
|
+
isError: true
|
|
518
|
+
});
|
|
519
|
+
} catch {}
|
|
520
|
+
return deny(message, options.toolUseID);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
//#endregion
|
|
401
525
|
//#region src/sdk-messages.ts
|
|
402
526
|
function record(value) {
|
|
403
527
|
return value !== null && typeof value === "object" ? value : void 0;
|
|
@@ -905,6 +1029,7 @@ var ClaudeSupervisor = class {
|
|
|
905
1029
|
#entries = /* @__PURE__ */ new Map();
|
|
906
1030
|
#runtime;
|
|
907
1031
|
#approval;
|
|
1032
|
+
#userQuestions;
|
|
908
1033
|
#config;
|
|
909
1034
|
#queryFactory;
|
|
910
1035
|
#runDetached;
|
|
@@ -916,6 +1041,7 @@ var ClaudeSupervisor = class {
|
|
|
916
1041
|
constructor(dependencies) {
|
|
917
1042
|
this.#runtime = dependencies.runtime;
|
|
918
1043
|
this.#approval = dependencies.approval;
|
|
1044
|
+
this.#userQuestions = dependencies.userQuestions;
|
|
919
1045
|
this.#config = dependencies.config;
|
|
920
1046
|
this.#queryFactory = dependencies.queryFactory ?? ((params) => query(params));
|
|
921
1047
|
this.#runDetached = dependencies.runDetached ?? ((operation) => operation());
|
|
@@ -1151,7 +1277,7 @@ var ClaudeSupervisor = class {
|
|
|
1151
1277
|
taskSnapshotAt: 0,
|
|
1152
1278
|
taskSnapshotTimer: void 0
|
|
1153
1279
|
};
|
|
1154
|
-
const
|
|
1280
|
+
const activeInteraction = () => {
|
|
1155
1281
|
const active = entry.active;
|
|
1156
1282
|
return active === void 0 ? void 0 : {
|
|
1157
1283
|
agent: active.agent,
|
|
@@ -1162,9 +1288,15 @@ var ClaudeSupervisor = class {
|
|
|
1162
1288
|
recordDenial: (toolUseId) => {
|
|
1163
1289
|
active.deniedToolUseIds.add(toolUseId);
|
|
1164
1290
|
},
|
|
1291
|
+
hasFullAccess: async () => {
|
|
1292
|
+
await this.#syncPermissionMode(entry);
|
|
1293
|
+
return entry.permissionMode === "bypassPermissions";
|
|
1294
|
+
},
|
|
1165
1295
|
appendActivity: (activity) => this.#appendActivity(active, activity)
|
|
1166
1296
|
};
|
|
1167
|
-
}
|
|
1297
|
+
};
|
|
1298
|
+
const userQuestion = createUserQuestionBridge(this.#userQuestions, activeInteraction);
|
|
1299
|
+
const canUseTool = createPermissionBridge(this.#approval, activeInteraction, userQuestion);
|
|
1168
1300
|
const options = {
|
|
1169
1301
|
pathToClaudeCodeExecutable: this.#config.executablePath,
|
|
1170
1302
|
cwd,
|
|
@@ -1347,6 +1479,12 @@ var ClaudeSupervisor = class {
|
|
|
1347
1479
|
title: message.toolName,
|
|
1348
1480
|
summary: message.summary
|
|
1349
1481
|
});
|
|
1482
|
+
if (!TASK_TOOL_NAMES.has(active.callNames.get(message.toolUseId) ?? message.toolName)) await this.#appendNativeToolResult(active, {
|
|
1483
|
+
kind: "tool-result",
|
|
1484
|
+
toolUseId: message.toolUseId,
|
|
1485
|
+
output: message.summary,
|
|
1486
|
+
isError: true
|
|
1487
|
+
});
|
|
1350
1488
|
return;
|
|
1351
1489
|
}
|
|
1352
1490
|
}
|
|
@@ -1803,7 +1941,7 @@ var ClaudeCodeAdapter = class extends LlmAdapter {
|
|
|
1803
1941
|
async *stream(options) {
|
|
1804
1942
|
if (options.purpose !== void 0) throw new Error(`dsh-claude: auxiliary ${options.purpose} calls are not routed into the Claude session`);
|
|
1805
1943
|
const agent = resolveAgent(this.#agents, options);
|
|
1806
|
-
if (
|
|
1944
|
+
if (this.#presetIdFor(agent) !== "claude") throw new Error(`dsh-claude: provider ${CLAUDE_CODE_PROVIDER} is available only to the ${CLAUDE_CODE_PRESET_ID} preset`);
|
|
1807
1945
|
const thinkingMode = thinkingModeFor(options.reasoningEffort);
|
|
1808
1946
|
const prompt = extractDirectUserText(options.messages);
|
|
1809
1947
|
const events = await this.#supervisor.runTurn({
|
|
@@ -2068,7 +2206,8 @@ const inject = [
|
|
|
2068
2206
|
"agentPresets",
|
|
2069
2207
|
"commands",
|
|
2070
2208
|
"subprocess",
|
|
2071
|
-
"approval"
|
|
2209
|
+
"approval",
|
|
2210
|
+
"userQuestions"
|
|
2072
2211
|
];
|
|
2073
2212
|
const Config = z.object({
|
|
2074
2213
|
executablePath: z.string().default(""),
|
|
@@ -2082,7 +2221,7 @@ const SCOPE_RETRY_MS = 500;
|
|
|
2082
2221
|
const MAX_CATALOG_RETRIES = 3;
|
|
2083
2222
|
const MAX_SCOPE_RETRIES = 24;
|
|
2084
2223
|
function mountClaudeMetadata(ctx, supervisor, agent, model, sidecar, resolveCommands = () => ctx.agentPresets.serviceFor(agent, CLAUDE_COMMANDS_SERVICE)) {
|
|
2085
|
-
if (
|
|
2224
|
+
if (ctx.agentPresets.composedPreset(agent.ctx) !== "claude") return void 0;
|
|
2086
2225
|
let stopped = false;
|
|
2087
2226
|
let pending = Promise.resolve();
|
|
2088
2227
|
let commandScope;
|
|
@@ -2179,13 +2318,17 @@ function mountClaudeMetadata(ctx, supervisor, agent, model, sidecar, resolveComm
|
|
|
2179
2318
|
};
|
|
2180
2319
|
}, "dsh-claude: agent metadata bridge");
|
|
2181
2320
|
}
|
|
2182
|
-
async function
|
|
2321
|
+
async function installManagedPresetCompatibility(logger, install = ensureManagedPreset) {
|
|
2183
2322
|
try {
|
|
2184
|
-
await
|
|
2323
|
+
return await install();
|
|
2185
2324
|
} catch (error) {
|
|
2186
2325
|
if (!(error instanceof ManagedPresetConflictError)) throw error;
|
|
2187
|
-
|
|
2326
|
+
logger.warn(`dsh-claude: preserving user-modified preset at ${error.path}`);
|
|
2327
|
+
return "conflict";
|
|
2188
2328
|
}
|
|
2329
|
+
}
|
|
2330
|
+
async function apply(ctx, config) {
|
|
2331
|
+
await installManagedPresetCompatibility(ctx.logger);
|
|
2189
2332
|
const supervisorConfig = {
|
|
2190
2333
|
executablePath: "",
|
|
2191
2334
|
defaultModel: config.model ?? "default",
|
|
@@ -2196,6 +2339,7 @@ async function apply(ctx, config) {
|
|
|
2196
2339
|
const supervisor = new ClaudeSupervisor({
|
|
2197
2340
|
runtime: ctx.subprocess,
|
|
2198
2341
|
approval: ctx.approval,
|
|
2342
|
+
userQuestions: ctx.userQuestions,
|
|
2199
2343
|
config: supervisorConfig,
|
|
2200
2344
|
runDetached: (operation) => ctx.agents.withoutInitiator(operation),
|
|
2201
2345
|
sidecar
|
|
@@ -2243,7 +2387,7 @@ async function apply(ctx, config) {
|
|
|
2243
2387
|
});
|
|
2244
2388
|
const onPresetSelected = ctx.on;
|
|
2245
2389
|
const stopSelected = onPresetSelected("agent-preset/selected", (sessionId, preset) => {
|
|
2246
|
-
if (
|
|
2390
|
+
if (preset !== "claude") return;
|
|
2247
2391
|
const agent = ctx.agents.get(sessionId);
|
|
2248
2392
|
if (agent !== void 0) mountWhenPresetSettles(agent);
|
|
2249
2393
|
});
|
|
@@ -2267,11 +2411,11 @@ async function apply(ctx, config) {
|
|
|
2267
2411
|
registerClaudeDoctorRoutes(webCtx, webCtx.subprocess, supervisor, supervisorConfig, resolutionError);
|
|
2268
2412
|
registerClaudeProjectionRoute(webCtx, sidecar, (sessionId) => {
|
|
2269
2413
|
const agent = webCtx.agents.get(sessionId);
|
|
2270
|
-
return agent !== void 0 &&
|
|
2414
|
+
return agent !== void 0 && webCtx.agentPresets.composedPreset(agent.ctx) === "claude";
|
|
2271
2415
|
});
|
|
2272
2416
|
});
|
|
2273
2417
|
}
|
|
2274
2418
|
//#endregion
|
|
2275
|
-
export { Config, apply, inject, mountClaudeMetadata, name };
|
|
2419
|
+
export { Config, apply, inject, installManagedPresetCompatibility, mountClaudeMetadata, name };
|
|
2276
2420
|
|
|
2277
2421
|
//# sourceMappingURL=index.mjs.map
|