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.
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/jonathansantilli/codegate/actions/workflows/ci.yml/badge.svg)](https://github.com/jonathansantilli/codegate/actions/workflows/ci.yml)
4
4
  [![CodeQL](https://github.com/jonathansantilli/codegate/actions/workflows/codeql.yml/badge.svg)](https://github.com/jonathansantilli/codegate/actions/workflows/codeql.yml)
5
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg?url=https://deepwiki.com/jonathansantilli/codegate)](https://deepwiki.com/jonathansantilli/codegate)
5
6
  [![npm version](https://img.shields.io/npm/v/codegate-ai)](https://www.npmjs.com/package/codegate-ai)
6
7
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./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:
@@ -89,15 +105,17 @@ codegate scan .
89
105
 
90
106
  ## Core Commands
91
107
 
92
- | Command | Purpose |
93
- | ----------------------- | ---------------------------------------------------------------------- |
94
- | `codegate scan [dir]` | Scan a directory for AI tool config risks. Defaults to `.`. |
95
- | `codegate run <tool>` | Scan current directory, then launch selected AI tool if policy allows. |
96
- | `codegate undo [dir]` | Restore the most recent remediation backup session. Defaults to `.`. |
97
- | `codegate init` | Create `~/.codegate/config.json` with defaults. |
98
- | `codegate update-kb` | Show knowledge-base update guidance. |
99
- | `codegate update-rules` | Show rules update guidance. |
100
- | `codegate --help` | Show CLI usage. |
108
+ | Command | Purpose |
109
+ | ------------------------ | ---------------------------------------------------------------------- |
110
+ | `codegate scan [target]` | Scan a directory, file, or URL target for AI tool config risks. |
111
+ | `codegate run <tool>` | Scan current directory, then launch selected AI tool if policy allows. |
112
+ | `codegate skills [...]` | Wrap `npx skills` and preflight-scan `skills add` targets. |
113
+ | `codegate clawhub [...]` | Wrap `npx clawhub` and preflight-scan `clawhub install` targets. |
114
+ | `codegate undo [dir]` | Restore the most recent remediation backup session. Defaults to `.`. |
115
+ | `codegate init` | Create `~/.codegate/config.json` with defaults. |
116
+ | `codegate update-kb` | Show knowledge-base update guidance. |
117
+ | `codegate update-rules` | Show rules update guidance. |
118
+ | `codegate --help` | Show CLI usage. |
101
119
 
102
120
  ## `scan` Command Flags
103
121
 
@@ -167,6 +185,42 @@ codegate run codex
167
185
  codegate run cursor
168
186
  ```
169
187
 
188
+ ## Installer Wrappers (`skills` and `clawhub`)
189
+
190
+ CodeGate also provides scan-first wrappers for skill installers:
191
+
192
+ - `codegate skills [skillsArgs...]` wraps `npx skills`.
193
+ - `codegate clawhub [clawhubArgs...]` wraps `npx clawhub`.
194
+
195
+ Behavior:
196
+
197
+ - For `skills add ...`, CodeGate resolves the requested source target, scans it, and only proceeds if policy allows.
198
+ - For `clawhub install ...`, CodeGate stages the remote skill content via `clawhub inspect`, scans the staged content, and only proceeds if policy allows.
199
+ - Dangerous findings block execution (fail-closed).
200
+ - Warning-level findings can still require confirmation unless `--cg-force` is provided.
201
+ - Non-install subcommands (for example `skills find` or `clawhub search`) are passed through without preflight scanning.
202
+
203
+ Wrapper flags (consumed by CodeGate, not forwarded):
204
+
205
+ - `--cg-force`
206
+ - `--cg-deep`
207
+ - `--cg-no-tui`
208
+ - `--cg-include-user-scope`
209
+ - `--cg-format <type>`
210
+ - `--cg-config <path>`
211
+
212
+ Examples:
213
+
214
+ ```bash
215
+ codegate skills add https://github.com/vercel-labs/skills --skill find-skills
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
218
+ codegate clawhub install security-auditor
219
+ codegate clawhub install security-auditor --version 1.0.0
220
+ codegate clawhub install security-auditor --cg-deep
221
+ codegate clawhub search security
222
+ ```
223
+
170
224
  ## Deep Scan (Layer 3)
171
225
 
172
226
  Deep scan is opt-in and only runs with `--deep`.
package/dist/cli.d.ts CHANGED
@@ -9,6 +9,7 @@ import { type ResolvedScanTarget } from "./scan-target.js";
9
9
  import type { CodeGateReport } from "./types/report.js";
10
10
  import { type RemediationRunnerInput, type RemediationRunnerResult } from "./layer4-remediation/remediation-runner.js";
11
11
  import { type SkillsWrapperLaunchResult } from "./commands/skills-wrapper.js";
12
+ import { type ClawhubWrapperLaunchResult } from "./commands/clawhub-wrapper.js";
12
13
  import { type DeepAgentOption, type MetaAgentCommandConsentContext, type MetaAgentCommandRunResult, type RemediationConsentContext, type ScanRunnerInput } from "./commands/scan-command.js";
13
14
  export interface RunWarningConsentContext {
14
15
  target: string;
@@ -57,10 +58,15 @@ export interface CliDeps {
57
58
  requestSkillSelection?: (options: string[]) => Promise<string | null> | string | null;
58
59
  executeDeepResource?: (resource: DeepScanResource) => Promise<ResourceFetchResult>;
59
60
  launchSkills?: (args: string[], cwd: string) => SkillsWrapperLaunchResult;
61
+ launchClawhub?: (args: string[], cwd: string) => ClawhubWrapperLaunchResult;
60
62
  runSkillsWrapper?: (input: {
61
63
  version: string;
62
64
  skillsArgs: string[];
63
65
  }) => Promise<void>;
66
+ runClawhubWrapper?: (input: {
67
+ version: string;
68
+ clawhubArgs: string[];
69
+ }) => Promise<void>;
64
70
  runWrapper?: (input: {
65
71
  target: string;
66
72
  cwd: string;
package/dist/cli.js CHANGED
@@ -21,6 +21,7 @@ import { runRemediation as runRemediationWorkflow, } from "./layer4-remediation/
21
21
  import { undoLatestSession } from "./commands/undo.js";
22
22
  import { executeScanCommand } from "./commands/scan-command.js";
23
23
  import { executeSkillsWrapper, launchSkillsPassthrough, } from "./commands/skills-wrapper.js";
24
+ import { executeClawhubWrapper, launchClawhubPassthrough, } from "./commands/clawhub-wrapper.js";
24
25
  import { promptDeepAgentSelection, promptDeepScanConsent, promptMetaAgentCommandConsent, promptRemediationConsent, promptSkillSelection, } from "./cli-prompts.js";
25
26
  import { resetScanState } from "./layer2-static/state/scan-state.js";
26
27
  const require = createRequire(import.meta.url);
@@ -67,6 +68,51 @@ function mapAcquisitionFailure(status, error) {
67
68
  error: error ?? "tool description acquisition failed",
68
69
  };
69
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
+ }
70
116
  async function promptRunWarningConsent(context) {
71
117
  const rl = createInterface({
72
118
  input: process.stdin,
@@ -157,6 +203,7 @@ const defaultCliDeps = {
157
203
  return fetchResourceMetadata(resource.request);
158
204
  },
159
205
  launchSkills: (args, cwd) => launchSkillsPassthrough(args, cwd),
206
+ launchClawhub: (args, cwd) => launchClawhubPassthrough(args, cwd),
160
207
  };
161
208
  function addScanCommand(program, version, deps) {
162
209
  program
@@ -245,38 +292,28 @@ function addScanCommand(program, version, deps) {
245
292
  prepareScanDiscovery: deps.prepareScanDiscovery,
246
293
  discoverDeepResources: deps.discoverDeepResources,
247
294
  discoverLocalTextTargets: deps.discoverLocalTextTargets,
248
- requestDeepScanConsent: promptCallbacksEnabled
249
- ? (deps.requestDeepScanConsent ??
250
- (interactivePromptsEnabled ? promptDeepScanConsent : undefined))
251
- : undefined,
252
- requestDeepAgentSelection: promptCallbacksEnabled
253
- ? (deps.requestDeepAgentSelection ??
254
- (interactivePromptsEnabled ? promptDeepAgentSelection : undefined))
255
- : undefined,
256
- requestMetaAgentCommandConsent: promptCallbacksEnabled
257
- ? (deps.requestMetaAgentCommandConsent ??
258
- (interactivePromptsEnabled ? promptMetaAgentCommandConsent : undefined))
259
- : undefined,
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
+ }),
260
310
  executeDeepResource: deps.executeDeepResource,
261
- runMetaAgentCommand: deps.runMetaAgentCommand ??
262
- (async (context) => {
263
- const commandResult = await runSandboxCommand({
264
- command: context.command.command,
265
- args: context.command.args,
266
- cwd: context.command.cwd,
267
- timeoutMs: context.command.timeoutMs,
268
- });
269
- return {
270
- command: context.command,
271
- code: commandResult.code,
272
- stdout: commandResult.stdout,
273
- stderr: commandResult.stderr,
274
- };
275
- }),
276
- requestRemediationConsent: promptCallbacksEnabled
277
- ? (deps.requestRemediationConsent ??
278
- (interactivePromptsEnabled ? promptRemediationConsent : undefined))
279
- : undefined,
311
+ runMetaAgentCommand: deps.runMetaAgentCommand ?? runMetaAgentCommandWithSandbox,
312
+ requestRemediationConsent: resolveInteractiveCallback({
313
+ enabled: promptCallbacksEnabled,
314
+ provided: deps.requestRemediationConsent,
315
+ fallback: interactivePromptsEnabled ? promptRemediationConsent : undefined,
316
+ }),
280
317
  runRemediation: deps.runRemediation,
281
318
  stdout: deps.stdout,
282
319
  stderr: deps.stderr,
@@ -376,6 +413,7 @@ function addSkillsCommand(program, version, deps) {
376
413
  .addHelpText("after", renderExampleHelp([
377
414
  "codegate skills add vercel-labs/skills --skill find-skills",
378
415
  "codegate skills add https://github.com/owner/repo --skill security-review",
416
+ "codegate skills add owner/repo --skill demo --cg-deep",
379
417
  "codegate skills find security",
380
418
  "codegate skills add owner/repo --skill demo --cg-force",
381
419
  ]))
@@ -388,6 +426,7 @@ function addSkillsCommand(program, version, deps) {
388
426
  pathExists: deps.pathExists,
389
427
  resolveConfig: deps.resolveConfig,
390
428
  runScan: deps.runScan,
429
+ ...buildWrapperScanBridgeDeps(deps),
391
430
  resolveScanTarget: deps.resolveScanTarget,
392
431
  requestSkillSelection: deps.requestSkillSelection,
393
432
  requestWarningProceed: deps.requestRunWarningConsent,
@@ -409,6 +448,49 @@ function addSkillsCommand(program, version, deps) {
409
448
  }
410
449
  });
411
450
  }
451
+ function addClawhubCommand(program, version, deps) {
452
+ program
453
+ .command("clawhub [clawhubArgs...]")
454
+ .description("Wrap npx clawhub with CodeGate preflight scanning for installs")
455
+ .allowUnknownOption(true)
456
+ .allowExcessArguments(true)
457
+ .addHelpText("after", renderExampleHelp([
458
+ "codegate clawhub install security-auditor",
459
+ "codegate clawhub install security-auditor --version 1.0.0",
460
+ "codegate clawhub install security-auditor --cg-deep",
461
+ "codegate clawhub search security",
462
+ "codegate clawhub install security-auditor --cg-force",
463
+ ]))
464
+ .action(async (clawhubArgs) => {
465
+ try {
466
+ const runClawhubWrapper = deps.runClawhubWrapper ??
467
+ ((input) => executeClawhubWrapper(input, {
468
+ cwd: deps.cwd,
469
+ isTTY: deps.isTTY,
470
+ pathExists: deps.pathExists,
471
+ resolveConfig: deps.resolveConfig,
472
+ runScan: deps.runScan,
473
+ ...buildWrapperScanBridgeDeps(deps),
474
+ resolveScanTarget: deps.resolveScanTarget,
475
+ requestWarningProceed: deps.requestRunWarningConsent,
476
+ launchClawhub: deps.launchClawhub ?? ((args, cwd) => launchClawhubPassthrough(args, cwd)),
477
+ stdout: deps.stdout,
478
+ stderr: deps.stderr,
479
+ setExitCode: deps.setExitCode,
480
+ renderTui: deps.renderTui,
481
+ }));
482
+ await runClawhubWrapper({
483
+ version,
484
+ clawhubArgs: clawhubArgs ?? [],
485
+ });
486
+ }
487
+ catch (error) {
488
+ const message = error instanceof Error ? error.message : String(error);
489
+ deps.stderr(`ClawHub wrapper failed: ${message}`);
490
+ deps.setExitCode(3);
491
+ }
492
+ });
493
+ }
412
494
  function addUndoCommand(program, deps) {
413
495
  program
414
496
  .command("undo [dir]")
@@ -513,10 +595,12 @@ export function createCli(version = packageJson.version ?? "0.0.0-dev", deps = d
513
595
  "codegate scan https://github.com/owner/repo",
514
596
  "codegate scan https://github.com/owner/repo/blob/main/skills/security-review/SKILL.md",
515
597
  "codegate skills add owner/repo --skill security-review",
598
+ "codegate clawhub install security-auditor",
516
599
  "codegate run claude",
517
600
  ]));
518
601
  addScanCommand(program, version, deps);
519
602
  addSkillsCommand(program, version, deps);
603
+ addClawhubCommand(program, version, deps);
520
604
  addRunCommand(program, version, deps);
521
605
  addUndoCommand(program, deps);
522
606
  addInitCommand(program, deps);
@@ -0,0 +1,76 @@
1
+ import { type CodeGateConfig, type OutputFormat, type ResolveConfigOptions } from "../config.js";
2
+ import { type ResolvedScanTarget } from "../scan-target.js";
3
+ import type { CodeGateReport } from "../types/report.js";
4
+ import { type ScanAnalysisDeps, type ScanRunnerInput } from "./scan-command.js";
5
+ interface SourceDetectionContext {
6
+ cwd: string;
7
+ pathExists: (path: string) => boolean;
8
+ }
9
+ export interface ClawhubWrapperRuntimeOptions {
10
+ force: boolean;
11
+ deep: boolean;
12
+ noTui: boolean;
13
+ includeUserScope: boolean;
14
+ format?: OutputFormat;
15
+ configPath?: string;
16
+ }
17
+ export interface ParsedClawhubInvocation {
18
+ passthroughArgs: string[];
19
+ wrapper: ClawhubWrapperRuntimeOptions;
20
+ subcommand: string | null;
21
+ sourceTarget: string | null;
22
+ requestedVersion: string | null;
23
+ }
24
+ export interface ClawhubWrapperLaunchResult {
25
+ status: number | null;
26
+ error?: Error;
27
+ }
28
+ export interface ExecuteClawhubWrapperInput {
29
+ version: string;
30
+ clawhubArgs: string[];
31
+ }
32
+ export interface ClawhubWarningConsentContext {
33
+ target: string;
34
+ report: CodeGateReport;
35
+ }
36
+ export interface ClawhubWrapperDeps {
37
+ cwd: () => string;
38
+ isTTY: () => boolean;
39
+ pathExists?: (path: string) => boolean;
40
+ resolveConfig: (options: ResolveConfigOptions) => CodeGateConfig;
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"];
50
+ resolveScanTarget?: (input: {
51
+ rawTarget: string;
52
+ cwd: string;
53
+ preferredSkill?: string;
54
+ interactive?: boolean;
55
+ requestSkillSelection?: (options: string[]) => Promise<string | null> | string | null;
56
+ }) => Promise<ResolvedScanTarget> | ResolvedScanTarget;
57
+ stageClawhubTarget?: (input: {
58
+ sourceTarget: string;
59
+ requestedVersion?: string;
60
+ cwd: string;
61
+ }) => Promise<ResolvedScanTarget> | ResolvedScanTarget;
62
+ requestWarningProceed?: (context: ClawhubWarningConsentContext) => Promise<boolean> | boolean;
63
+ launchClawhub: (args: string[], cwd: string) => ClawhubWrapperLaunchResult;
64
+ stdout: (message: string) => void;
65
+ stderr: (message: string) => void;
66
+ setExitCode: (code: number) => void;
67
+ renderTui?: (props: {
68
+ view: "dashboard" | "summary";
69
+ report: CodeGateReport;
70
+ notices?: string[];
71
+ }) => void;
72
+ }
73
+ export declare function parseClawhubInvocation(rawArgs: string[], context?: SourceDetectionContext): ParsedClawhubInvocation;
74
+ export declare function launchClawhubPassthrough(args: string[], cwd: string): ClawhubWrapperLaunchResult;
75
+ export declare function executeClawhubWrapper(input: ExecuteClawhubWrapperInput, deps: ClawhubWrapperDeps): Promise<void>;
76
+ export {};