doc-detective 4.0.2-dev.8 → 4.0.2-dev.9

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 (59) hide show
  1. package/dist/agents/adapters/claude-code.d.ts +77 -0
  2. package/dist/agents/adapters/claude-code.d.ts.map +1 -0
  3. package/dist/agents/adapters/claude-code.js +461 -0
  4. package/dist/agents/adapters/claude-code.js.map +1 -0
  5. package/dist/agents/adapters/codex.d.ts +64 -0
  6. package/dist/agents/adapters/codex.d.ts.map +1 -0
  7. package/dist/agents/adapters/codex.js +299 -0
  8. package/dist/agents/adapters/codex.js.map +1 -0
  9. package/dist/agents/adapters/copilot-cli.d.ts +29 -0
  10. package/dist/agents/adapters/copilot-cli.d.ts.map +1 -0
  11. package/dist/agents/adapters/copilot-cli.js +195 -0
  12. package/dist/agents/adapters/copilot-cli.js.map +1 -0
  13. package/dist/agents/adapters/gemini-cli.d.ts +29 -0
  14. package/dist/agents/adapters/gemini-cli.d.ts.map +1 -0
  15. package/dist/agents/adapters/gemini-cli.js +207 -0
  16. package/dist/agents/adapters/gemini-cli.js.map +1 -0
  17. package/dist/agents/adapters/opencode.d.ts +67 -0
  18. package/dist/agents/adapters/opencode.d.ts.map +1 -0
  19. package/dist/agents/adapters/opencode.js +341 -0
  20. package/dist/agents/adapters/opencode.js.map +1 -0
  21. package/dist/agents/adapters/qwen-code.d.ts +30 -0
  22. package/dist/agents/adapters/qwen-code.d.ts.map +1 -0
  23. package/dist/agents/adapters/qwen-code.js +212 -0
  24. package/dist/agents/adapters/qwen-code.js.map +1 -0
  25. package/dist/agents/command.d.ts +11 -0
  26. package/dist/agents/command.d.ts.map +1 -0
  27. package/dist/agents/command.js +41 -0
  28. package/dist/agents/command.js.map +1 -0
  29. package/dist/agents/fetcher.d.ts +30 -0
  30. package/dist/agents/fetcher.d.ts.map +1 -0
  31. package/dist/agents/fetcher.js +112 -0
  32. package/dist/agents/fetcher.js.map +1 -0
  33. package/dist/agents/prompts.d.ts +24 -0
  34. package/dist/agents/prompts.d.ts.map +1 -0
  35. package/dist/agents/prompts.js +74 -0
  36. package/dist/agents/prompts.js.map +1 -0
  37. package/dist/agents/registry.d.ts +4 -0
  38. package/dist/agents/registry.d.ts.map +1 -0
  39. package/dist/agents/registry.js +25 -0
  40. package/dist/agents/registry.js.map +1 -0
  41. package/dist/agents/runner.d.ts +13 -0
  42. package/dist/agents/runner.d.ts.map +1 -0
  43. package/dist/agents/runner.js +155 -0
  44. package/dist/agents/runner.js.map +1 -0
  45. package/dist/agents/spawn-helper.d.ts +33 -0
  46. package/dist/agents/spawn-helper.d.ts.map +1 -0
  47. package/dist/agents/spawn-helper.js +98 -0
  48. package/dist/agents/spawn-helper.js.map +1 -0
  49. package/dist/agents/types.d.ts +41 -0
  50. package/dist/agents/types.d.ts.map +1 -0
  51. package/dist/agents/types.js +2 -0
  52. package/dist/agents/types.js.map +1 -0
  53. package/dist/cli.js +40 -9
  54. package/dist/cli.js.map +1 -1
  55. package/dist/utils.d.ts +2 -1
  56. package/dist/utils.d.ts.map +1 -1
  57. package/dist/utils.js +14 -8
  58. package/dist/utils.js.map +1 -1
  59. package/package.json +3 -1
