@sentry/warden 0.0.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/.agents/skills/find-bugs/SKILL.md +75 -0
- package/.agents/skills/vercel-react-best-practices/AGENTS.md +2934 -0
- package/.agents/skills/vercel-react-best-practices/SKILL.md +136 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/.claude/settings.json +57 -0
- package/.claude/settings.local.json +88 -0
- package/.claude/skills/agent-prompt/SKILL.md +54 -0
- package/.claude/skills/agent-prompt/references/agentic-patterns.md +94 -0
- package/.claude/skills/agent-prompt/references/anti-patterns.md +140 -0
- package/.claude/skills/agent-prompt/references/context-design.md +124 -0
- package/.claude/skills/agent-prompt/references/core-principles.md +75 -0
- package/.claude/skills/agent-prompt/references/model-guidance.md +118 -0
- package/.claude/skills/agent-prompt/references/output-formats.md +98 -0
- package/.claude/skills/agent-prompt/references/skill-structure.md +115 -0
- package/.claude/skills/agent-prompt/references/system-prompts.md +115 -0
- package/.claude/skills/notseer/SKILL.md +131 -0
- package/.claude/skills/skill-writer/SKILL.md +140 -0
- package/.claude/skills/testing-guidelines/SKILL.md +132 -0
- package/.claude/skills/warden-skill/SKILL.md +250 -0
- package/.claude/skills/warden-skill/references/config-schema.md +133 -0
- package/.dex/config.toml +2 -0
- package/.github/workflows/ci.yml +33 -0
- package/.github/workflows/release.yml +54 -0
- package/.github/workflows/warden.yml +40 -0
- package/AGENTS.md +89 -0
- package/CONTRIBUTING.md +60 -0
- package/LICENSE +105 -0
- package/README.md +43 -0
- package/SPEC.md +263 -0
- package/action.yml +87 -0
- package/assets/favicon.png +0 -0
- package/assets/warden-icon-bw.svg +5 -0
- package/assets/warden-icon-purple.png +0 -0
- package/assets/warden-icon-purple.svg +5 -0
- package/docs/.claude/settings.local.json +11 -0
- package/docs/astro.config.mjs +43 -0
- package/docs/package.json +19 -0
- package/docs/pnpm-lock.yaml +4000 -0
- package/docs/public/favicon.svg +5 -0
- package/docs/src/components/Code.astro +141 -0
- package/docs/src/components/PackageManagerTabs.astro +183 -0
- package/docs/src/components/Terminal.astro +212 -0
- package/docs/src/layouts/Base.astro +380 -0
- package/docs/src/pages/cli.astro +167 -0
- package/docs/src/pages/config.astro +394 -0
- package/docs/src/pages/guide.astro +449 -0
- package/docs/src/pages/index.astro +490 -0
- package/docs/src/styles/global.css +551 -0
- package/docs/tsconfig.json +3 -0
- package/docs/vercel.json +5 -0
- package/eslint.config.js +33 -0
- package/package.json +73 -0
- package/src/action/index.ts +1 -0
- package/src/action/main.ts +868 -0
- package/src/cli/args.test.ts +477 -0
- package/src/cli/args.ts +415 -0
- package/src/cli/commands/add.ts +447 -0
- package/src/cli/commands/init.test.ts +136 -0
- package/src/cli/commands/init.ts +132 -0
- package/src/cli/commands/setup-app/browser.ts +38 -0
- package/src/cli/commands/setup-app/credentials.ts +45 -0
- package/src/cli/commands/setup-app/manifest.ts +48 -0
- package/src/cli/commands/setup-app/server.ts +172 -0
- package/src/cli/commands/setup-app.ts +156 -0
- package/src/cli/commands/sync.ts +114 -0
- package/src/cli/context.ts +131 -0
- package/src/cli/files.test.ts +155 -0
- package/src/cli/files.ts +89 -0
- package/src/cli/fix.test.ts +310 -0
- package/src/cli/fix.ts +387 -0
- package/src/cli/git.test.ts +119 -0
- package/src/cli/git.ts +318 -0
- package/src/cli/index.ts +14 -0
- package/src/cli/main.ts +672 -0
- package/src/cli/output/box.ts +235 -0
- package/src/cli/output/formatters.test.ts +187 -0
- package/src/cli/output/formatters.ts +269 -0
- package/src/cli/output/icons.ts +13 -0
- package/src/cli/output/index.ts +44 -0
- package/src/cli/output/ink-runner.tsx +337 -0
- package/src/cli/output/jsonl.test.ts +347 -0
- package/src/cli/output/jsonl.ts +126 -0
- package/src/cli/output/reporter.ts +435 -0
- package/src/cli/output/tasks.ts +374 -0
- package/src/cli/output/tty.test.ts +117 -0
- package/src/cli/output/tty.ts +60 -0
- package/src/cli/output/verbosity.test.ts +40 -0
- package/src/cli/output/verbosity.ts +31 -0
- package/src/cli/terminal.test.ts +148 -0
- package/src/cli/terminal.ts +301 -0
- package/src/config/index.ts +3 -0
- package/src/config/loader.test.ts +313 -0
- package/src/config/loader.ts +103 -0
- package/src/config/schema.ts +168 -0
- package/src/config/writer.test.ts +119 -0
- package/src/config/writer.ts +84 -0
- package/src/diff/classify.test.ts +162 -0
- package/src/diff/classify.ts +92 -0
- package/src/diff/coalesce.test.ts +208 -0
- package/src/diff/coalesce.ts +133 -0
- package/src/diff/context.test.ts +226 -0
- package/src/diff/context.ts +201 -0
- package/src/diff/index.ts +4 -0
- package/src/diff/parser.test.ts +212 -0
- package/src/diff/parser.ts +149 -0
- package/src/event/context.ts +132 -0
- package/src/event/index.ts +2 -0
- package/src/event/schedule-context.ts +101 -0
- package/src/examples/examples.integration.test.ts +66 -0
- package/src/examples/index.test.ts +101 -0
- package/src/examples/index.ts +122 -0
- package/src/examples/setup.ts +25 -0
- package/src/index.ts +115 -0
- package/src/output/dedup.test.ts +419 -0
- package/src/output/dedup.ts +607 -0
- package/src/output/github-checks.test.ts +300 -0
- package/src/output/github-checks.ts +476 -0
- package/src/output/github-issues.ts +329 -0
- package/src/output/index.ts +5 -0
- package/src/output/issue-renderer.ts +197 -0
- package/src/output/renderer.test.ts +727 -0
- package/src/output/renderer.ts +217 -0
- package/src/output/stale.test.ts +375 -0
- package/src/output/stale.ts +155 -0
- package/src/output/types.ts +34 -0
- package/src/sdk/index.ts +1 -0
- package/src/sdk/runner.test.ts +806 -0
- package/src/sdk/runner.ts +1232 -0
- package/src/skills/index.ts +36 -0
- package/src/skills/loader.test.ts +300 -0
- package/src/skills/loader.ts +423 -0
- package/src/skills/remote.test.ts +704 -0
- package/src/skills/remote.ts +604 -0
- package/src/triggers/matcher.test.ts +277 -0
- package/src/triggers/matcher.ts +152 -0
- package/src/types/index.ts +194 -0
- package/src/utils/async.ts +18 -0
- package/src/utils/index.test.ts +84 -0
- package/src/utils/index.ts +50 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +8 -0
- package/vitest.integration.config.ts +11 -0
- package/warden.toml +19 -0
package/src/cli/args.ts
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { SeverityThresholdSchema } from '../types/index.js';
|
|
5
|
+
import type { SeverityThreshold } from '../types/index.js';
|
|
6
|
+
|
|
7
|
+
export const CLIOptionsSchema = z.object({
|
|
8
|
+
targets: z.array(z.string()).optional(),
|
|
9
|
+
skill: z.string().optional(),
|
|
10
|
+
config: z.string().optional(),
|
|
11
|
+
json: z.boolean().default(false),
|
|
12
|
+
/** Write full run output to a JSONL file */
|
|
13
|
+
output: z.string().optional(),
|
|
14
|
+
failOn: SeverityThresholdSchema.optional(),
|
|
15
|
+
/** Only show findings at or above this severity in output */
|
|
16
|
+
commentOn: SeverityThresholdSchema.optional(),
|
|
17
|
+
help: z.boolean().default(false),
|
|
18
|
+
/** Max concurrent trigger/skill executions (default: 4) */
|
|
19
|
+
parallel: z.number().int().positive().optional(),
|
|
20
|
+
/** Model to use for analysis (fallback when not set in config) */
|
|
21
|
+
model: z.string().optional(),
|
|
22
|
+
// Verbosity options
|
|
23
|
+
quiet: z.boolean().default(false),
|
|
24
|
+
verbose: z.number().default(0),
|
|
25
|
+
color: z.boolean().optional(),
|
|
26
|
+
/** Automatically apply all suggested fixes */
|
|
27
|
+
fix: z.boolean().default(false),
|
|
28
|
+
/** Overwrite existing files (for init command) */
|
|
29
|
+
force: z.boolean().default(false),
|
|
30
|
+
/** List available skills (for add command) */
|
|
31
|
+
list: z.boolean().default(false),
|
|
32
|
+
/** Force interpretation of ambiguous targets as git refs */
|
|
33
|
+
git: z.boolean().default(false),
|
|
34
|
+
/** Remote repository reference for skills (e.g., "owner/repo" or "owner/repo@sha") */
|
|
35
|
+
remote: z.string().optional(),
|
|
36
|
+
/** Skip network operations - only use cached remote skills */
|
|
37
|
+
offline: z.boolean().default(false),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export type CLIOptions = z.infer<typeof CLIOptionsSchema>;
|
|
41
|
+
|
|
42
|
+
export interface SetupAppOptions {
|
|
43
|
+
org?: string;
|
|
44
|
+
port: number;
|
|
45
|
+
timeout: number;
|
|
46
|
+
name?: string;
|
|
47
|
+
open: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ParsedArgs {
|
|
51
|
+
command: 'run' | 'help' | 'init' | 'add' | 'version' | 'setup-app' | 'sync';
|
|
52
|
+
options: CLIOptions;
|
|
53
|
+
setupAppOptions?: SetupAppOptions;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const VERSION = '0.1.0';
|
|
57
|
+
|
|
58
|
+
export function showVersion(): void {
|
|
59
|
+
console.log(`warden ${VERSION}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const HELP_TEXT = `
|
|
63
|
+
Usage: warden [command] [targets...] [options]
|
|
64
|
+
|
|
65
|
+
Analyze code for security issues and code quality.
|
|
66
|
+
|
|
67
|
+
Commands:
|
|
68
|
+
init Initialize warden.toml and GitHub workflow
|
|
69
|
+
add [skill] Add a skill trigger to warden.toml
|
|
70
|
+
sync [remote] Update cached remote skills to latest
|
|
71
|
+
setup-app Create a GitHub App for Warden via manifest flow
|
|
72
|
+
(default) Run analysis on targets or using warden.toml triggers
|
|
73
|
+
|
|
74
|
+
Targets:
|
|
75
|
+
<files> Analyze specific files (e.g., src/auth.ts)
|
|
76
|
+
<glob> Analyze files matching pattern (e.g., "src/**/*.ts")
|
|
77
|
+
<git-ref> Analyze changes from git ref (e.g., HEAD~3, main..feature)
|
|
78
|
+
(none) Analyze uncommitted changes using warden.toml triggers
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
--skill <name> Run only this skill (default: run all built-in skills)
|
|
82
|
+
--config <path> Path to warden.toml (default: ./warden.toml)
|
|
83
|
+
-m, --model <model> Model to use (fallback when not set in config)
|
|
84
|
+
--json Output results as JSON
|
|
85
|
+
-o, --output <path> Write full run output to a JSONL file
|
|
86
|
+
--fail-on <severity> Exit with code 1 if findings >= severity
|
|
87
|
+
(off, critical, high, medium, low, info)
|
|
88
|
+
--comment-on <sev> Only show findings >= severity in output
|
|
89
|
+
(off, critical, high, medium, low, info)
|
|
90
|
+
--fix Automatically apply all suggested fixes
|
|
91
|
+
--parallel <n> Max concurrent trigger/skill executions (default: 4)
|
|
92
|
+
--git Force ambiguous targets to be treated as git refs
|
|
93
|
+
--quiet Errors and final summary only
|
|
94
|
+
-v, --verbose Show real-time findings and hunk details
|
|
95
|
+
-vv Show debug info (token counts, latencies)
|
|
96
|
+
--color / --no-color Override color detection
|
|
97
|
+
--help, -h Show this help message
|
|
98
|
+
--version, -V Show version number
|
|
99
|
+
|
|
100
|
+
Init Options:
|
|
101
|
+
-f, --force Overwrite existing files
|
|
102
|
+
|
|
103
|
+
Add Options:
|
|
104
|
+
--list List available skills
|
|
105
|
+
--remote <ref> Remote repository (owner/repo, URL, or with @sha)
|
|
106
|
+
|
|
107
|
+
Run Options:
|
|
108
|
+
--offline Use cached remote skills without network access
|
|
109
|
+
|
|
110
|
+
Setup-app Options:
|
|
111
|
+
--org <name> Create under organization (default: personal)
|
|
112
|
+
--port <number> Local server port (default: 3000)
|
|
113
|
+
--timeout <sec> Callback timeout in seconds (default: 300)
|
|
114
|
+
--name <string> Custom app name (default: Warden)
|
|
115
|
+
--no-open Print URL instead of opening browser
|
|
116
|
+
|
|
117
|
+
Examples:
|
|
118
|
+
warden init # Initialize warden configuration
|
|
119
|
+
warden add # Interactive skill selection
|
|
120
|
+
warden add security-review # Add specific skill trigger
|
|
121
|
+
warden add --list # List available skills
|
|
122
|
+
warden add --remote getsentry/skills --skill security-review
|
|
123
|
+
# Add remote skill trigger
|
|
124
|
+
warden add --remote https://github.com/getsentry/skills --skill security-review
|
|
125
|
+
# Add remote skill via URL
|
|
126
|
+
warden add --remote getsentry/skills@abc123 --skill security-review
|
|
127
|
+
# Add pinned remote skill
|
|
128
|
+
warden # Run triggers from warden.toml
|
|
129
|
+
warden src/auth.ts # Run all skills on file
|
|
130
|
+
warden src/auth.ts --skill security-review
|
|
131
|
+
# Run specific skill on file
|
|
132
|
+
warden "src/**/*.ts" # Run all skills on glob pattern
|
|
133
|
+
warden HEAD~3 # Run all skills on git changes
|
|
134
|
+
warden HEAD~3 --skill security-review # Run specific skill on git changes
|
|
135
|
+
warden --json # Output as JSON
|
|
136
|
+
warden --fail-on high # Fail if high+ severity findings
|
|
137
|
+
warden --offline # Use cached skills only
|
|
138
|
+
warden sync # Update all unpinned remote skills
|
|
139
|
+
warden setup-app # Create GitHub App interactively
|
|
140
|
+
warden setup-app --org myorg # Create app under organization
|
|
141
|
+
`;
|
|
142
|
+
|
|
143
|
+
export function showHelp(): void {
|
|
144
|
+
console.log(HELP_TEXT.trim());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface DetectTargetTypeOptions {
|
|
148
|
+
/** Current working directory for filesystem checks */
|
|
149
|
+
cwd?: string;
|
|
150
|
+
/** Force git ref interpretation for ambiguous targets */
|
|
151
|
+
forceGit?: boolean;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Detect if a target looks like a git ref vs a file path.
|
|
156
|
+
* Returns 'git' for git refs, 'file' for file paths.
|
|
157
|
+
*
|
|
158
|
+
* For ambiguous targets (no path separators, no extension), checks
|
|
159
|
+
* if a file/directory exists at that path before defaulting to git ref.
|
|
160
|
+
*/
|
|
161
|
+
export function detectTargetType(target: string, options: DetectTargetTypeOptions = {}): 'git' | 'file' {
|
|
162
|
+
const { cwd = process.cwd(), forceGit = false } = options;
|
|
163
|
+
|
|
164
|
+
// Git range syntax (e.g., main..feature, HEAD~3..HEAD)
|
|
165
|
+
if (target.includes('..')) {
|
|
166
|
+
return 'git';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Relative ref syntax (e.g., HEAD~3, main^2)
|
|
170
|
+
if (/[~^]\d*$/.test(target)) {
|
|
171
|
+
return 'git';
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Common git refs
|
|
175
|
+
if (/^(HEAD|FETCH_HEAD|ORIG_HEAD|MERGE_HEAD)$/i.test(target)) {
|
|
176
|
+
return 'git';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Contains path separators or glob characters → file
|
|
180
|
+
if (target.includes('/') || target.includes('*') || target.includes('?')) {
|
|
181
|
+
return 'file';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Has a file extension → file
|
|
185
|
+
if (/\.\w+$/.test(target)) {
|
|
186
|
+
return 'file';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Ambiguous target (no path separators, no extension)
|
|
190
|
+
// If --git flag is set, force git ref interpretation
|
|
191
|
+
if (forceGit) {
|
|
192
|
+
return 'git';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Check if file/directory exists at this path
|
|
196
|
+
const fullPath = `${cwd}/${target}`;
|
|
197
|
+
if (existsSync(fullPath)) {
|
|
198
|
+
return 'file';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Default to git ref (will be validated later)
|
|
202
|
+
return 'git';
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Classify targets into git refs and file patterns.
|
|
207
|
+
*/
|
|
208
|
+
export function classifyTargets(targets: string[], options: DetectTargetTypeOptions = {}): { gitRefs: string[]; filePatterns: string[] } {
|
|
209
|
+
const gitRefs: string[] = [];
|
|
210
|
+
const filePatterns: string[] = [];
|
|
211
|
+
|
|
212
|
+
for (const target of targets) {
|
|
213
|
+
if (detectTargetType(target, options) === 'git') {
|
|
214
|
+
gitRefs.push(target);
|
|
215
|
+
} else {
|
|
216
|
+
filePatterns.push(target);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return { gitRefs, filePatterns };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolve color option from --color / --no-color flags.
|
|
225
|
+
* Returns undefined for auto-detect, true for forced color, false for no color.
|
|
226
|
+
*/
|
|
227
|
+
function resolveColorOption(values: { color?: boolean; 'no-color'?: boolean }): boolean | undefined {
|
|
228
|
+
if (values['no-color']) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
if (values.color) {
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function parseCliArgs(argv: string[] = process.argv.slice(2)): ParsedArgs {
|
|
238
|
+
// Count -v flags before parsing (parseArgs doesn't handle multiple -v well)
|
|
239
|
+
let verboseCount = 0;
|
|
240
|
+
const filteredArgv = argv.filter((arg) => {
|
|
241
|
+
if (arg === '-v' || arg === '--verbose') {
|
|
242
|
+
verboseCount++;
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
if (arg === '-vv') {
|
|
246
|
+
verboseCount += 2;
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const { values, positionals } = parseArgs({
|
|
253
|
+
args: filteredArgv,
|
|
254
|
+
options: {
|
|
255
|
+
skill: { type: 'string' },
|
|
256
|
+
config: { type: 'string' },
|
|
257
|
+
model: { type: 'string', short: 'm' },
|
|
258
|
+
json: { type: 'boolean', default: false },
|
|
259
|
+
output: { type: 'string', short: 'o' },
|
|
260
|
+
'fail-on': { type: 'string' },
|
|
261
|
+
'comment-on': { type: 'string' },
|
|
262
|
+
fix: { type: 'boolean', default: false },
|
|
263
|
+
force: { type: 'boolean', short: 'f', default: false },
|
|
264
|
+
list: { type: 'boolean', short: 'l', default: false },
|
|
265
|
+
remote: { type: 'string' },
|
|
266
|
+
offline: { type: 'boolean', default: false },
|
|
267
|
+
parallel: { type: 'string' },
|
|
268
|
+
git: { type: 'boolean', default: false },
|
|
269
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
270
|
+
version: { type: 'boolean', short: 'V', default: false },
|
|
271
|
+
quiet: { type: 'boolean', default: false },
|
|
272
|
+
color: { type: 'boolean' },
|
|
273
|
+
'no-color': { type: 'boolean' },
|
|
274
|
+
// setup-app options
|
|
275
|
+
org: { type: 'string' },
|
|
276
|
+
port: { type: 'string' },
|
|
277
|
+
timeout: { type: 'string' },
|
|
278
|
+
name: { type: 'string' },
|
|
279
|
+
open: { type: 'boolean', default: true },
|
|
280
|
+
'no-open': { type: 'boolean' },
|
|
281
|
+
},
|
|
282
|
+
allowPositionals: true,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
if (values.version) {
|
|
286
|
+
return {
|
|
287
|
+
command: 'version',
|
|
288
|
+
options: CLIOptionsSchema.parse({}),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (values.help) {
|
|
293
|
+
return {
|
|
294
|
+
command: 'help',
|
|
295
|
+
options: CLIOptionsSchema.parse({ help: true }),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Filter out known commands from positionals
|
|
300
|
+
const commands = ['run', 'help', 'init', 'add', 'version', 'setup-app', 'sync'];
|
|
301
|
+
const targets = positionals.filter((p) => !commands.includes(p));
|
|
302
|
+
|
|
303
|
+
// Handle explicit help command
|
|
304
|
+
if (positionals.includes('help')) {
|
|
305
|
+
return {
|
|
306
|
+
command: 'help',
|
|
307
|
+
options: CLIOptionsSchema.parse({ help: true }),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Handle explicit version command
|
|
312
|
+
if (positionals.includes('version')) {
|
|
313
|
+
return {
|
|
314
|
+
command: 'version',
|
|
315
|
+
options: CLIOptionsSchema.parse({}),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Handle init command
|
|
320
|
+
if (positionals.includes('init')) {
|
|
321
|
+
return {
|
|
322
|
+
command: 'init',
|
|
323
|
+
options: CLIOptionsSchema.parse({
|
|
324
|
+
force: values.force,
|
|
325
|
+
quiet: values.quiet,
|
|
326
|
+
color: resolveColorOption(values),
|
|
327
|
+
}),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Handle add command
|
|
332
|
+
if (positionals.includes('add')) {
|
|
333
|
+
// First positional after 'add' is the skill name
|
|
334
|
+
const addIndex = positionals.indexOf('add');
|
|
335
|
+
const skillArg = positionals[addIndex + 1];
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
command: 'add',
|
|
339
|
+
options: CLIOptionsSchema.parse({
|
|
340
|
+
skill: values.skill ?? skillArg,
|
|
341
|
+
list: values.list,
|
|
342
|
+
remote: values.remote,
|
|
343
|
+
quiet: values.quiet,
|
|
344
|
+
color: resolveColorOption(values),
|
|
345
|
+
}),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Handle sync command
|
|
350
|
+
if (positionals.includes('sync')) {
|
|
351
|
+
// First positional after 'sync' is the remote to sync, --remote flag takes precedence
|
|
352
|
+
const syncIndex = positionals.indexOf('sync');
|
|
353
|
+
const remoteArg = values.remote ?? positionals[syncIndex + 1];
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
command: 'sync',
|
|
357
|
+
options: CLIOptionsSchema.parse({
|
|
358
|
+
remote: remoteArg,
|
|
359
|
+
quiet: values.quiet,
|
|
360
|
+
color: resolveColorOption(values),
|
|
361
|
+
}),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Handle setup-app command
|
|
366
|
+
if (positionals.includes('setup-app')) {
|
|
367
|
+
return {
|
|
368
|
+
command: 'setup-app',
|
|
369
|
+
options: CLIOptionsSchema.parse({
|
|
370
|
+
quiet: values.quiet,
|
|
371
|
+
color: resolveColorOption(values),
|
|
372
|
+
}),
|
|
373
|
+
setupAppOptions: {
|
|
374
|
+
org: values.org as string | undefined,
|
|
375
|
+
port: values.port ? parseInt(values.port as string, 10) : 3000,
|
|
376
|
+
timeout: values.timeout ? parseInt(values.timeout as string, 10) : 300,
|
|
377
|
+
name: values.name as string | undefined,
|
|
378
|
+
open: !values['no-open'],
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const rawOptions = {
|
|
384
|
+
targets: targets.length > 0 ? targets : undefined,
|
|
385
|
+
skill: values.skill,
|
|
386
|
+
config: values.config,
|
|
387
|
+
model: values.model,
|
|
388
|
+
json: values.json,
|
|
389
|
+
output: values.output,
|
|
390
|
+
failOn: values['fail-on'] as SeverityThreshold | undefined,
|
|
391
|
+
commentOn: values['comment-on'] as SeverityThreshold | undefined,
|
|
392
|
+
fix: values.fix,
|
|
393
|
+
force: values.force,
|
|
394
|
+
parallel: values.parallel ? parseInt(values.parallel, 10) : undefined,
|
|
395
|
+
git: values.git,
|
|
396
|
+
offline: values.offline,
|
|
397
|
+
help: values.help,
|
|
398
|
+
quiet: values.quiet,
|
|
399
|
+
verbose: verboseCount,
|
|
400
|
+
color: resolveColorOption(values),
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
const result = CLIOptionsSchema.safeParse(rawOptions);
|
|
404
|
+
if (!result.success) {
|
|
405
|
+
const issues = result.error.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`);
|
|
406
|
+
console.error('Invalid options:');
|
|
407
|
+
console.error(issues.join('\n'));
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
command: 'run',
|
|
413
|
+
options: result.data,
|
|
414
|
+
};
|
|
415
|
+
}
|