codegate-ai 0.5.0 → 0.6.0
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 +19 -0
- package/dist/cli.js +70 -31
- package/dist/commands/clawhub-wrapper.d.ts +10 -1
- package/dist/commands/clawhub-wrapper.js +35 -16
- package/dist/commands/scan-command.d.ts +9 -0
- package/dist/commands/scan-command.js +228 -204
- package/dist/commands/skills-wrapper.d.ts +10 -1
- package/dist/commands/skills-wrapper.js +35 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/jonathansantilli/codegate/actions/workflows/ci.yml)
|
|
4
4
|
[](https://github.com/jonathansantilli/codegate/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://deepwiki.com/jonathansantilli/codegate)
|
|
5
6
|
[](https://www.npmjs.com/package/codegate-ai)
|
|
6
7
|
[](./LICENSE)
|
|
7
8
|
|
|
@@ -70,6 +71,21 @@ npm install -g codegate-ai
|
|
|
70
71
|
codegate scan .
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
Recommended first run:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
codegate init
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Why run `init`:
|
|
81
|
+
|
|
82
|
+
- Creates `~/.codegate/config.json` so your behavior is explicit and easy to tune.
|
|
83
|
+
- Makes it straightforward to set preferences like `scan_user_scope`, output format, thresholds, and tool discovery options.
|
|
84
|
+
|
|
85
|
+
If you skip `init`, CodeGate still works with built-in defaults. Nothing breaks.
|
|
86
|
+
|
|
87
|
+
See the [Configuration](#configuration) section for full settings and examples.
|
|
88
|
+
|
|
73
89
|
## System Capabilities
|
|
74
90
|
|
|
75
91
|
1. Multi-layer analysis pipeline:
|
|
@@ -187,6 +203,7 @@ Behavior:
|
|
|
187
203
|
Wrapper flags (consumed by CodeGate, not forwarded):
|
|
188
204
|
|
|
189
205
|
- `--cg-force`
|
|
206
|
+
- `--cg-deep`
|
|
190
207
|
- `--cg-no-tui`
|
|
191
208
|
- `--cg-include-user-scope`
|
|
192
209
|
- `--cg-format <type>`
|
|
@@ -197,8 +214,10 @@ Examples:
|
|
|
197
214
|
```bash
|
|
198
215
|
codegate skills add https://github.com/vercel-labs/skills --skill find-skills
|
|
199
216
|
codegate skills add https://github.com/owner/repo --skill security-review --cg-force
|
|
217
|
+
codegate skills add https://github.com/owner/repo --skill security-review --cg-deep
|
|
200
218
|
codegate clawhub install security-auditor
|
|
201
219
|
codegate clawhub install security-auditor --version 1.0.0
|
|
220
|
+
codegate clawhub install security-auditor --cg-deep
|
|
202
221
|
codegate clawhub search security
|
|
203
222
|
```
|
|
204
223
|
|
package/dist/cli.js
CHANGED
|
@@ -68,6 +68,51 @@ function mapAcquisitionFailure(status, error) {
|
|
|
68
68
|
error: error ?? "tool description acquisition failed",
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
+
async function runMetaAgentCommandWithSandbox(context) {
|
|
72
|
+
const commandResult = await runSandboxCommand({
|
|
73
|
+
command: context.command.command,
|
|
74
|
+
args: context.command.args,
|
|
75
|
+
cwd: context.command.cwd,
|
|
76
|
+
timeoutMs: context.command.timeoutMs,
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
command: context.command,
|
|
80
|
+
code: commandResult.code,
|
|
81
|
+
stdout: commandResult.stdout,
|
|
82
|
+
stderr: commandResult.stderr,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function resolveInteractiveCallback(input) {
|
|
86
|
+
if (!input.enabled) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return input.provided ?? input.fallback;
|
|
90
|
+
}
|
|
91
|
+
function buildWrapperScanBridgeDeps(deps) {
|
|
92
|
+
const isTTY = deps.isTTY();
|
|
93
|
+
return {
|
|
94
|
+
prepareScanDiscovery: deps.prepareScanDiscovery,
|
|
95
|
+
discoverDeepResources: deps.discoverDeepResources,
|
|
96
|
+
discoverLocalTextTargets: deps.discoverLocalTextTargets,
|
|
97
|
+
requestDeepScanConsent: resolveInteractiveCallback({
|
|
98
|
+
enabled: true,
|
|
99
|
+
provided: deps.requestDeepScanConsent,
|
|
100
|
+
fallback: isTTY ? promptDeepScanConsent : undefined,
|
|
101
|
+
}),
|
|
102
|
+
requestDeepAgentSelection: resolveInteractiveCallback({
|
|
103
|
+
enabled: true,
|
|
104
|
+
provided: deps.requestDeepAgentSelection,
|
|
105
|
+
fallback: isTTY ? promptDeepAgentSelection : undefined,
|
|
106
|
+
}),
|
|
107
|
+
requestMetaAgentCommandConsent: resolveInteractiveCallback({
|
|
108
|
+
enabled: true,
|
|
109
|
+
provided: deps.requestMetaAgentCommandConsent,
|
|
110
|
+
fallback: isTTY ? promptMetaAgentCommandConsent : undefined,
|
|
111
|
+
}),
|
|
112
|
+
runMetaAgentCommand: deps.runMetaAgentCommand ?? runMetaAgentCommandWithSandbox,
|
|
113
|
+
executeDeepResource: deps.executeDeepResource,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
71
116
|
async function promptRunWarningConsent(context) {
|
|
72
117
|
const rl = createInterface({
|
|
73
118
|
input: process.stdin,
|
|
@@ -247,38 +292,28 @@ function addScanCommand(program, version, deps) {
|
|
|
247
292
|
prepareScanDiscovery: deps.prepareScanDiscovery,
|
|
248
293
|
discoverDeepResources: deps.discoverDeepResources,
|
|
249
294
|
discoverLocalTextTargets: deps.discoverLocalTextTargets,
|
|
250
|
-
requestDeepScanConsent:
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
: undefined,
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
:
|
|
295
|
+
requestDeepScanConsent: resolveInteractiveCallback({
|
|
296
|
+
enabled: promptCallbacksEnabled,
|
|
297
|
+
provided: deps.requestDeepScanConsent,
|
|
298
|
+
fallback: interactivePromptsEnabled ? promptDeepScanConsent : undefined,
|
|
299
|
+
}),
|
|
300
|
+
requestDeepAgentSelection: resolveInteractiveCallback({
|
|
301
|
+
enabled: promptCallbacksEnabled,
|
|
302
|
+
provided: deps.requestDeepAgentSelection,
|
|
303
|
+
fallback: interactivePromptsEnabled ? promptDeepAgentSelection : undefined,
|
|
304
|
+
}),
|
|
305
|
+
requestMetaAgentCommandConsent: resolveInteractiveCallback({
|
|
306
|
+
enabled: promptCallbacksEnabled,
|
|
307
|
+
provided: deps.requestMetaAgentCommandConsent,
|
|
308
|
+
fallback: interactivePromptsEnabled ? promptMetaAgentCommandConsent : undefined,
|
|
309
|
+
}),
|
|
262
310
|
executeDeepResource: deps.executeDeepResource,
|
|
263
|
-
runMetaAgentCommand: deps.runMetaAgentCommand ??
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
timeoutMs: context.command.timeoutMs,
|
|
270
|
-
});
|
|
271
|
-
return {
|
|
272
|
-
command: context.command,
|
|
273
|
-
code: commandResult.code,
|
|
274
|
-
stdout: commandResult.stdout,
|
|
275
|
-
stderr: commandResult.stderr,
|
|
276
|
-
};
|
|
277
|
-
}),
|
|
278
|
-
requestRemediationConsent: promptCallbacksEnabled
|
|
279
|
-
? (deps.requestRemediationConsent ??
|
|
280
|
-
(interactivePromptsEnabled ? promptRemediationConsent : undefined))
|
|
281
|
-
: undefined,
|
|
311
|
+
runMetaAgentCommand: deps.runMetaAgentCommand ?? runMetaAgentCommandWithSandbox,
|
|
312
|
+
requestRemediationConsent: resolveInteractiveCallback({
|
|
313
|
+
enabled: promptCallbacksEnabled,
|
|
314
|
+
provided: deps.requestRemediationConsent,
|
|
315
|
+
fallback: interactivePromptsEnabled ? promptRemediationConsent : undefined,
|
|
316
|
+
}),
|
|
282
317
|
runRemediation: deps.runRemediation,
|
|
283
318
|
stdout: deps.stdout,
|
|
284
319
|
stderr: deps.stderr,
|
|
@@ -378,6 +413,7 @@ function addSkillsCommand(program, version, deps) {
|
|
|
378
413
|
.addHelpText("after", renderExampleHelp([
|
|
379
414
|
"codegate skills add vercel-labs/skills --skill find-skills",
|
|
380
415
|
"codegate skills add https://github.com/owner/repo --skill security-review",
|
|
416
|
+
"codegate skills add owner/repo --skill demo --cg-deep",
|
|
381
417
|
"codegate skills find security",
|
|
382
418
|
"codegate skills add owner/repo --skill demo --cg-force",
|
|
383
419
|
]))
|
|
@@ -390,6 +426,7 @@ function addSkillsCommand(program, version, deps) {
|
|
|
390
426
|
pathExists: deps.pathExists,
|
|
391
427
|
resolveConfig: deps.resolveConfig,
|
|
392
428
|
runScan: deps.runScan,
|
|
429
|
+
...buildWrapperScanBridgeDeps(deps),
|
|
393
430
|
resolveScanTarget: deps.resolveScanTarget,
|
|
394
431
|
requestSkillSelection: deps.requestSkillSelection,
|
|
395
432
|
requestWarningProceed: deps.requestRunWarningConsent,
|
|
@@ -420,6 +457,7 @@ function addClawhubCommand(program, version, deps) {
|
|
|
420
457
|
.addHelpText("after", renderExampleHelp([
|
|
421
458
|
"codegate clawhub install security-auditor",
|
|
422
459
|
"codegate clawhub install security-auditor --version 1.0.0",
|
|
460
|
+
"codegate clawhub install security-auditor --cg-deep",
|
|
423
461
|
"codegate clawhub search security",
|
|
424
462
|
"codegate clawhub install security-auditor --cg-force",
|
|
425
463
|
]))
|
|
@@ -432,6 +470,7 @@ function addClawhubCommand(program, version, deps) {
|
|
|
432
470
|
pathExists: deps.pathExists,
|
|
433
471
|
resolveConfig: deps.resolveConfig,
|
|
434
472
|
runScan: deps.runScan,
|
|
473
|
+
...buildWrapperScanBridgeDeps(deps),
|
|
435
474
|
resolveScanTarget: deps.resolveScanTarget,
|
|
436
475
|
requestWarningProceed: deps.requestRunWarningConsent,
|
|
437
476
|
launchClawhub: deps.launchClawhub ?? ((args, cwd) => launchClawhubPassthrough(args, cwd)),
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { type CodeGateConfig, type OutputFormat, type ResolveConfigOptions } from "../config.js";
|
|
2
2
|
import { type ResolvedScanTarget } from "../scan-target.js";
|
|
3
3
|
import type { CodeGateReport } from "../types/report.js";
|
|
4
|
-
import type
|
|
4
|
+
import { type ScanAnalysisDeps, type ScanRunnerInput } from "./scan-command.js";
|
|
5
5
|
interface SourceDetectionContext {
|
|
6
6
|
cwd: string;
|
|
7
7
|
pathExists: (path: string) => boolean;
|
|
8
8
|
}
|
|
9
9
|
export interface ClawhubWrapperRuntimeOptions {
|
|
10
10
|
force: boolean;
|
|
11
|
+
deep: boolean;
|
|
11
12
|
noTui: boolean;
|
|
12
13
|
includeUserScope: boolean;
|
|
13
14
|
format?: OutputFormat;
|
|
@@ -38,6 +39,14 @@ export interface ClawhubWrapperDeps {
|
|
|
38
39
|
pathExists?: (path: string) => boolean;
|
|
39
40
|
resolveConfig: (options: ResolveConfigOptions) => CodeGateConfig;
|
|
40
41
|
runScan: (input: ScanRunnerInput) => Promise<CodeGateReport>;
|
|
42
|
+
prepareScanDiscovery?: ScanAnalysisDeps["prepareScanDiscovery"];
|
|
43
|
+
discoverDeepResources?: ScanAnalysisDeps["discoverDeepResources"];
|
|
44
|
+
discoverLocalTextTargets?: ScanAnalysisDeps["discoverLocalTextTargets"];
|
|
45
|
+
requestDeepScanConsent?: ScanAnalysisDeps["requestDeepScanConsent"];
|
|
46
|
+
requestDeepAgentSelection?: ScanAnalysisDeps["requestDeepAgentSelection"];
|
|
47
|
+
requestMetaAgentCommandConsent?: ScanAnalysisDeps["requestMetaAgentCommandConsent"];
|
|
48
|
+
runMetaAgentCommand?: ScanAnalysisDeps["runMetaAgentCommand"];
|
|
49
|
+
executeDeepResource?: ScanAnalysisDeps["executeDeepResource"];
|
|
41
50
|
resolveScanTarget?: (input: {
|
|
42
51
|
rawTarget: string;
|
|
43
52
|
cwd: string;
|
|
@@ -3,9 +3,9 @@ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
|
-
import {
|
|
7
|
-
import { reorderRequestedTargetFindings } from "../report/requested-target-findings.js";
|
|
6
|
+
import { OUTPUT_FORMATS, } from "../config.js";
|
|
8
7
|
import { resolveScanTarget } from "../scan-target.js";
|
|
8
|
+
import { runScanAnalysis } from "./scan-command.js";
|
|
9
9
|
import { renderByFormat, summarizeRequestedTargetFindings } from "./scan-command/helpers.js";
|
|
10
10
|
const CLAWHUB_GLOBAL_OPTIONS_WITH_VALUE = new Set(["--workdir", "--dir", "--site", "--registry"]);
|
|
11
11
|
const CLAWHUB_INSTALL_OPTIONS_WITH_VALUE = new Set(["--version"]);
|
|
@@ -381,6 +381,7 @@ async function stageClawhubTargetDefault(input, deps) {
|
|
|
381
381
|
export function parseClawhubInvocation(rawArgs, context) {
|
|
382
382
|
const wrapper = {
|
|
383
383
|
force: false,
|
|
384
|
+
deep: false,
|
|
384
385
|
noTui: false,
|
|
385
386
|
includeUserScope: false,
|
|
386
387
|
format: undefined,
|
|
@@ -400,6 +401,10 @@ export function parseClawhubInvocation(rawArgs, context) {
|
|
|
400
401
|
wrapper.force = true;
|
|
401
402
|
continue;
|
|
402
403
|
}
|
|
404
|
+
if (token === "--cg-deep") {
|
|
405
|
+
wrapper.deep = true;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
403
408
|
if (token === "--cg-no-tui") {
|
|
404
409
|
wrapper.noTui = true;
|
|
405
410
|
continue;
|
|
@@ -527,41 +532,55 @@ export async function executeClawhubWrapper(input, deps) {
|
|
|
527
532
|
const config = parsed.wrapper.includeUserScope
|
|
528
533
|
? { ...baseConfig, scan_user_scope: true }
|
|
529
534
|
: baseConfig;
|
|
530
|
-
|
|
535
|
+
const { report, deepScanNotes } = await runScanAnalysis({
|
|
531
536
|
version: input.version,
|
|
532
537
|
scanTarget: resolvedTarget.scanTarget,
|
|
538
|
+
displayTarget: resolvedTarget.displayTarget,
|
|
539
|
+
explicitCandidates: resolvedTarget.explicitCandidates,
|
|
533
540
|
config,
|
|
534
|
-
|
|
541
|
+
options: {
|
|
535
542
|
noTui,
|
|
536
543
|
format: parsed.wrapper.format,
|
|
537
544
|
force: parsed.wrapper.force,
|
|
538
545
|
includeUserScope: parsed.wrapper.includeUserScope,
|
|
546
|
+
deep: parsed.wrapper.deep,
|
|
539
547
|
},
|
|
540
|
-
|
|
548
|
+
}, {
|
|
549
|
+
isTTY: deps.isTTY,
|
|
550
|
+
runScan: deps.runScan,
|
|
551
|
+
prepareScanDiscovery: deps.prepareScanDiscovery,
|
|
552
|
+
discoverDeepResources: deps.discoverDeepResources,
|
|
553
|
+
discoverLocalTextTargets: deps.discoverLocalTextTargets,
|
|
554
|
+
requestDeepScanConsent: interactivePromptsEnabled ? deps.requestDeepScanConsent : undefined,
|
|
555
|
+
requestDeepAgentSelection: interactivePromptsEnabled
|
|
556
|
+
? deps.requestDeepAgentSelection
|
|
557
|
+
: undefined,
|
|
558
|
+
requestMetaAgentCommandConsent: interactivePromptsEnabled
|
|
559
|
+
? deps.requestMetaAgentCommandConsent
|
|
560
|
+
: undefined,
|
|
561
|
+
runMetaAgentCommand: deps.runMetaAgentCommand,
|
|
562
|
+
executeDeepResource: deps.executeDeepResource,
|
|
541
563
|
});
|
|
542
|
-
if (resolvedTarget.displayTarget && resolvedTarget.displayTarget !== report.scan_target) {
|
|
543
|
-
report = {
|
|
544
|
-
...report,
|
|
545
|
-
scan_target: resolvedTarget.displayTarget,
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
report = applyConfigPolicy(report, config);
|
|
549
|
-
report = reorderRequestedTargetFindings(report, resolvedTarget.displayTarget);
|
|
550
564
|
const shouldUseTui = config.tui.enabled && isTTY && deps.renderTui !== undefined && noTui !== true;
|
|
551
565
|
const targetSummaryNote = config.output_format === "terminal"
|
|
552
566
|
? summarizeRequestedTargetFindings(report, resolvedTarget.displayTarget)
|
|
553
567
|
: null;
|
|
568
|
+
const scanNotes = config.output_format === "terminal"
|
|
569
|
+
? targetSummaryNote
|
|
570
|
+
? [...deepScanNotes, targetSummaryNote]
|
|
571
|
+
: deepScanNotes
|
|
572
|
+
: [];
|
|
554
573
|
if (shouldUseTui) {
|
|
555
574
|
deps.renderTui?.({
|
|
556
575
|
view: "dashboard",
|
|
557
576
|
report,
|
|
558
|
-
notices:
|
|
577
|
+
notices: scanNotes.length > 0 ? scanNotes : undefined,
|
|
559
578
|
});
|
|
560
579
|
deps.renderTui?.({ view: "summary", report });
|
|
561
580
|
}
|
|
562
581
|
else {
|
|
563
|
-
|
|
564
|
-
deps.stdout(
|
|
582
|
+
for (const note of scanNotes) {
|
|
583
|
+
deps.stdout(note);
|
|
565
584
|
}
|
|
566
585
|
deps.stdout(renderByFormat(config.output_format, report));
|
|
567
586
|
}
|
|
@@ -88,4 +88,13 @@ export interface ExecuteScanCommandDeps {
|
|
|
88
88
|
notices?: string[];
|
|
89
89
|
}) => void;
|
|
90
90
|
}
|
|
91
|
+
type ScanAnalysisDepKeys = "isTTY" | "runScan" | "prepareScanDiscovery" | "discoverDeepResources" | "discoverLocalTextTargets" | "requestDeepScanConsent" | "requestDeepAgentSelection" | "requestMetaAgentCommandConsent" | "runMetaAgentCommand" | "executeDeepResource";
|
|
92
|
+
export type ScanAnalysisDeps = Pick<ExecuteScanCommandDeps, ScanAnalysisDepKeys>;
|
|
93
|
+
export type ScanAnalysisInput = Omit<ExecuteScanCommandInput, "cwd">;
|
|
94
|
+
export interface ScanAnalysisResult {
|
|
95
|
+
report: CodeGateReport;
|
|
96
|
+
deepScanNotes: string[];
|
|
97
|
+
}
|
|
98
|
+
export declare function runScanAnalysis(input: ScanAnalysisInput, deps: ScanAnalysisDeps): Promise<ScanAnalysisResult>;
|
|
91
99
|
export declare function executeScanCommand(input: ExecuteScanCommandInput, deps: ExecuteScanCommandDeps): Promise<void>;
|
|
100
|
+
export {};
|
|
@@ -68,229 +68,249 @@ function deepAgentOptions(report, config) {
|
|
|
68
68
|
return order.indexOf(left.id) - order.indexOf(right.id);
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
-
export async function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
report
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
export async function runScanAnalysis(input, deps) {
|
|
72
|
+
const interactivePromptsEnabled = deps.isTTY() && input.options.noTui !== true;
|
|
73
|
+
const discoveryContext = deps.prepareScanDiscovery
|
|
74
|
+
? await deps.prepareScanDiscovery(input.scanTarget, input.config, {
|
|
75
|
+
explicitCandidates: input.explicitCandidates,
|
|
76
|
+
})
|
|
77
|
+
: undefined;
|
|
78
|
+
let report = await deps.runScan({
|
|
79
|
+
version: input.version,
|
|
80
|
+
scanTarget: input.scanTarget,
|
|
81
|
+
config: input.config,
|
|
82
|
+
flags: input.options,
|
|
83
|
+
discoveryContext,
|
|
84
|
+
});
|
|
85
|
+
if (input.displayTarget && input.displayTarget !== report.scan_target) {
|
|
86
|
+
report = {
|
|
87
|
+
...report,
|
|
88
|
+
scan_target: input.displayTarget,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const deepScanNotes = [];
|
|
92
|
+
if (input.options.deep) {
|
|
93
|
+
const discoverResources = deps.discoverDeepResources ?? (async () => []);
|
|
94
|
+
const discoverLocalTextTargets = deps.discoverLocalTextTargets ?? (async () => []);
|
|
95
|
+
const resources = await discoverResources(input.scanTarget, input.config, discoveryContext);
|
|
96
|
+
const localTextTargets = await discoverLocalTextTargets(input.scanTarget, input.config, discoveryContext);
|
|
97
|
+
const optionsForAgent = deepAgentOptions(report, input.config);
|
|
98
|
+
let selectedAgent = null;
|
|
99
|
+
if ((resources.length > 0 || localTextTargets.length > 0) && optionsForAgent.length > 0) {
|
|
100
|
+
if (input.options.force || !interactivePromptsEnabled) {
|
|
101
|
+
selectedAgent = optionsForAgent[0] ?? null;
|
|
102
|
+
}
|
|
103
|
+
else if (deps.requestDeepAgentSelection) {
|
|
104
|
+
selectedAgent = await deps.requestDeepAgentSelection(optionsForAgent);
|
|
105
|
+
}
|
|
91
106
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const optionsForAgent = deepAgentOptions(report, input.config);
|
|
99
|
-
let selectedAgent = null;
|
|
100
|
-
if ((resources.length > 0 || localTextTargets.length > 0) && optionsForAgent.length > 0) {
|
|
101
|
-
if (input.options.force || !interactivePromptsEnabled) {
|
|
102
|
-
selectedAgent = optionsForAgent[0] ?? null;
|
|
103
|
-
}
|
|
104
|
-
else if (deps.requestDeepAgentSelection) {
|
|
105
|
-
selectedAgent = await deps.requestDeepAgentSelection(optionsForAgent);
|
|
106
|
-
}
|
|
107
|
+
if (resources.length === 0 && localTextTargets.length === 0) {
|
|
108
|
+
deepScanNotes.push(...noEligibleDeepResourceNotes());
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
if (selectedAgent) {
|
|
112
|
+
deepScanNotes.push(`Deep scan meta-agent selected: ${selectedAgent.label} (${selectedAgent.binary})`);
|
|
107
113
|
}
|
|
108
|
-
if (
|
|
109
|
-
deepScanNotes.push(
|
|
114
|
+
else if (optionsForAgent.length > 0) {
|
|
115
|
+
deepScanNotes.push("Deep scan meta-agent skipped. Running deterministic Layer 3 checks only.");
|
|
110
116
|
}
|
|
111
117
|
else {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
deepScanNotes.push("No supported deep-scan agent detected (Claude Code, Codex CLI, or OpenCode). Running deterministic Layer 3 checks only.");
|
|
118
|
+
deepScanNotes.push("No supported deep-scan agent detected (Claude Code, Codex CLI, or OpenCode). Running deterministic Layer 3 checks only.");
|
|
119
|
+
}
|
|
120
|
+
if (resources.length > 0) {
|
|
121
|
+
if (!deps.executeDeepResource) {
|
|
122
|
+
throw new Error("Deep resource executor not configured");
|
|
120
123
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
let resourcesWithFetchedMetadata = 0;
|
|
125
|
+
let executedMetaAgentCommands = 0;
|
|
126
|
+
const outcomes = await runDeepScanWithConsent(resources, async (resource) => {
|
|
127
|
+
if (input.options.force) {
|
|
128
|
+
return true;
|
|
124
129
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
130
|
+
if (deps.requestDeepScanConsent) {
|
|
131
|
+
return await deps.requestDeepScanConsent(resource);
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}, async (resource) => {
|
|
135
|
+
const fetched = await deps.executeDeepResource(resource);
|
|
136
|
+
if (fetched.status !== "ok" || !selectedAgent) {
|
|
137
|
+
return fetched;
|
|
138
|
+
}
|
|
139
|
+
resourcesWithFetchedMetadata += 1;
|
|
140
|
+
const prompt = buildSecurityAnalysisPrompt({
|
|
141
|
+
resourceId: resource.id,
|
|
142
|
+
resourceSummary: metadataSummary(fetched.metadata),
|
|
143
|
+
});
|
|
144
|
+
const command = buildMetaAgentCommand({
|
|
145
|
+
tool: selectedAgent.metaTool,
|
|
146
|
+
prompt,
|
|
147
|
+
workingDirectory: input.scanTarget,
|
|
148
|
+
binaryPath: selectedAgent.binary,
|
|
149
|
+
});
|
|
150
|
+
const commandContext = {
|
|
151
|
+
resource,
|
|
152
|
+
agent: selectedAgent,
|
|
153
|
+
command,
|
|
154
|
+
};
|
|
155
|
+
const approvedCommand = input.options.force ||
|
|
156
|
+
(deps.requestMetaAgentCommandConsent
|
|
157
|
+
? await deps.requestMetaAgentCommandConsent(commandContext)
|
|
158
|
+
: false);
|
|
159
|
+
if (!approvedCommand) {
|
|
160
|
+
return {
|
|
161
|
+
...fetched,
|
|
162
|
+
metadata: withMetaAgentFinding(fetched.metadata, {
|
|
163
|
+
id: `layer3-meta-agent-skipped-${resource.id}`,
|
|
164
|
+
severity: "INFO",
|
|
165
|
+
description: `Deep scan meta-agent command skipped for ${resource.id}`,
|
|
166
|
+
}),
|
|
155
167
|
};
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
metadata: withMetaAgentFinding(fetched.metadata, {
|
|
164
|
-
id: `layer3-meta-agent-skipped-${resource.id}`,
|
|
165
|
-
severity: "INFO",
|
|
166
|
-
description: `Deep scan meta-agent command skipped for ${resource.id}`,
|
|
167
|
-
}),
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
if (!deps.runMetaAgentCommand) {
|
|
171
|
-
throw new Error("Meta-agent command runner not configured");
|
|
172
|
-
}
|
|
173
|
-
executedMetaAgentCommands += 1;
|
|
174
|
-
const commandResult = await deps.runMetaAgentCommand(commandContext);
|
|
175
|
-
if (commandResult.code !== 0) {
|
|
176
|
-
return {
|
|
177
|
-
...fetched,
|
|
178
|
-
metadata: withMetaAgentFinding(fetched.metadata, {
|
|
179
|
-
id: `layer3-meta-agent-command-error-${resource.id}`,
|
|
180
|
-
severity: "LOW",
|
|
181
|
-
description: `Deep scan meta-agent command failed for ${resource.id}`,
|
|
182
|
-
evidence: commandResult.stderr || `exit code: ${commandResult.code}`,
|
|
183
|
-
}),
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
const parsedOutput = parseMetaAgentOutput(commandResult.stdout);
|
|
187
|
-
if (parsedOutput === null) {
|
|
188
|
-
return {
|
|
189
|
-
...fetched,
|
|
190
|
-
metadata: withMetaAgentFinding(fetched.metadata, {
|
|
191
|
-
id: `layer3-meta-agent-parse-error-${resource.id}`,
|
|
192
|
-
severity: "LOW",
|
|
193
|
-
description: `Deep scan meta-agent output was not valid JSON for ${resource.id}`,
|
|
194
|
-
evidence: commandResult.stdout.slice(0, 400),
|
|
195
|
-
}),
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
const normalizedOutput = Array.isArray(parsedOutput)
|
|
199
|
-
? { findings: parsedOutput }
|
|
200
|
-
: parsedOutput;
|
|
168
|
+
}
|
|
169
|
+
if (!deps.runMetaAgentCommand) {
|
|
170
|
+
throw new Error("Meta-agent command runner not configured");
|
|
171
|
+
}
|
|
172
|
+
executedMetaAgentCommands += 1;
|
|
173
|
+
const commandResult = await deps.runMetaAgentCommand(commandContext);
|
|
174
|
+
if (commandResult.code !== 0) {
|
|
201
175
|
return {
|
|
202
176
|
...fetched,
|
|
203
|
-
metadata:
|
|
177
|
+
metadata: withMetaAgentFinding(fetched.metadata, {
|
|
178
|
+
id: `layer3-meta-agent-command-error-${resource.id}`,
|
|
179
|
+
severity: "LOW",
|
|
180
|
+
description: `Deep scan meta-agent command failed for ${resource.id}`,
|
|
181
|
+
evidence: commandResult.stderr || `exit code: ${commandResult.code}`,
|
|
182
|
+
}),
|
|
204
183
|
};
|
|
205
|
-
});
|
|
206
|
-
const layer3Findings = layer3OutcomesToFindings(outcomes, {
|
|
207
|
-
unicodeAnalysis: input.config.unicode_analysis,
|
|
208
|
-
});
|
|
209
|
-
report = mergeLayer3Findings(report, layer3Findings);
|
|
210
|
-
if (selectedAgent) {
|
|
211
|
-
if (resourcesWithFetchedMetadata === 0) {
|
|
212
|
-
deepScanNotes.push("Selected meta-agent was not executed because no approved resources returned metadata successfully.");
|
|
213
|
-
}
|
|
214
|
-
else if (executedMetaAgentCommands === 0) {
|
|
215
|
-
deepScanNotes.push("Selected meta-agent was not executed because meta-agent command execution was not approved.");
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
const suffix = executedMetaAgentCommands === 1 ? "" : "s";
|
|
219
|
-
deepScanNotes.push(`Deep scan meta-agent executed for ${executedMetaAgentCommands} resource${suffix}.`);
|
|
220
|
-
}
|
|
221
184
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
185
|
+
const parsedOutput = parseMetaAgentOutput(commandResult.stdout);
|
|
186
|
+
if (parsedOutput === null) {
|
|
187
|
+
return {
|
|
188
|
+
...fetched,
|
|
189
|
+
metadata: withMetaAgentFinding(fetched.metadata, {
|
|
190
|
+
id: `layer3-meta-agent-parse-error-${resource.id}`,
|
|
191
|
+
severity: "LOW",
|
|
192
|
+
description: `Deep scan meta-agent output was not valid JSON for ${resource.id}`,
|
|
193
|
+
evidence: commandResult.stdout.slice(0, 400),
|
|
194
|
+
}),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const normalizedOutput = Array.isArray(parsedOutput)
|
|
198
|
+
? { findings: parsedOutput }
|
|
199
|
+
: parsedOutput;
|
|
200
|
+
return {
|
|
201
|
+
...fetched,
|
|
202
|
+
metadata: mergeMetaAgentMetadata(fetched.metadata, normalizedOutput),
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
const layer3Findings = layer3OutcomesToFindings(outcomes, {
|
|
206
|
+
unicodeAnalysis: input.config.unicode_analysis,
|
|
207
|
+
});
|
|
208
|
+
report = mergeLayer3Findings(report, layer3Findings);
|
|
209
|
+
if (selectedAgent) {
|
|
210
|
+
if (resourcesWithFetchedMetadata === 0) {
|
|
211
|
+
deepScanNotes.push("Selected meta-agent was not executed because no approved resources returned metadata successfully.");
|
|
226
212
|
}
|
|
227
|
-
else if (
|
|
228
|
-
deepScanNotes.push("
|
|
213
|
+
else if (executedMetaAgentCommands === 0) {
|
|
214
|
+
deepScanNotes.push("Selected meta-agent was not executed because meta-agent command execution was not approved.");
|
|
229
215
|
}
|
|
230
216
|
else {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
? { findings: parsedOutput }
|
|
276
|
-
: parsedOutput;
|
|
277
|
-
const localFindings = parseLocalTextFindings(target.reportPath, normalizedOutput);
|
|
278
|
-
report = mergeLayer3Findings(report, localFindings);
|
|
217
|
+
const suffix = executedMetaAgentCommands === 1 ? "" : "s";
|
|
218
|
+
deepScanNotes.push(`Deep scan meta-agent executed for ${executedMetaAgentCommands} resource${suffix}.`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (localTextTargets.length > 0) {
|
|
223
|
+
if (!selectedAgent) {
|
|
224
|
+
deepScanNotes.push("Local instruction-file analysis skipped because no meta-agent was selected.");
|
|
225
|
+
}
|
|
226
|
+
else if (!supportsToollessLocalTextAnalysis(selectedAgent.metaTool)) {
|
|
227
|
+
deepScanNotes.push("Local instruction-file analysis was skipped because the selected agent does not support tool-less analysis.");
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Local instruction files are analyzed as inert text only; referenced URLs stay as evidence, not inputs.
|
|
231
|
+
if (!deps.runMetaAgentCommand) {
|
|
232
|
+
throw new Error("Meta-agent command runner not configured");
|
|
233
|
+
}
|
|
234
|
+
const isolatedWorkingDirectory = mkdtempSync(join(tmpdir(), "codegate-local-analysis-"));
|
|
235
|
+
let executedLocalAnalyses = 0;
|
|
236
|
+
try {
|
|
237
|
+
for (const target of localTextTargets) {
|
|
238
|
+
const prompt = buildLocalTextAnalysisPrompt({
|
|
239
|
+
filePath: target.reportPath,
|
|
240
|
+
textContent: buildPromptEvidenceText(target.textContent),
|
|
241
|
+
referencedUrls: target.referencedUrls,
|
|
242
|
+
});
|
|
243
|
+
const command = buildMetaAgentCommand({
|
|
244
|
+
tool: selectedAgent.metaTool,
|
|
245
|
+
prompt,
|
|
246
|
+
workingDirectory: isolatedWorkingDirectory,
|
|
247
|
+
binaryPath: selectedAgent.binary,
|
|
248
|
+
});
|
|
249
|
+
command.timeoutMs = 60_000;
|
|
250
|
+
const commandContext = {
|
|
251
|
+
localFile: target,
|
|
252
|
+
agent: selectedAgent,
|
|
253
|
+
command,
|
|
254
|
+
};
|
|
255
|
+
const approvedCommand = input.options.force ||
|
|
256
|
+
(deps.requestMetaAgentCommandConsent
|
|
257
|
+
? await deps.requestMetaAgentCommandConsent(commandContext)
|
|
258
|
+
: false);
|
|
259
|
+
if (!approvedCommand) {
|
|
260
|
+
continue;
|
|
279
261
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
262
|
+
executedLocalAnalyses += 1;
|
|
263
|
+
const commandResult = await deps.runMetaAgentCommand(commandContext);
|
|
264
|
+
if (commandResult.code !== 0) {
|
|
265
|
+
deepScanNotes.push(`Local instruction-file analysis failed for ${target.reportPath}: ${commandResult.stderr || `exit code: ${commandResult.code}`}`);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const parsedOutput = parseMetaAgentOutput(commandResult.stdout);
|
|
269
|
+
if (parsedOutput === null) {
|
|
270
|
+
deepScanNotes.push(`Local instruction-file analysis returned invalid JSON for ${target.reportPath}.`);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const normalizedOutput = Array.isArray(parsedOutput)
|
|
274
|
+
? { findings: parsedOutput }
|
|
275
|
+
: parsedOutput;
|
|
276
|
+
const localFindings = parseLocalTextFindings(target.reportPath, normalizedOutput);
|
|
277
|
+
report = mergeLayer3Findings(report, localFindings);
|
|
287
278
|
}
|
|
288
279
|
}
|
|
280
|
+
finally {
|
|
281
|
+
rmSync(isolatedWorkingDirectory, { recursive: true, force: true });
|
|
282
|
+
}
|
|
283
|
+
if (executedLocalAnalyses > 0) {
|
|
284
|
+
const suffix = executedLocalAnalyses === 1 ? "" : "s";
|
|
285
|
+
deepScanNotes.push(`Local instruction-file analysis executed for ${executedLocalAnalyses} file${suffix}.`);
|
|
286
|
+
}
|
|
289
287
|
}
|
|
290
288
|
}
|
|
291
289
|
}
|
|
292
|
-
|
|
293
|
-
|
|
290
|
+
}
|
|
291
|
+
report = applyConfigPolicy(report, input.config);
|
|
292
|
+
report = reorderRequestedTargetFindings(report, input.displayTarget);
|
|
293
|
+
return {
|
|
294
|
+
report,
|
|
295
|
+
deepScanNotes,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
export async function executeScanCommand(input, deps) {
|
|
299
|
+
try {
|
|
300
|
+
const interactivePromptsEnabled = deps.isTTY() && input.options.noTui !== true;
|
|
301
|
+
const { report: analyzedReport, deepScanNotes } = await runScanAnalysis(input, {
|
|
302
|
+
isTTY: deps.isTTY,
|
|
303
|
+
runScan: deps.runScan,
|
|
304
|
+
prepareScanDiscovery: deps.prepareScanDiscovery,
|
|
305
|
+
discoverDeepResources: deps.discoverDeepResources,
|
|
306
|
+
discoverLocalTextTargets: deps.discoverLocalTextTargets,
|
|
307
|
+
requestDeepScanConsent: deps.requestDeepScanConsent,
|
|
308
|
+
requestDeepAgentSelection: deps.requestDeepAgentSelection,
|
|
309
|
+
requestMetaAgentCommandConsent: deps.requestMetaAgentCommandConsent,
|
|
310
|
+
runMetaAgentCommand: deps.runMetaAgentCommand,
|
|
311
|
+
executeDeepResource: deps.executeDeepResource,
|
|
312
|
+
});
|
|
313
|
+
let report = analyzedReport;
|
|
294
314
|
const remediationRequested = input.options.remediate ||
|
|
295
315
|
input.options.fixSafe ||
|
|
296
316
|
input.options.dryRun ||
|
|
@@ -378,7 +398,11 @@ export async function executeScanCommand(input, deps) {
|
|
|
378
398
|
const targetSummaryNote = input.config.output_format === "terminal"
|
|
379
399
|
? summarizeRequestedTargetFindings(report, input.displayTarget)
|
|
380
400
|
: null;
|
|
381
|
-
const scanNotes =
|
|
401
|
+
const scanNotes = input.config.output_format === "terminal"
|
|
402
|
+
? targetSummaryNote
|
|
403
|
+
? [...deepScanNotes, targetSummaryNote]
|
|
404
|
+
: deepScanNotes
|
|
405
|
+
: [];
|
|
382
406
|
if (shouldUseTui) {
|
|
383
407
|
deps.renderTui?.({ view: "dashboard", report, notices: scanNotes });
|
|
384
408
|
deps.renderTui?.({ view: "summary", report });
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type CodeGateConfig, type OutputFormat, type ResolveConfigOptions } from "../config.js";
|
|
2
2
|
import { type ResolvedScanTarget } from "../scan-target.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type ScanAnalysisDeps, type ScanRunnerInput } from "./scan-command.js";
|
|
4
4
|
import type { CodeGateReport } from "../types/report.js";
|
|
5
5
|
export interface SkillsWrapperRuntimeOptions {
|
|
6
6
|
force: boolean;
|
|
7
|
+
deep: boolean;
|
|
7
8
|
noTui: boolean;
|
|
8
9
|
includeUserScope: boolean;
|
|
9
10
|
format?: OutputFormat;
|
|
@@ -34,6 +35,14 @@ export interface SkillsWrapperDeps {
|
|
|
34
35
|
pathExists?: (path: string) => boolean;
|
|
35
36
|
resolveConfig: (options: ResolveConfigOptions) => CodeGateConfig;
|
|
36
37
|
runScan: (input: ScanRunnerInput) => Promise<CodeGateReport>;
|
|
38
|
+
prepareScanDiscovery?: ScanAnalysisDeps["prepareScanDiscovery"];
|
|
39
|
+
discoverDeepResources?: ScanAnalysisDeps["discoverDeepResources"];
|
|
40
|
+
discoverLocalTextTargets?: ScanAnalysisDeps["discoverLocalTextTargets"];
|
|
41
|
+
requestDeepScanConsent?: ScanAnalysisDeps["requestDeepScanConsent"];
|
|
42
|
+
requestDeepAgentSelection?: ScanAnalysisDeps["requestDeepAgentSelection"];
|
|
43
|
+
requestMetaAgentCommandConsent?: ScanAnalysisDeps["requestMetaAgentCommandConsent"];
|
|
44
|
+
runMetaAgentCommand?: ScanAnalysisDeps["runMetaAgentCommand"];
|
|
45
|
+
executeDeepResource?: ScanAnalysisDeps["executeDeepResource"];
|
|
37
46
|
resolveScanTarget?: (input: {
|
|
38
47
|
rawTarget: string;
|
|
39
48
|
cwd: string;
|
|
@@ -2,10 +2,10 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { OUTPUT_FORMATS, } from "../config.js";
|
|
6
6
|
import { renderByFormat, summarizeRequestedTargetFindings } from "./scan-command/helpers.js";
|
|
7
|
-
import { reorderRequestedTargetFindings } from "../report/requested-target-findings.js";
|
|
8
7
|
import { resolveScanTarget } from "../scan-target.js";
|
|
8
|
+
import { runScanAnalysis } from "./scan-command.js";
|
|
9
9
|
function parseWrapperOptionValue(args, index, flag) {
|
|
10
10
|
const current = args[index] ?? "";
|
|
11
11
|
const withEquals = `${flag}=`;
|
|
@@ -177,6 +177,7 @@ function findAddSubcommandIndex(args, context) {
|
|
|
177
177
|
export function parseSkillsInvocation(rawArgs, context) {
|
|
178
178
|
const wrapper = {
|
|
179
179
|
force: false,
|
|
180
|
+
deep: false,
|
|
180
181
|
noTui: false,
|
|
181
182
|
includeUserScope: false,
|
|
182
183
|
format: undefined,
|
|
@@ -196,6 +197,10 @@ export function parseSkillsInvocation(rawArgs, context) {
|
|
|
196
197
|
wrapper.force = true;
|
|
197
198
|
continue;
|
|
198
199
|
}
|
|
200
|
+
if (token === "--cg-deep") {
|
|
201
|
+
wrapper.deep = true;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
199
204
|
if (token === "--cg-no-tui") {
|
|
200
205
|
wrapper.noTui = true;
|
|
201
206
|
continue;
|
|
@@ -320,42 +325,56 @@ export async function executeSkillsWrapper(input, deps) {
|
|
|
320
325
|
const config = parsed.wrapper.includeUserScope
|
|
321
326
|
? { ...baseConfig, scan_user_scope: true }
|
|
322
327
|
: baseConfig;
|
|
323
|
-
|
|
328
|
+
const { report, deepScanNotes } = await runScanAnalysis({
|
|
324
329
|
version: input.version,
|
|
325
330
|
scanTarget: resolvedTarget.scanTarget,
|
|
331
|
+
displayTarget: resolvedTarget.displayTarget,
|
|
332
|
+
explicitCandidates: resolvedTarget.explicitCandidates,
|
|
326
333
|
config,
|
|
327
|
-
|
|
334
|
+
options: {
|
|
328
335
|
noTui,
|
|
329
336
|
format: parsed.wrapper.format,
|
|
330
337
|
force: parsed.wrapper.force,
|
|
331
338
|
includeUserScope: parsed.wrapper.includeUserScope,
|
|
332
339
|
skill: preferredSkill,
|
|
340
|
+
deep: parsed.wrapper.deep,
|
|
333
341
|
},
|
|
334
|
-
|
|
342
|
+
}, {
|
|
343
|
+
isTTY: deps.isTTY,
|
|
344
|
+
runScan: deps.runScan,
|
|
345
|
+
prepareScanDiscovery: deps.prepareScanDiscovery,
|
|
346
|
+
discoverDeepResources: deps.discoverDeepResources,
|
|
347
|
+
discoverLocalTextTargets: deps.discoverLocalTextTargets,
|
|
348
|
+
requestDeepScanConsent: interactivePromptsEnabled ? deps.requestDeepScanConsent : undefined,
|
|
349
|
+
requestDeepAgentSelection: interactivePromptsEnabled
|
|
350
|
+
? deps.requestDeepAgentSelection
|
|
351
|
+
: undefined,
|
|
352
|
+
requestMetaAgentCommandConsent: interactivePromptsEnabled
|
|
353
|
+
? deps.requestMetaAgentCommandConsent
|
|
354
|
+
: undefined,
|
|
355
|
+
runMetaAgentCommand: deps.runMetaAgentCommand,
|
|
356
|
+
executeDeepResource: deps.executeDeepResource,
|
|
335
357
|
});
|
|
336
|
-
if (resolvedTarget.displayTarget && resolvedTarget.displayTarget !== report.scan_target) {
|
|
337
|
-
report = {
|
|
338
|
-
...report,
|
|
339
|
-
scan_target: resolvedTarget.displayTarget,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
report = applyConfigPolicy(report, config);
|
|
343
|
-
report = reorderRequestedTargetFindings(report, resolvedTarget.displayTarget);
|
|
344
358
|
const shouldUseTui = config.tui.enabled && isTTY && deps.renderTui !== undefined && noTui !== true;
|
|
345
359
|
const targetSummaryNote = config.output_format === "terminal"
|
|
346
360
|
? summarizeRequestedTargetFindings(report, resolvedTarget.displayTarget)
|
|
347
361
|
: null;
|
|
362
|
+
const scanNotes = config.output_format === "terminal"
|
|
363
|
+
? targetSummaryNote
|
|
364
|
+
? [...deepScanNotes, targetSummaryNote]
|
|
365
|
+
: deepScanNotes
|
|
366
|
+
: [];
|
|
348
367
|
if (shouldUseTui) {
|
|
349
368
|
deps.renderTui?.({
|
|
350
369
|
view: "dashboard",
|
|
351
370
|
report,
|
|
352
|
-
notices:
|
|
371
|
+
notices: scanNotes.length > 0 ? scanNotes : undefined,
|
|
353
372
|
});
|
|
354
373
|
deps.renderTui?.({ view: "summary", report });
|
|
355
374
|
}
|
|
356
375
|
else {
|
|
357
|
-
|
|
358
|
-
deps.stdout(
|
|
376
|
+
for (const note of scanNotes) {
|
|
377
|
+
deps.stdout(note);
|
|
359
378
|
}
|
|
360
379
|
deps.stdout(renderByFormat(config.output_format, report));
|
|
361
380
|
}
|