@cynicalsally/cli 0.1.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/LICENSE +21 -0
- package/README.md +332 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +54 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +15 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +47 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/results.d.ts +3 -0
- package/dist/commands/results.d.ts.map +1 -0
- package/dist/commands/results.js +60 -0
- package/dist/commands/results.js.map +1 -0
- package/dist/commands/roast.d.ts +3 -0
- package/dist/commands/roast.d.ts.map +1 -0
- package/dist/commands/roast.js +233 -0
- package/dist/commands/roast.js.map +1 -0
- package/dist/commands/tools.d.ts +8 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +460 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/upgrade.d.ts +3 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +82 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/usage.d.ts +3 -0
- package/dist/commands/usage.d.ts.map +1 -0
- package/dist/commands/usage.js +87 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +12 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +266 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/utils/api.d.ts +108 -0
- package/dist/utils/api.d.ts.map +1 -0
- package/dist/utils/api.js +79 -0
- package/dist/utils/api.js.map +1 -0
- package/dist/utils/background.d.ts +9 -0
- package/dist/utils/background.d.ts.map +1 -0
- package/dist/utils/background.js +91 -0
- package/dist/utils/background.js.map +1 -0
- package/dist/utils/config.d.ts +13 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +65 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/files.d.ts +14 -0
- package/dist/utils/files.d.ts.map +1 -0
- package/dist/utils/files.js +141 -0
- package/dist/utils/files.js.map +1 -0
- package/dist/utils/flavor.d.ts +48 -0
- package/dist/utils/flavor.d.ts.map +1 -0
- package/dist/utils/flavor.js +79 -0
- package/dist/utils/flavor.js.map +1 -0
- package/dist/utils/git.d.ts +29 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +90 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/output.d.ts +5 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +206 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/report.d.ts +12 -0
- package/dist/utils/report.d.ts.map +1 -0
- package/dist/utils/report.js +190 -0
- package/dist/utils/report.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { getDeviceId, saveEmail } from "./config.js";
|
|
2
|
+
import { cacheFlavor } from "./flavor.js";
|
|
3
|
+
const API_BASE = process.env.SALLY_API_URL || "https://cynicalsally-web.onrender.com";
|
|
4
|
+
const FETCH_TIMEOUT_MS = 120_000; // 2 minutes (Sonnet FT can take a while)
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// API Client
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
export class ApiError extends Error {
|
|
9
|
+
statusCode;
|
|
10
|
+
constructor(statusCode, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.statusCode = statusCode;
|
|
13
|
+
this.name = "ApiError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Submit code for roasting via the Render backend */
|
|
17
|
+
export async function submitRoast(params) {
|
|
18
|
+
const deviceId = getDeviceId();
|
|
19
|
+
const url = `${API_BASE}/api/v1/review`;
|
|
20
|
+
const res = await fetch(url, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: { "Content-Type": "application/json" },
|
|
23
|
+
body: JSON.stringify({ ...params, deviceId }),
|
|
24
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
25
|
+
});
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
28
|
+
const message = body.error || `HTTP ${res.status}`;
|
|
29
|
+
// Use backend's Sally-voiced message when available
|
|
30
|
+
throw new ApiError(res.status, message);
|
|
31
|
+
}
|
|
32
|
+
return (await res.json());
|
|
33
|
+
}
|
|
34
|
+
/** Submit a premium tool request via the Render backend */
|
|
35
|
+
export async function submitTool(params) {
|
|
36
|
+
const deviceId = getDeviceId();
|
|
37
|
+
const url = `${API_BASE}/api/v1/tool`;
|
|
38
|
+
const res = await fetch(url, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: { "Content-Type": "application/json" },
|
|
41
|
+
body: JSON.stringify({ ...params, deviceId }),
|
|
42
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
46
|
+
const message = body.error || `HTTP ${res.status}`;
|
|
47
|
+
throw new ApiError(res.status, message);
|
|
48
|
+
}
|
|
49
|
+
return (await res.json());
|
|
50
|
+
}
|
|
51
|
+
/** Request magic link login */
|
|
52
|
+
export async function requestMagicLink(email) {
|
|
53
|
+
const deviceId = getDeviceId();
|
|
54
|
+
const res = await fetch(`${API_BASE}/api/v1/auth/magic-link`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: { "Content-Type": "application/json" },
|
|
57
|
+
body: JSON.stringify({ email, deviceId }),
|
|
58
|
+
});
|
|
59
|
+
return await res.json();
|
|
60
|
+
}
|
|
61
|
+
/** Check entitlements (quota, SuperClub status) + cache flavor */
|
|
62
|
+
export async function checkEntitlements() {
|
|
63
|
+
const deviceId = getDeviceId();
|
|
64
|
+
const res = await fetch(`${API_BASE}/api/v1/entitlements?deviceId=${deviceId}`);
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
return { isSuperClub: false, tier: null, quotaRemaining: 3, hasPrepaidGrant: false };
|
|
67
|
+
}
|
|
68
|
+
const data = (await res.json());
|
|
69
|
+
// Cache Sally's flavor text from backend
|
|
70
|
+
if (data.flavor) {
|
|
71
|
+
cacheFlavor(data.flavor);
|
|
72
|
+
}
|
|
73
|
+
// Auto-save email if returned by backend (SC users via Stripe)
|
|
74
|
+
if (data.email) {
|
|
75
|
+
saveEmail(data.email);
|
|
76
|
+
}
|
|
77
|
+
return data;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/utils/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Save a background job result for `sally results` to pick up */
|
|
2
|
+
export declare function saveResult(result: object, source: string): string;
|
|
3
|
+
/** Send OS notification */
|
|
4
|
+
export declare function sendNotification(title: string, message: string): void;
|
|
5
|
+
/** Spawn a detached background worker running sally roast with --bg-worker */
|
|
6
|
+
export declare function spawnBackgroundWorker(args: string[], cwd: string): void;
|
|
7
|
+
/** Ask user if they want to background the Full Truth review (single keypress) */
|
|
8
|
+
export declare function askBackground(promptText: string): Promise<boolean>;
|
|
9
|
+
//# sourceMappingURL=background.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/utils/background.ts"],"names":[],"mappings":"AAeA,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjE;AAOD,2BAA2B;AAC3B,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQrE;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAYvE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAyClE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { writeFileSync, mkdirSync, existsSync, openSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { exec } from "node:child_process";
|
|
6
|
+
const RESULTS_DIR = join(homedir(), ".sally", "results");
|
|
7
|
+
/** Ensure results directory exists */
|
|
8
|
+
function ensureResultsDir() {
|
|
9
|
+
if (!existsSync(RESULTS_DIR)) {
|
|
10
|
+
mkdirSync(RESULTS_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Save a background job result for `sally results` to pick up */
|
|
14
|
+
export function saveResult(result, source) {
|
|
15
|
+
ensureResultsDir();
|
|
16
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
17
|
+
const filename = `review-${timestamp}.json`;
|
|
18
|
+
const filepath = join(RESULTS_DIR, filename);
|
|
19
|
+
writeFileSync(filepath, JSON.stringify({ ...result, _source: source, _savedAt: new Date().toISOString() }, null, 2));
|
|
20
|
+
return filepath;
|
|
21
|
+
}
|
|
22
|
+
/** Sanitize string for safe shell use */
|
|
23
|
+
function shellEscape(s) {
|
|
24
|
+
return s.replace(/[\\'"$`!]/g, "\\$&").slice(0, 200);
|
|
25
|
+
}
|
|
26
|
+
/** Send OS notification */
|
|
27
|
+
export function sendNotification(title, message) {
|
|
28
|
+
const safeTitle = shellEscape(title);
|
|
29
|
+
const safeMessage = shellEscape(message);
|
|
30
|
+
if (process.platform === "darwin") {
|
|
31
|
+
exec(`osascript -e 'display notification "${safeMessage}" with title "${safeTitle}"'`);
|
|
32
|
+
}
|
|
33
|
+
else if (process.platform === "linux") {
|
|
34
|
+
exec(`notify-send "${safeTitle}" "${safeMessage}"`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Spawn a detached background worker running sally roast with --bg-worker */
|
|
38
|
+
export function spawnBackgroundWorker(args, cwd) {
|
|
39
|
+
ensureResultsDir();
|
|
40
|
+
const sallyBin = process.argv[1];
|
|
41
|
+
const logFile = join(homedir(), ".sally", "bg.log");
|
|
42
|
+
const out = openSync(logFile, "a");
|
|
43
|
+
const child = spawn(process.execPath, [sallyBin, "roast", ...args, "--bg-worker"], {
|
|
44
|
+
detached: true,
|
|
45
|
+
stdio: ["ignore", out, out],
|
|
46
|
+
cwd,
|
|
47
|
+
});
|
|
48
|
+
child.unref();
|
|
49
|
+
}
|
|
50
|
+
/** Ask user if they want to background the Full Truth review (single keypress) */
|
|
51
|
+
export function askBackground(promptText) {
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
console.log(promptText);
|
|
54
|
+
if (!process.stdin.isTTY) {
|
|
55
|
+
resolve(false);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let resolved = false;
|
|
59
|
+
const finish = (result) => {
|
|
60
|
+
if (resolved)
|
|
61
|
+
return;
|
|
62
|
+
resolved = true;
|
|
63
|
+
try {
|
|
64
|
+
process.stdin.setRawMode(false);
|
|
65
|
+
process.stdin.pause();
|
|
66
|
+
process.stdin.removeAllListeners("data");
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// ignore cleanup errors
|
|
70
|
+
}
|
|
71
|
+
resolve(result);
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
process.stdin.setRawMode(true);
|
|
75
|
+
process.stdin.resume();
|
|
76
|
+
process.stdin.setEncoding("utf8");
|
|
77
|
+
process.stdin.on("data", (key) => {
|
|
78
|
+
if (key === "\x03")
|
|
79
|
+
process.exit(0); // Ctrl+C
|
|
80
|
+
finish(key.toLowerCase() === "b");
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
finish(false);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Auto-continue after 8 seconds
|
|
88
|
+
setTimeout(() => finish(false), 8000);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=background.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background.js","sourceRoot":"","sources":["../../src/utils/background.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Get or create a persistent device ID */
|
|
2
|
+
export declare function getDeviceId(): string;
|
|
3
|
+
/** Save email after successful login */
|
|
4
|
+
export declare function saveEmail(email: string): void;
|
|
5
|
+
/** Get stored email */
|
|
6
|
+
export declare function getEmail(): string | undefined;
|
|
7
|
+
/** Clear session (logout) */
|
|
8
|
+
export declare function clearSession(): void;
|
|
9
|
+
/** Check if user is logged in */
|
|
10
|
+
export declare function isLoggedIn(): boolean;
|
|
11
|
+
/** Show tools hint once, then never again. Returns true if this is the first time. */
|
|
12
|
+
export declare function showToolsHint(): boolean;
|
|
13
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAkCA,2CAA2C;AAC3C,wBAAgB,WAAW,IAAI,MAAM,CAQpC;AAED,wCAAwC;AACxC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI7C;AAED,uBAAuB;AACvB,wBAAgB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7C;AAED,6BAA6B;AAC7B,wBAAgB,YAAY,IAAI,IAAI,CAInC;AAED,iCAAiC;AACjC,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,sFAAsF;AACtF,wBAAgB,aAAa,IAAI,OAAO,CAMvC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
const CONFIG_DIR = join(homedir(), ".sally");
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
7
|
+
function ensureConfigDir() {
|
|
8
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
9
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function readConfig() {
|
|
13
|
+
if (!existsSync(CONFIG_FILE))
|
|
14
|
+
return {};
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function writeConfig(config) {
|
|
23
|
+
ensureConfigDir();
|
|
24
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", { mode: 0o600 });
|
|
25
|
+
}
|
|
26
|
+
/** Get or create a persistent device ID */
|
|
27
|
+
export function getDeviceId() {
|
|
28
|
+
const config = readConfig();
|
|
29
|
+
if (config.device_id)
|
|
30
|
+
return config.device_id;
|
|
31
|
+
const id = randomUUID();
|
|
32
|
+
config.device_id = id;
|
|
33
|
+
writeConfig(config);
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
/** Save email after successful login */
|
|
37
|
+
export function saveEmail(email) {
|
|
38
|
+
const config = readConfig();
|
|
39
|
+
config.email = email;
|
|
40
|
+
writeConfig(config);
|
|
41
|
+
}
|
|
42
|
+
/** Get stored email */
|
|
43
|
+
export function getEmail() {
|
|
44
|
+
return readConfig().email;
|
|
45
|
+
}
|
|
46
|
+
/** Clear session (logout) */
|
|
47
|
+
export function clearSession() {
|
|
48
|
+
const config = readConfig();
|
|
49
|
+
delete config.email;
|
|
50
|
+
writeConfig(config);
|
|
51
|
+
}
|
|
52
|
+
/** Check if user is logged in */
|
|
53
|
+
export function isLoggedIn() {
|
|
54
|
+
return !!readConfig().email;
|
|
55
|
+
}
|
|
56
|
+
/** Show tools hint once, then never again. Returns true if this is the first time. */
|
|
57
|
+
export function showToolsHint() {
|
|
58
|
+
const config = readConfig();
|
|
59
|
+
if (config.tools_hint_shown)
|
|
60
|
+
return false;
|
|
61
|
+
config.tools_hint_shown = true;
|
|
62
|
+
writeConfig(config);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAc,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAQpD,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,SAAS,CAAC;IAE9C,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;IACxB,MAAM,CAAC,SAAS,GAAG,EAAE,CAAC;IACtB,WAAW,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,EAAE,CAAC,KAAK,CAAC;AAC5B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC;IACpB,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,UAAU;IACxB,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC;AAC9B,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,MAAM,CAAC,gBAAgB;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ReviewFile {
|
|
2
|
+
path: string;
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Read a single file for review.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readFileForReview(filePath: string): ReviewFile | null;
|
|
9
|
+
/**
|
|
10
|
+
* Walk a directory and collect files for review.
|
|
11
|
+
* Respects .gitignore, skips binaries and known non-code dirs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function collectFiles(dirPath: string): ReviewFile[];
|
|
14
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAgCD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAiBrE;AAkCD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAiD1D"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { readFileSync, statSync, readdirSync, existsSync, realpathSync } from "node:fs";
|
|
2
|
+
import { join, relative, extname, resolve } from "node:path";
|
|
3
|
+
// Extensions we skip (binaries, images, media, lockfiles)
|
|
4
|
+
const SKIP_EXTENSIONS = new Set([
|
|
5
|
+
".png", ".jpg", ".jpeg", ".gif", ".ico", ".svg", ".webp", ".avif",
|
|
6
|
+
".mp3", ".mp4", ".wav", ".ogg", ".webm", ".mov",
|
|
7
|
+
".woff", ".woff2", ".ttf", ".eot", ".otf",
|
|
8
|
+
".zip", ".gz", ".tar", ".bz2", ".7z", ".rar",
|
|
9
|
+
".exe", ".dll", ".so", ".dylib", ".bin",
|
|
10
|
+
".pdf", ".doc", ".docx", ".xls", ".xlsx",
|
|
11
|
+
".lock", ".lockb",
|
|
12
|
+
".map",
|
|
13
|
+
]);
|
|
14
|
+
// Directories we always skip
|
|
15
|
+
const SKIP_DIRS = new Set([
|
|
16
|
+
"node_modules", ".git", ".next", ".vercel", ".turbo",
|
|
17
|
+
"dist", "build", "out", ".output",
|
|
18
|
+
"__pycache__", ".pytest_cache", ".mypy_cache",
|
|
19
|
+
"vendor", "Pods", ".gradle",
|
|
20
|
+
"coverage", ".nyc_output",
|
|
21
|
+
]);
|
|
22
|
+
// Files we always skip
|
|
23
|
+
const SKIP_FILES = new Set([
|
|
24
|
+
"package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb",
|
|
25
|
+
".DS_Store", "Thumbs.db",
|
|
26
|
+
]);
|
|
27
|
+
const MAX_FILES = 50;
|
|
28
|
+
const MAX_FILE_SIZE = 100_000; // 100 KB
|
|
29
|
+
/**
|
|
30
|
+
* Read a single file for review.
|
|
31
|
+
*/
|
|
32
|
+
export function readFileForReview(filePath) {
|
|
33
|
+
try {
|
|
34
|
+
const stat = statSync(filePath);
|
|
35
|
+
if (!stat.isFile())
|
|
36
|
+
return null;
|
|
37
|
+
if (stat.size > MAX_FILE_SIZE)
|
|
38
|
+
return null;
|
|
39
|
+
if (SKIP_EXTENSIONS.has(extname(filePath).toLowerCase()))
|
|
40
|
+
return null;
|
|
41
|
+
if (SKIP_FILES.has(filePath.split("/").pop() || ""))
|
|
42
|
+
return null;
|
|
43
|
+
const content = readFileSync(filePath, "utf-8");
|
|
44
|
+
// Skip likely binary files (null bytes in first 512 chars)
|
|
45
|
+
if (content.slice(0, 512).includes("\0"))
|
|
46
|
+
return null;
|
|
47
|
+
return { path: filePath, content };
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Load .gitignore patterns from a directory.
|
|
55
|
+
* Returns a simple matcher function.
|
|
56
|
+
*/
|
|
57
|
+
function loadGitignore(dir) {
|
|
58
|
+
const gitignorePath = join(dir, ".gitignore");
|
|
59
|
+
if (!existsSync(gitignorePath))
|
|
60
|
+
return () => false;
|
|
61
|
+
try {
|
|
62
|
+
const lines = readFileSync(gitignorePath, "utf-8")
|
|
63
|
+
.split("\n")
|
|
64
|
+
.map((l) => l.trim())
|
|
65
|
+
.filter((l) => l && !l.startsWith("#"));
|
|
66
|
+
return (filePath) => {
|
|
67
|
+
const rel = relative(dir, filePath);
|
|
68
|
+
return lines.some((pattern) => {
|
|
69
|
+
// Simple glob matching: exact match, prefix match, or extension match
|
|
70
|
+
if (pattern.endsWith("/")) {
|
|
71
|
+
return rel.startsWith(pattern) || rel.includes("/" + pattern);
|
|
72
|
+
}
|
|
73
|
+
if (pattern.startsWith("*.")) {
|
|
74
|
+
return rel.endsWith(pattern.slice(1));
|
|
75
|
+
}
|
|
76
|
+
return rel === pattern || rel.startsWith(pattern + "/") || rel.includes("/" + pattern);
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return () => false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Walk a directory and collect files for review.
|
|
86
|
+
* Respects .gitignore, skips binaries and known non-code dirs.
|
|
87
|
+
*/
|
|
88
|
+
export function collectFiles(dirPath) {
|
|
89
|
+
const files = [];
|
|
90
|
+
const canonicalRoot = realpathSync(resolve(dirPath));
|
|
91
|
+
const isIgnored = loadGitignore(dirPath);
|
|
92
|
+
function walk(dir) {
|
|
93
|
+
if (files.length >= MAX_FILES)
|
|
94
|
+
return;
|
|
95
|
+
let entries;
|
|
96
|
+
try {
|
|
97
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (files.length >= MAX_FILES)
|
|
104
|
+
return;
|
|
105
|
+
const fullPath = join(dir, entry.name);
|
|
106
|
+
// Prevent path traversal via symlinks
|
|
107
|
+
let canonicalPath;
|
|
108
|
+
try {
|
|
109
|
+
canonicalPath = realpathSync(fullPath);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
continue; // broken symlink or inaccessible
|
|
113
|
+
}
|
|
114
|
+
if (!canonicalPath.startsWith(canonicalRoot))
|
|
115
|
+
continue;
|
|
116
|
+
if (entry.isDirectory()) {
|
|
117
|
+
if (SKIP_DIRS.has(entry.name))
|
|
118
|
+
continue;
|
|
119
|
+
if (isIgnored(fullPath))
|
|
120
|
+
continue;
|
|
121
|
+
walk(fullPath);
|
|
122
|
+
}
|
|
123
|
+
else if (entry.isFile()) {
|
|
124
|
+
if (SKIP_FILES.has(entry.name))
|
|
125
|
+
continue;
|
|
126
|
+
if (SKIP_EXTENSIONS.has(extname(entry.name).toLowerCase()))
|
|
127
|
+
continue;
|
|
128
|
+
if (isIgnored(fullPath))
|
|
129
|
+
continue;
|
|
130
|
+
const file = readFileForReview(fullPath);
|
|
131
|
+
if (file) {
|
|
132
|
+
file.path = relative(dirPath, fullPath);
|
|
133
|
+
files.push(file);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
walk(dirPath);
|
|
139
|
+
return files;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface Flavor {
|
|
2
|
+
spinner_quick: string;
|
|
3
|
+
spinner_ft: string;
|
|
4
|
+
bg_prompt: string;
|
|
5
|
+
bg_confirmed: string;
|
|
6
|
+
bg_results_hint: string;
|
|
7
|
+
quota_exhausted_qr: string;
|
|
8
|
+
quota_exhausted_ft: string;
|
|
9
|
+
usage_spinner: string;
|
|
10
|
+
usage_sc_greeting: string;
|
|
11
|
+
usage_free_upsell: string;
|
|
12
|
+
usage_anonymous: string;
|
|
13
|
+
login_spinner: string;
|
|
14
|
+
login_success: string;
|
|
15
|
+
login_already: string;
|
|
16
|
+
login_invalid_email: string;
|
|
17
|
+
login_failed: string;
|
|
18
|
+
logout_done: string;
|
|
19
|
+
logout_not_logged_in: string;
|
|
20
|
+
upgrade_already_sc: string;
|
|
21
|
+
upgrade_opening: string;
|
|
22
|
+
upgrade_waiting: string;
|
|
23
|
+
upgrade_success: string;
|
|
24
|
+
error_network: string;
|
|
25
|
+
error_generic: string;
|
|
26
|
+
no_files: string;
|
|
27
|
+
no_staged: string;
|
|
28
|
+
no_diff: string;
|
|
29
|
+
no_path: string;
|
|
30
|
+
scanning_dir: string;
|
|
31
|
+
found_staged: string;
|
|
32
|
+
found_unstaged: string;
|
|
33
|
+
found_last_commit: string;
|
|
34
|
+
report_saved: string;
|
|
35
|
+
fail_under: string;
|
|
36
|
+
tool_spinner_explain: string;
|
|
37
|
+
tool_spinner_review_pr: string;
|
|
38
|
+
tool_spinner_refactor: string;
|
|
39
|
+
tool_spinner_brainstorm: string;
|
|
40
|
+
tool_spinner_frontend: string;
|
|
41
|
+
tool_spinner_marketing: string;
|
|
42
|
+
tool_quota_exhausted: string;
|
|
43
|
+
}
|
|
44
|
+
/** Get cached flavor or return bland fallback */
|
|
45
|
+
export declare function getFlavor(): Flavor;
|
|
46
|
+
/** Save flavor from API response to cache */
|
|
47
|
+
export declare function cacheFlavor(flavor: Flavor): void;
|
|
48
|
+
//# sourceMappingURL=flavor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flavor.d.ts","sourceRoot":"","sources":["../../src/utils/flavor.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,MAAM;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IAGnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAoDD,iDAAiD;AACjD,wBAAgB,SAAS,IAAI,MAAM,CAYlC;AAED,6CAA6C;AAC7C,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAUhD"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
const SALLY_DIR = join(homedir(), ".sally");
|
|
5
|
+
const FLAVOR_CACHE = join(SALLY_DIR, "flavor.json");
|
|
6
|
+
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
7
|
+
/** Bare-bones fallbacks — intentionally bland. Sally's real voice is on the backend. */
|
|
8
|
+
const FALLBACK = {
|
|
9
|
+
spinner_quick: "Scanning...",
|
|
10
|
+
spinner_ft: "Analyzing...",
|
|
11
|
+
bg_prompt: "Press B to background this, or any key to wait...",
|
|
12
|
+
bg_confirmed: "Running in the background.",
|
|
13
|
+
bg_results_hint: "Run sally results to see the verdict.",
|
|
14
|
+
quota_exhausted_qr: "Monthly limit reached.",
|
|
15
|
+
quota_exhausted_ft: "Full Truth requires the Full Suite.",
|
|
16
|
+
usage_spinner: "Checking account...",
|
|
17
|
+
usage_sc_greeting: "Full Suite active.",
|
|
18
|
+
usage_free_upsell: "Run sally upgrade for more.",
|
|
19
|
+
usage_anonymous: "Not logged in.",
|
|
20
|
+
login_spinner: "Sending magic link...",
|
|
21
|
+
login_success: "Check your inbox.",
|
|
22
|
+
login_already: "Already logged in.",
|
|
23
|
+
login_invalid_email: "Invalid email.",
|
|
24
|
+
login_failed: "Failed to send.",
|
|
25
|
+
logout_done: "Logged out.",
|
|
26
|
+
logout_not_logged_in: "Not logged in.",
|
|
27
|
+
upgrade_already_sc: "Already Full Suite.",
|
|
28
|
+
upgrade_opening: "Opening Full Suite...",
|
|
29
|
+
upgrade_waiting: "Waiting for upgrade...",
|
|
30
|
+
upgrade_success: "Full Suite activated.",
|
|
31
|
+
error_network: "Network error.",
|
|
32
|
+
error_generic: "Something went wrong.",
|
|
33
|
+
no_files: "No files found.",
|
|
34
|
+
no_staged: "Nothing staged.",
|
|
35
|
+
no_diff: "No diff found.",
|
|
36
|
+
no_path: "Path not found.",
|
|
37
|
+
scanning_dir: "Scanning directory...",
|
|
38
|
+
found_staged: "Found staged changes.",
|
|
39
|
+
found_unstaged: "Found uncommitted changes.",
|
|
40
|
+
found_last_commit: "Roasting last commit.",
|
|
41
|
+
report_saved: "Saved to",
|
|
42
|
+
fail_under: "Below threshold.",
|
|
43
|
+
tool_spinner_explain: "Reading your code...",
|
|
44
|
+
tool_spinner_review_pr: "Reviewing PR...",
|
|
45
|
+
tool_spinner_refactor: "Analyzing for refactoring...",
|
|
46
|
+
tool_spinner_brainstorm: "Thinking about your idea...",
|
|
47
|
+
tool_spinner_frontend: "Inspecting frontend...",
|
|
48
|
+
tool_spinner_marketing: "Reading your copy...",
|
|
49
|
+
tool_quota_exhausted: "Tool limit reached.",
|
|
50
|
+
};
|
|
51
|
+
/** Get cached flavor or return bland fallback */
|
|
52
|
+
export function getFlavor() {
|
|
53
|
+
try {
|
|
54
|
+
if (existsSync(FLAVOR_CACHE)) {
|
|
55
|
+
const cached = JSON.parse(readFileSync(FLAVOR_CACHE, "utf-8"));
|
|
56
|
+
if (Date.now() - cached.cachedAt < CACHE_TTL_MS) {
|
|
57
|
+
return cached.flavor;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Cache corrupt — fall through
|
|
63
|
+
}
|
|
64
|
+
return FALLBACK;
|
|
65
|
+
}
|
|
66
|
+
/** Save flavor from API response to cache */
|
|
67
|
+
export function cacheFlavor(flavor) {
|
|
68
|
+
try {
|
|
69
|
+
if (!existsSync(SALLY_DIR)) {
|
|
70
|
+
mkdirSync(SALLY_DIR, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
const cached = { flavor, cachedAt: Date.now() };
|
|
73
|
+
writeFileSync(FLAVOR_CACHE, JSON.stringify(cached), { mode: 0o600 });
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Non-critical
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=flavor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flavor.js","sourceRoot":"","sources":["../../src/utils/flavor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AACpD,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAgD9C,wFAAwF;AACxF,MAAM,QAAQ,GAAW;IACvB,aAAa,EAAE,aAAa;IAC5B,UAAU,EAAE,cAAc;IAC1B,SAAS,EAAE,mDAAmD;IAC9D,YAAY,EAAE,4BAA4B;IAC1C,eAAe,EAAE,uCAAuC;IACxD,kBAAkB,EAAE,wBAAwB;IAC5C,kBAAkB,EAAE,qCAAqC;IACzD,aAAa,EAAE,qBAAqB;IACpC,iBAAiB,EAAE,oBAAoB;IACvC,iBAAiB,EAAE,6BAA6B;IAChD,eAAe,EAAE,gBAAgB;IACjC,aAAa,EAAE,uBAAuB;IACtC,aAAa,EAAE,mBAAmB;IAClC,aAAa,EAAE,oBAAoB;IACnC,mBAAmB,EAAE,gBAAgB;IACrC,YAAY,EAAE,iBAAiB;IAC/B,WAAW,EAAE,aAAa;IAC1B,oBAAoB,EAAE,gBAAgB;IACtC,kBAAkB,EAAE,qBAAqB;IACzC,eAAe,EAAE,uBAAuB;IACxC,eAAe,EAAE,wBAAwB;IACzC,eAAe,EAAE,uBAAuB;IACxC,aAAa,EAAE,gBAAgB;IAC/B,aAAa,EAAE,uBAAuB;IACtC,QAAQ,EAAE,iBAAiB;IAC3B,SAAS,EAAE,iBAAiB;IAC5B,OAAO,EAAE,gBAAgB;IACzB,OAAO,EAAE,iBAAiB;IAC1B,YAAY,EAAE,uBAAuB;IACrC,YAAY,EAAE,uBAAuB;IACrC,cAAc,EAAE,4BAA4B;IAC5C,iBAAiB,EAAE,uBAAuB;IAC1C,YAAY,EAAE,UAAU;IACxB,UAAU,EAAE,kBAAkB;IAC9B,oBAAoB,EAAE,sBAAsB;IAC5C,sBAAsB,EAAE,iBAAiB;IACzC,qBAAqB,EAAE,8BAA8B;IACrD,uBAAuB,EAAE,6BAA6B;IACtD,qBAAqB,EAAE,wBAAwB;IAC/C,sBAAsB,EAAE,sBAAsB;IAC9C,oBAAoB,EAAE,qBAAqB;CAC5C,CAAC;AAOF,iDAAiD;AACjD,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAiB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7E,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;gBAChD,OAAO,MAAM,CAAC,MAAM,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,MAAM,GAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC9D,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReviewFile } from "./files.js";
|
|
2
|
+
/**
|
|
3
|
+
* Check if we're inside a git repository.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isGitRepo(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Get staged changes as a unified diff.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getStagedChanges(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get unstaged (working directory) changes as a unified diff.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getUnstagedChanges(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get the last commit as a unified diff.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getLastCommitDiff(): string;
|
|
18
|
+
/**
|
|
19
|
+
* Get branch diff (current branch vs target branch).
|
|
20
|
+
*/
|
|
21
|
+
export declare function getBranchDiff(branch: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Parse a unified diff into a files array for the API.
|
|
24
|
+
*
|
|
25
|
+
* Extracts the changed files and their full content from the diff.
|
|
26
|
+
* For new/modified files, includes the "after" state.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseDiffToFiles(diff: string): ReviewFile[];
|
|
29
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAOnC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAyC3D"}
|