@@ -0,0 +1,299 @@
1
+ import path from "node:path";
2
+ import os from "node:os";
3
+ import fs from "node:fs";
4
+ import axios from "axios";
5
+ import YAML from "yaml";
6
+ import { safeSpawn } from "../spawn-helper.js";
7
+ import { fetchAgentToolsZip } from "../fetcher.js";
8
+ const CANONICAL_SKILL = "doc-detective-init";
9
+ const LATEST_SKILL_URL = "https://raw.githubusercontent.com/doc-detective/agent-tools/main/skills/doc-detective-init/SKILL.md";
10
+ export function defaultCodexDeps() {
11
+ return {
12
+ run: (cmd, args) => safeSpawn(cmd, args),
13
+ existsSync: fs.existsSync,
14
+ readFileSync: (p, enc = "utf8") => fs.readFileSync(p, enc),
15
+ readdirSync: (p) => fs.readdirSync(p),
16
+ mkdirSync: (p, opts) => { fs.mkdirSync(p, opts); },
17
+ writeFileSync: (p, data) => fs.writeFileSync(p, typeof data === "string" ? data : Buffer.from(data)),
18
+ rmSync: (p, opts) => { fs.rmSync(p, opts); },
19
+ homedir: os.homedir,
20
+ cwd: () => process.cwd(),
21
+ fetchLatestVersion: async () => {
22
+ const response = await axios.get(LATEST_SKILL_URL, {
23
+ timeout: 5000,
24
+ responseType: "text",
25
+ });
26
+ return parseMetadataVersion(String(response?.data ?? ""));
27
+ },
28
+ fetchZip: (ref) => fetchAgentToolsZip(ref),
29
+ };
30
+ }
31
+ export class CodexAdapter {
32
+ id = "codex";
33
+ displayName = "Codex";
34
+ deps;
35
+ constructor(deps = defaultCodexDeps()) {
36
+ this.deps = deps;
37
+ }
38
+ supportsScopes() {
39
+ return ["global", "project"];
40
+ }
41
+ async detect() {
42
+ const codexHome = path.join(this.deps.homedir(), ".codex");
43
+ const projectAgents = path.join(this.deps.cwd(), ".agents");
44
+ let onPath = false;
45
+ let version;
46
+ try {
47
+ const result = await this.deps.run("codex", ["--version"]);
48
+ if (result.exitCode === 0 && result.stdout.trim()) {
49
+ onPath = true;
50
+ version = result.stdout.trim();
51
+ }
52
+ }
53
+ catch {
54
+ // Binary absent — silent.
55
+ }
56
+ const configPaths = {};
57
+ if (this.deps.existsSync(codexHome))
58
+ configPaths.global = codexHome;
59
+ if (this.deps.existsSync(projectAgents))
60
+ configPaths.project = projectAgents;
61
+ const present = onPath || !!configPaths.global || !!configPaths.project;
62
+ const notes = [];
63
+ if (!onPath && (configPaths.global || configPaths.project)) {
64
+ notes.push("`codex` not on PATH; skills will be written to .agents/skills/ and auto-discovered on next Codex launch.");
65
+ }
66
+ return {
67
+ present,
68
+ onPath,
69
+ version,
70
+ configPaths,
71
+ notes: notes.length ? notes : undefined,
72
+ };
73
+ }
74
+ async getInstallState(scope) {
75
+ const base = this.queryLocalInstallState(scope);
76
+ if (!base.installed)
77
+ return base;
78
+ return this.enrichWithLatest(base);
79
+ }
80
+ skillsRoot(scope) {
81
+ const root = scope === "global" ? this.deps.homedir() : this.deps.cwd();
82
+ return path.join(root, ".agents", "skills");
83
+ }
84
+ canonicalSkillPath(scope) {
85
+ return path.join(this.skillsRoot(scope), CANONICAL_SKILL, "SKILL.md");
86
+ }
87
+ queryLocalInstallState(scope) {
88
+ const canonical = this.canonicalSkillPath(scope);
89
+ if (!this.deps.existsSync(canonical))
90
+ return { installed: false };
91
+ try {
92
+ const raw = this.deps.readFileSync(canonical, "utf8");
93
+ const version = parseMetadataVersion(raw);
94
+ return { installed: true, installedVersion: version };
95
+ }
96
+ catch {
97
+ return { installed: false };
98
+ }
99
+ }
100
+ async enrichWithLatest(state) {
101
+ let latestVersion;
102
+ try {
103
+ latestVersion = await this.deps.fetchLatestVersion();
104
+ }
105
+ catch {
106
+ latestVersion = undefined;
107
+ }
108
+ if (!latestVersion) {
109
+ return { ...state, latestVersion: undefined, upToDate: undefined };
110
+ }
111
+ const upToDate = state.installedVersion !== undefined
112
+ ? state.installedVersion === latestVersion
113
+ : undefined;
114
+ return { ...state, latestVersion, upToDate };
115
+ }
116
+ // Public (readonly) accessor on `deps` so tests can swap dependencies after
117
+ // construction if needed (e.g., force fetchZip to fail mid-test).
118
+ get depsRef() {
119
+ return this.deps;
120
+ }
121
+ async install(opts) {
122
+ const local = this.queryLocalInstallState(opts.scope);
123
+ const enriched = local.installed ? await this.enrichWithLatest(local) : local;
124
+ const isInstalled = enriched.installed;
125
+ const isUpToDate = enriched.upToDate === true;
126
+ // `upToDate === undefined` means the network probe for the latest
127
+ // version failed (offline, DNS hiccup, GitHub rate limit). Treat that
128
+ // as "keep what's on disk" rather than forcing a re-fetch every run —
129
+ // otherwise every offline re-run downloads the zip and overwrites
130
+ // files. `--force` still works for explicit refresh.
131
+ const latestUnknown = isInstalled && enriched.upToDate === undefined;
132
+ if (isInstalled && !opts.force && (isUpToDate || latestUnknown)) {
133
+ if (latestUnknown) {
134
+ opts.logger("Unable to determine the latest Codex skills version; keeping the existing installation. Re-run with --force to refresh explicitly.", "info");
135
+ }
136
+ return {
137
+ adapterId: this.id,
138
+ scope: opts.scope,
139
+ action: "already-up-to-date",
140
+ installedVersion: enriched.installedVersion,
141
+ };
142
+ }
143
+ const target = this.skillsRoot(opts.scope);
144
+ if (opts.dryRun) {
145
+ opts.logger(`[dry-run] would fetch doc-detective/agent-tools and copy doc-detective-* skills into ${target}`, "info");
146
+ return {
147
+ adapterId: this.id,
148
+ scope: opts.scope,
149
+ action: "dry-run",
150
+ installedVersion: enriched.installedVersion,
151
+ };
152
+ }
153
+ const fetched = await this.deps.fetchZip("main");
154
+ try {
155
+ const sourceSkills = path.join(fetched.tempDir, "skills");
156
+ if (!this.deps.existsSync(sourceSkills)) {
157
+ throw new Error(`Fetched agent-tools archive has no skills/ directory at ${sourceSkills}.`);
158
+ }
159
+ const sourceNames = (this.deps.readdirSync?.(sourceSkills) ?? []).filter((n) => n.startsWith("doc-detective-"));
160
+ if (sourceNames.length === 0) {
161
+ throw new Error("Fetched agent-tools archive has no doc-detective-* skills to install.");
162
+ }
163
+ // Fall back to the module-level `fs.rmSync` when no rmSync is injected
164
+ // — required, not optional, because `fs.renameSync` below fails with
165
+ // EEXIST if the old `dst` is still in place on cross-platform systems.
166
+ const rmSync = this.deps.rmSync ??
167
+ ((p, opts) => fs.rmSync(p, opts));
168
+ this.mkdirp(target);
169
+ for (const name of sourceNames) {
170
+ const src = path.join(sourceSkills, name);
171
+ const dst = path.join(target, name);
172
+ // Atomic-ish overwrite: copy into a sibling tmp dir, then remove the
173
+ // old dst and rename tmp into place. If copyDir fails (bad archive
174
+ // entry, disk full, permissions), the existing skill is untouched.
175
+ const tmpDst = `${dst}.install.tmp.${process.pid}.${Date.now()}`;
176
+ if (this.deps.existsSync(tmpDst)) {
177
+ rmSync(tmpDst, { recursive: true, force: true });
178
+ }
179
+ try {
180
+ this.copyDir(src, tmpDst);
181
+ }
182
+ catch (err) {
183
+ try {
184
+ rmSync(tmpDst, { recursive: true, force: true });
185
+ }
186
+ catch { }
187
+ throw err;
188
+ }
189
+ if (this.deps.existsSync(dst)) {
190
+ rmSync(dst, { recursive: true, force: true });
191
+ }
192
+ fs.renameSync(tmpDst, dst);
193
+ opts.logger(`Copied skill: ${name}`, "debug");
194
+ }
195
+ // Read back the newly-installed version from the canonical skill.
196
+ const installedVersion = this.queryLocalInstallState(opts.scope).installedVersion ??
197
+ enriched.latestVersion;
198
+ let action;
199
+ if (opts.force && isInstalled && isUpToDate)
200
+ action = "forced";
201
+ else if (isInstalled)
202
+ action = "updated";
203
+ else
204
+ action = "installed";
205
+ return {
206
+ adapterId: this.id,
207
+ scope: opts.scope,
208
+ action,
209
+ installedVersion,
210
+ };
211
+ }
212
+ catch (err) {
213
+ const reason = err instanceof Error ? err.message : String(err);
214
+ throw new Error(`Failed to install Codex skills from GitHub: ${reason}`);
215
+ }
216
+ finally {
217
+ // Only clean up the fetched tempDir when the fetcher reports ownership.
218
+ // Tests that point at a pre-populated source tree set `owned: false` so
219
+ // their fixtures aren't wiped out of from under them.
220
+ if (fetched.owned) {
221
+ // Fall back to the real `fs.rmSync` when deps didn't inject one.
222
+ // Without this, an undefined `deps.rmSync` would silently leak the
223
+ // fetched temp archive — the `?.` would short-circuit and drop it.
224
+ const rm = this.deps.rmSync ??
225
+ ((p, opts) => fs.rmSync(p, opts));
226
+ try {
227
+ rm(fetched.tempDir, { recursive: true, force: true });
228
+ }
229
+ catch { }
230
+ }
231
+ }
232
+ }
233
+ mkdirp(p) {
234
+ if (this.deps.mkdirSync) {
235
+ this.deps.mkdirSync(p, { recursive: true });
236
+ }
237
+ else {
238
+ fs.mkdirSync(p, { recursive: true });
239
+ }
240
+ }
241
+ /**
242
+ * Recursive directory copy. Uses `this.deps.readdirSync` and
243
+ * `this.deps.writeFileSync` where the injected signatures match, but falls
244
+ * back to `fs.statSync` and buffer-returning `fs.readFileSync` directly —
245
+ * the `CodexDeps.readFileSync` signature returns a string (UTF-8), so we
246
+ * can't use it here without losing binary content (images, shell scripts
247
+ * with executable bits, etc.). Fully-injected recursion would require
248
+ * widening the deps interface with buffer/stat variants; for the narrow
249
+ * use case of copying extracted skills the direct fs calls are fine.
250
+ */
251
+ copyDir(src, dst) {
252
+ this.mkdirp(dst);
253
+ const entries = this.deps.readdirSync?.(src) ?? [];
254
+ for (const entry of entries) {
255
+ const from = path.join(src, entry);
256
+ const to = path.join(dst, entry);
257
+ const stat = fs.statSync(from);
258
+ if (stat.isDirectory()) {
259
+ this.copyDir(from, to);
260
+ }
261
+ else {
262
+ const buf = fs.readFileSync(from);
263
+ if (this.deps.writeFileSync) {
264
+ this.deps.writeFileSync(to, buf);
265
+ }
266
+ else {
267
+ fs.writeFileSync(to, buf);
268
+ }
269
+ // Preserve executable bits (and other mode bits) from the source.
270
+ // Writing a Buffer doesn't carry these through — shell scripts in
271
+ // `hooks/scripts/` and similar need this or they won't execute.
272
+ try {
273
+ fs.chmodSync(to, stat.mode);
274
+ }
275
+ catch { }
276
+ }
277
+ }
278
+ }
279
+ }
280
+ /**
281
+ * Parse YAML frontmatter from a SKILL.md body and return metadata.version.
282
+ * Returns undefined if the front matter is missing, malformed, or lacks the
283
+ * metadata.version key. Never throws — Codex skills can vary.
284
+ */
285
+ export function parseMetadataVersion(body) {
286
+ const match = body.match(/^---\r?\n([\s\S]*?)\r?\n---/);
287
+ if (!match)
288
+ return undefined;
289
+ try {
290
+ const frontmatter = YAML.parse(match[1]);
291
+ const v = frontmatter?.metadata?.version;
292
+ return typeof v === "string" ? v : undefined;
293
+ }
294
+ catch {
295
+ return undefined;
296
+ }
297
+ }
298
+ export const codexAdapter = new CodexAdapter();
299
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/agents/adapters/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { AgentAdapter, DetectionResult, InstallOptions, InstallReport, InstallState, Scope } from "../types.js";
2
+ export interface RunResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ exitCode: number;
6
+ }
7
+ export interface CopilotCliDeps {
8
+ run: (cmd: string, args: string[]) => Promise<RunResult>;
9
+ existsSync: (p: string) => boolean;
10
+ readFileSync: (p: string, encoding?: BufferEncoding) => string;
11
+ homedir: () => string;
12
+ fetchLatestVersion: () => Promise<string | undefined>;
13
+ }
14
+ export declare function defaultCopilotCliDeps(): CopilotCliDeps;
15
+ export declare class CopilotCliAdapter implements AgentAdapter {
16
+ readonly id = "copilot";
17
+ readonly displayName = "GitHub Copilot CLI";
18
+ private deps;
19
+ constructor(deps?: CopilotCliDeps);
20
+ supportsScopes(): Scope[];
21
+ detect(): Promise<DetectionResult>;
22
+ getInstallState(_scope: Scope): Promise<InstallState>;
23
+ private pluginJsonPath;
24
+ private queryLocalInstallState;
25
+ private enrichWithLatest;
26
+ install(opts: InstallOptions): Promise<InstallReport>;
27
+ }
28
+ export declare const copilotCliAdapter: AgentAdapter;
29
+ //# sourceMappingURL=copilot-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-cli.d.ts","sourceRoot":"","sources":["../../../src/agents/adapters/copilot-cli.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,KAAK,EACN,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzD,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MAAM,CAAC;IAC/D,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACvD;AAQD,wBAAgB,qBAAqB,IAAI,cAAc,CAetD;AAED,qBAAa,iBAAkB,YAAW,YAAY;IACpD,QAAQ,CAAC,EAAE,aAAa;IACxB,QAAQ,CAAC,WAAW,wBAAwB;IAC5C,OAAO,CAAC,IAAI,CAAiB;gBAEjB,IAAI,GAAE,cAAwC;IAI1D,cAAc,IAAI,KAAK,EAAE;IAKnB,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC;IAkClC,eAAe,CAAC,MAAM,EAAE,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC;IAM3D,OAAO,CAAC,cAAc;YAeR,sBAAsB;YAetB,gBAAgB;IAiBxB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA6F5D;AAED,eAAO,MAAM,iBAAiB,EAAE,YAAsC,CAAC"}
@@ -0,0 +1,195 @@
1
+ import path from "node:path";
2
+ import os from "node:os";
3
+ import fs from "node:fs";
4
+ import axios from "axios";
5
+ import { safeSpawn } from "../spawn-helper.js";
6
+ const MARKETPLACE_NAME = "doc-detective";
7
+ const PLUGIN_NAME = "doc-detective";
8
+ const PLUGIN_KEY = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
9
+ const LATEST_PLUGIN_JSON_URL = "https://raw.githubusercontent.com/doc-detective/agent-tools/main/plugins/doc-detective/.claude-plugin/plugin.json";
10
+ export function defaultCopilotCliDeps() {
11
+ return {
12
+ run: (cmd, args) => safeSpawn(cmd, args),
13
+ existsSync: fs.existsSync,
14
+ readFileSync: (p, enc = "utf8") => fs.readFileSync(p, enc),
15
+ homedir: os.homedir,
16
+ fetchLatestVersion: async () => {
17
+ const response = await axios.get(LATEST_PLUGIN_JSON_URL, {
18
+ timeout: 5000,
19
+ responseType: "json",
20
+ });
21
+ const version = response?.data?.version;
22
+ return typeof version === "string" ? version : undefined;
23
+ },
24
+ };
25
+ }
26
+ export class CopilotCliAdapter {
27
+ id = "copilot";
28
+ displayName = "GitHub Copilot CLI";
29
+ deps;
30
+ constructor(deps = defaultCopilotCliDeps()) {
31
+ this.deps = deps;
32
+ }
33
+ supportsScopes() {
34
+ // Copilot CLI's `plugin install` has no --scope flag — always user-global.
35
+ return ["global"];
36
+ }
37
+ async detect() {
38
+ const copilotHome = path.join(this.deps.homedir(), ".copilot");
39
+ let onPath = false;
40
+ let version;
41
+ try {
42
+ const result = await this.deps.run("copilot", ["--version"]);
43
+ if (result.exitCode === 0 && result.stdout.trim()) {
44
+ onPath = true;
45
+ version = result.stdout.trim();
46
+ }
47
+ }
48
+ catch {
49
+ // Binary absent — fall through.
50
+ }
51
+ const configPaths = {};
52
+ if (this.deps.existsSync(copilotHome))
53
+ configPaths.global = copilotHome;
54
+ const present = onPath || !!configPaths.global;
55
+ const notes = [];
56
+ if (!onPath && configPaths.global) {
57
+ notes.push("`copilot` not on PATH but ~/.copilot exists; install requires the binary — run `npm install -g @github/copilot`.");
58
+ }
59
+ return {
60
+ present,
61
+ onPath,
62
+ version,
63
+ configPaths,
64
+ notes: notes.length ? notes : undefined,
65
+ };
66
+ }
67
+ async getInstallState(_scope) {
68
+ const base = await this.queryLocalInstallState();
69
+ if (!base.installed)
70
+ return base;
71
+ return this.enrichWithLatest(base);
72
+ }
73
+ pluginJsonPath() {
74
+ // Copilot CLI nests the plugin manifest under `.claude-plugin/` inside
75
+ // the installed plugin directory (verified on disk; the Claude-plugin
76
+ // format requires a `.claude-plugin/plugin.json` manifest).
77
+ return path.join(this.deps.homedir(), ".copilot", "installed-plugins", MARKETPLACE_NAME, PLUGIN_NAME, ".claude-plugin", "plugin.json");
78
+ }
79
+ async queryLocalInstallState() {
80
+ const manifestPath = this.pluginJsonPath();
81
+ if (!this.deps.existsSync(manifestPath))
82
+ return { installed: false };
83
+ try {
84
+ const raw = this.deps.readFileSync(manifestPath, "utf8");
85
+ const parsed = JSON.parse(raw);
86
+ if (typeof parsed?.version === "string") {
87
+ return { installed: true, installedVersion: parsed.version };
88
+ }
89
+ return { installed: true };
90
+ }
91
+ catch {
92
+ return { installed: false };
93
+ }
94
+ }
95
+ async enrichWithLatest(state) {
96
+ let latestVersion;
97
+ try {
98
+ latestVersion = await this.deps.fetchLatestVersion();
99
+ }
100
+ catch {
101
+ latestVersion = undefined;
102
+ }
103
+ if (!latestVersion) {
104
+ return { ...state, latestVersion: undefined, upToDate: undefined };
105
+ }
106
+ const upToDate = state.installedVersion !== undefined
107
+ ? state.installedVersion === latestVersion
108
+ : undefined;
109
+ return { ...state, latestVersion, upToDate };
110
+ }
111
+ async install(opts) {
112
+ const base = await this.queryLocalInstallState();
113
+ const enriched = base.installed ? await this.enrichWithLatest(base) : base;
114
+ const isInstalled = enriched.installed;
115
+ const isUpToDate = enriched.upToDate === true;
116
+ if (isInstalled && isUpToDate && !opts.force) {
117
+ return {
118
+ adapterId: this.id,
119
+ scope: opts.scope,
120
+ action: "already-up-to-date",
121
+ installedVersion: enriched.installedVersion,
122
+ };
123
+ }
124
+ const commands = isInstalled
125
+ ? [["copilot", "plugin", "update", PLUGIN_KEY]]
126
+ : [
127
+ ["copilot", "plugin", "marketplace", "add", "doc-detective/agent-tools"],
128
+ ["copilot", "plugin", "install", PLUGIN_KEY],
129
+ ];
130
+ if (opts.dryRun) {
131
+ for (const cmd of commands) {
132
+ opts.logger(`[dry-run] would run: ${cmd.join(" ")}`, "info");
133
+ }
134
+ return {
135
+ adapterId: this.id,
136
+ scope: opts.scope,
137
+ action: "dry-run",
138
+ installedVersion: enriched.installedVersion,
139
+ };
140
+ }
141
+ for (const [cmd, ...args] of commands) {
142
+ opts.logger(`Running: ${cmd} ${args.join(" ")}`, "debug");
143
+ let result;
144
+ try {
145
+ result = await this.deps.run(cmd, args);
146
+ }
147
+ catch (err) {
148
+ // ENOENT from safeSpawn = binary missing. Surface an actionable
149
+ // install hint rather than the raw spawn error.
150
+ const code = err?.code;
151
+ if (code === "ENOENT") {
152
+ throw new Error("GitHub Copilot CLI is not installed or not on PATH. Run `npm install -g @github/copilot` (then `copilot login`) and re-run install-agents.");
153
+ }
154
+ throw err;
155
+ }
156
+ if (result.stdout)
157
+ opts.logger(result.stdout, "debug");
158
+ if (result.exitCode !== 0) {
159
+ // Copilot sometimes prints auth/login hints to stdout with empty
160
+ // stderr, so classify on the combined output — otherwise the
161
+ // actionable `copilot login` hint gets swallowed and the user sees
162
+ // a generic "exited with code 1" instead.
163
+ const output = [result.stderr, result.stdout].filter(Boolean).join("\n");
164
+ const msg = output || `exit code ${result.exitCode}`;
165
+ if (/auth|login|token|unauthori[sz]ed/i.test(msg)) {
166
+ throw new Error(`GitHub Copilot CLI is not authenticated. Run \`copilot login\` and re-run install-agents. (copilot said: ${msg})`);
167
+ }
168
+ throw new Error(`\`${cmd} ${args.join(" ")}\` exited with code ${result.exitCode}: ${msg}`);
169
+ }
170
+ }
171
+ // Prefer the network-fetched latest (authoritative post-install); fall
172
+ // back to a fresh read of ~/.copilot/installed-plugins/…/plugin.json,
173
+ // then to the pre-install state. Same pattern as the Qwen adapter — keeps
174
+ // the install report accurate when `fetchLatestVersion()` failed.
175
+ const postInstall = await this.queryLocalInstallState();
176
+ const installedVersion = enriched.latestVersion ??
177
+ postInstall.installedVersion ??
178
+ enriched.installedVersion;
179
+ let action;
180
+ if (opts.force && isInstalled && isUpToDate)
181
+ action = "forced";
182
+ else if (isInstalled)
183
+ action = "updated";
184
+ else
185
+ action = "installed";
186
+ return {
187
+ adapterId: this.id,
188
+ scope: opts.scope,
189
+ action,
190
+ installedVersion,
191
+ };
192
+ }
193
+ }
194
+ export const copilotCliAdapter = new CopilotCliAdapter();
195
+ //# sourceMappingURL=copilot-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-cli.js","sourceRoot":"","sources":["../../../src/agents/adapters/copilot-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { AgentAdapter, DetectionResult, InstallOptions, InstallReport, InstallState, Scope } from "../types.js";
2
+ export interface RunResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ exitCode: number;
6
+ }
7
+ export interface GeminiCliDeps {
8
+ run: (cmd: string, args: string[]) => Promise<RunResult>;
9
+ existsSync: (p: string) => boolean;
10
+ readFileSync: (p: string, encoding?: BufferEncoding) => string;
11
+ homedir: () => string;
12
+ fetchLatestVersion: () => Promise<string | undefined>;
13
+ }
14
+ export declare function defaultGeminiCliDeps(): GeminiCliDeps;
15
+ export declare class GeminiCliAdapter implements AgentAdapter {
16
+ readonly id = "gemini";
17
+ readonly displayName = "Gemini CLI";
18
+ private deps;
19
+ constructor(deps?: GeminiCliDeps);
20
+ supportsScopes(): Scope[];
21
+ detect(): Promise<DetectionResult>;
22
+ getInstallState(_scope: Scope): Promise<InstallState>;
23
+ private manifestPath;
24
+ private queryLocalInstallState;
25
+ private enrichWithLatest;
26
+ install(opts: InstallOptions): Promise<InstallReport>;
27
+ }
28
+ export declare const geminiCliAdapter: AgentAdapter;
29
+ //# sourceMappingURL=gemini-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-cli.d.ts","sourceRoot":"","sources":["../../../src/agents/adapters/gemini-cli.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,KAAK,EACN,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzD,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MAAM,CAAC;IAC/D,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACvD;AAOD,wBAAgB,oBAAoB,IAAI,aAAa,CAepD;AAED,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,EAAE,YAAY;IACvB,QAAQ,CAAC,WAAW,gBAAgB;IACpC,OAAO,CAAC,IAAI,CAAgB;gBAEhB,IAAI,GAAE,aAAsC;IAIxD,cAAc,IAAI,KAAK,EAAE;IAKnB,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC;IAgClC,eAAe,CAAC,MAAM,EAAE,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC;IAM3D,OAAO,CAAC,YAAY;YAIN,sBAAsB;YAsCtB,gBAAgB;IAiBxB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAmF5D;AAED,eAAO,MAAM,gBAAgB,EAAE,YAAqC,CAAC"}