@hasna/terminal 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +64 -16
- package/package.json +1 -1
- package/src/ai.ts +8 -0
- package/src/cli.tsx +57 -18
- package/src/output-processor.ts +6 -1
- package/src/output-store.ts +58 -12
- package/src/tool-profiles.ts +139 -0
- package/temp/rtk/.claude/agents/code-reviewer.md +0 -221
- package/temp/rtk/.claude/agents/debugger.md +0 -519
- package/temp/rtk/.claude/agents/rtk-testing-specialist.md +0 -461
- package/temp/rtk/.claude/agents/rust-rtk.md +0 -511
- package/temp/rtk/.claude/agents/technical-writer.md +0 -355
- package/temp/rtk/.claude/commands/diagnose.md +0 -352
- package/temp/rtk/.claude/commands/test-routing.md +0 -362
- package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +0 -16
- package/temp/rtk/.claude/hooks/rtk-rewrite.sh +0 -70
- package/temp/rtk/.claude/hooks/rtk-suggest.sh +0 -152
- package/temp/rtk/.claude/rules/cli-testing.md +0 -526
- package/temp/rtk/.claude/skills/issue-triage/SKILL.md +0 -348
- package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +0 -134
- package/temp/rtk/.claude/skills/performance.md +0 -435
- package/temp/rtk/.claude/skills/pr-triage/SKILL.md +0 -315
- package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +0 -71
- package/temp/rtk/.claude/skills/repo-recap.md +0 -206
- package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +0 -78
- package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +0 -124
- package/temp/rtk/.claude/skills/security-guardian.md +0 -503
- package/temp/rtk/.claude/skills/ship.md +0 -404
- package/temp/rtk/.github/workflows/benchmark.yml +0 -34
- package/temp/rtk/.github/workflows/dco-check.yaml +0 -12
- package/temp/rtk/.github/workflows/release-please.yml +0 -51
- package/temp/rtk/.github/workflows/release.yml +0 -343
- package/temp/rtk/.github/workflows/security-check.yml +0 -135
- package/temp/rtk/.github/workflows/validate-docs.yml +0 -78
- package/temp/rtk/.release-please-manifest.json +0 -3
- package/temp/rtk/ARCHITECTURE.md +0 -1491
- package/temp/rtk/CHANGELOG.md +0 -640
- package/temp/rtk/CLAUDE.md +0 -605
- package/temp/rtk/CONTRIBUTING.md +0 -199
- package/temp/rtk/Cargo.lock +0 -1668
- package/temp/rtk/Cargo.toml +0 -64
- package/temp/rtk/Formula/rtk.rb +0 -43
- package/temp/rtk/INSTALL.md +0 -390
- package/temp/rtk/LICENSE +0 -21
- package/temp/rtk/README.md +0 -386
- package/temp/rtk/README_es.md +0 -159
- package/temp/rtk/README_fr.md +0 -197
- package/temp/rtk/README_ja.md +0 -159
- package/temp/rtk/README_ko.md +0 -159
- package/temp/rtk/README_zh.md +0 -167
- package/temp/rtk/ROADMAP.md +0 -15
- package/temp/rtk/SECURITY.md +0 -217
- package/temp/rtk/TEST_EXEC_TIME.md +0 -102
- package/temp/rtk/build.rs +0 -57
- package/temp/rtk/docs/AUDIT_GUIDE.md +0 -432
- package/temp/rtk/docs/FEATURES.md +0 -1410
- package/temp/rtk/docs/TROUBLESHOOTING.md +0 -309
- package/temp/rtk/docs/filter-workflow.md +0 -102
- package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
- package/temp/rtk/docs/tracking.md +0 -583
- package/temp/rtk/hooks/opencode-rtk.ts +0 -39
- package/temp/rtk/hooks/rtk-awareness.md +0 -29
- package/temp/rtk/hooks/rtk-rewrite.sh +0 -61
- package/temp/rtk/hooks/test-rtk-rewrite.sh +0 -442
- package/temp/rtk/install.sh +0 -124
- package/temp/rtk/release-please-config.json +0 -10
- package/temp/rtk/scripts/benchmark.sh +0 -592
- package/temp/rtk/scripts/check-installation.sh +0 -162
- package/temp/rtk/scripts/install-local.sh +0 -37
- package/temp/rtk/scripts/rtk-economics.sh +0 -137
- package/temp/rtk/scripts/test-all.sh +0 -561
- package/temp/rtk/scripts/test-aristote.sh +0 -227
- package/temp/rtk/scripts/test-tracking.sh +0 -79
- package/temp/rtk/scripts/update-readme-metrics.sh +0 -32
- package/temp/rtk/scripts/validate-docs.sh +0 -73
- package/temp/rtk/src/aws_cmd.rs +0 -880
- package/temp/rtk/src/binlog.rs +0 -1645
- package/temp/rtk/src/cargo_cmd.rs +0 -1727
- package/temp/rtk/src/cc_economics.rs +0 -1157
- package/temp/rtk/src/ccusage.rs +0 -340
- package/temp/rtk/src/config.rs +0 -187
- package/temp/rtk/src/container.rs +0 -855
- package/temp/rtk/src/curl_cmd.rs +0 -134
- package/temp/rtk/src/deps.rs +0 -268
- package/temp/rtk/src/diff_cmd.rs +0 -367
- package/temp/rtk/src/discover/mod.rs +0 -274
- package/temp/rtk/src/discover/provider.rs +0 -388
- package/temp/rtk/src/discover/registry.rs +0 -2022
- package/temp/rtk/src/discover/report.rs +0 -202
- package/temp/rtk/src/discover/rules.rs +0 -667
- package/temp/rtk/src/display_helpers.rs +0 -402
- package/temp/rtk/src/dotnet_cmd.rs +0 -1771
- package/temp/rtk/src/dotnet_format_report.rs +0 -133
- package/temp/rtk/src/dotnet_trx.rs +0 -593
- package/temp/rtk/src/env_cmd.rs +0 -204
- package/temp/rtk/src/filter.rs +0 -462
- package/temp/rtk/src/filters/README.md +0 -52
- package/temp/rtk/src/filters/ansible-playbook.toml +0 -34
- package/temp/rtk/src/filters/basedpyright.toml +0 -47
- package/temp/rtk/src/filters/biome.toml +0 -45
- package/temp/rtk/src/filters/brew-install.toml +0 -37
- package/temp/rtk/src/filters/composer-install.toml +0 -40
- package/temp/rtk/src/filters/df.toml +0 -16
- package/temp/rtk/src/filters/dotnet-build.toml +0 -64
- package/temp/rtk/src/filters/du.toml +0 -16
- package/temp/rtk/src/filters/fail2ban-client.toml +0 -15
- package/temp/rtk/src/filters/gcc.toml +0 -49
- package/temp/rtk/src/filters/gcloud.toml +0 -22
- package/temp/rtk/src/filters/hadolint.toml +0 -24
- package/temp/rtk/src/filters/helm.toml +0 -29
- package/temp/rtk/src/filters/iptables.toml +0 -27
- package/temp/rtk/src/filters/jj.toml +0 -28
- package/temp/rtk/src/filters/jq.toml +0 -24
- package/temp/rtk/src/filters/make.toml +0 -41
- package/temp/rtk/src/filters/markdownlint.toml +0 -24
- package/temp/rtk/src/filters/mix-compile.toml +0 -27
- package/temp/rtk/src/filters/mix-format.toml +0 -15
- package/temp/rtk/src/filters/mvn-build.toml +0 -44
- package/temp/rtk/src/filters/oxlint.toml +0 -43
- package/temp/rtk/src/filters/ping.toml +0 -63
- package/temp/rtk/src/filters/pio-run.toml +0 -40
- package/temp/rtk/src/filters/poetry-install.toml +0 -50
- package/temp/rtk/src/filters/pre-commit.toml +0 -35
- package/temp/rtk/src/filters/ps.toml +0 -16
- package/temp/rtk/src/filters/quarto-render.toml +0 -41
- package/temp/rtk/src/filters/rsync.toml +0 -48
- package/temp/rtk/src/filters/shellcheck.toml +0 -27
- package/temp/rtk/src/filters/shopify-theme.toml +0 -29
- package/temp/rtk/src/filters/skopeo.toml +0 -45
- package/temp/rtk/src/filters/sops.toml +0 -16
- package/temp/rtk/src/filters/ssh.toml +0 -44
- package/temp/rtk/src/filters/stat.toml +0 -34
- package/temp/rtk/src/filters/swift-build.toml +0 -41
- package/temp/rtk/src/filters/systemctl-status.toml +0 -33
- package/temp/rtk/src/filters/terraform-plan.toml +0 -35
- package/temp/rtk/src/filters/tofu-fmt.toml +0 -16
- package/temp/rtk/src/filters/tofu-init.toml +0 -38
- package/temp/rtk/src/filters/tofu-plan.toml +0 -35
- package/temp/rtk/src/filters/tofu-validate.toml +0 -17
- package/temp/rtk/src/filters/trunk-build.toml +0 -39
- package/temp/rtk/src/filters/ty.toml +0 -50
- package/temp/rtk/src/filters/uv-sync.toml +0 -37
- package/temp/rtk/src/filters/xcodebuild.toml +0 -99
- package/temp/rtk/src/filters/yamllint.toml +0 -25
- package/temp/rtk/src/find_cmd.rs +0 -598
- package/temp/rtk/src/format_cmd.rs +0 -386
- package/temp/rtk/src/gain.rs +0 -723
- package/temp/rtk/src/gh_cmd.rs +0 -1651
- package/temp/rtk/src/git.rs +0 -2012
- package/temp/rtk/src/go_cmd.rs +0 -592
- package/temp/rtk/src/golangci_cmd.rs +0 -254
- package/temp/rtk/src/grep_cmd.rs +0 -288
- package/temp/rtk/src/gt_cmd.rs +0 -810
- package/temp/rtk/src/hook_audit_cmd.rs +0 -283
- package/temp/rtk/src/hook_check.rs +0 -171
- package/temp/rtk/src/init.rs +0 -1859
- package/temp/rtk/src/integrity.rs +0 -537
- package/temp/rtk/src/json_cmd.rs +0 -231
- package/temp/rtk/src/learn/detector.rs +0 -628
- package/temp/rtk/src/learn/mod.rs +0 -119
- package/temp/rtk/src/learn/report.rs +0 -184
- package/temp/rtk/src/lint_cmd.rs +0 -694
- package/temp/rtk/src/local_llm.rs +0 -316
- package/temp/rtk/src/log_cmd.rs +0 -248
- package/temp/rtk/src/ls.rs +0 -324
- package/temp/rtk/src/main.rs +0 -2482
- package/temp/rtk/src/mypy_cmd.rs +0 -389
- package/temp/rtk/src/next_cmd.rs +0 -241
- package/temp/rtk/src/npm_cmd.rs +0 -236
- package/temp/rtk/src/parser/README.md +0 -267
- package/temp/rtk/src/parser/error.rs +0 -46
- package/temp/rtk/src/parser/formatter.rs +0 -336
- package/temp/rtk/src/parser/mod.rs +0 -311
- package/temp/rtk/src/parser/types.rs +0 -119
- package/temp/rtk/src/pip_cmd.rs +0 -302
- package/temp/rtk/src/playwright_cmd.rs +0 -479
- package/temp/rtk/src/pnpm_cmd.rs +0 -573
- package/temp/rtk/src/prettier_cmd.rs +0 -221
- package/temp/rtk/src/prisma_cmd.rs +0 -482
- package/temp/rtk/src/psql_cmd.rs +0 -382
- package/temp/rtk/src/pytest_cmd.rs +0 -384
- package/temp/rtk/src/read.rs +0 -217
- package/temp/rtk/src/rewrite_cmd.rs +0 -50
- package/temp/rtk/src/ruff_cmd.rs +0 -402
- package/temp/rtk/src/runner.rs +0 -271
- package/temp/rtk/src/summary.rs +0 -297
- package/temp/rtk/src/tee.rs +0 -405
- package/temp/rtk/src/telemetry.rs +0 -248
- package/temp/rtk/src/toml_filter.rs +0 -1655
- package/temp/rtk/src/tracking.rs +0 -1416
- package/temp/rtk/src/tree.rs +0 -209
- package/temp/rtk/src/tsc_cmd.rs +0 -259
- package/temp/rtk/src/utils.rs +0 -432
- package/temp/rtk/src/verify_cmd.rs +0 -47
- package/temp/rtk/src/vitest_cmd.rs +0 -385
- package/temp/rtk/src/wc_cmd.rs +0 -401
- package/temp/rtk/src/wget_cmd.rs +0 -260
- package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +0 -11
- package/temp/rtk/tests/fixtures/dotnet/format_changes.json +0 -31
- package/temp/rtk/tests/fixtures/dotnet/format_empty.json +0 -1
- package/temp/rtk/tests/fixtures/dotnet/format_success.json +0 -12
- package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +0 -18
package/temp/rtk/src/main.rs
DELETED
|
@@ -1,2482 +0,0 @@
|
|
|
1
|
-
mod aws_cmd;
|
|
2
|
-
mod binlog;
|
|
3
|
-
mod cargo_cmd;
|
|
4
|
-
mod cc_economics;
|
|
5
|
-
mod ccusage;
|
|
6
|
-
mod config;
|
|
7
|
-
mod container;
|
|
8
|
-
mod curl_cmd;
|
|
9
|
-
mod deps;
|
|
10
|
-
mod diff_cmd;
|
|
11
|
-
mod discover;
|
|
12
|
-
mod display_helpers;
|
|
13
|
-
mod dotnet_cmd;
|
|
14
|
-
mod dotnet_format_report;
|
|
15
|
-
mod dotnet_trx;
|
|
16
|
-
mod env_cmd;
|
|
17
|
-
mod filter;
|
|
18
|
-
mod find_cmd;
|
|
19
|
-
mod format_cmd;
|
|
20
|
-
mod gain;
|
|
21
|
-
mod gh_cmd;
|
|
22
|
-
mod git;
|
|
23
|
-
mod go_cmd;
|
|
24
|
-
mod golangci_cmd;
|
|
25
|
-
mod grep_cmd;
|
|
26
|
-
mod gt_cmd;
|
|
27
|
-
mod hook_audit_cmd;
|
|
28
|
-
mod hook_check;
|
|
29
|
-
mod init;
|
|
30
|
-
mod integrity;
|
|
31
|
-
mod json_cmd;
|
|
32
|
-
mod learn;
|
|
33
|
-
mod lint_cmd;
|
|
34
|
-
mod local_llm;
|
|
35
|
-
mod log_cmd;
|
|
36
|
-
mod ls;
|
|
37
|
-
mod mypy_cmd;
|
|
38
|
-
mod next_cmd;
|
|
39
|
-
mod npm_cmd;
|
|
40
|
-
mod parser;
|
|
41
|
-
mod pip_cmd;
|
|
42
|
-
mod playwright_cmd;
|
|
43
|
-
mod pnpm_cmd;
|
|
44
|
-
mod prettier_cmd;
|
|
45
|
-
mod prisma_cmd;
|
|
46
|
-
mod psql_cmd;
|
|
47
|
-
mod pytest_cmd;
|
|
48
|
-
mod read;
|
|
49
|
-
mod rewrite_cmd;
|
|
50
|
-
mod ruff_cmd;
|
|
51
|
-
mod runner;
|
|
52
|
-
mod summary;
|
|
53
|
-
mod tee;
|
|
54
|
-
mod telemetry;
|
|
55
|
-
mod toml_filter;
|
|
56
|
-
mod tracking;
|
|
57
|
-
mod tree;
|
|
58
|
-
mod tsc_cmd;
|
|
59
|
-
mod utils;
|
|
60
|
-
mod verify_cmd;
|
|
61
|
-
mod vitest_cmd;
|
|
62
|
-
mod wc_cmd;
|
|
63
|
-
mod wget_cmd;
|
|
64
|
-
|
|
65
|
-
use anyhow::{Context, Result};
|
|
66
|
-
use clap::error::ErrorKind;
|
|
67
|
-
use clap::{Parser, Subcommand};
|
|
68
|
-
use std::ffi::OsString;
|
|
69
|
-
use std::path::{Path, PathBuf};
|
|
70
|
-
|
|
71
|
-
#[derive(Parser)]
|
|
72
|
-
#[command(
|
|
73
|
-
name = "rtk",
|
|
74
|
-
version,
|
|
75
|
-
about = "Rust Token Killer - Minimize LLM token consumption",
|
|
76
|
-
long_about = "A high-performance CLI proxy designed to filter and summarize system outputs before they reach your LLM context."
|
|
77
|
-
)]
|
|
78
|
-
struct Cli {
|
|
79
|
-
#[command(subcommand)]
|
|
80
|
-
command: Commands,
|
|
81
|
-
|
|
82
|
-
/// Verbosity level (-v, -vv, -vvv)
|
|
83
|
-
#[arg(short, long, action = clap::ArgAction::Count, global = true)]
|
|
84
|
-
verbose: u8,
|
|
85
|
-
|
|
86
|
-
/// Ultra-compact mode: ASCII icons, inline format (Level 2 optimizations)
|
|
87
|
-
#[arg(short = 'u', long, global = true)]
|
|
88
|
-
ultra_compact: bool,
|
|
89
|
-
|
|
90
|
-
/// Set SKIP_ENV_VALIDATION=1 for child processes (Next.js, tsc, lint, prisma)
|
|
91
|
-
#[arg(long = "skip-env", global = true)]
|
|
92
|
-
skip_env: bool,
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
#[derive(Subcommand)]
|
|
96
|
-
enum Commands {
|
|
97
|
-
/// List directory contents with token-optimized output (proxy to native ls)
|
|
98
|
-
Ls {
|
|
99
|
-
/// Arguments passed to ls (supports all native ls flags like -l, -a, -h, -R)
|
|
100
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
101
|
-
args: Vec<String>,
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
/// Directory tree with token-optimized output (proxy to native tree)
|
|
105
|
-
Tree {
|
|
106
|
-
/// Arguments passed to tree (supports all native tree flags like -L, -d, -a)
|
|
107
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
108
|
-
args: Vec<String>,
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
/// Read file with intelligent filtering
|
|
112
|
-
Read {
|
|
113
|
-
/// File to read
|
|
114
|
-
file: PathBuf,
|
|
115
|
-
/// Filter: none, minimal, aggressive
|
|
116
|
-
#[arg(short, long, default_value = "minimal")]
|
|
117
|
-
level: filter::FilterLevel,
|
|
118
|
-
/// Max lines
|
|
119
|
-
#[arg(short, long, conflicts_with = "tail_lines")]
|
|
120
|
-
max_lines: Option<usize>,
|
|
121
|
-
/// Keep only last N lines
|
|
122
|
-
#[arg(long, conflicts_with = "max_lines")]
|
|
123
|
-
tail_lines: Option<usize>,
|
|
124
|
-
/// Show line numbers
|
|
125
|
-
#[arg(short = 'n', long)]
|
|
126
|
-
line_numbers: bool,
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
/// Generate 2-line technical summary (heuristic-based)
|
|
130
|
-
Smart {
|
|
131
|
-
/// File to analyze
|
|
132
|
-
file: PathBuf,
|
|
133
|
-
/// Model: heuristic
|
|
134
|
-
#[arg(short, long, default_value = "heuristic")]
|
|
135
|
-
model: String,
|
|
136
|
-
/// Force model download
|
|
137
|
-
#[arg(long)]
|
|
138
|
-
force_download: bool,
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
/// Git commands with compact output
|
|
142
|
-
Git {
|
|
143
|
-
/// Change to directory before executing (like git -C <path>, can be repeated)
|
|
144
|
-
#[arg(short = 'C', action = clap::ArgAction::Append)]
|
|
145
|
-
directory: Vec<String>,
|
|
146
|
-
|
|
147
|
-
/// Git configuration override (like git -c key=value, can be repeated)
|
|
148
|
-
#[arg(short = 'c', action = clap::ArgAction::Append)]
|
|
149
|
-
config_override: Vec<String>,
|
|
150
|
-
|
|
151
|
-
/// Set the path to the .git directory
|
|
152
|
-
#[arg(long = "git-dir")]
|
|
153
|
-
git_dir: Option<String>,
|
|
154
|
-
|
|
155
|
-
/// Set the path to the working tree
|
|
156
|
-
#[arg(long = "work-tree")]
|
|
157
|
-
work_tree: Option<String>,
|
|
158
|
-
|
|
159
|
-
/// Disable pager (like git --no-pager)
|
|
160
|
-
#[arg(long = "no-pager")]
|
|
161
|
-
no_pager: bool,
|
|
162
|
-
|
|
163
|
-
/// Skip optional locks (like git --no-optional-locks)
|
|
164
|
-
#[arg(long = "no-optional-locks")]
|
|
165
|
-
no_optional_locks: bool,
|
|
166
|
-
|
|
167
|
-
/// Treat repository as bare (like git --bare)
|
|
168
|
-
#[arg(long)]
|
|
169
|
-
bare: bool,
|
|
170
|
-
|
|
171
|
-
/// Treat pathspecs literally (like git --literal-pathspecs)
|
|
172
|
-
#[arg(long = "literal-pathspecs")]
|
|
173
|
-
literal_pathspecs: bool,
|
|
174
|
-
|
|
175
|
-
#[command(subcommand)]
|
|
176
|
-
command: GitCommands,
|
|
177
|
-
},
|
|
178
|
-
|
|
179
|
-
/// GitHub CLI (gh) commands with token-optimized output
|
|
180
|
-
Gh {
|
|
181
|
-
/// Subcommand: pr, issue, run, repo
|
|
182
|
-
subcommand: String,
|
|
183
|
-
/// Additional arguments
|
|
184
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
185
|
-
args: Vec<String>,
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
/// AWS CLI with compact output (force JSON, compress)
|
|
189
|
-
Aws {
|
|
190
|
-
/// AWS service subcommand (e.g., sts, s3, ec2, ecs, rds, cloudformation)
|
|
191
|
-
subcommand: String,
|
|
192
|
-
/// Additional arguments
|
|
193
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
194
|
-
args: Vec<String>,
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
/// PostgreSQL client with compact output (strip borders, compress tables)
|
|
198
|
-
Psql {
|
|
199
|
-
/// psql arguments
|
|
200
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
201
|
-
args: Vec<String>,
|
|
202
|
-
},
|
|
203
|
-
|
|
204
|
-
/// pnpm commands with ultra-compact output
|
|
205
|
-
Pnpm {
|
|
206
|
-
#[command(subcommand)]
|
|
207
|
-
command: PnpmCommands,
|
|
208
|
-
},
|
|
209
|
-
|
|
210
|
-
/// Run command and show only errors/warnings
|
|
211
|
-
Err {
|
|
212
|
-
/// Command to run
|
|
213
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
214
|
-
command: Vec<String>,
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
/// Run tests and show only failures
|
|
218
|
-
Test {
|
|
219
|
-
/// Test command (e.g. cargo test)
|
|
220
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
221
|
-
command: Vec<String>,
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
/// Show JSON structure without values
|
|
225
|
-
Json {
|
|
226
|
-
/// JSON file
|
|
227
|
-
file: PathBuf,
|
|
228
|
-
/// Max depth
|
|
229
|
-
#[arg(short, long, default_value = "5")]
|
|
230
|
-
depth: usize,
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
/// Summarize project dependencies
|
|
234
|
-
Deps {
|
|
235
|
-
/// Project path
|
|
236
|
-
#[arg(default_value = ".")]
|
|
237
|
-
path: PathBuf,
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
/// Show environment variables (filtered, sensitive masked)
|
|
241
|
-
Env {
|
|
242
|
-
/// Filter by name (e.g. PATH, AWS)
|
|
243
|
-
#[arg(short, long)]
|
|
244
|
-
filter: Option<String>,
|
|
245
|
-
/// Show all (include sensitive)
|
|
246
|
-
#[arg(long)]
|
|
247
|
-
show_all: bool,
|
|
248
|
-
},
|
|
249
|
-
|
|
250
|
-
/// Find files with compact tree output (accepts native find flags like -name, -type)
|
|
251
|
-
Find {
|
|
252
|
-
/// All find arguments (supports both RTK and native find syntax)
|
|
253
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
254
|
-
args: Vec<String>,
|
|
255
|
-
},
|
|
256
|
-
|
|
257
|
-
/// Ultra-condensed diff (only changed lines)
|
|
258
|
-
Diff {
|
|
259
|
-
/// First file or - for stdin (unified diff)
|
|
260
|
-
file1: PathBuf,
|
|
261
|
-
/// Second file (optional if stdin)
|
|
262
|
-
file2: Option<PathBuf>,
|
|
263
|
-
},
|
|
264
|
-
|
|
265
|
-
/// Filter and deduplicate log output
|
|
266
|
-
Log {
|
|
267
|
-
/// Log file (omit for stdin)
|
|
268
|
-
file: Option<PathBuf>,
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
/// .NET commands with compact output (build/test/restore/format)
|
|
272
|
-
Dotnet {
|
|
273
|
-
#[command(subcommand)]
|
|
274
|
-
command: DotnetCommands,
|
|
275
|
-
},
|
|
276
|
-
|
|
277
|
-
/// Docker commands with compact output
|
|
278
|
-
Docker {
|
|
279
|
-
#[command(subcommand)]
|
|
280
|
-
command: DockerCommands,
|
|
281
|
-
},
|
|
282
|
-
|
|
283
|
-
/// Kubectl commands with compact output
|
|
284
|
-
Kubectl {
|
|
285
|
-
#[command(subcommand)]
|
|
286
|
-
command: KubectlCommands,
|
|
287
|
-
},
|
|
288
|
-
|
|
289
|
-
/// Run command and show heuristic summary
|
|
290
|
-
Summary {
|
|
291
|
-
/// Command to run and summarize
|
|
292
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
293
|
-
command: Vec<String>,
|
|
294
|
-
},
|
|
295
|
-
|
|
296
|
-
/// Compact grep - strips whitespace, truncates, groups by file
|
|
297
|
-
Grep {
|
|
298
|
-
/// Pattern to search
|
|
299
|
-
pattern: String,
|
|
300
|
-
/// Path to search in
|
|
301
|
-
#[arg(default_value = ".")]
|
|
302
|
-
path: String,
|
|
303
|
-
/// Max line length
|
|
304
|
-
#[arg(short = 'l', long, default_value = "80")]
|
|
305
|
-
max_len: usize,
|
|
306
|
-
/// Max results to show
|
|
307
|
-
#[arg(short, long, default_value = "50")]
|
|
308
|
-
max: usize,
|
|
309
|
-
/// Show only match context (not full line)
|
|
310
|
-
#[arg(short, long)]
|
|
311
|
-
context_only: bool,
|
|
312
|
-
/// Filter by file type (e.g., ts, py, rust)
|
|
313
|
-
#[arg(short = 't', long)]
|
|
314
|
-
file_type: Option<String>,
|
|
315
|
-
/// Show line numbers (always on, accepted for grep/rg compatibility)
|
|
316
|
-
#[arg(short = 'n', long)]
|
|
317
|
-
line_numbers: bool,
|
|
318
|
-
/// Extra ripgrep arguments (e.g., -i, -A 3, -w, --glob)
|
|
319
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
320
|
-
extra_args: Vec<String>,
|
|
321
|
-
},
|
|
322
|
-
|
|
323
|
-
/// Initialize rtk instructions in CLAUDE.md
|
|
324
|
-
Init {
|
|
325
|
-
/// Add to global ~/.claude/CLAUDE.md instead of local
|
|
326
|
-
#[arg(short, long)]
|
|
327
|
-
global: bool,
|
|
328
|
-
|
|
329
|
-
/// Install OpenCode plugin (in addition to Claude Code)
|
|
330
|
-
#[arg(long)]
|
|
331
|
-
opencode: bool,
|
|
332
|
-
|
|
333
|
-
/// Show current configuration
|
|
334
|
-
#[arg(long)]
|
|
335
|
-
show: bool,
|
|
336
|
-
|
|
337
|
-
/// Inject full instructions into CLAUDE.md (legacy mode)
|
|
338
|
-
#[arg(long = "claude-md", group = "mode")]
|
|
339
|
-
claude_md: bool,
|
|
340
|
-
|
|
341
|
-
/// Hook only, no RTK.md
|
|
342
|
-
#[arg(long = "hook-only", group = "mode")]
|
|
343
|
-
hook_only: bool,
|
|
344
|
-
|
|
345
|
-
/// Auto-patch settings.json without prompting
|
|
346
|
-
#[arg(long = "auto-patch", group = "patch")]
|
|
347
|
-
auto_patch: bool,
|
|
348
|
-
|
|
349
|
-
/// Skip settings.json patching (print manual instructions)
|
|
350
|
-
#[arg(long = "no-patch", group = "patch")]
|
|
351
|
-
no_patch: bool,
|
|
352
|
-
|
|
353
|
-
/// Remove all RTK artifacts (hook, RTK.md, CLAUDE.md reference, settings.json entry)
|
|
354
|
-
#[arg(long)]
|
|
355
|
-
uninstall: bool,
|
|
356
|
-
},
|
|
357
|
-
|
|
358
|
-
/// Download with compact output (strips progress bars)
|
|
359
|
-
Wget {
|
|
360
|
-
/// URL to download
|
|
361
|
-
url: String,
|
|
362
|
-
/// Output to stdout instead of file
|
|
363
|
-
#[arg(short = 'O', long)]
|
|
364
|
-
stdout: bool,
|
|
365
|
-
/// Additional wget arguments
|
|
366
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
367
|
-
args: Vec<String>,
|
|
368
|
-
},
|
|
369
|
-
|
|
370
|
-
/// Word/line/byte count with compact output (strips paths and padding)
|
|
371
|
-
Wc {
|
|
372
|
-
/// Arguments passed to wc (files, flags like -l, -w, -c)
|
|
373
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
374
|
-
args: Vec<String>,
|
|
375
|
-
},
|
|
376
|
-
|
|
377
|
-
/// Show token savings summary and history
|
|
378
|
-
Gain {
|
|
379
|
-
/// Filter statistics to current project (current working directory) // added
|
|
380
|
-
#[arg(short, long)]
|
|
381
|
-
project: bool,
|
|
382
|
-
/// Show ASCII graph of daily savings
|
|
383
|
-
#[arg(short, long)]
|
|
384
|
-
graph: bool,
|
|
385
|
-
/// Show recent command history
|
|
386
|
-
#[arg(short = 'H', long)]
|
|
387
|
-
history: bool,
|
|
388
|
-
/// Show monthly quota savings estimate
|
|
389
|
-
#[arg(short, long)]
|
|
390
|
-
quota: bool,
|
|
391
|
-
/// Subscription tier for quota calculation: pro, 5x, 20x
|
|
392
|
-
#[arg(short, long, default_value = "20x", requires = "quota")]
|
|
393
|
-
tier: String,
|
|
394
|
-
/// Show detailed daily breakdown (all days)
|
|
395
|
-
#[arg(short, long)]
|
|
396
|
-
daily: bool,
|
|
397
|
-
/// Show weekly breakdown
|
|
398
|
-
#[arg(short, long)]
|
|
399
|
-
weekly: bool,
|
|
400
|
-
/// Show monthly breakdown
|
|
401
|
-
#[arg(short, long)]
|
|
402
|
-
monthly: bool,
|
|
403
|
-
/// Show all time breakdowns (daily + weekly + monthly)
|
|
404
|
-
#[arg(short, long)]
|
|
405
|
-
all: bool,
|
|
406
|
-
/// Output format: text, json, csv
|
|
407
|
-
#[arg(short, long, default_value = "text")]
|
|
408
|
-
format: String,
|
|
409
|
-
/// Show parse failure log (commands that fell back to raw execution)
|
|
410
|
-
#[arg(short = 'F', long)]
|
|
411
|
-
failures: bool,
|
|
412
|
-
},
|
|
413
|
-
|
|
414
|
-
/// Claude Code economics: spending (ccusage) vs savings (rtk) analysis
|
|
415
|
-
CcEconomics {
|
|
416
|
-
/// Show detailed daily breakdown
|
|
417
|
-
#[arg(short, long)]
|
|
418
|
-
daily: bool,
|
|
419
|
-
/// Show weekly breakdown
|
|
420
|
-
#[arg(short, long)]
|
|
421
|
-
weekly: bool,
|
|
422
|
-
/// Show monthly breakdown
|
|
423
|
-
#[arg(short, long)]
|
|
424
|
-
monthly: bool,
|
|
425
|
-
/// Show all time breakdowns (daily + weekly + monthly)
|
|
426
|
-
#[arg(short, long)]
|
|
427
|
-
all: bool,
|
|
428
|
-
/// Output format: text, json, csv
|
|
429
|
-
#[arg(short, long, default_value = "text")]
|
|
430
|
-
format: String,
|
|
431
|
-
},
|
|
432
|
-
|
|
433
|
-
/// Show or create configuration file
|
|
434
|
-
Config {
|
|
435
|
-
/// Create default config file
|
|
436
|
-
#[arg(long)]
|
|
437
|
-
create: bool,
|
|
438
|
-
},
|
|
439
|
-
|
|
440
|
-
/// Vitest commands with compact output
|
|
441
|
-
Vitest {
|
|
442
|
-
#[command(subcommand)]
|
|
443
|
-
command: VitestCommands,
|
|
444
|
-
},
|
|
445
|
-
|
|
446
|
-
/// Prisma commands with compact output (no ASCII art)
|
|
447
|
-
Prisma {
|
|
448
|
-
#[command(subcommand)]
|
|
449
|
-
command: PrismaCommands,
|
|
450
|
-
},
|
|
451
|
-
|
|
452
|
-
/// TypeScript compiler with grouped error output
|
|
453
|
-
Tsc {
|
|
454
|
-
/// TypeScript compiler arguments
|
|
455
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
456
|
-
args: Vec<String>,
|
|
457
|
-
},
|
|
458
|
-
|
|
459
|
-
/// Next.js build with compact output
|
|
460
|
-
Next {
|
|
461
|
-
/// Next.js build arguments
|
|
462
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
463
|
-
args: Vec<String>,
|
|
464
|
-
},
|
|
465
|
-
|
|
466
|
-
/// ESLint with grouped rule violations
|
|
467
|
-
Lint {
|
|
468
|
-
/// Linter arguments
|
|
469
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
470
|
-
args: Vec<String>,
|
|
471
|
-
},
|
|
472
|
-
|
|
473
|
-
/// Prettier format checker with compact output
|
|
474
|
-
Prettier {
|
|
475
|
-
/// Prettier arguments (e.g., --check, --write)
|
|
476
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
477
|
-
args: Vec<String>,
|
|
478
|
-
},
|
|
479
|
-
|
|
480
|
-
/// Universal format checker (prettier, black, ruff format)
|
|
481
|
-
Format {
|
|
482
|
-
/// Formatter arguments (auto-detects formatter from project files)
|
|
483
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
484
|
-
args: Vec<String>,
|
|
485
|
-
},
|
|
486
|
-
|
|
487
|
-
/// Playwright E2E tests with compact output
|
|
488
|
-
Playwright {
|
|
489
|
-
/// Playwright arguments
|
|
490
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
491
|
-
args: Vec<String>,
|
|
492
|
-
},
|
|
493
|
-
|
|
494
|
-
/// Cargo commands with compact output
|
|
495
|
-
Cargo {
|
|
496
|
-
#[command(subcommand)]
|
|
497
|
-
command: CargoCommands,
|
|
498
|
-
},
|
|
499
|
-
|
|
500
|
-
/// npm run with filtered output (strip boilerplate)
|
|
501
|
-
Npm {
|
|
502
|
-
/// npm run arguments (script name + options)
|
|
503
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
504
|
-
args: Vec<String>,
|
|
505
|
-
},
|
|
506
|
-
|
|
507
|
-
/// npx with intelligent routing (tsc, eslint, prisma -> specialized filters)
|
|
508
|
-
Npx {
|
|
509
|
-
/// npx arguments (command + options)
|
|
510
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
511
|
-
args: Vec<String>,
|
|
512
|
-
},
|
|
513
|
-
|
|
514
|
-
/// Curl with auto-JSON detection and schema output
|
|
515
|
-
Curl {
|
|
516
|
-
/// Curl arguments (URL + options)
|
|
517
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
518
|
-
args: Vec<String>,
|
|
519
|
-
},
|
|
520
|
-
|
|
521
|
-
/// Discover missed RTK savings from Claude Code history
|
|
522
|
-
Discover {
|
|
523
|
-
/// Filter by project path (substring match)
|
|
524
|
-
#[arg(short, long)]
|
|
525
|
-
project: Option<String>,
|
|
526
|
-
/// Max commands per section
|
|
527
|
-
#[arg(short, long, default_value = "15")]
|
|
528
|
-
limit: usize,
|
|
529
|
-
/// Scan all projects (default: current project only)
|
|
530
|
-
#[arg(short, long)]
|
|
531
|
-
all: bool,
|
|
532
|
-
/// Limit to sessions from last N days
|
|
533
|
-
#[arg(short, long, default_value = "30")]
|
|
534
|
-
since: u64,
|
|
535
|
-
/// Output format: text, json
|
|
536
|
-
#[arg(short, long, default_value = "text")]
|
|
537
|
-
format: String,
|
|
538
|
-
},
|
|
539
|
-
|
|
540
|
-
/// Learn CLI corrections from Claude Code error history
|
|
541
|
-
Learn {
|
|
542
|
-
/// Filter by project path (substring match)
|
|
543
|
-
#[arg(short, long)]
|
|
544
|
-
project: Option<String>,
|
|
545
|
-
/// Scan all projects (default: current project only)
|
|
546
|
-
#[arg(short, long)]
|
|
547
|
-
all: bool,
|
|
548
|
-
/// Limit to sessions from last N days
|
|
549
|
-
#[arg(short, long, default_value = "30")]
|
|
550
|
-
since: u64,
|
|
551
|
-
/// Output format: text, json
|
|
552
|
-
#[arg(short, long, default_value = "text")]
|
|
553
|
-
format: String,
|
|
554
|
-
/// Generate .claude/rules/cli-corrections.md file
|
|
555
|
-
#[arg(short, long)]
|
|
556
|
-
write_rules: bool,
|
|
557
|
-
/// Minimum confidence threshold (0.0-1.0)
|
|
558
|
-
#[arg(long, default_value = "0.6")]
|
|
559
|
-
min_confidence: f64,
|
|
560
|
-
/// Minimum occurrences to include in report
|
|
561
|
-
#[arg(long, default_value = "1")]
|
|
562
|
-
min_occurrences: usize,
|
|
563
|
-
},
|
|
564
|
-
|
|
565
|
-
/// Execute command without filtering but track usage
|
|
566
|
-
Proxy {
|
|
567
|
-
/// Command and arguments to execute
|
|
568
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
569
|
-
args: Vec<OsString>,
|
|
570
|
-
},
|
|
571
|
-
|
|
572
|
-
/// Verify hook integrity and run TOML filter inline tests
|
|
573
|
-
Verify {
|
|
574
|
-
/// Run tests only for this filter name
|
|
575
|
-
#[arg(long)]
|
|
576
|
-
filter: Option<String>,
|
|
577
|
-
/// Fail if any filter has no inline tests (CI mode)
|
|
578
|
-
#[arg(long)]
|
|
579
|
-
require_all: bool,
|
|
580
|
-
},
|
|
581
|
-
|
|
582
|
-
/// Ruff linter/formatter with compact output
|
|
583
|
-
Ruff {
|
|
584
|
-
/// Ruff arguments (e.g., check, format --check)
|
|
585
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
586
|
-
args: Vec<String>,
|
|
587
|
-
},
|
|
588
|
-
|
|
589
|
-
/// Pytest test runner with compact output
|
|
590
|
-
Pytest {
|
|
591
|
-
/// Pytest arguments
|
|
592
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
593
|
-
args: Vec<String>,
|
|
594
|
-
},
|
|
595
|
-
|
|
596
|
-
/// Mypy type checker with grouped error output
|
|
597
|
-
Mypy {
|
|
598
|
-
/// Mypy arguments
|
|
599
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
600
|
-
args: Vec<String>,
|
|
601
|
-
},
|
|
602
|
-
|
|
603
|
-
/// Pip package manager with compact output (auto-detects uv)
|
|
604
|
-
Pip {
|
|
605
|
-
/// Pip arguments (e.g., list, outdated, install)
|
|
606
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
607
|
-
args: Vec<String>,
|
|
608
|
-
},
|
|
609
|
-
|
|
610
|
-
/// Go commands with compact output
|
|
611
|
-
Go {
|
|
612
|
-
#[command(subcommand)]
|
|
613
|
-
command: GoCommands,
|
|
614
|
-
},
|
|
615
|
-
|
|
616
|
-
/// Graphite (gt) stacked PR commands with compact output
|
|
617
|
-
Gt {
|
|
618
|
-
#[command(subcommand)]
|
|
619
|
-
command: GtCommands,
|
|
620
|
-
},
|
|
621
|
-
|
|
622
|
-
/// golangci-lint with compact output
|
|
623
|
-
#[command(name = "golangci-lint")]
|
|
624
|
-
GolangciLint {
|
|
625
|
-
/// golangci-lint arguments
|
|
626
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
627
|
-
args: Vec<String>,
|
|
628
|
-
},
|
|
629
|
-
|
|
630
|
-
/// Show hook rewrite audit metrics (requires RTK_HOOK_AUDIT=1)
|
|
631
|
-
#[command(name = "hook-audit")]
|
|
632
|
-
HookAudit {
|
|
633
|
-
/// Show entries from last N days (0 = all time)
|
|
634
|
-
#[arg(short, long, default_value = "7")]
|
|
635
|
-
since: u64,
|
|
636
|
-
},
|
|
637
|
-
|
|
638
|
-
/// Rewrite a raw command to its RTK equivalent (single source of truth for hooks)
|
|
639
|
-
///
|
|
640
|
-
/// Exits 0 and prints the rewritten command if supported.
|
|
641
|
-
/// Exits 1 with no output if the command has no RTK equivalent.
|
|
642
|
-
///
|
|
643
|
-
/// Used by Claude Code, Gemini CLI, and other LLM hooks:
|
|
644
|
-
/// REWRITTEN=$(rtk rewrite "$CMD") || exit 0
|
|
645
|
-
Rewrite {
|
|
646
|
-
/// Raw command to rewrite (e.g. "git status", "cargo test && git push")
|
|
647
|
-
/// Accepts multiple args: `rtk rewrite ls -al` is equivalent to `rtk rewrite "ls -al"`
|
|
648
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
649
|
-
args: Vec<String>,
|
|
650
|
-
},
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
#[derive(Subcommand)]
|
|
654
|
-
enum GitCommands {
|
|
655
|
-
/// Condensed diff output
|
|
656
|
-
Diff {
|
|
657
|
-
/// Git arguments (supports all git diff flags like --stat, --cached, etc)
|
|
658
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
659
|
-
args: Vec<String>,
|
|
660
|
-
},
|
|
661
|
-
/// One-line commit history
|
|
662
|
-
Log {
|
|
663
|
-
/// Git arguments (supports all git log flags like --oneline, --graph, --all)
|
|
664
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
665
|
-
args: Vec<String>,
|
|
666
|
-
},
|
|
667
|
-
/// Compact status (supports all git status flags)
|
|
668
|
-
Status {
|
|
669
|
-
/// Git arguments (supports all git status flags like --porcelain, --short, -s)
|
|
670
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
671
|
-
args: Vec<String>,
|
|
672
|
-
},
|
|
673
|
-
/// Compact show (commit summary + stat + compacted diff)
|
|
674
|
-
Show {
|
|
675
|
-
/// Git arguments (supports all git show flags)
|
|
676
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
677
|
-
args: Vec<String>,
|
|
678
|
-
},
|
|
679
|
-
/// Add files → "ok ✓"
|
|
680
|
-
Add {
|
|
681
|
-
/// Files and flags to add (supports all git add flags like -A, -p, --all, etc)
|
|
682
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
683
|
-
args: Vec<String>,
|
|
684
|
-
},
|
|
685
|
-
/// Commit → "ok ✓ \<hash\>"
|
|
686
|
-
Commit {
|
|
687
|
-
/// Git commit arguments (supports -a, -m, --amend, --allow-empty, etc)
|
|
688
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
689
|
-
args: Vec<String>,
|
|
690
|
-
},
|
|
691
|
-
/// Push → "ok ✓ \<branch\>"
|
|
692
|
-
Push {
|
|
693
|
-
/// Git push arguments (supports -u, remote, branch, etc.)
|
|
694
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
695
|
-
args: Vec<String>,
|
|
696
|
-
},
|
|
697
|
-
/// Pull → "ok ✓ \<stats\>"
|
|
698
|
-
Pull {
|
|
699
|
-
/// Git pull arguments (supports --rebase, remote, branch, etc.)
|
|
700
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
701
|
-
args: Vec<String>,
|
|
702
|
-
},
|
|
703
|
-
/// Compact branch listing (current/local/remote)
|
|
704
|
-
Branch {
|
|
705
|
-
/// Git branch arguments (supports -d, -D, -m, etc.)
|
|
706
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
707
|
-
args: Vec<String>,
|
|
708
|
-
},
|
|
709
|
-
/// Fetch → "ok fetched (N new refs)"
|
|
710
|
-
Fetch {
|
|
711
|
-
/// Git fetch arguments
|
|
712
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
713
|
-
args: Vec<String>,
|
|
714
|
-
},
|
|
715
|
-
/// Stash management (list, show, pop, apply, drop)
|
|
716
|
-
Stash {
|
|
717
|
-
/// Subcommand: list, show, pop, apply, drop, push
|
|
718
|
-
subcommand: Option<String>,
|
|
719
|
-
/// Additional arguments
|
|
720
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
721
|
-
args: Vec<String>,
|
|
722
|
-
},
|
|
723
|
-
/// Compact worktree listing
|
|
724
|
-
Worktree {
|
|
725
|
-
/// Git worktree arguments (add, remove, prune, or empty for list)
|
|
726
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
727
|
-
args: Vec<String>,
|
|
728
|
-
},
|
|
729
|
-
/// Passthrough: runs any unsupported git subcommand directly
|
|
730
|
-
#[command(external_subcommand)]
|
|
731
|
-
Other(Vec<OsString>),
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
#[derive(Subcommand)]
|
|
735
|
-
enum PnpmCommands {
|
|
736
|
-
/// List installed packages (ultra-dense)
|
|
737
|
-
List {
|
|
738
|
-
/// Depth level (default: 0)
|
|
739
|
-
#[arg(short, long, default_value = "0")]
|
|
740
|
-
depth: usize,
|
|
741
|
-
/// Additional pnpm arguments
|
|
742
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
743
|
-
args: Vec<String>,
|
|
744
|
-
},
|
|
745
|
-
/// Show outdated packages (condensed: "pkg: old → new")
|
|
746
|
-
Outdated {
|
|
747
|
-
/// Additional pnpm arguments
|
|
748
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
749
|
-
args: Vec<String>,
|
|
750
|
-
},
|
|
751
|
-
/// Install packages (filter progress bars)
|
|
752
|
-
Install {
|
|
753
|
-
/// Packages to install
|
|
754
|
-
packages: Vec<String>,
|
|
755
|
-
/// Additional pnpm arguments
|
|
756
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
757
|
-
args: Vec<String>,
|
|
758
|
-
},
|
|
759
|
-
/// Build (generic passthrough, no framework-specific filter)
|
|
760
|
-
Build {
|
|
761
|
-
/// Additional build arguments
|
|
762
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
763
|
-
args: Vec<String>,
|
|
764
|
-
},
|
|
765
|
-
/// Typecheck (delegates to tsc filter)
|
|
766
|
-
Typecheck {
|
|
767
|
-
/// Additional typecheck arguments
|
|
768
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
769
|
-
args: Vec<String>,
|
|
770
|
-
},
|
|
771
|
-
/// Passthrough: runs any unsupported pnpm subcommand directly
|
|
772
|
-
#[command(external_subcommand)]
|
|
773
|
-
Other(Vec<OsString>),
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
#[derive(Subcommand)]
|
|
777
|
-
enum DockerCommands {
|
|
778
|
-
/// List running containers
|
|
779
|
-
Ps,
|
|
780
|
-
/// List images
|
|
781
|
-
Images,
|
|
782
|
-
/// Show container logs (deduplicated)
|
|
783
|
-
Logs { container: String },
|
|
784
|
-
/// Docker Compose commands with compact output
|
|
785
|
-
Compose {
|
|
786
|
-
#[command(subcommand)]
|
|
787
|
-
command: ComposeCommands,
|
|
788
|
-
},
|
|
789
|
-
/// Passthrough: runs any unsupported docker subcommand directly
|
|
790
|
-
#[command(external_subcommand)]
|
|
791
|
-
Other(Vec<OsString>),
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
#[derive(Subcommand)]
|
|
795
|
-
enum ComposeCommands {
|
|
796
|
-
/// List compose services (compact)
|
|
797
|
-
Ps,
|
|
798
|
-
/// Show compose logs (deduplicated)
|
|
799
|
-
Logs {
|
|
800
|
-
/// Optional service name
|
|
801
|
-
service: Option<String>,
|
|
802
|
-
},
|
|
803
|
-
/// Build compose services (summary)
|
|
804
|
-
Build {
|
|
805
|
-
/// Optional service name
|
|
806
|
-
service: Option<String>,
|
|
807
|
-
},
|
|
808
|
-
/// Passthrough: runs any unsupported compose subcommand directly
|
|
809
|
-
#[command(external_subcommand)]
|
|
810
|
-
Other(Vec<OsString>),
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
#[derive(Subcommand)]
|
|
814
|
-
enum KubectlCommands {
|
|
815
|
-
/// List pods
|
|
816
|
-
Pods {
|
|
817
|
-
#[arg(short, long)]
|
|
818
|
-
namespace: Option<String>,
|
|
819
|
-
/// All namespaces
|
|
820
|
-
#[arg(short = 'A', long)]
|
|
821
|
-
all: bool,
|
|
822
|
-
},
|
|
823
|
-
/// List services
|
|
824
|
-
Services {
|
|
825
|
-
#[arg(short, long)]
|
|
826
|
-
namespace: Option<String>,
|
|
827
|
-
/// All namespaces
|
|
828
|
-
#[arg(short = 'A', long)]
|
|
829
|
-
all: bool,
|
|
830
|
-
},
|
|
831
|
-
/// Show pod logs (deduplicated)
|
|
832
|
-
Logs {
|
|
833
|
-
pod: String,
|
|
834
|
-
#[arg(short, long)]
|
|
835
|
-
container: Option<String>,
|
|
836
|
-
},
|
|
837
|
-
/// Passthrough: runs any unsupported kubectl subcommand directly
|
|
838
|
-
#[command(external_subcommand)]
|
|
839
|
-
Other(Vec<OsString>),
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
#[derive(Subcommand)]
|
|
843
|
-
enum VitestCommands {
|
|
844
|
-
/// Run tests with filtered output (90% token reduction)
|
|
845
|
-
Run {
|
|
846
|
-
/// Additional vitest arguments
|
|
847
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
848
|
-
args: Vec<String>,
|
|
849
|
-
},
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
#[derive(Subcommand)]
|
|
853
|
-
enum PrismaCommands {
|
|
854
|
-
/// Generate Prisma Client (strip ASCII art)
|
|
855
|
-
Generate {
|
|
856
|
-
/// Additional prisma arguments
|
|
857
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
858
|
-
args: Vec<String>,
|
|
859
|
-
},
|
|
860
|
-
/// Manage migrations
|
|
861
|
-
Migrate {
|
|
862
|
-
#[command(subcommand)]
|
|
863
|
-
command: PrismaMigrateCommands,
|
|
864
|
-
},
|
|
865
|
-
/// Push schema to database
|
|
866
|
-
DbPush {
|
|
867
|
-
/// Additional prisma arguments
|
|
868
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
869
|
-
args: Vec<String>,
|
|
870
|
-
},
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
#[derive(Subcommand)]
|
|
874
|
-
enum PrismaMigrateCommands {
|
|
875
|
-
/// Create and apply migration
|
|
876
|
-
Dev {
|
|
877
|
-
/// Migration name
|
|
878
|
-
#[arg(short, long)]
|
|
879
|
-
name: Option<String>,
|
|
880
|
-
/// Additional arguments
|
|
881
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
882
|
-
args: Vec<String>,
|
|
883
|
-
},
|
|
884
|
-
/// Check migration status
|
|
885
|
-
Status {
|
|
886
|
-
/// Additional arguments
|
|
887
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
888
|
-
args: Vec<String>,
|
|
889
|
-
},
|
|
890
|
-
/// Deploy migrations to production
|
|
891
|
-
Deploy {
|
|
892
|
-
/// Additional arguments
|
|
893
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
894
|
-
args: Vec<String>,
|
|
895
|
-
},
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
#[derive(Subcommand)]
|
|
899
|
-
enum CargoCommands {
|
|
900
|
-
/// Build with compact output (strip Compiling lines, keep errors)
|
|
901
|
-
Build {
|
|
902
|
-
/// Additional cargo build arguments
|
|
903
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
904
|
-
args: Vec<String>,
|
|
905
|
-
},
|
|
906
|
-
/// Test with failures-only output
|
|
907
|
-
Test {
|
|
908
|
-
/// Additional cargo test arguments
|
|
909
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
910
|
-
args: Vec<String>,
|
|
911
|
-
},
|
|
912
|
-
/// Clippy with warnings grouped by lint rule
|
|
913
|
-
Clippy {
|
|
914
|
-
/// Additional cargo clippy arguments
|
|
915
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
916
|
-
args: Vec<String>,
|
|
917
|
-
},
|
|
918
|
-
/// Check with compact output (strip Checking lines, keep errors)
|
|
919
|
-
Check {
|
|
920
|
-
/// Additional cargo check arguments
|
|
921
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
922
|
-
args: Vec<String>,
|
|
923
|
-
},
|
|
924
|
-
/// Install with compact output (strip dep compilation, keep installed/errors)
|
|
925
|
-
Install {
|
|
926
|
-
/// Additional cargo install arguments
|
|
927
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
928
|
-
args: Vec<String>,
|
|
929
|
-
},
|
|
930
|
-
/// Nextest with failures-only output
|
|
931
|
-
Nextest {
|
|
932
|
-
/// Additional cargo nextest arguments (e.g., run, list, --lib)
|
|
933
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
934
|
-
args: Vec<String>,
|
|
935
|
-
},
|
|
936
|
-
/// Passthrough: runs any unsupported cargo subcommand directly
|
|
937
|
-
#[command(external_subcommand)]
|
|
938
|
-
Other(Vec<OsString>),
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
#[derive(Subcommand)]
|
|
942
|
-
enum DotnetCommands {
|
|
943
|
-
/// Build with compact output
|
|
944
|
-
Build {
|
|
945
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
946
|
-
args: Vec<String>,
|
|
947
|
-
},
|
|
948
|
-
/// Test with compact output
|
|
949
|
-
Test {
|
|
950
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
951
|
-
args: Vec<String>,
|
|
952
|
-
},
|
|
953
|
-
/// Restore with compact output
|
|
954
|
-
Restore {
|
|
955
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
956
|
-
args: Vec<String>,
|
|
957
|
-
},
|
|
958
|
-
/// Format with compact output
|
|
959
|
-
Format {
|
|
960
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
961
|
-
args: Vec<String>,
|
|
962
|
-
},
|
|
963
|
-
/// Passthrough: runs any unsupported dotnet subcommand directly
|
|
964
|
-
#[command(external_subcommand)]
|
|
965
|
-
Other(Vec<OsString>),
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
#[derive(Subcommand)]
|
|
969
|
-
enum GoCommands {
|
|
970
|
-
/// Run tests with compact output (90% token reduction via JSON streaming)
|
|
971
|
-
Test {
|
|
972
|
-
/// Additional go test arguments
|
|
973
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
974
|
-
args: Vec<String>,
|
|
975
|
-
},
|
|
976
|
-
/// Build with compact output (errors only)
|
|
977
|
-
Build {
|
|
978
|
-
/// Additional go build arguments
|
|
979
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
980
|
-
args: Vec<String>,
|
|
981
|
-
},
|
|
982
|
-
/// Vet with compact output
|
|
983
|
-
Vet {
|
|
984
|
-
/// Additional go vet arguments
|
|
985
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
986
|
-
args: Vec<String>,
|
|
987
|
-
},
|
|
988
|
-
/// Passthrough: runs any unsupported go subcommand directly
|
|
989
|
-
#[command(external_subcommand)]
|
|
990
|
-
Other(Vec<OsString>),
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
/// RTK-only subcommands that should never fall back to raw execution.
|
|
994
|
-
/// If Clap fails to parse these, show the Clap error directly.
|
|
995
|
-
const RTK_META_COMMANDS: &[&str] = &[
|
|
996
|
-
"gain",
|
|
997
|
-
"discover",
|
|
998
|
-
"learn",
|
|
999
|
-
"init",
|
|
1000
|
-
"config",
|
|
1001
|
-
"proxy",
|
|
1002
|
-
"hook-audit",
|
|
1003
|
-
"cc-economics",
|
|
1004
|
-
"verify",
|
|
1005
|
-
];
|
|
1006
|
-
|
|
1007
|
-
fn run_fallback(parse_error: clap::Error) -> Result<()> {
|
|
1008
|
-
let args: Vec<String> = std::env::args().skip(1).collect();
|
|
1009
|
-
|
|
1010
|
-
// No args → show Clap's error (user ran just "rtk" with bad syntax)
|
|
1011
|
-
if args.is_empty() {
|
|
1012
|
-
parse_error.exit();
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
// RTK meta-commands should never fall back to raw execution.
|
|
1016
|
-
// e.g. `rtk gain --badtypo` should show Clap's error, not try to run `gain` from $PATH.
|
|
1017
|
-
if RTK_META_COMMANDS.contains(&args[0].as_str()) {
|
|
1018
|
-
parse_error.exit();
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
let raw_command = args.join(" ");
|
|
1022
|
-
let error_message = utils::strip_ansi(&parse_error.to_string());
|
|
1023
|
-
|
|
1024
|
-
// Start timer before execution to capture actual command runtime
|
|
1025
|
-
let timer = tracking::TimedExecution::start();
|
|
1026
|
-
|
|
1027
|
-
// TOML filter lookup — bypass with RTK_NO_TOML=1
|
|
1028
|
-
// Use basename of args[0] so absolute paths (/usr/bin/make) still match "^make\b".
|
|
1029
|
-
let lookup_cmd = {
|
|
1030
|
-
let base = std::path::Path::new(&args[0])
|
|
1031
|
-
.file_name()
|
|
1032
|
-
.map(|n| n.to_string_lossy().into_owned())
|
|
1033
|
-
.unwrap_or_else(|| args[0].clone());
|
|
1034
|
-
std::iter::once(base.as_str())
|
|
1035
|
-
.chain(args[1..].iter().map(|s| s.as_str()))
|
|
1036
|
-
.collect::<Vec<_>>()
|
|
1037
|
-
.join(" ")
|
|
1038
|
-
};
|
|
1039
|
-
let toml_match = if std::env::var("RTK_NO_TOML").ok().as_deref() == Some("1") {
|
|
1040
|
-
None
|
|
1041
|
-
} else {
|
|
1042
|
-
toml_filter::find_matching_filter(&lookup_cmd)
|
|
1043
|
-
};
|
|
1044
|
-
|
|
1045
|
-
if let Some(filter) = toml_match {
|
|
1046
|
-
// TOML match: capture stdout for filtering
|
|
1047
|
-
let result = std::process::Command::new(&args[0])
|
|
1048
|
-
.args(&args[1..])
|
|
1049
|
-
.stdin(std::process::Stdio::inherit())
|
|
1050
|
-
.stdout(std::process::Stdio::piped()) // capture
|
|
1051
|
-
.stderr(std::process::Stdio::inherit()) // stderr always direct
|
|
1052
|
-
.output();
|
|
1053
|
-
|
|
1054
|
-
match result {
|
|
1055
|
-
Ok(output) => {
|
|
1056
|
-
let stdout_raw = String::from_utf8_lossy(&output.stdout);
|
|
1057
|
-
|
|
1058
|
-
// Tee raw output BEFORE filtering on failure — lets LLM re-read if needed
|
|
1059
|
-
let tee_hint = if !output.status.success() {
|
|
1060
|
-
tee::tee_and_hint(&stdout_raw, &raw_command, output.status.code().unwrap_or(1))
|
|
1061
|
-
} else {
|
|
1062
|
-
None
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
let filtered = toml_filter::apply_filter(filter, &stdout_raw);
|
|
1066
|
-
println!("{}", filtered);
|
|
1067
|
-
if let Some(hint) = tee_hint {
|
|
1068
|
-
println!("{}", hint);
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
timer.track(
|
|
1072
|
-
&raw_command,
|
|
1073
|
-
&format!("rtk:toml {}", raw_command),
|
|
1074
|
-
&stdout_raw,
|
|
1075
|
-
&filtered,
|
|
1076
|
-
);
|
|
1077
|
-
tracking::record_parse_failure_silent(&raw_command, &error_message, true);
|
|
1078
|
-
|
|
1079
|
-
if !output.status.success() {
|
|
1080
|
-
std::process::exit(output.status.code().unwrap_or(1));
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
Err(e) => {
|
|
1084
|
-
// Command not found — same behaviour as no-TOML path
|
|
1085
|
-
tracking::record_parse_failure_silent(&raw_command, &error_message, false);
|
|
1086
|
-
eprintln!("[rtk: {}]", e);
|
|
1087
|
-
std::process::exit(127);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
} else {
|
|
1091
|
-
// No TOML match: original passthrough behaviour (Stdio::inherit, streaming)
|
|
1092
|
-
let status = std::process::Command::new(&args[0])
|
|
1093
|
-
.args(&args[1..])
|
|
1094
|
-
.stdin(std::process::Stdio::inherit())
|
|
1095
|
-
.stdout(std::process::Stdio::inherit())
|
|
1096
|
-
.stderr(std::process::Stdio::inherit())
|
|
1097
|
-
.status();
|
|
1098
|
-
|
|
1099
|
-
match status {
|
|
1100
|
-
Ok(s) => {
|
|
1101
|
-
timer.track_passthrough(&raw_command, &format!("rtk fallback: {}", raw_command));
|
|
1102
|
-
|
|
1103
|
-
tracking::record_parse_failure_silent(&raw_command, &error_message, true);
|
|
1104
|
-
|
|
1105
|
-
if !s.success() {
|
|
1106
|
-
std::process::exit(s.code().unwrap_or(1));
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
Err(e) => {
|
|
1110
|
-
tracking::record_parse_failure_silent(&raw_command, &error_message, false);
|
|
1111
|
-
// Command not found or other OS error — single message, no duplicate Clap error
|
|
1112
|
-
eprintln!("[rtk: {}]", e);
|
|
1113
|
-
std::process::exit(127);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
Ok(())
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
#[derive(Subcommand)]
|
|
1122
|
-
enum GtCommands {
|
|
1123
|
-
/// Compact stack log output
|
|
1124
|
-
Log {
|
|
1125
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
1126
|
-
args: Vec<String>,
|
|
1127
|
-
},
|
|
1128
|
-
/// Compact submit output
|
|
1129
|
-
Submit {
|
|
1130
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
1131
|
-
args: Vec<String>,
|
|
1132
|
-
},
|
|
1133
|
-
/// Compact sync output
|
|
1134
|
-
Sync {
|
|
1135
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
1136
|
-
args: Vec<String>,
|
|
1137
|
-
},
|
|
1138
|
-
/// Compact restack output
|
|
1139
|
-
Restack {
|
|
1140
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
1141
|
-
args: Vec<String>,
|
|
1142
|
-
},
|
|
1143
|
-
/// Compact create output
|
|
1144
|
-
Create {
|
|
1145
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
1146
|
-
args: Vec<String>,
|
|
1147
|
-
},
|
|
1148
|
-
/// Branch info and management
|
|
1149
|
-
Branch {
|
|
1150
|
-
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
|
1151
|
-
args: Vec<String>,
|
|
1152
|
-
},
|
|
1153
|
-
/// Passthrough: git-passthrough detection or direct gt execution
|
|
1154
|
-
#[command(external_subcommand)]
|
|
1155
|
-
Other(Vec<OsString>),
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
/// Split a string into shell-like tokens, respecting single and double quotes.
|
|
1159
|
-
/// e.g. `git log --format="%H %s"` → ["git", "log", "--format=%H %s"]
|
|
1160
|
-
fn shell_split(input: &str) -> Vec<String> {
|
|
1161
|
-
let mut tokens = Vec::new();
|
|
1162
|
-
let mut current = String::new();
|
|
1163
|
-
let mut chars = input.chars().peekable();
|
|
1164
|
-
let mut in_single = false;
|
|
1165
|
-
let mut in_double = false;
|
|
1166
|
-
|
|
1167
|
-
while let Some(c) = chars.next() {
|
|
1168
|
-
match c {
|
|
1169
|
-
'\'' if !in_double => in_single = !in_single,
|
|
1170
|
-
'"' if !in_single => in_double = !in_double,
|
|
1171
|
-
' ' | '\t' if !in_single && !in_double => {
|
|
1172
|
-
if !current.is_empty() {
|
|
1173
|
-
tokens.push(std::mem::take(&mut current));
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
_ => current.push(c),
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
if !current.is_empty() {
|
|
1180
|
-
tokens.push(current);
|
|
1181
|
-
}
|
|
1182
|
-
tokens
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
fn main() -> Result<()> {
|
|
1186
|
-
// Fire-and-forget telemetry ping (1/day, non-blocking)
|
|
1187
|
-
telemetry::maybe_ping();
|
|
1188
|
-
|
|
1189
|
-
let cli = match Cli::try_parse() {
|
|
1190
|
-
Ok(cli) => cli,
|
|
1191
|
-
Err(e) => {
|
|
1192
|
-
if matches!(e.kind(), ErrorKind::DisplayHelp | ErrorKind::DisplayVersion) {
|
|
1193
|
-
e.exit();
|
|
1194
|
-
}
|
|
1195
|
-
return run_fallback(e);
|
|
1196
|
-
}
|
|
1197
|
-
};
|
|
1198
|
-
|
|
1199
|
-
// Warn if installed hook is outdated/missing (1/day, non-blocking).
|
|
1200
|
-
// Skip for Gain — it shows its own inline hook warning.
|
|
1201
|
-
if !matches!(cli.command, Commands::Gain { .. }) {
|
|
1202
|
-
hook_check::maybe_warn();
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
// Runtime integrity check for operational commands.
|
|
1206
|
-
// Meta commands (init, gain, verify, config, etc.) skip the check
|
|
1207
|
-
// because they don't go through the hook pipeline.
|
|
1208
|
-
if is_operational_command(&cli.command) {
|
|
1209
|
-
integrity::runtime_check()?;
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
match cli.command {
|
|
1213
|
-
Commands::Ls { args } => {
|
|
1214
|
-
ls::run(&args, cli.verbose)?;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
Commands::Tree { args } => {
|
|
1218
|
-
tree::run(&args, cli.verbose)?;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
Commands::Read {
|
|
1222
|
-
file,
|
|
1223
|
-
level,
|
|
1224
|
-
max_lines,
|
|
1225
|
-
tail_lines,
|
|
1226
|
-
line_numbers,
|
|
1227
|
-
} => {
|
|
1228
|
-
if file == Path::new("-") {
|
|
1229
|
-
read::run_stdin(level, max_lines, tail_lines, line_numbers, cli.verbose)?;
|
|
1230
|
-
} else {
|
|
1231
|
-
read::run(
|
|
1232
|
-
&file,
|
|
1233
|
-
level,
|
|
1234
|
-
max_lines,
|
|
1235
|
-
tail_lines,
|
|
1236
|
-
line_numbers,
|
|
1237
|
-
cli.verbose,
|
|
1238
|
-
)?;
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
Commands::Smart {
|
|
1243
|
-
file,
|
|
1244
|
-
model,
|
|
1245
|
-
force_download,
|
|
1246
|
-
} => {
|
|
1247
|
-
local_llm::run(&file, &model, force_download, cli.verbose)?;
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
Commands::Git {
|
|
1251
|
-
directory,
|
|
1252
|
-
config_override,
|
|
1253
|
-
git_dir,
|
|
1254
|
-
work_tree,
|
|
1255
|
-
no_pager,
|
|
1256
|
-
no_optional_locks,
|
|
1257
|
-
bare,
|
|
1258
|
-
literal_pathspecs,
|
|
1259
|
-
command,
|
|
1260
|
-
} => {
|
|
1261
|
-
// Build global git args (inserted between "git" and subcommand)
|
|
1262
|
-
let mut global_args: Vec<String> = Vec::new();
|
|
1263
|
-
for dir in &directory {
|
|
1264
|
-
global_args.push("-C".to_string());
|
|
1265
|
-
global_args.push(dir.clone());
|
|
1266
|
-
}
|
|
1267
|
-
for cfg in &config_override {
|
|
1268
|
-
global_args.push("-c".to_string());
|
|
1269
|
-
global_args.push(cfg.clone());
|
|
1270
|
-
}
|
|
1271
|
-
if let Some(ref dir) = git_dir {
|
|
1272
|
-
global_args.push("--git-dir".to_string());
|
|
1273
|
-
global_args.push(dir.clone());
|
|
1274
|
-
}
|
|
1275
|
-
if let Some(ref tree) = work_tree {
|
|
1276
|
-
global_args.push("--work-tree".to_string());
|
|
1277
|
-
global_args.push(tree.clone());
|
|
1278
|
-
}
|
|
1279
|
-
if no_pager {
|
|
1280
|
-
global_args.push("--no-pager".to_string());
|
|
1281
|
-
}
|
|
1282
|
-
if no_optional_locks {
|
|
1283
|
-
global_args.push("--no-optional-locks".to_string());
|
|
1284
|
-
}
|
|
1285
|
-
if bare {
|
|
1286
|
-
global_args.push("--bare".to_string());
|
|
1287
|
-
}
|
|
1288
|
-
if literal_pathspecs {
|
|
1289
|
-
global_args.push("--literal-pathspecs".to_string());
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
match command {
|
|
1293
|
-
GitCommands::Diff { args } => {
|
|
1294
|
-
git::run(
|
|
1295
|
-
git::GitCommand::Diff,
|
|
1296
|
-
&args,
|
|
1297
|
-
None,
|
|
1298
|
-
cli.verbose,
|
|
1299
|
-
&global_args,
|
|
1300
|
-
)?;
|
|
1301
|
-
}
|
|
1302
|
-
GitCommands::Log { args } => {
|
|
1303
|
-
git::run(git::GitCommand::Log, &args, None, cli.verbose, &global_args)?;
|
|
1304
|
-
}
|
|
1305
|
-
GitCommands::Status { args } => {
|
|
1306
|
-
git::run(
|
|
1307
|
-
git::GitCommand::Status,
|
|
1308
|
-
&args,
|
|
1309
|
-
None,
|
|
1310
|
-
cli.verbose,
|
|
1311
|
-
&global_args,
|
|
1312
|
-
)?;
|
|
1313
|
-
}
|
|
1314
|
-
GitCommands::Show { args } => {
|
|
1315
|
-
git::run(
|
|
1316
|
-
git::GitCommand::Show,
|
|
1317
|
-
&args,
|
|
1318
|
-
None,
|
|
1319
|
-
cli.verbose,
|
|
1320
|
-
&global_args,
|
|
1321
|
-
)?;
|
|
1322
|
-
}
|
|
1323
|
-
GitCommands::Add { args } => {
|
|
1324
|
-
git::run(git::GitCommand::Add, &args, None, cli.verbose, &global_args)?;
|
|
1325
|
-
}
|
|
1326
|
-
GitCommands::Commit { args } => {
|
|
1327
|
-
git::run(
|
|
1328
|
-
git::GitCommand::Commit,
|
|
1329
|
-
&args,
|
|
1330
|
-
None,
|
|
1331
|
-
cli.verbose,
|
|
1332
|
-
&global_args,
|
|
1333
|
-
)?;
|
|
1334
|
-
}
|
|
1335
|
-
GitCommands::Push { args } => {
|
|
1336
|
-
git::run(
|
|
1337
|
-
git::GitCommand::Push,
|
|
1338
|
-
&args,
|
|
1339
|
-
None,
|
|
1340
|
-
cli.verbose,
|
|
1341
|
-
&global_args,
|
|
1342
|
-
)?;
|
|
1343
|
-
}
|
|
1344
|
-
GitCommands::Pull { args } => {
|
|
1345
|
-
git::run(
|
|
1346
|
-
git::GitCommand::Pull,
|
|
1347
|
-
&args,
|
|
1348
|
-
None,
|
|
1349
|
-
cli.verbose,
|
|
1350
|
-
&global_args,
|
|
1351
|
-
)?;
|
|
1352
|
-
}
|
|
1353
|
-
GitCommands::Branch { args } => {
|
|
1354
|
-
git::run(
|
|
1355
|
-
git::GitCommand::Branch,
|
|
1356
|
-
&args,
|
|
1357
|
-
None,
|
|
1358
|
-
cli.verbose,
|
|
1359
|
-
&global_args,
|
|
1360
|
-
)?;
|
|
1361
|
-
}
|
|
1362
|
-
GitCommands::Fetch { args } => {
|
|
1363
|
-
git::run(
|
|
1364
|
-
git::GitCommand::Fetch,
|
|
1365
|
-
&args,
|
|
1366
|
-
None,
|
|
1367
|
-
cli.verbose,
|
|
1368
|
-
&global_args,
|
|
1369
|
-
)?;
|
|
1370
|
-
}
|
|
1371
|
-
GitCommands::Stash { subcommand, args } => {
|
|
1372
|
-
git::run(
|
|
1373
|
-
git::GitCommand::Stash { subcommand },
|
|
1374
|
-
&args,
|
|
1375
|
-
None,
|
|
1376
|
-
cli.verbose,
|
|
1377
|
-
&global_args,
|
|
1378
|
-
)?;
|
|
1379
|
-
}
|
|
1380
|
-
GitCommands::Worktree { args } => {
|
|
1381
|
-
git::run(
|
|
1382
|
-
git::GitCommand::Worktree,
|
|
1383
|
-
&args,
|
|
1384
|
-
None,
|
|
1385
|
-
cli.verbose,
|
|
1386
|
-
&global_args,
|
|
1387
|
-
)?;
|
|
1388
|
-
}
|
|
1389
|
-
GitCommands::Other(args) => {
|
|
1390
|
-
git::run_passthrough(&args, &global_args, cli.verbose)?;
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
Commands::Gh { subcommand, args } => {
|
|
1396
|
-
gh_cmd::run(&subcommand, &args, cli.verbose, cli.ultra_compact)?;
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
Commands::Aws { subcommand, args } => {
|
|
1400
|
-
aws_cmd::run(&subcommand, &args, cli.verbose)?;
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
Commands::Psql { args } => {
|
|
1404
|
-
psql_cmd::run(&args, cli.verbose)?;
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
Commands::Pnpm { command } => match command {
|
|
1408
|
-
PnpmCommands::List { depth, args } => {
|
|
1409
|
-
pnpm_cmd::run(pnpm_cmd::PnpmCommand::List { depth }, &args, cli.verbose)?;
|
|
1410
|
-
}
|
|
1411
|
-
PnpmCommands::Outdated { args } => {
|
|
1412
|
-
pnpm_cmd::run(pnpm_cmd::PnpmCommand::Outdated, &args, cli.verbose)?;
|
|
1413
|
-
}
|
|
1414
|
-
PnpmCommands::Install { packages, args } => {
|
|
1415
|
-
pnpm_cmd::run(
|
|
1416
|
-
pnpm_cmd::PnpmCommand::Install { packages },
|
|
1417
|
-
&args,
|
|
1418
|
-
cli.verbose,
|
|
1419
|
-
)?;
|
|
1420
|
-
}
|
|
1421
|
-
PnpmCommands::Build { args } => {
|
|
1422
|
-
let mut build_args: Vec<String> = vec!["build".into()];
|
|
1423
|
-
build_args.extend(args);
|
|
1424
|
-
let os_args: Vec<OsString> = build_args.into_iter().map(OsString::from).collect();
|
|
1425
|
-
pnpm_cmd::run_passthrough(&os_args, cli.verbose)?;
|
|
1426
|
-
}
|
|
1427
|
-
PnpmCommands::Typecheck { args } => {
|
|
1428
|
-
tsc_cmd::run(&args, cli.verbose)?;
|
|
1429
|
-
}
|
|
1430
|
-
PnpmCommands::Other(args) => {
|
|
1431
|
-
pnpm_cmd::run_passthrough(&args, cli.verbose)?;
|
|
1432
|
-
}
|
|
1433
|
-
},
|
|
1434
|
-
|
|
1435
|
-
Commands::Err { command } => {
|
|
1436
|
-
let cmd = command.join(" ");
|
|
1437
|
-
runner::run_err(&cmd, cli.verbose)?;
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
Commands::Test { command } => {
|
|
1441
|
-
let cmd = command.join(" ");
|
|
1442
|
-
runner::run_test(&cmd, cli.verbose)?;
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
Commands::Json { file, depth } => {
|
|
1446
|
-
if file == Path::new("-") {
|
|
1447
|
-
json_cmd::run_stdin(depth, cli.verbose)?;
|
|
1448
|
-
} else {
|
|
1449
|
-
json_cmd::run(&file, depth, cli.verbose)?;
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
Commands::Deps { path } => {
|
|
1454
|
-
deps::run(&path, cli.verbose)?;
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
Commands::Env { filter, show_all } => {
|
|
1458
|
-
env_cmd::run(filter.as_deref(), show_all, cli.verbose)?;
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
Commands::Find { args } => {
|
|
1462
|
-
find_cmd::run_from_args(&args, cli.verbose)?;
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
Commands::Diff { file1, file2 } => {
|
|
1466
|
-
if let Some(f2) = file2 {
|
|
1467
|
-
diff_cmd::run(&file1, &f2, cli.verbose)?;
|
|
1468
|
-
} else {
|
|
1469
|
-
diff_cmd::run_stdin(cli.verbose)?;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
Commands::Log { file } => {
|
|
1474
|
-
if let Some(f) = file {
|
|
1475
|
-
log_cmd::run_file(&f, cli.verbose)?;
|
|
1476
|
-
} else {
|
|
1477
|
-
log_cmd::run_stdin(cli.verbose)?;
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
Commands::Dotnet { command } => match command {
|
|
1482
|
-
DotnetCommands::Build { args } => {
|
|
1483
|
-
dotnet_cmd::run_build(&args, cli.verbose)?;
|
|
1484
|
-
}
|
|
1485
|
-
DotnetCommands::Test { args } => {
|
|
1486
|
-
dotnet_cmd::run_test(&args, cli.verbose)?;
|
|
1487
|
-
}
|
|
1488
|
-
DotnetCommands::Restore { args } => {
|
|
1489
|
-
dotnet_cmd::run_restore(&args, cli.verbose)?;
|
|
1490
|
-
}
|
|
1491
|
-
DotnetCommands::Format { args } => {
|
|
1492
|
-
dotnet_cmd::run_format(&args, cli.verbose)?;
|
|
1493
|
-
}
|
|
1494
|
-
DotnetCommands::Other(args) => {
|
|
1495
|
-
dotnet_cmd::run_passthrough(&args, cli.verbose)?;
|
|
1496
|
-
}
|
|
1497
|
-
},
|
|
1498
|
-
|
|
1499
|
-
Commands::Docker { command } => match command {
|
|
1500
|
-
DockerCommands::Ps => {
|
|
1501
|
-
container::run(container::ContainerCmd::DockerPs, &[], cli.verbose)?;
|
|
1502
|
-
}
|
|
1503
|
-
DockerCommands::Images => {
|
|
1504
|
-
container::run(container::ContainerCmd::DockerImages, &[], cli.verbose)?;
|
|
1505
|
-
}
|
|
1506
|
-
DockerCommands::Logs { container: c } => {
|
|
1507
|
-
container::run(container::ContainerCmd::DockerLogs, &[c], cli.verbose)?;
|
|
1508
|
-
}
|
|
1509
|
-
DockerCommands::Compose { command: compose } => match compose {
|
|
1510
|
-
ComposeCommands::Ps => {
|
|
1511
|
-
container::run_compose_ps(cli.verbose)?;
|
|
1512
|
-
}
|
|
1513
|
-
ComposeCommands::Logs { service } => {
|
|
1514
|
-
container::run_compose_logs(service.as_deref(), cli.verbose)?;
|
|
1515
|
-
}
|
|
1516
|
-
ComposeCommands::Build { service } => {
|
|
1517
|
-
container::run_compose_build(service.as_deref(), cli.verbose)?;
|
|
1518
|
-
}
|
|
1519
|
-
ComposeCommands::Other(args) => {
|
|
1520
|
-
container::run_compose_passthrough(&args, cli.verbose)?;
|
|
1521
|
-
}
|
|
1522
|
-
},
|
|
1523
|
-
DockerCommands::Other(args) => {
|
|
1524
|
-
container::run_docker_passthrough(&args, cli.verbose)?;
|
|
1525
|
-
}
|
|
1526
|
-
},
|
|
1527
|
-
|
|
1528
|
-
Commands::Kubectl { command } => match command {
|
|
1529
|
-
KubectlCommands::Pods { namespace, all } => {
|
|
1530
|
-
let mut args: Vec<String> = Vec::new();
|
|
1531
|
-
if all {
|
|
1532
|
-
args.push("-A".to_string());
|
|
1533
|
-
} else if let Some(n) = namespace {
|
|
1534
|
-
args.push("-n".to_string());
|
|
1535
|
-
args.push(n);
|
|
1536
|
-
}
|
|
1537
|
-
container::run(container::ContainerCmd::KubectlPods, &args, cli.verbose)?;
|
|
1538
|
-
}
|
|
1539
|
-
KubectlCommands::Services { namespace, all } => {
|
|
1540
|
-
let mut args: Vec<String> = Vec::new();
|
|
1541
|
-
if all {
|
|
1542
|
-
args.push("-A".to_string());
|
|
1543
|
-
} else if let Some(n) = namespace {
|
|
1544
|
-
args.push("-n".to_string());
|
|
1545
|
-
args.push(n);
|
|
1546
|
-
}
|
|
1547
|
-
container::run(container::ContainerCmd::KubectlServices, &args, cli.verbose)?;
|
|
1548
|
-
}
|
|
1549
|
-
KubectlCommands::Logs { pod, container: c } => {
|
|
1550
|
-
let mut args = vec![pod];
|
|
1551
|
-
if let Some(cont) = c {
|
|
1552
|
-
args.push("-c".to_string());
|
|
1553
|
-
args.push(cont);
|
|
1554
|
-
}
|
|
1555
|
-
container::run(container::ContainerCmd::KubectlLogs, &args, cli.verbose)?;
|
|
1556
|
-
}
|
|
1557
|
-
KubectlCommands::Other(args) => {
|
|
1558
|
-
container::run_kubectl_passthrough(&args, cli.verbose)?;
|
|
1559
|
-
}
|
|
1560
|
-
},
|
|
1561
|
-
|
|
1562
|
-
Commands::Summary { command } => {
|
|
1563
|
-
let cmd = command.join(" ");
|
|
1564
|
-
summary::run(&cmd, cli.verbose)?;
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
Commands::Grep {
|
|
1568
|
-
pattern,
|
|
1569
|
-
path,
|
|
1570
|
-
max_len,
|
|
1571
|
-
max,
|
|
1572
|
-
context_only,
|
|
1573
|
-
file_type,
|
|
1574
|
-
line_numbers: _, // no-op: line numbers always enabled in grep_cmd::run
|
|
1575
|
-
extra_args,
|
|
1576
|
-
} => {
|
|
1577
|
-
grep_cmd::run(
|
|
1578
|
-
&pattern,
|
|
1579
|
-
&path,
|
|
1580
|
-
max_len,
|
|
1581
|
-
max,
|
|
1582
|
-
context_only,
|
|
1583
|
-
file_type.as_deref(),
|
|
1584
|
-
&extra_args,
|
|
1585
|
-
cli.verbose,
|
|
1586
|
-
)?;
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
Commands::Init {
|
|
1590
|
-
global,
|
|
1591
|
-
opencode,
|
|
1592
|
-
show,
|
|
1593
|
-
claude_md,
|
|
1594
|
-
hook_only,
|
|
1595
|
-
auto_patch,
|
|
1596
|
-
no_patch,
|
|
1597
|
-
uninstall,
|
|
1598
|
-
} => {
|
|
1599
|
-
if show {
|
|
1600
|
-
init::show_config()?;
|
|
1601
|
-
} else if uninstall {
|
|
1602
|
-
init::uninstall(global, cli.verbose)?;
|
|
1603
|
-
} else {
|
|
1604
|
-
let install_opencode = opencode;
|
|
1605
|
-
let install_claude = !opencode;
|
|
1606
|
-
|
|
1607
|
-
let patch_mode = if auto_patch {
|
|
1608
|
-
init::PatchMode::Auto
|
|
1609
|
-
} else if no_patch {
|
|
1610
|
-
init::PatchMode::Skip
|
|
1611
|
-
} else {
|
|
1612
|
-
init::PatchMode::Ask
|
|
1613
|
-
};
|
|
1614
|
-
init::run(
|
|
1615
|
-
global,
|
|
1616
|
-
install_claude,
|
|
1617
|
-
install_opencode,
|
|
1618
|
-
claude_md,
|
|
1619
|
-
hook_only,
|
|
1620
|
-
patch_mode,
|
|
1621
|
-
cli.verbose,
|
|
1622
|
-
)?;
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
Commands::Wget { url, stdout, args } => {
|
|
1627
|
-
if stdout {
|
|
1628
|
-
wget_cmd::run_stdout(&url, &args, cli.verbose)?;
|
|
1629
|
-
} else {
|
|
1630
|
-
wget_cmd::run(&url, &args, cli.verbose)?;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
Commands::Wc { args } => {
|
|
1635
|
-
wc_cmd::run(&args, cli.verbose)?;
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
Commands::Gain {
|
|
1639
|
-
project, // added
|
|
1640
|
-
graph,
|
|
1641
|
-
history,
|
|
1642
|
-
quota,
|
|
1643
|
-
tier,
|
|
1644
|
-
daily,
|
|
1645
|
-
weekly,
|
|
1646
|
-
monthly,
|
|
1647
|
-
all,
|
|
1648
|
-
format,
|
|
1649
|
-
failures,
|
|
1650
|
-
} => {
|
|
1651
|
-
gain::run(
|
|
1652
|
-
project, // added: pass project flag
|
|
1653
|
-
graph,
|
|
1654
|
-
history,
|
|
1655
|
-
quota,
|
|
1656
|
-
&tier,
|
|
1657
|
-
daily,
|
|
1658
|
-
weekly,
|
|
1659
|
-
monthly,
|
|
1660
|
-
all,
|
|
1661
|
-
&format,
|
|
1662
|
-
failures,
|
|
1663
|
-
cli.verbose,
|
|
1664
|
-
)?;
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
Commands::CcEconomics {
|
|
1668
|
-
daily,
|
|
1669
|
-
weekly,
|
|
1670
|
-
monthly,
|
|
1671
|
-
all,
|
|
1672
|
-
format,
|
|
1673
|
-
} => {
|
|
1674
|
-
cc_economics::run(daily, weekly, monthly, all, &format, cli.verbose)?;
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
Commands::Config { create } => {
|
|
1678
|
-
if create {
|
|
1679
|
-
let path = config::Config::create_default()?;
|
|
1680
|
-
println!("Created: {}", path.display());
|
|
1681
|
-
} else {
|
|
1682
|
-
config::show_config()?;
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
Commands::Vitest { command } => match command {
|
|
1687
|
-
VitestCommands::Run { args } => {
|
|
1688
|
-
vitest_cmd::run(vitest_cmd::VitestCommand::Run, &args, cli.verbose)?;
|
|
1689
|
-
}
|
|
1690
|
-
},
|
|
1691
|
-
|
|
1692
|
-
Commands::Prisma { command } => match command {
|
|
1693
|
-
PrismaCommands::Generate { args } => {
|
|
1694
|
-
prisma_cmd::run(prisma_cmd::PrismaCommand::Generate, &args, cli.verbose)?;
|
|
1695
|
-
}
|
|
1696
|
-
PrismaCommands::Migrate { command } => match command {
|
|
1697
|
-
PrismaMigrateCommands::Dev { name, args } => {
|
|
1698
|
-
prisma_cmd::run(
|
|
1699
|
-
prisma_cmd::PrismaCommand::Migrate {
|
|
1700
|
-
subcommand: prisma_cmd::MigrateSubcommand::Dev { name },
|
|
1701
|
-
},
|
|
1702
|
-
&args,
|
|
1703
|
-
cli.verbose,
|
|
1704
|
-
)?;
|
|
1705
|
-
}
|
|
1706
|
-
PrismaMigrateCommands::Status { args } => {
|
|
1707
|
-
prisma_cmd::run(
|
|
1708
|
-
prisma_cmd::PrismaCommand::Migrate {
|
|
1709
|
-
subcommand: prisma_cmd::MigrateSubcommand::Status,
|
|
1710
|
-
},
|
|
1711
|
-
&args,
|
|
1712
|
-
cli.verbose,
|
|
1713
|
-
)?;
|
|
1714
|
-
}
|
|
1715
|
-
PrismaMigrateCommands::Deploy { args } => {
|
|
1716
|
-
prisma_cmd::run(
|
|
1717
|
-
prisma_cmd::PrismaCommand::Migrate {
|
|
1718
|
-
subcommand: prisma_cmd::MigrateSubcommand::Deploy,
|
|
1719
|
-
},
|
|
1720
|
-
&args,
|
|
1721
|
-
cli.verbose,
|
|
1722
|
-
)?;
|
|
1723
|
-
}
|
|
1724
|
-
},
|
|
1725
|
-
PrismaCommands::DbPush { args } => {
|
|
1726
|
-
prisma_cmd::run(prisma_cmd::PrismaCommand::DbPush, &args, cli.verbose)?;
|
|
1727
|
-
}
|
|
1728
|
-
},
|
|
1729
|
-
|
|
1730
|
-
Commands::Tsc { args } => {
|
|
1731
|
-
tsc_cmd::run(&args, cli.verbose)?;
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
Commands::Next { args } => {
|
|
1735
|
-
next_cmd::run(&args, cli.verbose)?;
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
Commands::Lint { args } => {
|
|
1739
|
-
lint_cmd::run(&args, cli.verbose)?;
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
Commands::Prettier { args } => {
|
|
1743
|
-
prettier_cmd::run(&args, cli.verbose)?;
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
Commands::Format { args } => {
|
|
1747
|
-
format_cmd::run(&args, cli.verbose)?;
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
Commands::Playwright { args } => {
|
|
1751
|
-
playwright_cmd::run(&args, cli.verbose)?;
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
Commands::Cargo { command } => match command {
|
|
1755
|
-
CargoCommands::Build { args } => {
|
|
1756
|
-
cargo_cmd::run(cargo_cmd::CargoCommand::Build, &args, cli.verbose)?;
|
|
1757
|
-
}
|
|
1758
|
-
CargoCommands::Test { args } => {
|
|
1759
|
-
cargo_cmd::run(cargo_cmd::CargoCommand::Test, &args, cli.verbose)?;
|
|
1760
|
-
}
|
|
1761
|
-
CargoCommands::Clippy { args } => {
|
|
1762
|
-
cargo_cmd::run(cargo_cmd::CargoCommand::Clippy, &args, cli.verbose)?;
|
|
1763
|
-
}
|
|
1764
|
-
CargoCommands::Check { args } => {
|
|
1765
|
-
cargo_cmd::run(cargo_cmd::CargoCommand::Check, &args, cli.verbose)?;
|
|
1766
|
-
}
|
|
1767
|
-
CargoCommands::Install { args } => {
|
|
1768
|
-
cargo_cmd::run(cargo_cmd::CargoCommand::Install, &args, cli.verbose)?;
|
|
1769
|
-
}
|
|
1770
|
-
CargoCommands::Nextest { args } => {
|
|
1771
|
-
cargo_cmd::run(cargo_cmd::CargoCommand::Nextest, &args, cli.verbose)?;
|
|
1772
|
-
}
|
|
1773
|
-
CargoCommands::Other(args) => {
|
|
1774
|
-
cargo_cmd::run_passthrough(&args, cli.verbose)?;
|
|
1775
|
-
}
|
|
1776
|
-
},
|
|
1777
|
-
|
|
1778
|
-
Commands::Npm { args } => {
|
|
1779
|
-
npm_cmd::run(&args, cli.verbose, cli.skip_env)?;
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
|
-
Commands::Curl { args } => {
|
|
1783
|
-
curl_cmd::run(&args, cli.verbose)?;
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
Commands::Discover {
|
|
1787
|
-
project,
|
|
1788
|
-
limit,
|
|
1789
|
-
all,
|
|
1790
|
-
since,
|
|
1791
|
-
format,
|
|
1792
|
-
} => {
|
|
1793
|
-
discover::run(project.as_deref(), all, since, limit, &format, cli.verbose)?;
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
Commands::Learn {
|
|
1797
|
-
project,
|
|
1798
|
-
all,
|
|
1799
|
-
since,
|
|
1800
|
-
format,
|
|
1801
|
-
write_rules,
|
|
1802
|
-
min_confidence,
|
|
1803
|
-
min_occurrences,
|
|
1804
|
-
} => {
|
|
1805
|
-
learn::run(
|
|
1806
|
-
project,
|
|
1807
|
-
all,
|
|
1808
|
-
since,
|
|
1809
|
-
format,
|
|
1810
|
-
write_rules,
|
|
1811
|
-
min_confidence,
|
|
1812
|
-
min_occurrences,
|
|
1813
|
-
)?;
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
Commands::Npx { args } => {
|
|
1817
|
-
if args.is_empty() {
|
|
1818
|
-
anyhow::bail!("npx requires a command argument");
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
// Intelligent routing: delegate to specialized filters
|
|
1822
|
-
match args[0].as_str() {
|
|
1823
|
-
"tsc" | "typescript" => {
|
|
1824
|
-
tsc_cmd::run(&args[1..], cli.verbose)?;
|
|
1825
|
-
}
|
|
1826
|
-
"eslint" => {
|
|
1827
|
-
lint_cmd::run(&args[1..], cli.verbose)?;
|
|
1828
|
-
}
|
|
1829
|
-
"prisma" => {
|
|
1830
|
-
// Route to prisma_cmd based on subcommand
|
|
1831
|
-
if args.len() > 1 {
|
|
1832
|
-
let prisma_args: Vec<String> = args[2..].to_vec();
|
|
1833
|
-
match args[1].as_str() {
|
|
1834
|
-
"generate" => {
|
|
1835
|
-
prisma_cmd::run(
|
|
1836
|
-
prisma_cmd::PrismaCommand::Generate,
|
|
1837
|
-
&prisma_args,
|
|
1838
|
-
cli.verbose,
|
|
1839
|
-
)?;
|
|
1840
|
-
}
|
|
1841
|
-
"db" if args.len() > 2 && args[2] == "push" => {
|
|
1842
|
-
prisma_cmd::run(
|
|
1843
|
-
prisma_cmd::PrismaCommand::DbPush,
|
|
1844
|
-
&args[3..],
|
|
1845
|
-
cli.verbose,
|
|
1846
|
-
)?;
|
|
1847
|
-
}
|
|
1848
|
-
_ => {
|
|
1849
|
-
// Passthrough other prisma subcommands
|
|
1850
|
-
let timer = tracking::TimedExecution::start();
|
|
1851
|
-
let mut cmd = std::process::Command::new("npx");
|
|
1852
|
-
for arg in &args {
|
|
1853
|
-
cmd.arg(arg);
|
|
1854
|
-
}
|
|
1855
|
-
let status = cmd.status().context("Failed to run npx prisma")?;
|
|
1856
|
-
let args_str = args.join(" ");
|
|
1857
|
-
timer.track_passthrough(
|
|
1858
|
-
&format!("npx {}", args_str),
|
|
1859
|
-
&format!("rtk npx {} (passthrough)", args_str),
|
|
1860
|
-
);
|
|
1861
|
-
if !status.success() {
|
|
1862
|
-
std::process::exit(status.code().unwrap_or(1));
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
} else {
|
|
1867
|
-
let timer = tracking::TimedExecution::start();
|
|
1868
|
-
let status = std::process::Command::new("npx")
|
|
1869
|
-
.arg("prisma")
|
|
1870
|
-
.status()
|
|
1871
|
-
.context("Failed to run npx prisma")?;
|
|
1872
|
-
timer.track_passthrough("npx prisma", "rtk npx prisma (passthrough)");
|
|
1873
|
-
if !status.success() {
|
|
1874
|
-
std::process::exit(status.code().unwrap_or(1));
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
"next" => {
|
|
1879
|
-
next_cmd::run(&args[1..], cli.verbose)?;
|
|
1880
|
-
}
|
|
1881
|
-
"prettier" => {
|
|
1882
|
-
prettier_cmd::run(&args[1..], cli.verbose)?;
|
|
1883
|
-
}
|
|
1884
|
-
"playwright" => {
|
|
1885
|
-
playwright_cmd::run(&args[1..], cli.verbose)?;
|
|
1886
|
-
}
|
|
1887
|
-
_ => {
|
|
1888
|
-
// Generic passthrough with npm boilerplate filter
|
|
1889
|
-
npm_cmd::run(&args, cli.verbose, cli.skip_env)?;
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
Commands::Ruff { args } => {
|
|
1895
|
-
ruff_cmd::run(&args, cli.verbose)?;
|
|
1896
|
-
}
|
|
1897
|
-
|
|
1898
|
-
Commands::Pytest { args } => {
|
|
1899
|
-
pytest_cmd::run(&args, cli.verbose)?;
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
Commands::Mypy { args } => {
|
|
1903
|
-
mypy_cmd::run(&args, cli.verbose)?;
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
Commands::Pip { args } => {
|
|
1907
|
-
pip_cmd::run(&args, cli.verbose)?;
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
Commands::Go { command } => match command {
|
|
1911
|
-
GoCommands::Test { args } => {
|
|
1912
|
-
go_cmd::run_test(&args, cli.verbose)?;
|
|
1913
|
-
}
|
|
1914
|
-
GoCommands::Build { args } => {
|
|
1915
|
-
go_cmd::run_build(&args, cli.verbose)?;
|
|
1916
|
-
}
|
|
1917
|
-
GoCommands::Vet { args } => {
|
|
1918
|
-
go_cmd::run_vet(&args, cli.verbose)?;
|
|
1919
|
-
}
|
|
1920
|
-
GoCommands::Other(args) => {
|
|
1921
|
-
go_cmd::run_other(&args, cli.verbose)?;
|
|
1922
|
-
}
|
|
1923
|
-
},
|
|
1924
|
-
|
|
1925
|
-
Commands::Gt { command } => match command {
|
|
1926
|
-
GtCommands::Log { args } => {
|
|
1927
|
-
gt_cmd::run_log(&args, cli.verbose)?;
|
|
1928
|
-
}
|
|
1929
|
-
GtCommands::Submit { args } => {
|
|
1930
|
-
gt_cmd::run_submit(&args, cli.verbose)?;
|
|
1931
|
-
}
|
|
1932
|
-
GtCommands::Sync { args } => {
|
|
1933
|
-
gt_cmd::run_sync(&args, cli.verbose)?;
|
|
1934
|
-
}
|
|
1935
|
-
GtCommands::Restack { args } => {
|
|
1936
|
-
gt_cmd::run_restack(&args, cli.verbose)?;
|
|
1937
|
-
}
|
|
1938
|
-
GtCommands::Create { args } => {
|
|
1939
|
-
gt_cmd::run_create(&args, cli.verbose)?;
|
|
1940
|
-
}
|
|
1941
|
-
GtCommands::Branch { args } => {
|
|
1942
|
-
gt_cmd::run_branch(&args, cli.verbose)?;
|
|
1943
|
-
}
|
|
1944
|
-
GtCommands::Other(args) => {
|
|
1945
|
-
gt_cmd::run_other(&args, cli.verbose)?;
|
|
1946
|
-
}
|
|
1947
|
-
},
|
|
1948
|
-
|
|
1949
|
-
Commands::GolangciLint { args } => {
|
|
1950
|
-
golangci_cmd::run(&args, cli.verbose)?;
|
|
1951
|
-
}
|
|
1952
|
-
|
|
1953
|
-
Commands::HookAudit { since } => {
|
|
1954
|
-
hook_audit_cmd::run(since, cli.verbose)?;
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
Commands::Rewrite { args } => {
|
|
1958
|
-
let cmd = args.join(" ");
|
|
1959
|
-
rewrite_cmd::run(&cmd)?;
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
Commands::Proxy { args } => {
|
|
1963
|
-
use std::io::{Read, Write};
|
|
1964
|
-
use std::process::{Command, Stdio};
|
|
1965
|
-
use std::thread;
|
|
1966
|
-
|
|
1967
|
-
if args.is_empty() {
|
|
1968
|
-
anyhow::bail!(
|
|
1969
|
-
"proxy requires a command to execute\nUsage: rtk proxy <command> [args...]"
|
|
1970
|
-
);
|
|
1971
|
-
}
|
|
1972
|
-
|
|
1973
|
-
let timer = tracking::TimedExecution::start();
|
|
1974
|
-
|
|
1975
|
-
// If a single quoted arg contains spaces, split it respecting quotes (#388).
|
|
1976
|
-
// e.g. rtk proxy 'head -50 file.php' → cmd=head, args=["-50", "file.php"]
|
|
1977
|
-
// e.g. rtk proxy 'git log --format="%H %s"' → cmd=git, args=["log", "--format=%H %s"]
|
|
1978
|
-
let (cmd_name, cmd_args): (String, Vec<String>) = if args.len() == 1 {
|
|
1979
|
-
let full = args[0].to_string_lossy();
|
|
1980
|
-
let parts = shell_split(&full);
|
|
1981
|
-
if parts.len() > 1 {
|
|
1982
|
-
(parts[0].clone(), parts[1..].to_vec())
|
|
1983
|
-
} else {
|
|
1984
|
-
(full.into_owned(), vec![])
|
|
1985
|
-
}
|
|
1986
|
-
} else {
|
|
1987
|
-
(
|
|
1988
|
-
args[0].to_string_lossy().into_owned(),
|
|
1989
|
-
args[1..]
|
|
1990
|
-
.iter()
|
|
1991
|
-
.map(|s| s.to_string_lossy().into_owned())
|
|
1992
|
-
.collect(),
|
|
1993
|
-
)
|
|
1994
|
-
};
|
|
1995
|
-
|
|
1996
|
-
if cli.verbose > 0 {
|
|
1997
|
-
eprintln!("Proxy mode: {} {}", cmd_name, cmd_args.join(" "));
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
let mut child = Command::new(&cmd_name)
|
|
2001
|
-
.args(&cmd_args)
|
|
2002
|
-
.stdout(Stdio::piped())
|
|
2003
|
-
.stderr(Stdio::piped())
|
|
2004
|
-
.spawn()
|
|
2005
|
-
.context(format!("Failed to execute command: {}", cmd_name))?;
|
|
2006
|
-
|
|
2007
|
-
let stdout_pipe = child
|
|
2008
|
-
.stdout
|
|
2009
|
-
.take()
|
|
2010
|
-
.context("Failed to capture child stdout")?;
|
|
2011
|
-
let stderr_pipe = child
|
|
2012
|
-
.stderr
|
|
2013
|
-
.take()
|
|
2014
|
-
.context("Failed to capture child stderr")?;
|
|
2015
|
-
|
|
2016
|
-
let stdout_handle = thread::spawn(move || -> std::io::Result<Vec<u8>> {
|
|
2017
|
-
let mut reader = stdout_pipe;
|
|
2018
|
-
let mut captured = Vec::new();
|
|
2019
|
-
let mut buf = [0u8; 8192];
|
|
2020
|
-
|
|
2021
|
-
loop {
|
|
2022
|
-
let count = reader.read(&mut buf)?;
|
|
2023
|
-
if count == 0 {
|
|
2024
|
-
break;
|
|
2025
|
-
}
|
|
2026
|
-
captured.extend_from_slice(&buf[..count]);
|
|
2027
|
-
let mut out = std::io::stdout().lock();
|
|
2028
|
-
out.write_all(&buf[..count])?;
|
|
2029
|
-
out.flush()?;
|
|
2030
|
-
}
|
|
2031
|
-
|
|
2032
|
-
Ok(captured)
|
|
2033
|
-
});
|
|
2034
|
-
|
|
2035
|
-
let stderr_handle = thread::spawn(move || -> std::io::Result<Vec<u8>> {
|
|
2036
|
-
let mut reader = stderr_pipe;
|
|
2037
|
-
let mut captured = Vec::new();
|
|
2038
|
-
let mut buf = [0u8; 8192];
|
|
2039
|
-
|
|
2040
|
-
loop {
|
|
2041
|
-
let count = reader.read(&mut buf)?;
|
|
2042
|
-
if count == 0 {
|
|
2043
|
-
break;
|
|
2044
|
-
}
|
|
2045
|
-
captured.extend_from_slice(&buf[..count]);
|
|
2046
|
-
let mut err = std::io::stderr().lock();
|
|
2047
|
-
err.write_all(&buf[..count])?;
|
|
2048
|
-
err.flush()?;
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
|
-
Ok(captured)
|
|
2052
|
-
});
|
|
2053
|
-
|
|
2054
|
-
let status = child
|
|
2055
|
-
.wait()
|
|
2056
|
-
.context(format!("Failed waiting for command: {}", cmd_name))?;
|
|
2057
|
-
|
|
2058
|
-
let stdout_bytes = stdout_handle
|
|
2059
|
-
.join()
|
|
2060
|
-
.map_err(|_| anyhow::anyhow!("stdout streaming thread panicked"))??;
|
|
2061
|
-
let stderr_bytes = stderr_handle
|
|
2062
|
-
.join()
|
|
2063
|
-
.map_err(|_| anyhow::anyhow!("stderr streaming thread panicked"))??;
|
|
2064
|
-
|
|
2065
|
-
let stdout = String::from_utf8_lossy(&stdout_bytes);
|
|
2066
|
-
let stderr = String::from_utf8_lossy(&stderr_bytes);
|
|
2067
|
-
let full_output = format!("{}{}", stdout, stderr);
|
|
2068
|
-
|
|
2069
|
-
// Track usage (input = output since no filtering)
|
|
2070
|
-
timer.track(
|
|
2071
|
-
&format!("{} {}", cmd_name, cmd_args.join(" ")),
|
|
2072
|
-
&format!("rtk proxy {} {}", cmd_name, cmd_args.join(" ")),
|
|
2073
|
-
&full_output,
|
|
2074
|
-
&full_output,
|
|
2075
|
-
);
|
|
2076
|
-
|
|
2077
|
-
// Exit with same code as child process
|
|
2078
|
-
if !status.success() {
|
|
2079
|
-
std::process::exit(status.code().unwrap_or(1));
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
|
|
2083
|
-
Commands::Verify {
|
|
2084
|
-
filter,
|
|
2085
|
-
require_all,
|
|
2086
|
-
} => {
|
|
2087
|
-
if filter.is_some() {
|
|
2088
|
-
// Filter-specific mode: run only that filter's tests
|
|
2089
|
-
verify_cmd::run(filter, require_all)?;
|
|
2090
|
-
} else {
|
|
2091
|
-
// Default or --require-all: always run integrity check first
|
|
2092
|
-
integrity::run_verify(cli.verbose)?;
|
|
2093
|
-
verify_cmd::run(None, require_all)?;
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
|
|
2098
|
-
Ok(())
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
|
-
/// Returns true for commands that are invoked via the hook pipeline
|
|
2102
|
-
/// (i.e., commands that process rewritten shell commands).
|
|
2103
|
-
/// Meta commands (init, gain, verify, etc.) are excluded because
|
|
2104
|
-
/// they are run directly by the user, not through the hook.
|
|
2105
|
-
/// Returns true for commands that go through the hook pipeline
|
|
2106
|
-
/// and therefore require integrity verification.
|
|
2107
|
-
///
|
|
2108
|
-
/// SECURITY: whitelist pattern — new commands are NOT integrity-checked
|
|
2109
|
-
/// until explicitly added here. A forgotten command fails open (no check)
|
|
2110
|
-
/// rather than creating false confidence about what's protected.
|
|
2111
|
-
fn is_operational_command(cmd: &Commands) -> bool {
|
|
2112
|
-
matches!(
|
|
2113
|
-
cmd,
|
|
2114
|
-
Commands::Ls { .. }
|
|
2115
|
-
| Commands::Tree { .. }
|
|
2116
|
-
| Commands::Read { .. }
|
|
2117
|
-
| Commands::Smart { .. }
|
|
2118
|
-
| Commands::Git { .. }
|
|
2119
|
-
| Commands::Gh { .. }
|
|
2120
|
-
| Commands::Pnpm { .. }
|
|
2121
|
-
| Commands::Err { .. }
|
|
2122
|
-
| Commands::Test { .. }
|
|
2123
|
-
| Commands::Json { .. }
|
|
2124
|
-
| Commands::Deps { .. }
|
|
2125
|
-
| Commands::Env { .. }
|
|
2126
|
-
| Commands::Find { .. }
|
|
2127
|
-
| Commands::Diff { .. }
|
|
2128
|
-
| Commands::Log { .. }
|
|
2129
|
-
| Commands::Dotnet { .. }
|
|
2130
|
-
| Commands::Docker { .. }
|
|
2131
|
-
| Commands::Kubectl { .. }
|
|
2132
|
-
| Commands::Summary { .. }
|
|
2133
|
-
| Commands::Grep { .. }
|
|
2134
|
-
| Commands::Wget { .. }
|
|
2135
|
-
| Commands::Vitest { .. }
|
|
2136
|
-
| Commands::Prisma { .. }
|
|
2137
|
-
| Commands::Tsc { .. }
|
|
2138
|
-
| Commands::Next { .. }
|
|
2139
|
-
| Commands::Lint { .. }
|
|
2140
|
-
| Commands::Prettier { .. }
|
|
2141
|
-
| Commands::Playwright { .. }
|
|
2142
|
-
| Commands::Cargo { .. }
|
|
2143
|
-
| Commands::Npm { .. }
|
|
2144
|
-
| Commands::Npx { .. }
|
|
2145
|
-
| Commands::Curl { .. }
|
|
2146
|
-
| Commands::Ruff { .. }
|
|
2147
|
-
| Commands::Pytest { .. }
|
|
2148
|
-
| Commands::Pip { .. }
|
|
2149
|
-
| Commands::Go { .. }
|
|
2150
|
-
| Commands::GolangciLint { .. }
|
|
2151
|
-
| Commands::Gt { .. }
|
|
2152
|
-
)
|
|
2153
|
-
}
|
|
2154
|
-
|
|
2155
|
-
#[cfg(test)]
|
|
2156
|
-
mod tests {
|
|
2157
|
-
use super::*;
|
|
2158
|
-
use clap::Parser;
|
|
2159
|
-
|
|
2160
|
-
#[test]
|
|
2161
|
-
fn test_git_commit_single_message() {
|
|
2162
|
-
let cli = Cli::try_parse_from(["rtk", "git", "commit", "-m", "fix: typo"]).unwrap();
|
|
2163
|
-
match cli.command {
|
|
2164
|
-
Commands::Git {
|
|
2165
|
-
command: GitCommands::Commit { args },
|
|
2166
|
-
..
|
|
2167
|
-
} => {
|
|
2168
|
-
assert_eq!(args, vec!["-m", "fix: typo"]);
|
|
2169
|
-
}
|
|
2170
|
-
_ => panic!("Expected Git Commit command"),
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
#[test]
|
|
2175
|
-
fn test_git_commit_multiple_messages() {
|
|
2176
|
-
let cli = Cli::try_parse_from([
|
|
2177
|
-
"rtk",
|
|
2178
|
-
"git",
|
|
2179
|
-
"commit",
|
|
2180
|
-
"-m",
|
|
2181
|
-
"feat: add support",
|
|
2182
|
-
"-m",
|
|
2183
|
-
"Body paragraph here.",
|
|
2184
|
-
])
|
|
2185
|
-
.unwrap();
|
|
2186
|
-
match cli.command {
|
|
2187
|
-
Commands::Git {
|
|
2188
|
-
command: GitCommands::Commit { args },
|
|
2189
|
-
..
|
|
2190
|
-
} => {
|
|
2191
|
-
assert_eq!(
|
|
2192
|
-
args,
|
|
2193
|
-
vec!["-m", "feat: add support", "-m", "Body paragraph here."]
|
|
2194
|
-
);
|
|
2195
|
-
}
|
|
2196
|
-
_ => panic!("Expected Git Commit command"),
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
|
|
2200
|
-
// #327: git commit -am "msg" was rejected by Clap
|
|
2201
|
-
#[test]
|
|
2202
|
-
fn test_git_commit_am_flag() {
|
|
2203
|
-
let cli = Cli::try_parse_from(["rtk", "git", "commit", "-am", "quick fix"]).unwrap();
|
|
2204
|
-
match cli.command {
|
|
2205
|
-
Commands::Git {
|
|
2206
|
-
command: GitCommands::Commit { args },
|
|
2207
|
-
..
|
|
2208
|
-
} => {
|
|
2209
|
-
assert_eq!(args, vec!["-am", "quick fix"]);
|
|
2210
|
-
}
|
|
2211
|
-
_ => panic!("Expected Git Commit command"),
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
#[test]
|
|
2216
|
-
fn test_git_commit_amend() {
|
|
2217
|
-
let cli =
|
|
2218
|
-
Cli::try_parse_from(["rtk", "git", "commit", "--amend", "-m", "new msg"]).unwrap();
|
|
2219
|
-
match cli.command {
|
|
2220
|
-
Commands::Git {
|
|
2221
|
-
command: GitCommands::Commit { args },
|
|
2222
|
-
..
|
|
2223
|
-
} => {
|
|
2224
|
-
assert_eq!(args, vec!["--amend", "-m", "new msg"]);
|
|
2225
|
-
}
|
|
2226
|
-
_ => panic!("Expected Git Commit command"),
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
|
-
#[test]
|
|
2231
|
-
fn test_git_global_options_parsing() {
|
|
2232
|
-
let cli =
|
|
2233
|
-
Cli::try_parse_from(["rtk", "git", "--no-pager", "--no-optional-locks", "status"])
|
|
2234
|
-
.unwrap();
|
|
2235
|
-
match cli.command {
|
|
2236
|
-
Commands::Git {
|
|
2237
|
-
no_pager,
|
|
2238
|
-
no_optional_locks,
|
|
2239
|
-
bare,
|
|
2240
|
-
literal_pathspecs,
|
|
2241
|
-
..
|
|
2242
|
-
} => {
|
|
2243
|
-
assert!(no_pager);
|
|
2244
|
-
assert!(no_optional_locks);
|
|
2245
|
-
assert!(!bare);
|
|
2246
|
-
assert!(!literal_pathspecs);
|
|
2247
|
-
}
|
|
2248
|
-
_ => panic!("Expected Git command"),
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
|
|
2252
|
-
#[test]
|
|
2253
|
-
fn test_git_commit_long_flag_multiple() {
|
|
2254
|
-
let cli = Cli::try_parse_from([
|
|
2255
|
-
"rtk",
|
|
2256
|
-
"git",
|
|
2257
|
-
"commit",
|
|
2258
|
-
"--message",
|
|
2259
|
-
"title",
|
|
2260
|
-
"--message",
|
|
2261
|
-
"body",
|
|
2262
|
-
"--message",
|
|
2263
|
-
"footer",
|
|
2264
|
-
])
|
|
2265
|
-
.unwrap();
|
|
2266
|
-
match cli.command {
|
|
2267
|
-
Commands::Git {
|
|
2268
|
-
command: GitCommands::Commit { args },
|
|
2269
|
-
..
|
|
2270
|
-
} => {
|
|
2271
|
-
assert_eq!(
|
|
2272
|
-
args,
|
|
2273
|
-
vec![
|
|
2274
|
-
"--message",
|
|
2275
|
-
"title",
|
|
2276
|
-
"--message",
|
|
2277
|
-
"body",
|
|
2278
|
-
"--message",
|
|
2279
|
-
"footer"
|
|
2280
|
-
]
|
|
2281
|
-
);
|
|
2282
|
-
}
|
|
2283
|
-
_ => panic!("Expected Git Commit command"),
|
|
2284
|
-
}
|
|
2285
|
-
}
|
|
2286
|
-
|
|
2287
|
-
#[test]
|
|
2288
|
-
fn test_try_parse_valid_git_status() {
|
|
2289
|
-
let result = Cli::try_parse_from(["rtk", "git", "status"]);
|
|
2290
|
-
assert!(result.is_ok(), "git status should parse successfully");
|
|
2291
|
-
}
|
|
2292
|
-
|
|
2293
|
-
#[test]
|
|
2294
|
-
fn test_try_parse_help_is_display_help() {
|
|
2295
|
-
match Cli::try_parse_from(["rtk", "--help"]) {
|
|
2296
|
-
Err(e) => assert_eq!(e.kind(), ErrorKind::DisplayHelp),
|
|
2297
|
-
Ok(_) => panic!("Expected DisplayHelp error"),
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
|
|
2301
|
-
#[test]
|
|
2302
|
-
fn test_try_parse_version_is_display_version() {
|
|
2303
|
-
match Cli::try_parse_from(["rtk", "--version"]) {
|
|
2304
|
-
Err(e) => assert_eq!(e.kind(), ErrorKind::DisplayVersion),
|
|
2305
|
-
Ok(_) => panic!("Expected DisplayVersion error"),
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
|
|
2309
|
-
#[test]
|
|
2310
|
-
fn test_try_parse_unknown_subcommand_is_error() {
|
|
2311
|
-
match Cli::try_parse_from(["rtk", "nonexistent-command"]) {
|
|
2312
|
-
Err(e) => assert!(!matches!(
|
|
2313
|
-
e.kind(),
|
|
2314
|
-
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion
|
|
2315
|
-
)),
|
|
2316
|
-
Ok(_) => panic!("Expected parse error for unknown subcommand"),
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
#[test]
|
|
2321
|
-
fn test_try_parse_git_with_dash_c_succeeds() {
|
|
2322
|
-
let result = Cli::try_parse_from(["rtk", "git", "-C", "/path", "status"]);
|
|
2323
|
-
assert!(
|
|
2324
|
-
result.is_ok(),
|
|
2325
|
-
"git -C /path status should parse successfully"
|
|
2326
|
-
);
|
|
2327
|
-
if let Ok(cli) = result {
|
|
2328
|
-
match cli.command {
|
|
2329
|
-
Commands::Git { directory, .. } => {
|
|
2330
|
-
assert_eq!(directory, vec!["/path"]);
|
|
2331
|
-
}
|
|
2332
|
-
_ => panic!("Expected Git command"),
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2337
|
-
#[test]
|
|
2338
|
-
fn test_gain_failures_flag_parses() {
|
|
2339
|
-
let result = Cli::try_parse_from(["rtk", "gain", "--failures"]);
|
|
2340
|
-
assert!(result.is_ok());
|
|
2341
|
-
if let Ok(cli) = result {
|
|
2342
|
-
match cli.command {
|
|
2343
|
-
Commands::Gain { failures, .. } => assert!(failures),
|
|
2344
|
-
_ => panic!("Expected Gain command"),
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
#[test]
|
|
2350
|
-
fn test_gain_failures_short_flag_parses() {
|
|
2351
|
-
let result = Cli::try_parse_from(["rtk", "gain", "-F"]);
|
|
2352
|
-
assert!(result.is_ok());
|
|
2353
|
-
if let Ok(cli) = result {
|
|
2354
|
-
match cli.command {
|
|
2355
|
-
Commands::Gain { failures, .. } => assert!(failures),
|
|
2356
|
-
_ => panic!("Expected Gain command"),
|
|
2357
|
-
}
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
|
|
2361
|
-
#[test]
|
|
2362
|
-
fn test_meta_commands_reject_bad_flags() {
|
|
2363
|
-
// RTK meta-commands should produce parse errors (not fall through to raw execution).
|
|
2364
|
-
// Skip "proxy" because it uses trailing_var_arg (accepts any args by design).
|
|
2365
|
-
for cmd in RTK_META_COMMANDS {
|
|
2366
|
-
if *cmd == "proxy" {
|
|
2367
|
-
continue;
|
|
2368
|
-
}
|
|
2369
|
-
let result = Cli::try_parse_from(["rtk", cmd, "--nonexistent-flag-xyz"]);
|
|
2370
|
-
assert!(
|
|
2371
|
-
result.is_err(),
|
|
2372
|
-
"Meta-command '{}' with bad flag should fail to parse",
|
|
2373
|
-
cmd
|
|
2374
|
-
);
|
|
2375
|
-
}
|
|
2376
|
-
}
|
|
2377
|
-
|
|
2378
|
-
#[test]
|
|
2379
|
-
fn test_meta_command_list_is_complete() {
|
|
2380
|
-
// Verify all meta-commands are in the guard list by checking they parse with valid syntax
|
|
2381
|
-
let meta_cmds_that_parse = [
|
|
2382
|
-
vec!["rtk", "gain"],
|
|
2383
|
-
vec!["rtk", "discover"],
|
|
2384
|
-
vec!["rtk", "learn"],
|
|
2385
|
-
vec!["rtk", "init"],
|
|
2386
|
-
vec!["rtk", "config"],
|
|
2387
|
-
vec!["rtk", "proxy", "echo", "hi"],
|
|
2388
|
-
vec!["rtk", "hook-audit"],
|
|
2389
|
-
vec!["rtk", "cc-economics"],
|
|
2390
|
-
];
|
|
2391
|
-
for args in &meta_cmds_that_parse {
|
|
2392
|
-
let result = Cli::try_parse_from(args.iter());
|
|
2393
|
-
assert!(
|
|
2394
|
-
result.is_ok(),
|
|
2395
|
-
"Meta-command {:?} should parse successfully",
|
|
2396
|
-
args
|
|
2397
|
-
);
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
|
|
2401
|
-
#[test]
|
|
2402
|
-
fn test_shell_split_simple() {
|
|
2403
|
-
assert_eq!(
|
|
2404
|
-
shell_split("head -50 file.php"),
|
|
2405
|
-
vec!["head", "-50", "file.php"]
|
|
2406
|
-
);
|
|
2407
|
-
}
|
|
2408
|
-
|
|
2409
|
-
#[test]
|
|
2410
|
-
fn test_shell_split_double_quotes() {
|
|
2411
|
-
assert_eq!(
|
|
2412
|
-
shell_split(r#"git log --format="%H %s""#),
|
|
2413
|
-
vec!["git", "log", "--format=%H %s"]
|
|
2414
|
-
);
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
|
-
#[test]
|
|
2418
|
-
fn test_shell_split_single_quotes() {
|
|
2419
|
-
assert_eq!(
|
|
2420
|
-
shell_split("grep -r 'hello world' ."),
|
|
2421
|
-
vec!["grep", "-r", "hello world", "."]
|
|
2422
|
-
);
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
#[test]
|
|
2426
|
-
fn test_shell_split_single_word() {
|
|
2427
|
-
assert_eq!(shell_split("ls"), vec!["ls"]);
|
|
2428
|
-
}
|
|
2429
|
-
|
|
2430
|
-
#[test]
|
|
2431
|
-
fn test_shell_split_empty() {
|
|
2432
|
-
let result: Vec<String> = shell_split("");
|
|
2433
|
-
assert!(result.is_empty());
|
|
2434
|
-
}
|
|
2435
|
-
|
|
2436
|
-
#[test]
|
|
2437
|
-
fn test_rewrite_clap_multi_args() {
|
|
2438
|
-
// This is the bug KuSh reported: `rtk rewrite ls -al` failed because
|
|
2439
|
-
// Clap rejected `-al` as an unknown flag. With trailing_var_arg + allow_hyphen_values,
|
|
2440
|
-
// multiple args are accepted and joined into a single command string.
|
|
2441
|
-
let cases = vec![
|
|
2442
|
-
vec!["rtk", "rewrite", "ls", "-al"],
|
|
2443
|
-
vec!["rtk", "rewrite", "git", "status"],
|
|
2444
|
-
vec!["rtk", "rewrite", "npm", "exec"],
|
|
2445
|
-
vec!["rtk", "rewrite", "cargo", "test"],
|
|
2446
|
-
vec!["rtk", "rewrite", "du", "-sh", "."],
|
|
2447
|
-
vec!["rtk", "rewrite", "head", "-50", "file.txt"],
|
|
2448
|
-
];
|
|
2449
|
-
for args in &cases {
|
|
2450
|
-
let result = Cli::try_parse_from(args.iter());
|
|
2451
|
-
assert!(
|
|
2452
|
-
result.is_ok(),
|
|
2453
|
-
"rtk rewrite {:?} should parse (was failing before trailing_var_arg fix)",
|
|
2454
|
-
&args[2..]
|
|
2455
|
-
);
|
|
2456
|
-
if let Ok(cli) = result {
|
|
2457
|
-
match cli.command {
|
|
2458
|
-
Commands::Rewrite { ref args } => {
|
|
2459
|
-
assert!(args.len() >= 2, "rewrite args should capture all tokens");
|
|
2460
|
-
}
|
|
2461
|
-
_ => panic!("expected Rewrite command"),
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
|
|
2467
|
-
#[test]
|
|
2468
|
-
fn test_rewrite_clap_quoted_single_arg() {
|
|
2469
|
-
// Quoted form: `rtk rewrite "git status"` — single arg containing spaces
|
|
2470
|
-
let result = Cli::try_parse_from(["rtk", "rewrite", "git status"]);
|
|
2471
|
-
assert!(result.is_ok());
|
|
2472
|
-
if let Ok(cli) = result {
|
|
2473
|
-
match cli.command {
|
|
2474
|
-
Commands::Rewrite { ref args } => {
|
|
2475
|
-
assert_eq!(args.len(), 1);
|
|
2476
|
-
assert_eq!(args[0], "git status");
|
|
2477
|
-
}
|
|
2478
|
-
_ => panic!("expected Rewrite command"),
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
}
|