doc-detective 4.0.2-dev.1 → 4.0.2-dev.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/dist/agents/adapters/claude-code.d.ts +77 -0
- package/dist/agents/adapters/claude-code.d.ts.map +1 -0
- package/dist/agents/adapters/claude-code.js +461 -0
- package/dist/agents/adapters/claude-code.js.map +1 -0
- package/dist/agents/adapters/codex.d.ts +64 -0
- package/dist/agents/adapters/codex.d.ts.map +1 -0
- package/dist/agents/adapters/codex.js +299 -0
- package/dist/agents/adapters/codex.js.map +1 -0
- package/dist/agents/adapters/copilot-cli.d.ts +29 -0
- package/dist/agents/adapters/copilot-cli.d.ts.map +1 -0
- package/dist/agents/adapters/copilot-cli.js +195 -0
- package/dist/agents/adapters/copilot-cli.js.map +1 -0
- package/dist/agents/adapters/gemini-cli.d.ts +29 -0
- package/dist/agents/adapters/gemini-cli.d.ts.map +1 -0
- package/dist/agents/adapters/gemini-cli.js +207 -0
- package/dist/agents/adapters/gemini-cli.js.map +1 -0
- package/dist/agents/adapters/opencode.d.ts +67 -0
- package/dist/agents/adapters/opencode.d.ts.map +1 -0
- package/dist/agents/adapters/opencode.js +341 -0
- package/dist/agents/adapters/opencode.js.map +1 -0
- package/dist/agents/adapters/qwen-code.d.ts +30 -0
- package/dist/agents/adapters/qwen-code.d.ts.map +1 -0
- package/dist/agents/adapters/qwen-code.js +212 -0
- package/dist/agents/adapters/qwen-code.js.map +1 -0
- package/dist/agents/command.d.ts +11 -0
- package/dist/agents/command.d.ts.map +1 -0
- package/dist/agents/command.js +41 -0
- package/dist/agents/command.js.map +1 -0
- package/dist/agents/fetcher.d.ts +30 -0
- package/dist/agents/fetcher.d.ts.map +1 -0
- package/dist/agents/fetcher.js +112 -0
- package/dist/agents/fetcher.js.map +1 -0
- package/dist/agents/prompts.d.ts +24 -0
- package/dist/agents/prompts.d.ts.map +1 -0
- package/dist/agents/prompts.js +74 -0
- package/dist/agents/prompts.js.map +1 -0
- package/dist/agents/registry.d.ts +4 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +25 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/runner.d.ts +13 -0
- package/dist/agents/runner.d.ts.map +1 -0
- package/dist/agents/runner.js +155 -0
- package/dist/agents/runner.js.map +1 -0
- package/dist/agents/spawn-helper.d.ts +33 -0
- package/dist/agents/spawn-helper.d.ts.map +1 -0
- package/dist/agents/spawn-helper.js +98 -0
- package/dist/agents/spawn-helper.js.map +1 -0
- package/dist/agents/types.d.ts +41 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/cli.js +42 -10
- package/dist/cli.js.map +1 -1
- package/dist/common/src/detectTests.d.ts.map +1 -1
- package/dist/common/src/detectTests.js +43 -12
- package/dist/common/src/detectTests.js.map +1 -1
- package/dist/common/src/fileTypes.d.ts.map +1 -1
- package/dist/common/src/fileTypes.js +10 -0
- package/dist/common/src/fileTypes.js.map +1 -1
- package/dist/common/src/schemas/schemas.json +594 -0
- package/dist/common/src/types/generated/checkLink_v3.d.ts +15 -0
- package/dist/common/src/types/generated/checkLink_v3.d.ts.map +1 -1
- package/dist/common/src/types/generated/config_v3.d.ts +4 -0
- package/dist/common/src/types/generated/config_v3.d.ts.map +1 -1
- package/dist/common/src/types/generated/resolvedTests_v3.d.ts +4 -0
- package/dist/common/src/types/generated/resolvedTests_v3.d.ts.map +1 -1
- package/dist/common/src/types/generated/step_v3.d.ts +15 -0
- package/dist/common/src/types/generated/step_v3.d.ts.map +1 -1
- package/dist/common/src/types/generated/test_v3.d.ts +30 -0
- package/dist/common/src/types/generated/test_v3.d.ts.map +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +10 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/integrations/heretto.d.ts.map +1 -1
- package/dist/core/integrations/heretto.js +11 -3
- package/dist/core/integrations/heretto.js.map +1 -1
- package/dist/core/tests/checkLink.d.ts.map +1 -1
- package/dist/core/tests/checkLink.js +136 -29
- package/dist/core/tests/checkLink.js.map +1 -1
- package/dist/core/tests/loadCookie.d.ts.map +1 -1
- package/dist/core/tests/loadCookie.js +12 -2
- package/dist/core/tests/loadCookie.js.map +1 -1
- package/dist/core/tests/saveScreenshot.d.ts +15 -1
- package/dist/core/tests/saveScreenshot.d.ts.map +1 -1
- package/dist/core/tests/saveScreenshot.js +41 -17
- package/dist/core/tests/saveScreenshot.js.map +1 -1
- package/dist/index.cjs +816 -59
- package/dist/reporters/htmlReporter.d.ts +2 -0
- package/dist/reporters/htmlReporter.d.ts.map +1 -0
- package/dist/reporters/htmlReporter.js +1589 -0
- package/dist/reporters/htmlReporter.js.map +1 -0
- package/dist/utils.d.ts +2 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +43 -10
- package/dist/utils.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agents/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE;QACR,UAAU,EAAE,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,SAAS,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;KACnD,CAAC;IACF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrD,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC;CACvB;AAOD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,iBAAiB,EACvB,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CAmE1B"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { listAdapters } from "./registry.js";
|
|
2
|
+
const defaultLogger = (msg, level = "info") => {
|
|
3
|
+
if (level === "error")
|
|
4
|
+
console.error(msg);
|
|
5
|
+
else
|
|
6
|
+
console.log(msg);
|
|
7
|
+
};
|
|
8
|
+
export async function runInstallAgents(argv, deps = {}) {
|
|
9
|
+
const adapters = deps.adapters ?? listAdapters();
|
|
10
|
+
const logger = deps.logger ?? defaultLogger;
|
|
11
|
+
const isTTY = deps.isTTY ?? (() => Boolean(process.stdin.isTTY));
|
|
12
|
+
const dryRun = argv["dry-run"] === true;
|
|
13
|
+
// --yes requires explicit --agent and --scope; no prompts.
|
|
14
|
+
if (argv.yes) {
|
|
15
|
+
if (!argv.agent || argv.agent.length === 0) {
|
|
16
|
+
throw new Error("--yes requires at least one --agent (for example, --agent claude).");
|
|
17
|
+
}
|
|
18
|
+
if (!argv.scope) {
|
|
19
|
+
throw new Error("--yes requires --scope project|global.");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Resolve which agents to target.
|
|
23
|
+
const targeted = await resolveTargetAgents(argv, adapters, {
|
|
24
|
+
isTTY: isTTY(),
|
|
25
|
+
prompts: deps.prompts,
|
|
26
|
+
logger,
|
|
27
|
+
});
|
|
28
|
+
if (targeted.length === 0) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
// Resolve scope.
|
|
32
|
+
const scope = await resolveScope(argv, targeted, {
|
|
33
|
+
isTTY: isTTY(),
|
|
34
|
+
prompts: deps.prompts,
|
|
35
|
+
});
|
|
36
|
+
// Install each in order; collect reports. When an adapter doesn't support
|
|
37
|
+
// the requested scope, degrade to its nearest supported scope and attach a
|
|
38
|
+
// note to the report so callers see the divergence.
|
|
39
|
+
const reports = [];
|
|
40
|
+
for (const adapter of targeted) {
|
|
41
|
+
const effective = effectiveScopeFor(adapter, scope);
|
|
42
|
+
if (effective.degraded) {
|
|
43
|
+
logger(`⚠ ${adapter.displayName} does not support ${scope} scope — installing as ${effective.scope}.`, "warn");
|
|
44
|
+
}
|
|
45
|
+
logger(`\n→ ${adapter.displayName} (${adapter.id}) — scope: ${effective.scope}`, "info");
|
|
46
|
+
const report = await adapter.install({
|
|
47
|
+
scope: effective.scope,
|
|
48
|
+
force: Boolean(argv.force),
|
|
49
|
+
dryRun,
|
|
50
|
+
logger,
|
|
51
|
+
});
|
|
52
|
+
const finalReport = effective.degraded
|
|
53
|
+
? {
|
|
54
|
+
...report,
|
|
55
|
+
notes: [
|
|
56
|
+
...(report.notes ?? []),
|
|
57
|
+
`Requested scope '${scope}' is not supported by ${adapter.displayName}; installed as '${effective.scope}' instead.`,
|
|
58
|
+
],
|
|
59
|
+
}
|
|
60
|
+
: report;
|
|
61
|
+
reports.push(finalReport);
|
|
62
|
+
logger(summarizeReport(finalReport), "info");
|
|
63
|
+
}
|
|
64
|
+
return reports;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the effective scope an adapter will actually receive. If the desired
|
|
68
|
+
* scope is supported, pass it through. Otherwise, degrade to the adapter's
|
|
69
|
+
* first supported scope and flag that we did.
|
|
70
|
+
*/
|
|
71
|
+
function effectiveScopeFor(adapter, desired) {
|
|
72
|
+
const supported = adapter.supportsScopes();
|
|
73
|
+
if (supported.includes(desired))
|
|
74
|
+
return { scope: desired, degraded: false };
|
|
75
|
+
return { scope: supported[0], degraded: true };
|
|
76
|
+
}
|
|
77
|
+
async function resolveTargetAgents(argv, adapters, ctx) {
|
|
78
|
+
if (argv.agent && argv.agent.length > 0) {
|
|
79
|
+
const chosen = [];
|
|
80
|
+
const seen = new Set();
|
|
81
|
+
for (const id of argv.agent) {
|
|
82
|
+
// Preserve first-seen order but drop duplicates — `--agent codex --agent codex`
|
|
83
|
+
// should run one install, not two.
|
|
84
|
+
if (seen.has(id))
|
|
85
|
+
continue;
|
|
86
|
+
seen.add(id);
|
|
87
|
+
const match = adapters.find((a) => a.id === id);
|
|
88
|
+
if (!match) {
|
|
89
|
+
const known = adapters.map((a) => a.id).join(", ");
|
|
90
|
+
throw new Error(`Unknown agent '${id}'. Known agents: ${known}`);
|
|
91
|
+
}
|
|
92
|
+
chosen.push(match);
|
|
93
|
+
}
|
|
94
|
+
return chosen;
|
|
95
|
+
}
|
|
96
|
+
// No --agent: run detection across all adapters and prompt the user with the
|
|
97
|
+
// ones that reported present.
|
|
98
|
+
const detections = await Promise.all(adapters.map(async (a) => ({ adapter: a, result: await a.detect() })));
|
|
99
|
+
const detected = detections.filter((d) => d.result.present).map((d) => d.adapter);
|
|
100
|
+
if (detected.length === 0) {
|
|
101
|
+
ctx.logger("No supported coding agents detected on this machine. Install one (e.g., Claude Code) and re-run.", "info");
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
if (!ctx.isTTY) {
|
|
105
|
+
throw new Error("Cannot prompt for agents in a non-TTY environment. Pass --agent explicitly (repeatable).");
|
|
106
|
+
}
|
|
107
|
+
if (!ctx.prompts) {
|
|
108
|
+
throw new Error("No prompts implementation available; pass --agent explicitly.");
|
|
109
|
+
}
|
|
110
|
+
const selectedIds = await ctx.prompts.pickAgents(detected);
|
|
111
|
+
return detected.filter((a) => selectedIds.includes(a.id));
|
|
112
|
+
}
|
|
113
|
+
async function resolveScope(argv, targeted, ctx) {
|
|
114
|
+
if (argv.scope === "project" || argv.scope === "global") {
|
|
115
|
+
return argv.scope;
|
|
116
|
+
}
|
|
117
|
+
// Intersect the supported-scope sets across all chosen adapters. Seed with
|
|
118
|
+
// the first adapter's supported scopes (not `[]`) so that an empty running
|
|
119
|
+
// intersection stays empty — otherwise the next adapter would re-seed it.
|
|
120
|
+
const [first, ...rest] = targeted;
|
|
121
|
+
const intersection = rest.reduce((acc, a) => acc.filter((s) => a.supportsScopes().includes(s)), first.supportsScopes());
|
|
122
|
+
// If no scope is common to every chosen adapter, pick "global" as a
|
|
123
|
+
// sensible default and let each adapter degrade via effectiveScopeFor().
|
|
124
|
+
if (intersection.length === 0)
|
|
125
|
+
return "global";
|
|
126
|
+
if (intersection.length === 1)
|
|
127
|
+
return intersection[0];
|
|
128
|
+
if (!ctx.isTTY) {
|
|
129
|
+
throw new Error("Cannot prompt for scope in a non-TTY environment. Pass --scope project|global.");
|
|
130
|
+
}
|
|
131
|
+
if (!ctx.prompts) {
|
|
132
|
+
throw new Error("No prompts implementation available; pass --scope project|global.");
|
|
133
|
+
}
|
|
134
|
+
return ctx.prompts.pickScope(intersection);
|
|
135
|
+
}
|
|
136
|
+
function summarizeReport(r) {
|
|
137
|
+
const ver = r.installedVersion ? ` @ ${r.installedVersion}` : "";
|
|
138
|
+
switch (r.action) {
|
|
139
|
+
case "installed":
|
|
140
|
+
return ` installed${ver}`;
|
|
141
|
+
case "updated":
|
|
142
|
+
return ` updated${ver}`;
|
|
143
|
+
case "already-up-to-date":
|
|
144
|
+
return ` already up to date${ver}`;
|
|
145
|
+
case "forced":
|
|
146
|
+
return ` forced reinstall${ver}`;
|
|
147
|
+
case "dry-run":
|
|
148
|
+
return ` dry-run (no changes)`;
|
|
149
|
+
case "fallback":
|
|
150
|
+
return ` wrote settings.json fallback${ver}`;
|
|
151
|
+
default:
|
|
152
|
+
return ` ${r.action}${ver}`;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/agents/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface SpawnResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
exitCode: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Build a single cmd.exe-safe command line from (cmd, args). Follows the
|
|
8
|
+
* canonical `CommandLineToArgvW` escaping rules so the child process sees
|
|
9
|
+
* each arg verbatim:
|
|
10
|
+
* 1. Double any run of backslashes that directly precedes a `"` or the
|
|
11
|
+
* end of the string (so the closing `"` we add below isn't escaped).
|
|
12
|
+
* 2. Escape each embedded `"` as `\"`.
|
|
13
|
+
* 3. Wrap the whole arg in `"..."`.
|
|
14
|
+
* Naive `s.replace(/"/g, '\\"')` is wrong for args like `a\"b` or `a\\`
|
|
15
|
+
* because the preceding backslashes turn the intended escape into a real
|
|
16
|
+
* backslash + unescaped quote, breaking out of the quoted context.
|
|
17
|
+
*
|
|
18
|
+
* Chose this shape because Node 22+'s DEP0190 deprecates
|
|
19
|
+
* `spawn(cmd, args[], {shell:true})` (joining args without escaping), but
|
|
20
|
+
* `spawn(<single string>, [], {shell:true})` stays supported. Inside
|
|
21
|
+
* double quotes cmd.exe treats `&|<>^` literally, so no caret escaping is
|
|
22
|
+
* needed for our hardcoded args.
|
|
23
|
+
*/
|
|
24
|
+
export declare function winCommandLine(cmd: string, args: string[]): string;
|
|
25
|
+
/**
|
|
26
|
+
* Spawn a command and resolve with its stdout/stderr/exit code. Unlike the
|
|
27
|
+
* shared `spawnCommand` in src/utils.ts, this helper attaches an `error`
|
|
28
|
+
* listener so that ENOENT (binary not on PATH) rejects the promise cleanly
|
|
29
|
+
* instead of crashing the process. That matters for adapters that probe for
|
|
30
|
+
* optional binaries (`copilot`, `gemini`, `codex`).
|
|
31
|
+
*/
|
|
32
|
+
export declare function safeSpawn(cmd: string, args?: string[]): Promise<SpawnResult>;
|
|
33
|
+
//# sourceMappingURL=spawn-helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-helper.d.ts","sourceRoot":"","sources":["../../src/agents/spawn-helper.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAQlE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CA6DhF"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Build a single cmd.exe-safe command line from (cmd, args). Follows the
|
|
4
|
+
* canonical `CommandLineToArgvW` escaping rules so the child process sees
|
|
5
|
+
* each arg verbatim:
|
|
6
|
+
* 1. Double any run of backslashes that directly precedes a `"` or the
|
|
7
|
+
* end of the string (so the closing `"` we add below isn't escaped).
|
|
8
|
+
* 2. Escape each embedded `"` as `\"`.
|
|
9
|
+
* 3. Wrap the whole arg in `"..."`.
|
|
10
|
+
* Naive `s.replace(/"/g, '\\"')` is wrong for args like `a\"b` or `a\\`
|
|
11
|
+
* because the preceding backslashes turn the intended escape into a real
|
|
12
|
+
* backslash + unescaped quote, breaking out of the quoted context.
|
|
13
|
+
*
|
|
14
|
+
* Chose this shape because Node 22+'s DEP0190 deprecates
|
|
15
|
+
* `spawn(cmd, args[], {shell:true})` (joining args without escaping), but
|
|
16
|
+
* `spawn(<single string>, [], {shell:true})` stays supported. Inside
|
|
17
|
+
* double quotes cmd.exe treats `&|<>^` literally, so no caret escaping is
|
|
18
|
+
* needed for our hardcoded args.
|
|
19
|
+
*/
|
|
20
|
+
export function winCommandLine(cmd, args) {
|
|
21
|
+
const quote = (s) => {
|
|
22
|
+
const escaped = s.replace(/(\\*)("|$)/g, (_, slashes, end) => slashes + slashes + (end === '"' ? '\\"' : ""));
|
|
23
|
+
return `"${escaped}"`;
|
|
24
|
+
};
|
|
25
|
+
return [cmd, ...args].map(quote).join(" ");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Spawn a command and resolve with its stdout/stderr/exit code. Unlike the
|
|
29
|
+
* shared `spawnCommand` in src/utils.ts, this helper attaches an `error`
|
|
30
|
+
* listener so that ENOENT (binary not on PATH) rejects the promise cleanly
|
|
31
|
+
* instead of crashing the process. That matters for adapters that probe for
|
|
32
|
+
* optional binaries (`copilot`, `gemini`, `codex`).
|
|
33
|
+
*/
|
|
34
|
+
export function safeSpawn(cmd, args = []) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
let stdout = "";
|
|
37
|
+
let stderr = "";
|
|
38
|
+
let settled = false;
|
|
39
|
+
const finish = (err, result) => {
|
|
40
|
+
if (settled)
|
|
41
|
+
return;
|
|
42
|
+
settled = true;
|
|
43
|
+
if (err)
|
|
44
|
+
reject(err);
|
|
45
|
+
else
|
|
46
|
+
resolve(result);
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
// Close the child's stdin with `ignore` so any interactive prompt in
|
|
50
|
+
// the target tool (for example, `qwen extensions install` asking for
|
|
51
|
+
// consent despite `--consent`) fails fast with EOF instead of hanging
|
|
52
|
+
// indefinitely in CI / non-TTY contexts. We capture stdout/stderr via
|
|
53
|
+
// pipes so the caller can still surface output/errors.
|
|
54
|
+
//
|
|
55
|
+
// On Windows, npm installs globally-linked binaries as `.cmd` / `.ps1`
|
|
56
|
+
// shims (so `qwen` on disk is actually `qwen.cmd`). Without
|
|
57
|
+
// `shell: true`, Node's spawn resolves only exact filenames — it can't
|
|
58
|
+
// see `.cmd` extensions and ENOENTs even when the binary works fine
|
|
59
|
+
// from PowerShell / cmd. We therefore enable the shell on win32 so
|
|
60
|
+
// cmd.exe resolves PATHEXT extensions the same way the user's
|
|
61
|
+
// terminal does. Node 22+ deprecates `spawn(cmd, args, {shell: true})`
|
|
62
|
+
// (DEP0190) because args are joined without escaping, so on win32 we
|
|
63
|
+
// instead build a single pre-quoted command line and pass it as the
|
|
64
|
+
// `cmd` argument with `shell: true`. All callers pass hardcoded
|
|
65
|
+
// strings, so shell-injection isn't a risk.
|
|
66
|
+
const onWindows = process.platform === "win32";
|
|
67
|
+
const spawnCmd = onWindows ? winCommandLine(cmd, args) : cmd;
|
|
68
|
+
const spawnArgs = onWindows ? [] : args;
|
|
69
|
+
const child = spawn(spawnCmd, spawnArgs, {
|
|
70
|
+
env: process.env,
|
|
71
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
72
|
+
shell: onWindows,
|
|
73
|
+
});
|
|
74
|
+
child.on("error", (err) => finish(err));
|
|
75
|
+
child.stdout?.on("data", (chunk) => { stdout += chunk.toString(); });
|
|
76
|
+
child.stderr?.on("data", (chunk) => { stderr += chunk.toString(); });
|
|
77
|
+
child.on("close", (code, signal) => {
|
|
78
|
+
// `code === null` means the child was killed by a signal. Surface that
|
|
79
|
+
// as a non-zero exit code (and annotate stderr) so callers that only
|
|
80
|
+
// inspect exitCode still detect failure.
|
|
81
|
+
const exitCode = code !== null ? code : 1;
|
|
82
|
+
const signalNote = signal ? `\n[terminated by signal ${signal}]` : "";
|
|
83
|
+
finish(null, {
|
|
84
|
+
// Strip `\r?\n` so Windows CLIs that emit CRLF don't leave a
|
|
85
|
+
// stray `\r` in captured output (breaks log comparisons and
|
|
86
|
+
// produces mystery `^M` glyphs in terminal output).
|
|
87
|
+
stdout: stdout.replace(/\r?\n$/, ""),
|
|
88
|
+
stderr: (stderr + signalNote).replace(/\r?\n$/, ""),
|
|
89
|
+
exitCode,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
finish(err instanceof Error ? err : new Error(String(err)));
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=spawn-helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-helper.js","sourceRoot":"","sources":["../../src/agents/spawn-helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type Scope = "global" | "project";
|
|
2
|
+
export interface DetectionResult {
|
|
3
|
+
present: boolean;
|
|
4
|
+
onPath: boolean;
|
|
5
|
+
version?: string;
|
|
6
|
+
configPaths: {
|
|
7
|
+
global?: string;
|
|
8
|
+
project?: string;
|
|
9
|
+
};
|
|
10
|
+
notes?: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface InstallState {
|
|
13
|
+
installed: boolean;
|
|
14
|
+
installedVersion?: string;
|
|
15
|
+
latestVersion?: string;
|
|
16
|
+
upToDate?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export type LogLevel = "info" | "warn" | "error" | "debug";
|
|
19
|
+
export interface InstallOptions {
|
|
20
|
+
scope: Scope;
|
|
21
|
+
force: boolean;
|
|
22
|
+
dryRun: boolean;
|
|
23
|
+
logger: (message: string, level?: LogLevel) => void;
|
|
24
|
+
}
|
|
25
|
+
export type InstallAction = "installed" | "updated" | "already-up-to-date" | "forced" | "dry-run" | "fallback";
|
|
26
|
+
export interface InstallReport {
|
|
27
|
+
adapterId: string;
|
|
28
|
+
scope: Scope;
|
|
29
|
+
action: InstallAction;
|
|
30
|
+
installedVersion?: string;
|
|
31
|
+
notes?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface AgentAdapter {
|
|
34
|
+
id: string;
|
|
35
|
+
displayName: string;
|
|
36
|
+
detect(): Promise<DetectionResult>;
|
|
37
|
+
supportsScopes(): Scope[];
|
|
38
|
+
getInstallState(scope: Scope): Promise<InstallState>;
|
|
39
|
+
install(opts: InstallOptions): Promise<InstallReport>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,MAAM,aAAa,GACrB,WAAW,GACX,SAAS,GACT,oBAAoB,GACpB,QAAQ,GACR,SAAS,GACT,UAAU,CAAC;AAEf,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IACnC,cAAc,IAAI,KAAK,EAAE,CAAC;IAC1B,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
CHANGED
|
@@ -1,22 +1,53 @@
|
|
|
1
1
|
import { runTests } from "./core/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { buildYargs, setConfig, outputResults, setMeta, getVersionData, log, getResolvedTestsFromEnv, reportResults, } from "./utils.js";
|
|
3
|
+
import { installAgentsCommand } from "./agents/command.js";
|
|
4
|
+
import { argv as processArgv } from "node:process";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import fs from "node:fs";
|
|
6
7
|
// Run
|
|
7
8
|
setMeta();
|
|
8
|
-
main(
|
|
9
|
-
//
|
|
9
|
+
main(processArgv).catch((err) => {
|
|
10
|
+
// yargs' .fail handler prints usage + message; this catches anything that
|
|
11
|
+
// escapes (including our rethrown errors) so the process exits non-zero.
|
|
12
|
+
console.error(err?.message || err);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
});
|
|
10
15
|
async function main(argv) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
await buildYargs(argv)
|
|
17
|
+
.command({
|
|
18
|
+
command: "$0",
|
|
19
|
+
describe: "Run Doc Detective tests (default).",
|
|
20
|
+
handler: runTestsHandler,
|
|
21
|
+
})
|
|
22
|
+
.command({
|
|
23
|
+
// Preserved for back-compat with the `runTests` npm script and any
|
|
24
|
+
// existing CI invocations. Runs the same handler as the default.
|
|
25
|
+
command: "runTests",
|
|
26
|
+
describe: false,
|
|
27
|
+
handler: runTestsHandler,
|
|
28
|
+
})
|
|
29
|
+
.command(installAgentsCommand)
|
|
30
|
+
.strict()
|
|
31
|
+
.demandCommand(0)
|
|
32
|
+
// Suppress yargs' default help-dump on failure; surface the concrete error
|
|
33
|
+
// message instead. The top-level .catch() prints it and sets exit code.
|
|
34
|
+
.fail((msg, err) => {
|
|
35
|
+
if (err)
|
|
36
|
+
throw err;
|
|
37
|
+
throw new Error(msg);
|
|
38
|
+
})
|
|
39
|
+
.parseAsync();
|
|
40
|
+
}
|
|
41
|
+
// Legacy "run tests" flow — unchanged behavior when no subcommand is given.
|
|
42
|
+
async function runTestsHandler(args) {
|
|
15
43
|
// Get .doc-detective JSON or YAML config, if it exists, preferring a config arg if provided
|
|
16
44
|
const configPathJSON = path.resolve(process.cwd(), ".doc-detective.json");
|
|
17
45
|
const configPathYAML = path.resolve(process.cwd(), ".doc-detective.yaml");
|
|
18
46
|
const configPathYML = path.resolve(process.cwd(), ".doc-detective.yml");
|
|
19
|
-
|
|
47
|
+
// Guard `args.config` so the handler falls back to the defaults cleanly
|
|
48
|
+
// when --config is omitted (args.config is undefined in that case).
|
|
49
|
+
const hasExplicitConfig = typeof args.config === "string" && args.config.length > 0 && fs.existsSync(args.config);
|
|
50
|
+
const configPath = hasExplicitConfig
|
|
20
51
|
? args.config
|
|
21
52
|
: fs.existsSync(configPathJSON)
|
|
22
53
|
? configPathJSON
|
|
@@ -42,7 +73,8 @@ async function main(argv) {
|
|
|
42
73
|
await reportResults({ apiConfig, results });
|
|
43
74
|
}
|
|
44
75
|
else {
|
|
45
|
-
// Output results
|
|
76
|
+
// Output results — config.reporters (populated from args.reporters by
|
|
77
|
+
// setConfig) is the source of truth for which reporters run.
|
|
46
78
|
await outputResults(config, output, results, { command: "runTests" });
|
|
47
79
|
}
|
|
48
80
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,UAAU,EACV,SAAS,EACT,aAAa,EACb,OAAO,EACP,cAAc,EACd,GAAG,EACH,uBAAuB,EACvB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM;AACN,OAAO,EAAE,CAAC;AACV,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC9B,0EAA0E;IAC1E,yEAAyE;IACzE,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,MAAM,UAAU,CAAC,IAAI,CAAC;SACnB,OAAO,CAAC;QACP,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,oCAAoC;QAC9C,OAAO,EAAE,eAAe;KACzB,CAAC;SACD,OAAO,CAAC;QACP,mEAAmE;QACnE,iEAAiE;QACjE,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,eAAe;KACzB,CAAC;SACD,OAAO,CAAC,oBAAoB,CAAC;SAC7B,MAAM,EAAE;SACR,aAAa,CAAC,CAAC,CAAC;QACjB,2EAA2E;QAC3E,wEAAwE;SACvE,IAAI,CAAC,CAAC,GAAW,EAAE,GAAsB,EAAE,EAAE;QAC5C,IAAI,GAAG;YAAE,MAAM,GAAG,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC;SACD,UAAU,EAAE,CAAC;AAClB,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,eAAe,CAAC,IAAS;IACtC,4FAA4F;IAC5F,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,qBAAqB,CAAC,CAAC;IAC1E,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,qBAAqB,CAAC,CAAC;IAC1E,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;IACxE,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,iBAAiB,GACrB,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1F,MAAM,UAAU,GAAG,iBAAiB;QAClC,CAAC,CAAC,IAAI,CAAC,MAAM;QACb,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;YAC/B,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;gBAC/B,CAAC,CAAC,cAAc;gBAChB,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;oBAC9B,CAAC,CAAC,aAAa;oBACf,CAAC,CAAC,IAAI,CAAC;IAET,aAAa;IACb,MAAM,MAAM,GAAQ,MAAM,SAAS,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5E,GAAG,CACD,sBAAsB,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EACjE,OAAO,EACP,MAAM,CACP,CAAC;IACF,GAAG,CAAC,gBAAgB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAExE,mDAAmD;IACnD,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,GAAG,EAAE,aAAa,IAAI,IAAI,CAAC;IACjD,MAAM,SAAS,GAAG,GAAG,EAAE,SAAS,IAAI,IAAI,CAAC;IAEzC,YAAY;IACZ,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,MAAM,OAAO,GAAG,aAAa;QAC3B,CAAC,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,CAAC;QAC3C,CAAC,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE3B,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACN,sEAAsE;QACtE,6DAA6D;QAC7D,MAAM,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectTests.d.ts","sourceRoot":"","sources":["../../../src/common/src/detectTests.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAA+C,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAoCvF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAMvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAe3F;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAOlF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAoEnH;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,iBAAiB,EAAE,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"detectTests.d.ts","sourceRoot":"","sources":["../../../src/common/src/detectTests.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAA+C,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAoCvF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAMvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAe3F;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAOlF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAoEnH;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,iBAAiB,EAAE,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAgE5G;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CA2DrC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,EACjC,MAAW,EACX,OAAO,EACP,QAAa,EACb,QAAQ,GACT,EAAE;IACD,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAmU1B;AAkDD;;GAEG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CAqBhF"}
|
|
@@ -183,6 +183,19 @@ export function parseXmlAttributes({ stringifiedObject }) {
|
|
|
183
183
|
*/
|
|
184
184
|
export function parseObject({ stringifiedObject }) {
|
|
185
185
|
if (typeof stringifiedObject === "string") {
|
|
186
|
+
// Decode XML/HTML entities (e.g., " → " and ' → ') that may be
|
|
187
|
+
// introduced by DITA OT or other XML processors when normalizing attribute
|
|
188
|
+
// values. & must be decoded last so author-escaped sequences like
|
|
189
|
+
// "&lt;" (meant to render as the literal text "<") aren't double-decoded
|
|
190
|
+
// into "<".
|
|
191
|
+
if (/&(?:#\d+|#x[0-9a-fA-F]+|amp|lt|gt|quot|apos);/.test(stringifiedObject)) {
|
|
192
|
+
stringifiedObject = stringifiedObject
|
|
193
|
+
.replace(/'|'/g, "'")
|
|
194
|
+
.replace(/"|"/g, '"')
|
|
195
|
+
.replace(/</g, "<")
|
|
196
|
+
.replace(/>/g, ">")
|
|
197
|
+
.replace(/&/g, "&");
|
|
198
|
+
}
|
|
186
199
|
// First, try to parse as XML attributes
|
|
187
200
|
const xmlAttrs = parseXmlAttributes({ stringifiedObject });
|
|
188
201
|
if (xmlAttrs !== null) {
|
|
@@ -488,18 +501,7 @@ export async function parseContent({ config = {}, content, filePath = "", fileTy
|
|
|
488
501
|
if (step.screenshot && config._herettoPathMapping) {
|
|
489
502
|
const herettoIntegration = findHerettoIntegration(config, filePath);
|
|
490
503
|
if (herettoIntegration) {
|
|
491
|
-
|
|
492
|
-
step.screenshot = { path: step.screenshot };
|
|
493
|
-
}
|
|
494
|
-
else if (typeof step.screenshot === "boolean") {
|
|
495
|
-
step.screenshot = {};
|
|
496
|
-
}
|
|
497
|
-
step.screenshot.sourceIntegration = {
|
|
498
|
-
type: "heretto",
|
|
499
|
-
integrationName: herettoIntegration,
|
|
500
|
-
filePath: step.screenshot.path || "",
|
|
501
|
-
contentPath: filePath,
|
|
502
|
-
};
|
|
504
|
+
attachHerettoScreenshotSourceIntegration(step, herettoIntegration, filePath);
|
|
503
505
|
}
|
|
504
506
|
}
|
|
505
507
|
}
|
|
@@ -576,6 +578,13 @@ export async function parseContent({ config = {}, content, filePath = "", fileTy
|
|
|
576
578
|
endIndex: statement._endIndex,
|
|
577
579
|
};
|
|
578
580
|
}
|
|
581
|
+
// Attach sourceIntegration for Heretto on screenshot steps
|
|
582
|
+
if (step.screenshot && config._herettoPathMapping) {
|
|
583
|
+
const herettoIntegration = findHerettoIntegration(config, filePath);
|
|
584
|
+
if (herettoIntegration) {
|
|
585
|
+
attachHerettoScreenshotSourceIntegration(step, herettoIntegration, filePath);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
579
588
|
const validation = validate({
|
|
580
589
|
schemaKey: "step_v3",
|
|
581
590
|
object: step,
|
|
@@ -618,6 +627,28 @@ export async function parseContent({ config = {}, content, filePath = "", fileTy
|
|
|
618
627
|
});
|
|
619
628
|
return validatedTests;
|
|
620
629
|
}
|
|
630
|
+
/**
|
|
631
|
+
* Attaches a Heretto sourceIntegration descriptor to a screenshot step in place.
|
|
632
|
+
* Normalizes non-object screenshot values (string paths, booleans, other primitives)
|
|
633
|
+
* to an object shape before assigning sourceIntegration so downstream validation
|
|
634
|
+
* has a predictable structure to reject or accept.
|
|
635
|
+
*/
|
|
636
|
+
function attachHerettoScreenshotSourceIntegration(step, integrationName, contentPath) {
|
|
637
|
+
if (typeof step.screenshot === "string") {
|
|
638
|
+
step.screenshot = { path: step.screenshot };
|
|
639
|
+
}
|
|
640
|
+
else if (step.screenshot === null ||
|
|
641
|
+
typeof step.screenshot !== "object" ||
|
|
642
|
+
Array.isArray(step.screenshot)) {
|
|
643
|
+
step.screenshot = {};
|
|
644
|
+
}
|
|
645
|
+
step.screenshot.sourceIntegration = {
|
|
646
|
+
type: "heretto",
|
|
647
|
+
integrationName,
|
|
648
|
+
filePath: step.screenshot.path || "",
|
|
649
|
+
contentPath,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
621
652
|
/**
|
|
622
653
|
* Helper function to find which Heretto integration a file belongs to.
|
|
623
654
|
*/
|