dsh-agy-link 0.4.22 → 0.4.25
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/CHANGELOG.md +24 -0
- package/dist/index.js +255 -78
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.25 (2026-09-04)
|
|
4
|
+
|
|
5
|
+
- **Fixed: Plugin Startup Blocker on DSH >= 0.1.1-rc.x / 0.1.2-rc.1 (`missing export 'CallId'`, issue #4).**
|
|
6
|
+
- **Root cause**: Newer `@deepseek-ai/dsh-llm` versions (e.g. `0.1.2-alpha.1` ~ `0.1.2-rc.1`) renamed `CallId` to `ToolCallId`. A named import `import { CallId } from '@deepseek-ai/dsh-llm'` caused Node ESM static resolution to fail at startup with `The requested module '@deepseek-ai/dsh-llm' does not provide an export named 'CallId'`, surfacing as a plugin load failure on DSH Desktop 2.0.5 and CLI.
|
|
7
|
+
- **Fix**: Replaced named import with a namespace fallback resolution `toToolCallId = dshLlm.ToolCallId ?? dshLlm.CallId ?? identity`. This avoids missing named export evaluation errors and ensures seamless backwards and forwards compatibility across all DSH host versions.
|
|
8
|
+
- **Ecosystem & Test Hardening**: Upgraded development dependencies to `@deepseek-ai/dsh-*@0.1.2-rc.1`. Configured `--test-concurrency=1` in test runner to prevent mock environment variable collisions across concurrent subprocess tests, achieving 100% pass rate across all 151 unit tests. Verified live startup with DSH 0.1.2-rc.1 and `dsh-lark-link`.
|
|
9
|
+
|
|
10
|
+
## 0.4.24 (2026-08-28)
|
|
11
|
+
|
|
12
|
+
- **Fixed: Antigravity Models Missing From Picker When Logged In (已登录/显示余量但模型列表不显示 — issue #1).**
|
|
13
|
+
- **Decoupled Adapter Registration from Synchronous Binary Discovery**: `registerAdapter` now executes regardless of initial `bin()` probe results (using resilient fallback model catalog), ensuring the Antigravity provider is never dropped during startup even if CLI path resolution is deferred.
|
|
14
|
+
- **Expanded macOS / Linux GUI App Path Discovery**: extended `resolveAgyBin` search candidates to include `~/.bun/bin`, `~/.cargo/bin`, `~/.local/share/pnpm`, `~/Library/pnpm`, `~/.yarn/bin`, `~/.npm-global/bin`, NVM (`~/.nvm/versions/node/*/bin`), FNM, Volta, ASDF shims, Linuxbrew, etc., fixing GUI desktop apps starting with minimal default system PATH.
|
|
15
|
+
- **Account-Aware Model Discovery & Environment Isolation**: model discovery now inherits current active/primary account isolated environment and proxy settings, falling back across ready pool accounts if default system HOME is unauthenticated.
|
|
16
|
+
- **Defensive Model & Effort Sanitization**: defensive catalog cleaning against empty IDs, blank names, empty reasoning effort arrays, and out-of-bounds `defaultEffort` to strictly satisfy DSH host validation and prevent fail-all provider group drops (`INVALID_CATALOG` / `INVALID_MODEL_*`).
|
|
17
|
+
- **Cross-Platform & Unit Tests**: added defensive catalog normalization and explicit binary path resolution tests across test suites.
|
|
18
|
+
|
|
19
|
+
## 0.4.23 (2026-08-27)
|
|
20
|
+
|
|
21
|
+
- **Enhanced: Antigravity Tool Mirroring with Native Git +/- Diff Cards & Full Tool Vocabulary.**
|
|
22
|
+
- **Tool Vocabulary & Parameter Mapping**: mapped agy's official editing tool `replace_file_content` (`TargetFile`, `TargetContent`, `ReplacementContent`, `Description`, `Instruction`) and write tool `write_to_file` (`TargetFile`, `CodeContent`, `Overwrite`, `Description`) to DSH native `DiffCallView` / `DiffResultView` cards.
|
|
23
|
+
- **Git Head Base Line Diffing**: added cross-platform `getGitHeadContent` to retrieve committed file content for full-file writes (`write_to_file`), allowing DSH to render line-by-line git `+`/`-` additions and deletions rather than treating existing modified files as blank new files.
|
|
24
|
+
- **Expanded Tool Support**: mapped `view_file` (with `AbsolutePath`/`StartLine` line location navigation), `grep_search`, `find_by_name`, `ask_question`, `read_url_content`, and `generate_image` onto their respective native/generic tool cards with descriptive titles.
|
|
25
|
+
- **Cross-Platform Hardened**: path normalization with forward-slash compatibility across Windows/macOS/Linux, `windowsHide: true`, strict subprocess timeout, and safe error fallback.
|
|
26
|
+
|
|
3
27
|
## 0.4.22 (2026-08-27)
|
|
4
28
|
|
|
5
29
|
- **Fixed: `registration.adapter.prepareCall is not a function` on new DSH hosts (本轮运行失败 UNKNOWN).**
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { execFile, execFileSync, spawn } from "node:child_process";
|
|
3
|
-
import { delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import path, { delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { accessSync, chmodSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { homedir, tmpdir } from "node:os";
|
|
6
|
-
import
|
|
6
|
+
import * as dshLlm from "@deepseek-ai/dsh-llm";
|
|
7
|
+
import { LlmAdapter, LlmError } from "@deepseek-ai/dsh-llm";
|
|
7
8
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
8
9
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
9
10
|
import { mkdir, mkdtemp, readFile, readdir, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -549,6 +550,48 @@ const MIRROR_TOOL_NAME = "agy_tool";
|
|
|
549
550
|
/** The only tool this DSH deployment lets a model call directly. */
|
|
550
551
|
const WRAPPER_TOOL_NAME = "run_code";
|
|
551
552
|
/**
|
|
553
|
+
* Retrieve the committed HEAD content of a file via git, for computing
|
|
554
|
+
* line diffs on full-file writes. Pure & safe: catches all failures (not in git,
|
|
555
|
+
* untracked, git missing, binary) and returns null in <=500ms.
|
|
556
|
+
*/
|
|
557
|
+
function getGitHeadContent(filePath, execFn = execFileSync) {
|
|
558
|
+
if (!filePath || typeof filePath !== "string" || filePath === "file") return null;
|
|
559
|
+
try {
|
|
560
|
+
const resolved = path.resolve(filePath);
|
|
561
|
+
const toplevel = execFn("git", ["rev-parse", "--show-toplevel"], {
|
|
562
|
+
cwd: path.dirname(resolved),
|
|
563
|
+
encoding: "utf-8",
|
|
564
|
+
stdio: [
|
|
565
|
+
"ignore",
|
|
566
|
+
"pipe",
|
|
567
|
+
"ignore"
|
|
568
|
+
],
|
|
569
|
+
timeout: 500,
|
|
570
|
+
windowsHide: true
|
|
571
|
+
});
|
|
572
|
+
const root = typeof toplevel === "string" ? toplevel.trim() : "";
|
|
573
|
+
if (!root) return null;
|
|
574
|
+
const relPath = path.relative(root, resolved).replace(/\\/g, "/");
|
|
575
|
+
if (relPath.startsWith("..")) return null;
|
|
576
|
+
const content = execFn("git", ["show", `HEAD:${relPath}`], {
|
|
577
|
+
cwd: root,
|
|
578
|
+
encoding: "utf-8",
|
|
579
|
+
stdio: [
|
|
580
|
+
"ignore",
|
|
581
|
+
"pipe",
|
|
582
|
+
"ignore"
|
|
583
|
+
],
|
|
584
|
+
timeout: 500,
|
|
585
|
+
windowsHide: true
|
|
586
|
+
});
|
|
587
|
+
const str = typeof content === "string" ? content : "";
|
|
588
|
+
if (str.includes("\0")) return null;
|
|
589
|
+
return str;
|
|
590
|
+
} catch {
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
552
595
|
* Build the run_code tool-call arguments that replay one recorded agy tool
|
|
553
596
|
* step. The deployment's tool-dispatch policy only allows `run_code` as a
|
|
554
597
|
* direct model call (everything else must be invoked from inside a
|
|
@@ -581,8 +624,9 @@ function toolInput(args) {
|
|
|
581
624
|
}
|
|
582
625
|
/**
|
|
583
626
|
* agy serializes tool args with PascalCase keys (CommandLine, AbsolutePath,
|
|
584
|
-
* SearchDirectory, …);
|
|
585
|
-
*
|
|
627
|
+
* SearchDirectory, TargetFile, TargetContent, ReplacementContent, CodeContent…);
|
|
628
|
+
* pick() accepts all casing spellings so cards always read the real field
|
|
629
|
+
* instead of falling back to raw JSON.
|
|
586
630
|
*/
|
|
587
631
|
function pick$1(input, ...keys) {
|
|
588
632
|
for (const k of keys) {
|
|
@@ -598,41 +642,50 @@ function presentMirrorCall(args) {
|
|
|
598
642
|
switch (name) {
|
|
599
643
|
case "run_command":
|
|
600
644
|
case "bash":
|
|
601
|
-
case "execute_command":
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
645
|
+
case "execute_command": {
|
|
646
|
+
const command = pick$1(input, "CommandLine", "command_line", "command", "cmd", "Cmd") ?? JSON.stringify(input);
|
|
647
|
+
const desc = pick$1(input, "Description", "description", "toolAction", "toolSummary");
|
|
648
|
+
const cwd = pick$1(input, "Cwd", "cwd", "WorkingDirectory", "working_directory");
|
|
649
|
+
return {
|
|
650
|
+
card: "terminal",
|
|
651
|
+
title: command,
|
|
652
|
+
...desc !== void 0 ? { description: desc } : {},
|
|
653
|
+
...cwd !== void 0 ? { cwd } : {}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
case "replace_file_content":
|
|
657
|
+
case "edit_file":
|
|
658
|
+
case "replace_in_file":
|
|
659
|
+
case "edit": {
|
|
660
|
+
const path = pick$1(input, "TargetFile", "target_file", "path", "file_path", "Path", "FilePath", "AbsolutePath", "targetFile") ?? "file";
|
|
661
|
+
const oldText = pick$1(input, "TargetContent", "target_content", "old_string", "oldText", "OldString", "OldText", "targetContent") ?? null;
|
|
662
|
+
const newText = pick$1(input, "ReplacementContent", "replacement_content", "new_string", "newText", "content", "NewString", "NewText", "Content", "replacementContent") ?? "";
|
|
663
|
+
const desc = pick$1(input, "Description", "description", "Instruction", "instruction", "toolAction", "toolSummary");
|
|
612
664
|
return {
|
|
613
665
|
card: "diff",
|
|
614
|
-
title: "
|
|
666
|
+
title: desc ? `${desc} · ${path}` : "Edit " + path,
|
|
615
667
|
diffs: [{
|
|
616
668
|
path,
|
|
617
|
-
oldText
|
|
618
|
-
newText
|
|
669
|
+
oldText,
|
|
670
|
+
newText
|
|
619
671
|
}],
|
|
620
672
|
locations: [{ path }]
|
|
621
673
|
};
|
|
622
674
|
}
|
|
623
|
-
case "
|
|
624
|
-
case "
|
|
625
|
-
case "
|
|
626
|
-
const path = pick$1(input, "path", "file_path", "Path", "FilePath", "AbsolutePath") ?? "file";
|
|
627
|
-
const
|
|
628
|
-
const
|
|
675
|
+
case "write_to_file":
|
|
676
|
+
case "write_file":
|
|
677
|
+
case "create_file": {
|
|
678
|
+
const path = pick$1(input, "TargetFile", "target_file", "path", "file_path", "filename", "Path", "FilePath", "FileName", "AbsolutePath", "targetFile") ?? "file";
|
|
679
|
+
const content = pick$1(input, "CodeContent", "code_content", "content", "Content", "FileContents", "contents", "codeContent") ?? "";
|
|
680
|
+
const desc = pick$1(input, "Description", "description", "toolAction", "toolSummary");
|
|
681
|
+
const oldText = pick$1(input, "old_string", "oldText", "OldString", "OldText") ?? getGitHeadContent(path);
|
|
629
682
|
return {
|
|
630
683
|
card: "diff",
|
|
631
|
-
title: "
|
|
684
|
+
title: desc ? `${desc} · ${path}` : "Write " + path,
|
|
632
685
|
diffs: [{
|
|
633
686
|
path,
|
|
634
687
|
oldText,
|
|
635
|
-
newText
|
|
688
|
+
newText: content
|
|
636
689
|
}],
|
|
637
690
|
locations: [{ path }]
|
|
638
691
|
};
|
|
@@ -641,11 +694,12 @@ function presentMirrorCall(args) {
|
|
|
641
694
|
case "view_file":
|
|
642
695
|
case "read":
|
|
643
696
|
case "open_file": {
|
|
644
|
-
const path = pick$1(input, "path", "file_path", "filename", "Path", "FilePath", "FileName", "
|
|
645
|
-
const offset = typeof input.offset === "number" ? input.offset : typeof input.Offset === "number" ? input.Offset : void 0;
|
|
697
|
+
const path = pick$1(input, "AbsolutePath", "absolute_path", "TargetFile", "target_file", "path", "file_path", "filename", "Path", "FilePath", "FileName", "targetFile") ?? "";
|
|
698
|
+
const offset = typeof input.offset === "number" ? input.offset : typeof input.Offset === "number" ? input.Offset : typeof input.StartLine === "number" ? input.StartLine - 1 : typeof input.start_line === "number" ? input.start_line - 1 : void 0;
|
|
699
|
+
const desc = pick$1(input, "Description", "description", "toolAction", "toolSummary");
|
|
646
700
|
return {
|
|
647
701
|
card: "generic",
|
|
648
|
-
title: "Read " + path,
|
|
702
|
+
title: desc ? `${desc} · ${path}` : "Read " + path,
|
|
649
703
|
kind: "read",
|
|
650
704
|
...path !== "" ? { locations: [{
|
|
651
705
|
path,
|
|
@@ -655,35 +709,70 @@ function presentMirrorCall(args) {
|
|
|
655
709
|
}
|
|
656
710
|
case "find_by_name":
|
|
657
711
|
case "glob":
|
|
658
|
-
case "search_files":
|
|
712
|
+
case "search_files": {
|
|
713
|
+
const q = pick$1(input, "pattern", "Pattern", "query", "Query", "regex", "Regex", "QueryString") ?? "";
|
|
714
|
+
return {
|
|
715
|
+
card: "generic",
|
|
716
|
+
title: pick$1(input, "Description", "description", "toolAction", "toolSummary") ?? (q !== "" ? "Search " + q : "Search"),
|
|
717
|
+
kind: "search"
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
case "grep_search":
|
|
659
721
|
case "search":
|
|
660
722
|
case "search_file_content":
|
|
661
723
|
case "grep": {
|
|
662
|
-
const q = pick$1(input, "
|
|
724
|
+
const q = pick$1(input, "query", "Query", "pattern", "Pattern", "regex", "Regex", "QueryString") ?? "";
|
|
663
725
|
return {
|
|
664
726
|
card: "generic",
|
|
665
|
-
title: q !== "" ? "Search " + q : "Search",
|
|
727
|
+
title: pick$1(input, "Description", "description", "toolAction", "toolSummary") ?? (q !== "" ? "Search " + q : "Search"),
|
|
666
728
|
kind: "search"
|
|
667
729
|
};
|
|
668
730
|
}
|
|
669
731
|
case "list_dir":
|
|
670
732
|
case "ls": {
|
|
671
|
-
const path = pick$1(input, "path", "directory", "Path", "Directory", "SearchDirectory", "AbsolutePath") ?? "";
|
|
733
|
+
const path = pick$1(input, "DirectoryPath", "directory_path", "path", "directory", "Path", "Directory", "SearchDirectory", "search_directory", "AbsolutePath") ?? "";
|
|
672
734
|
return {
|
|
673
735
|
card: "generic",
|
|
674
|
-
title: path !== "" ? "List " + path : "List directory"
|
|
736
|
+
title: pick$1(input, "Description", "description", "toolAction", "toolSummary") ?? (path !== "" ? "List " + path : "List directory")
|
|
675
737
|
};
|
|
676
738
|
}
|
|
677
739
|
case "delete_file":
|
|
678
740
|
case "remove_file":
|
|
679
|
-
case "rm":
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
741
|
+
case "rm": {
|
|
742
|
+
const path = pick$1(input, "TargetFile", "target_file", "path", "file_path", "Path", "FilePath", "AbsolutePath") ?? "";
|
|
743
|
+
return {
|
|
744
|
+
card: "generic",
|
|
745
|
+
title: pick$1(input, "Description", "description", "toolAction", "toolSummary") ?? "Delete " + path,
|
|
746
|
+
kind: "delete"
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
case "ask_question": {
|
|
750
|
+
const questions = input.questions;
|
|
751
|
+
const firstQ = Array.isArray(questions) && questions.length > 0 && typeof questions[0].question === "string" ? questions[0].question : void 0;
|
|
752
|
+
return {
|
|
753
|
+
card: "generic",
|
|
754
|
+
title: firstQ ? `Ask Question: ${firstQ}` : "Ask Question",
|
|
755
|
+
rawInput: input
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
case "read_url_content": {
|
|
759
|
+
const url = pick$1(input, "Url", "url") ?? "";
|
|
760
|
+
return {
|
|
761
|
+
card: "generic",
|
|
762
|
+
title: pick$1(input, "Description", "description", "toolAction", "toolSummary") ?? (url ? `Fetch ${url}` : "Fetch URL"),
|
|
763
|
+
kind: "fetch"
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
case "generate_image": {
|
|
767
|
+
const prompt = pick$1(input, "Prompt", "prompt", "ImageName", "image_name") ?? "";
|
|
768
|
+
return {
|
|
769
|
+
card: "generic",
|
|
770
|
+
title: prompt ? `Generate Image: ${prompt}` : "Generate Image"
|
|
771
|
+
};
|
|
772
|
+
}
|
|
684
773
|
default: return {
|
|
685
774
|
card: "generic",
|
|
686
|
-
title: name !== "" ? name : "agy tool",
|
|
775
|
+
title: pick$1(input, "Description", "description", "toolAction", "toolSummary") ?? (name !== "" ? name : "agy tool"),
|
|
687
776
|
rawInput: input
|
|
688
777
|
};
|
|
689
778
|
}
|
|
@@ -700,6 +789,7 @@ function presentMirrorResult(args, result) {
|
|
|
700
789
|
card: "terminal",
|
|
701
790
|
output: text
|
|
702
791
|
};
|
|
792
|
+
case "replace_file_content":
|
|
703
793
|
case "write_to_file":
|
|
704
794
|
case "write_file":
|
|
705
795
|
case "create_file":
|
|
@@ -800,6 +890,7 @@ function defineAgyMirrorTool(deps) {
|
|
|
800
890
|
}
|
|
801
891
|
//#endregion
|
|
802
892
|
//#region src/host/mapper.ts
|
|
893
|
+
const toToolCallId = dshLlm.ToolCallId ?? dshLlm.CallId ?? ((id) => id);
|
|
803
894
|
function usageFromRaw(raw) {
|
|
804
895
|
const usage = {
|
|
805
896
|
inputTokens: raw.input_tokens ?? 0,
|
|
@@ -969,7 +1060,7 @@ var EventMapper = class {
|
|
|
969
1060
|
index: idx,
|
|
970
1061
|
block: {
|
|
971
1062
|
type: "tool-call",
|
|
972
|
-
id:
|
|
1063
|
+
id: toToolCallId(mirrorCallId(this.opts.runId, absIndex)),
|
|
973
1064
|
name: toolName,
|
|
974
1065
|
arguments: argumentsJson
|
|
975
1066
|
}
|
|
@@ -1079,7 +1170,7 @@ function parseModelsOutput(stdout) {
|
|
|
1079
1170
|
const out = [];
|
|
1080
1171
|
for (const line of text.split(/\n/)) {
|
|
1081
1172
|
const t = line.trim();
|
|
1082
|
-
if (t === "" || t.startsWith("Fetching") || t.startsWith("Error")) continue;
|
|
1173
|
+
if (t === "" || t.startsWith("Fetching") || t.startsWith("Error") || /^(please sign in|warning|tip:)/i.test(t)) continue;
|
|
1083
1174
|
const m = t.match(/^(\S+)(?:\t+|\s{2,})(.+)$/);
|
|
1084
1175
|
if (m && m[1] !== void 0 && m[2] !== void 0) out.push({
|
|
1085
1176
|
slug: m[1],
|
|
@@ -1097,9 +1188,14 @@ function dedupeBySlug(raw) {
|
|
|
1097
1188
|
const seen = /* @__PURE__ */ new Set();
|
|
1098
1189
|
const out = [];
|
|
1099
1190
|
for (const r of raw) {
|
|
1100
|
-
if (
|
|
1101
|
-
|
|
1102
|
-
|
|
1191
|
+
if (!r.slug || typeof r.slug !== "string") continue;
|
|
1192
|
+
const slug = r.slug.trim();
|
|
1193
|
+
if (slug === "" || seen.has(slug)) continue;
|
|
1194
|
+
seen.add(slug);
|
|
1195
|
+
out.push({
|
|
1196
|
+
slug,
|
|
1197
|
+
label: typeof r.label === "string" && r.label.trim() !== "" ? r.label.trim() : slug
|
|
1198
|
+
});
|
|
1103
1199
|
}
|
|
1104
1200
|
return out;
|
|
1105
1201
|
}
|
|
@@ -1207,10 +1303,10 @@ function stripEffortLabel(label, eff) {
|
|
|
1207
1303
|
return label.replace(re, "").trim();
|
|
1208
1304
|
}
|
|
1209
1305
|
function buildFallbackCatalog(defs) {
|
|
1210
|
-
return defs.map((d) => ({
|
|
1211
|
-
id: d.id,
|
|
1212
|
-
name: d.name,
|
|
1213
|
-
efforts: d.efforts
|
|
1306
|
+
return defs.filter((d) => Boolean(d && typeof d.id === "string" && d.id.trim() !== "")).map((d) => ({
|
|
1307
|
+
id: d.id.trim(),
|
|
1308
|
+
name: typeof d.name === "string" && d.name.trim() !== "" ? d.name.trim() : d.id.trim(),
|
|
1309
|
+
efforts: Array.isArray(d.efforts) && d.efforts.length > 0 ? d.efforts.filter((e) => typeof e === "string" && e.trim() !== "") : null
|
|
1214
1310
|
}));
|
|
1215
1311
|
}
|
|
1216
1312
|
var ModelCatalog = class {
|
|
@@ -1288,7 +1384,7 @@ function findEntry(catalog, id) {
|
|
|
1288
1384
|
if (resolved !== id) return catalog.models.find((m) => m.id === resolved);
|
|
1289
1385
|
}
|
|
1290
1386
|
function defaultEffortFor(entry, cfg) {
|
|
1291
|
-
if (!entry.efforts) return void 0;
|
|
1387
|
+
if (!entry.efforts || entry.efforts.length === 0) return void 0;
|
|
1292
1388
|
if (cfg.defaultEffort !== "" && entry.efforts.includes(cfg.defaultEffort)) return cfg.defaultEffort;
|
|
1293
1389
|
for (const pref of [
|
|
1294
1390
|
"high",
|
|
@@ -1790,15 +1886,47 @@ function resolveAgyBin(cfg) {
|
|
|
1790
1886
|
if (cfg.agyBin !== "") candidates.push(cfg.agyBin);
|
|
1791
1887
|
const pathEnv = process.env.PATH ?? "";
|
|
1792
1888
|
for (const dir of pathEnv.split(delimiter)) if (dir !== "") candidates.push(...binCandidates(dir));
|
|
1889
|
+
const home = homedir();
|
|
1793
1890
|
if (IS_WIN) {
|
|
1794
1891
|
const local = process.env.LOCALAPPDATA ?? "";
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1892
|
+
const appData = process.env.APPDATA ?? "";
|
|
1893
|
+
if (local !== "") {
|
|
1894
|
+
candidates.push(join(local, "Programs", "agy", "agy.exe"));
|
|
1895
|
+
candidates.push(join(local, "pnpm", "agy.cmd"));
|
|
1896
|
+
candidates.push(join(local, "pnpm", "agy.exe"));
|
|
1897
|
+
}
|
|
1898
|
+
if (appData !== "") {
|
|
1899
|
+
candidates.push(join(appData, "npm", "agy.cmd"));
|
|
1900
|
+
candidates.push(join(appData, "Roaming", "npm", "agy.cmd"));
|
|
1901
|
+
}
|
|
1902
|
+
candidates.push(join(home, ".local", "bin", "agy.exe"));
|
|
1903
|
+
candidates.push(join(home, ".local", "bin", "agy.cmd"));
|
|
1904
|
+
candidates.push(join(home, ".bun", "bin", "agy.exe"));
|
|
1905
|
+
candidates.push(join(home, ".cargo", "bin", "agy.exe"));
|
|
1906
|
+
candidates.push(join(home, "scoop", "shims", "agy.exe"));
|
|
1798
1907
|
} else {
|
|
1799
|
-
candidates.push(join(
|
|
1908
|
+
candidates.push(join(home, ".local", "bin", "agy"));
|
|
1800
1909
|
candidates.push("/usr/local/bin/agy");
|
|
1801
1910
|
candidates.push("/opt/homebrew/bin/agy");
|
|
1911
|
+
candidates.push("/opt/homebrew/sbin/agy");
|
|
1912
|
+
candidates.push("/home/linuxbrew/.linuxbrew/bin/agy");
|
|
1913
|
+
candidates.push(join(home, ".bun", "bin", "agy"));
|
|
1914
|
+
candidates.push(join(home, ".cargo", "bin", "agy"));
|
|
1915
|
+
candidates.push(join(home, ".local", "share", "pnpm", "agy"));
|
|
1916
|
+
candidates.push(join(home, "Library", "pnpm", "agy"));
|
|
1917
|
+
candidates.push(join(home, ".yarn", "bin", "agy"));
|
|
1918
|
+
candidates.push(join(home, ".npm-global", "bin", "agy"));
|
|
1919
|
+
candidates.push(join(home, ".volta", "bin", "agy"));
|
|
1920
|
+
candidates.push(join(home, ".asdf", "shims", "agy"));
|
|
1921
|
+
candidates.push(join(home, ".nix-profile", "bin", "agy"));
|
|
1922
|
+
candidates.push("/run/current-system/sw/bin/agy");
|
|
1923
|
+
try {
|
|
1924
|
+
const nvmNodeDir = join(home, ".nvm", "versions", "node");
|
|
1925
|
+
if (existsSync(nvmNodeDir)) for (const v of readdirSync(nvmNodeDir)) candidates.push(join(nvmNodeDir, v, "bin", "agy"));
|
|
1926
|
+
} catch {}
|
|
1927
|
+
candidates.push(join(home, ".local", "share", "fnm", "current", "bin", "agy"));
|
|
1928
|
+
candidates.push(join(home, ".fnm", "current", "bin", "agy"));
|
|
1929
|
+
candidates.push(join(home, "Library", "Application Support", "fnm", "current", "bin", "agy"));
|
|
1802
1930
|
}
|
|
1803
1931
|
const hits = [];
|
|
1804
1932
|
for (const c of candidates) try {
|
|
@@ -2087,15 +2215,19 @@ var AgyAdapter = class extends LlmAdapter {
|
|
|
2087
2215
|
const models = [];
|
|
2088
2216
|
const dropped = [];
|
|
2089
2217
|
for (const m of cat.models) {
|
|
2090
|
-
if (
|
|
2091
|
-
|
|
2218
|
+
if (!m || typeof m.id !== "string") continue;
|
|
2219
|
+
const id = m.id.trim();
|
|
2220
|
+
if (id === "") continue;
|
|
2221
|
+
if (seen.has(id)) {
|
|
2222
|
+
dropped.push(id);
|
|
2092
2223
|
continue;
|
|
2093
2224
|
}
|
|
2094
|
-
seen.add(
|
|
2225
|
+
seen.add(id);
|
|
2226
|
+
const name = typeof m.name === "string" && m.name.trim() !== "" ? m.name.trim() : id;
|
|
2095
2227
|
models.push({
|
|
2096
2228
|
provider: PROVIDER_ID,
|
|
2097
|
-
id
|
|
2098
|
-
name
|
|
2229
|
+
id,
|
|
2230
|
+
name,
|
|
2099
2231
|
inputModalities: ["text", "image"]
|
|
2100
2232
|
});
|
|
2101
2233
|
}
|
|
@@ -2104,26 +2236,37 @@ var AgyAdapter = class extends LlmAdapter {
|
|
|
2104
2236
|
}
|
|
2105
2237
|
async resolveModel(_provider, model, _signal) {
|
|
2106
2238
|
const cfg = this.deps.getConfig();
|
|
2107
|
-
const
|
|
2108
|
-
const
|
|
2109
|
-
const
|
|
2239
|
+
const cat = this.deps.catalog.get();
|
|
2240
|
+
const rawModel = typeof model === "string" ? model.trim() : "";
|
|
2241
|
+
const cleanId = rawModel !== "" ? rawModel : cfg.defaultModel;
|
|
2242
|
+
const entry = findEntry(cat, cleanId);
|
|
2243
|
+
const rawName = entry ? entry.name : cleanId;
|
|
2244
|
+
const name = typeof rawName === "string" && rawName.trim() !== "" ? rawName.trim() : cleanId;
|
|
2245
|
+
const contextWindow = typeof cfg.contextWindowDefault === "number" && cfg.contextWindowDefault > 0 ? cfg.contextWindowDefault : 2e5;
|
|
2110
2246
|
const resolved = {
|
|
2111
2247
|
provider: PROVIDER_ID,
|
|
2112
|
-
id:
|
|
2248
|
+
id: cleanId,
|
|
2113
2249
|
name,
|
|
2114
2250
|
inputModalities: ["text", "image"],
|
|
2115
2251
|
context: { contextWindow },
|
|
2116
|
-
defaultMaxTokens: cfg.maxTokensDefault
|
|
2252
|
+
defaultMaxTokens: typeof cfg.maxTokensDefault === "number" && cfg.maxTokensDefault > 0 ? cfg.maxTokensDefault : 8192
|
|
2117
2253
|
};
|
|
2118
|
-
if (entry && entry.efforts) {
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
})
|
|
2125
|
-
|
|
2126
|
-
|
|
2254
|
+
if (entry && Array.isArray(entry.efforts) && entry.efforts.length > 0) {
|
|
2255
|
+
const cleanEfforts = Array.from(new Set(entry.efforts.filter((e) => typeof e === "string" && e.trim() !== "")));
|
|
2256
|
+
if (cleanEfforts.length > 0) {
|
|
2257
|
+
const def = defaultEffortFor({
|
|
2258
|
+
...entry,
|
|
2259
|
+
efforts: cleanEfforts
|
|
2260
|
+
}, cfg);
|
|
2261
|
+
const validDef = def && cleanEfforts.includes(def) ? def : cleanEfforts[0];
|
|
2262
|
+
resolved.reasoning = {
|
|
2263
|
+
efforts: cleanEfforts.map((e) => ({
|
|
2264
|
+
id: e,
|
|
2265
|
+
name: e
|
|
2266
|
+
})),
|
|
2267
|
+
...validDef ? { defaultEffort: validDef } : {}
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2127
2270
|
}
|
|
2128
2271
|
return resolved;
|
|
2129
2272
|
}
|
|
@@ -28346,7 +28489,7 @@ function apply(ctx, entryConfig = {}) {
|
|
|
28346
28489
|
let lastParser = new StreamJsonParser();
|
|
28347
28490
|
const getConfig = () => resolveConfig(entryConfig);
|
|
28348
28491
|
const bin = () => {
|
|
28349
|
-
if (binCache === void 0) binCache = resolveAgyBin(getConfig());
|
|
28492
|
+
if (binCache === void 0 || binCache === null) binCache = resolveAgyBin(getConfig());
|
|
28350
28493
|
return binCache;
|
|
28351
28494
|
};
|
|
28352
28495
|
const version = () => versionCache;
|
|
@@ -28354,10 +28497,41 @@ function apply(ctx, entryConfig = {}) {
|
|
|
28354
28497
|
const pool = new AccountPoolManager();
|
|
28355
28498
|
const quota = new QuotaService(pool);
|
|
28356
28499
|
const semaphore = new Semaphore(() => getConfig().maxConcurrent);
|
|
28500
|
+
const getDiscoveryEnv = (account) => {
|
|
28501
|
+
const cfg = getConfig();
|
|
28502
|
+
return {
|
|
28503
|
+
...process.env,
|
|
28504
|
+
...cfg.disableTelemetry ? {
|
|
28505
|
+
DO_NOT_TRACK: "1",
|
|
28506
|
+
DISABLE_TELEMETRY: "1",
|
|
28507
|
+
GOOGLE_CLOUD_DISABLE_TELEMETRY: "1",
|
|
28508
|
+
ANTIGRAVITY_DISABLE_TELEMETRY: "1"
|
|
28509
|
+
} : {},
|
|
28510
|
+
...account && account.dir ? isolatedHomeEnv(account.dir) : {},
|
|
28511
|
+
...account?.proxyUrl ? {
|
|
28512
|
+
ALL_PROXY: account.proxyUrl,
|
|
28513
|
+
HTTPS_PROXY: account.proxyUrl,
|
|
28514
|
+
HTTP_PROXY: account.proxyUrl,
|
|
28515
|
+
all_proxy: account.proxyUrl,
|
|
28516
|
+
https_proxy: account.proxyUrl,
|
|
28517
|
+
http_proxy: account.proxyUrl
|
|
28518
|
+
} : {}
|
|
28519
|
+
};
|
|
28520
|
+
};
|
|
28357
28521
|
const catalog = new ModelCatalog(async (signal) => {
|
|
28358
28522
|
const b = bin();
|
|
28359
28523
|
if (!b) throw new Error("agy binary not found");
|
|
28360
|
-
const
|
|
28524
|
+
const poolData = pool.getPoolData();
|
|
28525
|
+
const primaryAcc = poolData.primaryAccountId ? pool.getAccount(poolData.primaryAccountId) : void 0;
|
|
28526
|
+
const candidateAccount = primaryAcc && primaryAcc.enabled && !primaryAcc.authRequired ? primaryAcc : pool.getAccounts().find((a) => a.enabled && !a.authRequired);
|
|
28527
|
+
let out = await probeProcess(b, ["models"], 3e4, signal, getDiscoveryEnv(candidateAccount));
|
|
28528
|
+
if ((out.code !== 0 || out.stdout.includes("Please sign in") || /sign in|auth|not logged in/i.test(out.stderrTail)) && (!candidateAccount || !candidateAccount.dir)) {
|
|
28529
|
+
const secondary = pool.getAccounts().find((a) => a.enabled && !a.authRequired && a.dir);
|
|
28530
|
+
if (secondary) {
|
|
28531
|
+
const secondaryOut = await probeProcess(b, ["models"], 3e4, signal, getDiscoveryEnv(secondary));
|
|
28532
|
+
if (secondaryOut.code === 0 && secondaryOut.stdout.trim() !== "") out = secondaryOut;
|
|
28533
|
+
}
|
|
28534
|
+
}
|
|
28361
28535
|
if (out.code !== 0 && out.stdout.trim() === "") throw new Error("agy models failed: " + (out.stderrTail.trim() !== "" ? out.stderrTail.trim().slice(-200) : "exit " + String(out.code)));
|
|
28362
28536
|
return {
|
|
28363
28537
|
stdout: out.stdout,
|
|
@@ -28411,6 +28585,7 @@ function apply(ctx, entryConfig = {}) {
|
|
|
28411
28585
|
const file = overridesPath();
|
|
28412
28586
|
const current = readOverrides(file);
|
|
28413
28587
|
current[key] = value;
|
|
28588
|
+
binCache = void 0;
|
|
28414
28589
|
try {
|
|
28415
28590
|
mkdirSync(stateDir(), { recursive: true });
|
|
28416
28591
|
writeFileSync(file, JSON.stringify(current, null, 2), "utf8");
|
|
@@ -28424,25 +28599,27 @@ function apply(ctx, entryConfig = {}) {
|
|
|
28424
28599
|
log("dormant: disabled by config");
|
|
28425
28600
|
return;
|
|
28426
28601
|
}
|
|
28427
|
-
|
|
28602
|
+
const currentBin = bin();
|
|
28603
|
+
if (!currentBin) {
|
|
28428
28604
|
dormantReason = "agy binary not found — install via https://antigravity.google/docs/cli/install";
|
|
28429
28605
|
log("dormant: agy binary not found");
|
|
28430
28606
|
return;
|
|
28431
28607
|
}
|
|
28432
28608
|
try {
|
|
28433
|
-
versionCache = parseVersion((await probeProcess(
|
|
28609
|
+
versionCache = parseVersion((await probeProcess(currentBin, ["--version"], 1e4)).stdout);
|
|
28434
28610
|
if (versionCache && compareVersions(versionCache, "1.1.8") < 0) {
|
|
28435
28611
|
dormantReason = "agy " + versionCache + " is older than 1.1.8 — run: agy update";
|
|
28436
28612
|
log("dormant: " + dormantReason);
|
|
28437
28613
|
return;
|
|
28438
28614
|
}
|
|
28615
|
+
dormantReason = null;
|
|
28439
28616
|
log("agy detected: " + (versionCache ?? "unknown version"));
|
|
28440
28617
|
} catch {
|
|
28441
28618
|
log("version probe failed — continuing with fallback catalog");
|
|
28442
28619
|
}
|
|
28443
28620
|
await catalog.refreshIfNeeded().catch(() => void 0);
|
|
28444
28621
|
})();
|
|
28445
|
-
if (getConfig().enabled
|
|
28622
|
+
if (getConfig().enabled) try {
|
|
28446
28623
|
ctx.llm.registerAdapter([PROVIDER_ID], adapter);
|
|
28447
28624
|
log("registered provider route: antigravity");
|
|
28448
28625
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-agy-link",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.25",
|
|
4
4
|
"description": "Google Antigravity (agy CLI) models for DeepSeek Harness — stream Gemini/Claude/GPT-OSS subscriptions into DSH with thinking, tool activity, token usage and in-GUI Google OAuth login.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
55
|
-
"@deepseek-ai/dsh-commands": "
|
|
56
|
-
"@deepseek-ai/dsh-llm": "
|
|
57
|
-
"@deepseek-ai/dsh-tools": "
|
|
55
|
+
"@deepseek-ai/dsh-commands": "0.1.2-rc.1",
|
|
56
|
+
"@deepseek-ai/dsh-llm": "0.1.2-rc.1",
|
|
57
|
+
"@deepseek-ai/dsh-tools": "0.1.2-rc.1",
|
|
58
58
|
"@types/node": "^24.3.0",
|
|
59
59
|
"@types/qrcode": "^1.5.5",
|
|
60
60
|
"tsdown": "^0.22.14",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"scripts": {
|
|
84
84
|
"build": "tsdown",
|
|
85
85
|
"check": "tsc --noEmit",
|
|
86
|
-
"test": "node --experimental-transform-types --test \"test/**/*.test.ts\"",
|
|
86
|
+
"test": "node --experimental-transform-types --test --test-concurrency=1 \"test/**/*.test.ts\"",
|
|
87
87
|
"prepack": "npm run build"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|