@mcoda/integrations 0.1.9 → 0.1.11

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/README.md CHANGED
@@ -27,7 +27,7 @@ const docs = await client.search({ docType: "rfp", query: "payments" });
27
27
 
28
28
  ## Notes
29
29
  - Docdex state lives under `~/.docdex` (managed by the `docdex` CLI); mcoda does not create repo-local `.docdex`.
30
- - Chromium QA expects Playwright browsers provisioned via `docdex setup`.
30
+ - Chromium QA expects Docdex-installed Chromium (`docdex setup` or `MCODA_QA_CHROMIUM_PATH`).
31
31
  - Some integrations call external services; configure base URLs and tokens as needed.
32
32
  - Primarily used by the mcoda CLI; APIs may evolve.
33
33
 
@@ -28,14 +28,21 @@ export declare class DocdexClient {
28
28
  private resolvedBaseUrl?;
29
29
  private repoId?;
30
30
  private initializing;
31
+ private disabledReason?;
31
32
  constructor(options?: {
32
33
  workspaceRoot?: string;
33
34
  baseUrl?: string;
34
35
  authToken?: string;
35
36
  repoId?: string;
36
37
  });
38
+ disable(reason?: string): void;
39
+ isAvailable(): boolean;
37
40
  private normalizePath;
41
+ private resolveLocalDocPath;
42
+ private loadLocalDoc;
38
43
  private resolveBaseUrl;
44
+ private buildMissingRepoMessage;
45
+ ensureRepoScope(): Promise<void>;
39
46
  private ensureRepoInitialized;
40
47
  private fetchRemote;
41
48
  private buildLocalDoc;
@@ -51,5 +58,8 @@ export declare class DocdexClient {
51
58
  reindex(): Promise<void>;
52
59
  registerDocument(input: RegisterDocumentInput): Promise<DocdexDocument>;
53
60
  ensureRegisteredFromFile(docPath: string, docType: string, metadata?: Record<string, unknown>): Promise<DocdexDocument>;
61
+ private callMcp;
62
+ memorySave(text: string): Promise<void>;
63
+ savePreference(agentId: string, category: string, content: string): Promise<void>;
54
64
  }
55
65
  //# sourceMappingURL=DocdexClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DocdexClient.d.ts","sourceRoot":"","sources":["../../src/docdex/DocdexClient.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAkDD,qBAAa,YAAY;IAMrB,OAAO,CAAC,OAAO;IALjB,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;gBAGnB,OAAO,GAAE;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACZ;IAKR,OAAO,CAAC,aAAa;YAYP,cAAc;YAWd,qBAAqB;YA0BrB,WAAW;IA8BzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,mBAAmB;IAmDrB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA4BtD,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAS1F,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAkBtH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAcxB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IA0BvE,wBAAwB,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,cAAc,CAAC;CAoB3B"}
1
+ {"version":3,"file":"DocdexClient.d.ts","sourceRoot":"","sources":["../../src/docdex/DocdexClient.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAkDD,qBAAa,YAAY;IAOrB,OAAO,CAAC,OAAO;IANjB,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAC,CAAS;gBAGtB,OAAO,GAAE;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACZ;IAKR,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAI9B,WAAW,IAAI,OAAO;IAItB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,mBAAmB;YASb,YAAY;YAYZ,cAAc;IAY5B,OAAO,CAAC,uBAAuB;IAKzB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAWxB,qBAAqB;YA0BrB,WAAW;IAwCzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,mBAAmB;IAmDrB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA4BtD,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAkB1F,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAkBtH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAcxB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IA0BvE,wBAAwB,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,cAAc,CAAC;YAqBZ,OAAO;IAyBf,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQvC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQxF"}
@@ -59,6 +59,12 @@ export class DocdexClient {
59
59
  this.initializing = false;
60
60
  this.repoId = options.repoId;
61
61
  }
62
+ disable(reason) {
63
+ this.disabledReason = reason?.trim() || "docdex unavailable";
64
+ }
65
+ isAvailable() {
66
+ return !this.disabledReason;
67
+ }
62
68
  normalizePath(inputPath) {
63
69
  if (!inputPath)
64
70
  return undefined;
@@ -71,7 +77,32 @@ export class DocdexClient {
71
77
  }
72
78
  return absolute;
73
79
  }
80
+ resolveLocalDocPath(docPath) {
81
+ if (!this.options.workspaceRoot)
82
+ return undefined;
83
+ const root = path.resolve(this.options.workspaceRoot);
84
+ const absolute = path.resolve(path.isAbsolute(docPath) ? docPath : path.join(root, docPath));
85
+ if (!absolute.startsWith(root))
86
+ return undefined;
87
+ const relative = path.relative(root, absolute);
88
+ return { absolute, relative: relative || undefined };
89
+ }
90
+ async loadLocalDoc(docPath, docType) {
91
+ const resolved = this.resolveLocalDocPath(docPath);
92
+ if (!resolved)
93
+ return undefined;
94
+ try {
95
+ const content = await fs.readFile(resolved.absolute, "utf8");
96
+ const inferred = docType || inferDocType(resolved.relative ?? docPath);
97
+ return this.buildLocalDoc(inferred, resolved.relative ?? docPath, content);
98
+ }
99
+ catch {
100
+ return undefined;
101
+ }
102
+ }
74
103
  async resolveBaseUrl() {
104
+ if (this.disabledReason)
105
+ return undefined;
75
106
  if (this.options.baseUrl !== undefined) {
76
107
  const trimmed = this.options.baseUrl.trim();
77
108
  return trimmed ? normalizeBaseUrl(trimmed) : undefined;
@@ -82,6 +113,21 @@ export class DocdexClient {
82
113
  this.resolvedBaseUrl = resolved ? normalizeBaseUrl(resolved) : undefined;
83
114
  return this.resolvedBaseUrl;
84
115
  }
116
+ buildMissingRepoMessage() {
117
+ const root = this.options.workspaceRoot ? path.resolve(this.options.workspaceRoot) : "unknown workspace";
118
+ return `Docdex repo scope missing for ${root}. Ensure docdexd is running and initialized for this repo, or set MCODA_DOCDEX_URL and MCODA_DOCDEX_REPO_ID.`;
119
+ }
120
+ async ensureRepoScope() {
121
+ const baseUrl = await this.resolveBaseUrl();
122
+ if (!baseUrl)
123
+ return;
124
+ if (!this.repoId) {
125
+ await this.ensureRepoInitialized(baseUrl, true);
126
+ }
127
+ if (!this.repoId) {
128
+ throw new Error(this.buildMissingRepoMessage());
129
+ }
130
+ }
85
131
  async ensureRepoInitialized(baseUrl, force = false) {
86
132
  if ((this.repoId && !force) || this.initializing)
87
133
  return;
@@ -113,18 +159,29 @@ export class DocdexClient {
113
159
  }
114
160
  }
115
161
  async fetchRemote(pathname, init) {
162
+ if (this.disabledReason) {
163
+ throw new Error(`Docdex unavailable: ${this.disabledReason}`);
164
+ }
116
165
  const baseUrl = await this.resolveBaseUrl();
117
166
  if (!baseUrl) {
118
167
  throw new Error("Docdex baseUrl not configured. Run docdex setup or set MCODA_DOCDEX_URL.");
119
168
  }
120
- await this.ensureRepoInitialized(baseUrl);
169
+ await this.ensureRepoScope();
121
170
  const url = new URL(pathname, baseUrl);
171
+ if (this.repoId && !url.searchParams.has("repo_id")) {
172
+ url.searchParams.set("repo_id", this.repoId);
173
+ }
174
+ if (this.options.workspaceRoot && !url.searchParams.has("repo_root")) {
175
+ url.searchParams.set("repo_root", path.resolve(this.options.workspaceRoot));
176
+ }
122
177
  const buildHeaders = () => {
123
178
  const headers = { "Content-Type": "application/json" };
124
179
  if (this.options.authToken)
125
180
  headers.authorization = `Bearer ${this.options.authToken}`;
126
181
  if (this.repoId)
127
182
  headers["x-docdex-repo-id"] = this.repoId;
183
+ if (this.options.workspaceRoot)
184
+ headers["x-docdex-repo-root"] = path.resolve(this.options.workspaceRoot);
128
185
  return { ...headers, ...init?.headers };
129
186
  };
130
187
  const response = await fetch(url, { ...init, headers: buildHeaders() });
@@ -241,9 +298,19 @@ export class DocdexClient {
241
298
  async findDocumentByPath(docPath, docType) {
242
299
  const normalized = this.normalizePath(docPath);
243
300
  const query = normalized ?? docPath;
244
- const docs = await this.search({ query, docType });
245
- if (!docs.length)
246
- return undefined;
301
+ let docs = [];
302
+ try {
303
+ docs = await this.search({ query, docType });
304
+ }
305
+ catch (error) {
306
+ const local = await this.loadLocalDoc(docPath, docType);
307
+ if (local)
308
+ return local;
309
+ throw error;
310
+ }
311
+ if (!docs.length) {
312
+ return await this.loadLocalDoc(docPath, docType);
313
+ }
247
314
  if (!normalized)
248
315
  return docs[0];
249
316
  return docs.find((doc) => doc.path === normalized) ?? docs[0];
@@ -331,4 +398,45 @@ export class DocdexClient {
331
398
  return this.buildLocalDoc(inferredType, normalizedPath, content, metadata);
332
399
  }
333
400
  }
401
+ async callMcp(toolName, args) {
402
+ const payload = {
403
+ jsonrpc: "2.0",
404
+ id: randomUUID(),
405
+ method: "tools/call",
406
+ params: {
407
+ name: toolName,
408
+ arguments: args,
409
+ },
410
+ };
411
+ const response = await this.fetchRemote("/v1/mcp", {
412
+ method: "POST",
413
+ body: JSON.stringify(payload),
414
+ });
415
+ const raw = (await response.json());
416
+ if (raw.error) {
417
+ throw new Error(raw.error.message ?? "Docdex MCP call failed");
418
+ }
419
+ const result = raw.result;
420
+ if (result && typeof result === "object" && result.structuredContent !== undefined) {
421
+ return result.structuredContent;
422
+ }
423
+ return result;
424
+ }
425
+ async memorySave(text) {
426
+ if (!text.trim())
427
+ return;
428
+ await this.callMcp("docdex_memory_save", {
429
+ project_root: this.options.workspaceRoot,
430
+ text,
431
+ });
432
+ }
433
+ async savePreference(agentId, category, content) {
434
+ if (!agentId.trim() || !category.trim() || !content.trim())
435
+ return;
436
+ await this.callMcp("docdex_save_preference", {
437
+ agent_id: agentId,
438
+ category,
439
+ content,
440
+ });
441
+ }
334
442
  }
@@ -8,18 +8,32 @@ export interface DocdexCheckResult {
8
8
  details?: Record<string, unknown>;
9
9
  }>;
10
10
  }
11
- export interface DocdexBrowserInfo {
11
+ export interface DocdexHealthSummary {
12
12
  ok: boolean;
13
13
  message?: string;
14
- browsersPath?: string;
15
- browsers?: Array<{
14
+ failedChecks?: Array<{
16
15
  name?: string;
17
- path?: string;
18
- version?: string;
16
+ status?: string;
17
+ message?: string;
19
18
  }>;
20
19
  }
20
+ export interface DocdexChromiumDetails {
21
+ path?: string;
22
+ manifestPath?: string;
23
+ installedAt?: string;
24
+ version?: string;
25
+ platform?: string;
26
+ downloadUrl?: string;
27
+ }
28
+ export interface DocdexBrowserInfo {
29
+ ok: boolean;
30
+ message?: string;
31
+ installHint?: string;
32
+ autoInstallEnabled?: boolean;
33
+ configuredKind?: string;
34
+ chromium?: DocdexChromiumDetails;
35
+ }
21
36
  export declare const resolveDocdexBinary: () => string | undefined;
22
- export declare const resolvePlaywrightCli: () => string | undefined;
23
37
  export declare const runDocdex: (args: string[], options?: {
24
38
  cwd?: string;
25
39
  env?: NodeJS.ProcessEnv;
@@ -27,14 +41,17 @@ export declare const runDocdex: (args: string[], options?: {
27
41
  stdout: string;
28
42
  stderr: string;
29
43
  }>;
44
+ export declare const parseDocdexCheckOutput: (output: string) => DocdexCheckResult;
30
45
  export declare const readDocdexCheck: (options?: {
31
46
  cwd?: string;
32
47
  env?: NodeJS.ProcessEnv;
33
48
  }) => Promise<DocdexCheckResult>;
49
+ export declare const summarizeDocdexCheck: (check: DocdexCheckResult) => DocdexHealthSummary;
34
50
  export declare const resolveDocdexBaseUrl: (options?: {
35
51
  cwd?: string;
36
52
  env?: NodeJS.ProcessEnv;
37
53
  }) => Promise<string | undefined>;
54
+ export declare const parseDocdexBrowserCheck: (check: DocdexCheckResult) => DocdexBrowserInfo;
38
55
  export declare const resolveDocdexBrowserInfo: (options?: {
39
56
  cwd?: string;
40
57
  env?: NodeJS.ProcessEnv;
@@ -1 +1 @@
1
- {"version":3,"file":"DocdexRuntime.d.ts","sourceRoot":"","sources":["../../src/docdex/DocdexRuntime.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAuBD,eAAO,MAAM,mBAAmB,QAAO,MAAM,GAAG,SAI/C,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAO,MAAM,GAAG,SAehD,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,MAAM,MAAM,EAAE,EACd,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KACtD,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAU5C,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KAAG,OAAO,CAAC,iBAAiB,CAsBxH,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAsB9H,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KACtD,OAAO,CAAC,iBAAiB,CAgC3B,CAAC"}
1
+ {"version":3,"file":"DocdexRuntime.d.ts","sourceRoot":"","sources":["../../src/docdex/DocdexRuntime.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAuBD,eAAO,MAAM,mBAAmB,QAAO,MAAM,GAAG,SAI/C,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,MAAM,MAAM,EAAE,EACd,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KACtD,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAU5C,CAAC;AAUF,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,KAAG,iBAiCvD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KAAG,OAAO,CAAC,iBAAiB,CAexH,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,OAAO,iBAAiB,KAAG,mBAsB/D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAsB9H,CAAC;AA0BF,eAAO,MAAM,uBAAuB,GAAI,OAAO,iBAAiB,KAAG,iBAoClE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,KACtD,OAAO,CAAC,iBAAiB,CAW3B,CAAC"}
@@ -29,25 +29,6 @@ export const resolveDocdexBinary = () => {
29
29
  return undefined;
30
30
  return path.join(root, "bin", "docdex.js");
31
31
  };
32
- export const resolvePlaywrightCli = () => {
33
- const require = createRequire(import.meta.url);
34
- try {
35
- return require.resolve("playwright/cli.js");
36
- }
37
- catch {
38
- // fall through to docdex-local resolution
39
- }
40
- const root = resolveDocdexPackageRoot();
41
- if (!root)
42
- return undefined;
43
- try {
44
- const requireFromDocdex = createRequire(path.join(root, "package.json"));
45
- return requireFromDocdex.resolve("playwright/cli.js");
46
- }
47
- catch {
48
- return undefined;
49
- }
50
- };
51
32
  export const runDocdex = async (args, options = {}) => {
52
33
  const binary = resolveDocdexBinary();
53
34
  if (!binary) {
@@ -59,6 +40,46 @@ export const runDocdex = async (args, options = {}) => {
59
40
  });
60
41
  return { stdout: stdout ?? "", stderr: stderr ?? "" };
61
42
  };
43
+ const MAX_DOCDEX_SNIPPET = 240;
44
+ const formatDocdexSnippet = (value) => {
45
+ const trimmed = value.trim().replace(/\s+/g, " ");
46
+ if (trimmed.length <= MAX_DOCDEX_SNIPPET)
47
+ return trimmed;
48
+ return `${trimmed.slice(0, MAX_DOCDEX_SNIPPET)}...`;
49
+ };
50
+ export const parseDocdexCheckOutput = (output) => {
51
+ const trimmed = output.trim();
52
+ if (!trimmed) {
53
+ throw new Error("Docdex check returned empty output");
54
+ }
55
+ const attempts = [{ label: "full", candidate: trimmed }];
56
+ const braceStart = trimmed.indexOf("{");
57
+ const braceEnd = trimmed.lastIndexOf("}");
58
+ if (braceStart !== -1 && braceEnd > braceStart) {
59
+ attempts.push({ label: "brace-slice", candidate: trimmed.slice(braceStart, braceEnd + 1) });
60
+ }
61
+ const lines = trimmed.split(/\r?\n/);
62
+ for (let i = 0; i < lines.length; i += 1) {
63
+ const line = lines[i].trim();
64
+ if (!line.startsWith("{"))
65
+ continue;
66
+ const joined = lines.slice(i).join("\n").trim();
67
+ attempts.push({ label: "line-join", candidate: joined });
68
+ break;
69
+ }
70
+ let lastError;
71
+ for (const attempt of attempts) {
72
+ try {
73
+ return JSON.parse(attempt.candidate);
74
+ }
75
+ catch (error) {
76
+ lastError = error;
77
+ }
78
+ }
79
+ const snippet = formatDocdexSnippet(trimmed);
80
+ const message = lastError?.message ? `${lastError.message}. ` : "";
81
+ throw new Error(`Docdex check returned invalid JSON: ${message}Output: "${snippet}"`);
82
+ };
62
83
  export const readDocdexCheck = async (options = {}) => {
63
84
  let stdout = "";
64
85
  let stderr = "";
@@ -74,15 +95,29 @@ export const readDocdexCheck = async (options = {}) => {
74
95
  }
75
96
  }
76
97
  const trimmed = stdout.trim() || stderr.trim();
77
- if (!trimmed) {
78
- throw new Error("Docdex check returned empty output");
79
- }
80
- try {
81
- return JSON.parse(trimmed);
82
- }
83
- catch (error) {
84
- throw new Error(`Docdex check returned invalid JSON: ${error.message}`);
98
+ return parseDocdexCheckOutput(trimmed);
99
+ };
100
+ export const summarizeDocdexCheck = (check) => {
101
+ const failures = check.checks?.filter((item) => item?.status && item.status !== "ok")?.map((item) => ({
102
+ name: item.name,
103
+ status: item.status,
104
+ message: item.message,
105
+ })) ?? [];
106
+ if (check.success === false || failures.length > 0) {
107
+ const details = failures
108
+ .map((item) => {
109
+ const head = item.name ? `${item.name}=${item.status ?? "error"}` : item.status ?? "error";
110
+ const tail = item.message ? ` (${item.message})` : "";
111
+ return `${head}${tail}`;
112
+ })
113
+ .join("; ");
114
+ return {
115
+ ok: false,
116
+ message: details || "Docdex check failed.",
117
+ failedChecks: failures,
118
+ };
85
119
  }
120
+ return { ok: true };
86
121
  };
87
122
  export const resolveDocdexBaseUrl = async (options = {}) => {
88
123
  for (const key of DOCDEX_ENV_URLS) {
@@ -109,34 +144,73 @@ export const resolveDocdexBaseUrl = async (options = {}) => {
109
144
  return undefined;
110
145
  }
111
146
  };
147
+ const coerceString = (value) => {
148
+ if (typeof value !== "string")
149
+ return undefined;
150
+ const trimmed = value.trim();
151
+ return trimmed ? trimmed : undefined;
152
+ };
153
+ const coerceChromiumDetails = (value) => {
154
+ if (!value || typeof value !== "object")
155
+ return undefined;
156
+ const details = value;
157
+ return {
158
+ path: coerceString(details.path),
159
+ manifestPath: coerceString(details.manifest_path ?? details.manifestPath),
160
+ installedAt: coerceString(details.installed_at ?? details.installedAt),
161
+ version: coerceString(details.version),
162
+ platform: coerceString(details.platform),
163
+ downloadUrl: coerceString(details.download_url ?? details.downloadUrl),
164
+ };
165
+ };
166
+ const buildBrowserSetupHint = (installHint) => {
167
+ const hint = installHint ?? "docdexd browser install";
168
+ return `Run \`${hint}\` to install the headless Chromium browser.`;
169
+ };
170
+ export const parseDocdexBrowserCheck = (check) => {
171
+ const browserCheck = check.checks?.find((c) => c.name === "browser");
172
+ const details = browserCheck?.details;
173
+ const chromium = coerceChromiumDetails(details?.chromium);
174
+ const installHint = coerceString(details?.install_hint);
175
+ const autoInstallEnabled = typeof details?.auto_install_enabled === "boolean" ? details.auto_install_enabled : undefined;
176
+ const configuredKind = coerceString(details?.configured_kind);
177
+ if (!browserCheck) {
178
+ const setupHint = buildBrowserSetupHint(installHint);
179
+ return {
180
+ ok: false,
181
+ message: `Docdex browser check unavailable. ${setupHint}`,
182
+ chromium,
183
+ installHint,
184
+ autoInstallEnabled,
185
+ configuredKind,
186
+ };
187
+ }
188
+ if (browserCheck.status !== "ok") {
189
+ const setupHint = buildBrowserSetupHint(installHint);
190
+ return {
191
+ ok: false,
192
+ message: `${browserCheck.message ?? "Docdex browser check failed."} ${setupHint}`,
193
+ chromium,
194
+ installHint,
195
+ autoInstallEnabled,
196
+ configuredKind,
197
+ };
198
+ }
199
+ return {
200
+ ok: true,
201
+ chromium,
202
+ installHint,
203
+ autoInstallEnabled,
204
+ configuredKind,
205
+ };
206
+ };
112
207
  export const resolveDocdexBrowserInfo = async (options = {}) => {
113
- const setupHint = "Run `docdex setup` to install Playwright and at least one browser.";
114
208
  try {
115
209
  const check = await readDocdexCheck(options);
116
- const browserCheck = check.checks?.find((c) => c.name === "browser");
117
- if (!browserCheck || browserCheck.status !== "ok") {
118
- return {
119
- ok: false,
120
- message: `${browserCheck?.message ?? "Docdex browser check failed."} ${setupHint}`,
121
- };
122
- }
123
- const details = browserCheck.details ?? {};
124
- const playwright = details.playwright ?? {};
125
- const browsers = Array.isArray(playwright.browsers) ? playwright.browsers : [];
126
- if (!browsers.length) {
127
- return {
128
- ok: false,
129
- message: `Docdex has no Playwright browsers configured. ${setupHint}`,
130
- };
131
- }
132
- const browsersPath = typeof playwright.browsers_path === "string" ? playwright.browsers_path : undefined;
133
- return {
134
- ok: true,
135
- browsersPath,
136
- browsers,
137
- };
210
+ return parseDocdexBrowserCheck(check);
138
211
  }
139
212
  catch (error) {
213
+ const setupHint = buildBrowserSetupHint();
140
214
  return {
141
215
  ok: false,
142
216
  message: `Docdex check failed: ${error.message}. ${setupHint}`,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./docdex/DocdexClient.js";
2
+ export * from "./docdex/DocdexRuntime.js";
2
3
  export * from "./telemetry/TelemetryClient.js";
3
4
  export * from "./vcs/VcsClient.js";
4
5
  export * from "./qa/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./docdex/DocdexClient.js";
2
+ export * from "./docdex/DocdexRuntime.js";
2
3
  export * from "./telemetry/TelemetryClient.js";
3
4
  export * from "./vcs/VcsClient.js";
4
5
  export * from "./qa/index.js";
@@ -1,10 +1,68 @@
1
1
  import { QaProfile } from '@mcoda/shared/qa/QaProfile.js';
2
+ import type { QaBrowserAction } from '@mcoda/shared/qa/QaPlan.js';
2
3
  import { QaAdapter } from './QaAdapter.js';
3
4
  import { QaContext, QaEnsureResult, QaRunResult } from './QaTypes.js';
5
+ type BrowserFetchResult = {
6
+ html: string;
7
+ innerText?: string;
8
+ textContent?: string;
9
+ status?: number;
10
+ finalUrl?: string;
11
+ };
12
+ type BrowserActionResult = {
13
+ index: number;
14
+ type: QaBrowserAction['type'];
15
+ ok: boolean;
16
+ message?: string;
17
+ url?: string;
18
+ durationMs?: number;
19
+ };
20
+ type BrowserActionSnapshot = {
21
+ index: number;
22
+ name: string;
23
+ html: string;
24
+ innerText?: string;
25
+ textContent?: string;
26
+ url?: string;
27
+ };
28
+ export declare const resolveChromiumBinary: () => Promise<string | undefined>;
29
+ declare class NetworkIdleTracker {
30
+ inflight: number;
31
+ lastActivity: number;
32
+ sawLoad: boolean;
33
+ documentStatus?: number;
34
+ documentUrl?: string;
35
+ handle(method: string, params?: any): void;
36
+ }
37
+ declare class CdpClient {
38
+ private ws;
39
+ private queue;
40
+ private nextId;
41
+ private closed;
42
+ static connect(wsUrl: string): Promise<CdpClient>;
43
+ private constructor();
44
+ call(method: string, params: Record<string, unknown>, tracker?: NetworkIdleTracker, timeoutMs?: number): Promise<any>;
45
+ waitForNetworkIdle(tracker: NetworkIdleTracker, timeoutMs: number): Promise<boolean>;
46
+ close(): void;
47
+ }
4
48
  export declare class ChromiumQaAdapter implements QaAdapter {
5
- private resolveCwd;
6
49
  ensureInstalled(profile: QaProfile, ctx: QaContext): Promise<QaEnsureResult>;
7
50
  private persistLogs;
51
+ private persistBrowserArtifacts;
8
52
  invoke(profile: QaProfile, ctx: QaContext): Promise<QaRunResult>;
53
+ private runBrowserActions;
54
+ private runBrowser;
9
55
  }
56
+ export declare const __testing: {
57
+ resolveActionUrl: (actionUrl: string | undefined, baseUrl: string | undefined) => string | undefined;
58
+ resolveActionTimeoutMs: (action: QaBrowserAction, fallbackMs: number) => number;
59
+ runBrowserActionsWithClient: (client: CdpClient, actions: QaBrowserAction[], baseUrl: string | undefined, timeoutMs: number) => Promise<{
60
+ outcome: "pass" | "fail";
61
+ errorMessage?: string;
62
+ results: BrowserActionResult[];
63
+ snapshots: BrowserActionSnapshot[];
64
+ finalDom?: BrowserFetchResult;
65
+ }>;
66
+ };
67
+ export {};
10
68
  //# sourceMappingURL=ChromiumQaAdapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChromiumQaAdapter.d.ts","sourceRoot":"","sources":["../../src/qa/ChromiumQaAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAQtE,qBAAa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,UAAU;IASZ,eAAe,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC;YAqBpE,WAAW;IAYnB,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;CA8CvE"}
1
+ {"version":3,"file":"ChromiumQaAdapter.d.ts","sourceRoot":"","sources":["../../src/qa/ChromiumQaAdapter.ts"],"names":[],"mappings":"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"}