codegate-ai 0.4.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.
@@ -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 executeScanCommand(input, deps) {
72
- try {
73
- const interactivePromptsEnabled = deps.isTTY() && input.options.noTui !== true;
74
- const discoveryContext = deps.prepareScanDiscovery
75
- ? await deps.prepareScanDiscovery(input.scanTarget, input.config, {
76
- explicitCandidates: input.explicitCandidates,
77
- })
78
- : undefined;
79
- let report = await deps.runScan({
80
- version: input.version,
81
- scanTarget: input.scanTarget,
82
- config: input.config,
83
- flags: input.options,
84
- discoveryContext,
85
- });
86
- if (input.displayTarget && input.displayTarget !== report.scan_target) {
87
- report = {
88
- ...report,
89
- scan_target: input.displayTarget,
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
- const deepScanNotes = [];
93
- if (input.options.deep) {
94
- const discoverResources = deps.discoverDeepResources ?? (async () => []);
95
- const discoverLocalTextTargets = deps.discoverLocalTextTargets ?? (async () => []);
96
- const resources = await discoverResources(input.scanTarget, input.config, discoveryContext);
97
- const localTextTargets = await discoverLocalTextTargets(input.scanTarget, input.config, discoveryContext);
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 (resources.length === 0 && localTextTargets.length === 0) {
109
- deepScanNotes.push(...noEligibleDeepResourceNotes());
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
- if (selectedAgent) {
113
- deepScanNotes.push(`Deep scan meta-agent selected: ${selectedAgent.label} (${selectedAgent.binary})`);
114
- }
115
- else if (optionsForAgent.length > 0) {
116
- deepScanNotes.push("Deep scan meta-agent skipped. Running deterministic Layer 3 checks only.");
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
- if (resources.length > 0) {
122
- if (!deps.executeDeepResource) {
123
- throw new Error("Deep resource executor not configured");
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
- let resourcesWithFetchedMetadata = 0;
126
- let executedMetaAgentCommands = 0;
127
- const outcomes = await runDeepScanWithConsent(resources, async (resource) => {
128
- if (input.options.force) {
129
- return true;
130
- }
131
- if (deps.requestDeepScanConsent) {
132
- return await deps.requestDeepScanConsent(resource);
133
- }
134
- return false;
135
- }, async (resource) => {
136
- const fetched = await deps.executeDeepResource(resource);
137
- if (fetched.status !== "ok" || !selectedAgent) {
138
- return fetched;
139
- }
140
- resourcesWithFetchedMetadata += 1;
141
- const prompt = buildSecurityAnalysisPrompt({
142
- resourceId: resource.id,
143
- resourceSummary: metadataSummary(fetched.metadata),
144
- });
145
- const command = buildMetaAgentCommand({
146
- tool: selectedAgent.metaTool,
147
- prompt,
148
- workingDirectory: input.scanTarget,
149
- binaryPath: selectedAgent.binary,
150
- });
151
- const commandContext = {
152
- resource,
153
- agent: selectedAgent,
154
- command,
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
- const approvedCommand = input.options.force ||
157
- (deps.requestMetaAgentCommandConsent
158
- ? await deps.requestMetaAgentCommandConsent(commandContext)
159
- : false);
160
- if (!approvedCommand) {
161
- return {
162
- ...fetched,
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: mergeMetaAgentMetadata(fetched.metadata, normalizedOutput),
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
- if (localTextTargets.length > 0) {
224
- if (!selectedAgent) {
225
- deepScanNotes.push("Local instruction-file analysis skipped because no meta-agent was selected.");
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 (!supportsToollessLocalTextAnalysis(selectedAgent.metaTool)) {
228
- deepScanNotes.push("Local instruction-file analysis was skipped because the selected agent does not support tool-less analysis.");
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
- // Local instruction files are analyzed as inert text only; referenced URLs stay as evidence, not inputs.
232
- if (!deps.runMetaAgentCommand) {
233
- throw new Error("Meta-agent command runner not configured");
234
- }
235
- const isolatedWorkingDirectory = mkdtempSync(join(tmpdir(), "codegate-local-analysis-"));
236
- let executedLocalAnalyses = 0;
237
- try {
238
- for (const target of localTextTargets) {
239
- const prompt = buildLocalTextAnalysisPrompt({
240
- filePath: target.reportPath,
241
- textContent: buildPromptEvidenceText(target.textContent),
242
- referencedUrls: target.referencedUrls,
243
- });
244
- const command = buildMetaAgentCommand({
245
- tool: selectedAgent.metaTool,
246
- prompt,
247
- workingDirectory: isolatedWorkingDirectory,
248
- binaryPath: selectedAgent.binary,
249
- });
250
- command.timeoutMs = 60_000;
251
- const commandContext = {
252
- localFile: target,
253
- agent: selectedAgent,
254
- command,
255
- };
256
- const approvedCommand = input.options.force ||
257
- (deps.requestMetaAgentCommandConsent
258
- ? await deps.requestMetaAgentCommandConsent(commandContext)
259
- : false);
260
- if (!approvedCommand) {
261
- continue;
262
- }
263
- executedLocalAnalyses += 1;
264
- const commandResult = await deps.runMetaAgentCommand(commandContext);
265
- if (commandResult.code !== 0) {
266
- deepScanNotes.push(`Local instruction-file analysis failed for ${target.reportPath}: ${commandResult.stderr || `exit code: ${commandResult.code}`}`);
267
- continue;
268
- }
269
- const parsedOutput = parseMetaAgentOutput(commandResult.stdout);
270
- if (parsedOutput === null) {
271
- deepScanNotes.push(`Local instruction-file analysis returned invalid JSON for ${target.reportPath}.`);
272
- continue;
273
- }
274
- const normalizedOutput = Array.isArray(parsedOutput)
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
- finally {
282
- rmSync(isolatedWorkingDirectory, { recursive: true, force: true });
283
- }
284
- if (executedLocalAnalyses > 0) {
285
- const suffix = executedLocalAnalyses === 1 ? "" : "s";
286
- deepScanNotes.push(`Local instruction-file analysis executed for ${executedLocalAnalyses} file${suffix}.`);
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
- report = applyConfigPolicy(report, input.config);
293
- report = reorderRequestedTargetFindings(report, input.displayTarget);
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 = targetSummaryNote ? [...deepScanNotes, targetSummaryNote] : deepScanNotes;
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 { ScanRunnerInput } from "./scan-command.js";
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 { applyConfigPolicy, OUTPUT_FORMATS, } from "../config.js";
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
- let report = await deps.runScan({
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
- flags: {
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
- discoveryContext: undefined,
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: targetSummaryNote ? [targetSummaryNote] : undefined,
371
+ notices: scanNotes.length > 0 ? scanNotes : undefined,
353
372
  });
354
373
  deps.renderTui?.({ view: "summary", report });
355
374
  }
356
375
  else {
357
- if (targetSummaryNote) {
358
- deps.stdout(targetSummaryNote);
376
+ for (const note of scanNotes) {
377
+ deps.stdout(note);
359
378
  }
360
379
  deps.stdout(renderByFormat(config.output_format, report));
361
380
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codegate-ai",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Pre-flight security scanner for AI coding tool configurations.",
5
5
  "license": "MIT",
6
6
  "type": "module",