@openma/deepseek-harness-acp 0.4.4 → 0.4.5
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/bridge.js +13 -2
- package/dist/index.js +130 -4
- package/package.json +1 -1
package/dist/bridge.js
CHANGED
|
@@ -1482,13 +1482,24 @@ async function apply(ctx, config = {}) {
|
|
|
1482
1482
|
mcpCapabilities: { http: true, sse: false },
|
|
1483
1483
|
...hasPersistence ? { sessionCapabilities: { list: {} } } : {}
|
|
1484
1484
|
},
|
|
1485
|
-
authMethods: [
|
|
1485
|
+
authMethods: [
|
|
1486
|
+
// ACP Terminal Auth (see the registry's AUTHENTICATION.md):
|
|
1487
|
+
// the client runs `dsh-acp login` in an interactive
|
|
1488
|
+
// terminal; the key lands in the shared harness
|
|
1489
|
+
// credential store (~/.dsh/.credentials.yaml).
|
|
1490
|
+
{
|
|
1491
|
+
id: "terminal-login",
|
|
1492
|
+
name: "Log in with a DeepSeek API key",
|
|
1493
|
+
description: "Interactive terminal setup \u2014 saves the key to the harness credential store shared with the dsh Web UI",
|
|
1494
|
+
_meta: { "terminal-auth": { args: ["login"], env: {} } }
|
|
1495
|
+
}
|
|
1496
|
+
]
|
|
1486
1497
|
});
|
|
1487
1498
|
},
|
|
1488
1499
|
async authenticate(_params) {
|
|
1489
1500
|
if (!await credentialPresent()) {
|
|
1490
1501
|
throw authRequired(
|
|
1491
|
-
"no DeepSeek credential found: save one in the dsh Web UI (Settings \u2192 Models) or set DEEPSEEK_API_KEY"
|
|
1502
|
+
"no DeepSeek credential found: run `dsh-acp login`, save one in the dsh Web UI (Settings \u2192 Models), or set DEEPSEEK_API_KEY"
|
|
1492
1503
|
);
|
|
1493
1504
|
}
|
|
1494
1505
|
},
|
package/dist/index.js
CHANGED
|
@@ -1507,13 +1507,24 @@ async function apply(ctx, config = {}) {
|
|
|
1507
1507
|
mcpCapabilities: { http: true, sse: false },
|
|
1508
1508
|
...hasPersistence ? { sessionCapabilities: { list: {} } } : {}
|
|
1509
1509
|
},
|
|
1510
|
-
authMethods: [
|
|
1510
|
+
authMethods: [
|
|
1511
|
+
// ACP Terminal Auth (see the registry's AUTHENTICATION.md):
|
|
1512
|
+
// the client runs `dsh-acp login` in an interactive
|
|
1513
|
+
// terminal; the key lands in the shared harness
|
|
1514
|
+
// credential store (~/.dsh/.credentials.yaml).
|
|
1515
|
+
{
|
|
1516
|
+
id: "terminal-login",
|
|
1517
|
+
name: "Log in with a DeepSeek API key",
|
|
1518
|
+
description: "Interactive terminal setup \u2014 saves the key to the harness credential store shared with the dsh Web UI",
|
|
1519
|
+
_meta: { "terminal-auth": { args: ["login"], env: {} } }
|
|
1520
|
+
}
|
|
1521
|
+
]
|
|
1511
1522
|
});
|
|
1512
1523
|
},
|
|
1513
1524
|
async authenticate(_params) {
|
|
1514
1525
|
if (!await credentialPresent()) {
|
|
1515
1526
|
throw authRequired(
|
|
1516
|
-
"no DeepSeek credential found: save one in the dsh Web UI (Settings \u2192 Models) or set DEEPSEEK_API_KEY"
|
|
1527
|
+
"no DeepSeek credential found: run `dsh-acp login`, save one in the dsh Web UI (Settings \u2192 Models), or set DEEPSEEK_API_KEY"
|
|
1517
1528
|
);
|
|
1518
1529
|
}
|
|
1519
1530
|
},
|
|
@@ -2356,6 +2367,9 @@ async function bootAcpProfile(host, overrides) {
|
|
|
2356
2367
|
overlays.push({ id: "session-telemetry-otel", disabled: true });
|
|
2357
2368
|
}
|
|
2358
2369
|
const bridgeRow = rows.get("acp-bridge");
|
|
2370
|
+
if (overrides?.serve === false && bridgeRow !== void 0) {
|
|
2371
|
+
overlays.push({ id: "acp-bridge", disabled: true });
|
|
2372
|
+
}
|
|
2359
2373
|
if (overrides !== void 0 && bridgeRow !== void 0) {
|
|
2360
2374
|
const patch = {};
|
|
2361
2375
|
if (overrides.provider !== void 0) patch["provider"] = overrides.provider;
|
|
@@ -2392,9 +2406,93 @@ async function bootAcpProfile(host, overrides) {
|
|
|
2392
2406
|
return ctx;
|
|
2393
2407
|
}
|
|
2394
2408
|
|
|
2409
|
+
// src/login.ts
|
|
2410
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
2411
|
+
import { join as join3 } from "node:path";
|
|
2412
|
+
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
2413
|
+
async function readSecret(promptText) {
|
|
2414
|
+
const stdin = process.stdin;
|
|
2415
|
+
if (!stdin.isTTY) {
|
|
2416
|
+
const chunks = [];
|
|
2417
|
+
for await (const chunk of stdin) {
|
|
2418
|
+
chunks.push(Buffer.from(chunk));
|
|
2419
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
2420
|
+
const newline = text.indexOf("\n");
|
|
2421
|
+
if (newline >= 0) return text.slice(0, newline).trim();
|
|
2422
|
+
}
|
|
2423
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
2424
|
+
}
|
|
2425
|
+
process.stderr.write(promptText);
|
|
2426
|
+
return await new Promise((resolve2) => {
|
|
2427
|
+
stdin.setRawMode(true);
|
|
2428
|
+
stdin.resume();
|
|
2429
|
+
stdin.setEncoding("utf8");
|
|
2430
|
+
let buffer = "";
|
|
2431
|
+
const onData = (chunk) => {
|
|
2432
|
+
for (const char of chunk) {
|
|
2433
|
+
if (char === "\n" || char === "\r" || char === "") {
|
|
2434
|
+
stdin.setRawMode(false);
|
|
2435
|
+
stdin.pause();
|
|
2436
|
+
stdin.off("data", onData);
|
|
2437
|
+
process.stderr.write("\n");
|
|
2438
|
+
resolve2(buffer.trim());
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
if (char === "") {
|
|
2442
|
+
stdin.setRawMode(false);
|
|
2443
|
+
process.stderr.write("^C\n");
|
|
2444
|
+
process.exit(130);
|
|
2445
|
+
}
|
|
2446
|
+
if (char === "\x7F" || char === "\b") {
|
|
2447
|
+
buffer = buffer.slice(0, -1);
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
buffer += char;
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2453
|
+
stdin.on("data", onData);
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
async function runLogin(ctx, hostBase, argv) {
|
|
2457
|
+
const req = createRequire3(join3(hostBase, "noop.js"));
|
|
2458
|
+
let credentialRef2;
|
|
2459
|
+
try {
|
|
2460
|
+
const mod = await import(pathToFileURL3(req.resolve("@deepseek-ai/dsh-credentials")).href);
|
|
2461
|
+
credentialRef2 = mod.credentialRef;
|
|
2462
|
+
} catch {
|
|
2463
|
+
credentialRef2 = void 0;
|
|
2464
|
+
}
|
|
2465
|
+
const store = ctx.get("credentials");
|
|
2466
|
+
if (store === void 0 || credentialRef2 === void 0) {
|
|
2467
|
+
process.stderr.write(
|
|
2468
|
+
"This composition has no writable credential store; export DEEPSEEK_API_KEY instead.\n"
|
|
2469
|
+
);
|
|
2470
|
+
return 1;
|
|
2471
|
+
}
|
|
2472
|
+
const ref = credentialRef2("DEEPSEEK_API_KEY");
|
|
2473
|
+
const before = await store.describe(ref);
|
|
2474
|
+
if (before.configured && before.source !== void 0) {
|
|
2475
|
+
process.stderr.write(`A key is already configured (source: ${before.source}).
|
|
2476
|
+
`);
|
|
2477
|
+
}
|
|
2478
|
+
const key = argv[0] ?? await readSecret("DeepSeek API key (input hidden): ");
|
|
2479
|
+
if (key.length === 0) {
|
|
2480
|
+
process.stderr.write("No key entered; nothing saved.\n");
|
|
2481
|
+
return 1;
|
|
2482
|
+
}
|
|
2483
|
+
await store.set(ref, key);
|
|
2484
|
+
const masked = key.length <= 8 ? "\u2026" : `${key.slice(0, 4)}\u2026${key.slice(-4)}`;
|
|
2485
|
+
process.stderr.write(
|
|
2486
|
+
`Saved ${masked} to the harness credential store (~/.dsh/.credentials.yaml, mode 600).
|
|
2487
|
+
The dsh Web UI and every dsh surface share this credential.
|
|
2488
|
+
`
|
|
2489
|
+
);
|
|
2490
|
+
return 0;
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2395
2493
|
// src/settings.ts
|
|
2396
2494
|
import { homedir } from "node:os";
|
|
2397
|
-
import { join as
|
|
2495
|
+
import { join as join4 } from "node:path";
|
|
2398
2496
|
var DEFAULT_PERSONA = `You are a coding assistant powered by the {{model}} model, working inside an editor via the Agent Client Protocol. Your working directory is {{cwd}}. Your bash tool runs under a file sandbox \u2014 a \`[sandbox: file access denied \u2026]\` result is policy, not a command bug.
|
|
2399
2497
|
|
|
2400
2498
|
Verify your work by running the code or tests. Keep answers brief and factual.`;
|
|
@@ -2487,7 +2585,7 @@ function resolveSettings(argv) {
|
|
|
2487
2585
|
models,
|
|
2488
2586
|
maxTokens,
|
|
2489
2587
|
permissionMode,
|
|
2490
|
-
sessionRoot: stringFlag(parsed, "session-root") ?? envString("DSH_SESSION_ROOT") ??
|
|
2588
|
+
sessionRoot: stringFlag(parsed, "session-root") ?? envString("DSH_SESSION_ROOT") ?? join4(homedir(), ".dsh-acp", "sessions"),
|
|
2491
2589
|
persona: stringFlag(parsed, "persona") ?? envString("DSH_SYSTEM_PROMPT") ?? DEFAULT_PERSONA,
|
|
2492
2590
|
thinking: !parsed.flags.has("no-thinking"),
|
|
2493
2591
|
reasoningEffort: reasoningRaw,
|
|
@@ -2495,6 +2593,8 @@ function resolveSettings(argv) {
|
|
|
2495
2593
|
};
|
|
2496
2594
|
}
|
|
2497
2595
|
var HELP_TEXT = `Usage: dsh-acp [options]
|
|
2596
|
+
dsh-acp login [api-key] Save a DeepSeek API key (interactive when omitted)
|
|
2597
|
+
dsh-acp update Self-update via npm
|
|
2498
2598
|
|
|
2499
2599
|
Agent Client Protocol (ACP) stdio server for DeepSeek Harness. Speak ACP on
|
|
2500
2600
|
stdin/stdout from an ACP client such as Zed; diagnostics go to stderr.
|
|
@@ -2538,6 +2638,32 @@ async function main() {
|
|
|
2538
2638
|
console.log(HELP_TEXT.trimEnd());
|
|
2539
2639
|
return;
|
|
2540
2640
|
}
|
|
2641
|
+
if (argv[0] === "login") {
|
|
2642
|
+
let booted;
|
|
2643
|
+
let hostBase;
|
|
2644
|
+
try {
|
|
2645
|
+
const host = resolveHost(void 0);
|
|
2646
|
+
hostBase = host.base;
|
|
2647
|
+
booted = await bootAcpProfile(host, { serve: false });
|
|
2648
|
+
} catch (error) {
|
|
2649
|
+
if (error instanceof HarnessNotFoundError) {
|
|
2650
|
+
logError(error.message);
|
|
2651
|
+
process.exitCode = 1;
|
|
2652
|
+
return;
|
|
2653
|
+
}
|
|
2654
|
+
throw error;
|
|
2655
|
+
}
|
|
2656
|
+
try {
|
|
2657
|
+
process.exitCode = await runLogin(
|
|
2658
|
+
booted,
|
|
2659
|
+
hostBase,
|
|
2660
|
+
argv.slice(1)
|
|
2661
|
+
);
|
|
2662
|
+
} finally {
|
|
2663
|
+
await booted.fiber.dispose().catch(() => void 0);
|
|
2664
|
+
}
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2541
2667
|
if (argv[0] === "update") {
|
|
2542
2668
|
logInfo(`updating ${NAME} (npm install -g ${NAME}@latest)\u2026`);
|
|
2543
2669
|
const result = spawnSync("npm", ["install", "-g", `${NAME}@latest`], { stdio: ["ignore", 2, 2] });
|