@hasna/terminal 2.0.5 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +52 -21
- package/package.json +1 -1
- package/src/ai.ts +77 -130
- package/src/cli.tsx +51 -21
- package/src/command-validator.ts +11 -0
- package/src/context-hints.ts +291 -0
- package/src/discover.ts +238 -0
- package/src/economy.ts +53 -0
- package/src/output-processor.ts +7 -18
- package/src/output-store.ts +65 -0
- package/src/providers/base.ts +3 -1
- package/src/providers/groq.ts +108 -0
- package/src/providers/index.ts +26 -2
- package/src/providers/providers.test.ts +4 -2
- package/src/providers/xai.ts +108 -0
- package/src/sessions-db.ts +81 -0
- package/temp/rtk/.claude/agents/code-reviewer.md +221 -0
- package/temp/rtk/.claude/agents/debugger.md +519 -0
- package/temp/rtk/.claude/agents/rtk-testing-specialist.md +461 -0
- package/temp/rtk/.claude/agents/rust-rtk.md +511 -0
- package/temp/rtk/.claude/agents/technical-writer.md +355 -0
- package/temp/rtk/.claude/commands/diagnose.md +352 -0
- package/temp/rtk/.claude/commands/test-routing.md +362 -0
- package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +16 -0
- package/temp/rtk/.claude/hooks/rtk-rewrite.sh +70 -0
- package/temp/rtk/.claude/hooks/rtk-suggest.sh +152 -0
- package/temp/rtk/.claude/rules/cli-testing.md +526 -0
- package/temp/rtk/.claude/skills/issue-triage/SKILL.md +348 -0
- package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +134 -0
- package/temp/rtk/.claude/skills/performance.md +435 -0
- package/temp/rtk/.claude/skills/pr-triage/SKILL.md +315 -0
- package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +71 -0
- package/temp/rtk/.claude/skills/repo-recap.md +206 -0
- package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +78 -0
- package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +124 -0
- package/temp/rtk/.claude/skills/security-guardian.md +503 -0
- package/temp/rtk/.claude/skills/ship.md +404 -0
- package/temp/rtk/.github/workflows/benchmark.yml +34 -0
- package/temp/rtk/.github/workflows/dco-check.yaml +12 -0
- package/temp/rtk/.github/workflows/release-please.yml +51 -0
- package/temp/rtk/.github/workflows/release.yml +343 -0
- package/temp/rtk/.github/workflows/security-check.yml +135 -0
- package/temp/rtk/.github/workflows/validate-docs.yml +78 -0
- package/temp/rtk/.release-please-manifest.json +3 -0
- package/temp/rtk/ARCHITECTURE.md +1491 -0
- package/temp/rtk/CHANGELOG.md +640 -0
- package/temp/rtk/CLAUDE.md +605 -0
- package/temp/rtk/CONTRIBUTING.md +199 -0
- package/temp/rtk/Cargo.lock +1668 -0
- package/temp/rtk/Cargo.toml +64 -0
- package/temp/rtk/Formula/rtk.rb +43 -0
- package/temp/rtk/INSTALL.md +390 -0
- package/temp/rtk/LICENSE +21 -0
- package/temp/rtk/README.md +386 -0
- package/temp/rtk/README_es.md +159 -0
- package/temp/rtk/README_fr.md +197 -0
- package/temp/rtk/README_ja.md +159 -0
- package/temp/rtk/README_ko.md +159 -0
- package/temp/rtk/README_zh.md +167 -0
- package/temp/rtk/ROADMAP.md +15 -0
- package/temp/rtk/SECURITY.md +217 -0
- package/temp/rtk/TEST_EXEC_TIME.md +102 -0
- package/temp/rtk/build.rs +57 -0
- package/temp/rtk/docs/AUDIT_GUIDE.md +432 -0
- package/temp/rtk/docs/FEATURES.md +1410 -0
- package/temp/rtk/docs/TROUBLESHOOTING.md +309 -0
- package/temp/rtk/docs/filter-workflow.md +102 -0
- package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
- package/temp/rtk/docs/tracking.md +583 -0
- package/temp/rtk/hooks/opencode-rtk.ts +39 -0
- package/temp/rtk/hooks/rtk-awareness.md +29 -0
- package/temp/rtk/hooks/rtk-rewrite.sh +61 -0
- package/temp/rtk/hooks/test-rtk-rewrite.sh +442 -0
- package/temp/rtk/install.sh +124 -0
- package/temp/rtk/release-please-config.json +10 -0
- package/temp/rtk/scripts/benchmark.sh +592 -0
- package/temp/rtk/scripts/check-installation.sh +162 -0
- package/temp/rtk/scripts/install-local.sh +37 -0
- package/temp/rtk/scripts/rtk-economics.sh +137 -0
- package/temp/rtk/scripts/test-all.sh +561 -0
- package/temp/rtk/scripts/test-aristote.sh +227 -0
- package/temp/rtk/scripts/test-tracking.sh +79 -0
- package/temp/rtk/scripts/update-readme-metrics.sh +32 -0
- package/temp/rtk/scripts/validate-docs.sh +73 -0
- package/temp/rtk/src/aws_cmd.rs +880 -0
- package/temp/rtk/src/binlog.rs +1645 -0
- package/temp/rtk/src/cargo_cmd.rs +1727 -0
- package/temp/rtk/src/cc_economics.rs +1157 -0
- package/temp/rtk/src/ccusage.rs +340 -0
- package/temp/rtk/src/config.rs +187 -0
- package/temp/rtk/src/container.rs +855 -0
- package/temp/rtk/src/curl_cmd.rs +134 -0
- package/temp/rtk/src/deps.rs +268 -0
- package/temp/rtk/src/diff_cmd.rs +367 -0
- package/temp/rtk/src/discover/mod.rs +274 -0
- package/temp/rtk/src/discover/provider.rs +388 -0
- package/temp/rtk/src/discover/registry.rs +2022 -0
- package/temp/rtk/src/discover/report.rs +202 -0
- package/temp/rtk/src/discover/rules.rs +667 -0
- package/temp/rtk/src/display_helpers.rs +402 -0
- package/temp/rtk/src/dotnet_cmd.rs +1771 -0
- package/temp/rtk/src/dotnet_format_report.rs +133 -0
- package/temp/rtk/src/dotnet_trx.rs +593 -0
- package/temp/rtk/src/env_cmd.rs +204 -0
- package/temp/rtk/src/filter.rs +462 -0
- package/temp/rtk/src/filters/README.md +52 -0
- package/temp/rtk/src/filters/ansible-playbook.toml +34 -0
- package/temp/rtk/src/filters/basedpyright.toml +47 -0
- package/temp/rtk/src/filters/biome.toml +45 -0
- package/temp/rtk/src/filters/brew-install.toml +37 -0
- package/temp/rtk/src/filters/composer-install.toml +40 -0
- package/temp/rtk/src/filters/df.toml +16 -0
- package/temp/rtk/src/filters/dotnet-build.toml +64 -0
- package/temp/rtk/src/filters/du.toml +16 -0
- package/temp/rtk/src/filters/fail2ban-client.toml +15 -0
- package/temp/rtk/src/filters/gcc.toml +49 -0
- package/temp/rtk/src/filters/gcloud.toml +22 -0
- package/temp/rtk/src/filters/hadolint.toml +24 -0
- package/temp/rtk/src/filters/helm.toml +29 -0
- package/temp/rtk/src/filters/iptables.toml +27 -0
- package/temp/rtk/src/filters/jj.toml +28 -0
- package/temp/rtk/src/filters/jq.toml +24 -0
- package/temp/rtk/src/filters/make.toml +41 -0
- package/temp/rtk/src/filters/markdownlint.toml +24 -0
- package/temp/rtk/src/filters/mix-compile.toml +27 -0
- package/temp/rtk/src/filters/mix-format.toml +15 -0
- package/temp/rtk/src/filters/mvn-build.toml +44 -0
- package/temp/rtk/src/filters/oxlint.toml +43 -0
- package/temp/rtk/src/filters/ping.toml +63 -0
- package/temp/rtk/src/filters/pio-run.toml +40 -0
- package/temp/rtk/src/filters/poetry-install.toml +50 -0
- package/temp/rtk/src/filters/pre-commit.toml +35 -0
- package/temp/rtk/src/filters/ps.toml +16 -0
- package/temp/rtk/src/filters/quarto-render.toml +41 -0
- package/temp/rtk/src/filters/rsync.toml +48 -0
- package/temp/rtk/src/filters/shellcheck.toml +27 -0
- package/temp/rtk/src/filters/shopify-theme.toml +29 -0
- package/temp/rtk/src/filters/skopeo.toml +45 -0
- package/temp/rtk/src/filters/sops.toml +16 -0
- package/temp/rtk/src/filters/ssh.toml +44 -0
- package/temp/rtk/src/filters/stat.toml +34 -0
- package/temp/rtk/src/filters/swift-build.toml +41 -0
- package/temp/rtk/src/filters/systemctl-status.toml +33 -0
- package/temp/rtk/src/filters/terraform-plan.toml +35 -0
- package/temp/rtk/src/filters/tofu-fmt.toml +16 -0
- package/temp/rtk/src/filters/tofu-init.toml +38 -0
- package/temp/rtk/src/filters/tofu-plan.toml +35 -0
- package/temp/rtk/src/filters/tofu-validate.toml +17 -0
- package/temp/rtk/src/filters/trunk-build.toml +39 -0
- package/temp/rtk/src/filters/ty.toml +50 -0
- package/temp/rtk/src/filters/uv-sync.toml +37 -0
- package/temp/rtk/src/filters/xcodebuild.toml +99 -0
- package/temp/rtk/src/filters/yamllint.toml +25 -0
- package/temp/rtk/src/find_cmd.rs +598 -0
- package/temp/rtk/src/format_cmd.rs +386 -0
- package/temp/rtk/src/gain.rs +723 -0
- package/temp/rtk/src/gh_cmd.rs +1651 -0
- package/temp/rtk/src/git.rs +2012 -0
- package/temp/rtk/src/go_cmd.rs +592 -0
- package/temp/rtk/src/golangci_cmd.rs +254 -0
- package/temp/rtk/src/grep_cmd.rs +288 -0
- package/temp/rtk/src/gt_cmd.rs +810 -0
- package/temp/rtk/src/hook_audit_cmd.rs +283 -0
- package/temp/rtk/src/hook_check.rs +171 -0
- package/temp/rtk/src/init.rs +1859 -0
- package/temp/rtk/src/integrity.rs +537 -0
- package/temp/rtk/src/json_cmd.rs +231 -0
- package/temp/rtk/src/learn/detector.rs +628 -0
- package/temp/rtk/src/learn/mod.rs +119 -0
- package/temp/rtk/src/learn/report.rs +184 -0
- package/temp/rtk/src/lint_cmd.rs +694 -0
- package/temp/rtk/src/local_llm.rs +316 -0
- package/temp/rtk/src/log_cmd.rs +248 -0
- package/temp/rtk/src/ls.rs +324 -0
- package/temp/rtk/src/main.rs +2482 -0
- package/temp/rtk/src/mypy_cmd.rs +389 -0
- package/temp/rtk/src/next_cmd.rs +241 -0
- package/temp/rtk/src/npm_cmd.rs +236 -0
- package/temp/rtk/src/parser/README.md +267 -0
- package/temp/rtk/src/parser/error.rs +46 -0
- package/temp/rtk/src/parser/formatter.rs +336 -0
- package/temp/rtk/src/parser/mod.rs +311 -0
- package/temp/rtk/src/parser/types.rs +119 -0
- package/temp/rtk/src/pip_cmd.rs +302 -0
- package/temp/rtk/src/playwright_cmd.rs +479 -0
- package/temp/rtk/src/pnpm_cmd.rs +573 -0
- package/temp/rtk/src/prettier_cmd.rs +221 -0
- package/temp/rtk/src/prisma_cmd.rs +482 -0
- package/temp/rtk/src/psql_cmd.rs +382 -0
- package/temp/rtk/src/pytest_cmd.rs +384 -0
- package/temp/rtk/src/read.rs +217 -0
- package/temp/rtk/src/rewrite_cmd.rs +50 -0
- package/temp/rtk/src/ruff_cmd.rs +402 -0
- package/temp/rtk/src/runner.rs +271 -0
- package/temp/rtk/src/summary.rs +297 -0
- package/temp/rtk/src/tee.rs +405 -0
- package/temp/rtk/src/telemetry.rs +248 -0
- package/temp/rtk/src/toml_filter.rs +1655 -0
- package/temp/rtk/src/tracking.rs +1416 -0
- package/temp/rtk/src/tree.rs +209 -0
- package/temp/rtk/src/tsc_cmd.rs +259 -0
- package/temp/rtk/src/utils.rs +432 -0
- package/temp/rtk/src/verify_cmd.rs +47 -0
- package/temp/rtk/src/vitest_cmd.rs +385 -0
- package/temp/rtk/src/wc_cmd.rs +401 -0
- package/temp/rtk/src/wget_cmd.rs +260 -0
- package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +11 -0
- package/temp/rtk/tests/fixtures/dotnet/format_changes.json +31 -0
- package/temp/rtk/tests/fixtures/dotnet/format_empty.json +1 -0
- package/temp/rtk/tests/fixtures/dotnet/format_success.json +12 -0
- package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +18 -0
- package/dist/App.js +0 -404
- package/dist/Browse.js +0 -79
- package/dist/FuzzyPicker.js +0 -47
- package/dist/Onboarding.js +0 -51
- package/dist/Spinner.js +0 -12
- package/dist/StatusBar.js +0 -49
- package/dist/ai.js +0 -368
- package/dist/cache.js +0 -41
- package/dist/command-rewriter.js +0 -64
- package/dist/command-validator.js +0 -77
- package/dist/compression.js +0 -107
- package/dist/diff-cache.js +0 -107
- package/dist/economy.js +0 -79
- package/dist/expand-store.js +0 -38
- package/dist/file-cache.js +0 -72
- package/dist/file-index.js +0 -62
- package/dist/history.js +0 -62
- package/dist/lazy-executor.js +0 -54
- package/dist/line-dedup.js +0 -59
- package/dist/loop-detector.js +0 -75
- package/dist/mcp/install.js +0 -98
- package/dist/mcp/server.js +0 -569
- package/dist/noise-filter.js +0 -86
- package/dist/output-processor.js +0 -136
- package/dist/output-router.js +0 -41
- package/dist/parsers/base.js +0 -2
- package/dist/parsers/build.js +0 -64
- package/dist/parsers/errors.js +0 -101
- package/dist/parsers/files.js +0 -78
- package/dist/parsers/git.js +0 -99
- package/dist/parsers/index.js +0 -48
- package/dist/parsers/tests.js +0 -89
- package/dist/providers/anthropic.js +0 -39
- package/dist/providers/base.js +0 -4
- package/dist/providers/cerebras.js +0 -95
- package/dist/providers/index.js +0 -49
- package/dist/recipes/model.js +0 -20
- package/dist/recipes/storage.js +0 -136
- package/dist/search/content-search.js +0 -68
- package/dist/search/file-search.js +0 -61
- package/dist/search/filters.js +0 -34
- package/dist/search/index.js +0 -5
- package/dist/search/semantic.js +0 -320
- package/dist/session-boot.js +0 -59
- package/dist/session-context.js +0 -55
- package/dist/sessions-db.js +0 -120
- package/dist/smart-display.js +0 -286
- package/dist/snapshots.js +0 -51
- package/dist/supervisor.js +0 -112
- package/dist/test-watchlist.js +0 -131
- package/dist/tree.js +0 -94
- package/dist/usage-cache.js +0 -65
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Output store — saves full raw output to disk when AI compresses it
|
|
2
|
+
// Agents can read the file for full detail. Rotates to cap disk usage.
|
|
3
|
+
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync, statSync, unlinkSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { createHash } from "crypto";
|
|
7
|
+
|
|
8
|
+
const OUTPUTS_DIR = join(process.env.HOME ?? "~", ".terminal", "outputs");
|
|
9
|
+
const MAX_FILES = 50;
|
|
10
|
+
const MAX_TOTAL_SIZE = 5 * 1024 * 1024; // 5MB
|
|
11
|
+
|
|
12
|
+
/** Ensure outputs directory exists */
|
|
13
|
+
function ensureDir() {
|
|
14
|
+
if (!existsSync(OUTPUTS_DIR)) mkdirSync(OUTPUTS_DIR, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Generate a short hash for an output */
|
|
18
|
+
function hashOutput(command: string, output: string): string {
|
|
19
|
+
return createHash("md5").update(command + output.slice(0, 1000)).digest("hex").slice(0, 12);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Rotate old files to stay within limits */
|
|
23
|
+
function rotate() {
|
|
24
|
+
try {
|
|
25
|
+
const files = readdirSync(OUTPUTS_DIR)
|
|
26
|
+
.map(f => ({ name: f, path: join(OUTPUTS_DIR, f), mtime: statSync(join(OUTPUTS_DIR, f)).mtimeMs, size: statSync(join(OUTPUTS_DIR, f)).size }))
|
|
27
|
+
.sort((a, b) => b.mtime - a.mtime); // newest first
|
|
28
|
+
|
|
29
|
+
// Remove excess files
|
|
30
|
+
let totalSize = 0;
|
|
31
|
+
for (let i = 0; i < files.length; i++) {
|
|
32
|
+
totalSize += files[i].size;
|
|
33
|
+
if (i >= MAX_FILES || totalSize > MAX_TOTAL_SIZE) {
|
|
34
|
+
try { unlinkSync(files[i].path); } catch {}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Save full output to disk, return the file path */
|
|
41
|
+
export function saveOutput(command: string, rawOutput: string): string {
|
|
42
|
+
ensureDir();
|
|
43
|
+
|
|
44
|
+
const hash = hashOutput(command, rawOutput);
|
|
45
|
+
const filename = `${hash}.txt`;
|
|
46
|
+
const filepath = join(OUTPUTS_DIR, filename);
|
|
47
|
+
|
|
48
|
+
// Write with command header
|
|
49
|
+
const content = `$ ${command}\n${"─".repeat(60)}\n${rawOutput}`;
|
|
50
|
+
writeFileSync(filepath, content, "utf8");
|
|
51
|
+
|
|
52
|
+
rotate();
|
|
53
|
+
|
|
54
|
+
return filepath;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Format the hint line that tells agents where to find full output */
|
|
58
|
+
export function formatOutputHint(filepath: string): string {
|
|
59
|
+
return `[full output: ${filepath}]`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Get the outputs directory path */
|
|
63
|
+
export function getOutputsDir(): string {
|
|
64
|
+
return OUTPUTS_DIR;
|
|
65
|
+
}
|
package/src/providers/base.ts
CHANGED
|
@@ -24,9 +24,11 @@ export interface LLMProvider {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export interface ProviderConfig {
|
|
27
|
-
provider: "cerebras" | "anthropic" | "auto";
|
|
27
|
+
provider: "cerebras" | "anthropic" | "groq" | "xai" | "auto";
|
|
28
28
|
cerebrasModel?: string;
|
|
29
29
|
anthropicModel?: string;
|
|
30
|
+
groqModel?: string;
|
|
31
|
+
xaiModel?: string;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export const DEFAULT_PROVIDER_CONFIG: ProviderConfig = {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Groq provider — uses OpenAI-compatible API
|
|
2
|
+
// Ultra-fast inference. Supports Llama, Qwen, Kimi models.
|
|
3
|
+
|
|
4
|
+
import type { LLMProvider, ProviderOptions, StreamCallbacks } from "./base.js";
|
|
5
|
+
|
|
6
|
+
const GROQ_BASE_URL = "https://api.groq.com/openai/v1";
|
|
7
|
+
const DEFAULT_MODEL = "openai/gpt-oss-120b";
|
|
8
|
+
|
|
9
|
+
export class GroqProvider implements LLMProvider {
|
|
10
|
+
readonly name = "groq";
|
|
11
|
+
private apiKey: string;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
this.apiKey = process.env.GROQ_API_KEY ?? "";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
isAvailable(): boolean {
|
|
18
|
+
return !!process.env.GROQ_API_KEY;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async complete(prompt: string, options: ProviderOptions): Promise<string> {
|
|
22
|
+
const model = options.model ?? DEFAULT_MODEL;
|
|
23
|
+
const res = await fetch(`${GROQ_BASE_URL}/chat/completions`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
model,
|
|
31
|
+
max_tokens: options.maxTokens ?? 256,
|
|
32
|
+
messages: [
|
|
33
|
+
{ role: "system", content: options.system },
|
|
34
|
+
{ role: "user", content: prompt },
|
|
35
|
+
],
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const text = await res.text();
|
|
41
|
+
throw new Error(`Groq API error ${res.status}: ${text}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const json = (await res.json()) as any;
|
|
45
|
+
return (json.choices?.[0]?.message?.content ?? "").trim();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async stream(prompt: string, options: ProviderOptions, callbacks: StreamCallbacks): Promise<string> {
|
|
49
|
+
const model = options.model ?? DEFAULT_MODEL;
|
|
50
|
+
const res = await fetch(`${GROQ_BASE_URL}/chat/completions`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
model,
|
|
58
|
+
max_tokens: options.maxTokens ?? 256,
|
|
59
|
+
stream: true,
|
|
60
|
+
messages: [
|
|
61
|
+
{ role: "system", content: options.system },
|
|
62
|
+
{ role: "user", content: prompt },
|
|
63
|
+
],
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const text = await res.text();
|
|
69
|
+
throw new Error(`Groq API error ${res.status}: ${text}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let result = "";
|
|
73
|
+
const reader = res.body?.getReader();
|
|
74
|
+
if (!reader) throw new Error("No response body");
|
|
75
|
+
|
|
76
|
+
const decoder = new TextDecoder();
|
|
77
|
+
let buffer = "";
|
|
78
|
+
|
|
79
|
+
while (true) {
|
|
80
|
+
const { done, value } = await reader.read();
|
|
81
|
+
if (done) break;
|
|
82
|
+
|
|
83
|
+
buffer += decoder.decode(value, { stream: true });
|
|
84
|
+
const lines = buffer.split("\n");
|
|
85
|
+
buffer = lines.pop() ?? "";
|
|
86
|
+
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
const trimmed = line.trim();
|
|
89
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
90
|
+
const data = trimmed.slice(6);
|
|
91
|
+
if (data === "[DONE]") break;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const parsed = JSON.parse(data) as any;
|
|
95
|
+
const delta = parsed.choices?.[0]?.delta?.content;
|
|
96
|
+
if (delta) {
|
|
97
|
+
result += delta;
|
|
98
|
+
callbacks.onToken(result.trim());
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// skip malformed chunks
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return result.trim();
|
|
107
|
+
}
|
|
108
|
+
}
|
package/src/providers/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { LLMProvider, ProviderConfig } from "./base.js";
|
|
|
4
4
|
import { DEFAULT_PROVIDER_CONFIG } from "./base.js";
|
|
5
5
|
import { AnthropicProvider } from "./anthropic.js";
|
|
6
6
|
import { CerebrasProvider } from "./cerebras.js";
|
|
7
|
+
import { GroqProvider } from "./groq.js";
|
|
8
|
+
import { XaiProvider } from "./xai.js";
|
|
7
9
|
|
|
8
10
|
export type { LLMProvider, ProviderOptions, StreamCallbacks, ProviderConfig } from "./base.js";
|
|
9
11
|
export { DEFAULT_PROVIDER_CONFIG } from "./base.js";
|
|
@@ -37,17 +39,37 @@ function resolveProvider(config: ProviderConfig): LLMProvider {
|
|
|
37
39
|
return p;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
if (config.provider === "groq") {
|
|
43
|
+
const p = new GroqProvider();
|
|
44
|
+
if (!p.isAvailable()) throw new Error("GROQ_API_KEY not set. Run: export GROQ_API_KEY=your-key");
|
|
45
|
+
return p;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (config.provider === "xai") {
|
|
49
|
+
const p = new XaiProvider();
|
|
50
|
+
if (!p.isAvailable()) throw new Error("XAI_API_KEY not set. Run: export XAI_API_KEY=your-key");
|
|
51
|
+
return p;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// auto: prefer Cerebras (qwen-235b, fast + accurate), then xAI, then Groq, then Anthropic
|
|
41
55
|
const cerebras = new CerebrasProvider();
|
|
42
56
|
if (cerebras.isAvailable()) return cerebras;
|
|
43
57
|
|
|
58
|
+
const xai = new XaiProvider();
|
|
59
|
+
if (xai.isAvailable()) return xai;
|
|
60
|
+
|
|
61
|
+
const groq = new GroqProvider();
|
|
62
|
+
if (groq.isAvailable()) return groq;
|
|
63
|
+
|
|
44
64
|
const anthropic = new AnthropicProvider();
|
|
45
65
|
if (anthropic.isAvailable()) return anthropic;
|
|
46
66
|
|
|
47
67
|
throw new Error(
|
|
48
68
|
"No API key found. Set one of:\n" +
|
|
49
69
|
" export CEREBRAS_API_KEY=your-key (free, open-source)\n" +
|
|
50
|
-
" export
|
|
70
|
+
" export GROQ_API_KEY=your-key (free, fast)\n" +
|
|
71
|
+
" export XAI_API_KEY=your-key (Grok, code-optimized)\n" +
|
|
72
|
+
" export ANTHROPIC_API_KEY=your-key (Claude)"
|
|
51
73
|
);
|
|
52
74
|
}
|
|
53
75
|
|
|
@@ -55,6 +77,8 @@ function resolveProvider(config: ProviderConfig): LLMProvider {
|
|
|
55
77
|
export function availableProviders(): { name: string; available: boolean }[] {
|
|
56
78
|
return [
|
|
57
79
|
{ name: "cerebras", available: new CerebrasProvider().isAvailable() },
|
|
80
|
+
{ name: "groq", available: new GroqProvider().isAvailable() },
|
|
81
|
+
{ name: "xai", available: new XaiProvider().isAvailable() },
|
|
58
82
|
{ name: "anthropic", available: new AnthropicProvider().isAvailable() },
|
|
59
83
|
];
|
|
60
84
|
}
|
|
@@ -4,9 +4,11 @@ import { availableProviders, resetProvider } from "./index.js";
|
|
|
4
4
|
describe("providers", () => {
|
|
5
5
|
it("lists available providers", () => {
|
|
6
6
|
const providers = availableProviders();
|
|
7
|
-
expect(providers.length).toBe(
|
|
7
|
+
expect(providers.length).toBe(4);
|
|
8
8
|
expect(providers[0].name).toBe("cerebras");
|
|
9
|
-
expect(providers[1].name).toBe("
|
|
9
|
+
expect(providers[1].name).toBe("groq");
|
|
10
|
+
expect(providers[2].name).toBe("xai");
|
|
11
|
+
expect(providers[3].name).toBe("anthropic");
|
|
10
12
|
});
|
|
11
13
|
|
|
12
14
|
it("resetProvider clears cache", () => {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// xAI/Grok provider — uses OpenAI-compatible API
|
|
2
|
+
// grok-code-fast-1 for code tasks, grok-4-fast for general queries.
|
|
3
|
+
|
|
4
|
+
import type { LLMProvider, ProviderOptions, StreamCallbacks } from "./base.js";
|
|
5
|
+
|
|
6
|
+
const XAI_BASE_URL = "https://api.x.ai/v1";
|
|
7
|
+
const DEFAULT_MODEL = "grok-code-fast-1";
|
|
8
|
+
|
|
9
|
+
export class XaiProvider implements LLMProvider {
|
|
10
|
+
readonly name = "xai";
|
|
11
|
+
private apiKey: string;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
this.apiKey = process.env.XAI_API_KEY ?? "";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
isAvailable(): boolean {
|
|
18
|
+
return !!process.env.XAI_API_KEY;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async complete(prompt: string, options: ProviderOptions): Promise<string> {
|
|
22
|
+
const model = options.model ?? DEFAULT_MODEL;
|
|
23
|
+
const res = await fetch(`${XAI_BASE_URL}/chat/completions`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
model,
|
|
31
|
+
max_tokens: options.maxTokens ?? 256,
|
|
32
|
+
messages: [
|
|
33
|
+
{ role: "system", content: options.system },
|
|
34
|
+
{ role: "user", content: prompt },
|
|
35
|
+
],
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const text = await res.text();
|
|
41
|
+
throw new Error(`xAI API error ${res.status}: ${text}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const json = (await res.json()) as any;
|
|
45
|
+
return (json.choices?.[0]?.message?.content ?? "").trim();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async stream(prompt: string, options: ProviderOptions, callbacks: StreamCallbacks): Promise<string> {
|
|
49
|
+
const model = options.model ?? DEFAULT_MODEL;
|
|
50
|
+
const res = await fetch(`${XAI_BASE_URL}/chat/completions`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
model,
|
|
58
|
+
max_tokens: options.maxTokens ?? 256,
|
|
59
|
+
stream: true,
|
|
60
|
+
messages: [
|
|
61
|
+
{ role: "system", content: options.system },
|
|
62
|
+
{ role: "user", content: prompt },
|
|
63
|
+
],
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const text = await res.text();
|
|
69
|
+
throw new Error(`xAI API error ${res.status}: ${text}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let result = "";
|
|
73
|
+
const reader = res.body?.getReader();
|
|
74
|
+
if (!reader) throw new Error("No response body");
|
|
75
|
+
|
|
76
|
+
const decoder = new TextDecoder();
|
|
77
|
+
let buffer = "";
|
|
78
|
+
|
|
79
|
+
while (true) {
|
|
80
|
+
const { done, value } = await reader.read();
|
|
81
|
+
if (done) break;
|
|
82
|
+
|
|
83
|
+
buffer += decoder.decode(value, { stream: true });
|
|
84
|
+
const lines = buffer.split("\n");
|
|
85
|
+
buffer = lines.pop() ?? "";
|
|
86
|
+
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
const trimmed = line.trim();
|
|
89
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
90
|
+
const data = trimmed.slice(6);
|
|
91
|
+
if (data === "[DONE]") break;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const parsed = JSON.parse(data) as any;
|
|
95
|
+
const delta = parsed.choices?.[0]?.delta?.content;
|
|
96
|
+
if (delta) {
|
|
97
|
+
result += delta;
|
|
98
|
+
callbacks.onToken(result.trim());
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// skip malformed chunks
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return result.trim();
|
|
107
|
+
}
|
|
108
|
+
}
|
package/src/sessions-db.ts
CHANGED
|
@@ -45,6 +45,32 @@ function getDb(): Database {
|
|
|
45
45
|
|
|
46
46
|
CREATE INDEX IF NOT EXISTS idx_interactions_session ON interactions(session_id);
|
|
47
47
|
CREATE INDEX IF NOT EXISTS idx_sessions_started ON sessions(started_at);
|
|
48
|
+
|
|
49
|
+
CREATE TABLE IF NOT EXISTS corrections (
|
|
50
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
51
|
+
prompt TEXT NOT NULL,
|
|
52
|
+
failed_command TEXT NOT NULL,
|
|
53
|
+
error_output TEXT,
|
|
54
|
+
corrected_command TEXT NOT NULL,
|
|
55
|
+
worked INTEGER DEFAULT 1,
|
|
56
|
+
error_type TEXT,
|
|
57
|
+
created_at INTEGER NOT NULL
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE TABLE IF NOT EXISTS outputs (
|
|
61
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
62
|
+
session_id TEXT,
|
|
63
|
+
command TEXT NOT NULL,
|
|
64
|
+
raw_output_path TEXT,
|
|
65
|
+
compressed_summary TEXT,
|
|
66
|
+
tokens_raw INTEGER DEFAULT 0,
|
|
67
|
+
tokens_compressed INTEGER DEFAULT 0,
|
|
68
|
+
provider TEXT,
|
|
69
|
+
model TEXT,
|
|
70
|
+
created_at INTEGER NOT NULL
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_corrections_prompt ON corrections(prompt);
|
|
48
74
|
`);
|
|
49
75
|
|
|
50
76
|
return db;
|
|
@@ -186,6 +212,61 @@ export function getSessionStats(): SessionStats {
|
|
|
186
212
|
};
|
|
187
213
|
}
|
|
188
214
|
|
|
215
|
+
// ── Corrections ─────────────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
/** Record a correction: command failed, then AI retried with a better one */
|
|
218
|
+
export function recordCorrection(
|
|
219
|
+
prompt: string,
|
|
220
|
+
failedCommand: string,
|
|
221
|
+
errorOutput: string,
|
|
222
|
+
correctedCommand: string,
|
|
223
|
+
worked: boolean,
|
|
224
|
+
errorType?: string,
|
|
225
|
+
): void {
|
|
226
|
+
getDb().prepare(
|
|
227
|
+
"INSERT INTO corrections (prompt, failed_command, error_output, corrected_command, worked, error_type, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
228
|
+
).run(prompt, failedCommand, errorOutput?.slice(0, 2000) ?? "", correctedCommand, worked ? 1 : 0, errorType ?? null, Date.now());
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Find similar corrections for a prompt — used to inject as negative examples */
|
|
232
|
+
export function findSimilarCorrections(prompt: string, limit: number = 5): { failed_command: string; corrected_command: string; error_type: string }[] {
|
|
233
|
+
// Simple keyword matching — extract significant words from prompt
|
|
234
|
+
const words = prompt.toLowerCase().split(/\s+/).filter(w => w.length > 3);
|
|
235
|
+
if (words.length === 0) return [];
|
|
236
|
+
|
|
237
|
+
// Search corrections where the prompt shares keywords
|
|
238
|
+
const all = getDb().prepare(
|
|
239
|
+
"SELECT prompt, failed_command, corrected_command, error_type FROM corrections WHERE worked = 1 ORDER BY created_at DESC LIMIT 100"
|
|
240
|
+
).all() as any[];
|
|
241
|
+
|
|
242
|
+
return all
|
|
243
|
+
.filter(c => {
|
|
244
|
+
const cWords = c.prompt.toLowerCase().split(/\s+/);
|
|
245
|
+
const overlap = words.filter((w: string) => cWords.some((cw: string) => cw.includes(w) || w.includes(cw)));
|
|
246
|
+
return overlap.length >= Math.min(2, words.length);
|
|
247
|
+
})
|
|
248
|
+
.slice(0, limit)
|
|
249
|
+
.map(c => ({ failed_command: c.failed_command, corrected_command: c.corrected_command, error_type: c.error_type ?? "unknown" }));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ── Output tracking ─────────────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
/** Record a compressed output for audit trail */
|
|
255
|
+
export function recordOutput(
|
|
256
|
+
command: string,
|
|
257
|
+
rawOutputPath: string | null,
|
|
258
|
+
compressedSummary: string,
|
|
259
|
+
tokensRaw: number,
|
|
260
|
+
tokensCompressed: number,
|
|
261
|
+
provider?: string,
|
|
262
|
+
model?: string,
|
|
263
|
+
sessionId?: string,
|
|
264
|
+
): void {
|
|
265
|
+
getDb().prepare(
|
|
266
|
+
"INSERT INTO outputs (session_id, command, raw_output_path, compressed_summary, tokens_raw, tokens_compressed, provider, model, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
267
|
+
).run(sessionId ?? null, command, rawOutputPath ?? null, compressedSummary?.slice(0, 5000) ?? "", tokensRaw, tokensCompressed, provider ?? null, model ?? null, Date.now());
|
|
268
|
+
}
|
|
269
|
+
|
|
189
270
|
/** Close the database connection */
|
|
190
271
|
export function closeDb(): void {
|
|
191
272
|
if (db) { db.close(); db = null; }
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-reviewer
|
|
3
|
+
description: Use this agent when you need comprehensive code quality assurance, security vulnerability detection, or performance optimization analysis. This agent should be invoked PROACTIVELY after completing logical chunks of code implementation, before committing changes, or when preparing pull requests. Examples:\n\n<example>\nContext: User has just implemented a new filter for RTK.\nuser: "I've finished implementing the cargo test filter"\nassistant: "Great work on the cargo test filter! Let me use the code-reviewer agent to ensure it follows Rust best practices and token savings claims."\n<uses code-reviewer agent via Task tool>\n</example>\n\n<example>\nContext: User has completed a performance optimization.\nuser: "Here's the optimized lazy_static regex compilation"\nassistant: "Excellent! Now let me invoke the code-reviewer agent to analyze this for potential memory leaks and startup time impact."\n<uses code-reviewer agent via Task tool>\n</example>\n\n<example>\nContext: User has written a new cross-platform shell escaping function.\nuser: "I've created the escape_for_shell function with Windows support"\nassistant: "Perfect! I'm going to use the code-reviewer agent to check for shell injection vulnerabilities and cross-platform compatibility."\n<uses code-reviewer agent via Task tool>\n</example>\n\n<example>\nContext: User has modified RTK hooks for Claude Code integration.\nuser: "Updated the rtk-rewrite.sh hook"\nassistant: "Important changes! Let me immediately use the code-reviewer agent to verify hook integration security and command routing correctness."\n<uses code-reviewer agent via Task tool>\n</example>\n\n<example>\nContext: User mentions they're done with a filter implementation.\nuser: "The git log filter is complete"\nassistant: "Excellent progress! Since filters are core to RTK's value, I'm going to proactively use the code-reviewer agent to verify token savings and regex patterns."\n<uses code-reviewer agent via Task tool>\n</example>
|
|
4
|
+
model: sonnet
|
|
5
|
+
color: red
|
|
6
|
+
skills:
|
|
7
|
+
- security-guardian
|
|
8
|
+
- backend-architect
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
You are an elite code review expert specializing in modern AI-powered code analysis, security vulnerabilities, performance optimization, and production reliability. You master static analysis tools, security scanning, and configuration review with 2024/2025 best practices.
|
|
12
|
+
|
|
13
|
+
## Your Core Mission
|
|
14
|
+
|
|
15
|
+
You provide comprehensive, production-grade code reviews that prevent bugs, security vulnerabilities, and production incidents. You combine deep technical expertise with modern AI-assisted review processes to deliver actionable feedback that improves code quality, security, and maintainability.
|
|
16
|
+
|
|
17
|
+
## Your Review Process
|
|
18
|
+
|
|
19
|
+
1. **Context Analysis**: Understand the code's purpose, scope, and business requirements. Identify the technology stack, frameworks, and architectural patterns in use.
|
|
20
|
+
|
|
21
|
+
2. **Automated Analysis**: Apply appropriate static analysis tools and AI-powered review techniques:
|
|
22
|
+
- Security scanning (OWASP Top 10, vulnerability detection)
|
|
23
|
+
- Performance analysis (complexity, resource usage, bottlenecks)
|
|
24
|
+
- Code quality metrics (maintainability, technical debt)
|
|
25
|
+
- Dependency vulnerability scanning
|
|
26
|
+
- Configuration security assessment
|
|
27
|
+
|
|
28
|
+
3. **Manual Expert Review**: Conduct deep analysis of:
|
|
29
|
+
- Business logic correctness and edge cases
|
|
30
|
+
- Security implications and attack vectors
|
|
31
|
+
- Performance and scalability considerations
|
|
32
|
+
- Architecture and design pattern adherence
|
|
33
|
+
- Error handling and resilience patterns
|
|
34
|
+
- Test coverage and quality
|
|
35
|
+
|
|
36
|
+
4. **Structured Feedback Delivery**: Organize findings by severity:
|
|
37
|
+
- 🔴 **CRITICAL**: Security vulnerabilities, data loss risks, production-breaking issues
|
|
38
|
+
- 🟡 **IMPORTANT**: Performance problems, maintainability issues, technical debt
|
|
39
|
+
- 🟢 **RECOMMENDED**: Best practice improvements, optimization opportunities, style refinements
|
|
40
|
+
|
|
41
|
+
5. **Actionable Recommendations**: For each issue:
|
|
42
|
+
- Explain WHY it's a problem (impact and consequences)
|
|
43
|
+
- Provide SPECIFIC code examples showing the fix
|
|
44
|
+
- Suggest alternative approaches when applicable
|
|
45
|
+
- Reference relevant documentation or best practices
|
|
46
|
+
|
|
47
|
+
## Your Expertise Areas
|
|
48
|
+
|
|
49
|
+
**Security Review**:
|
|
50
|
+
|
|
51
|
+
- OWASP Top 10 vulnerability detection
|
|
52
|
+
- Input validation and sanitization
|
|
53
|
+
- Shell injection prevention (critical for CLI tools)
|
|
54
|
+
- Command injection vulnerabilities
|
|
55
|
+
- Cryptographic practices and key management
|
|
56
|
+
- Secrets and credential management
|
|
57
|
+
- API security and rate limiting
|
|
58
|
+
|
|
59
|
+
**Performance Analysis**:
|
|
60
|
+
|
|
61
|
+
- Startup time optimization (<10ms target for RTK)
|
|
62
|
+
- Memory leak and resource management
|
|
63
|
+
- Regex compilation overhead (lazy_static patterns)
|
|
64
|
+
- Caching strategy effectiveness
|
|
65
|
+
- Asynchronous programming patterns (when applicable)
|
|
66
|
+
- Connection pooling and resource limits
|
|
67
|
+
- Scalability bottleneck identification
|
|
68
|
+
|
|
69
|
+
**Code Quality**:
|
|
70
|
+
|
|
71
|
+
- SOLID principles and design patterns
|
|
72
|
+
- Code duplication and refactoring opportunities
|
|
73
|
+
- Naming conventions and readability
|
|
74
|
+
- Technical debt assessment
|
|
75
|
+
- Test coverage and quality (snapshot tests, token accuracy)
|
|
76
|
+
- Documentation completeness
|
|
77
|
+
|
|
78
|
+
**Configuration & Infrastructure**:
|
|
79
|
+
|
|
80
|
+
- Production configuration security
|
|
81
|
+
- CI/CD pipeline security
|
|
82
|
+
- Environment-specific validation
|
|
83
|
+
- Monitoring and observability setup
|
|
84
|
+
|
|
85
|
+
## Your Communication Style
|
|
86
|
+
|
|
87
|
+
- **Constructive and Educational**: Focus on teaching, not just finding faults
|
|
88
|
+
- **Specific and Actionable**: Provide concrete examples and fixes
|
|
89
|
+
- **Prioritized**: Clearly distinguish critical issues from nice-to-haves
|
|
90
|
+
- **Balanced**: Acknowledge good practices while identifying improvements
|
|
91
|
+
- **Pragmatic**: Consider development velocity and deadlines
|
|
92
|
+
- **Professional**: Maintain respectful, mentor-like tone
|
|
93
|
+
|
|
94
|
+
## Your Response Format
|
|
95
|
+
|
|
96
|
+
Structure your reviews as follows:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
## Code Review Summary
|
|
100
|
+
[Brief overview of what was reviewed and overall assessment]
|
|
101
|
+
|
|
102
|
+
## Critical Issues 🔴
|
|
103
|
+
[Security vulnerabilities, production risks - must fix before deployment]
|
|
104
|
+
|
|
105
|
+
## Important Issues 🟡
|
|
106
|
+
[Performance problems, maintainability concerns - should fix soon]
|
|
107
|
+
|
|
108
|
+
## Recommendations 🟢
|
|
109
|
+
[Best practice improvements, optimizations - consider for future iterations]
|
|
110
|
+
|
|
111
|
+
## Positive Observations ✅
|
|
112
|
+
[Acknowledge good practices and well-implemented patterns]
|
|
113
|
+
|
|
114
|
+
## Additional Context
|
|
115
|
+
[Relevant documentation, similar patterns in codebase, architectural considerations]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Special Considerations
|
|
119
|
+
|
|
120
|
+
- **Project Context**: Always consider the project's specific coding standards from CLAUDE.md files
|
|
121
|
+
- **Framework Patterns**: Respect established patterns (e.g., RTK filter design, lazy_static regex)
|
|
122
|
+
- **Business Rules**: Validate against domain-specific requirements when provided
|
|
123
|
+
- **Production Impact**: Prioritize issues that could cause production incidents
|
|
124
|
+
- **Team Standards**: Align feedback with team conventions and established practices
|
|
125
|
+
|
|
126
|
+
## When to Escalate
|
|
127
|
+
|
|
128
|
+
- Critical security vulnerabilities requiring immediate attention
|
|
129
|
+
- Architectural decisions with significant long-term implications
|
|
130
|
+
- Performance issues that could impact production at scale
|
|
131
|
+
- Compliance violations (GDPR, PCI DSS, SOC2)
|
|
132
|
+
- Breaking changes to public APIs or contracts
|
|
133
|
+
|
|
134
|
+
## The New Dev Test
|
|
135
|
+
|
|
136
|
+
> Can a new developer understand, modify, and debug this code within 30 minutes?
|
|
137
|
+
|
|
138
|
+
Apply this test to every code review. If the answer is "no", the code needs:
|
|
139
|
+
|
|
140
|
+
- Better naming (self-documenting code)
|
|
141
|
+
- Smaller functions with single responsibility
|
|
142
|
+
- Comments explaining WHY, not WHAT
|
|
143
|
+
- Clearer error messages with context
|
|
144
|
+
|
|
145
|
+
## Red Flags - Instant Concerns
|
|
146
|
+
|
|
147
|
+
Raise alarms immediately when you see:
|
|
148
|
+
|
|
149
|
+
| Red Flag | Why It's Dangerous |
|
|
150
|
+
| --------------------------------- | ------------------------------------------ |
|
|
151
|
+
| `.unwrap()` in production | Panics crash CLI, breaks user workflow |
|
|
152
|
+
| Regex compiled at runtime | Kills startup time (<10ms target) |
|
|
153
|
+
| Functions > 50 lines | Too complex, hard to test and maintain |
|
|
154
|
+
| Nesting > 3 levels deep | Cognitive overload, refactor needed |
|
|
155
|
+
| Magic numbers/strings | Unclear intent, maintenance nightmare |
|
|
156
|
+
| No input validation | Injection risks, garbage in = crash out |
|
|
157
|
+
| `// TODO` or `// FIXME` in PR | Incomplete work, tech debt shipped |
|
|
158
|
+
| Missing error context | "Error occurred" tells us nothing |
|
|
159
|
+
| No tests for new filter | Regression risk, no token savings proof |
|
|
160
|
+
| Copy-pasted filter code | DRY violation, update one = miss the other |
|
|
161
|
+
| No fallback to raw command | Filter failure breaks user workflow |
|
|
162
|
+
|
|
163
|
+
## Adversarial Questions to Always Ask
|
|
164
|
+
|
|
165
|
+
1. **Edge cases**: What happens with empty input? Null? Max values? Unicode? ANSI codes?
|
|
166
|
+
2. **Failure path**: When this filter fails, does it fallback to raw command?
|
|
167
|
+
3. **Performance**: What's the startup time? Will it scale with 10x data?
|
|
168
|
+
4. **Security**: Can an attacker craft input to exploit this (shell injection)?
|
|
169
|
+
5. **Testability**: Can I unit test this without mocking the entire system?
|
|
170
|
+
6. **Reversibility**: If this causes a bug in prod, how fast can we rollback?
|
|
171
|
+
7. **Dependencies**: Does this import pull in unnecessary weight?
|
|
172
|
+
8. **Token savings**: Does the filter achieve 60-90% savings with real fixtures?
|
|
173
|
+
|
|
174
|
+
## Code Smell Shortcuts
|
|
175
|
+
|
|
176
|
+
Quick patterns that indicate deeper issues:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
Smell → Likely Problem → Check For
|
|
180
|
+
─────────────────────────────────────────────────
|
|
181
|
+
.unwrap() → Panic risk → Use .context() with ?
|
|
182
|
+
Regex in function → Recompiled every call → lazy_static!
|
|
183
|
+
No filter fallback → Broken workflow → execute_raw(cmd, args)
|
|
184
|
+
<60% token savings → Weak filter → Improve condensation logic
|
|
185
|
+
No cross-platform test → Platform bugs → Add #[cfg(target_os = "...")]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## RTK-Specific Review Checklist
|
|
189
|
+
|
|
190
|
+
When reviewing RTK code, always verify:
|
|
191
|
+
|
|
192
|
+
### Filters (🔴 Critical)
|
|
193
|
+
- [ ] **Lazy regex**: All regex use `lazy_static!` (not compiled at runtime)
|
|
194
|
+
- [ ] **Fallback**: Filter has fallback to raw command on error
|
|
195
|
+
- [ ] **Token savings**: Test verifies ≥60% savings with real fixtures
|
|
196
|
+
- [ ] **Snapshot test**: Filter has snapshot test with `insta::assert_snapshot!`
|
|
197
|
+
- [ ] **Exit codes**: Filter preserves command exit codes (0 = success, non-zero = failure)
|
|
198
|
+
|
|
199
|
+
### Security (🔴 Critical)
|
|
200
|
+
- [ ] **Shell injection**: No unescaped user input in shell commands
|
|
201
|
+
- [ ] **Command injection**: No string concatenation for command building
|
|
202
|
+
- [ ] **Cross-platform**: Shell escaping tested on macOS, Linux, Windows
|
|
203
|
+
|
|
204
|
+
### Performance (🟡 Important)
|
|
205
|
+
- [ ] **Startup time**: Benchmarked with `hyperfine` (<10ms target)
|
|
206
|
+
- [ ] **Memory usage**: Verified with `time -l` (<5MB target)
|
|
207
|
+
- [ ] **No async**: RTK is single-threaded, no tokio/async-std
|
|
208
|
+
|
|
209
|
+
### Testing (🟡 Important)
|
|
210
|
+
- [ ] **Real fixtures**: Tests use real command output, not synthetic
|
|
211
|
+
- [ ] **Token accuracy**: Tests verify token savings claims
|
|
212
|
+
- [ ] **Cross-platform**: Tests use `#[cfg(target_os = "...")]` for platform-specific behavior
|
|
213
|
+
- [ ] **Integration**: Integration tests pass (`cargo test --ignored`)
|
|
214
|
+
|
|
215
|
+
### Code Quality (🟢 Recommended)
|
|
216
|
+
- [ ] **Error handling**: All `?` operators have `.context("description")`
|
|
217
|
+
- [ ] **No unwrap**: Production code uses `Result` or `expect("reason")`
|
|
218
|
+
- [ ] **Documentation**: Public functions have doc comments
|
|
219
|
+
- [ ] **Clippy**: Zero warnings (`cargo clippy --all-targets`)
|
|
220
|
+
|
|
221
|
+
You are proactive, thorough, and focused on preventing issues before they reach production. Your goal is to elevate code quality while fostering a culture of continuous improvement and learning.
|