Fix: Add date validation in analysis.ts to prevent RangeError

swadhinbiswas committed 9 months ago
a7662cd
1 parent a8ea19b
commit a7662cd
188 files changed
+22463 -6084
▼.astro/settings.json
+5-0
1
+{
2
+ "_variables": {
3
+ "lastUpdateCheck": 1768929857510
4
+ }
5
+}
0
6
▼.astro/types.d.ts
+1-0
1
+/// <reference types="astro/client" />
0
2
▼cli/bin/och.ts
+302-21
1
1
#!/usr/bin/env node
2
2
/**
3
3
* OpenCodeHub CLI
4
- * Stack-first PR workflow tool with repo management
4
+ * Complete Git hosting platform with stack-first PR workflows
5
5
*/
6
6
7
7
import { Command } from "commander";
8
8
import chalk from "chalk";
9
+import { simpleGit } from "simple-git";
10
+
11
+// Import all command modules
9
12
import { stackCommands } from "../src/commands/stack/index.js";
10
13
import { authCommands } from "../src/commands/auth.js";
11
14
import { pushRepo, cloneRepo, createRepo, listRepos } from "../src/commands/repo.js";
15
+import { prCommands } from "../src/commands/pr/index.js";
16
+import { issueCommands } from "../src/commands/issue/index.js";
17
+import { ciCommands } from "../src/commands/ci/index.js";
18
+import { queueCommands } from "../src/commands/queue/index.js";
19
+import { reviewCommands } from "../src/commands/review/index.js";
20
+import { metricsCommands } from "../src/commands/metrics/index.js";
21
+import { configCommands } from "../src/commands/config/index.js";
22
+import { branchCommands } from "../src/commands/branch/index.js";
23
+import { releaseCommands } from "../src/commands/release/index.js";
24
+import { searchCommands } from "../src/commands/search/index.js";
25
+import { secretCommands } from "../src/commands/secret/index.js";
26
+import { sshKeyCommands } from "../src/commands/ssh-key/index.js";
27
+import { apiCommands } from "../src/commands/api/index.js";
28
+import { inboxCommand } from "../src/commands/inbox/index.js";
29
+import { notifyCommand } from "../src/commands/notify/index.js";
30
+import { automateCommand } from "../src/commands/automate/index.js";
31
+import { insightsCommand } from "../src/commands/insights/index.js";
12
32
33
+const git = simpleGit();
13
34
const program = new Command();
14
35
15
36
program
16
37
.name("och")
17
- .description("OpenCodeHub CLI - Git hosting and stack-first PR workflows")
18
- .version("1.0.0");
38
+ .description("OpenCodeHub CLI - Complete Git hosting with stack-first PR workflows")
39
+ .version("1.1.0");
40
+
41
+// ================================
42
+// Core Commands
43
+// ================================
19
44
20
-// Auth commands - authCommands is already named "auth"
45
+// Auth commands
21
46
program.addCommand(authCommands);
22
47
23
-// Stack commands - stackCommands is already named "stack"
48
+// Stack commands (Graphite-like workflow)
24
49
program.addCommand(stackCommands);
25
50
26
-// Repo commands
51
+// PR commands (GitHub/GitLab style)
52
+program.addCommand(prCommands);
53
+
54
+// Issue commands
55
+program.addCommand(issueCommands);
56
+
57
+// CI/CD commands
58
+program.addCommand(ciCommands);
59
+
60
+// Merge Queue commands
61
+program.addCommand(queueCommands);
62
+
63
+// Review commands (including AI review)
64
+program.addCommand(reviewCommands);
65
+
66
+// Metrics commands
67
+program.addCommand(metricsCommands);
68
+
69
+// Inbox commands (Graphite-style PR inbox)
70
+program.addCommand(inboxCommand);
71
+
72
+// Notification commands
73
+program.addCommand(notifyCommand);
74
+
75
+// Automation commands
76
+program.addCommand(automateCommand);
77
+
78
+// Insights commands
79
+program.addCommand(insightsCommand);
80
+
81
+// ================================
82
+// Repository Commands
83
+// ================================
84
+
27
85
const repoCommand = program
28
86
.command("repo")
29
87
.description("Repository management");
68
126
await listRepos();
69
127
});
70
128
71
-// Shorthand: och push (same as och repo push)
129
+// ================================
130
+// Branch & Config Commands
131
+// ================================
132
+
133
+program.addCommand(branchCommands);
134
+program.addCommand(configCommands);
135
+
136
+// ================================
137
+// Advanced Commands
138
+// ================================
139
+
140
+program.addCommand(releaseCommands);
141
+program.addCommand(searchCommands);
142
+program.addCommand(secretCommands);
143
+program.addCommand(sshKeyCommands);
144
+program.addCommand(apiCommands);
145
+
146
+// ================================
147
+// Shorthand Commands
148
+// ================================
149
+
150
+// och push (shorthand for repo push)
72
151
program
73
152
.command("push")
74
153
.description("Push to OpenCodeHub (shorthand for 'repo push')")
78
157
await pushRepo(options);
79
158
});
80
159
81
-// Repo init
160
+// och init
82
161
program
83
162
.command("init")
84
163
.description("Initialize repository for OpenCodeHub")
85
164
.option("-u, --url <url>", "OpenCodeHub server URL")
86
165
.action(async (options) => {
87
- console.log(chalk.blue("Initializing repository..."));
88
- console.log(`Server: ${options.url || "http://localhost:4321"}`);
89
- // TODO: Create .ochrc config
166
+ console.log(chalk.blue("Initializing repository for OpenCodeHub..."));
167
+
168
+ const { saveConfig } = await import("../src/lib/config.js");
169
+ if (options.url) {
170
+ saveConfig({ serverUrl: options.url });
171
+ console.log(chalk.green(`✓ Server URL set to ${options.url}`));
172
+ }
173
+
174
+ // Check if git repo exists
175
+ const isRepo = await git.checkIsRepo();
176
+ if (!isRepo) {
177
+ console.log(chalk.yellow("Not a git repository. Initialize with 'git init' first."));
178
+ return;
179
+ }
180
+
181
+ console.log(chalk.green("✓ Repository initialized for OpenCodeHub"));
182
+ console.log(chalk.dim("\nNext steps:"));
183
+ console.log(chalk.dim(" 1. Run 'och auth login' to authenticate"));
184
+ console.log(chalk.dim(" 2. Run 'och repo create <name>' to create remote"));
185
+ console.log(chalk.dim(" 3. Run 'och push' to push your code"));
90
186
});
91
187
92
-// Sync command
188
+// och sync (bidirectional sync)
93
189
program
94
190
.command("sync")
95
- .description("Bidirectional sync with remote")
96
- .action(async () => {
97
- console.log(chalk.blue("Syncing with remote..."));
98
- // TODO: Implement sync
191
+ .description("Sync with remote (fetch + push)")
192
+ .option("-f, --force", "Force push after sync")
193
+ .action(async (options) => {
194
+ const ora = (await import("ora")).default;
195
+ const spinner = ora("Syncing with remote...").start();
196
+
197
+ try {
198
+ spinner.text = "Fetching from remote...";
199
+ await git.fetch();
200
+
201
+ spinner.text = "Pulling changes...";
202
+ try {
203
+ await git.pull(["--rebase"]);
204
+ } catch (e) {
205
+ // May fail if no upstream
206
+ }
207
+
208
+ spinner.text = "Pushing changes...";
209
+ const pushArgs = options.force ? ["--force-with-lease"] : [];
210
+ await git.push(pushArgs);
211
+
212
+ spinner.succeed("Synced with remote");
213
+ } catch (error) {
214
+ spinner.fail("Sync failed");
215
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
216
+ process.exit(1);
217
+ }
99
218
});
100
219
101
-// Status command
220
+// och status (stack status)
102
221
program
103
222
.command("status")
104
223
.alias("st")
105
- .description("Show current stack status")
224
+ .description("Show current stack and branch status")
225
+ .action(async () => {
226
+ const branches = await git.branchLocal();
227
+ const currentBranch = branches.current;
228
+ const stackBranches = branches.all.filter(b => b.startsWith("stack/"));
229
+
230
+ console.log(chalk.bold("\n📊 Status\n"));
231
+ console.log(`Current branch: ${chalk.cyan(currentBranch)}`);
232
+
233
+ if (stackBranches.length > 0) {
234
+ console.log(`\nStack branches: ${stackBranches.length}`);
235
+ for (const branch of stackBranches) {
236
+ const isCurrent = branch === currentBranch;
237
+ const marker = isCurrent ? chalk.yellow("●") : chalk.dim("○");
238
+ console.log(` ${marker} ${isCurrent ? chalk.bold(branch) : branch}`);
239
+ }
240
+ }
241
+
242
+ // Show git status
243
+ const status = await git.status();
244
+ if (status.modified.length > 0 || status.not_added.length > 0 || status.staged.length > 0) {
245
+ console.log(chalk.bold("\nChanges:"));
246
+ if (status.staged.length > 0) {
247
+ console.log(chalk.green(` Staged: ${status.staged.length} files`));
248
+ }
249
+ if (status.modified.length > 0) {
250
+ console.log(chalk.yellow(` Modified: ${status.modified.length} files`));
251
+ }
252
+ if (status.not_added.length > 0) {
253
+ console.log(chalk.red(` Untracked: ${status.not_added.length} files`));
254
+ }
255
+ } else {
256
+ console.log(chalk.dim("\nWorking tree clean"));
257
+ }
258
+
259
+ console.log("");
260
+ });
261
+
262
+// och whoami (alias for auth status)
263
+program
264
+ .command("whoami")
265
+ .description("Show current authenticated user")
106
266
.action(async () => {
107
- console.log(chalk.blue("Stack Status"));
108
- console.log("─".repeat(40));
109
- // TODO: Show current stack
267
+ const { getConfig } = await import("../src/lib/config.js");
268
+ const config = getConfig();
269
+
270
+ if (!config.token) {
271
+ console.log(chalk.yellow("Not authenticated"));
272
+ console.log(chalk.dim("Run 'och auth login' to authenticate"));
273
+ return;
274
+ }
275
+
276
+ const ora = (await import("ora")).default;
277
+ const spinner = ora("Checking authentication...").start();
278
+
279
+ try {
280
+ const response = await fetch(`${config.serverUrl}/api/user`, {
281
+ headers: { "Authorization": `Bearer ${config.token}` },
282
+ });
283
+
284
+ if (response.ok) {
285
+ const userData = await response.json();
286
+ spinner.stop();
287
+ console.log(userData.data?.username || "unknown");
288
+ } else {
289
+ spinner.fail("Token is invalid or expired");
290
+ }
291
+ } catch {
292
+ spinner.fail("Could not connect to server");
293
+ }
294
+ });
295
+
296
+// ================================
297
+// Completions Command
298
+// ================================
299
+
300
+program
301
+ .command("completion")
302
+ .description("Generate shell completions")
303
+ .argument("<shell>", "Shell type (bash, zsh, fish)")
304
+ .action((shell: string) => {
305
+ const shells: Record<string, string> = {
306
+ bash: `
307
+# OpenCodeHub CLI bash completion
308
+_och_completions() {
309
+ local cur="\${COMP_WORDS[COMP_CWORD]}"
310
+ local commands="auth stack pr issue ci queue review metrics repo branch config release search secret ssh-key api push init sync status whoami"
311
+ COMPREPLY=($(compgen -W "$commands" -- "$cur"))
312
+}
313
+complete -F _och_completions och
314
+`,
315
+ zsh: `
316
+# OpenCodeHub CLI zsh completion
317
+#compdef och
318
+
319
+_och() {
320
+ local -a commands
321
+ commands=(
322
+ 'auth:Manage authentication'
323
+ 'stack:Manage stacked PRs'
324
+ 'pr:Manage pull requests'
325
+ 'issue:Manage issues'
326
+ 'ci:Manage CI/CD pipelines'
327
+ 'queue:Manage merge queue'
328
+ 'review:Manage code reviews'
329
+ 'metrics:View developer metrics'
330
+ 'repo:Repository management'
331
+ 'branch:Branch management'
332
+ 'config:CLI configuration'
333
+ 'release:Manage releases'
334
+ 'search:Search repositories, issues, PRs'
335
+ 'secret:Manage secrets'
336
+ 'ssh-key:Manage SSH keys'
337
+ 'api:Direct API access'
338
+ 'push:Push to remote'
339
+ 'init:Initialize repository'
340
+ 'sync:Sync with remote'
341
+ 'status:Show status'
342
+ 'whoami:Show current user'
343
+ )
344
+ _describe 'command' commands
345
+}
346
+
347
+compdef _och och
348
+`,
349
+ fish: `
350
+# OpenCodeHub CLI fish completion
351
+complete -c och -f
352
+complete -c och -n "__fish_use_subcommand" -a "auth" -d "Manage authentication"
353
+complete -c och -n "__fish_use_subcommand" -a "stack" -d "Manage stacked PRs"
354
+complete -c och -n "__fish_use_subcommand" -a "pr" -d "Manage pull requests"
355
+complete -c och -n "__fish_use_subcommand" -a "issue" -d "Manage issues"
356
+complete -c och -n "__fish_use_subcommand" -a "ci" -d "Manage CI/CD pipelines"
357
+complete -c och -n "__fish_use_subcommand" -a "queue" -d "Manage merge queue"
358
+complete -c och -n "__fish_use_subcommand" -a "review" -d "Manage code reviews"
359
+complete -c och -n "__fish_use_subcommand" -a "metrics" -d "View developer metrics"
360
+complete -c och -n "__fish_use_subcommand" -a "repo" -d "Repository management"
361
+complete -c och -n "__fish_use_subcommand" -a "branch" -d "Branch management"
362
+complete -c och -n "__fish_use_subcommand" -a "config" -d "CLI configuration"
363
+complete -c och -n "__fish_use_subcommand" -a "release" -d "Manage releases"
364
+complete -c och -n "__fish_use_subcommand" -a "search" -d "Search repos, issues, PRs"
365
+complete -c och -n "__fish_use_subcommand" -a "secret" -d "Manage secrets"
366
+complete -c och -n "__fish_use_subcommand" -a "ssh-key" -d "Manage SSH keys"
367
+complete -c och -n "__fish_use_subcommand" -a "api" -d "Direct API access"
368
+complete -c och -n "__fish_use_subcommand" -a "push" -d "Push to remote"
369
+complete -c och -n "__fish_use_subcommand" -a "init" -d "Initialize repository"
370
+complete -c och -n "__fish_use_subcommand" -a "sync" -d "Sync with remote"
371
+complete -c och -n "__fish_use_subcommand" -a "status" -d "Show status"
372
+complete -c och -n "__fish_use_subcommand" -a "whoami" -d "Show current user"
373
+`,
374
+ };
375
+
376
+ if (!shells[shell]) {
377
+ console.error(chalk.red(`Unknown shell: ${shell}`));
378
+ console.log(chalk.dim("Supported shells: bash, zsh, fish"));
379
+ process.exit(1);
380
+ }
381
+
382
+ console.log(shells[shell]);
110
383
});
111
384
385
+// ================================
386
+// Parse and Execute
387
+// ================================
388
+
112
389
program.parse(process.argv);
113
390
391
+// Show help if no arguments
392
+if (process.argv.length === 2) {
393
+ program.help();
394
+}
114
395
▼cli/package-lock.json
+26-0
10
10
"license": "MIT",
11
11
"dependencies": {
12
12
"chalk": "^5.3.0",
13
+ "cli-table3": "^0.6.5",
13
14
"commander": "^12.0.0",
14
15
"conf": "^12.0.0",
15
16
"inquirer": "^9.2.0",
30
31
"node": ">=18.0.0"
31
32
}
32
33
},
34
+ "node_modules/@colors/colors": {
35
+ "version": "1.5.0",
36
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
37
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
38
+ "license": "MIT",
39
+ "optional": true,
40
+ "engines": {
41
+ "node": ">=0.1.90"
42
+ }
43
+ },
33
44
"node_modules/@esbuild/aix-ppc64": {
34
45
"version": "0.27.2",
35
46
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
1263
1274
"url": "https://github.com/sponsors/sindresorhus"
1264
1275
}
1265
1276
},
1277
+ "node_modules/cli-table3": {
1278
+ "version": "0.6.5",
1279
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz",
1280
+ "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==",
1281
+ "license": "MIT",
1282
+ "dependencies": {
1283
+ "string-width": "^4.2.0"
1284
+ },
1285
+ "engines": {
1286
+ "node": "10.* || >= 12.*"
1287
+ },
1288
+ "optionalDependencies": {
1289
+ "@colors/colors": "1.5.0"
1290
+ }
1291
+ },
1266
1292
"node_modules/cli-width": {
1267
1293
"version": "4.1.0",
1268
1294
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
1269
1295
▼cli/package.json
+2-1
31
31
},
32
32
"dependencies": {
33
33
"chalk": "^5.3.0",
34
+ "cli-table3": "^0.6.5",
34
35
"commander": "^12.0.0",
35
36
"conf": "^12.0.0",
36
37
"inquirer": "^9.2.0",
61
62
"workflow",
62
63
"opencodehub"
63
64
]
64
-}
65
+}
65
66
▼cli/src/commands/api/index.ts
+156-0
1
+/**
2
+ * API Commands
3
+ * Make direct API requests to OpenCodeHub
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import { getConfig } from "../../lib/config.js";
9
+
10
+export const apiCommands = new Command("api")
11
+ .description("Make direct API requests")
12
+ .argument("<endpoint>", "API endpoint (e.g., /user or repos/owner/name)")
13
+ .option("-X, --method <method>", "HTTP method", "GET")
14
+ .option("-F, --field <field>", "Add field to request body (key=value)", (val, acc: string[]) => [...acc, val], [])
15
+ .option("-f, --raw-field <field>", "Add raw field (no JSON parsing)", (val, acc: string[]) => [...acc, val], [])
16
+ .option("-H, --header <header>", "Add header", (val, acc: string[]) => [...acc, val], [])
17
+ .option("--input <file>", "Read body from file")
18
+ .option("-q, --quiet", "Only output response body")
19
+ .option("--jq <query>", "Filter JSON output (basic support)")
20
+ .option("-i, --include", "Include response headers")
21
+ .action(async (endpoint: string, options) => {
22
+ const config = getConfig();
23
+ if (!config.token) {
24
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
25
+ process.exit(1);
26
+ }
27
+
28
+ try {
29
+ // Normalize endpoint
30
+ if (!endpoint.startsWith("/")) {
31
+ endpoint = "/" + endpoint;
32
+ }
33
+ if (!endpoint.startsWith("/api")) {
34
+ endpoint = "/api" + endpoint;
35
+ }
36
+
37
+ // Build headers
38
+ const headers: Record<string, string> = {
39
+ "Authorization": `Bearer ${config.token}`,
40
+ "Content-Type": "application/json",
41
+ };
42
+
43
+ for (const header of options.header) {
44
+ const [key, ...valueParts] = header.split(":");
45
+ headers[key.trim()] = valueParts.join(":").trim();
46
+ }
47
+
48
+ // Build body
49
+ let body: any = undefined;
50
+
51
+ if (options.input) {
52
+ const fs = await import("fs");
53
+ body = fs.readFileSync(options.input, "utf-8");
54
+ } else if (options.field.length > 0 || options.rawField.length > 0) {
55
+ body = {};
56
+ for (const field of options.field) {
57
+ const [key, ...valueParts] = field.split("=");
58
+ const value = valueParts.join("=");
59
+ // Try to parse as JSON
60
+ try {
61
+ body[key] = JSON.parse(value);
62
+ } catch {
63
+ body[key] = value;
64
+ }
65
+ }
66
+ for (const field of options.rawField) {
67
+ const [key, ...valueParts] = field.split("=");
68
+ body[key] = valueParts.join("=");
69
+ }
70
+ body = JSON.stringify(body);
71
+ }
72
+
73
+ const url = `${config.serverUrl}${endpoint}`;
74
+
75
+ if (!options.quiet) {
76
+ console.error(chalk.dim(`${options.method} ${url}\n`));
77
+ }
78
+
79
+ const response = await fetch(url, {
80
+ method: options.method,
81
+ headers,
82
+ body,
83
+ });
84
+
85
+ // Output headers if requested
86
+ if (options.include) {
87
+ console.log(chalk.cyan(`HTTP/1.1 ${response.status} ${response.statusText}`));
88
+ response.headers.forEach((value, key) => {
89
+ console.log(`${key}: ${value}`);
90
+ });
91
+ console.log("");
92
+ }
93
+
94
+ // Parse and output response
95
+ const contentType = response.headers.get("content-type") || "";
96
+
97
+ if (contentType.includes("application/json")) {
98
+ const data = await response.json();
99
+
100
+ if (options.jq) {
101
+ // Basic jq support
102
+ const output = applyJqFilter(data, options.jq);
103
+ console.log(JSON.stringify(output, null, 2));
104
+ } else {
105
+ console.log(JSON.stringify(data, null, 2));
106
+ }
107
+ } else {
108
+ const text = await response.text();
109
+ console.log(text);
110
+ }
111
+
112
+ if (!response.ok && !options.quiet) {
113
+ process.exit(1);
114
+ }
115
+ } catch (error) {
116
+ console.error(chalk.red("API request failed"));
117
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
118
+ process.exit(1);
119
+ }
120
+ });
121
+
122
+/**
123
+ * Basic jq-like filter support
124
+ */
125
+function applyJqFilter(data: any, query: string): any {
126
+ if (query === ".") return data;
127
+
128
+ const parts = query.split(".").filter(Boolean);
129
+ let result = data;
130
+
131
+ for (const part of parts) {
132
+ // Handle array index
133
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
134
+ if (arrayMatch) {
135
+ result = result[arrayMatch[1]][parseInt(arrayMatch[2])];
136
+ }
137
+ // Handle array access []
138
+ else if (part === "[]") {
139
+ // Already handled - just continue
140
+ }
141
+ // Handle property access
142
+ else {
143
+ if (Array.isArray(result)) {
144
+ result = result.map(item => item[part]);
145
+ } else {
146
+ result = result[part];
147
+ }
148
+ }
149
+
150
+ if (result === undefined) break;
151
+ }
152
+
153
+ return result;
154
+}
155
+
156
+export default apiCommands;
0
157
▼cli/src/commands/automate/index.ts
+305-0
1
+/**
2
+ * Automate CLI Commands
3
+ * Manage workflow automation rules
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import Table from "cli-table3";
10
+import inquirer from "inquirer";
11
+import { getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth } from "../../lib/api.js";
12
+import { getConfig } from "../../lib/config.js";
13
+import simpleGit from "simple-git";
14
+
15
+const git = simpleGit();
16
+
17
+export const automateCommand = new Command("automate")
18
+ .description("Manage workflow automation rules");
19
+
20
+// Helper to get repo info
21
+async function getRepoInfo() {
22
+ try {
23
+ const remotes = await git.getRemotes(true);
24
+ const origin = remotes.find((r) => r.name === "origin");
25
+ if (!origin?.refs?.fetch) return null;
26
+
27
+ const url = origin.refs.fetch;
28
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
29
+ if (!match) return null;
30
+
31
+ return { owner: match[1], name: match[2] };
32
+ } catch {
33
+ return null;
34
+ }
35
+}
36
+
37
+// List automation rules
38
+automateCommand
39
+ .command("list")
40
+ .description("List automation rules for current repository")
41
+ .option("--json", "Output as JSON")
42
+ .action(async (options) => {
43
+ const spinner = ora("Loading automation rules...").start();
44
+
45
+ try {
46
+ const config = getConfig();
47
+ if (!config.token) {
48
+ spinner.fail("Not authenticated. Run 'och auth login' first.");
49
+ process.exit(1);
50
+ }
51
+
52
+ const repoInfo = await getRepoInfo();
53
+ if (!repoInfo) {
54
+ spinner.fail("Not in a git repository with an origin remote");
55
+ process.exit(1);
56
+ }
57
+
58
+ // Get repository ID first
59
+ const repoRes = await getWithAuth(`/api/repos/${repoInfo.owner}/${repoInfo.name}`);
60
+ if (!repoRes.repository?.id) {
61
+ spinner.fail("Repository not found on OpenCodeHub");
62
+ process.exit(1);
63
+ }
64
+
65
+ const res = await getWithAuth(`/api/automation-rules?repositoryId=${repoRes.repository.id}`);
66
+ const rules = res.rules || [];
67
+
68
+ spinner.stop();
69
+
70
+ if (options.json) {
71
+ console.log(JSON.stringify(rules, null, 2));
72
+ return;
73
+ }
74
+
75
+ if (rules.length === 0) {
76
+ console.log(chalk.gray("\n ⚡ No automation rules. Create one with: och automate create\n"));
77
+ return;
78
+ }
79
+
80
+ console.log(chalk.bold(`\n⚡ Automation Rules for ${repoInfo.owner}/${repoInfo.name}\n`));
81
+
82
+ const table = new Table({
83
+ head: [
84
+ chalk.gray("Name"),
85
+ chalk.gray("Trigger"),
86
+ chalk.gray("Status"),
87
+ chalk.gray("Runs"),
88
+ ],
89
+ });
90
+
91
+ for (const rule of rules) {
92
+ table.push([
93
+ rule.name,
94
+ formatTrigger(rule.trigger),
95
+ rule.isEnabled ? chalk.green("enabled") : chalk.gray("disabled"),
96
+ String(rule.runCount || 0),
97
+ ]);
98
+ }
99
+
100
+ console.log(table.toString());
101
+ console.log();
102
+ } catch (error: any) {
103
+ spinner.fail(`Failed: ${error.message}`);
104
+ process.exit(1);
105
+ }
106
+ });
107
+
108
+// Create automation rule
109
+automateCommand
110
+ .command("create")
111
+ .description("Create a new automation rule")
112
+ .action(async () => {
113
+ try {
114
+ const config = getConfig();
115
+ if (!config.token) {
116
+ console.log(chalk.red("Not authenticated. Run 'och auth login' first."));
117
+ process.exit(1);
118
+ }
119
+
120
+ const repoInfo = await getRepoInfo();
121
+ if (!repoInfo) {
122
+ console.log(chalk.red("Not in a git repository"));
123
+ process.exit(1);
124
+ }
125
+
126
+ // Get repository ID
127
+ const repoRes = await getWithAuth(`/api/repos/${repoInfo.owner}/${repoInfo.name}`);
128
+ if (!repoRes.repository?.id) {
129
+ console.log(chalk.red("Repository not found on OpenCodeHub"));
130
+ process.exit(1);
131
+ }
132
+
133
+ console.log(chalk.bold(`\n⚡ Create Automation Rule for ${repoInfo.owner}/${repoInfo.name}\n`));
134
+
135
+ const answers = await inquirer.prompt([
136
+ {
137
+ type: "input",
138
+ name: "name",
139
+ message: "Rule name:",
140
+ validate: (input) => input.length > 0 || "Name required",
141
+ },
142
+ {
143
+ type: "list",
144
+ name: "trigger",
145
+ message: "When should this run?",
146
+ choices: [
147
+ { name: "PR is opened", value: "pr_opened" },
148
+ { name: "PR is approved", value: "pr_approved" },
149
+ { name: "CI passes", value: "ci_passed" },
150
+ { name: "CI fails", value: "ci_failed" },
151
+ { name: "Label is added", value: "label_added" },
152
+ { name: "Review is requested", value: "pr_review_requested" },
153
+ ],
154
+ },
155
+ {
156
+ type: "checkbox",
157
+ name: "actions",
158
+ message: "What actions to take?",
159
+ choices: [
160
+ { name: "Add label", value: "add_label" },
161
+ { name: "Assign reviewer", value: "assign_reviewer" },
162
+ { name: "Add to merge queue", value: "add_to_merge_queue" },
163
+ { name: "Trigger AI review", value: "trigger_ai_review" },
164
+ { name: "Add comment", value: "add_comment" },
165
+ ],
166
+ validate: (input) => input.length > 0 || "Select at least one action",
167
+ },
168
+ ]);
169
+
170
+ // Build actions array with params
171
+ const actions = [];
172
+ for (const action of answers.actions) {
173
+ const actionObj: any = { type: action, params: {} };
174
+
175
+ if (action === "add_label") {
176
+ const { label } = await inquirer.prompt([
177
+ { type: "input", name: "label", message: "Label name:" },
178
+ ]);
179
+ actionObj.params.label = label;
180
+ } else if (action === "assign_reviewer") {
181
+ const { reviewer } = await inquirer.prompt([
182
+ { type: "input", name: "reviewer", message: "Reviewer username (@codeowners for auto):" },
183
+ ]);
184
+ actionObj.params.assignee = reviewer;
185
+ } else if (action === "add_comment") {
186
+ const { comment } = await inquirer.prompt([
187
+ { type: "input", name: "comment", message: "Comment text:" },
188
+ ]);
189
+ actionObj.params.body = comment;
190
+ }
191
+
192
+ actions.push(actionObj);
193
+ }
194
+
195
+ const spinner = ora("Creating rule...").start();
196
+
197
+ await postWithAuth("/api/automation-rules", {
198
+ repositoryId: repoRes.repository.id,
199
+ name: answers.name,
200
+ trigger: answers.trigger,
201
+ actions: JSON.stringify(actions),
202
+ });
203
+
204
+ spinner.succeed(`Created automation: ${chalk.cyan(answers.name)}`);
205
+ } catch (error: any) {
206
+ console.error(chalk.red(`Failed: ${error.message}`));
207
+ }
208
+ });
209
+
210
+// Enable/disable rule
211
+automateCommand
212
+ .command("enable <name>")
213
+ .description("Enable an automation rule")
214
+ .action(async (name) => {
215
+ await toggleRule(name, true);
216
+ });
217
+
218
+automateCommand
219
+ .command("disable <name>")
220
+ .description("Disable an automation rule")
221
+ .action(async (name) => {
222
+ await toggleRule(name, false);
223
+ });
224
+
225
+async function toggleRule(name: string, enabled: boolean) {
226
+ const spinner = ora(`${enabled ? "Enabling" : "Disabling"} rule...`).start();
227
+
228
+ try {
229
+ const repoInfo = await getRepoInfo();
230
+ if (!repoInfo) {
231
+ spinner.fail("Not in a git repository");
232
+ return;
233
+ }
234
+
235
+ const repoRes = await getWithAuth(`/api/repos/${repoInfo.owner}/${repoInfo.name}`);
236
+ const res = await getWithAuth(`/api/automation-rules?repositoryId=${repoRes.repository?.id}`);
237
+ const rule = res.rules?.find((r: any) => r.name === name);
238
+
239
+ if (!rule) {
240
+ spinner.fail(`Rule "${name}" not found`);
241
+ return;
242
+ }
243
+
244
+ await patchWithAuth(`/api/automation-rules?id=${rule.id}`, { isEnabled: enabled });
245
+ spinner.succeed(`${enabled ? "Enabled" : "Disabled"}: ${chalk.cyan(name)}`);
246
+ } catch (error: any) {
247
+ spinner.fail(`Failed: ${error.message}`);
248
+ }
249
+}
250
+
251
+// Delete rule
252
+automateCommand
253
+ .command("delete <name>")
254
+ .description("Delete an automation rule")
255
+ .action(async (name) => {
256
+ try {
257
+ const { confirm } = await inquirer.prompt([
258
+ {
259
+ type: "confirm",
260
+ name: "confirm",
261
+ message: `Delete automation rule "${name}"?`,
262
+ default: false,
263
+ },
264
+ ]);
265
+
266
+ if (!confirm) return;
267
+
268
+ const spinner = ora("Deleting rule...").start();
269
+
270
+ const repoInfo = await getRepoInfo();
271
+ if (!repoInfo) {
272
+ spinner.fail("Not in a git repository");
273
+ return;
274
+ }
275
+
276
+ const repoRes = await getWithAuth(`/api/repos/${repoInfo.owner}/${repoInfo.name}`);
277
+ const res = await getWithAuth(`/api/automation-rules?repositoryId=${repoRes.repository?.id}`);
278
+ const rule = res.rules?.find((r: any) => r.name === name);
279
+
280
+ if (!rule) {
281
+ spinner.fail(`Rule "${name}" not found`);
282
+ return;
283
+ }
284
+
285
+ await deleteWithAuth(`/api/automation-rules?id=${rule.id}`);
286
+ spinner.succeed(`Deleted: ${chalk.cyan(name)}`);
287
+ } catch (error: any) {
288
+ console.error(chalk.red(`Failed: ${error.message}`));
289
+ }
290
+ });
291
+
292
+function formatTrigger(trigger: string): string {
293
+ const labels: Record<string, string> = {
294
+ pr_opened: "PR opened",
295
+ pr_approved: "PR approved",
296
+ pr_merged: "PR merged",
297
+ ci_passed: "CI passes",
298
+ ci_failed: "CI fails",
299
+ label_added: "Label added",
300
+ pr_review_requested: "Review requested",
301
+ };
302
+ return labels[trigger] || trigger;
303
+}
304
+
305
+export default automateCommand;
0
306
▼cli/src/commands/branch/index.ts
+239-0
1
+/**
2
+ * Branch Commands
3
+ * Manage git branches from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import { simpleGit } from "simple-git";
11
+
12
+const git = simpleGit();
13
+
14
+export const branchCommands = new Command("branch")
15
+ .description("Manage branches");
16
+
17
+// Branch Checkout (interactive)
18
+branchCommands
19
+ .command("checkout [branch]")
20
+ .alias("co")
21
+ .description("Checkout a branch (interactive if no branch specified)")
22
+ .action(async (branch?: string) => {
23
+ try {
24
+ if (branch) {
25
+ const spinner = ora(`Checking out ${branch}...`).start();
26
+ await git.checkout(branch);
27
+ spinner.succeed(`Checked out ${chalk.cyan(branch)}`);
28
+ return;
29
+ }
30
+
31
+ // Interactive mode
32
+ const branches = await git.branchLocal();
33
+ const currentBranch = branches.current;
34
+
35
+ const choices = branches.all.map(b => ({
36
+ name: b === currentBranch ? `${chalk.green("●")} ${b} ${chalk.dim("(current)")}` : ` ${b}`,
37
+ value: b,
38
+ short: b,
39
+ }));
40
+
41
+ const { selectedBranch } = await inquirer.prompt([
42
+ {
43
+ type: "list",
44
+ name: "selectedBranch",
45
+ message: "Select branch to checkout:",
46
+ choices,
47
+ pageSize: 15,
48
+ },
49
+ ]);
50
+
51
+ if (selectedBranch === currentBranch) {
52
+ console.log(chalk.dim("Already on that branch."));
53
+ return;
54
+ }
55
+
56
+ const spinner = ora(`Checking out ${selectedBranch}...`).start();
57
+ await git.checkout(selectedBranch);
58
+ spinner.succeed(`Checked out ${chalk.cyan(selectedBranch)}`);
59
+ } catch (error) {
60
+ console.error(chalk.red("Failed to checkout branch"));
61
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
62
+ process.exit(1);
63
+ }
64
+ });
65
+
66
+// Branch Rename
67
+branchCommands
68
+ .command("rename [old-name] <new-name>")
69
+ .alias("mv")
70
+ .description("Rename a branch (renames current branch if old-name not specified)")
71
+ .action(async (oldNameOrNewName: string, newName?: string) => {
72
+ try {
73
+ let oldBranch: string;
74
+ let targetNewName: string;
75
+
76
+ if (newName) {
77
+ oldBranch = oldNameOrNewName;
78
+ targetNewName = newName;
79
+ } else {
80
+ // Rename current branch
81
+ const branches = await git.branchLocal();
82
+ oldBranch = branches.current;
83
+ targetNewName = oldNameOrNewName;
84
+ }
85
+
86
+ const spinner = ora(`Renaming ${oldBranch} to ${targetNewName}...`).start();
87
+
88
+ await git.raw(["branch", "-m", oldBranch, targetNewName]);
89
+
90
+ spinner.succeed(`Renamed ${chalk.cyan(oldBranch)} to ${chalk.green(targetNewName)}`);
91
+ } catch (error) {
92
+ console.error(chalk.red("Failed to rename branch"));
93
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
94
+ process.exit(1);
95
+ }
96
+ });
97
+
98
+// Branch Delete
99
+branchCommands
100
+ .command("delete <branch>")
101
+ .alias("rm")
102
+ .description("Delete a branch")
103
+ .option("-f, --force", "Force delete even if not merged")
104
+ .option("-r, --remote", "Also delete remote branch")
105
+ .action(async (branch: string, options) => {
106
+ try {
107
+ // Check if trying to delete current branch
108
+ const branches = await git.branchLocal();
109
+ if (branch === branches.current) {
110
+ console.error(chalk.red("Cannot delete the current branch. Switch to another branch first."));
111
+ process.exit(1);
112
+ }
113
+
114
+ const spinner = ora(`Deleting branch ${branch}...`).start();
115
+
116
+ // Delete local branch
117
+ if (options.force) {
118
+ await git.branch(["-D", branch]);
119
+ } else {
120
+ await git.branch(["-d", branch]);
121
+ }
122
+
123
+ spinner.text = `Deleted local branch ${branch}`;
124
+
125
+ // Delete remote branch if requested
126
+ if (options.remote) {
127
+ try {
128
+ await git.push(["origin", "--delete", branch]);
129
+ spinner.succeed(`Deleted ${chalk.cyan(branch)} (local and remote)`);
130
+ } catch (remoteError) {
131
+ spinner.warn(`Deleted local branch ${chalk.cyan(branch)}, but failed to delete remote`);
132
+ console.error(chalk.dim(remoteError instanceof Error ? remoteError.message : ""));
133
+ }
134
+ } else {
135
+ spinner.succeed(`Deleted ${chalk.cyan(branch)}`);
136
+ }
137
+ } catch (error) {
138
+ console.error(chalk.red("Failed to delete branch"));
139
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
140
+ process.exit(1);
141
+ }
142
+ });
143
+
144
+// Branch List
145
+branchCommands
146
+ .command("list")
147
+ .alias("ls")
148
+ .description("List branches")
149
+ .option("-a, --all", "Show all branches including remote")
150
+ .option("-r, --remote", "Show only remote branches")
151
+ .action(async (options) => {
152
+ try {
153
+ let branches;
154
+
155
+ if (options.all) {
156
+ branches = await git.branch(["-a"]);
157
+ } else if (options.remote) {
158
+ branches = await git.branch(["-r"]);
159
+ } else {
160
+ branches = await git.branchLocal();
161
+ }
162
+
163
+ console.log(chalk.bold("\n🌿 Branches\n"));
164
+
165
+ for (const branch of branches.all) {
166
+ if (branch === branches.current) {
167
+ console.log(chalk.green(`● ${branch}`) + chalk.dim(" (current)"));
168
+ } else if (branch.startsWith("remotes/")) {
169
+ console.log(chalk.dim(` ${branch.replace("remotes/", "")}`));
170
+ } else {
171
+ console.log(` ${branch}`);
172
+ }
173
+ }
174
+
175
+ console.log("");
176
+ } catch (error) {
177
+ console.error(chalk.red("Failed to list branches"));
178
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
179
+ process.exit(1);
180
+ }
181
+ });
182
+
183
+// Branch Create
184
+branchCommands
185
+ .command("create <name>")
186
+ .alias("new")
187
+ .description("Create a new branch")
188
+ .option("-b, --base <branch>", "Base branch to create from")
189
+ .option("-c, --checkout", "Checkout the new branch after creation")
190
+ .action(async (name: string, options) => {
191
+ try {
192
+ const spinner = ora(`Creating branch ${name}...`).start();
193
+
194
+ if (options.base) {
195
+ await git.checkoutBranch(name, options.base);
196
+ if (!options.checkout) {
197
+ // Go back to previous branch
198
+ await git.checkout("-");
199
+ }
200
+ } else if (options.checkout) {
201
+ await git.checkoutLocalBranch(name);
202
+ } else {
203
+ await git.branch([name]);
204
+ }
205
+
206
+ if (options.checkout) {
207
+ spinner.succeed(`Created and checked out ${chalk.green(name)}`);
208
+ } else {
209
+ spinner.succeed(`Created branch ${chalk.green(name)}`);
210
+ }
211
+ } catch (error) {
212
+ console.error(chalk.red("Failed to create branch"));
213
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
214
+ process.exit(1);
215
+ }
216
+ });
217
+
218
+// Branch Track
219
+branchCommands
220
+ .command("track <remote-branch>")
221
+ .description("Create a local branch tracking a remote branch")
222
+ .action(async (remoteBranch: string) => {
223
+ try {
224
+ const spinner = ora(`Tracking ${remoteBranch}...`).start();
225
+
226
+ // Extract branch name from remote/branch format
227
+ const branchName = remoteBranch.replace(/^origin\//, "");
228
+
229
+ await git.checkout(["-b", branchName, "--track", `origin/${branchName}`]);
230
+
231
+ spinner.succeed(`Created ${chalk.green(branchName)} tracking ${chalk.cyan(`origin/${branchName}`)}`);
232
+ } catch (error) {
233
+ console.error(chalk.red("Failed to track branch"));
234
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
235
+ process.exit(1);
236
+ }
237
+ });
238
+
239
+export default branchCommands;
0
240
▼cli/src/commands/ci/index.ts
+350-0
1
+/**
2
+ * CI Commands
3
+ * Manage CI/CD pipelines from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import { simpleGit } from "simple-git";
10
+import { getConfig } from "../../lib/config.js";
11
+import { getWithAuth, postWithAuth } from "../../lib/api.js";
12
+
13
+const git = simpleGit();
14
+
15
+interface PipelineRun {
16
+ id: string;
17
+ number: number;
18
+ status: string;
19
+ conclusion?: string;
20
+ branch: string;
21
+ commit: string;
22
+ event: string;
23
+ createdAt: string;
24
+ startedAt?: string;
25
+ completedAt?: string;
26
+ duration?: number;
27
+ jobs?: PipelineJob[];
28
+}
29
+
30
+interface PipelineJob {
31
+ id: string;
32
+ name: string;
33
+ status: string;
34
+ conclusion?: string;
35
+ startedAt?: string;
36
+ completedAt?: string;
37
+}
38
+
39
+export const ciCommands = new Command("ci")
40
+ .description("Manage CI/CD pipelines");
41
+
42
+// Get repo info from git remote
43
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
44
+ try {
45
+ const remotes = await git.getRemotes(true);
46
+ const origin = remotes.find(r => r.name === "origin");
47
+ if (!origin?.refs?.push) return null;
48
+
49
+ const url = origin.refs.push;
50
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
51
+ if (match) {
52
+ return { owner: match[1], repo: match[2] };
53
+ }
54
+ return null;
55
+ } catch {
56
+ return null;
57
+ }
58
+}
59
+
60
+function getStatusIcon(status: string, conclusion?: string): string {
61
+ if (status === "completed") {
62
+ switch (conclusion) {
63
+ case "success": return chalk.green("✓");
64
+ case "failure": return chalk.red("✗");
65
+ case "cancelled": return chalk.yellow("⊘");
66
+ case "skipped": return chalk.dim("○");
67
+ default: return chalk.dim("?");
68
+ }
69
+ }
70
+ switch (status) {
71
+ case "queued": return chalk.yellow("◷");
72
+ case "in_progress": return chalk.blue("●");
73
+ case "waiting": return chalk.dim("◌");
74
+ default: return chalk.dim("?");
75
+ }
76
+}
77
+
78
+function formatDuration(seconds?: number): string {
79
+ if (!seconds) return "-";
80
+ if (seconds < 60) return `${seconds}s`;
81
+ const mins = Math.floor(seconds / 60);
82
+ const secs = seconds % 60;
83
+ return `${mins}m ${secs}s`;
84
+}
85
+
86
+// CI List
87
+ciCommands
88
+ .command("list")
89
+ .alias("ls")
90
+ .description("List pipeline runs")
91
+ .option("-b, --branch <branch>", "Filter by branch")
92
+ .option("-s, --status <status>", "Filter by status (queued, in_progress, completed)")
93
+ .option("-L, --limit <n>", "Maximum results", "20")
94
+ .action(async (options) => {
95
+ const config = getConfig();
96
+ if (!config.token) {
97
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
98
+ process.exit(1);
99
+ }
100
+
101
+ const spinner = ora("Fetching pipeline runs...").start();
102
+
103
+ try {
104
+ const repoInfo = await getRepoInfo();
105
+ if (!repoInfo) {
106
+ spinner.fail("Could not determine repository");
107
+ process.exit(1);
108
+ }
109
+
110
+ const params = new URLSearchParams();
111
+ if (options.branch) params.append("branch", options.branch);
112
+ if (options.status) params.append("status", options.status);
113
+ params.append("limit", options.limit);
114
+
115
+ const result = await getWithAuth<{ data: PipelineRun[] }>(
116
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/actions/runs?${params}`
117
+ );
118
+
119
+ spinner.stop();
120
+
121
+ if (result.data.length === 0) {
122
+ console.log(chalk.dim("No pipeline runs found."));
123
+ return;
124
+ }
125
+
126
+ console.log(chalk.bold(`\n🔄 Pipeline Runs (${result.data.length})\n`));
127
+
128
+ for (const run of result.data) {
129
+ const icon = getStatusIcon(run.status, run.conclusion);
130
+ const duration = formatDuration(run.duration);
131
+ const time = new Date(run.createdAt).toLocaleString();
132
+
133
+ console.log(`${icon} #${run.number} ${run.event} on ${chalk.cyan(run.branch)}`);
134
+ console.log(chalk.dim(` ${run.commit.slice(0, 7)} • ${time} • ${duration}`));
135
+ }
136
+
137
+ console.log("");
138
+ } catch (error) {
139
+ spinner.fail("Failed to list pipeline runs");
140
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
141
+ process.exit(1);
142
+ }
143
+ });
144
+
145
+// CI View
146
+ciCommands
147
+ .command("view <run-id>")
148
+ .description("View a pipeline run")
149
+ .option("-j, --jobs", "Show jobs")
150
+ .action(async (runId: string, options) => {
151
+ const config = getConfig();
152
+ if (!config.token) {
153
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
154
+ process.exit(1);
155
+ }
156
+
157
+ const spinner = ora("Fetching pipeline run...").start();
158
+
159
+ try {
160
+ const repoInfo = await getRepoInfo();
161
+ if (!repoInfo) {
162
+ spinner.fail("Could not determine repository");
163
+ process.exit(1);
164
+ }
165
+
166
+ const result = await getWithAuth<{ data: PipelineRun }>(
167
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/actions/runs/${runId}`
168
+ );
169
+
170
+ spinner.stop();
171
+
172
+ const run = result.data;
173
+ const icon = getStatusIcon(run.status, run.conclusion);
174
+
175
+ console.log(chalk.bold(`\n${icon} Pipeline Run #${run.number}\n`));
176
+ console.log(`Status: ${run.status}${run.conclusion ? ` (${run.conclusion})` : ""}`);
177
+ console.log(`Event: ${run.event}`);
178
+ console.log(`Branch: ${chalk.cyan(run.branch)}`);
179
+ console.log(`Commit: ${run.commit.slice(0, 7)}`);
180
+ console.log(`Started: ${run.startedAt ? new Date(run.startedAt).toLocaleString() : "-"}`);
181
+ console.log(`Duration: ${formatDuration(run.duration)}`);
182
+
183
+ if (run.jobs && run.jobs.length > 0) {
184
+ console.log(chalk.bold("\nJobs:"));
185
+ for (const job of run.jobs) {
186
+ const jobIcon = getStatusIcon(job.status, job.conclusion);
187
+ console.log(` ${jobIcon} ${job.name}`);
188
+ }
189
+ }
190
+
191
+ console.log("");
192
+ } catch (error) {
193
+ spinner.fail("Failed to fetch pipeline run");
194
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
195
+ process.exit(1);
196
+ }
197
+ });
198
+
199
+// CI Trace (stream logs)
200
+ciCommands
201
+ .command("trace <job-id>")
202
+ .alias("logs")
203
+ .description("Stream job logs")
204
+ .option("-f, --follow", "Follow log output")
205
+ .action(async (jobId: string, options) => {
206
+ const config = getConfig();
207
+ if (!config.token) {
208
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
209
+ process.exit(1);
210
+ }
211
+
212
+ const spinner = ora("Fetching job logs...").start();
213
+
214
+ try {
215
+ const repoInfo = await getRepoInfo();
216
+ if (!repoInfo) {
217
+ spinner.fail("Could not determine repository");
218
+ process.exit(1);
219
+ }
220
+
221
+ const result = await getWithAuth<{ data: { logs: string } }>(
222
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/actions/jobs/${jobId}/logs`
223
+ );
224
+
225
+ spinner.stop();
226
+
227
+ console.log(result.data.logs);
228
+ } catch (error) {
229
+ spinner.fail("Failed to fetch job logs");
230
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
231
+ process.exit(1);
232
+ }
233
+ });
234
+
235
+// CI Retry
236
+ciCommands
237
+ .command("retry <run-id>")
238
+ .alias("rerun")
239
+ .description("Retry a failed pipeline run")
240
+ .option("--failed-only", "Only retry failed jobs")
241
+ .action(async (runId: string, options) => {
242
+ const config = getConfig();
243
+ if (!config.token) {
244
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
245
+ process.exit(1);
246
+ }
247
+
248
+ const spinner = ora(`Retrying pipeline run #${runId}...`).start();
249
+
250
+ try {
251
+ const repoInfo = await getRepoInfo();
252
+ if (!repoInfo) {
253
+ spinner.fail("Could not determine repository");
254
+ process.exit(1);
255
+ }
256
+
257
+ await postWithAuth(
258
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/actions/runs/${runId}/rerun`,
259
+ { failedOnly: options.failedOnly }
260
+ );
261
+
262
+ spinner.succeed(`Retried pipeline run #${runId}`);
263
+ } catch (error) {
264
+ spinner.fail("Failed to retry pipeline run");
265
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
266
+ process.exit(1);
267
+ }
268
+ });
269
+
270
+// CI Cancel
271
+ciCommands
272
+ .command("cancel <run-id>")
273
+ .description("Cancel a running pipeline")
274
+ .action(async (runId: string) => {
275
+ const config = getConfig();
276
+ if (!config.token) {
277
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
278
+ process.exit(1);
279
+ }
280
+
281
+ const spinner = ora(`Cancelling pipeline run #${runId}...`).start();
282
+
283
+ try {
284
+ const repoInfo = await getRepoInfo();
285
+ if (!repoInfo) {
286
+ spinner.fail("Could not determine repository");
287
+ process.exit(1);
288
+ }
289
+
290
+ await postWithAuth(
291
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/actions/runs/${runId}/cancel`,
292
+ {}
293
+ );
294
+
295
+ spinner.succeed(`Cancelled pipeline run #${runId}`);
296
+ } catch (error) {
297
+ spinner.fail("Failed to cancel pipeline run");
298
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
299
+ process.exit(1);
300
+ }
301
+ });
302
+
303
+// CI Status (current branch)
304
+ciCommands
305
+ .command("status")
306
+ .description("Show CI status for current branch")
307
+ .action(async () => {
308
+ const config = getConfig();
309
+ if (!config.token) {
310
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
311
+ process.exit(1);
312
+ }
313
+
314
+ const spinner = ora("Checking CI status...").start();
315
+
316
+ try {
317
+ const repoInfo = await getRepoInfo();
318
+ if (!repoInfo) {
319
+ spinner.fail("Could not determine repository");
320
+ process.exit(1);
321
+ }
322
+
323
+ const currentBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
324
+
325
+ const result = await getWithAuth<{ data: PipelineRun[] }>(
326
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/actions/runs?branch=${currentBranch}&limit=1`
327
+ );
328
+
329
+ spinner.stop();
330
+
331
+ if (result.data.length === 0) {
332
+ console.log(chalk.dim(`No CI runs found for branch ${currentBranch}`));
333
+ return;
334
+ }
335
+
336
+ const run = result.data[0];
337
+ const icon = getStatusIcon(run.status, run.conclusion);
338
+
339
+ console.log(`\n${icon} ${run.status}${run.conclusion ? ` (${run.conclusion})` : ""}`);
340
+ console.log(chalk.dim(` Run #${run.number} on ${currentBranch}`));
341
+ console.log(chalk.dim(` ${run.commit.slice(0, 7)} • ${formatDuration(run.duration)}`));
342
+ console.log("");
343
+ } catch (error) {
344
+ spinner.fail("Failed to check CI status");
345
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
346
+ process.exit(1);
347
+ }
348
+ });
349
+
350
+export default ciCommands;
0
351
▼cli/src/commands/config/index.ts
+160-0
1
+/**
2
+ * Config Commands
3
+ * Manage CLI configuration
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import Conf from "conf";
9
+
10
+interface OchConfig {
11
+ serverUrl: string;
12
+ token: string;
13
+ defaultBranch: string;
14
+ editor: string;
15
+ pager: string;
16
+}
17
+
18
+const config = new Conf<OchConfig>({
19
+ projectName: "opencodehub-cli",
20
+ defaults: {
21
+ serverUrl: "http://localhost:4321",
22
+ token: "",
23
+ defaultBranch: "main",
24
+ editor: "",
25
+ pager: "",
26
+ },
27
+});
28
+
29
+const configDescriptions: Record<string, string> = {
30
+ serverUrl: "OpenCodeHub server URL",
31
+ token: "Personal access token",
32
+ defaultBranch: "Default base branch for PRs",
33
+ editor: "Editor to use for interactive editing",
34
+ pager: "Pager to use for long output",
35
+};
36
+
37
+export const configCommands = new Command("config")
38
+ .description("Manage CLI configuration");
39
+
40
+// Config List
41
+configCommands
42
+ .command("list")
43
+ .alias("ls")
44
+ .description("List all configuration values")
45
+ .action(() => {
46
+ console.log(chalk.bold("\n⚙️ CLI Configuration\n"));
47
+
48
+ const keys = ["serverUrl", "defaultBranch", "editor", "pager"];
49
+
50
+ for (const key of keys) {
51
+ const value = config.get(key as keyof OchConfig);
52
+ const desc = configDescriptions[key] || "";
53
+ const displayValue = value || chalk.dim("(not set)");
54
+
55
+ console.log(`${chalk.cyan(key)}: ${displayValue}`);
56
+ if (desc) {
57
+ console.log(chalk.dim(` ${desc}`));
58
+ }
59
+ }
60
+
61
+ // Show token status (not the actual token)
62
+ const hasToken = !!config.get("token");
63
+ console.log(`${chalk.cyan("token")}: ${hasToken ? chalk.green("●") + " configured" : chalk.dim("(not set)")}`);
64
+ console.log(chalk.dim(" Personal access token"));
65
+
66
+ console.log(chalk.dim(`\nConfig file: ${config.path}`));
67
+ console.log("");
68
+ });
69
+
70
+// Config Get
71
+configCommands
72
+ .command("get <key>")
73
+ .description("Get a configuration value")
74
+ .action((key: string) => {
75
+ const value = config.get(key as keyof OchConfig);
76
+
77
+ if (key === "token") {
78
+ if (value) {
79
+ console.log(value.slice(0, 12) + "...");
80
+ } else {
81
+ console.log(chalk.dim("(not set)"));
82
+ }
83
+ } else if (value !== undefined) {
84
+ console.log(value);
85
+ } else {
86
+ console.error(chalk.red(`Unknown config key: ${key}`));
87
+ console.log(chalk.dim("Available keys: serverUrl, token, defaultBranch, editor, pager"));
88
+ process.exit(1);
89
+ }
90
+ });
91
+
92
+// Config Set
93
+configCommands
94
+ .command("set <key> <value>")
95
+ .description("Set a configuration value")
96
+ .action((key: string, value: string) => {
97
+ const validKeys = ["serverUrl", "token", "defaultBranch", "editor", "pager"];
98
+
99
+ if (!validKeys.includes(key)) {
100
+ console.error(chalk.red(`Unknown config key: ${key}`));
101
+ console.log(chalk.dim(`Available keys: ${validKeys.join(", ")}`));
102
+ process.exit(1);
103
+ }
104
+
105
+ config.set(key as keyof OchConfig, value);
106
+ console.log(chalk.green(`✓ Set ${key} = ${key === "token" ? value.slice(0, 12) + "..." : value}`));
107
+ });
108
+
109
+// Config Unset
110
+configCommands
111
+ .command("unset <key>")
112
+ .alias("delete")
113
+ .description("Unset a configuration value")
114
+ .action((key: string) => {
115
+ const validKeys = ["serverUrl", "token", "defaultBranch", "editor", "pager"];
116
+
117
+ if (!validKeys.includes(key)) {
118
+ console.error(chalk.red(`Unknown config key: ${key}`));
119
+ process.exit(1);
120
+ }
121
+
122
+ config.delete(key as keyof OchConfig);
123
+ console.log(chalk.green(`✓ Unset ${key}`));
124
+ });
125
+
126
+// Config Path
127
+configCommands
128
+ .command("path")
129
+ .description("Show config file path")
130
+ .action(() => {
131
+ console.log(config.path);
132
+ });
133
+
134
+// Config Reset
135
+configCommands
136
+ .command("reset")
137
+ .description("Reset all configuration to defaults")
138
+ .option("-y, --yes", "Skip confirmation")
139
+ .action(async (options) => {
140
+ if (!options.yes) {
141
+ const inquirer = await import("inquirer");
142
+ const { confirm } = await inquirer.default.prompt([
143
+ {
144
+ type: "confirm",
145
+ name: "confirm",
146
+ message: "Reset all configuration to defaults?",
147
+ default: false,
148
+ },
149
+ ]);
150
+ if (!confirm) {
151
+ console.log(chalk.dim("Cancelled."));
152
+ return;
153
+ }
154
+ }
155
+
156
+ config.clear();
157
+ console.log(chalk.green("✓ Configuration reset to defaults"));
158
+ });
159
+
160
+export default configCommands;
0
161
▼cli/src/commands/inbox/index.ts
+230-0
1
+/**
2
+ * Inbox CLI Commands
3
+ * View and manage PR inbox with custom sections
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import Table from "cli-table3";
10
+import inquirer from "inquirer";
11
+import { getWithAuth, postWithAuth } from "../../lib/api.js";
12
+import { getConfig } from "../../lib/config.js";
13
+
14
+export const inboxCommand = new Command("inbox")
15
+ .description("View and manage your PR inbox");
16
+
17
+// List inbox items
18
+inboxCommand
19
+ .command("list")
20
+ .description("List PRs in your inbox")
21
+ .option("-s, --section <name>", "Filter by section name")
22
+ .option("--all", "Show all PRs including read")
23
+ .option("--json", "Output as JSON")
24
+ .action(async (options) => {
25
+ const spinner = ora("Loading inbox...").start();
26
+
27
+ try {
28
+ const config = getConfig();
29
+ if (!config.token) {
30
+ spinner.fail("Not authenticated. Run 'och auth login' first.");
31
+ process.exit(1);
32
+ }
33
+
34
+ // Get inbox sections
35
+ const sectionsRes = await getWithAuth("/api/inbox-sections");
36
+ const sections = sectionsRes.sections || [];
37
+
38
+ // Get PRs for inbox
39
+ const prsRes = await getWithAuth("/api/pull-requests?inbox=true");
40
+ const prs = prsRes.pullRequests || [];
41
+
42
+ spinner.stop();
43
+
44
+ if (options.json) {
45
+ console.log(JSON.stringify({ sections, prs }, null, 2));
46
+ return;
47
+ }
48
+
49
+ if (prs.length === 0) {
50
+ console.log(chalk.gray("\n 📭 Your inbox is empty!\n"));
51
+ return;
52
+ }
53
+
54
+ // Display sections
55
+ if (sections.length > 0) {
56
+ console.log(chalk.bold("\n📥 Inbox Sections\n"));
57
+ for (const section of sections) {
58
+ const sectionPrs = prs.filter((pr: any) => {
59
+ // Simple filter matching for demo
60
+ return true;
61
+ });
62
+ console.log(
63
+ ` ${chalk.cyan(section.name)} ${chalk.gray(`(${sectionPrs.length})`)}`
64
+ );
65
+ }
66
+ console.log();
67
+ }
68
+
69
+ // Display PRs
70
+ const table = new Table({
71
+ head: [
72
+ chalk.gray("#"),
73
+ chalk.gray("Title"),
74
+ chalk.gray("Author"),
75
+ chalk.gray("Status"),
76
+ chalk.gray("Updated"),
77
+ ],
78
+ colWidths: [8, 40, 15, 12, 12],
79
+ });
80
+
81
+ for (const pr of prs.slice(0, 20)) {
82
+ const statusColor =
83
+ pr.state === "open"
84
+ ? chalk.green
85
+ : pr.state === "merged"
86
+ ? chalk.magenta
87
+ : chalk.red;
88
+
89
+ table.push([
90
+ chalk.cyan(`#${pr.number}`),
91
+ pr.title.substring(0, 38),
92
+ pr.author?.username || "unknown",
93
+ statusColor(pr.state),
94
+ new Date(pr.updatedAt).toLocaleDateString(),
95
+ ]);
96
+ }
97
+
98
+ console.log(table.toString());
99
+ console.log(
100
+ chalk.gray(`\n Showing ${Math.min(prs.length, 20)} of ${prs.length} PRs\n`)
101
+ );
102
+ } catch (error: any) {
103
+ spinner.fail(`Failed to load inbox: ${error.message}`);
104
+ process.exit(1);
105
+ }
106
+ });
107
+
108
+// Section management
109
+const sectionCommand = inboxCommand
110
+ .command("section")
111
+ .description("Manage inbox sections");
112
+
113
+sectionCommand
114
+ .command("list")
115
+ .description("List custom sections")
116
+ .action(async () => {
117
+ const spinner = ora("Loading sections...").start();
118
+
119
+ try {
120
+ const res = await getWithAuth("/api/inbox-sections");
121
+ const sections = res.sections || [];
122
+
123
+ spinner.stop();
124
+
125
+ if (sections.length === 0) {
126
+ console.log(chalk.gray("\n No custom sections. Create one with: och inbox section create\n"));
127
+ return;
128
+ }
129
+
130
+ console.log(chalk.bold("\n📑 Inbox Sections\n"));
131
+ for (const section of sections) {
132
+ const filters = section.filters ? Object.keys(section.filters).length : 0;
133
+ console.log(
134
+ ` ${section.isDefault ? "📌" : "📁"} ${chalk.cyan(section.name)} ${chalk.gray(
135
+ `(${filters} filters)`
136
+ )}`
137
+ );
138
+ }
139
+ console.log();
140
+ } catch (error: any) {
141
+ spinner.fail(`Failed to load sections: ${error.message}`);
142
+ }
143
+ });
144
+
145
+sectionCommand
146
+ .command("create")
147
+ .description("Create a new inbox section")
148
+ .action(async () => {
149
+ try {
150
+ const answers = await inquirer.prompt([
151
+ {
152
+ type: "input",
153
+ name: "name",
154
+ message: "Section name:",
155
+ validate: (input) => input.length > 0 || "Name is required",
156
+ },
157
+ {
158
+ type: "checkbox",
159
+ name: "filters",
160
+ message: "Select filters:",
161
+ choices: [
162
+ { name: "Needs my review", value: "isReviewRequested" },
163
+ { name: "Authored by me", value: "isAuthoredByMe" },
164
+ { name: "CI passing", value: "ciPassing" },
165
+ { name: "Ready to merge", value: "readyToMerge" },
166
+ { name: "Has conflicts", value: "hasConflicts" },
167
+ ],
168
+ },
169
+ ]);
170
+
171
+ const spinner = ora("Creating section...").start();
172
+
173
+ const filters: Record<string, boolean> = {};
174
+ for (const f of answers.filters) {
175
+ filters[f] = true;
176
+ }
177
+
178
+ await postWithAuth("/api/inbox-sections", {
179
+ name: answers.name,
180
+ filters,
181
+ });
182
+
183
+ spinner.succeed(`Created section: ${chalk.cyan(answers.name)}`);
184
+ } catch (error: any) {
185
+ console.error(chalk.red(`Failed to create section: ${error.message}`));
186
+ }
187
+ });
188
+
189
+sectionCommand
190
+ .command("delete <name>")
191
+ .description("Delete an inbox section")
192
+ .action(async (name) => {
193
+ try {
194
+ const { confirm } = await inquirer.prompt([
195
+ {
196
+ type: "confirm",
197
+ name: "confirm",
198
+ message: `Delete section "${name}"?`,
199
+ default: false,
200
+ },
201
+ ]);
202
+
203
+ if (!confirm) {
204
+ console.log(chalk.gray("Cancelled"));
205
+ return;
206
+ }
207
+
208
+ const spinner = ora("Deleting section...").start();
209
+
210
+ // Get section ID by name
211
+ const res = await getWithAuth("/api/inbox-sections");
212
+ const section = res.sections?.find((s: any) => s.name === name);
213
+
214
+ if (!section) {
215
+ spinner.fail(`Section "${name}" not found`);
216
+ return;
217
+ }
218
+
219
+ await postWithAuth("/api/inbox-sections", {
220
+ method: "DELETE",
221
+ id: section.id,
222
+ });
223
+
224
+ spinner.succeed(`Deleted section: ${chalk.cyan(name)}`);
225
+ } catch (error: any) {
226
+ console.error(chalk.red(`Failed to delete section: ${error.message}`));
227
+ }
228
+ });
229
+
230
+export default inboxCommand;
0
231
▼cli/src/commands/insights/index.ts
+261-0
1
+/**
2
+ * Insights CLI Commands
3
+ * View developer metrics and team insights
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import Table from "cli-table3";
10
+import { getWithAuth } from "../../lib/api.js";
11
+import { getConfig } from "../../lib/config.js";
12
+import simpleGit from "simple-git";
13
+
14
+const git = simpleGit();
15
+
16
+export const insightsCommand = new Command("insights")
17
+ .description("View developer metrics and insights");
18
+
19
+// Helper to get repo info
20
+async function getRepoInfo() {
21
+ try {
22
+ const remotes = await git.getRemotes(true);
23
+ const origin = remotes.find((r) => r.name === "origin");
24
+ if (!origin?.refs?.fetch) return null;
25
+
26
+ const url = origin.refs.fetch;
27
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
28
+ if (!match) return null;
29
+
30
+ return { owner: match[1], name: match[2] };
31
+ } catch {
32
+ return null;
33
+ }
34
+}
35
+
36
+// Show personal metrics
37
+insightsCommand
38
+ .command("show")
39
+ .description("Show your developer metrics")
40
+ .option("-p, --period <period>", "Time period: 1w, 4w, 3m, 1y", "4w")
41
+ .option("--json", "Output as JSON")
42
+ .action(async (options) => {
43
+ const spinner = ora("Loading metrics...").start();
44
+
45
+ try {
46
+ const config = getConfig();
47
+ if (!config.token) {
48
+ spinner.fail("Not authenticated. Run 'och auth login' first.");
49
+ process.exit(1);
50
+ }
51
+
52
+ const res = await getWithAuth(`/api/metrics/user?period=${options.period}`);
53
+
54
+ spinner.stop();
55
+
56
+ if (options.json) {
57
+ console.log(JSON.stringify(res, null, 2));
58
+ return;
59
+ }
60
+
61
+ const metrics = res.metrics || {
62
+ prsOpened: 0,
63
+ prsMerged: 0,
64
+ reviewsGiven: 0,
65
+ avgTimeToMerge: 0,
66
+ avgReviewTime: 0,
67
+ };
68
+
69
+ console.log(chalk.bold("\n📊 Your Developer Metrics\n"));
70
+ console.log(chalk.gray(` Period: Last ${formatPeriod(options.period)}\n`));
71
+
72
+ // Main metrics
73
+ const table = new Table({
74
+ chars: { mid: "", "left-mid": "", "mid-mid": "", "right-mid": "" },
75
+ });
76
+
77
+ table.push(
78
+ [chalk.cyan("PRs Opened"), chalk.bold.white(metrics.prsOpened)],
79
+ [chalk.magenta("PRs Merged"), chalk.bold.white(metrics.prsMerged)],
80
+ [chalk.blue("Reviews Given"), chalk.bold.white(metrics.reviewsGiven)],
81
+ [chalk.yellow("Avg Time to Merge"), chalk.bold.white(formatDuration(metrics.avgTimeToMerge))],
82
+ [chalk.green("Merge Rate"), chalk.bold.white(
83
+ metrics.prsOpened > 0
84
+ ? `${Math.round((metrics.prsMerged / metrics.prsOpened) * 100)}%`
85
+ : "N/A"
86
+ )],
87
+ );
88
+
89
+ console.log(table.toString());
90
+ console.log();
91
+
92
+ // Productivity tip
93
+ if (metrics.prsOpened > 0 && metrics.avgTimeToMerge > 48) {
94
+ console.log(chalk.yellow(" 💡 Tip: Your PRs take an average of " +
95
+ formatDuration(metrics.avgTimeToMerge) + " to merge."));
96
+ console.log(chalk.gray(" Consider smaller PRs for faster reviews.\n"));
97
+ }
98
+ } catch (error: any) {
99
+ spinner.fail(`Failed: ${error.message}`);
100
+ process.exit(1);
101
+ }
102
+ });
103
+
104
+// Show team metrics
105
+insightsCommand
106
+ .command("team")
107
+ .description("Show team/repository metrics and leaderboard")
108
+ .option("-p, --period <period>", "Time period: 1w, 4w, 3m, 1y", "4w")
109
+ .option("-n, --limit <n>", "Number of top contributors", "10")
110
+ .option("--json", "Output as JSON")
111
+ .action(async (options) => {
112
+ const spinner = ora("Loading team metrics...").start();
113
+
114
+ try {
115
+ const config = getConfig();
116
+ if (!config.token) {
117
+ spinner.fail("Not authenticated. Run 'och auth login' first.");
118
+ process.exit(1);
119
+ }
120
+
121
+ const repoInfo = await getRepoInfo();
122
+ let endpoint = `/api/metrics/team?period=${options.period}&limit=${options.limit}`;
123
+
124
+ if (repoInfo) {
125
+ const repoRes = await getWithAuth(`/api/repos/${repoInfo.owner}/${repoInfo.name}`);
126
+ if (repoRes.repository?.id) {
127
+ endpoint += `&repositoryId=${repoRes.repository.id}`;
128
+ }
129
+ }
130
+
131
+ const res = await getWithAuth(endpoint);
132
+
133
+ spinner.stop();
134
+
135
+ if (options.json) {
136
+ console.log(JSON.stringify(res, null, 2));
137
+ return;
138
+ }
139
+
140
+ const contributors = res.contributors || [];
141
+ const repoMetrics = res.metrics || {};
142
+
143
+ if (repoInfo) {
144
+ console.log(chalk.bold(`\n👥 Team Metrics for ${repoInfo.owner}/${repoInfo.name}\n`));
145
+ } else {
146
+ console.log(chalk.bold("\n👥 Team Metrics\n"));
147
+ }
148
+
149
+ console.log(chalk.gray(` Period: Last ${formatPeriod(options.period)}\n`));
150
+
151
+ // Repository summary
152
+ if (repoMetrics.totalPrs !== undefined) {
153
+ console.log(` Total PRs: ${chalk.cyan(repoMetrics.totalPrs)}`);
154
+ console.log(` Merged: ${chalk.green(repoMetrics.mergedPrs || 0)}`);
155
+ console.log(` Open: ${chalk.yellow(repoMetrics.openPrs || 0)}`);
156
+ console.log();
157
+ }
158
+
159
+ // Leaderboard
160
+ if (contributors.length > 0) {
161
+ console.log(chalk.bold(" 🏆 Top Contributors\n"));
162
+
163
+ const table = new Table({
164
+ head: [
165
+ chalk.gray("#"),
166
+ chalk.gray("Developer"),
167
+ chalk.gray("PRs"),
168
+ chalk.gray("Reviews"),
169
+ chalk.gray("Score"),
170
+ ],
171
+ });
172
+
173
+ contributors.forEach((c: any, i: number) => {
174
+ const medal = i === 0 ? "🥇" : i === 1 ? "🥈" : i === 2 ? "🥉" : `${i + 1}`;
175
+ const score = (c.prs || 0) * 2 + (c.reviews || 0);
176
+
177
+ table.push([
178
+ medal,
179
+ chalk.white(c.username),
180
+ chalk.cyan(c.prs || 0),
181
+ chalk.blue(c.reviews || 0),
182
+ chalk.yellow(score),
183
+ ]);
184
+ });
185
+
186
+ console.log(table.toString());
187
+ } else {
188
+ console.log(chalk.gray(" No contributor data available.\n"));
189
+ }
190
+
191
+ console.log();
192
+ } catch (error: any) {
193
+ spinner.fail(`Failed: ${error.message}`);
194
+ process.exit(1);
195
+ }
196
+ });
197
+
198
+// Repository metrics
199
+insightsCommand
200
+ .command("repo")
201
+ .description("Show current repository metrics")
202
+ .option("--json", "Output as JSON")
203
+ .action(async (options) => {
204
+ const spinner = ora("Loading repository metrics...").start();
205
+
206
+ try {
207
+ const repoInfo = await getRepoInfo();
208
+ if (!repoInfo) {
209
+ spinner.fail("Not in a git repository");
210
+ process.exit(1);
211
+ }
212
+
213
+ const res = await getWithAuth(`/api/repos/${repoInfo.owner}/${repoInfo.name}/metrics`);
214
+
215
+ spinner.stop();
216
+
217
+ if (options.json) {
218
+ console.log(JSON.stringify(res, null, 2));
219
+ return;
220
+ }
221
+
222
+ const m = res.metrics || {};
223
+
224
+ console.log(chalk.bold(`\n📈 Repository Metrics: ${repoInfo.owner}/${repoInfo.name}\n`));
225
+
226
+ const table = new Table();
227
+ table.push(
228
+ [chalk.gray("Stars"), chalk.yellow(`⭐ ${m.stars || 0}`)],
229
+ [chalk.gray("Forks"), chalk.blue(`🍴 ${m.forks || 0}`)],
230
+ [chalk.gray("Open PRs"), chalk.green(`📝 ${m.openPrs || 0}`)],
231
+ [chalk.gray("Open Issues"), chalk.red(`🐛 ${m.openIssues || 0}`)],
232
+ [chalk.gray("Contributors"), chalk.cyan(`👥 ${m.contributors || 0}`)],
233
+ [chalk.gray("Commits (30d)"), chalk.magenta(`📊 ${m.recentCommits || 0}`)],
234
+ );
235
+
236
+ console.log(table.toString());
237
+ console.log();
238
+ } catch (error: any) {
239
+ spinner.fail(`Failed: ${error.message}`);
240
+ process.exit(1);
241
+ }
242
+ });
243
+
244
+function formatPeriod(period: string): string {
245
+ const labels: Record<string, string> = {
246
+ "1w": "1 week",
247
+ "4w": "4 weeks",
248
+ "3m": "3 months",
249
+ "1y": "1 year",
250
+ };
251
+ return labels[period] || period;
252
+}
253
+
254
+function formatDuration(hours: number): string {
255
+ if (!hours || hours === 0) return "N/A";
256
+ if (hours < 1) return "< 1h";
257
+ if (hours < 24) return `${Math.round(hours)}h`;
258
+ return `${Math.round(hours / 24)}d`;
259
+}
260
+
261
+export default insightsCommand;
0
262
▼cli/src/commands/issue/index.ts
+370-0
1
+/**
2
+ * Issue Commands
3
+ * Manage issues from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import { simpleGit } from "simple-git";
11
+import { getConfig } from "../../lib/config.js";
12
+import { getWithAuth, postWithAuth, patchWithAuth } from "../../lib/api.js";
13
+
14
+const git = simpleGit();
15
+
16
+interface Issue {
17
+ id: string;
18
+ number: number;
19
+ title: string;
20
+ state: string;
21
+ author: { username: string };
22
+ createdAt: string;
23
+ updatedAt: string;
24
+ labels?: { name: string; color: string }[];
25
+ assignees?: { username: string }[];
26
+ milestone?: { title: string };
27
+}
28
+
29
+export const issueCommands = new Command("issue")
30
+ .description("Manage issues");
31
+
32
+// Get repo info from git remote
33
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
34
+ try {
35
+ const remotes = await git.getRemotes(true);
36
+ const origin = remotes.find(r => r.name === "origin");
37
+ if (!origin?.refs?.push) return null;
38
+
39
+ const url = origin.refs.push;
40
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
41
+ if (match) {
42
+ return { owner: match[1], repo: match[2] };
43
+ }
44
+ return null;
45
+ } catch {
46
+ return null;
47
+ }
48
+}
49
+
50
+// Issue Create
51
+issueCommands
52
+ .command("create")
53
+ .description("Create a new issue")
54
+ .option("-t, --title <title>", "Issue title")
55
+ .option("-b, --body <body>", "Issue description")
56
+ .option("-a, --assignee <user>", "Assign to user")
57
+ .option("-l, --label <label>", "Add label", (val, acc: string[]) => [...acc, val], [])
58
+ .option("-m, --milestone <name>", "Add to milestone")
59
+ .action(async (options) => {
60
+ const config = getConfig();
61
+ if (!config.token) {
62
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
63
+ process.exit(1);
64
+ }
65
+
66
+ try {
67
+ const repoInfo = await getRepoInfo();
68
+ if (!repoInfo) {
69
+ console.error(chalk.red("Could not determine repository"));
70
+ process.exit(1);
71
+ }
72
+
73
+ let title = options.title;
74
+ let body = options.body;
75
+
76
+ if (!title) {
77
+ const answers = await inquirer.prompt([
78
+ {
79
+ type: "input",
80
+ name: "title",
81
+ message: "Issue Title:",
82
+ validate: (input) => input.length > 0 || "Title is required",
83
+ },
84
+ {
85
+ type: "editor",
86
+ name: "body",
87
+ message: "Issue Description (optional):",
88
+ },
89
+ ]);
90
+ title = answers.title;
91
+ body = answers.body;
92
+ }
93
+
94
+ const spinner = ora("Creating issue...").start();
95
+
96
+ const result = await postWithAuth<{ data: Issue }>(
97
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues`,
98
+ {
99
+ title,
100
+ body,
101
+ assignee: options.assignee,
102
+ labels: options.label,
103
+ milestone: options.milestone,
104
+ }
105
+ );
106
+
107
+ spinner.succeed(`Created issue #${result.data.number}: ${result.data.title}`);
108
+ console.log(chalk.dim(` ${config.serverUrl}/${repoInfo.owner}/${repoInfo.repo}/issues/${result.data.number}`));
109
+ } catch (error) {
110
+ console.error(chalk.red("Failed to create issue"));
111
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
112
+ process.exit(1);
113
+ }
114
+ });
115
+
116
+// Issue List
117
+issueCommands
118
+ .command("list")
119
+ .alias("ls")
120
+ .description("List issues")
121
+ .option("-s, --state <state>", "Filter by state (open, closed, all)", "open")
122
+ .option("-a, --author <user>", "Filter by author")
123
+ .option("-A, --assignee <user>", "Filter by assignee")
124
+ .option("-l, --label <label>", "Filter by label")
125
+ .option("-m, --milestone <name>", "Filter by milestone")
126
+ .option("-L, --limit <n>", "Maximum results", "30")
127
+ .action(async (options) => {
128
+ const config = getConfig();
129
+ if (!config.token) {
130
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
131
+ process.exit(1);
132
+ }
133
+
134
+ const spinner = ora("Fetching issues...").start();
135
+
136
+ try {
137
+ const repoInfo = await getRepoInfo();
138
+ if (!repoInfo) {
139
+ spinner.fail("Could not determine repository");
140
+ process.exit(1);
141
+ }
142
+
143
+ const params = new URLSearchParams();
144
+ if (options.state !== "all") params.append("state", options.state);
145
+ if (options.author) params.append("author", options.author);
146
+ if (options.assignee) params.append("assignee", options.assignee);
147
+ if (options.label) params.append("label", options.label);
148
+ if (options.milestone) params.append("milestone", options.milestone);
149
+ params.append("limit", options.limit);
150
+
151
+ const result = await getWithAuth<{ data: Issue[] }>(
152
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues?${params}`
153
+ );
154
+
155
+ spinner.stop();
156
+
157
+ if (result.data.length === 0) {
158
+ console.log(chalk.dim("No issues found."));
159
+ return;
160
+ }
161
+
162
+ console.log(chalk.bold(`\n📋 Issues (${result.data.length})\n`));
163
+
164
+ for (const issue of result.data) {
165
+ const stateIcon = issue.state === "open" ? chalk.green("●") : chalk.red("●");
166
+ const labels = issue.labels?.map(l => chalk.hex(l.color || "#888")(l.name)).join(" ") || "";
167
+
168
+ console.log(`${stateIcon} #${issue.number} ${issue.title} ${labels}`);
169
+ console.log(chalk.dim(` @${issue.author.username} • ${new Date(issue.createdAt).toLocaleDateString()}`));
170
+ }
171
+
172
+ console.log("");
173
+ } catch (error) {
174
+ spinner.fail("Failed to list issues");
175
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
176
+ process.exit(1);
177
+ }
178
+ });
179
+
180
+// Issue View
181
+issueCommands
182
+ .command("view <number>")
183
+ .description("View an issue")
184
+ .option("-c, --comments", "Show comments")
185
+ .action(async (number: string, options) => {
186
+ const config = getConfig();
187
+ if (!config.token) {
188
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
189
+ process.exit(1);
190
+ }
191
+
192
+ const spinner = ora("Fetching issue...").start();
193
+
194
+ try {
195
+ const repoInfo = await getRepoInfo();
196
+ if (!repoInfo) {
197
+ spinner.fail("Could not determine repository");
198
+ process.exit(1);
199
+ }
200
+
201
+ const result = await getWithAuth<{ data: Issue & { body?: string } }>(
202
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues/${number}`
203
+ );
204
+
205
+ spinner.stop();
206
+
207
+ const issue = result.data;
208
+ const stateColor = issue.state === "open" ? chalk.green : chalk.red;
209
+
210
+ console.log(chalk.bold(`\n#${issue.number} ${issue.title}\n`));
211
+ console.log(`State: ${stateColor(issue.state.toUpperCase())}`);
212
+ console.log(`Author: @${issue.author.username}`);
213
+ console.log(`Created: ${new Date(issue.createdAt).toLocaleDateString()}`);
214
+
215
+ if (issue.labels && issue.labels.length > 0) {
216
+ const labels = issue.labels.map(l => chalk.hex(l.color || "#888")(l.name)).join(", ");
217
+ console.log(`Labels: ${labels}`);
218
+ }
219
+
220
+ if (issue.assignees && issue.assignees.length > 0) {
221
+ const assignees = issue.assignees.map(a => `@${a.username}`).join(", ");
222
+ console.log(`Assignees: ${assignees}`);
223
+ }
224
+
225
+ if (issue.milestone) {
226
+ console.log(`Milestone: ${issue.milestone.title}`);
227
+ }
228
+
229
+ if (result.data.body) {
230
+ console.log(chalk.dim("\n─".repeat(40)));
231
+ console.log(result.data.body);
232
+ }
233
+
234
+ console.log(chalk.dim("\n─".repeat(40)));
235
+ console.log(chalk.dim(`${config.serverUrl}/${repoInfo.owner}/${repoInfo.repo}/issues/${number}`));
236
+ console.log("");
237
+ } catch (error) {
238
+ spinner.fail("Failed to fetch issue");
239
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
240
+ process.exit(1);
241
+ }
242
+ });
243
+
244
+// Issue Close
245
+issueCommands
246
+ .command("close <number>")
247
+ .description("Close an issue")
248
+ .option("-c, --comment <comment>", "Add a closing comment")
249
+ .action(async (number: string, options) => {
250
+ const config = getConfig();
251
+ if (!config.token) {
252
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
253
+ process.exit(1);
254
+ }
255
+
256
+ const spinner = ora(`Closing issue #${number}...`).start();
257
+
258
+ try {
259
+ const repoInfo = await getRepoInfo();
260
+ if (!repoInfo) {
261
+ spinner.fail("Could not determine repository");
262
+ process.exit(1);
263
+ }
264
+
265
+ if (options.comment) {
266
+ await postWithAuth(
267
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues/${number}/comments`,
268
+ { body: options.comment }
269
+ );
270
+ }
271
+
272
+ await patchWithAuth(
273
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues/${number}`,
274
+ { state: "closed" }
275
+ );
276
+
277
+ spinner.succeed(`Closed issue #${number}`);
278
+ } catch (error) {
279
+ spinner.fail("Failed to close issue");
280
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
281
+ process.exit(1);
282
+ }
283
+ });
284
+
285
+// Issue Reopen
286
+issueCommands
287
+ .command("reopen <number>")
288
+ .description("Reopen an issue")
289
+ .action(async (number: string) => {
290
+ const config = getConfig();
291
+ if (!config.token) {
292
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
293
+ process.exit(1);
294
+ }
295
+
296
+ const spinner = ora(`Reopening issue #${number}...`).start();
297
+
298
+ try {
299
+ const repoInfo = await getRepoInfo();
300
+ if (!repoInfo) {
301
+ spinner.fail("Could not determine repository");
302
+ process.exit(1);
303
+ }
304
+
305
+ await patchWithAuth(
306
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues/${number}`,
307
+ { state: "open" }
308
+ );
309
+
310
+ spinner.succeed(`Reopened issue #${number}`);
311
+ } catch (error) {
312
+ spinner.fail("Failed to reopen issue");
313
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
314
+ process.exit(1);
315
+ }
316
+ });
317
+
318
+// Issue Comment
319
+issueCommands
320
+ .command("comment <number>")
321
+ .description("Add a comment to an issue")
322
+ .option("-b, --body <body>", "Comment body")
323
+ .action(async (number: string, options) => {
324
+ const config = getConfig();
325
+ if (!config.token) {
326
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
327
+ process.exit(1);
328
+ }
329
+
330
+ try {
331
+ const repoInfo = await getRepoInfo();
332
+ if (!repoInfo) {
333
+ console.error(chalk.red("Could not determine repository"));
334
+ process.exit(1);
335
+ }
336
+
337
+ let body = options.body;
338
+
339
+ if (!body) {
340
+ const answers = await inquirer.prompt([
341
+ {
342
+ type: "editor",
343
+ name: "body",
344
+ message: "Comment:",
345
+ },
346
+ ]);
347
+ body = answers.body;
348
+ }
349
+
350
+ if (!body || body.trim() === "") {
351
+ console.error(chalk.red("Comment cannot be empty"));
352
+ process.exit(1);
353
+ }
354
+
355
+ const spinner = ora("Adding comment...").start();
356
+
357
+ await postWithAuth(
358
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/issues/${number}/comments`,
359
+ { body }
360
+ );
361
+
362
+ spinner.succeed(`Added comment to issue #${number}`);
363
+ } catch (error) {
364
+ console.error(chalk.red("Failed to add comment"));
365
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
366
+ process.exit(1);
367
+ }
368
+ });
369
+
370
+export default issueCommands;
0
371
▼cli/src/commands/metrics/index.ts
+205-0
1
+/**
2
+ * Metrics Commands
3
+ * View developer metrics from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import { simpleGit } from "simple-git";
10
+import { getConfig } from "../../lib/config.js";
11
+import { getWithAuth } from "../../lib/api.js";
12
+
13
+const git = simpleGit();
14
+
15
+interface UserMetrics {
16
+ authored: {
17
+ total: number;
18
+ merged: number;
19
+ avgTimeToMerge: number;
20
+ };
21
+ reviewed: {
22
+ total: number;
23
+ approvals: number;
24
+ changesRequested: number;
25
+ };
26
+ trends: Array<{
27
+ week: string;
28
+ authored: number;
29
+ reviewed: number;
30
+ }>;
31
+}
32
+
33
+interface RepoMetrics {
34
+ period: string;
35
+ prsOpened: number;
36
+ prsMerged: number;
37
+ avgTimeToFirstReview: number;
38
+ avgTimeToMerge: number;
39
+ avgReviewRounds: number;
40
+ topAuthors: Array<{ username: string; prCount: number }>;
41
+ topReviewers: Array<{ username: string; reviewCount: number }>;
42
+}
43
+
44
+export const metricsCommands = new Command("metrics")
45
+ .description("View developer metrics");
46
+
47
+// Get repo info from git remote
48
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
49
+ try {
50
+ const remotes = await git.getRemotes(true);
51
+ const origin = remotes.find(r => r.name === "origin");
52
+ if (!origin?.refs?.push) return null;
53
+
54
+ const url = origin.refs.push;
55
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
56
+ if (match) {
57
+ return { owner: match[1], repo: match[2] };
58
+ }
59
+ return null;
60
+ } catch {
61
+ return null;
62
+ }
63
+}
64
+
65
+function formatDuration(hours: number): string {
66
+ if (hours < 1) return `${Math.round(hours * 60)}m`;
67
+ if (hours < 24) return `${hours.toFixed(1)}h`;
68
+ return `${(hours / 24).toFixed(1)}d`;
69
+}
70
+
71
+function progressBar(value: number, max: number, width: number = 20): string {
72
+ const filled = Math.round((value / max) * width);
73
+ const empty = width - filled;
74
+ return chalk.green("━".repeat(filled)) + chalk.dim("━".repeat(empty));
75
+}
76
+
77
+// Metrics Show
78
+metricsCommands
79
+ .command("show")
80
+ .description("Show metrics")
81
+ .option("-u, --user <username>", "Show metrics for specific user")
82
+ .option("-r, --repo", "Show repository metrics")
83
+ .option("-w, --weeks <n>", "Number of weeks to show", "4")
84
+ .action(async (options) => {
85
+ const config = getConfig();
86
+ if (!config.token) {
87
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
88
+ process.exit(1);
89
+ }
90
+
91
+ const spinner = ora("Fetching metrics...").start();
92
+
93
+ try {
94
+ if (options.repo) {
95
+ // Repository metrics
96
+ const repoInfo = await getRepoInfo();
97
+ if (!repoInfo) {
98
+ spinner.fail("Could not determine repository");
99
+ process.exit(1);
100
+ }
101
+
102
+ const result = await getWithAuth<{ data: RepoMetrics[] }>(
103
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/metrics?weeks=${options.weeks}`
104
+ );
105
+
106
+ spinner.stop();
107
+ displayRepoMetrics(result.data, `${repoInfo.owner}/${repoInfo.repo}`);
108
+ } else {
109
+ // User metrics
110
+ const endpoint = options.user
111
+ ? `/api/users/${options.user}/metrics?weeks=${options.weeks}`
112
+ : `/api/user/metrics?weeks=${options.weeks}`;
113
+
114
+ const result = await getWithAuth<{ data: UserMetrics }>(endpoint);
115
+
116
+ spinner.stop();
117
+ displayUserMetrics(result.data, options.user || "You");
118
+ }
119
+ } catch (error) {
120
+ spinner.fail("Failed to fetch metrics");
121
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
122
+ process.exit(1);
123
+ }
124
+ });
125
+
126
+function displayUserMetrics(metrics: UserMetrics, username: string) {
127
+ console.log(chalk.bold(`\n📊 Metrics for ${username}\n`));
128
+
129
+ // Authored PRs
130
+ console.log(chalk.bold("PRs Authored"));
131
+ console.log(` Total: ${metrics.authored.total}`);
132
+ console.log(` Merged: ${metrics.authored.merged}`);
133
+ console.log(` Avg Merge: ${formatDuration(metrics.authored.avgTimeToMerge)}`);
134
+
135
+ // Reviews
136
+ console.log(chalk.bold("\nReviews Given"));
137
+ console.log(` Total: ${metrics.reviewed.total}`);
138
+ console.log(` Approvals: ${metrics.reviewed.approvals}`);
139
+ console.log(` Changes Requested: ${metrics.reviewed.changesRequested}`);
140
+
141
+ // Trends
142
+ if (metrics.trends && metrics.trends.length > 0) {
143
+ console.log(chalk.bold("\nWeekly Trend"));
144
+ const maxAuthored = Math.max(...metrics.trends.map(t => t.authored), 1);
145
+ const maxReviewed = Math.max(...metrics.trends.map(t => t.reviewed), 1);
146
+
147
+ for (const week of metrics.trends) {
148
+ console.log(chalk.dim(` ${week.week}`));
149
+ console.log(` Authored: ${progressBar(week.authored, maxAuthored)} ${week.authored}`);
150
+ console.log(` Reviewed: ${progressBar(week.reviewed, maxReviewed)} ${week.reviewed}`);
151
+ }
152
+ }
153
+
154
+ console.log("");
155
+}
156
+
157
+function displayRepoMetrics(metrics: RepoMetrics[], repoName: string) {
158
+ console.log(chalk.bold(`\n📊 Metrics for ${repoName}\n`));
159
+
160
+ if (metrics.length === 0) {
161
+ console.log(chalk.dim("No metrics data available."));
162
+ return;
163
+ }
164
+
165
+ const latest = metrics[0];
166
+
167
+ // PR Activity
168
+ console.log(chalk.bold("PR Activity (Latest Period)"));
169
+ console.log(` PRs Opened: ${latest.prsOpened}`);
170
+ console.log(` PRs Merged: ${latest.prsMerged}`);
171
+ console.log(` Avg First Review: ${formatDuration(latest.avgTimeToFirstReview)}`);
172
+ console.log(` Avg Time to Merge: ${formatDuration(latest.avgTimeToMerge)}`);
173
+ console.log(` Avg Review Rounds: ${latest.avgReviewRounds.toFixed(1)}`);
174
+
175
+ // Top Authors
176
+ if (latest.topAuthors && latest.topAuthors.length > 0) {
177
+ console.log(chalk.bold("\nTop Authors"));
178
+ const maxPRs = Math.max(...latest.topAuthors.map(a => a.prCount), 1);
179
+ for (const author of latest.topAuthors.slice(0, 5)) {
180
+ console.log(` @${author.username.padEnd(15)} ${progressBar(author.prCount, maxPRs, 15)} ${author.prCount}`);
181
+ }
182
+ }
183
+
184
+ // Top Reviewers
185
+ if (latest.topReviewers && latest.topReviewers.length > 0) {
186
+ console.log(chalk.bold("\nTop Reviewers"));
187
+ const maxReviews = Math.max(...latest.topReviewers.map(r => r.reviewCount), 1);
188
+ for (const reviewer of latest.topReviewers.slice(0, 5)) {
189
+ console.log(` @${reviewer.username.padEnd(15)} ${progressBar(reviewer.reviewCount, maxReviews, 15)} ${reviewer.reviewCount}`);
190
+ }
191
+ }
192
+
193
+ // Trends
194
+ if (metrics.length > 1) {
195
+ console.log(chalk.bold("\nWeekly Trend"));
196
+ const maxMerged = Math.max(...metrics.map(m => m.prsMerged), 1);
197
+ for (const week of metrics.slice(0, 4)) {
198
+ console.log(` ${week.period}: ${progressBar(week.prsMerged, maxMerged)} ${week.prsMerged} merged`);
199
+ }
200
+ }
201
+
202
+ console.log("");
203
+}
204
+
205
+export default metricsCommands;
0
206
▼cli/src/commands/notify/index.ts
+231-0
1
+/**
2
+ * Notify CLI Commands
3
+ * Manage notifications and preferences
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import Table from "cli-table3";
10
+import inquirer from "inquirer";
11
+import { getWithAuth, postWithAuth, patchWithAuth } from "../../lib/api.js";
12
+import { getConfig } from "../../lib/config.js";
13
+
14
+export const notifyCommand = new Command("notify")
15
+ .description("Manage notifications and preferences");
16
+
17
+// List notifications
18
+notifyCommand
19
+ .command("list")
20
+ .description("List your notifications")
21
+ .option("-u, --unread", "Show unread only")
22
+ .option("-n, --limit <n>", "Limit results", "20")
23
+ .option("--json", "Output as JSON")
24
+ .action(async (options) => {
25
+ const spinner = ora("Loading notifications...").start();
26
+
27
+ try {
28
+ const config = getConfig();
29
+ if (!config.token) {
30
+ spinner.fail("Not authenticated. Run 'och auth login' first.");
31
+ process.exit(1);
32
+ }
33
+
34
+ const filter = options.unread ? "unread" : "all";
35
+ const res = await getWithAuth(`/api/notifications?filter=${filter}&limit=${options.limit}`);
36
+ const notifications = res.notifications || [];
37
+
38
+ spinner.stop();
39
+
40
+ if (options.json) {
41
+ console.log(JSON.stringify(notifications, null, 2));
42
+ return;
43
+ }
44
+
45
+ if (notifications.length === 0) {
46
+ console.log(chalk.gray("\n 🔔 No notifications\n"));
47
+ return;
48
+ }
49
+
50
+ console.log(chalk.bold("\n🔔 Notifications\n"));
51
+
52
+ for (const notif of notifications) {
53
+ const icon = getNotificationIcon(notif.type);
54
+ const time = timeAgo(notif.createdAt);
55
+ const readIndicator = notif.isRead ? "" : chalk.cyan("●");
56
+
57
+ console.log(
58
+ ` ${icon} ${readIndicator} ${chalk.white(notif.title)} ${chalk.gray(`(${time})`)}`
59
+ );
60
+ if (notif.body) {
61
+ console.log(chalk.gray(` ${notif.body.substring(0, 60)}...`));
62
+ }
63
+ }
64
+
65
+ console.log();
66
+ } catch (error: any) {
67
+ spinner.fail(`Failed to load notifications: ${error.message}`);
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+// Mark notification as read
73
+notifyCommand
74
+ .command("read [id]")
75
+ .description("Mark notification(s) as read")
76
+ .option("-a, --all", "Mark all as read")
77
+ .action(async (id, options) => {
78
+ const spinner = ora("Marking as read...").start();
79
+
80
+ try {
81
+ if (options.all) {
82
+ await postWithAuth("/api/notifications/mark-all-read", {});
83
+ spinner.succeed("Marked all notifications as read");
84
+ } else if (id) {
85
+ await patchWithAuth(`/api/notifications/${id}`, { isRead: true });
86
+ spinner.succeed("Marked notification as read");
87
+ } else {
88
+ spinner.fail("Specify notification ID or use --all");
89
+ }
90
+ } catch (error: any) {
91
+ spinner.fail(`Failed: ${error.message}`);
92
+ }
93
+ });
94
+
95
+// View/update notification settings
96
+notifyCommand
97
+ .command("settings")
98
+ .description("View or update notification preferences")
99
+ .option("--show", "Show current settings")
100
+ .action(async (options) => {
101
+ try {
102
+ const config = getConfig();
103
+ if (!config.token) {
104
+ console.log(chalk.red("Not authenticated. Run 'och auth login' first."));
105
+ process.exit(1);
106
+ }
107
+
108
+ // Get current settings
109
+ const spinner = ora("Loading settings...").start();
110
+ let currentSettings;
111
+ try {
112
+ currentSettings = await getWithAuth("/api/user/notification-preferences");
113
+ } catch {
114
+ currentSettings = { preferences: {}, quietHours: null };
115
+ }
116
+ spinner.stop();
117
+
118
+ if (options.show) {
119
+ console.log(chalk.bold("\n⚙️ Notification Settings\n"));
120
+
121
+ const eventTypes = [
122
+ "mention", "assign", "review_request", "pr_approved",
123
+ "pr_merged", "ci_passed", "ci_failed"
124
+ ];
125
+
126
+ const table = new Table({
127
+ head: [chalk.gray("Event"), chalk.gray("Email"), chalk.gray("In-App")],
128
+ });
129
+
130
+ for (const event of eventTypes) {
131
+ const pref = currentSettings.preferences?.[event] || {};
132
+ table.push([
133
+ event,
134
+ pref.emailEnabled ? chalk.green("✓") : chalk.red("✗"),
135
+ pref.inAppEnabled ? chalk.green("✓") : chalk.red("✗"),
136
+ ]);
137
+ }
138
+
139
+ console.log(table.toString());
140
+
141
+ if (currentSettings.quietHours?.isEnabled) {
142
+ console.log(
143
+ chalk.yellow(
144
+ `\n 🌙 Quiet hours: ${currentSettings.quietHours.startTime} - ${currentSettings.quietHours.endTime}`
145
+ )
146
+ );
147
+ }
148
+
149
+ console.log();
150
+ return;
151
+ }
152
+
153
+ // Interactive settings update
154
+ const { category } = await inquirer.prompt([
155
+ {
156
+ type: "list",
157
+ name: "category",
158
+ message: "What would you like to configure?",
159
+ choices: [
160
+ { name: "Email notifications", value: "email" },
161
+ { name: "Quiet hours", value: "quietHours" },
162
+ { name: "Cancel", value: "cancel" },
163
+ ],
164
+ },
165
+ ]);
166
+
167
+ if (category === "cancel") return;
168
+
169
+ if (category === "quietHours") {
170
+ const hours = await inquirer.prompt([
171
+ {
172
+ type: "confirm",
173
+ name: "enabled",
174
+ message: "Enable quiet hours?",
175
+ default: currentSettings.quietHours?.isEnabled || false,
176
+ },
177
+ {
178
+ type: "input",
179
+ name: "start",
180
+ message: "Start time (HH:MM):",
181
+ default: currentSettings.quietHours?.startTime || "22:00",
182
+ when: (answers) => answers.enabled,
183
+ },
184
+ {
185
+ type: "input",
186
+ name: "end",
187
+ message: "End time (HH:MM):",
188
+ default: currentSettings.quietHours?.endTime || "08:00",
189
+ when: (answers) => answers.enabled,
190
+ },
191
+ ]);
192
+
193
+ const saveSpinner = ora("Saving settings...").start();
194
+ await postWithAuth("/api/user/notification-preferences", {
195
+ quietHours: {
196
+ isEnabled: hours.enabled,
197
+ startTime: hours.start,
198
+ endTime: hours.end,
199
+ },
200
+ });
201
+ saveSpinner.succeed("Quiet hours updated");
202
+ }
203
+ } catch (error: any) {
204
+ console.error(chalk.red(`Failed: ${error.message}`));
205
+ }
206
+ });
207
+
208
+function getNotificationIcon(type: string): string {
209
+ const icons: Record<string, string> = {
210
+ mention: "💬",
211
+ assign: "👤",
212
+ review_request: "👀",
213
+ pr_approved: "✅",
214
+ pr_changes_requested: "⚠️",
215
+ pr_merged: "🎉",
216
+ ci_passed: "✅",
217
+ ci_failed: "❌",
218
+ comment: "💬",
219
+ };
220
+ return icons[type] || "🔔";
221
+}
222
+
223
+function timeAgo(date: string): string {
224
+ const seconds = Math.floor((Date.now() - new Date(date).getTime()) / 1000);
225
+ if (seconds < 60) return "just now";
226
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
227
+ if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
228
+ return `${Math.floor(seconds / 86400)}d ago`;
229
+}
230
+
231
+export default notifyCommand;
0
232
▼cli/src/commands/pr/index.ts
+437-0
1
+/**
2
+ * PR Commands
3
+ * Manage pull requests from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import { simpleGit } from "simple-git";
11
+import { getConfig } from "../../lib/config.js";
12
+import { getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth } from "../../lib/api.js";
13
+
14
+const git = simpleGit();
15
+
16
+interface PullRequest {
17
+ id: string;
18
+ number: number;
19
+ title: string;
20
+ state: string;
21
+ author: { username: string };
22
+ sourceBranch: string;
23
+ targetBranch: string;
24
+ createdAt: string;
25
+ updatedAt: string;
26
+ isDraft: boolean;
27
+ additions?: number;
28
+ deletions?: number;
29
+ changedFiles?: number;
30
+}
31
+
32
+export const prCommands = new Command("pr")
33
+ .description("Manage pull requests");
34
+
35
+// Get repo info from git remote
36
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
37
+ try {
38
+ const remotes = await git.getRemotes(true);
39
+ const origin = remotes.find(r => r.name === "origin");
40
+ if (!origin?.refs?.push) return null;
41
+
42
+ const url = origin.refs.push;
43
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
44
+ if (match) {
45
+ return { owner: match[1], repo: match[2] };
46
+ }
47
+ return null;
48
+ } catch {
49
+ return null;
50
+ }
51
+}
52
+
53
+// PR Create
54
+prCommands
55
+ .command("create")
56
+ .description("Create a new pull request")
57
+ .option("-t, --title <title>", "PR title")
58
+ .option("-b, --body <body>", "PR description")
59
+ .option("-B, --base <branch>", "Base branch", "main")
60
+ .option("-d, --draft", "Create as draft PR")
61
+ .option("-a, --assignee <user>", "Assign to user")
62
+ .option("-l, --label <label>", "Add label (can be used multiple times)", (val, acc: string[]) => [...acc, val], [])
63
+ .action(async (options) => {
64
+ const config = getConfig();
65
+ if (!config.token) {
66
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
67
+ process.exit(1);
68
+ }
69
+
70
+ const spinner = ora("Preparing pull request...").start();
71
+
72
+ try {
73
+ const repoInfo = await getRepoInfo();
74
+ if (!repoInfo) {
75
+ spinner.fail("Could not determine repository");
76
+ process.exit(1);
77
+ }
78
+
79
+ const currentBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
80
+
81
+ if (currentBranch === options.base) {
82
+ spinner.fail(`Cannot create PR from ${options.base} to ${options.base}`);
83
+ process.exit(1);
84
+ }
85
+
86
+ spinner.stop();
87
+
88
+ // Get title interactively if not provided
89
+ let title = options.title;
90
+ let body = options.body;
91
+
92
+ if (!title) {
93
+ const lastCommit = await git.log({ maxCount: 1 });
94
+ const defaultTitle = lastCommit.latest?.message?.split("\n")[0] || currentBranch;
95
+
96
+ const answers = await inquirer.prompt([
97
+ {
98
+ type: "input",
99
+ name: "title",
100
+ message: "PR Title:",
101
+ default: defaultTitle,
102
+ },
103
+ {
104
+ type: "editor",
105
+ name: "body",
106
+ message: "PR Description (optional):",
107
+ },
108
+ ]);
109
+ title = answers.title;
110
+ body = answers.body;
111
+ }
112
+
113
+ spinner.start("Creating pull request...");
114
+
115
+ const result = await postWithAuth<{ data: PullRequest }>(
116
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls`,
117
+ {
118
+ title,
119
+ body,
120
+ sourceBranch: currentBranch,
121
+ targetBranch: options.base,
122
+ isDraft: options.draft || false,
123
+ assignee: options.assignee,
124
+ labels: options.label,
125
+ }
126
+ );
127
+
128
+ spinner.succeed(`Created PR #${result.data.number}: ${result.data.title}`);
129
+ console.log(chalk.dim(` ${config.serverUrl}/${repoInfo.owner}/${repoInfo.repo}/pull/${result.data.number}`));
130
+ } catch (error) {
131
+ spinner.fail("Failed to create pull request");
132
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
133
+ process.exit(1);
134
+ }
135
+ });
136
+
137
+// PR List
138
+prCommands
139
+ .command("list")
140
+ .alias("ls")
141
+ .description("List pull requests")
142
+ .option("-s, --state <state>", "Filter by state (open, closed, merged, all)", "open")
143
+ .option("-a, --author <user>", "Filter by author")
144
+ .option("-l, --label <label>", "Filter by label")
145
+ .option("-L, --limit <n>", "Maximum results", "30")
146
+ .action(async (options) => {
147
+ const config = getConfig();
148
+ if (!config.token) {
149
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
150
+ process.exit(1);
151
+ }
152
+
153
+ const spinner = ora("Fetching pull requests...").start();
154
+
155
+ try {
156
+ const repoInfo = await getRepoInfo();
157
+ if (!repoInfo) {
158
+ spinner.fail("Could not determine repository");
159
+ process.exit(1);
160
+ }
161
+
162
+ const params = new URLSearchParams();
163
+ if (options.state !== "all") params.append("state", options.state);
164
+ if (options.author) params.append("author", options.author);
165
+ if (options.label) params.append("label", options.label);
166
+ params.append("limit", options.limit);
167
+
168
+ const result = await getWithAuth<{ data: PullRequest[] }>(
169
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls?${params}`
170
+ );
171
+
172
+ spinner.stop();
173
+
174
+ if (result.data.length === 0) {
175
+ console.log(chalk.dim("No pull requests found."));
176
+ return;
177
+ }
178
+
179
+ console.log(chalk.bold(`\n📋 Pull Requests (${result.data.length})\n`));
180
+
181
+ for (const pr of result.data) {
182
+ const stateIcon = pr.state === "open" ? chalk.green("●") :
183
+ pr.state === "merged" ? chalk.magenta("●") : chalk.red("●");
184
+ const draftLabel = pr.isDraft ? chalk.dim(" [draft]") : "";
185
+
186
+ console.log(`${stateIcon} #${pr.number} ${pr.title}${draftLabel}`);
187
+ console.log(chalk.dim(` ${pr.sourceBranch} → ${pr.targetBranch} • @${pr.author.username}`));
188
+ }
189
+
190
+ console.log("");
191
+ } catch (error) {
192
+ spinner.fail("Failed to list pull requests");
193
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
194
+ process.exit(1);
195
+ }
196
+ });
197
+
198
+// PR View
199
+prCommands
200
+ .command("view <number>")
201
+ .description("View a pull request")
202
+ .option("-w, --web", "Open in browser")
203
+ .action(async (number: string, options) => {
204
+ const config = getConfig();
205
+ if (!config.token) {
206
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
207
+ process.exit(1);
208
+ }
209
+
210
+ const spinner = ora("Fetching pull request...").start();
211
+
212
+ try {
213
+ const repoInfo = await getRepoInfo();
214
+ if (!repoInfo) {
215
+ spinner.fail("Could not determine repository");
216
+ process.exit(1);
217
+ }
218
+
219
+ const result = await getWithAuth<{ data: PullRequest & { body?: string } }>(
220
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${number}`
221
+ );
222
+
223
+ spinner.stop();
224
+
225
+ const pr = result.data;
226
+ const stateColor = pr.state === "open" ? chalk.green :
227
+ pr.state === "merged" ? chalk.magenta : chalk.red;
228
+
229
+ console.log(chalk.bold(`\n#${pr.number} ${pr.title}\n`));
230
+ console.log(`State: ${stateColor(pr.state.toUpperCase())}${pr.isDraft ? chalk.dim(" (draft)") : ""}`);
231
+ console.log(`Author: @${pr.author.username}`);
232
+ console.log(`Branch: ${pr.sourceBranch} → ${pr.targetBranch}`);
233
+ console.log(`Created: ${new Date(pr.createdAt).toLocaleDateString()}`);
234
+
235
+ if (pr.additions !== undefined) {
236
+ console.log(`Changes: ${chalk.green(`+${pr.additions}`)} ${chalk.red(`-${pr.deletions}`)} (${pr.changedFiles} files)`);
237
+ }
238
+
239
+ if (pr.body) {
240
+ console.log(chalk.dim("\n─".repeat(40)));
241
+ console.log(pr.body);
242
+ }
243
+
244
+ console.log(chalk.dim("\n─".repeat(40)));
245
+ console.log(chalk.dim(`${config.serverUrl}/${repoInfo.owner}/${repoInfo.repo}/pull/${number}`));
246
+ console.log("");
247
+ } catch (error) {
248
+ spinner.fail("Failed to fetch pull request");
249
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
250
+ process.exit(1);
251
+ }
252
+ });
253
+
254
+// PR Merge
255
+prCommands
256
+ .command("merge <number>")
257
+ .description("Merge a pull request")
258
+ .option("-m, --merge", "Use merge commit")
259
+ .option("-s, --squash", "Squash and merge")
260
+ .option("-r, --rebase", "Rebase and merge")
261
+ .option("-d, --delete-branch", "Delete branch after merge")
262
+ .action(async (number: string, options) => {
263
+ const config = getConfig();
264
+ if (!config.token) {
265
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
266
+ process.exit(1);
267
+ }
268
+
269
+ const mergeMethod = options.squash ? "squash" : options.rebase ? "rebase" : "merge";
270
+ const spinner = ora(`Merging PR #${number} (${mergeMethod})...`).start();
271
+
272
+ try {
273
+ const repoInfo = await getRepoInfo();
274
+ if (!repoInfo) {
275
+ spinner.fail("Could not determine repository");
276
+ process.exit(1);
277
+ }
278
+
279
+ await postWithAuth(
280
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${number}/merge`,
281
+ {
282
+ method: mergeMethod,
283
+ deleteBranch: options.deleteBranch,
284
+ }
285
+ );
286
+
287
+ spinner.succeed(`Merged PR #${number}`);
288
+ } catch (error) {
289
+ spinner.fail("Failed to merge pull request");
290
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
291
+ process.exit(1);
292
+ }
293
+ });
294
+
295
+// PR Checkout
296
+prCommands
297
+ .command("checkout <number>")
298
+ .alias("co")
299
+ .description("Checkout a pull request locally")
300
+ .action(async (number: string) => {
301
+ const config = getConfig();
302
+ if (!config.token) {
303
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
304
+ process.exit(1);
305
+ }
306
+
307
+ const spinner = ora(`Checking out PR #${number}...`).start();
308
+
309
+ try {
310
+ const repoInfo = await getRepoInfo();
311
+ if (!repoInfo) {
312
+ spinner.fail("Could not determine repository");
313
+ process.exit(1);
314
+ }
315
+
316
+ // Get PR info
317
+ const result = await getWithAuth<{ data: PullRequest }>(
318
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${number}`
319
+ );
320
+
321
+ const branchName = result.data.sourceBranch;
322
+
323
+ // Fetch and checkout
324
+ spinner.text = `Fetching ${branchName}...`;
325
+ await git.fetch(["origin", branchName]);
326
+
327
+ spinner.text = `Checking out ${branchName}...`;
328
+ await git.checkout(branchName);
329
+
330
+ spinner.succeed(`Checked out PR #${number} (${branchName})`);
331
+ } catch (error) {
332
+ spinner.fail("Failed to checkout pull request");
333
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
334
+ process.exit(1);
335
+ }
336
+ });
337
+
338
+// PR Close
339
+prCommands
340
+ .command("close <number>")
341
+ .description("Close a pull request")
342
+ .action(async (number: string) => {
343
+ const config = getConfig();
344
+ if (!config.token) {
345
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
346
+ process.exit(1);
347
+ }
348
+
349
+ const spinner = ora(`Closing PR #${number}...`).start();
350
+
351
+ try {
352
+ const repoInfo = await getRepoInfo();
353
+ if (!repoInfo) {
354
+ spinner.fail("Could not determine repository");
355
+ process.exit(1);
356
+ }
357
+
358
+ await patchWithAuth(
359
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${number}`,
360
+ { state: "closed" }
361
+ );
362
+
363
+ spinner.succeed(`Closed PR #${number}`);
364
+ } catch (error) {
365
+ spinner.fail("Failed to close pull request");
366
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
367
+ process.exit(1);
368
+ }
369
+ });
370
+
371
+// PR Diff
372
+prCommands
373
+ .command("diff <number>")
374
+ .description("View pull request diff")
375
+ .action(async (number: string) => {
376
+ const config = getConfig();
377
+ if (!config.token) {
378
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
379
+ process.exit(1);
380
+ }
381
+
382
+ const spinner = ora(`Fetching diff for PR #${number}...`).start();
383
+
384
+ try {
385
+ const repoInfo = await getRepoInfo();
386
+ if (!repoInfo) {
387
+ spinner.fail("Could not determine repository");
388
+ process.exit(1);
389
+ }
390
+
391
+ const result = await getWithAuth<{ data: { diff: string } }>(
392
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${number}/diff`
393
+ );
394
+
395
+ spinner.stop();
396
+ console.log(result.data.diff);
397
+ } catch (error) {
398
+ spinner.fail("Failed to fetch diff");
399
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
400
+ process.exit(1);
401
+ }
402
+ });
403
+
404
+// PR Ready (mark as ready for review)
405
+prCommands
406
+ .command("ready <number>")
407
+ .description("Mark pull request as ready for review")
408
+ .action(async (number: string) => {
409
+ const config = getConfig();
410
+ if (!config.token) {
411
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
412
+ process.exit(1);
413
+ }
414
+
415
+ const spinner = ora(`Marking PR #${number} as ready...`).start();
416
+
417
+ try {
418
+ const repoInfo = await getRepoInfo();
419
+ if (!repoInfo) {
420
+ spinner.fail("Could not determine repository");
421
+ process.exit(1);
422
+ }
423
+
424
+ await patchWithAuth(
425
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${number}`,
426
+ { isDraft: false }
427
+ );
428
+
429
+ spinner.succeed(`PR #${number} is now ready for review`);
430
+ } catch (error) {
431
+ spinner.fail("Failed to update pull request");
432
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
433
+ process.exit(1);
434
+ }
435
+ });
436
+
437
+export default prCommands;
0
438
▼cli/src/commands/queue/index.ts
+258-0
1
+/**
2
+ * Queue Commands
3
+ * Manage merge queue from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import { simpleGit } from "simple-git";
10
+import { getConfig } from "../../lib/config.js";
11
+import { getWithAuth, postWithAuth, deleteWithAuth } from "../../lib/api.js";
12
+
13
+const git = simpleGit();
14
+
15
+interface QueueItem {
16
+ id: string;
17
+ position: number;
18
+ status: string;
19
+ priority: number;
20
+ pullRequest: {
21
+ number: number;
22
+ title: string;
23
+ sourceBranch: string;
24
+ targetBranch: string;
25
+ author: { username: string };
26
+ };
27
+ addedAt: string;
28
+ estimatedMergeTime?: string;
29
+}
30
+
31
+export const queueCommands = new Command("queue")
32
+ .description("Manage merge queue");
33
+
34
+// Get repo info from git remote
35
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
36
+ try {
37
+ const remotes = await git.getRemotes(true);
38
+ const origin = remotes.find(r => r.name === "origin");
39
+ if (!origin?.refs?.push) return null;
40
+
41
+ const url = origin.refs.push;
42
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
43
+ if (match) {
44
+ return { owner: match[1], repo: match[2] };
45
+ }
46
+ return null;
47
+ } catch {
48
+ return null;
49
+ }
50
+}
51
+
52
+function getStatusIcon(status: string): string {
53
+ switch (status) {
54
+ case "pending": return chalk.yellow("◷");
55
+ case "running_ci": return chalk.blue("●");
56
+ case "ready": return chalk.green("✓");
57
+ case "merging": return chalk.magenta("↻");
58
+ case "failed": return chalk.red("✗");
59
+ default: return chalk.dim("○");
60
+ }
61
+}
62
+
63
+// Queue Add
64
+queueCommands
65
+ .command("add <pr-number>")
66
+ .description("Add a pull request to the merge queue")
67
+ .option("-p, --priority <n>", "Priority (higher = sooner)", "0")
68
+ .option("-m, --method <method>", "Merge method (merge, squash, rebase)", "merge")
69
+ .action(async (prNumber: string, options) => {
70
+ const config = getConfig();
71
+ if (!config.token) {
72
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
73
+ process.exit(1);
74
+ }
75
+
76
+ const spinner = ora(`Adding PR #${prNumber} to merge queue...`).start();
77
+
78
+ try {
79
+ const repoInfo = await getRepoInfo();
80
+ if (!repoInfo) {
81
+ spinner.fail("Could not determine repository");
82
+ process.exit(1);
83
+ }
84
+
85
+ const result = await postWithAuth<{ data: QueueItem }>(
86
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/merge-queue`,
87
+ {
88
+ pullRequestNumber: parseInt(prNumber),
89
+ priority: parseInt(options.priority),
90
+ mergeMethod: options.method,
91
+ }
92
+ );
93
+
94
+ spinner.succeed(`Added PR #${prNumber} to merge queue at position ${result.data.position}`);
95
+
96
+ if (result.data.estimatedMergeTime) {
97
+ const eta = new Date(result.data.estimatedMergeTime);
98
+ console.log(chalk.dim(` Estimated merge: ${eta.toLocaleTimeString()}`));
99
+ }
100
+ } catch (error) {
101
+ spinner.fail("Failed to add to merge queue");
102
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
103
+ process.exit(1);
104
+ }
105
+ });
106
+
107
+// Queue List
108
+queueCommands
109
+ .command("list")
110
+ .alias("ls")
111
+ .description("List merge queue items")
112
+ .action(async () => {
113
+ const config = getConfig();
114
+ if (!config.token) {
115
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
116
+ process.exit(1);
117
+ }
118
+
119
+ const spinner = ora("Fetching merge queue...").start();
120
+
121
+ try {
122
+ const repoInfo = await getRepoInfo();
123
+ if (!repoInfo) {
124
+ spinner.fail("Could not determine repository");
125
+ process.exit(1);
126
+ }
127
+
128
+ const result = await getWithAuth<{ data: QueueItem[] }>(
129
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/merge-queue`
130
+ );
131
+
132
+ spinner.stop();
133
+
134
+ if (result.data.length === 0) {
135
+ console.log(chalk.dim("Merge queue is empty."));
136
+ return;
137
+ }
138
+
139
+ console.log(chalk.bold(`\n🔀 Merge Queue (${result.data.length} items)\n`));
140
+ console.log(chalk.dim(" Pos PR Title Status"));
141
+ console.log(chalk.dim(" ─── ── ───── ──────"));
142
+
143
+ for (const item of result.data) {
144
+ const icon = getStatusIcon(item.status);
145
+ const pr = item.pullRequest;
146
+ const title = pr.title.length > 35 ? pr.title.slice(0, 32) + "..." : pr.title.padEnd(35);
147
+
148
+ console.log(` ${String(item.position).padStart(3)} #${String(pr.number).padEnd(5)} ${title} ${icon} ${item.status}`);
149
+ }
150
+
151
+ console.log("");
152
+ } catch (error) {
153
+ spinner.fail("Failed to fetch merge queue");
154
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
155
+ process.exit(1);
156
+ }
157
+ });
158
+
159
+// Queue Remove
160
+queueCommands
161
+ .command("remove <pr-number>")
162
+ .alias("rm")
163
+ .description("Remove a pull request from the merge queue")
164
+ .action(async (prNumber: string) => {
165
+ const config = getConfig();
166
+ if (!config.token) {
167
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
168
+ process.exit(1);
169
+ }
170
+
171
+ const spinner = ora(`Removing PR #${prNumber} from merge queue...`).start();
172
+
173
+ try {
174
+ const repoInfo = await getRepoInfo();
175
+ if (!repoInfo) {
176
+ spinner.fail("Could not determine repository");
177
+ process.exit(1);
178
+ }
179
+
180
+ await deleteWithAuth(
181
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/merge-queue/${prNumber}`
182
+ );
183
+
184
+ spinner.succeed(`Removed PR #${prNumber} from merge queue`);
185
+ } catch (error) {
186
+ spinner.fail("Failed to remove from merge queue");
187
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
188
+ process.exit(1);
189
+ }
190
+ });
191
+
192
+// Queue Status
193
+queueCommands
194
+ .command("status")
195
+ .description("Show merge queue status for current PR")
196
+ .action(async () => {
197
+ const config = getConfig();
198
+ if (!config.token) {
199
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
200
+ process.exit(1);
201
+ }
202
+
203
+ const spinner = ora("Checking queue status...").start();
204
+
205
+ try {
206
+ const repoInfo = await getRepoInfo();
207
+ if (!repoInfo) {
208
+ spinner.fail("Could not determine repository");
209
+ process.exit(1);
210
+ }
211
+
212
+ const currentBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
213
+
214
+ // Find PR for current branch
215
+ const prs = await getWithAuth<{ data: { number: number }[] }>(
216
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls?sourceBranch=${currentBranch}&state=open&limit=1`
217
+ );
218
+
219
+ if (prs.data.length === 0) {
220
+ spinner.info(`No open PR found for branch ${currentBranch}`);
221
+ return;
222
+ }
223
+
224
+ const prNumber = prs.data[0].number;
225
+
226
+ // Get queue status
227
+ const result = await getWithAuth<{ data: QueueItem[] }>(
228
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/merge-queue`
229
+ );
230
+
231
+ spinner.stop();
232
+
233
+ const item = result.data.find(i => i.pullRequest.number === prNumber);
234
+
235
+ if (!item) {
236
+ console.log(chalk.dim(`PR #${prNumber} is not in the merge queue.`));
237
+ console.log(chalk.dim(`Run 'och queue add ${prNumber}' to add it.`));
238
+ return;
239
+ }
240
+
241
+ const icon = getStatusIcon(item.status);
242
+ console.log(`\n${icon} PR #${prNumber} is at position ${item.position} in the queue`);
243
+ console.log(`Status: ${item.status}`);
244
+
245
+ if (item.estimatedMergeTime) {
246
+ const eta = new Date(item.estimatedMergeTime);
247
+ console.log(`Estimated merge: ${eta.toLocaleString()}`);
248
+ }
249
+
250
+ console.log("");
251
+ } catch (error) {
252
+ spinner.fail("Failed to check queue status");
253
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
254
+ process.exit(1);
255
+ }
256
+ });
257
+
258
+export default queueCommands;
0
259
▼cli/src/commands/release/index.ts
+299-0
1
+/**
2
+ * Release Commands
3
+ * Manage releases from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import { simpleGit } from "simple-git";
11
+import { getConfig } from "../../lib/config.js";
12
+import { getWithAuth, postWithAuth } from "../../lib/api.js";
13
+
14
+const git = simpleGit();
15
+
16
+interface Release {
17
+ id: string;
18
+ tagName: string;
19
+ name: string;
20
+ body?: string;
21
+ isDraft: boolean;
22
+ isPrerelease: boolean;
23
+ createdAt: string;
24
+ publishedAt?: string;
25
+ author: { username: string };
26
+ assets?: { name: string; size: number; downloadUrl: string }[];
27
+}
28
+
29
+export const releaseCommands = new Command("release")
30
+ .description("Manage releases");
31
+
32
+// Get repo info from git remote
33
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
34
+ try {
35
+ const remotes = await git.getRemotes(true);
36
+ const origin = remotes.find(r => r.name === "origin");
37
+ if (!origin?.refs?.push) return null;
38
+
39
+ const url = origin.refs.push;
40
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
41
+ if (match) {
42
+ return { owner: match[1], repo: match[2] };
43
+ }
44
+ return null;
45
+ } catch {
46
+ return null;
47
+ }
48
+}
49
+
50
+// Release Create
51
+releaseCommands
52
+ .command("create <tag>")
53
+ .description("Create a new release")
54
+ .option("-t, --title <title>", "Release title")
55
+ .option("-n, --notes <notes>", "Release notes")
56
+ .option("-F, --notes-file <file>", "Read release notes from file")
57
+ .option("-d, --draft", "Create as draft release")
58
+ .option("-p, --prerelease", "Mark as pre-release")
59
+ .option("--target <branch>", "Target branch for tag", "main")
60
+ .option("--generate-notes", "Auto-generate release notes")
61
+ .action(async (tag: string, options) => {
62
+ const config = getConfig();
63
+ if (!config.token) {
64
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
65
+ process.exit(1);
66
+ }
67
+
68
+ try {
69
+ const repoInfo = await getRepoInfo();
70
+ if (!repoInfo) {
71
+ console.error(chalk.red("Could not determine repository"));
72
+ process.exit(1);
73
+ }
74
+
75
+ let title = options.title || tag;
76
+ let notes = options.notes;
77
+
78
+ // Read notes from file if specified
79
+ if (options.notesFile) {
80
+ const fs = await import("fs");
81
+ notes = fs.readFileSync(options.notesFile, "utf-8");
82
+ }
83
+
84
+ // Interactive mode if notes not provided
85
+ if (!notes && !options.generateNotes) {
86
+ const answers = await inquirer.prompt([
87
+ {
88
+ type: "input",
89
+ name: "title",
90
+ message: "Release title:",
91
+ default: title,
92
+ },
93
+ {
94
+ type: "editor",
95
+ name: "notes",
96
+ message: "Release notes:",
97
+ },
98
+ ]);
99
+ title = answers.title;
100
+ notes = answers.notes;
101
+ }
102
+
103
+ const spinner = ora(`Creating release ${tag}...`).start();
104
+
105
+ const result = await postWithAuth<{ data: Release }>(
106
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/releases`,
107
+ {
108
+ tagName: tag,
109
+ name: title,
110
+ body: notes,
111
+ targetCommitish: options.target,
112
+ isDraft: options.draft || false,
113
+ isPrerelease: options.prerelease || false,
114
+ generateNotes: options.generateNotes || false,
115
+ }
116
+ );
117
+
118
+ const status = result.data.isDraft ? " (draft)" : result.data.isPrerelease ? " (pre-release)" : "";
119
+ spinner.succeed(`Created release ${chalk.green(tag)}${status}`);
120
+ console.log(chalk.dim(` ${config.serverUrl}/${repoInfo.owner}/${repoInfo.repo}/releases/tag/${tag}`));
121
+ } catch (error) {
122
+ console.error(chalk.red("Failed to create release"));
123
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
124
+ process.exit(1);
125
+ }
126
+ });
127
+
128
+// Release List
129
+releaseCommands
130
+ .command("list")
131
+ .alias("ls")
132
+ .description("List releases")
133
+ .option("-L, --limit <n>", "Maximum results", "10")
134
+ .option("--include-drafts", "Include draft releases")
135
+ .action(async (options) => {
136
+ const config = getConfig();
137
+ if (!config.token) {
138
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
139
+ process.exit(1);
140
+ }
141
+
142
+ const spinner = ora("Fetching releases...").start();
143
+
144
+ try {
145
+ const repoInfo = await getRepoInfo();
146
+ if (!repoInfo) {
147
+ spinner.fail("Could not determine repository");
148
+ process.exit(1);
149
+ }
150
+
151
+ const params = new URLSearchParams();
152
+ params.append("limit", options.limit);
153
+ if (options.includeDrafts) params.append("includeDrafts", "true");
154
+
155
+ const result = await getWithAuth<{ data: Release[] }>(
156
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/releases?${params}`
157
+ );
158
+
159
+ spinner.stop();
160
+
161
+ if (result.data.length === 0) {
162
+ console.log(chalk.dim("No releases found."));
163
+ return;
164
+ }
165
+
166
+ console.log(chalk.bold(`\n📦 Releases (${result.data.length})\n`));
167
+
168
+ for (const release of result.data) {
169
+ const icon = release.isDraft ? chalk.yellow("◌") :
170
+ release.isPrerelease ? chalk.blue("●") :
171
+ chalk.green("●");
172
+ const labels = [
173
+ release.isDraft ? chalk.yellow("[draft]") : "",
174
+ release.isPrerelease ? chalk.blue("[pre-release]") : "",
175
+ ].filter(Boolean).join(" ");
176
+
177
+ console.log(`${icon} ${chalk.bold(release.tagName)} ${release.name !== release.tagName ? `- ${release.name}` : ""} ${labels}`);
178
+ console.log(chalk.dim(` ${new Date(release.publishedAt || release.createdAt).toLocaleDateString()} • @${release.author.username}`));
179
+ }
180
+
181
+ console.log("");
182
+ } catch (error) {
183
+ spinner.fail("Failed to list releases");
184
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
185
+ process.exit(1);
186
+ }
187
+ });
188
+
189
+// Release View
190
+releaseCommands
191
+ .command("view <tag>")
192
+ .description("View a release")
193
+ .action(async (tag: string) => {
194
+ const config = getConfig();
195
+ if (!config.token) {
196
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
197
+ process.exit(1);
198
+ }
199
+
200
+ const spinner = ora("Fetching release...").start();
201
+
202
+ try {
203
+ const repoInfo = await getRepoInfo();
204
+ if (!repoInfo) {
205
+ spinner.fail("Could not determine repository");
206
+ process.exit(1);
207
+ }
208
+
209
+ const result = await getWithAuth<{ data: Release }>(
210
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/releases/tags/${tag}`
211
+ );
212
+
213
+ spinner.stop();
214
+
215
+ const release = result.data;
216
+
217
+ console.log(chalk.bold(`\n📦 ${release.tagName}`));
218
+ if (release.name !== release.tagName) {
219
+ console.log(`Title: ${release.name}`);
220
+ }
221
+ console.log(`Author: @${release.author.username}`);
222
+ console.log(`Date: ${new Date(release.publishedAt || release.createdAt).toLocaleString()}`);
223
+
224
+ if (release.isDraft) console.log(chalk.yellow("Status: Draft"));
225
+ if (release.isPrerelease) console.log(chalk.blue("Status: Pre-release"));
226
+
227
+ if (release.body) {
228
+ console.log(chalk.dim("\n─".repeat(40)));
229
+ console.log(release.body);
230
+ }
231
+
232
+ if (release.assets && release.assets.length > 0) {
233
+ console.log(chalk.bold("\nAssets:"));
234
+ for (const asset of release.assets) {
235
+ const size = (asset.size / 1024 / 1024).toFixed(2);
236
+ console.log(` 📎 ${asset.name} (${size} MB)`);
237
+ }
238
+ }
239
+
240
+ console.log(chalk.dim("\n─".repeat(40)));
241
+ console.log(chalk.dim(`${config.serverUrl}/${repoInfo.owner}/${repoInfo.repo}/releases/tag/${tag}`));
242
+ console.log("");
243
+ } catch (error) {
244
+ spinner.fail("Failed to fetch release");
245
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
246
+ process.exit(1);
247
+ }
248
+ });
249
+
250
+// Release Delete
251
+releaseCommands
252
+ .command("delete <tag>")
253
+ .description("Delete a release")
254
+ .option("-y, --yes", "Skip confirmation")
255
+ .action(async (tag: string, options) => {
256
+ const config = getConfig();
257
+ if (!config.token) {
258
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
259
+ process.exit(1);
260
+ }
261
+
262
+ try {
263
+ const repoInfo = await getRepoInfo();
264
+ if (!repoInfo) {
265
+ console.error(chalk.red("Could not determine repository"));
266
+ process.exit(1);
267
+ }
268
+
269
+ if (!options.yes) {
270
+ const { confirm } = await inquirer.prompt([
271
+ {
272
+ type: "confirm",
273
+ name: "confirm",
274
+ message: `Delete release ${tag}?`,
275
+ default: false,
276
+ },
277
+ ]);
278
+ if (!confirm) {
279
+ console.log(chalk.dim("Cancelled."));
280
+ return;
281
+ }
282
+ }
283
+
284
+ const spinner = ora(`Deleting release ${tag}...`).start();
285
+
286
+ const { deleteWithAuth } = await import("../../lib/api.js");
287
+ await deleteWithAuth(
288
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/releases/tags/${tag}`
289
+ );
290
+
291
+ spinner.succeed(`Deleted release ${tag}`);
292
+ } catch (error) {
293
+ console.error(chalk.red("Failed to delete release"));
294
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
295
+ process.exit(1);
296
+ }
297
+ });
298
+
299
+export default releaseCommands;
0
300
▼cli/src/commands/review/index.ts
+335-0
1
+/**
2
+ * Review Commands
3
+ * Manage code reviews from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import { simpleGit } from "simple-git";
11
+import { getConfig } from "../../lib/config.js";
12
+import { getWithAuth, postWithAuth } from "../../lib/api.js";
13
+
14
+const git = simpleGit();
15
+
16
+interface AIReview {
17
+ id: string;
18
+ status: string;
19
+ summary?: string;
20
+ overallSeverity?: string;
21
+ tokensUsed?: number;
22
+ createdAt: string;
23
+ completedAt?: string;
24
+ suggestions?: AIReviewSuggestion[];
25
+}
26
+
27
+interface AIReviewSuggestion {
28
+ id: string;
29
+ path: string;
30
+ line?: number;
31
+ severity: string;
32
+ type: string;
33
+ title: string;
34
+ message: string;
35
+ suggestedFix?: string;
36
+}
37
+
38
+export const reviewCommands = new Command("review")
39
+ .description("Manage code reviews");
40
+
41
+// Get repo info from git remote
42
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
43
+ try {
44
+ const remotes = await git.getRemotes(true);
45
+ const origin = remotes.find(r => r.name === "origin");
46
+ if (!origin?.refs?.push) return null;
47
+
48
+ const url = origin.refs.push;
49
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
50
+ if (match) {
51
+ return { owner: match[1], repo: match[2] };
52
+ }
53
+ return null;
54
+ } catch {
55
+ return null;
56
+ }
57
+}
58
+
59
+function getSeverityIcon(severity: string): string {
60
+ switch (severity) {
61
+ case "critical": return chalk.red("🔴");
62
+ case "error": return chalk.red("⛔");
63
+ case "warning": return chalk.yellow("⚠️");
64
+ case "info": return chalk.blue("ℹ️");
65
+ default: return chalk.dim("○");
66
+ }
67
+}
68
+
69
+// Review AI - Trigger AI review
70
+reviewCommands
71
+ .command("ai <pr-number>")
72
+ .description("Trigger AI code review for a pull request")
73
+ .option("--wait", "Wait for review to complete")
74
+ .action(async (prNumber: string, options) => {
75
+ const config = getConfig();
76
+ if (!config.token) {
77
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
78
+ process.exit(1);
79
+ }
80
+
81
+ const spinner = ora(`Triggering AI review for PR #${prNumber}...`).start();
82
+
83
+ try {
84
+ const repoInfo = await getRepoInfo();
85
+ if (!repoInfo) {
86
+ spinner.fail("Could not determine repository");
87
+ process.exit(1);
88
+ }
89
+
90
+ const result = await postWithAuth<{ data: AIReview }>(
91
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${prNumber}/ai-review`,
92
+ {}
93
+ );
94
+
95
+ if (options.wait) {
96
+ spinner.text = "Waiting for AI review to complete...";
97
+
98
+ let review = result.data;
99
+ while (review.status === "pending" || review.status === "running") {
100
+ await new Promise(resolve => setTimeout(resolve, 3000));
101
+ const statusResult = await getWithAuth<{ data: AIReview }>(
102
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${prNumber}/ai-review/latest`
103
+ );
104
+ review = statusResult.data;
105
+ }
106
+
107
+ spinner.stop();
108
+ displayReview(review);
109
+ } else {
110
+ spinner.succeed(`AI review triggered for PR #${prNumber}`);
111
+ console.log(chalk.dim(" Run 'och review status " + prNumber + "' to check progress"));
112
+ }
113
+ } catch (error) {
114
+ spinner.fail("Failed to trigger AI review");
115
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
116
+ process.exit(1);
117
+ }
118
+ });
119
+
120
+// Review Status - Check AI review status
121
+reviewCommands
122
+ .command("status <pr-number>")
123
+ .description("Check AI review status for a pull request")
124
+ .action(async (prNumber: string) => {
125
+ const config = getConfig();
126
+ if (!config.token) {
127
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
128
+ process.exit(1);
129
+ }
130
+
131
+ const spinner = ora(`Fetching review status for PR #${prNumber}...`).start();
132
+
133
+ try {
134
+ const repoInfo = await getRepoInfo();
135
+ if (!repoInfo) {
136
+ spinner.fail("Could not determine repository");
137
+ process.exit(1);
138
+ }
139
+
140
+ const result = await getWithAuth<{ data: AIReview }>(
141
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${prNumber}/ai-review/latest`
142
+ );
143
+
144
+ spinner.stop();
145
+ displayReview(result.data);
146
+ } catch (error) {
147
+ spinner.fail("Failed to fetch review status");
148
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
149
+ process.exit(1);
150
+ }
151
+ });
152
+
153
+function displayReview(review: AIReview) {
154
+ console.log(chalk.bold("\n🤖 AI Review\n"));
155
+ console.log(`Status: ${review.status}`);
156
+
157
+ if (review.overallSeverity) {
158
+ console.log(`Severity: ${getSeverityIcon(review.overallSeverity)} ${review.overallSeverity}`);
159
+ }
160
+
161
+ if (review.summary) {
162
+ console.log(chalk.dim("\n─".repeat(40)));
163
+ console.log(chalk.bold("Summary:"));
164
+ console.log(review.summary);
165
+ }
166
+
167
+ if (review.suggestions && review.suggestions.length > 0) {
168
+ console.log(chalk.dim("\n─".repeat(40)));
169
+ console.log(chalk.bold(`\nSuggestions (${review.suggestions.length}):\n`));
170
+
171
+ for (const suggestion of review.suggestions) {
172
+ const icon = getSeverityIcon(suggestion.severity);
173
+ console.log(`${icon} ${chalk.bold(suggestion.title)}`);
174
+ console.log(chalk.dim(` ${suggestion.path}${suggestion.line ? `:${suggestion.line}` : ""}`));
175
+ console.log(` ${suggestion.message}`);
176
+ if (suggestion.suggestedFix) {
177
+ console.log(chalk.green(` Fix: ${suggestion.suggestedFix}`));
178
+ }
179
+ console.log("");
180
+ }
181
+ }
182
+
183
+ if (review.tokensUsed) {
184
+ console.log(chalk.dim(`Tokens used: ${review.tokensUsed}`));
185
+ }
186
+}
187
+
188
+// Review Approve
189
+reviewCommands
190
+ .command("approve <pr-number>")
191
+ .description("Approve a pull request")
192
+ .option("-b, --body <body>", "Review comment")
193
+ .action(async (prNumber: string, options) => {
194
+ const config = getConfig();
195
+ if (!config.token) {
196
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
197
+ process.exit(1);
198
+ }
199
+
200
+ const spinner = ora(`Approving PR #${prNumber}...`).start();
201
+
202
+ try {
203
+ const repoInfo = await getRepoInfo();
204
+ if (!repoInfo) {
205
+ spinner.fail("Could not determine repository");
206
+ process.exit(1);
207
+ }
208
+
209
+ await postWithAuth(
210
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${prNumber}/reviews`,
211
+ {
212
+ event: "approve",
213
+ body: options.body,
214
+ }
215
+ );
216
+
217
+ spinner.succeed(`Approved PR #${prNumber}`);
218
+ } catch (error) {
219
+ spinner.fail("Failed to approve pull request");
220
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
221
+ process.exit(1);
222
+ }
223
+ });
224
+
225
+// Review Request Changes
226
+reviewCommands
227
+ .command("request-changes <pr-number>")
228
+ .description("Request changes on a pull request")
229
+ .option("-b, --body <body>", "Review comment")
230
+ .action(async (prNumber: string, options) => {
231
+ const config = getConfig();
232
+ if (!config.token) {
233
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
234
+ process.exit(1);
235
+ }
236
+
237
+ let body = options.body;
238
+
239
+ if (!body) {
240
+ const answers = await inquirer.prompt([
241
+ {
242
+ type: "editor",
243
+ name: "body",
244
+ message: "Review comment (explain what changes are needed):",
245
+ },
246
+ ]);
247
+ body = answers.body;
248
+ }
249
+
250
+ if (!body || body.trim() === "") {
251
+ console.error(chalk.red("A comment is required when requesting changes"));
252
+ process.exit(1);
253
+ }
254
+
255
+ const spinner = ora(`Requesting changes on PR #${prNumber}...`).start();
256
+
257
+ try {
258
+ const repoInfo = await getRepoInfo();
259
+ if (!repoInfo) {
260
+ spinner.fail("Could not determine repository");
261
+ process.exit(1);
262
+ }
263
+
264
+ await postWithAuth(
265
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${prNumber}/reviews`,
266
+ {
267
+ event: "request_changes",
268
+ body,
269
+ }
270
+ );
271
+
272
+ spinner.succeed(`Requested changes on PR #${prNumber}`);
273
+ } catch (error) {
274
+ spinner.fail("Failed to request changes");
275
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
276
+ process.exit(1);
277
+ }
278
+ });
279
+
280
+// Review Comment
281
+reviewCommands
282
+ .command("comment <pr-number>")
283
+ .description("Add a review comment to a pull request")
284
+ .option("-b, --body <body>", "Comment body")
285
+ .action(async (prNumber: string, options) => {
286
+ const config = getConfig();
287
+ if (!config.token) {
288
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
289
+ process.exit(1);
290
+ }
291
+
292
+ let body = options.body;
293
+
294
+ if (!body) {
295
+ const answers = await inquirer.prompt([
296
+ {
297
+ type: "editor",
298
+ name: "body",
299
+ message: "Review comment:",
300
+ },
301
+ ]);
302
+ body = answers.body;
303
+ }
304
+
305
+ if (!body || body.trim() === "") {
306
+ console.error(chalk.red("Comment cannot be empty"));
307
+ process.exit(1);
308
+ }
309
+
310
+ const spinner = ora(`Adding comment to PR #${prNumber}...`).start();
311
+
312
+ try {
313
+ const repoInfo = await getRepoInfo();
314
+ if (!repoInfo) {
315
+ spinner.fail("Could not determine repository");
316
+ process.exit(1);
317
+ }
318
+
319
+ await postWithAuth(
320
+ `/api/repos/${repoInfo.owner}/${repoInfo.repo}/pulls/${prNumber}/reviews`,
321
+ {
322
+ event: "comment",
323
+ body,
324
+ }
325
+ );
326
+
327
+ spinner.succeed(`Added comment to PR #${prNumber}`);
328
+ } catch (error) {
329
+ spinner.fail("Failed to add comment");
330
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
331
+ process.exit(1);
332
+ }
333
+ });
334
+
335
+export default reviewCommands;
0
336
▼cli/src/commands/search/index.ts
+263-0
1
+/**
2
+ * Search Commands
3
+ * Search repositories, issues, and PRs from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import { getConfig } from "../../lib/config.js";
10
+import { getWithAuth } from "../../lib/api.js";
11
+
12
+interface SearchResult<T> {
13
+ total: number;
14
+ items: T[];
15
+}
16
+
17
+interface RepoResult {
18
+ id: string;
19
+ fullName: string;
20
+ description?: string;
21
+ visibility: string;
22
+ stars: number;
23
+ forks: number;
24
+ updatedAt: string;
25
+}
26
+
27
+interface IssueResult {
28
+ id: string;
29
+ number: number;
30
+ title: string;
31
+ state: string;
32
+ repository: { fullName: string };
33
+ author: { username: string };
34
+ createdAt: string;
35
+}
36
+
37
+interface PRResult {
38
+ id: string;
39
+ number: number;
40
+ title: string;
41
+ state: string;
42
+ repository: { fullName: string };
43
+ author: { username: string };
44
+ sourceBranch: string;
45
+ targetBranch: string;
46
+ createdAt: string;
47
+}
48
+
49
+export const searchCommands = new Command("search")
50
+ .description("Search repositories, issues, and pull requests");
51
+
52
+// Search Repos
53
+searchCommands
54
+ .command("repos <query>")
55
+ .alias("repo")
56
+ .description("Search repositories")
57
+ .option("-L, --limit <n>", "Maximum results", "20")
58
+ .option("--sort <field>", "Sort by (stars, forks, updated)", "stars")
59
+ .option("--order <direction>", "Sort order (asc, desc)", "desc")
60
+ .action(async (query: string, options) => {
61
+ const config = getConfig();
62
+ if (!config.token) {
63
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
64
+ process.exit(1);
65
+ }
66
+
67
+ const spinner = ora(`Searching repositories for "${query}"...`).start();
68
+
69
+ try {
70
+ const params = new URLSearchParams();
71
+ params.append("q", query);
72
+ params.append("limit", options.limit);
73
+ params.append("sort", options.sort);
74
+ params.append("order", options.order);
75
+
76
+ const result = await getWithAuth<{ data: SearchResult<RepoResult> }>(
77
+ `/api/search/repos?${params}`
78
+ );
79
+
80
+ spinner.stop();
81
+
82
+ if (result.data.items.length === 0) {
83
+ console.log(chalk.dim(`No repositories found matching "${query}"`));
84
+ return;
85
+ }
86
+
87
+ console.log(chalk.bold(`\n🔍 Repositories (${result.data.total} total, showing ${result.data.items.length})\n`));
88
+
89
+ for (const repo of result.data.items) {
90
+ const icon = repo.visibility === "private" ? chalk.yellow("🔒") : chalk.green("📦");
91
+ console.log(`${icon} ${chalk.bold(repo.fullName)}`);
92
+ if (repo.description) {
93
+ console.log(chalk.dim(` ${repo.description.slice(0, 80)}${repo.description.length > 80 ? "..." : ""}`));
94
+ }
95
+ console.log(chalk.dim(` ⭐ ${repo.stars} 🍴 ${repo.forks} Updated ${new Date(repo.updatedAt).toLocaleDateString()}`));
96
+ }
97
+
98
+ console.log("");
99
+ } catch (error) {
100
+ spinner.fail("Search failed");
101
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
102
+ process.exit(1);
103
+ }
104
+ });
105
+
106
+// Search Issues
107
+searchCommands
108
+ .command("issues <query>")
109
+ .alias("issue")
110
+ .description("Search issues")
111
+ .option("-L, --limit <n>", "Maximum results", "20")
112
+ .option("-s, --state <state>", "Filter by state (open, closed, all)", "open")
113
+ .option("-r, --repo <repo>", "Limit to specific repository (owner/name)")
114
+ .action(async (query: string, options) => {
115
+ const config = getConfig();
116
+ if (!config.token) {
117
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
118
+ process.exit(1);
119
+ }
120
+
121
+ const spinner = ora(`Searching issues for "${query}"...`).start();
122
+
123
+ try {
124
+ const params = new URLSearchParams();
125
+ params.append("q", query);
126
+ params.append("limit", options.limit);
127
+ if (options.state !== "all") params.append("state", options.state);
128
+ if (options.repo) params.append("repo", options.repo);
129
+
130
+ const result = await getWithAuth<{ data: SearchResult<IssueResult> }>(
131
+ `/api/search/issues?${params}`
132
+ );
133
+
134
+ spinner.stop();
135
+
136
+ if (result.data.items.length === 0) {
137
+ console.log(chalk.dim(`No issues found matching "${query}"`));
138
+ return;
139
+ }
140
+
141
+ console.log(chalk.bold(`\n🔍 Issues (${result.data.total} total, showing ${result.data.items.length})\n`));
142
+
143
+ for (const issue of result.data.items) {
144
+ const icon = issue.state === "open" ? chalk.green("●") : chalk.red("●");
145
+ console.log(`${icon} ${chalk.cyan(issue.repository.fullName)}#${issue.number} ${issue.title}`);
146
+ console.log(chalk.dim(` @${issue.author.username} • ${new Date(issue.createdAt).toLocaleDateString()}`));
147
+ }
148
+
149
+ console.log("");
150
+ } catch (error) {
151
+ spinner.fail("Search failed");
152
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
153
+ process.exit(1);
154
+ }
155
+ });
156
+
157
+// Search PRs
158
+searchCommands
159
+ .command("prs <query>")
160
+ .alias("pr")
161
+ .description("Search pull requests")
162
+ .option("-L, --limit <n>", "Maximum results", "20")
163
+ .option("-s, --state <state>", "Filter by state (open, closed, merged, all)", "open")
164
+ .option("-r, --repo <repo>", "Limit to specific repository (owner/name)")
165
+ .action(async (query: string, options) => {
166
+ const config = getConfig();
167
+ if (!config.token) {
168
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
169
+ process.exit(1);
170
+ }
171
+
172
+ const spinner = ora(`Searching pull requests for "${query}"...`).start();
173
+
174
+ try {
175
+ const params = new URLSearchParams();
176
+ params.append("q", query);
177
+ params.append("limit", options.limit);
178
+ if (options.state !== "all") params.append("state", options.state);
179
+ if (options.repo) params.append("repo", options.repo);
180
+
181
+ const result = await getWithAuth<{ data: SearchResult<PRResult> }>(
182
+ `/api/search/prs?${params}`
183
+ );
184
+
185
+ spinner.stop();
186
+
187
+ if (result.data.items.length === 0) {
188
+ console.log(chalk.dim(`No pull requests found matching "${query}"`));
189
+ return;
190
+ }
191
+
192
+ console.log(chalk.bold(`\n🔍 Pull Requests (${result.data.total} total, showing ${result.data.items.length})\n`));
193
+
194
+ for (const pr of result.data.items) {
195
+ const icon = pr.state === "open" ? chalk.green("●") :
196
+ pr.state === "merged" ? chalk.magenta("●") : chalk.red("●");
197
+ console.log(`${icon} ${chalk.cyan(pr.repository.fullName)}#${pr.number} ${pr.title}`);
198
+ console.log(chalk.dim(` ${pr.sourceBranch} → ${pr.targetBranch} • @${pr.author.username}`));
199
+ }
200
+
201
+ console.log("");
202
+ } catch (error) {
203
+ spinner.fail("Search failed");
204
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
205
+ process.exit(1);
206
+ }
207
+ });
208
+
209
+// Search Code (bonus)
210
+searchCommands
211
+ .command("code <query>")
212
+ .description("Search code")
213
+ .option("-L, --limit <n>", "Maximum results", "20")
214
+ .option("-r, --repo <repo>", "Limit to specific repository (owner/name)")
215
+ .option("-l, --language <lang>", "Filter by language")
216
+ .action(async (query: string, options) => {
217
+ const config = getConfig();
218
+ if (!config.token) {
219
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
220
+ process.exit(1);
221
+ }
222
+
223
+ const spinner = ora(`Searching code for "${query}"...`).start();
224
+
225
+ try {
226
+ const params = new URLSearchParams();
227
+ params.append("q", query);
228
+ params.append("limit", options.limit);
229
+ if (options.repo) params.append("repo", options.repo);
230
+ if (options.language) params.append("language", options.language);
231
+
232
+ const result = await getWithAuth<{
233
+ data: SearchResult<{
234
+ path: string;
235
+ repository: { fullName: string };
236
+ matches: { line: number; content: string }[];
237
+ }>
238
+ }>(`/api/search/code?${params}`);
239
+
240
+ spinner.stop();
241
+
242
+ if (result.data.items.length === 0) {
243
+ console.log(chalk.dim(`No code found matching "${query}"`));
244
+ return;
245
+ }
246
+
247
+ console.log(chalk.bold(`\n🔍 Code (${result.data.total} total, showing ${result.data.items.length})\n`));
248
+
249
+ for (const item of result.data.items) {
250
+ console.log(`${chalk.cyan(item.repository.fullName)}/${chalk.bold(item.path)}`);
251
+ for (const match of item.matches.slice(0, 3)) {
252
+ console.log(chalk.dim(` ${match.line}: `) + match.content.trim());
253
+ }
254
+ console.log("");
255
+ }
256
+ } catch (error) {
257
+ spinner.fail("Search failed");
258
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
259
+ process.exit(1);
260
+ }
261
+ });
262
+
263
+export default searchCommands;
0
264
▼cli/src/commands/secret/index.ts
+228-0
1
+/**
2
+ * Secret Commands
3
+ * Manage repository and organization secrets from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import { simpleGit } from "simple-git";
11
+import { getConfig } from "../../lib/config.js";
12
+import { getWithAuth, postWithAuth, deleteWithAuth } from "../../lib/api.js";
13
+
14
+const git = simpleGit();
15
+
16
+interface Secret {
17
+ name: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+}
21
+
22
+export const secretCommands = new Command("secret")
23
+ .description("Manage secrets");
24
+
25
+// Get repo info from git remote
26
+async function getRepoInfo(): Promise<{ owner: string; repo: string } | null> {
27
+ try {
28
+ const remotes = await git.getRemotes(true);
29
+ const origin = remotes.find(r => r.name === "origin");
30
+ if (!origin?.refs?.push) return null;
31
+
32
+ const url = origin.refs.push;
33
+ const match = url.match(/[:/]([^/]+)\/([^/.]+)/);
34
+ if (match) {
35
+ return { owner: match[1], repo: match[2] };
36
+ }
37
+ return null;
38
+ } catch {
39
+ return null;
40
+ }
41
+}
42
+
43
+// Secret Set
44
+secretCommands
45
+ .command("set <name>")
46
+ .description("Set a secret")
47
+ .option("-b, --body <value>", "Secret value (not recommended, use stdin)")
48
+ .option("-o, --org <org>", "Set organization secret instead of repo secret")
49
+ .option("-e, --env <env>", "Set environment-specific secret")
50
+ .action(async (name: string, options) => {
51
+ const config = getConfig();
52
+ if (!config.token) {
53
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
54
+ process.exit(1);
55
+ }
56
+
57
+ try {
58
+ let value = options.body;
59
+
60
+ if (!value) {
61
+ // Check if stdin has data (piped input)
62
+ if (!process.stdin.isTTY) {
63
+ const chunks: Buffer[] = [];
64
+ for await (const chunk of process.stdin) {
65
+ chunks.push(chunk);
66
+ }
67
+ value = Buffer.concat(chunks).toString().trim();
68
+ } else {
69
+ // Interactive prompt
70
+ const answers = await inquirer.prompt([
71
+ {
72
+ type: "password",
73
+ name: "value",
74
+ message: `Enter value for ${name}:`,
75
+ mask: "*",
76
+ },
77
+ ]);
78
+ value = answers.value;
79
+ }
80
+ }
81
+
82
+ if (!value) {
83
+ console.error(chalk.red("Secret value cannot be empty"));
84
+ process.exit(1);
85
+ }
86
+
87
+ const spinner = ora(`Setting secret ${name}...`).start();
88
+
89
+ let endpoint: string;
90
+
91
+ if (options.org) {
92
+ endpoint = `/api/orgs/${options.org}/actions/secrets/${name}`;
93
+ } else {
94
+ const repoInfo = await getRepoInfo();
95
+ if (!repoInfo) {
96
+ spinner.fail("Could not determine repository");
97
+ process.exit(1);
98
+ }
99
+ const envPart = options.env ? `/environments/${options.env}` : "";
100
+ endpoint = `/api/repos/${repoInfo.owner}/${repoInfo.repo}${envPart}/actions/secrets/${name}`;
101
+ }
102
+
103
+ await postWithAuth(endpoint, { value });
104
+
105
+ spinner.succeed(`Set secret ${chalk.cyan(name)}`);
106
+ } catch (error) {
107
+ console.error(chalk.red("Failed to set secret"));
108
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
109
+ process.exit(1);
110
+ }
111
+ });
112
+
113
+// Secret List
114
+secretCommands
115
+ .command("list")
116
+ .alias("ls")
117
+ .description("List secrets")
118
+ .option("-o, --org <org>", "List organization secrets")
119
+ .option("-e, --env <env>", "List environment secrets")
120
+ .action(async (options) => {
121
+ const config = getConfig();
122
+ if (!config.token) {
123
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
124
+ process.exit(1);
125
+ }
126
+
127
+ const spinner = ora("Fetching secrets...").start();
128
+
129
+ try {
130
+ let endpoint: string;
131
+ let context: string;
132
+
133
+ if (options.org) {
134
+ endpoint = `/api/orgs/${options.org}/actions/secrets`;
135
+ context = `organization ${options.org}`;
136
+ } else {
137
+ const repoInfo = await getRepoInfo();
138
+ if (!repoInfo) {
139
+ spinner.fail("Could not determine repository");
140
+ process.exit(1);
141
+ }
142
+ const envPart = options.env ? `/environments/${options.env}` : "";
143
+ endpoint = `/api/repos/${repoInfo.owner}/${repoInfo.repo}${envPart}/actions/secrets`;
144
+ context = options.env ? `environment ${options.env}` : `repository ${repoInfo.owner}/${repoInfo.repo}`;
145
+ }
146
+
147
+ const result = await getWithAuth<{ data: Secret[] }>(endpoint);
148
+
149
+ spinner.stop();
150
+
151
+ if (result.data.length === 0) {
152
+ console.log(chalk.dim(`No secrets found for ${context}`));
153
+ return;
154
+ }
155
+
156
+ console.log(chalk.bold(`\n🔐 Secrets for ${context}\n`));
157
+
158
+ for (const secret of result.data) {
159
+ console.log(` ${chalk.cyan(secret.name)}`);
160
+ console.log(chalk.dim(` Updated ${new Date(secret.updatedAt).toLocaleDateString()}`));
161
+ }
162
+
163
+ console.log("");
164
+ } catch (error) {
165
+ spinner.fail("Failed to list secrets");
166
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
167
+ process.exit(1);
168
+ }
169
+ });
170
+
171
+// Secret Delete
172
+secretCommands
173
+ .command("delete <name>")
174
+ .alias("rm")
175
+ .description("Delete a secret")
176
+ .option("-o, --org <org>", "Delete organization secret")
177
+ .option("-e, --env <env>", "Delete environment secret")
178
+ .option("-y, --yes", "Skip confirmation")
179
+ .action(async (name: string, options) => {
180
+ const config = getConfig();
181
+ if (!config.token) {
182
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
183
+ process.exit(1);
184
+ }
185
+
186
+ try {
187
+ if (!options.yes) {
188
+ const { confirm } = await inquirer.prompt([
189
+ {
190
+ type: "confirm",
191
+ name: "confirm",
192
+ message: `Delete secret ${name}?`,
193
+ default: false,
194
+ },
195
+ ]);
196
+ if (!confirm) {
197
+ console.log(chalk.dim("Cancelled."));
198
+ return;
199
+ }
200
+ }
201
+
202
+ const spinner = ora(`Deleting secret ${name}...`).start();
203
+
204
+ let endpoint: string;
205
+
206
+ if (options.org) {
207
+ endpoint = `/api/orgs/${options.org}/actions/secrets/${name}`;
208
+ } else {
209
+ const repoInfo = await getRepoInfo();
210
+ if (!repoInfo) {
211
+ spinner.fail("Could not determine repository");
212
+ process.exit(1);
213
+ }
214
+ const envPart = options.env ? `/environments/${options.env}` : "";
215
+ endpoint = `/api/repos/${repoInfo.owner}/${repoInfo.repo}${envPart}/actions/secrets/${name}`;
216
+ }
217
+
218
+ await deleteWithAuth(endpoint);
219
+
220
+ spinner.succeed(`Deleted secret ${chalk.cyan(name)}`);
221
+ } catch (error) {
222
+ console.error(chalk.red("Failed to delete secret"));
223
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
224
+ process.exit(1);
225
+ }
226
+ });
227
+
228
+export default secretCommands;
0
229
▼cli/src/commands/ssh-key/index.ts
+220-0
1
+/**
2
+ * SSH Key Commands
3
+ * Manage SSH keys from the CLI
4
+ */
5
+
6
+import { Command } from "commander";
7
+import chalk from "chalk";
8
+import ora from "ora";
9
+import inquirer from "inquirer";
10
+import * as fs from "fs";
11
+import * as os from "os";
12
+import * as path from "path";
13
+import { getConfig } from "../../lib/config.js";
14
+import { getWithAuth, postWithAuth, deleteWithAuth } from "../../lib/api.js";
15
+
16
+interface SSHKey {
17
+ id: string;
18
+ title: string;
19
+ key: string;
20
+ fingerprint: string;
21
+ createdAt: string;
22
+ lastUsedAt?: string;
23
+}
24
+
25
+export const sshKeyCommands = new Command("ssh-key")
26
+ .description("Manage SSH keys");
27
+
28
+// SSH Key Add
29
+sshKeyCommands
30
+ .command("add")
31
+ .description("Add an SSH key to your account")
32
+ .option("-t, --title <title>", "Key title")
33
+ .option("-f, --file <path>", "Path to public key file")
34
+ .action(async (options) => {
35
+ const config = getConfig();
36
+ if (!config.token) {
37
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
38
+ process.exit(1);
39
+ }
40
+
41
+ try {
42
+ let publicKey: string;
43
+ let title = options.title;
44
+
45
+ if (options.file) {
46
+ // Read from file
47
+ const keyPath = options.file.replace("~", os.homedir());
48
+ if (!fs.existsSync(keyPath)) {
49
+ console.error(chalk.red(`File not found: ${keyPath}`));
50
+ process.exit(1);
51
+ }
52
+ publicKey = fs.readFileSync(keyPath, "utf-8").trim();
53
+ } else {
54
+ // Look for default keys
55
+ const sshDir = path.join(os.homedir(), ".ssh");
56
+ const defaultKeys = ["id_ed25519.pub", "id_rsa.pub", "id_ecdsa.pub"];
57
+ const availableKeys: { name: string; path: string }[] = [];
58
+
59
+ for (const keyFile of defaultKeys) {
60
+ const keyPath = path.join(sshDir, keyFile);
61
+ if (fs.existsSync(keyPath)) {
62
+ availableKeys.push({ name: keyFile, path: keyPath });
63
+ }
64
+ }
65
+
66
+ if (availableKeys.length === 0) {
67
+ console.log(chalk.yellow("No SSH keys found in ~/.ssh/"));
68
+ console.log(chalk.dim("Generate one with: ssh-keygen -t ed25519"));
69
+ process.exit(1);
70
+ }
71
+
72
+ const { selectedKey } = await inquirer.prompt([
73
+ {
74
+ type: "list",
75
+ name: "selectedKey",
76
+ message: "Select SSH key to add:",
77
+ choices: availableKeys.map(k => ({
78
+ name: k.name,
79
+ value: k.path,
80
+ })),
81
+ },
82
+ ]);
83
+
84
+ publicKey = fs.readFileSync(selectedKey, "utf-8").trim();
85
+ }
86
+
87
+ // Parse key type and validate
88
+ if (!publicKey.startsWith("ssh-") && !publicKey.startsWith("ecdsa-")) {
89
+ console.error(chalk.red("Invalid SSH public key format"));
90
+ process.exit(1);
91
+ }
92
+
93
+ // Get title if not provided
94
+ if (!title) {
95
+ const defaultTitle = `${os.userInfo().username}@${os.hostname()}`;
96
+ const answers = await inquirer.prompt([
97
+ {
98
+ type: "input",
99
+ name: "title",
100
+ message: "Key title:",
101
+ default: defaultTitle,
102
+ },
103
+ ]);
104
+ title = answers.title;
105
+ }
106
+
107
+ const spinner = ora("Adding SSH key...").start();
108
+
109
+ const result = await postWithAuth<{ data: SSHKey }>(
110
+ "/api/user/ssh-keys",
111
+ { title, key: publicKey }
112
+ );
113
+
114
+ spinner.succeed(`Added SSH key: ${chalk.cyan(title)}`);
115
+ console.log(chalk.dim(` Fingerprint: ${result.data.fingerprint}`));
116
+ } catch (error) {
117
+ console.error(chalk.red("Failed to add SSH key"));
118
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
119
+ process.exit(1);
120
+ }
121
+ });
122
+
123
+// SSH Key List
124
+sshKeyCommands
125
+ .command("list")
126
+ .alias("ls")
127
+ .description("List your SSH keys")
128
+ .action(async () => {
129
+ const config = getConfig();
130
+ if (!config.token) {
131
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
132
+ process.exit(1);
133
+ }
134
+
135
+ const spinner = ora("Fetching SSH keys...").start();
136
+
137
+ try {
138
+ const result = await getWithAuth<{ data: SSHKey[] }>("/api/user/ssh-keys");
139
+
140
+ spinner.stop();
141
+
142
+ if (result.data.length === 0) {
143
+ console.log(chalk.dim("No SSH keys found."));
144
+ console.log(chalk.dim("Add one with: och ssh-key add"));
145
+ return;
146
+ }
147
+
148
+ console.log(chalk.bold(`\n🔑 SSH Keys (${result.data.length})\n`));
149
+
150
+ for (const key of result.data) {
151
+ const keyType = key.key.split(" ")[0].replace("ssh-", "").toUpperCase();
152
+ console.log(` ${chalk.cyan(key.title)} ${chalk.dim(`(${keyType})`)}`);
153
+ console.log(chalk.dim(` ID: ${key.id}`));
154
+ console.log(chalk.dim(` Fingerprint: ${key.fingerprint}`));
155
+ console.log(chalk.dim(` Added: ${new Date(key.createdAt).toLocaleDateString()}`));
156
+ if (key.lastUsedAt) {
157
+ console.log(chalk.dim(` Last used: ${new Date(key.lastUsedAt).toLocaleDateString()}`));
158
+ }
159
+ console.log("");
160
+ }
161
+ } catch (error) {
162
+ spinner.fail("Failed to list SSH keys");
163
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
164
+ process.exit(1);
165
+ }
166
+ });
167
+
168
+// SSH Key Delete
169
+sshKeyCommands
170
+ .command("delete <id>")
171
+ .alias("rm")
172
+ .description("Delete an SSH key")
173
+ .option("-y, --yes", "Skip confirmation")
174
+ .action(async (id: string, options) => {
175
+ const config = getConfig();
176
+ if (!config.token) {
177
+ console.error(chalk.red("Not logged in. Run 'och auth login' first."));
178
+ process.exit(1);
179
+ }
180
+
181
+ try {
182
+ // Get key info first
183
+ const spinner = ora("Fetching key info...").start();
184
+ const result = await getWithAuth<{ data: SSHKey[] }>("/api/user/ssh-keys");
185
+ const key = result.data.find(k => k.id === id);
186
+ spinner.stop();
187
+
188
+ if (!key) {
189
+ console.error(chalk.red(`SSH key not found: ${id}`));
190
+ process.exit(1);
191
+ }
192
+
193
+ if (!options.yes) {
194
+ const { confirm } = await inquirer.prompt([
195
+ {
196
+ type: "confirm",
197
+ name: "confirm",
198
+ message: `Delete SSH key "${key.title}"?`,
199
+ default: false,
200
+ },
201
+ ]);
202
+ if (!confirm) {
203
+ console.log(chalk.dim("Cancelled."));
204
+ return;
205
+ }
206
+ }
207
+
208
+ const deleteSpinner = ora("Deleting SSH key...").start();
209
+
210
+ await deleteWithAuth(`/api/user/ssh-keys/${id}`);
211
+
212
+ deleteSpinner.succeed(`Deleted SSH key: ${chalk.cyan(key.title)}`);
213
+ } catch (error) {
214
+ console.error(chalk.red("Failed to delete SSH key"));
215
+ console.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
216
+ process.exit(1);
217
+ }
218
+ });
219
+
220
+export default sshKeyCommands;
0
221
▼cli/src/lib/api.ts
+11-0
46
46
const config = getConfig();
47
47
return apiCall<T>(config.serverUrl, endpoint, "POST", body);
48
48
}
49
+
50
+export async function patchWithAuth<T = any>(endpoint: string, body: any): Promise<T> {
51
+ const config = getConfig();
52
+ return apiCall<T>(config.serverUrl, endpoint, "PATCH", body);
53
+}
54
+
55
+export async function deleteWithAuth<T = any>(endpoint: string): Promise<T> {
56
+ const config = getConfig();
57
+ return apiCall<T>(config.serverUrl, endpoint, "DELETE");
58
+}
59
+
49
60
▼cookies.txt
+5-0
1
+# Netscape HTTP Cookie File
2
+# https://curl.se/docs/http-cookies.html
3
+# This file was generated by libcurl! Edit at your own risk.
4
+
5
+#HttpOnly_localhost FALSE / FALSE 1769537822 och_session eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw
0
6
▼create_repo_debug.txt
+36-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 42012
14
+* using HTTP/1.x
15
+> POST /api/repos HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Cookie: och_session=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw
20
+> Content-Type: application/json
21
+> Content-Length: 114
22
+>
23
+} [114 bytes data]
24
+* upload completely sent off: 114 bytes
25
+ 100 114 0 0 100 114 0 94 00:01 00:01 95 100 114 0 0 100 114 0 51 00:02 00:02 51< HTTP/1.1 500 Internal Server Error
26
+< Vary: Origin
27
+< content-type: application/json
28
+< Date: Tue, 20 Jan 2026 18:17:56 GMT
29
+< Connection: keep-alive
30
+< Keep-Alive: timeout=5
31
+< Transfer-Encoding: chunked
32
+<
33
+{ [1473 bytes data]
34
+ 100 1575 0 1461 100 114 611 47 00:02 00:02 51 100 1575 0 1461 100 114 611 47 00:02 00:02 51 100 1575 0 1461 100 114 611 47 00:02 00:02 51
35
+* Connection #0 to host localhost:3000 left intact
36
+{"success":false,"error":{"code":"SERVER_ERROR","message":"Failed to initialize repository: {\"stack\":\"Error: Pushing to data/repos/testuser5/test-repo-2.git\\nfatal: 'data/repos/testuser5/test-repo-2.git' does not appear to be a git repository\\nfatal: Could not read from remote repository.\\n\\nPlease make sure you have the correct access rights\\nand the repository exists.\\n\\n at Object.action (file:///home/swadhin/owngit/OpenCodeHub/node_modules/simple-git/dist/esm/index.js:4462:25)\\n at PluginStore.exec (file:///home/swadhin/owngit/OpenCodeHub/node_modules/simple-git/dist/esm/index.js:4501:25)\\n at file:///home/swadhin/owngit/OpenCodeHub/node_modules/simple-git/dist/esm/index.js:1345:43\\n at new Promise (<anonymous>)\\n at GitExecutorChain.handleTaskData (file:///home/swadhin/owngit/OpenCodeHub/node_modules/simple-git/dist/esm/index.js:1343:16)\\n at GitExecutorChain.attemptRemoteTask (file:///home/swadhin/owngit/OpenCodeHub/node_modules/simple-git/dist/esm/index.js:1330:42)\\n at async GitExecutorChain.attemptTask (file:///home/swadhin/owngit/OpenCodeHub/node_modules/simple-git/dist/esm/index.js:1302:18)\",\"message\":\"Pushing to data/repos/testuser5/test-repo-2.git\\nfatal: 'data/repos/testuser5/test-repo-2.git' does not appear to be a git repository\\nfatal: Could not read from remote repository.\\n\\nPlease make sure you have the correct access rights\\nand the repository exists.\\n\",\"task\":{}}"}}
0
37
▼create_repo_out_3.txt
+36-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 58654
14
+* using HTTP/1.x
15
+> POST /api/repos HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Cookie: och_session=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw
20
+> Content-Type: application/json
21
+> Content-Length: 113
22
+>
23
+} [113 bytes data]
24
+* upload completely sent off: 113 bytes
25
+ 100 113 0 0 100 113 0 94 00:01 00:01 94 100 113 0 0 100 113 0 51 00:02 00:02 51 100 113 0 0 100 113 0 35 00:03 00:03 35< HTTP/1.1 201 Created
26
+< Vary: Origin
27
+< content-type: application/json
28
+< Date: Tue, 20 Jan 2026 18:19:30 GMT
29
+< Connection: keep-alive
30
+< Keep-Alive: timeout=5
31
+< Transfer-Encoding: chunked
32
+<
33
+{ [513 bytes data]
34
+ 100 614 0 501 100 113 128 29 00:03 00:03 35 100 614 0 501 100 113 128 28 00:04 00:03 00:01 35 100 614 0 501 100 113 128 28 00:04 00:03 00:01 35
35
+* Connection #0 to host localhost:3000 left intact
36
+{"success":true,"data":{"id":"repo_w-EIXfinHhyGRl1r7eIiB","name":"test-repo-3","slug":"test-repo-3","fullName":"testuser5/test-repo-3","description":"Third test repository","visibility":"public","defaultBranch":"main","sshCloneUrl":"ssh://git@localhost:2222/testuser5/test-repo-3.git","httpCloneUrl":"http://localhost:3000/testuser5/test-repo-3.git","owner":{"id":"usr_Gxx3ZB2N5y8iUurZ2DATl","username":"testuser5","displayName":"Test User 5","avatarUrl":null},"createdAt":"2026-01-20T18:19:28.138Z"}}
0
37
▼create_repo_output.txt
+36-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 36728
14
+* using HTTP/1.x
15
+> POST /api/repos HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Cookie: och_session=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw
20
+> Content-Type: application/json
21
+> Content-Length: 113
22
+>
23
+} [113 bytes data]
24
+* upload completely sent off: 113 bytes
25
+ 100 113 0 0 100 113 0 94 00:01 00:01 94 100 113 0 0 100 113 0 51 00:02 00:02 51 100 113 0 0 100 113 0 35 00:03 00:03 35 100 113 0 0 100 113 0 26 00:04 00:04 26 100 113 0 0 100 113 0 21 00:05 00:05 21 100 113 0 0 100 113 0 18 00:06 00:06 0 100 113 0 0 100 113 0 15 00:07 00:07 0< HTTP/1.1 500 Internal Server Error
26
+< Vary: Origin
27
+< content-type: application/json
28
+< Date: Tue, 20 Jan 2026 18:17:33 GMT
29
+< Connection: keep-alive
30
+< Keep-Alive: timeout=5
31
+< Transfer-Encoding: chunked
32
+<
33
+{ [104 bytes data]
34
+ 100 206 0 93 100 113 12 15 00:07 00:07 18 100 206 0 93 100 113 12 15 00:07 00:07 18 100 206 0 93 100 113 12 15 00:07 00:07 18
35
+* Connection #0 to host localhost:3000 left intact
36
+{"success":false,"error":{"code":"SERVER_ERROR","message":"Failed to initialize repository"}}
0
37
▼debug_output.txt
+39-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 56498
14
+* using HTTP/1.x
15
+> POST /api/auth/register HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Content-Type: application/json
20
+> Content-Length: 127
21
+>
22
+} [127 bytes data]
23
+* upload completely sent off: 127 bytes
24
+< HTTP/1.1 429 Too Many Requests
25
+< Vary: Origin
26
+< content-type: application/json
27
+< retry-after: 815
28
+< x-ratelimit-limit: 5
29
+< x-ratelimit-remaining: 0
30
+< x-ratelimit-reset: 2026-01-20T18:28:40.319Z
31
+< Date: Tue, 20 Jan 2026 18:15:05 GMT
32
+< Connection: keep-alive
33
+< Keep-Alive: timeout=5
34
+< Transfer-Encoding: chunked
35
+<
36
+{ [106 bytes data]
37
+ 100 222 0 95 100 127 11640 15561 0 100 222 0 95 100 127 11509 15386 0 100 222 0 95 100 127 11384 15218 0
38
+* Connection #0 to host localhost:3000 left intact
39
+{"error":"Too many requests","message":"Rate limit exceeded. Please try again in 815 seconds."}
0
40
▼debug_output_2.txt
+35-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 51152
14
+* using HTTP/1.x
15
+> POST /api/auth/register HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Content-Type: application/json
20
+> Content-Length: 127
21
+>
22
+} [127 bytes data]
23
+* upload completely sent off: 127 bytes
24
+< HTTP/1.1 400 Bad Request
25
+< Vary: Origin
26
+< content-type: application/json
27
+< Date: Tue, 20 Jan 2026 18:15:30 GMT
28
+< Connection: keep-alive
29
+< Keep-Alive: timeout=5
30
+< Transfer-Encoding: chunked
31
+<
32
+{ [2132 bytes data]
33
+ 100 2247 0 2120 100 127 3006 180 0 100 2247 0 2120 100 127 3005 180 0 100 2247 0 2120 100 127 3004 179 0
34
+* Connection #0 to host localhost:3000 left intact
35
+{"success":false,"error":{"code":"BAD_REQUEST","message":"DEBUG ERROR: Failed query: select \"id\", \"username\", \"email\", \"password_hash\", \"display_name\", \"bio\", \"avatar_url\", \"location\", \"website\", \"company\", \"is_admin\", \"is_active\", \"email_verified\", \"two_factor_enabled\", \"two_factor_secret\", \"last_login_at\", \"created_at\", \"updated_at\" from \"users\" \"users\" where (\"users\".\"username\" = $1 or \"users\".\"email\" = $2) limit $3\nparams: testuser4,[email protected],1 | Error: Failed query: select \"id\", \"username\", \"email\", \"password_hash\", \"display_name\", \"bio\", \"avatar_url\", \"location\", \"website\", \"company\", \"is_admin\", \"is_active\", \"email_verified\", \"two_factor_enabled\", \"two_factor_secret\", \"last_login_at\", \"created_at\", \"updated_at\" from \"users\" \"users\" where (\"users\".\"username\" = $1 or \"users\".\"email\" = $2) limit $3\nparams: testuser4,[email protected],1\n at NodePgPreparedQuery.queryWithCache (file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/pg-core/session.js:41:15)\n at process.processTicksAndRejections (node:internal/process/task_queues:103:5)\n at async file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/node-postgres/session.js:117:22\n at async eval (/home/swadhin/owngit/OpenCodeHub/src/pages/api/auth/register.ts:55:26)\n at async Module.eval (/home/swadhin/owngit/OpenCodeHub/src/lib/errors.ts:71:14)\n at async renderEndpoint (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/runtime/server/endpoint.js:34:18)\n at async lastNext (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/render-context.js:139:23)\n at async callMiddleware (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/middleware/callMiddleware.js:11:10)\n at async RenderContext.render (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/render-context.js:178:22)\n at async handleRoute (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/vite-plugin-astro-server/route.js:135:16)"}}
0
36
▼debug_output_3.txt
+35-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 53356
14
+* using HTTP/1.x
15
+> POST /api/auth/register HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Content-Type: application/json
20
+> Content-Length: 127
21
+>
22
+} [127 bytes data]
23
+* upload completely sent off: 127 bytes
24
+< HTTP/1.1 400 Bad Request
25
+< Vary: Origin
26
+< content-type: application/json
27
+< Date: Tue, 20 Jan 2026 18:16:10 GMT
28
+< Connection: keep-alive
29
+< Keep-Alive: timeout=5
30
+< Transfer-Encoding: chunked
31
+<
32
+{ [4149 bytes data]
33
+{"success":false,"error":{"code":"BAD_REQUEST","message":"DEBUG ERROR: {\"stack\":\"Error: Failed query: select \\\"id\\\", \\\"username\\\", \\\"email\\\", \\\"password_hash\\\", \\\"display_name\\\", \\\"bio\\\", \\\"avatar_url\\\", \\\"location\\\", \\\"website\\\", \\\"company\\\", \\\"is_admin\\\", \\\"is_active\\\", \\\"email_verified\\\", \\\"two_factor_enabled\\\", \\\"two_factor_secret\\\", \\\"last_login_at\\\", \\\"created_at\\\", \\\"updated_at\\\" from \\\"users\\\" \\\"users\\\" where (\\\"users\\\".\\\"username\\\" = $1 or \\\"users\\\".\\\"email\\\" = $2) limit $3\\nparams: testuser4,[email protected],1\\n at NodePgPreparedQuery.queryWithCache (file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/pg-core/session.js:41:15)\\n at process.processTicksAndRejections (node:internal/process/task_queues:103:5)\\n at async file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/node-postgres/session.js:117:22\\n at async eval (/home/swadhin/owngit/OpenCodeHub/src/pages/api/auth/register.ts:55:26)\\n at async Module.eval (/home/swadhin/owngit/OpenCodeHub/src/lib/errors.ts:71:14)\\n at async renderEndpoint (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/runtime/server/endpoint.js:34:18)\\n at async lastNext (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/render-context.js:139:23)\\n at async callMiddleware (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/middleware/callMiddleware.js:11:10)\\n at async RenderContext.render (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/render-context.js:178:22)\\n at async handleRoute (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/vite-plugin-astro-server/route.js:135:16)\",\"message\":\"Failed query: select \\\"id\\\", \\\"username\\\", \\\"email\\\", \\\"password_hash\\\", \\\"display_name\\\", \\\"bio\\\", \\\"avatar_url\\\", \\\"location\\\", \\\"website\\\", \\\"company\\\", \\\"is_admin\\\", \\\"is_active\\\", \\\"email_verified\\\", \\\"two_factor_enabled\\\", \\\"two_factor_secret\\\", \\\"last_login_at\\\", \\\"created_at\\\", \\\"updated_at\\\" from \\\"users\\\" \\\"users\\\" where (\\\"users\\\".\\\"username\\\" = $1 or \\\"users\\\".\\\"email\\\" = $2) limit $3\\nparams: testuser4,[email protected],1\",\"query\":\"select \\\"id\\\", \\\"username\\\", \\\"email\\\", \\\"password_hash\\\", \\\"display_name\\\", \\\"bio\\\", \\\"avatar_url\\\", \\\"location\\\", \\\"website\\\", \\\"company\\\", \\\"is_admin\\\", \\\"is_active\\\", \\\"email_verified\\\", \\\"two_factor_enabled\\\", \\\"two_factor_secret\\\", \\\"last_login_at\\\", \\\"created_at\\\", \\\"updated_at\\\" from \\\"users\\\" \\\"users\\\" where (\\\"users\\\".\\\"username\\\" = $1 or \\\"users\\\".\\\"email\\\" = $2) limit $3\",\"params\":[\"testuser4\",\"[email protected]\",1],\"cause\":{\"stack\":\"Error: self-signed certificate in certificate chain\\n at /home/swadhin/owngit/OpenCodeHub/node_modules/pg-pool/index.js:45:11\\n at process.processTicksAndRejections (node:internal/process/task_queues:103:5)\\n at async file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/node-postgres/session.js:124:18\\n at async NodePgPreparedQuery.queryWithCache (file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/pg-core/session.js:39:16)\\n at async file:///home/swadhin/owngit/OpenCodeHub/node_modules/drizzle-orm/node-postgres/session.js:117:22\\n at async eval (/home/swadhin/owngit/OpenCodeHub/src/pages/api/auth/register.ts:55:26)\\n at async Module.eval (/home/swadhin/owngit/OpenCodeHub/src/lib/errors.ts:71:14)\\n at async renderEndpoint (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/runtime/server/endpoint.js:34:18)\\n at async lastNext (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/render-context.js:139:23)\\n at async callMiddleware (file:///home/swadhin/owngit/OpenCodeHub/node_modules/astro/dist/core/middleware/callMiddleware.js:11:10)\",\"message\":\"self-signed 100 4263 0 4136 100 127 9314 286 0 100 4263 0 4136 100 127 9310 285 0 100 4263 0 4136 100 127 9306 285 0
34
+* Connection #0 to host localhost:3000 left intact
35
+ certificate in certificate chain\"}}"}}
0
36
▼debug_output_4.txt
+37-0
1
+Note: Unnecessary
2
+Note: use of -X or
3
+Note: --request,
4
+Note: POST is
5
+Note: already
6
+Note: inferred.
7
+* Host localhost:3000 was resolved.
8
+* IPv6: ::1
9
+* IPv4: 127.0.0.1
10
+ % Total % Received % Xferd Average Speed Time Time Time Current
11
+ Dload Upload Total Spent Left Speed
12
+ 0 0 0 0 0 0 0 0 0* Trying [::1]:3000...
13
+* Established connection to localhost (::1 port 3000) from ::1 port 32838
14
+* using HTTP/1.x
15
+> POST /api/auth/register HTTP/1.1
16
+> Host: localhost:3000
17
+> User-Agent: curl/8.18.0
18
+> Accept: */*
19
+> Content-Type: application/json
20
+> Content-Length: 127
21
+>
22
+} [127 bytes data]
23
+* upload completely sent off: 127 bytes
24
+ 100 127 0 0 100 127 0 105 00:01 00:01 105< HTTP/1.1 201 Created
25
+< Vary: Origin
26
+* Added cookie och_session="eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw" for domain localhost, path /, expire 1769537822
27
+< set-cookie: och_session=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw; Path=/; Expires=Tue, 27 Jan 2026 18:17:02 GMT; HttpOnly; SameSite=Lax
28
+< content-type: application/json
29
+< Date: Tue, 20 Jan 2026 18:17:02 GMT
30
+< Connection: keep-alive
31
+< Keep-Alive: timeout=5
32
+< Transfer-Encoding: chunked
33
+<
34
+{ [560 bytes data]
35
+ 100 675 0 548 100 127 418 97 00:01 00:01 105 100 675 0 548 100 127 418 97 00:01 00:01 105 100 675 0 548 100 127 418 97 00:01 00:01 105
36
+* Connection #0 to host localhost:3000 left intact
37
+{"success":true,"data":{"user":{"id":"usr_Gxx3ZB2N5y8iUurZ2DATl","username":"testuser5","email":"[email protected]","displayName":"Test User 5"},"token":"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c3JfR3h4M1pCMk41eThpVXVyWjJEQVRsIiwidXNlcm5hbWUiOiJ0ZXN0dXNlcjUiLCJlbWFpbCI6InRlc3R1c2VyNUBleGFtcGxlLmNvbSIsInNlc3Npb25JZCI6InNlc3NfS3VFUHlNQmFsZ0s0RjgwZTVWZENMIiwiaWF0IjoxNzY4OTMzMDIyLCJpc3MiOiJvcGVuY29kZWh1YiIsImF1ZCI6Im9wZW5jb2RlaHViLWFwaSIsImV4cCI6MTc2OTUzNzgyMn0.QiHu30cZVUMaWabicMoWL9QIuy0FQ0fE4tEPkpUF3Sw","expiresAt":"2026-01-27T18:17:02.573Z"}}
0
38
▼docker-compose.yml
+2-2
49
49
50
50
# PostgreSQL database
51
51
postgres:
52
- image: postgres:16-alpine
52
+ image: docker.io/library/postgres:16-alpine
53
53
container_name: opencodehub-postgres
54
54
restart: unless-stopped
55
55
environment:
70
70
71
71
# Redis for caching and sessions
72
72
redis:
73
- image: redis:7-alpine
73
+ image: docker.io/library/redis:7-alpine
74
74
container_name: opencodehub-redis
75
75
restart: unless-stopped
76
76
command: redis-server --appendonly yes
77
77
▼drizzle.config.ts
+1-1
20
20
switch (driver) {
21
21
case "postgres":
22
22
case "mysql":
23
- return { url };
23
+ return { url, ssl: { rejectUnauthorized: false } };
24
24
case "libsql":
25
25
case "turso":
26
26
return { url, authToken: process.env.DATABASE_AUTH_TOKEN };
27
27
▼lint_output.txt
+1348-0
1
+
2
3
+> astro check
4
+
5
+14:15:31 [types] Generated 33ms
6
+14:15:31 [check] Getting diagnostics for Astro files in /home/swadhin/owngit/OpenCodeHub...
7
+src/components/admin/AdminDashboard.tsx:141:30 - warning ts(6385): 'Github' is deprecated.
8
+
9
+141 <Github className="h-8 w-8 text-white opacity-30 hover:opacity-70 transition-opacity cursor-pointer" />
10
+   ~~~~~~
11
+src/components/admin/AdminDashboard.tsx:10:10 - warning ts(6385): 'Github' is deprecated.
12
+
13
+10 import { Github } from "lucide-react";
14
+   ~~~~~~
15
+
16
+src/components/admin/AlertBanner.tsx:2:44 - warning ts(6133): 'Bell' is declared but its value is never read.
17
+
18
+2 import { AlertTriangle, CheckCircle, Info, Bell, X } from "lucide-react";
19
+   ~~~~
20
+
21
+src/components/admin/DashboardStats.tsx:1:45 - warning ts(6133): 'useTransform' is declared but its value is never read.
22
+
23
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
24
+   ~~~~~~~~~~~~
25
+src/components/admin/DashboardStats.tsx:1:34 - warning ts(6133): 'useSpring' is declared but its value is never read.
26
+
27
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
28
+   ~~~~~~~~~
29
+src/components/admin/DashboardStats.tsx:1:18 - warning ts(6133): 'useMotionValue' is declared but its value is never read.
30
+
31
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
32
+   ~~~~~~~~~~~~~~
33
+
34
+src/components/admin/GlobeViz.tsx:199:27 - warning ts(6133): 'activities' is declared but its value is never read.
35
+
36
+199 function CSSGlobeFallback({ activities = [] }: Props) {
37
+   ~~~~~~~~~~~~~~~~~~~
38
+src/components/admin/GlobeViz.tsx:89:54 - warning ts(6133): 'i' is declared but its value is never read.
39
+
40
+89 markers: activities.slice(0, 20).map((_, i) => ({
41
+   ~
42
+
43
+src/components/admin/QuickStatsRow.tsx:2:78 - warning ts(6133): 'Zap' is declared but its value is never read.
44
+
45
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
46
+   ~~~
47
+src/components/admin/QuickStatsRow.tsx:2:68 - warning ts(6133): 'Activity' is declared but its value is never read.
48
+
49
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
50
+   ~~~~~~~~
51
+src/components/admin/QuickStatsRow.tsx:2:49 - warning ts(6133): 'Clock' is declared but its value is never read.
52
+
53
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
54
+   ~~~~~
55
+
56
+src/components/admin/SystemStatus.tsx:18:5 - warning ts(6133): 'color' is declared but its value is never read.
57
+
58
+18 color,
59
+   ~~~~~
60
+src/components/admin/SystemStatus.tsx:1:47 - warning ts(6133): 'Server' is declared but its value is never read.
61
+
62
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
63
+   ~~~~~~
64
+src/components/admin/SystemStatus.tsx:1:41 - warning ts(6133): 'Wifi' is declared but its value is never read.
65
+
66
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
67
+   ~~~~
68
+
69
+src/components/dashboard/ActivityStream.tsx:80:55 - warning ts(6133): 'i' is declared but its value is never read.
70
+
71
+80 {users.slice(0, 5).map((user, i) => (
72
+   ~
73
+src/components/dashboard/ActivityStream.tsx:2:1 - warning ts(6133): 'React' is declared but its value is never read.
74
+
75
+2 import * as React from "react";
76
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
+
78
+src/components/git/CommitGraph.tsx:209:35 - warning ts(6133): 'index' is declared but its value is never read.
79
+
80
+209 {commits.map((commit, index) => {
81
+   ~~~~~
82
+src/components/git/CommitGraph.tsx:51:11 - warning ts(6133): 'branchHeads' is declared but its value is never read.
83
+
84
+51 const branchHeads: Map<string, string> = new Map()
85
+   ~~~~~~~~~~~
86
+
87
+src/components/home/HeroSection.tsx:87:26 - warning ts(6385): 'Github' is deprecated.
88
+
89
+87 <Github className="h-4 w-4" />
90
+   ~~~~~~
91
+src/components/home/HeroSection.tsx:6:22 - warning ts(6385): 'Github' is deprecated.
92
+
93
+6 import { ArrowRight, Github, Star, GitBranch, Zap } from "lucide-react";
94
+   ~~~~~~
95
+src/components/home/HeroSection.tsx:4:1 - warning ts(6133): 'ColourfulText' is declared but its value is never read.
96
+
97
+4 import { ColourfulText } from "@/components/ui/colourful-text";
98
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
+
100
+src/components/issues/IssueDetail.tsx:68:67 - warning ts(6133): 'repoName' is declared but its value is never read.
101
+
102
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
103
+   ~~~~~~~~
104
+src/components/issues/IssueDetail.tsx:68:56 - warning ts(6133): 'repoOwner' is declared but its value is never read.
105
+
106
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
107
+   ~~~~~~~~~
108
+
109
+src/components/issues/IssuesList.tsx:14:5 - warning ts(6133): 'Filter' is declared but its value is never read.
110
+
111
+14 Filter
112
+   ~~~~~~
113
+
114
+src/components/layout/Header.astro:2:10 - warning ts(6133): 'GitBranch' is declared but its value is never read.
115
+
116
+2 import { GitBranch, Search, Bell, Plus, Menu } from "lucide-react"
117
+   ~~~~~~~~~
118
+
119
+src/components/pr/AIReviewPanel.tsx:76:5 - warning ts(6133): 'reviewId' is declared but its value is never read.
120
+
121
+76 reviewId,
122
+   ~~~~~~~~
123
+src/components/pr/AIReviewPanel.tsx:6:8 - warning ts(6133): 'React' is declared but its value is never read.
124
+
125
+6 import React, { useState } from "react";
126
+   ~~~~~
127
+
128
+src/components/pr/StackVisualization.tsx:52:5 - warning ts(6133): 'onReorder' is declared but its value is never read.
129
+
130
+52 onReorder,
131
+   ~~~~~~~~~
132
+src/components/pr/StackVisualization.tsx:45:5 - warning ts(6133): 'stackId' is declared but its value is never read.
133
+
134
+45 stackId,
135
+   ~~~~~~~
136
+
137
+src/components/pulls/PullRequestsList.tsx:14:5 - warning ts(6133): 'Sparkles' is declared but its value is never read.
138
+
139
+14 Sparkles,
140
+   ~~~~~~~~
141
+
142
+src/components/repo/FileExplorer.astro:2:20 - warning ts(6133): 'Folder' is declared but its value is never read.
143
+
144
+2 import { FileText, Folder } from "lucide-react";
145
+   ~~~~~~
146
+
147
+src/components/repo/RepoHeader.astro:3:3 - warning ts(6133): 'GitBranch' is declared but its value is never read.
148
+
149
+3 GitBranch,
150
+   ~~~~~~~~~
151
+
152
+src/components/search/GlobalSearch.tsx:17:12 - warning ts(6133): 'loading' is declared but its value is never read.
153
+
154
+17 const [loading, setLoading] = React.useState(false);
155
+   ~~~~~~~
156
+src/components/search/GlobalSearch.tsx:11:18 - warning ts(6133): 'FileText' is declared but its value is never read.
157
+
158
+11 import { Search, FileText, User, GitBranch, GitPullRequest, CircleDot, Workflow } from "lucide-react";
159
+   ~~~~~~~~
160
+
161
+src/components/ui/animated-tooltip.tsx:4:8 - warning ts(6133): 'React' is declared but its value is never read.
162
+
163
+4 import React, { useState } from "react";
164
+   ~~~~~
165
+src/components/ui/animated-tooltip.tsx:2:1 - warning ts(6133): 'cn' is declared but its value is never read.
166
+
167
+2 import { cn } from "@/lib/cn";
168
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
+
170
+src/components/ui/text-generate-effect.tsx:2:29 - warning ts(6133): 'useState' is declared but its value is never read.
171
+
172
+2 import { useEffect, useRef, useState } from "react";
173
+   ~~~~~~~~
174
+src/components/ui/text-generate-effect.tsx:2:21 - warning ts(6133): 'useRef' is declared but its value is never read.
175
+
176
+2 import { useEffect, useRef, useState } from "react";
177
+   ~~~~~~
178
+
179
+src/components/ui/text-reveal-card.tsx:3:29 - warning ts(6133): 'useTransform' is declared but its value is never read.
180
+
181
+3 import { motion, useScroll, useTransform } from "framer-motion";
182
+   ~~~~~~~~~~~~
183
+src/components/ui/text-reveal-card.tsx:3:18 - warning ts(6133): 'useScroll' is declared but its value is never read.
184
+
185
+3 import { motion, useScroll, useTransform } from "framer-motion";
186
+   ~~~~~~~~~
187
+
188
+src/db/seed-activity.ts:6:1 - warning ts(6133): 'eq' is declared but its value is never read.
189
+
190
+6 import { eq } from "drizzle-orm";
191
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
+src/db/seed-activity.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
193
+
194
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
195
+   ~~~~~
196
+src/db/seed-activity.ts:3:10 - warning ts(6133): 'repositories' is declared but its value is never read.
197
+
198
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
199
+   ~~~~~~~~~~~~
200
+
201
+src/db/seed-notifications.ts:5:32 - warning ts(6133): 'repositories' is declared but its value is never read.
202
+
203
+5 import { notifications, users, repositories } from "@/db/schema";
204
+   ~~~~~~~~~~~~
205
+src/db/seed-notifications.ts:5:25 - warning ts(6133): 'users' is declared but its value is never read.
206
+
207
+5 import { notifications, users, repositories } from "@/db/schema";
208
+   ~~~~~
209
+
210
+src/db/seed-scale.ts:25:11 - warning ts(6133): 'reposPath' is declared but its value is never read.
211
+
212
+25 const reposPath = process.env.GIT_REPOS_PATH || "./data/repos";
213
+   ~~~~~~~~~
214
+src/db/seed-scale.ts:9:1 - warning ts(6133): 'fs' is declared but its value is never read.
215
+
216
+9 import fs from "fs/promises";
217
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
+src/db/seed-scale.ts:7:1 - warning ts(6133): 'eq' is declared but its value is never read.
219
+
220
+7 import { eq } from "drizzle-orm";
221
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222
+src/db/seed-scale.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
223
+
224
+3 import { repositories, users } from "@/db/schema";
225
+   ~~~~~
226
+
227
+src/db/schema/developer-metrics.ts:7:19 - warning ts(6133): 'real' is declared but its value is never read.
228
+
229
+7 import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
230
+   ~~~~
231
+
232
+src/db/schema/pipeline-runners.ts:3:10 - warning ts(6133): 'integer' is declared but its value is never read.
233
+
234
+3 import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
235
+   ~~~~~~~
236
+
237
+src/db/schema/pull-requests.ts:8:18 - warning ts(6133): 'milestones' is declared but its value is never read.
238
+
239
+8 import { labels, milestones } from "./issues";
240
+   ~~~~~~~~~~
241
+
242
+src/db/schema/security.ts:3:1 - warning ts(6133): 'users' is declared but its value is never read.
243
+
244
+3 import { users } from "./users";
245
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246
+
247
+src/lib/ai-review.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
248
+
249
+6 import { eq, and, desc } from "drizzle-orm";
250
+   ~~~
251
+
252
+src/lib/analysis.ts:35:87 - warning ts(6133): 'force' is declared but its value is never read.
253
+
254
+35 export async function analyzeRepository(repoId: string, userId: string | null = null, force = false) {
255
+   ~~~~~
256
+src/lib/analysis.ts:4:22 - warning ts(6133): 'getRepoSize' is declared but its value is never read.
257
+
258
+4 import { getCommits, getRepoSize, listFiles, getCommitDiff } from "./git";
259
+   ~~~~~~~~~~~
260
+
261
+src/lib/auth.ts:281:22 - warning ts(6133): 'gt' is declared but its value is never read.
262
+
263
+281 const { eq, and, gt } = await import("drizzle-orm");
264
+   ~~
265
+src/lib/auth.ts:281:17 - warning ts(6133): 'and' is declared but its value is never read.
266
+
267
+281 const { eq, and, gt } = await import("drizzle-orm");
268
+   ~~~
269
+src/lib/auth.ts:280:35 - warning ts(6133): 'users' is declared but its value is never read.
270
+
271
+280 const { personalAccessTokens, users } = await import("@/db/schema/users");
272
+   ~~~~~
273
+
274
+src/lib/automations.ts:320:23 - warning ts(6133): 'notifyPrEvent' is declared but its value is never read.
275
+
276
+320 const { notifyPrEvent } = await import("./slack-notifications");
277
+   ~~~~~~~~~~~~~~~~~
278
+
279
+src/lib/conflict-automation.ts:11:1 - warning ts(6192): All imports in import declaration are unused.
280
+
281
+11 import { notifyPrEvent, notifyUserDm } from "./slack-notifications";
282
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283
+src/lib/conflict-automation.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
284
+
285
+6 import { eq, and } from "drizzle-orm";
286
+   ~~~
287
+
288
+src/lib/developer-metrics.ts:6:35 - warning ts(6133): 'lte' is declared but its value is never read.
289
+
290
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
291
+   ~~~
292
+src/lib/developer-metrics.ts:6:30 - warning ts(6133): 'gte' is declared but its value is never read.
293
+
294
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
295
+   ~~~
296
+src/lib/developer-metrics.ts:6:25 - warning ts(6133): 'sql' is declared but its value is never read.
297
+
298
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
299
+   ~~~
300
+
301
+src/lib/git-storage.ts:15:27 - warning ts(6133): 'StorageAdapter' is declared but its value is never read.
302
+
303
+15 import { getStorage, type StorageAdapter } from "./storage";
304
+   ~~~~~~~~~~~~~~
305
+src/lib/git-storage.ts:14:1 - warning ts(6133): 'Readable' is declared but its value is never read.
306
+
307
+14 import { Readable } from "stream";
308
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309
+src/lib/git-storage.ts:10:54 - warning ts(6133): 'statSync' is declared but its value is never read.
310
+
311
+10 import { existsSync, mkdirSync, rmSync, readdirSync, statSync } from "fs";
312
+   ~~~~~~~~
313
+
314
+src/lib/git.ts:1171:32 - warning ts(6133): 'reject' is declared but its value is never read.
315
+
316
+1171 return new Promise((resolve, reject) => {
317
+   ~~~~~~
318
+src/lib/git.ts:14:3 - warning ts(6133): 'releaseRepo' is declared but its value is never read.
319
+
320
+14 releaseRepo,
321
+   ~~~~~~~~~~~
322
+src/lib/git.ts:13:3 - warning ts(6133): 'acquireRepo' is declared but its value is never read.
323
+
324
+13 acquireRepo,
325
+   ~~~~~~~~~~~
326
+
327
+src/lib/lfs.ts:64:3 - warning ts(6133): 'repoDiskPath' is declared but its value is never read.
328
+
329
+64 repoDiskPath: string,
330
+   ~~~~~~~~~~~~
331
+
332
+src/lib/merge-queue.ts:11:1 - warning ts(6133): 'emitQueueEvent' is declared but its value is never read.
333
+
334
+11 import { emitQueueEvent } from "./realtime";
335
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336
+src/lib/merge-queue.ts:6:34 - warning ts(6133): 'gt' is declared but its value is never read.
337
+
338
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
339
+   ~~
340
+src/lib/merge-queue.ts:6:30 - warning ts(6133): 'lt' is declared but its value is never read.
341
+
342
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
343
+   ~~
344
+
345
+src/lib/pipeline.ts:292:15 - warning ts(6133): 'tag' is declared but its value is never read.
346
+
347
+292 const tag = payload.ref.replace("refs/tags/", "");
348
+   ~~~
349
+src/lib/pipeline.ts:238:11 - warning ts(6133): 'artifactsDir' is declared but its value is never read.
350
+
351
+238 private artifactsDir: string;
352
+   ~~~~~~~~~~~~
353
+src/lib/pipeline.ts:237:11 - warning ts(6133): 'workDir' is declared but its value is never read.
354
+
355
+237 private workDir: string;
356
+   ~~~~~~~
357
+
358
+src/lib/realtime.ts:49:61 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
359
+
360
+49 return `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
361
+   ~~~~~~
362
+
363
+src/lib/security.ts:116:15 - warning ts(6133): 'rawOutput' is declared but its value is never read.
364
+
365
+116 const rawOutput = logsBuffer.toString("utf-8");
366
+   ~~~~~~~~~
367
+src/lib/security.ts:76:15 - warning ts(6133): 'stream' is declared but its value is never read.
368
+
369
+76 const stream = await container.logs({ follow: true, stdout: true, stderr: true });
370
+   ~~~~~~
371
+src/lib/security.ts:56:15 - warning ts(6133): 'chunks' is declared but its value is never read.
372
+
373
+56 const chunks: Buffer[] = [];
374
+   ~~~~~~
375
+src/lib/security.ts:48:41 - warning ts(6133): 'event' is declared but its value is never read.
376
+
377
+48 function onProgress(event: any) { }
378
+   ~~~~~
379
+src/lib/security.ts:44:51 - warning ts(6133): 'output' is declared but its value is never read.
380
+
381
+44 function onFinished(err: any, output: any) {
382
+   ~~~~~~
383
+src/lib/security.ts:40:41 - warning ts(6133): 'reject' is declared but its value is never read.
384
+
385
+40 await new Promise((resolve, reject) => {
386
+   ~~~~~~
387
+src/lib/security.ts:15:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
388
+
389
+15 repositoryId: string
390
+   ~~~~~~~~~~~~
391
+src/lib/security.ts:5:21 - warning ts(6133): 'writeFile' is declared but its value is never read.
392
+
393
+5 import { mkdir, rm, writeFile } from "fs/promises";
394
+   ~~~~~~~~~
395
+
396
+src/lib/slack-notifications.ts:257:5 - warning ts(6133): 'event' is declared but its value is never read.
397
+
398
+257 event: string,
399
+   ~~~~~
400
+
401
+src/lib/ssh.ts:190:32 - warning ts(6133): 'accept' is declared but its value is never read.
402
+
403
+190 session.on("shell", (accept, reject) => {
404
+   ~~~~~~
405
+src/lib/ssh.ts:78:39 - warning ts(6133): 'reject' is declared but its value is never read.
406
+
407
+78 client.on("session", (accept, reject) => {
408
+   ~~~~~~
409
+src/lib/ssh.ts:37:5 - warning ts(6133): 'port' is declared but its value is never read.
410
+
411
+37 port,
412
+   ~~~~
413
+
414
+src/lib/storage.ts:1196:9 - warning ts(6133): 'eq' is declared but its value is never read.
415
+
416
+1196 const { eq } = await import("drizzle-orm");
417
+   ~~~~~~
418
+src/lib/storage.ts:1098:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
419
+
420
+1098 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
421
+   ~~~~~~~~~
422
+src/lib/storage.ts:1084:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
423
+
424
+1084 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
425
+   ~~~~~~~~~
426
+src/lib/storage.ts:971:30 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
427
+
428
+971 const chunk = buffer.slice(i, Math.min(i + chunkSize, buffer.length));
429
+   ~~~~~
430
+src/lib/storage.ts:875:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
431
+
432
+875 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
433
+   ~~~~~~~~~
434
+src/lib/storage.ts:868:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
435
+
436
+868 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
437
+   ~~~~~~~~~
438
+src/lib/storage.ts:798:21 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
439
+
440
+798 return buffer.slice(options.range.start, options.range.end + 1);
441
+   ~~~~~
442
+src/lib/storage.ts:660:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
443
+
444
+660 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
445
+   ~~~~~~~~~
446
+src/lib/storage.ts:649:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
447
+
448
+649 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
449
+   ~~~~~~~~~
450
+src/lib/storage.ts:539:51 - warning ts(6133): 'options' is declared but its value is never read.
451
+
452
+539 async put(key: string, data: Buffer | Readable, options?: PutOptions): Promise<void> {
453
+   ~~~~~~~
454
+src/lib/storage.ts:274:5 - warning ts(6133): 'expiresIn' is declared but its value is never read.
455
+
456
+274 expiresIn: number = 3600
457
+   ~~~~~~~~~
458
+
459
+src/lib/sync.ts:361:23 - warning ts(6133): 'baseHead' is declared but its value is never read.
460
+
461
+361 const baseHead = await git.revparse([baseBranch]);
462
+   ~~~~~~~~
463
+src/lib/sync.ts:360:23 - warning ts(6133): 'mergeBase' is declared but its value is never read.
464
+
465
+360 const mergeBase = await git.raw(["merge-base", baseBranch, branchName]);
466
+   ~~~~~~~~~
467
+src/lib/sync.ts:267:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
468
+
469
+267 repositoryId: string,
470
+   ~~~~~~~~~~~~
471
+src/lib/sync.ts:57:15 - warning ts(6133): 'currentBranch' is declared but its value is never read.
472
+
473
+57 const currentBranch = status.current;
474
+   ~~~~~~~~~~~~~
475
+src/lib/sync.ts:10:1 - warning ts(6133): 'generateId' is declared but its value is never read.
476
+
477
+10 import { generateId } from "./utils";
478
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479
+src/lib/sync.ts:9:20 - warning ts(6133): 'getStackForPr' is declared but its value is never read.
480
+
481
+9 import { getStack, getStackForPr, addToStack, createStack } from "./stacks";
482
+   ~~~~~~~~~~~~~
483
+src/lib/sync.ts:6:19 - warning ts(6133): 'desc' is declared but its value is never read.
484
+
485
+6 import { eq, and, desc } from "drizzle-orm";
486
+   ~~~~
487
+
488
+src/lib/workflows.ts:26:92 - warning ts(6133): 'pusherId' is declared but its value is never read.
489
+
490
+26 export async function triggerRepoWorkflows(repoId: string, commitSha: string, ref: string, pusherId: string) {
491
+   ~~~~~~~~
492
+src/lib/workflows.ts:8:1 - warning ts(6133): 'existsSync' is declared but its value is never read.
493
+
494
+8 import { existsSync } from "fs";
495
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496
+
497
+src/pages/cli.astro:5:5 - warning ts(6133): 'Cpu' is declared but its value is never read.
498
+
499
+5 Cpu,
500
+   ~~~
501
+
502
+src/pages/explore.astro:4:20 - warning ts(6133): 'sql' is declared but its value is never read.
503
+
504
+4 import { desc, eq, sql, count } from "drizzle-orm";
505
+   ~~~
506
+
507
+src/pages/inbox.astro:28:5 - warning ts(6133): 'title' is declared but its value is never read.
508
+
509
+28 let title = "Inbox";
510
+   ~~~~~
511
+src/pages/inbox.astro:15:3 - warning ts(6133): 'Bot' is declared but its value is never read.
512
+
513
+15 Bot,
514
+   ~~~
515
+src/pages/inbox.astro:13:3 - warning ts(6133): 'Search' is declared but its value is never read.
516
+
517
+13 Search,
518
+   ~~~~~~
519
+src/pages/inbox.astro:5:29 - warning ts(6133): 'ne' is declared but its value is never read.
520
+
521
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
522
+   ~~
523
+src/pages/inbox.astro:5:25 - warning ts(6133): 'or' is declared but its value is never read.
524
+
525
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
526
+   ~~
527
+src/pages/inbox.astro:423:37 - error ts(2339): Property 'click' does not exist on type 'Element'.
528
+
529
+423 prItems[selectedIndex]?.click();
530
+   ~~~~~
531
+src/pages/inbox.astro:403:54 - error ts(2339): Property 'tagName' does not exist on type 'EventTarget'.
532
+
533
+403 if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") {
534
+   ~~~~~~~
535
+src/pages/inbox.astro:403:45 - error ts(18047): 'e.target' is possibly 'null'.
536
+
537
+403 if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") {
538
+   ~~~~~~~~
539
+src/pages/inbox.astro:403:22 - error ts(2339): Property 'tagName' does not exist on type 'EventTarget'.
540
+
541
+403 if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") {
542
+   ~~~~~~~
543
+src/pages/inbox.astro:403:13 - error ts(18047): 'e.target' is possibly 'null'.
544
+
545
+403 if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") {
546
+   ~~~~~~~~
547
+src/pages/inbox.astro:386:28 - error ts(7006): Parameter 'index' implicitly has an 'any' type.
548
+
549
+386 const highlightPR = (index) => {
550
+   ~~~~~
551
+
552
+src/pages/insights.astro:11:3 - warning ts(6133): 'Calendar' is declared but its value is never read.
553
+
554
+11 Calendar,
555
+   ~~~~~~~~
556
+src/pages/insights.astro:4:30 - warning ts(6133): 'sql' is declared but its value is never read.
557
+
558
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
559
+   ~~~
560
+src/pages/insights.astro:4:14 - warning ts(6133): 'desc' is declared but its value is never read.
561
+
562
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
563
+   ~~~~
564
+
565
+src/pages/issues.astro:7:7 - warning ts(6133): 'currentUser' is declared but its value is never read.
566
+
567
+7 const currentUser = Astro.locals.user;
568
+   ~~~~~~~~~~~
569
+src/pages/issues.astro:4:25 - warning ts(6133): 'sql' is declared but its value is never read.
570
+
571
+4 import { desc, eq, and, sql } from "drizzle-orm";
572
+   ~~~
573
+src/pages/issues.astro:4:20 - warning ts(6133): 'and' is declared but its value is never read.
574
+
575
+4 import { desc, eq, and, sql } from "drizzle-orm";
576
+   ~~~
577
+
578
+src/pages/merge-queue.astro:353:56 - warning ts(6133): 'index' is declared but its value is never read.
579
+
580
+353 {queueItems.map((item, index) => {
581
+   ~~~~~
582
+src/pages/merge-queue.astro:222:10 - warning ts(6133): 'timeAgo' is declared but its value is never read.
583
+
584
+222 function timeAgo(date: string) {
585
+   ~~~~~~~
586
+src/pages/merge-queue.astro:73:5 - warning ts(6133): 'lastProcessedAt' is declared but its value is never read.
587
+
588
+73 let lastProcessedAt: string | null = null;
589
+   ~~~~~~~~~~~~~~~
590
+
591
+src/pages/password-reset.astro:95:13 - warning ts(6133): 'response' is declared but its value is never read.
592
+
593
+95 const response = await fetch("/api/auth/password-reset", {
594
+   ~~~~~~~~
595
+
596
+src/pages/repositories.astro:14:53 - warning ts(6133): 'Globe' is declared but its value is never read.
597
+
598
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
599
+   ~~~~~
600
+src/pages/repositories.astro:14:47 - warning ts(6133): 'Lock' is declared but its value is never read.
601
+
602
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
603
+   ~~~~
604
+src/pages/repositories.astro:5:1 - warning ts(6192): All imports in import declaration are unused.
605
+
606
+ 5 import {
607
+  ~~~~~~~~
608
+ 6 Card,
609
+  ~~~~~~~~
610
+...
611
+ 10 CardContent,
612
+  ~~~~~~~~~~~~~~~
613
+ 11 } from "@/components/ui/card";
614
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
615
+
616
+src/pages/stars.astro:152:54 - warning ts(6385): 'event' is deprecated.
617
+
618
+152 onclick="event.preventDefault(); event.stopPropagation();"
619
+   ~~~~~
620
+src/pages/stars.astro:152:30 - warning ts(6385): 'event' is deprecated.
621
+
622
+152 onclick="event.preventDefault(); event.stopPropagation();"
623
+   ~~~~~
624
+
625
+src/pages/[owner]/[repo]/index.astro:15:19 - warning ts(6133): 'sql' is declared but its value is never read.
626
+
627
+15 import { eq, and, sql, count } from "drizzle-orm";
628
+   ~~~
629
+src/pages/[owner]/[repo]/index.astro:12:3 - warning ts(6133): 'Clock' is declared but its value is never read.
630
+
631
+12 Clock,
632
+   ~~~~~
633
+src/pages/[owner]/[repo]/index.astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
634
+
635
+6 Tag,
636
+   ~~~
637
+
638
+src/pages/[owner]/[repo]/labels.astro:245:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
639
+
640
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
641
+
642
+Add the `is:inline` directive explicitly to silence this hint.
643
+
644
+245 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
645
+   ~~~~~~~~~~~
646
+
647
+src/pages/[owner]/[repo]/merge-queue.astro:248:57 - warning ts(6133): 'i' is declared but its value is never read.
648
+
649
+248 {item.stack.entries.map((entry, i) => (
650
+   ~
651
+src/pages/[owner]/[repo]/merge-queue.astro:13:3 - warning ts(6133): 'Play' is declared but its value is never read.
652
+
653
+13 Play,
654
+   ~~~~
655
+src/pages/[owner]/[repo]/merge-queue.astro:8:19 - warning ts(6133): 'sql' is declared but its value is never read.
656
+
657
+8 import { and, eq, sql, count } from "drizzle-orm";
658
+   ~~~
659
+
660
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:18:3 - warning ts(6133): 'Monitor' is declared but its value is never read.
661
+
662
+18 Monitor,
663
+   ~~~~~~~
664
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:13:3 - warning ts(6133): 'FileText' is declared but its value is never read.
665
+
666
+13 FileText,
667
+   ~~~~~~~~
668
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:337:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
669
+
670
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
671
+
672
+Add the `is:inline` directive explicitly to silence this hint.
673
+
674
+337 <script define:vars={{ initialContent: !fileData.isBinary ? fileData.content : "" }}>
675
+   ~~~~~~~~~~~
676
+
677
+src/pages/[owner]/[repo]/branches/index.astro:16:3 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
678
+
679
+16 AlertCircle,
680
+   ~~~~~~~~~~~
681
+src/pages/[owner]/[repo]/branches/index.astro:15:3 - warning ts(6133): 'Search' is declared but its value is never read.
682
+
683
+15 Search,
684
+   ~~~~~~
685
+src/pages/[owner]/[repo]/branches/index.astro:13:3 - warning ts(6133): 'MoreHorizontal' is declared but its value is never read.
686
+
687
+13 MoreHorizontal,
688
+   ~~~~~~~~~~~~~~
689
+src/pages/[owner]/[repo]/branches/index.astro:9:19 - warning ts(6133): 'sql' is declared but its value is never read.
690
+
691
+9 import { and, eq, sql, count } from "drizzle-orm";
692
+   ~~~
693
+src/pages/[owner]/[repo]/branches/index.astro:8:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
694
+
695
+8 import { getRepoPath } from "@/lib/utils";
696
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
697
+src/pages/[owner]/[repo]/branches/index.astro:351:42 - warning ts(6133): 'e' is declared but its value is never read.
698
+
699
+351 btn.addEventListener("click", async (e: any) => {
700
+   ~
701
+
702
+src/pages/[owner]/[repo]/commits/[...ref].astro:9:1 - warning ts(6133): 'Button' is declared but its value is never read.
703
+
704
+9 import { Button } from "@/components/ui/button";
705
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
706
+
707
+src/pages/[owner]/[repo]/edit/[...ref].astro:108:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
708
+
709
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
710
+
711
+Add the `is:inline` directive explicitly to silence this hint.
712
+
713
+108 <script define:vars={{ initialContent: fileContent, repoId: repo.id, branch: currentBranch, path: filePath, owner: repo.owner, repoName: repo.name }}>
714
+   ~~~~~~~~~~~
715
+
716
+src/pages/[owner]/[repo]/insights/index.astro:75:41 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
717
+
718
+75 repo.openIssueCount = issueCountResult?.count || 0;
719
+   ~~~~~
720
+src/pages/[owner]/[repo]/insights/index.astro:65:13 - error ts(2554): Expected 0 arguments, but got 1.
721
+
722
+65 .select({ count: count() })
723
+   ~~~~~~~~~~~~~~~~~~
724
+src/pages/[owner]/[repo]/insights/index.astro:276:69 - warning ts(6133): 'i' is declared but its value is never read.
725
+
726
+276 {contributors.map((contributor, i) => (
727
+   ~
728
+src/pages/[owner]/[repo]/insights/index.astro:84:7 - warning ts(6133): 'recentCommits' is declared but its value is never read.
729
+
730
+84 const recentCommits = await getCommits(repoData.diskPath, { limit: 20 });
731
+   ~~~~~~~~~~~~~
732
+src/pages/[owner]/[repo]/insights/index.astro:9:5 - warning ts(6133): 'GitCommit' is declared but its value is never read.
733
+
734
+9 GitCommit,
735
+   ~~~~~~~~~
736
+src/pages/[owner]/[repo]/insights/index.astro:5:24 - warning ts(6133): 'desc' is declared but its value is never read.
737
+
738
+5 import { eq, and, sql, desc, gte, count } from "drizzle-orm";
739
+   ~~~~
740
+src/pages/[owner]/[repo]/insights/index.astro:5:19 - warning ts(6133): 'sql' is declared but its value is never read.
741
+
742
+5 import { eq, and, sql, desc, gte, count } from "drizzle-orm";
743
+   ~~~
744
+
745
+src/pages/[owner]/[repo]/pulls/[number].astro:100:11 - error ts(2554): Expected 0 arguments, but got 1.
746
+
747
+100 .select({ count: sql<number>`count(*)` })
748
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
749
+src/pages/[owner]/[repo]/pulls/[number].astro:359:50 - warning ts(6133): 'i' is declared but its value is never read.
750
+
751
+359 {stackInfo.entries.map((entry, i) => {
752
+   ~
753
+src/pages/[owner]/[repo]/pulls/[number].astro:136:5 - warning ts(6133): 'mergeError' is declared but its value is never read.
754
+
755
+136 let mergeError = "";
756
+   ~~~~~~~~~~
757
+src/pages/[owner]/[repo]/pulls/[number].astro:24:3 - warning ts(6133): 'ChevronRight' is declared but its value is never read.
758
+
759
+24 ChevronRight,
760
+   ~~~~~~~~~~~~
761
+src/pages/[owner]/[repo]/pulls/[number].astro:16:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
762
+
763
+16 CheckCircle2,
764
+   ~~~~~~~~~~~~
765
+src/pages/[owner]/[repo]/pulls/[number].astro:13:29 - warning ts(6133): 'count' is declared but its value is never read.
766
+
767
+13 import { and, eq, sql, asc, count } from "drizzle-orm";
768
+   ~~~~~
769
+src/pages/[owner]/[repo]/pulls/[number].astro:419:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
770
+
771
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
772
+
773
+Add the `is:inline` directive explicitly to silence this hint.
774
+
775
+419 define:vars={{
776
+   ~~~~~~~~~~~
777
+
778
+src/pages/[owner]/[repo]/pulls/index.astro:51:42 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
779
+
780
+51 const openIssueCount = issueCountResult?.count || 0;
781
+   ~~~~~
782
+src/pages/[owner]/[repo]/pulls/index.astro:41:11 - error ts(2554): Expected 0 arguments, but got 1.
783
+
784
+41 .select({ count: count() })
785
+   ~~~~~~~~~~~~~~~~~~
786
+src/pages/[owner]/[repo]/pulls/index.astro:7:25 - warning ts(6133): 'sql' is declared but its value is never read.
787
+
788
+7 import { and, desc, eq, sql, count } from "drizzle-orm";
789
+   ~~~
790
+
791
+src/pages/[owner]/[repo]/pulls/new.astro:109:42 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
792
+
793
+109 const openIssueCount = issueCountResult?.count || 0;
794
+   ~~~~~
795
+src/pages/[owner]/[repo]/pulls/new.astro:99:11 - error ts(2554): Expected 0 arguments, but got 1.
796
+
797
+99 .select({ count: count() })
798
+   ~~~~~~~~~~~~~~~~~~
799
+src/pages/[owner]/[repo]/pulls/new.astro:66:20 - error ts(2554): Expected 2 arguments, but got 1.
800
+
801
+66 const repoPath = getRepoPath(repoData.id);
802
+   ~~~~~~~~~~~
803
+src/pages/[owner]/[repo]/pulls/new.astro:84:5 - warning ts(6133): 'canMerge' is declared but its value is never read.
804
+
805
+84 let canMerge = false;
806
+   ~~~~~~~~
807
+src/pages/[owner]/[repo]/pulls/new.astro:83:5 - warning ts(6133): 'error' is declared but its value is never read.
808
+
809
+83 let error = "";
810
+   ~~~~~
811
+src/pages/[owner]/[repo]/pulls/new.astro:25:3 - warning ts(6133): 'ArrowRight' is declared but its value is never read.
812
+
813
+25 ArrowRight,
814
+   ~~~~~~~~~~
815
+src/pages/[owner]/[repo]/pulls/new.astro:22:19 - warning ts(6133): 'sql' is declared but its value is never read.
816
+
817
+22 import { and, eq, sql, count } from "drizzle-orm";
818
+   ~~~
819
+src/pages/[owner]/[repo]/pulls/new.astro:336:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
820
+
821
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
822
+
823
+Add the `is:inline` directive explicitly to silence this hint.
824
+
825
+336 define:vars={{
826
+   ~~~~~~~~~~~
827
+
828
+src/pages/[owner]/[repo]/security/index.astro:47:12 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
829
+
830
+47 .get())?.count || 0;
831
+   ~~~~~
832
+src/pages/[owner]/[repo]/security/index.astro:39:11 - error ts(2554): Expected 0 arguments, but got 1.
833
+
834
+39 .select({ count: sql<number>`count(*)` })
835
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
836
+src/pages/[owner]/[repo]/security/index.astro:8:10 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
837
+
838
+8 import { AlertCircle, CheckCircle, Shield, Play, Loader2 } from "lucide-react";
839
+   ~~~~~~~~~~~
840
+src/pages/[owner]/[repo]/security/index.astro:202:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
841
+
842
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
843
+
844
+Add the `is:inline` directive explicitly to silence this hint.
845
+
846
+202 <script define:vars={{ repoOwner: repoInfo.owner, repoName: repoInfo.name }}>
847
+   ~~~~~~~~~~~
848
+
849
+src/pages/[owner]/[repo]/settings/collaborators.astro:83:10 - warning ts(6133): 'getRoleDescription' is declared but its value is never read.
850
+
851
+83 function getRoleDescription(role: string) {
852
+   ~~~~~~~~~~~~~~~~~~
853
+src/pages/[owner]/[repo]/settings/collaborators.astro:297:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
854
+
855
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
856
+
857
+Add the `is:inline` directive explicitly to silence this hint.
858
+
859
+297 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
860
+   ~~~~~~~~~~~
861
+
862
+src/pages/[owner]/[repo]/settings/index.astro:240:32 - error ts(18047): 'repo.isArchived' is possibly 'null'.
863
+
864
+240 data-archived={repo.isArchived.toString()}
865
+   ~~~~~~~~~~~~~~~
866
+src/pages/[owner]/[repo]/settings/index.astro:267:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
867
+
868
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
869
+
870
+Add the `is:inline` directive explicitly to silence this hint.
871
+
872
+267 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
873
+   ~~~~~~~~~~~
874
+
875
+src/pages/[owner]/[repo]/settings/webhooks.astro:326:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
876
+
877
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
878
+
879
+Add the `is:inline` directive explicitly to silence this hint.
880
+
881
+326 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
882
+   ~~~~~~~~~~~
883
+
884
+src/pages/[owner]/[repo]/settings/actions/runners.astro:15:18 - warning ts(6133): 'Terminal' is declared but its value is never read.
885
+
886
+15 import { Server, Terminal, Copy } from "lucide-react";
887
+   ~~~~~~~~
888
+src/pages/[owner]/[repo]/settings/actions/runners.astro:210:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
889
+
890
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
891
+
892
+Add the `is:inline` directive explicitly to silence this hint.
893
+
894
+210 <script define:vars={{ repoId: repoData.id }}>
895
+   ~~~~~~~~~~~
896
+
897
+src/pages/[owner]/[repo]/settings/branches/[id].astro:117:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
898
+
899
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
900
+
901
+Add the `is:inline` directive explicitly to silence this hint.
902
+
903
+117 <script define:vars={{ repoId: repository.id, ruleId: rule.id, owner, repo }}>
904
+   ~~~~~~~~~~~
905
+
906
+src/pages/[owner]/[repo]/settings/branches/index.astro:59:20 - error ts(18047): 'rule.requiredApprovals' is possibly 'null'.
907
+
908
+59 {rule.requiredApprovals > 0 && <span>• {rule.requiredApprovals} Approval(s)</span>}
909
+   ~~~~~~~~~~~~~~~~~~~~~~
910
+src/pages/[owner]/[repo]/settings/branches/index.astro:2:20 - error ts(2307): Cannot find module '@/layouts/RepositoryLayout.astro' or its corresponding type declarations.
911
+
912
+2 import Layout from "@/layouts/RepositoryLayout.astro";
913
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
914
+src/pages/[owner]/[repo]/settings/branches/index.astro:4:14 - warning ts(6133): 'and' is declared but its value is never read.
915
+
916
+4 import { eq, and } from "drizzle-orm";
917
+   ~~~
918
+
919
+src/pages/[owner]/[repo]/settings/branches/new.astro:152:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
920
+
921
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
922
+
923
+Add the `is:inline` directive explicitly to silence this hint.
924
+
925
+152 <script define:vars={{ repoId: repository.id, owner, repo }}>
926
+   ~~~~~~~~~~~
927
+
928
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:5:19 - warning ts(6133): 'desc' is declared but its value is never read.
929
+
930
+5 import { eq, and, desc } from "drizzle-orm";
931
+   ~~~~
932
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:176:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
933
+
934
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
935
+
936
+Add the `is:inline` directive explicitly to silence this hint.
937
+
938
+176 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name, webhookId: webhook.id }}>
939
+   ~~~~~~~~~~~
940
+
941
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:120:52 - error ts(2551): Property 'isActive' does not exist on type '{ id: string; createdAt: string; updatedAt: string; repositoryId: string; active: boolean; createdById: string | null; url: string; secret: string | null; events: unknown; contentType: string; deliveryCount: number | null; lastDeliveryStatus: string | null; lastDeliveryAt: string | null; }'. Did you mean 'active'?
942
+
943
+120 {!hook.isActive && (
944
+   ~~~~~~~~
945
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:7:52 - warning ts(6133): 'MoreVertical' is declared but its value is never read.
946
+
947
+7 import { Plus, CheckCircle2, XCircle, AlertCircle, MoreVertical } from "lucide-react";
948
+   ~~~~~~~~~~~~
949
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:7:39 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
950
+
951
+7 import { Plus, CheckCircle2, XCircle, AlertCircle, MoreVertical } from "lucide-react";
952
+   ~~~~~~~~~~~
953
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:161:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
954
+
955
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
956
+
957
+Add the `is:inline` directive explicitly to silence this hint.
958
+
959
+161 <script define:vars={{ repoId: repo.id }}>
960
+   ~~~~~~~~~~~
961
+
962
+src/pages/[owner]/[repo]/settings/webhooks/new.astro:187:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
963
+
964
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
965
+
966
+Add the `is:inline` directive explicitly to silence this hint.
967
+
968
+187 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name }}>
969
+   ~~~~~~~~~~~
970
+
971
+src/pages/[owner]/[repo]/tree/[...ref].astro:70:42 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
972
+
973
+70 const openIssueCount = issueCountResult?.count || 0;
974
+   ~~~~~
975
+src/pages/[owner]/[repo]/tree/[...ref].astro:60:11 - error ts(2554): Expected 0 arguments, but got 1.
976
+
977
+60 .select({ count: sql<number>`count(*)` })
978
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
979
+src/pages/[owner]/[repo]/tree/[...ref].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
980
+
981
+6 Tag,
982
+   ~~~
983
+
984
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:63:42 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
985
+
986
+63 const openIssueCount = issueCountResult?.count || 0;
987
+   ~~~~~
988
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:53:11 - error ts(2554): Expected 0 arguments, but got 1.
989
+
990
+53 .select({ count: sql<number>`count(*)` })
991
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
992
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:11:3 - warning ts(6133): 'FileText' is declared but its value is never read.
993
+
994
+11 FileText,
995
+   ~~~~~~~~
996
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
997
+
998
+6 Tag,
999
+   ~~~
1000
+
1001
+src/pages/admin/audit.astro:76:28 - error ts(2339): Property 'count' does not exist on type '{ id: string; userId: string | null; repositoryId: string | null; action: string; actorType: string; actorId: string | null; actorIp: string | null; actorUserAgent: string | null; targetType: string | null; targetId: string | null; targetName: string | null; data: string | null; createdAt: string; }'.
1002
+
1003
+76 const total = totalResult?.count || 0;
1004
+   ~~~~~
1005
+src/pages/admin/audit.astro:70:13 - error ts(2554): Expected 0 arguments, but got 1.
1006
+
1007
+70 db.select({ count: sql<number>`count(*)` })
1008
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1009
+src/pages/admin/audit.astro:18:3 - warning ts(6133): 'ExternalLink' is declared but its value is never read.
1010
+
1011
+18 ExternalLink
1012
+   ~~~~~~~~~~~~
1013
+src/pages/admin/audit.astro:4:27 - warning ts(6133): 'eq' is declared but its value is never read.
1014
+
1015
+4 import { desc, sql, like, eq, or } from "drizzle-orm";
1016
+   ~~
1017
+
1018
+src/pages/admin/repositories.astro:45:28 - error ts(2339): Property 'count' does not exist on type '{ id: string; name: string; slug: string; description: string | null; ownerId: string; ownerType: string; visibility: string; defaultBranch: string; diskPath: string; sshCloneUrl: string | null; ... 23 more ...; updatedAt: string; }'.
1019
+
1020
+45 const total = totalResult?.count || 0;
1021
+   ~~~~~
1022
+src/pages/admin/repositories.astro:39:15 - error ts(2554): Expected 0 arguments, but got 1.
1023
+
1024
+39 db.select({ count: sql<number>`count(*)` })
1025
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1026
+src/pages/admin/repositories.astro:4:16 - warning ts(6133): 'eq' is declared but its value is never read.
1027
+
1028
+4 import { desc, eq, like, or, sql } from "drizzle-orm";
1029
+   ~~
1030
+
1031
+src/pages/admin/settings.astro:7:10 - error ts(2440): Import declaration conflicts with local declaration of 'Settings'.
1032
+
1033
+7 import { Settings, Save, Mail, Globe, Lock } from "lucide-react";
1034
+   ~~~~~~~~
1035
+src/pages/admin/settings.astro:169:17 - error ts(2339): Property 'disabled' does not exist on type 'HTMLElement'.
1036
+
1037
+169 btn.disabled = false;
1038
+   ~~~~~~~~
1039
+src/pages/admin/settings.astro:169:13 - error ts(18047): 'btn' is possibly 'null'.
1040
+
1041
+169 btn.disabled = false;
1042
+   ~~~
1043
+src/pages/admin/settings.astro:168:13 - error ts(18047): 'btn' is possibly 'null'.
1044
+
1045
+168 btn.textContent = original;
1046
+   ~~~
1047
+src/pages/admin/settings.astro:152:69 - error ts(2339): Property 'checked' does not exist on type 'HTMLElement'.
1048
+
1049
+152 data.allowSignups = document.getElementById('allowSignups').checked;
1050
+   ~~~~~~~
1051
+src/pages/admin/settings.astro:152:29 - error ts(2531): Object is possibly 'null'.
1052
+
1053
+152 data.allowSignups = document.getElementById('allowSignups').checked;
1054
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1055
+src/pages/admin/settings.astro:148:39 - error ts(2345): Argument of type 'EventTarget | null' is not assignable to parameter of type 'HTMLFormElement | undefined'.
1056
+ Type 'null' is not assignable to type 'HTMLFormElement | undefined'.
1057
+
1058
+148 const formData = new FormData(e.target);
1059
+   ~~~~~~~~
1060
+src/pages/admin/settings.astro:146:13 - error ts(2339): Property 'disabled' does not exist on type 'HTMLElement'.
1061
+
1062
+146 btn.disabled = true;
1063
+   ~~~~~~~~
1064
+src/pages/admin/settings.astro:146:9 - error ts(18047): 'btn' is possibly 'null'.
1065
+
1066
+146 btn.disabled = true;
1067
+   ~~~
1068
+src/pages/admin/settings.astro:145:9 - error ts(18047): 'btn' is possibly 'null'.
1069
+
1070
+145 btn.textContent = "Saving...";
1071
+   ~~~
1072
+src/pages/admin/settings.astro:144:26 - error ts(18047): 'btn' is possibly 'null'.
1073
+
1074
+144 const original = btn.textContent;
1075
+   ~~~
1076
+src/pages/admin/settings.astro:133:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1077
+
1078
+133 document.getElementById('smtpFrom').value = config.smtpFrom || '';
1079
+   ~~~~~
1080
+src/pages/admin/settings.astro:133:17 - error ts(2531): Object is possibly 'null'.
1081
+
1082
+133 document.getElementById('smtpFrom').value = config.smtpFrom || '';
1083
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1084
+src/pages/admin/settings.astro:132:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1085
+
1086
+132 document.getElementById('smtpUser').value = config.smtpUser || '';
1087
+   ~~~~~
1088
+src/pages/admin/settings.astro:132:17 - error ts(2531): Object is possibly 'null'.
1089
+
1090
+132 document.getElementById('smtpUser').value = config.smtpUser || '';
1091
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1092
+src/pages/admin/settings.astro:131:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1093
+
1094
+131 document.getElementById('smtpPort').value = config.smtpPort || '';
1095
+   ~~~~~
1096
+src/pages/admin/settings.astro:131:17 - error ts(2531): Object is possibly 'null'.
1097
+
1098
+131 document.getElementById('smtpPort').value = config.smtpPort || '';
1099
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1100
+src/pages/admin/settings.astro:130:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1101
+
1102
+130 document.getElementById('smtpHost').value = config.smtpHost || '';
1103
+   ~~~~~
1104
+src/pages/admin/settings.astro:130:17 - error ts(2531): Object is possibly 'null'.
1105
+
1106
+130 document.getElementById('smtpHost').value = config.smtpHost || '';
1107
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1108
+src/pages/admin/settings.astro:128:57 - error ts(2339): Property 'checked' does not exist on type 'HTMLElement'.
1109
+
1110
+128 document.getElementById('allowSignups').checked = !!config.allowSignups;
1111
+   ~~~~~~~
1112
+src/pages/admin/settings.astro:128:17 - error ts(2531): Object is possibly 'null'.
1113
+
1114
+128 document.getElementById('allowSignups').checked = !!config.allowSignups;
1115
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1116
+src/pages/admin/settings.astro:127:60 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1117
+
1118
+127 document.getElementById('siteDescription').value = config.siteDescription || '';
1119
+   ~~~~~
1120
+src/pages/admin/settings.astro:127:17 - error ts(2531): Object is possibly 'null'.
1121
+
1122
+127 document.getElementById('siteDescription').value = config.siteDescription || '';
1123
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1124
+src/pages/admin/settings.astro:126:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1125
+
1126
+126 document.getElementById('siteName').value = config.siteName || '';
1127
+   ~~~~~
1128
+src/pages/admin/settings.astro:126:17 - error ts(2531): Object is possibly 'null'.
1129
+
1130
+126 document.getElementById('siteName').value = config.siteName || '';
1131
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1132
+
1133
+src/pages/admin/users.astro:106:58 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1134
+
1135
+106 <p class="text-2xl font-bold">{adminUsers?.count || 0}</p>
1136
+   ~~~~~
1137
+src/pages/admin/users.astro:95:59 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1138
+
1139
+95 <p class="text-2xl font-bold">{activeUsers?.count || 0}</p>
1140
+   ~~~~~
1141
+src/pages/admin/users.astro:84:58 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1142
+
1143
+84 <p class="text-2xl font-bold">{totalUsers?.count || 0}</p>
1144
+   ~~~~~
1145
+src/pages/admin/users.astro:54:13 - error ts(2554): Expected 0 arguments, but got 1.
1146
+
1147
+54 db.select({ count: sql<number>`count(*)` }).from(schema.users).where(eq(schema.users.isAdmin, true)).get(),
1148
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1149
+src/pages/admin/users.astro:53:13 - error ts(2554): Expected 0 arguments, but got 1.
1150
+
1151
+53 db.select({ count: sql<number>`count(*)` }).from(schema.users).where(eq(schema.users.isActive, true)).get(),
1152
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1153
+src/pages/admin/users.astro:52:13 - error ts(2554): Expected 0 arguments, but got 1.
1154
+
1155
+52 db.select({ count: sql<number>`count(*)` }).from(schema.users).get(),
1156
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1157
+src/pages/admin/users.astro:47:28 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1158
+
1159
+47 const total = totalResult?.count || 0;
1160
+   ~~~~~
1161
+src/pages/admin/users.astro:41:13 - error ts(2554): Expected 0 arguments, but got 1.
1162
+
1163
+41 db.select({ count: sql<number>`count(*)` })
1164
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1165
+src/pages/admin/users.astro:8:10 - error ts(2440): Import declaration conflicts with local declaration of 'Users'.
1166
+
1167
+8 import { Users, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1168
+   ~~~~~
1169
+src/pages/admin/users.astro:277:28 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1170
+
1171
+277 const isActive = btn.dataset.isActive === 'true';
1172
+   ~~~~~~~
1173
+src/pages/admin/users.astro:276:26 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1174
+
1175
+276 const userId = btn.dataset.userId;
1176
+   ~~~~~~~
1177
+src/pages/admin/users.astro:254:27 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1178
+
1179
+254 const isAdmin = btn.dataset.isAdmin === 'true';
1180
+   ~~~~~~~
1181
+src/pages/admin/users.astro:253:26 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1182
+
1183
+253 const userId = btn.dataset.userId;
1184
+   ~~~~~~~
1185
+
1186
+src/pages/api/ai-review-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1187
+
1188
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1189
+   ~~~~~~
1190
+
1191
+src/pages/api/automation-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1192
+
1193
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1194
+   ~~~~~~
1195
+src/pages/api/automation-rules.ts:7:14 - warning ts(6133): 'and' is declared but its value is never read.
1196
+
1197
+7 import { eq, and } from "drizzle-orm";
1198
+   ~~~
1199
+
1200
+src/pages/api/inbox-sections.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1201
+
1202
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1203
+   ~~~~~~
1204
+
1205
+src/pages/api/search.ts:3:20 - warning ts(6133): 'eq' is declared but its value is never read.
1206
+
1207
+3 import { like, or, eq, desc } from 'drizzle-orm';
1208
+   ~~
1209
+
1210
+src/pages/api/actions/trigger-test.ts:10:1 - warning ts(6133): 'eq' is declared but its value is never read.
1211
+
1212
+10 import { eq } from "drizzle-orm";
1213
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1214
+src/pages/api/actions/trigger-test.ts:8:57 - warning ts(6133): 'notFound' is declared but its value is never read.
1215
+
1216
+8 import { success, unauthorized, serverError, parseBody, notFound } from '@/lib/api';
1217
+   ~~~~~~~~
1218
+
1219
+src/pages/api/realtime/events.ts:28:48 - warning ts(6133): 'request' is declared but its value is never read.
1220
+
1221
+28 export const POST: APIRoute = async ({ locals, request }) => {
1222
+   ~~~~~~~
1223
+
1224
+src/pages/api/repos/[owner]/[repo]/protection.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1225
+
1226
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1227
+   ~~~~~~~~~~
1228
+
1229
+src/pages/api/repos/[owner]/[repo]/git/push.ts:142:26 - warning ts(6133): 'sha' is declared but its value is never read.
1230
+
1231
+142 for (const { sha, ref } of bundleRefs) {
1232
+   ~~~
1233
+src/pages/api/repos/[owner]/[repo]/git/push.ts:22:22 - warning ts(6133): 'mkdirSync' is declared but its value is never read.
1234
+
1235
+22 import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "fs";
1236
+   ~~~~~~~~~
1237
+src/pages/api/repos/[owner]/[repo]/git/push.ts:18:5 - warning ts(6133): 'getDiskPath' is declared but its value is never read.
1238
+
1239
+18 getDiskPath,
1240
+   ~~~~~~~~~~~
1241
+src/pages/api/repos/[owner]/[repo]/git/push.ts:13:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
1242
+
1243
+13 import { getRepoPath } from "@/lib/utils";
1244
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1245
+
1246
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:30 - warning ts(6133): 'number' is declared but its value is never read.
1247
+
1248
+210 const { owner, repo, number, commentId } = params;
1249
+   ~~~~~~
1250
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:24 - warning ts(6133): 'repo' is declared but its value is never read.
1251
+
1252
+210 const { owner, repo, number, commentId } = params;
1253
+   ~~~~
1254
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:30 - warning ts(6133): 'number' is declared but its value is never read.
1255
+
1256
+163 const { owner, repo, number, commentId } = params;
1257
+   ~~~~~~
1258
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:24 - warning ts(6133): 'repo' is declared but its value is never read.
1259
+
1260
+163 const { owner, repo, number, commentId } = params;
1261
+   ~~~~
1262
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:99:24 - warning ts(6133): 'repo' is declared but its value is never read.
1263
+
1264
+99 const { owner, repo, number } = params;
1265
+   ~~~~
1266
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:37:24 - warning ts(6133): 'repo' is declared but its value is never read.
1267
+
1268
+37 const { owner, repo, number } = params;
1269
+   ~~~~
1270
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1271
+
1272
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1273
+   ~~~~~~~~~~
1274
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:7:25 - warning ts(6133): 'isNull' is declared but its value is never read.
1275
+
1276
+7 import { eq, and, desc, isNull } from "drizzle-orm";
1277
+   ~~~~~~
1278
+
1279
+src/pages/api/stacks/index.ts:26:6 - warning ts(6196): 'CreateStackInput' is declared but never used.
1280
+
1281
+26 type CreateStackInput = z.infer<typeof createStackSchema>;
1282
+   ~~~~~~~~~~~~~~~~
1283
+src/pages/api/stacks/index.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1284
+
1285
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1286
+   ~~~~~~~~~~
1287
+
1288
+src/pages/api/user/notification-preferences.ts:12:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1289
+
1290
+12 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1291
+   ~~~~~~
1292
+
1293
+src/pages/api/user/tokens.ts:103:24 - warning ts(6133): 'prefix' is declared but its value is never read.
1294
+
1295
+103 const { token, prefix } = generateToken();
1296
+   ~~~~~~
1297
+src/pages/api/user/tokens.ts:79:34 - warning ts(6133): 'scopes' is declared but its value is never read.
1298
+
1299
+79 const { name, expiresIn, scopes } = parsed.data;
1300
+   ~~~~~~
1301
+src/pages/api/user/tokens.ts:26:10 - warning ts(6133): 'hashToken' is declared but its value is never read.
1302
+
1303
+26 function hashToken(token: string): string {
1304
+   ~~~~~~~~~
1305
+src/pages/api/user/tokens.ts:8:23 - warning ts(6133): 'schema' is declared but its value is never read.
1306
+
1307
+8 import { getDatabase, schema } from "@/db";
1308
+   ~~~~~~
1309
+
1310
+src/pages/settings/ai-review-rules.astro:35:38 - error ts(2353): Object literal may only specify known properties, and 'fullName' does not exist in type '{ id?: boolean | undefined; name?: boolean | undefined; slug?: boolean | undefined; description?: boolean | undefined; ownerId?: boolean | undefined; ownerType?: boolean | undefined; ... 27 more ...; updatedAt?: boolean | undefined; }'.
1311
+
1312
+35 columns: { id: true, name: true, fullName: true },
1313
+   ~~~~~~~~
1314
+src/pages/settings/ai-review-rules.astro:19:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
1315
+
1316
+19 CheckCircle2,
1317
+   ~~~~~~~~~~~~
1318
+src/pages/settings/ai-review-rules.astro:4:14 - warning ts(6133): 'and' is declared but its value is never read.
1319
+
1320
+4 import { eq, and, desc } from "drizzle-orm";
1321
+   ~~~
1322
+src/pages/settings/ai-review-rules.astro:469:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1323
+
1324
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1325
+
1326
+Add the `is:inline` directive explicitly to silence this hint.
1327
+
1328
+469 <script define:vars={{ repoId }}>
1329
+   ~~~~~~~~~~~
1330
+
1331
+src/pages/settings/automations.astro:301:61 - warning ts(6133): 'i' is declared but its value is never read.
1332
+
1333
+301 {actions.slice(0, 3).map((action, i) => (
1334
+   ~
1335
+src/pages/settings/automations.astro:437:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1336
+
1337
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1338
+
1339
+Add the `is:inline` directive explicitly to silence this hint.
1340
+
1341
+437 <script define:vars={{ repoId }}>
1342
+   ~~~~~~~~~~~
1343
+
1344
+Result (300 files):
1345
+- 67 errors
1346
+- 0 warnings
1347
+- 224 hints
1348
+
0
1349
▼lint_output_2.txt
+1308-0
1
+
2
3
+> astro check
4
+
5
+14:18:14 [types] Generated 33ms
6
+14:18:14 [check] Getting diagnostics for Astro files in /home/swadhin/owngit/OpenCodeHub...
7
+src/components/admin/AdminDashboard.tsx:141:30 - warning ts(6385): 'Github' is deprecated.
8
+
9
+141 <Github className="h-8 w-8 text-white opacity-30 hover:opacity-70 transition-opacity cursor-pointer" />
10
+   ~~~~~~
11
+src/components/admin/AdminDashboard.tsx:10:10 - warning ts(6385): 'Github' is deprecated.
12
+
13
+10 import { Github } from "lucide-react";
14
+   ~~~~~~
15
+
16
+src/components/admin/AlertBanner.tsx:2:44 - warning ts(6133): 'Bell' is declared but its value is never read.
17
+
18
+2 import { AlertTriangle, CheckCircle, Info, Bell, X } from "lucide-react";
19
+   ~~~~
20
+
21
+src/components/admin/DashboardStats.tsx:1:45 - warning ts(6133): 'useTransform' is declared but its value is never read.
22
+
23
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
24
+   ~~~~~~~~~~~~
25
+src/components/admin/DashboardStats.tsx:1:34 - warning ts(6133): 'useSpring' is declared but its value is never read.
26
+
27
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
28
+   ~~~~~~~~~
29
+src/components/admin/DashboardStats.tsx:1:18 - warning ts(6133): 'useMotionValue' is declared but its value is never read.
30
+
31
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
32
+   ~~~~~~~~~~~~~~
33
+
34
+src/components/admin/GlobeViz.tsx:199:27 - warning ts(6133): 'activities' is declared but its value is never read.
35
+
36
+199 function CSSGlobeFallback({ activities = [] }: Props) {
37
+   ~~~~~~~~~~~~~~~~~~~
38
+src/components/admin/GlobeViz.tsx:89:54 - warning ts(6133): 'i' is declared but its value is never read.
39
+
40
+89 markers: activities.slice(0, 20).map((_, i) => ({
41
+   ~
42
+
43
+src/components/admin/QuickStatsRow.tsx:2:78 - warning ts(6133): 'Zap' is declared but its value is never read.
44
+
45
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
46
+   ~~~
47
+src/components/admin/QuickStatsRow.tsx:2:68 - warning ts(6133): 'Activity' is declared but its value is never read.
48
+
49
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
50
+   ~~~~~~~~
51
+src/components/admin/QuickStatsRow.tsx:2:49 - warning ts(6133): 'Clock' is declared but its value is never read.
52
+
53
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
54
+   ~~~~~
55
+
56
+src/components/admin/SystemStatus.tsx:18:5 - warning ts(6133): 'color' is declared but its value is never read.
57
+
58
+18 color,
59
+   ~~~~~
60
+src/components/admin/SystemStatus.tsx:1:47 - warning ts(6133): 'Server' is declared but its value is never read.
61
+
62
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
63
+   ~~~~~~
64
+src/components/admin/SystemStatus.tsx:1:41 - warning ts(6133): 'Wifi' is declared but its value is never read.
65
+
66
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
67
+   ~~~~
68
+
69
+src/components/dashboard/ActivityStream.tsx:80:55 - warning ts(6133): 'i' is declared but its value is never read.
70
+
71
+80 {users.slice(0, 5).map((user, i) => (
72
+   ~
73
+src/components/dashboard/ActivityStream.tsx:2:1 - warning ts(6133): 'React' is declared but its value is never read.
74
+
75
+2 import * as React from "react";
76
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
+
78
+src/components/git/CommitGraph.tsx:209:35 - warning ts(6133): 'index' is declared but its value is never read.
79
+
80
+209 {commits.map((commit, index) => {
81
+   ~~~~~
82
+src/components/git/CommitGraph.tsx:51:11 - warning ts(6133): 'branchHeads' is declared but its value is never read.
83
+
84
+51 const branchHeads: Map<string, string> = new Map()
85
+   ~~~~~~~~~~~
86
+
87
+src/components/home/HeroSection.tsx:87:26 - warning ts(6385): 'Github' is deprecated.
88
+
89
+87 <Github className="h-4 w-4" />
90
+   ~~~~~~
91
+src/components/home/HeroSection.tsx:6:22 - warning ts(6385): 'Github' is deprecated.
92
+
93
+6 import { ArrowRight, Github, Star, GitBranch, Zap } from "lucide-react";
94
+   ~~~~~~
95
+src/components/home/HeroSection.tsx:4:1 - warning ts(6133): 'ColourfulText' is declared but its value is never read.
96
+
97
+4 import { ColourfulText } from "@/components/ui/colourful-text";
98
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
+
100
+src/components/issues/IssueDetail.tsx:68:67 - warning ts(6133): 'repoName' is declared but its value is never read.
101
+
102
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
103
+   ~~~~~~~~
104
+src/components/issues/IssueDetail.tsx:68:56 - warning ts(6133): 'repoOwner' is declared but its value is never read.
105
+
106
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
107
+   ~~~~~~~~~
108
+
109
+src/components/issues/IssuesList.tsx:14:5 - warning ts(6133): 'Filter' is declared but its value is never read.
110
+
111
+14 Filter
112
+   ~~~~~~
113
+
114
+src/components/layout/Header.astro:2:10 - warning ts(6133): 'GitBranch' is declared but its value is never read.
115
+
116
+2 import { GitBranch, Search, Bell, Plus, Menu } from "lucide-react"
117
+   ~~~~~~~~~
118
+
119
+src/components/pr/AIReviewPanel.tsx:76:5 - warning ts(6133): 'reviewId' is declared but its value is never read.
120
+
121
+76 reviewId,
122
+   ~~~~~~~~
123
+src/components/pr/AIReviewPanel.tsx:6:8 - warning ts(6133): 'React' is declared but its value is never read.
124
+
125
+6 import React, { useState } from "react";
126
+   ~~~~~
127
+
128
+src/components/pr/StackVisualization.tsx:52:5 - warning ts(6133): 'onReorder' is declared but its value is never read.
129
+
130
+52 onReorder,
131
+   ~~~~~~~~~
132
+src/components/pr/StackVisualization.tsx:45:5 - warning ts(6133): 'stackId' is declared but its value is never read.
133
+
134
+45 stackId,
135
+   ~~~~~~~
136
+
137
+src/components/pulls/PullRequestsList.tsx:14:5 - warning ts(6133): 'Sparkles' is declared but its value is never read.
138
+
139
+14 Sparkles,
140
+   ~~~~~~~~
141
+
142
+src/components/repo/FileExplorer.astro:2:20 - warning ts(6133): 'Folder' is declared but its value is never read.
143
+
144
+2 import { FileText, Folder } from "lucide-react";
145
+   ~~~~~~
146
+
147
+src/components/repo/RepoHeader.astro:3:3 - warning ts(6133): 'GitBranch' is declared but its value is never read.
148
+
149
+3 GitBranch,
150
+   ~~~~~~~~~
151
+
152
+src/components/search/GlobalSearch.tsx:17:12 - warning ts(6133): 'loading' is declared but its value is never read.
153
+
154
+17 const [loading, setLoading] = React.useState(false);
155
+   ~~~~~~~
156
+src/components/search/GlobalSearch.tsx:11:18 - warning ts(6133): 'FileText' is declared but its value is never read.
157
+
158
+11 import { Search, FileText, User, GitBranch, GitPullRequest, CircleDot, Workflow } from "lucide-react";
159
+   ~~~~~~~~
160
+
161
+src/components/ui/animated-tooltip.tsx:4:8 - warning ts(6133): 'React' is declared but its value is never read.
162
+
163
+4 import React, { useState } from "react";
164
+   ~~~~~
165
+src/components/ui/animated-tooltip.tsx:2:1 - warning ts(6133): 'cn' is declared but its value is never read.
166
+
167
+2 import { cn } from "@/lib/cn";
168
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
+
170
+src/components/ui/text-generate-effect.tsx:2:29 - warning ts(6133): 'useState' is declared but its value is never read.
171
+
172
+2 import { useEffect, useRef, useState } from "react";
173
+   ~~~~~~~~
174
+src/components/ui/text-generate-effect.tsx:2:21 - warning ts(6133): 'useRef' is declared but its value is never read.
175
+
176
+2 import { useEffect, useRef, useState } from "react";
177
+   ~~~~~~
178
+
179
+src/components/ui/text-reveal-card.tsx:3:29 - warning ts(6133): 'useTransform' is declared but its value is never read.
180
+
181
+3 import { motion, useScroll, useTransform } from "framer-motion";
182
+   ~~~~~~~~~~~~
183
+src/components/ui/text-reveal-card.tsx:3:18 - warning ts(6133): 'useScroll' is declared but its value is never read.
184
+
185
+3 import { motion, useScroll, useTransform } from "framer-motion";
186
+   ~~~~~~~~~
187
+
188
+src/db/seed-activity.ts:6:1 - warning ts(6133): 'eq' is declared but its value is never read.
189
+
190
+6 import { eq } from "drizzle-orm";
191
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
+src/db/seed-activity.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
193
+
194
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
195
+   ~~~~~
196
+src/db/seed-activity.ts:3:10 - warning ts(6133): 'repositories' is declared but its value is never read.
197
+
198
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
199
+   ~~~~~~~~~~~~
200
+
201
+src/db/seed-notifications.ts:5:32 - warning ts(6133): 'repositories' is declared but its value is never read.
202
+
203
+5 import { notifications, users, repositories } from "@/db/schema";
204
+   ~~~~~~~~~~~~
205
+src/db/seed-notifications.ts:5:25 - warning ts(6133): 'users' is declared but its value is never read.
206
+
207
+5 import { notifications, users, repositories } from "@/db/schema";
208
+   ~~~~~
209
+
210
+src/db/seed-scale.ts:25:11 - warning ts(6133): 'reposPath' is declared but its value is never read.
211
+
212
+25 const reposPath = process.env.GIT_REPOS_PATH || "./data/repos";
213
+   ~~~~~~~~~
214
+src/db/seed-scale.ts:9:1 - warning ts(6133): 'fs' is declared but its value is never read.
215
+
216
+9 import fs from "fs/promises";
217
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
+src/db/seed-scale.ts:7:1 - warning ts(6133): 'eq' is declared but its value is never read.
219
+
220
+7 import { eq } from "drizzle-orm";
221
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222
+src/db/seed-scale.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
223
+
224
+3 import { repositories, users } from "@/db/schema";
225
+   ~~~~~
226
+
227
+src/db/schema/developer-metrics.ts:7:19 - warning ts(6133): 'real' is declared but its value is never read.
228
+
229
+7 import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
230
+   ~~~~
231
+
232
+src/db/schema/pipeline-runners.ts:3:10 - warning ts(6133): 'integer' is declared but its value is never read.
233
+
234
+3 import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
235
+   ~~~~~~~
236
+
237
+src/db/schema/pull-requests.ts:8:18 - warning ts(6133): 'milestones' is declared but its value is never read.
238
+
239
+8 import { labels, milestones } from "./issues";
240
+   ~~~~~~~~~~
241
+
242
+src/db/schema/security.ts:3:1 - warning ts(6133): 'users' is declared but its value is never read.
243
+
244
+3 import { users } from "./users";
245
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246
+
247
+src/lib/ai-review.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
248
+
249
+6 import { eq, and, desc } from "drizzle-orm";
250
+   ~~~
251
+
252
+src/lib/analysis.ts:35:87 - warning ts(6133): 'force' is declared but its value is never read.
253
+
254
+35 export async function analyzeRepository(repoId: string, userId: string | null = null, force = false) {
255
+   ~~~~~
256
+src/lib/analysis.ts:4:22 - warning ts(6133): 'getRepoSize' is declared but its value is never read.
257
+
258
+4 import { getCommits, getRepoSize, listFiles, getCommitDiff } from "./git";
259
+   ~~~~~~~~~~~
260
+
261
+src/lib/auth.ts:281:22 - warning ts(6133): 'gt' is declared but its value is never read.
262
+
263
+281 const { eq, and, gt } = await import("drizzle-orm");
264
+   ~~
265
+src/lib/auth.ts:281:17 - warning ts(6133): 'and' is declared but its value is never read.
266
+
267
+281 const { eq, and, gt } = await import("drizzle-orm");
268
+   ~~~
269
+src/lib/auth.ts:280:35 - warning ts(6133): 'users' is declared but its value is never read.
270
+
271
+280 const { personalAccessTokens, users } = await import("@/db/schema/users");
272
+   ~~~~~
273
+
274
+src/lib/automations.ts:320:23 - warning ts(6133): 'notifyPrEvent' is declared but its value is never read.
275
+
276
+320 const { notifyPrEvent } = await import("./slack-notifications");
277
+   ~~~~~~~~~~~~~~~~~
278
+
279
+src/lib/conflict-automation.ts:11:1 - warning ts(6192): All imports in import declaration are unused.
280
+
281
+11 import { notifyPrEvent, notifyUserDm } from "./slack-notifications";
282
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283
+src/lib/conflict-automation.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
284
+
285
+6 import { eq, and } from "drizzle-orm";
286
+   ~~~
287
+
288
+src/lib/developer-metrics.ts:6:35 - warning ts(6133): 'lte' is declared but its value is never read.
289
+
290
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
291
+   ~~~
292
+src/lib/developer-metrics.ts:6:30 - warning ts(6133): 'gte' is declared but its value is never read.
293
+
294
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
295
+   ~~~
296
+src/lib/developer-metrics.ts:6:25 - warning ts(6133): 'sql' is declared but its value is never read.
297
+
298
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
299
+   ~~~
300
+
301
+src/lib/git-storage.ts:15:27 - warning ts(6133): 'StorageAdapter' is declared but its value is never read.
302
+
303
+15 import { getStorage, type StorageAdapter } from "./storage";
304
+   ~~~~~~~~~~~~~~
305
+src/lib/git-storage.ts:14:1 - warning ts(6133): 'Readable' is declared but its value is never read.
306
+
307
+14 import { Readable } from "stream";
308
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309
+src/lib/git-storage.ts:10:54 - warning ts(6133): 'statSync' is declared but its value is never read.
310
+
311
+10 import { existsSync, mkdirSync, rmSync, readdirSync, statSync } from "fs";
312
+   ~~~~~~~~
313
+
314
+src/lib/git.ts:1171:32 - warning ts(6133): 'reject' is declared but its value is never read.
315
+
316
+1171 return new Promise((resolve, reject) => {
317
+   ~~~~~~
318
+src/lib/git.ts:14:3 - warning ts(6133): 'releaseRepo' is declared but its value is never read.
319
+
320
+14 releaseRepo,
321
+   ~~~~~~~~~~~
322
+src/lib/git.ts:13:3 - warning ts(6133): 'acquireRepo' is declared but its value is never read.
323
+
324
+13 acquireRepo,
325
+   ~~~~~~~~~~~
326
+
327
+src/lib/lfs.ts:64:3 - warning ts(6133): 'repoDiskPath' is declared but its value is never read.
328
+
329
+64 repoDiskPath: string,
330
+   ~~~~~~~~~~~~
331
+
332
+src/lib/merge-queue.ts:11:1 - warning ts(6133): 'emitQueueEvent' is declared but its value is never read.
333
+
334
+11 import { emitQueueEvent } from "./realtime";
335
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336
+src/lib/merge-queue.ts:6:34 - warning ts(6133): 'gt' is declared but its value is never read.
337
+
338
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
339
+   ~~
340
+src/lib/merge-queue.ts:6:30 - warning ts(6133): 'lt' is declared but its value is never read.
341
+
342
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
343
+   ~~
344
+
345
+src/lib/pipeline.ts:292:15 - warning ts(6133): 'tag' is declared but its value is never read.
346
+
347
+292 const tag = payload.ref.replace("refs/tags/", "");
348
+   ~~~
349
+src/lib/pipeline.ts:238:11 - warning ts(6133): 'artifactsDir' is declared but its value is never read.
350
+
351
+238 private artifactsDir: string;
352
+   ~~~~~~~~~~~~
353
+src/lib/pipeline.ts:237:11 - warning ts(6133): 'workDir' is declared but its value is never read.
354
+
355
+237 private workDir: string;
356
+   ~~~~~~~
357
+
358
+src/lib/realtime.ts:49:61 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
359
+
360
+49 return `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
361
+   ~~~~~~
362
+
363
+src/lib/security.ts:116:15 - warning ts(6133): 'rawOutput' is declared but its value is never read.
364
+
365
+116 const rawOutput = logsBuffer.toString("utf-8");
366
+   ~~~~~~~~~
367
+src/lib/security.ts:76:15 - warning ts(6133): 'stream' is declared but its value is never read.
368
+
369
+76 const stream = await container.logs({ follow: true, stdout: true, stderr: true });
370
+   ~~~~~~
371
+src/lib/security.ts:56:15 - warning ts(6133): 'chunks' is declared but its value is never read.
372
+
373
+56 const chunks: Buffer[] = [];
374
+   ~~~~~~
375
+src/lib/security.ts:48:41 - warning ts(6133): 'event' is declared but its value is never read.
376
+
377
+48 function onProgress(event: any) { }
378
+   ~~~~~
379
+src/lib/security.ts:44:51 - warning ts(6133): 'output' is declared but its value is never read.
380
+
381
+44 function onFinished(err: any, output: any) {
382
+   ~~~~~~
383
+src/lib/security.ts:40:41 - warning ts(6133): 'reject' is declared but its value is never read.
384
+
385
+40 await new Promise((resolve, reject) => {
386
+   ~~~~~~
387
+src/lib/security.ts:15:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
388
+
389
+15 repositoryId: string
390
+   ~~~~~~~~~~~~
391
+src/lib/security.ts:5:21 - warning ts(6133): 'writeFile' is declared but its value is never read.
392
+
393
+5 import { mkdir, rm, writeFile } from "fs/promises";
394
+   ~~~~~~~~~
395
+
396
+src/lib/slack-notifications.ts:257:5 - warning ts(6133): 'event' is declared but its value is never read.
397
+
398
+257 event: string,
399
+   ~~~~~
400
+
401
+src/lib/ssh.ts:190:32 - warning ts(6133): 'accept' is declared but its value is never read.
402
+
403
+190 session.on("shell", (accept, reject) => {
404
+   ~~~~~~
405
+src/lib/ssh.ts:78:39 - warning ts(6133): 'reject' is declared but its value is never read.
406
+
407
+78 client.on("session", (accept, reject) => {
408
+   ~~~~~~
409
+src/lib/ssh.ts:37:5 - warning ts(6133): 'port' is declared but its value is never read.
410
+
411
+37 port,
412
+   ~~~~
413
+
414
+src/lib/storage.ts:1196:9 - warning ts(6133): 'eq' is declared but its value is never read.
415
+
416
+1196 const { eq } = await import("drizzle-orm");
417
+   ~~~~~~
418
+src/lib/storage.ts:1098:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
419
+
420
+1098 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
421
+   ~~~~~~~~~
422
+src/lib/storage.ts:1084:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
423
+
424
+1084 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
425
+   ~~~~~~~~~
426
+src/lib/storage.ts:971:30 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
427
+
428
+971 const chunk = buffer.slice(i, Math.min(i + chunkSize, buffer.length));
429
+   ~~~~~
430
+src/lib/storage.ts:875:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
431
+
432
+875 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
433
+   ~~~~~~~~~
434
+src/lib/storage.ts:868:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
435
+
436
+868 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
437
+   ~~~~~~~~~
438
+src/lib/storage.ts:798:21 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
439
+
440
+798 return buffer.slice(options.range.start, options.range.end + 1);
441
+   ~~~~~
442
+src/lib/storage.ts:660:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
443
+
444
+660 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
445
+   ~~~~~~~~~
446
+src/lib/storage.ts:649:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
447
+
448
+649 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
449
+   ~~~~~~~~~
450
+src/lib/storage.ts:539:51 - warning ts(6133): 'options' is declared but its value is never read.
451
+
452
+539 async put(key: string, data: Buffer | Readable, options?: PutOptions): Promise<void> {
453
+   ~~~~~~~
454
+src/lib/storage.ts:274:5 - warning ts(6133): 'expiresIn' is declared but its value is never read.
455
+
456
+274 expiresIn: number = 3600
457
+   ~~~~~~~~~
458
+
459
+src/lib/sync.ts:361:23 - warning ts(6133): 'baseHead' is declared but its value is never read.
460
+
461
+361 const baseHead = await git.revparse([baseBranch]);
462
+   ~~~~~~~~
463
+src/lib/sync.ts:360:23 - warning ts(6133): 'mergeBase' is declared but its value is never read.
464
+
465
+360 const mergeBase = await git.raw(["merge-base", baseBranch, branchName]);
466
+   ~~~~~~~~~
467
+src/lib/sync.ts:267:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
468
+
469
+267 repositoryId: string,
470
+   ~~~~~~~~~~~~
471
+src/lib/sync.ts:57:15 - warning ts(6133): 'currentBranch' is declared but its value is never read.
472
+
473
+57 const currentBranch = status.current;
474
+   ~~~~~~~~~~~~~
475
+src/lib/sync.ts:10:1 - warning ts(6133): 'generateId' is declared but its value is never read.
476
+
477
+10 import { generateId } from "./utils";
478
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479
+src/lib/sync.ts:9:20 - warning ts(6133): 'getStackForPr' is declared but its value is never read.
480
+
481
+9 import { getStack, getStackForPr, addToStack, createStack } from "./stacks";
482
+   ~~~~~~~~~~~~~
483
+src/lib/sync.ts:6:19 - warning ts(6133): 'desc' is declared but its value is never read.
484
+
485
+6 import { eq, and, desc } from "drizzle-orm";
486
+   ~~~~
487
+
488
+src/lib/workflows.ts:26:92 - warning ts(6133): 'pusherId' is declared but its value is never read.
489
+
490
+26 export async function triggerRepoWorkflows(repoId: string, commitSha: string, ref: string, pusherId: string) {
491
+   ~~~~~~~~
492
+src/lib/workflows.ts:8:1 - warning ts(6133): 'existsSync' is declared but its value is never read.
493
+
494
+8 import { existsSync } from "fs";
495
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496
+
497
+src/pages/cli.astro:5:5 - warning ts(6133): 'Cpu' is declared but its value is never read.
498
+
499
+5 Cpu,
500
+   ~~~
501
+
502
+src/pages/explore.astro:4:20 - warning ts(6133): 'sql' is declared but its value is never read.
503
+
504
+4 import { desc, eq, sql, count } from "drizzle-orm";
505
+   ~~~
506
+
507
+src/pages/inbox.astro:28:5 - warning ts(6133): 'title' is declared but its value is never read.
508
+
509
+28 let title = "Inbox";
510
+   ~~~~~
511
+src/pages/inbox.astro:15:3 - warning ts(6133): 'Bot' is declared but its value is never read.
512
+
513
+15 Bot,
514
+   ~~~
515
+src/pages/inbox.astro:13:3 - warning ts(6133): 'Search' is declared but its value is never read.
516
+
517
+13 Search,
518
+   ~~~~~~
519
+src/pages/inbox.astro:5:29 - warning ts(6133): 'ne' is declared but its value is never read.
520
+
521
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
522
+   ~~
523
+src/pages/inbox.astro:5:25 - warning ts(6133): 'or' is declared but its value is never read.
524
+
525
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
526
+   ~~
527
+
528
+src/pages/insights.astro:11:3 - warning ts(6133): 'Calendar' is declared but its value is never read.
529
+
530
+11 Calendar,
531
+   ~~~~~~~~
532
+src/pages/insights.astro:4:30 - warning ts(6133): 'sql' is declared but its value is never read.
533
+
534
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
535
+   ~~~
536
+src/pages/insights.astro:4:14 - warning ts(6133): 'desc' is declared but its value is never read.
537
+
538
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
539
+   ~~~~
540
+
541
+src/pages/issues.astro:7:7 - warning ts(6133): 'currentUser' is declared but its value is never read.
542
+
543
+7 const currentUser = Astro.locals.user;
544
+   ~~~~~~~~~~~
545
+src/pages/issues.astro:4:25 - warning ts(6133): 'sql' is declared but its value is never read.
546
+
547
+4 import { desc, eq, and, sql } from "drizzle-orm";
548
+   ~~~
549
+src/pages/issues.astro:4:20 - warning ts(6133): 'and' is declared but its value is never read.
550
+
551
+4 import { desc, eq, and, sql } from "drizzle-orm";
552
+   ~~~
553
+
554
+src/pages/merge-queue.astro:353:56 - warning ts(6133): 'index' is declared but its value is never read.
555
+
556
+353 {queueItems.map((item, index) => {
557
+   ~~~~~
558
+src/pages/merge-queue.astro:222:10 - warning ts(6133): 'timeAgo' is declared but its value is never read.
559
+
560
+222 function timeAgo(date: string) {
561
+   ~~~~~~~
562
+src/pages/merge-queue.astro:73:5 - warning ts(6133): 'lastProcessedAt' is declared but its value is never read.
563
+
564
+73 let lastProcessedAt: string | null = null;
565
+   ~~~~~~~~~~~~~~~
566
+
567
+src/pages/password-reset.astro:95:13 - warning ts(6133): 'response' is declared but its value is never read.
568
+
569
+95 const response = await fetch("/api/auth/password-reset", {
570
+   ~~~~~~~~
571
+
572
+src/pages/repositories.astro:14:53 - warning ts(6133): 'Globe' is declared but its value is never read.
573
+
574
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
575
+   ~~~~~
576
+src/pages/repositories.astro:14:47 - warning ts(6133): 'Lock' is declared but its value is never read.
577
+
578
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
579
+   ~~~~
580
+src/pages/repositories.astro:5:1 - warning ts(6192): All imports in import declaration are unused.
581
+
582
+ 5 import {
583
+  ~~~~~~~~
584
+ 6 Card,
585
+  ~~~~~~~~
586
+...
587
+ 10 CardContent,
588
+  ~~~~~~~~~~~~~~~
589
+ 11 } from "@/components/ui/card";
590
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
591
+
592
+src/pages/stars.astro:152:54 - warning ts(6385): 'event' is deprecated.
593
+
594
+152 onclick="event.preventDefault(); event.stopPropagation();"
595
+   ~~~~~
596
+src/pages/stars.astro:152:30 - warning ts(6385): 'event' is deprecated.
597
+
598
+152 onclick="event.preventDefault(); event.stopPropagation();"
599
+   ~~~~~
600
+
601
+src/pages/[owner]/[repo]/index.astro:15:19 - warning ts(6133): 'sql' is declared but its value is never read.
602
+
603
+15 import { eq, and, sql, count } from "drizzle-orm";
604
+   ~~~
605
+src/pages/[owner]/[repo]/index.astro:12:3 - warning ts(6133): 'Clock' is declared but its value is never read.
606
+
607
+12 Clock,
608
+   ~~~~~
609
+src/pages/[owner]/[repo]/index.astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
610
+
611
+6 Tag,
612
+   ~~~
613
+
614
+src/pages/[owner]/[repo]/labels.astro:245:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
615
+
616
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
617
+
618
+Add the `is:inline` directive explicitly to silence this hint.
619
+
620
+245 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
621
+   ~~~~~~~~~~~
622
+
623
+src/pages/[owner]/[repo]/merge-queue.astro:248:57 - warning ts(6133): 'i' is declared but its value is never read.
624
+
625
+248 {item.stack.entries.map((entry, i) => (
626
+   ~
627
+src/pages/[owner]/[repo]/merge-queue.astro:13:3 - warning ts(6133): 'Play' is declared but its value is never read.
628
+
629
+13 Play,
630
+   ~~~~
631
+src/pages/[owner]/[repo]/merge-queue.astro:8:19 - warning ts(6133): 'sql' is declared but its value is never read.
632
+
633
+8 import { and, eq, sql, count } from "drizzle-orm";
634
+   ~~~
635
+
636
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:18:3 - warning ts(6133): 'Monitor' is declared but its value is never read.
637
+
638
+18 Monitor,
639
+   ~~~~~~~
640
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:13:3 - warning ts(6133): 'FileText' is declared but its value is never read.
641
+
642
+13 FileText,
643
+   ~~~~~~~~
644
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:337:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
645
+
646
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
647
+
648
+Add the `is:inline` directive explicitly to silence this hint.
649
+
650
+337 <script define:vars={{ initialContent: !fileData.isBinary ? fileData.content : "" }}>
651
+   ~~~~~~~~~~~
652
+
653
+src/pages/[owner]/[repo]/branches/index.astro:16:3 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
654
+
655
+16 AlertCircle,
656
+   ~~~~~~~~~~~
657
+src/pages/[owner]/[repo]/branches/index.astro:15:3 - warning ts(6133): 'Search' is declared but its value is never read.
658
+
659
+15 Search,
660
+   ~~~~~~
661
+src/pages/[owner]/[repo]/branches/index.astro:13:3 - warning ts(6133): 'MoreHorizontal' is declared but its value is never read.
662
+
663
+13 MoreHorizontal,
664
+   ~~~~~~~~~~~~~~
665
+src/pages/[owner]/[repo]/branches/index.astro:9:19 - warning ts(6133): 'sql' is declared but its value is never read.
666
+
667
+9 import { and, eq, sql, count } from "drizzle-orm";
668
+   ~~~
669
+src/pages/[owner]/[repo]/branches/index.astro:8:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
670
+
671
+8 import { getRepoPath } from "@/lib/utils";
672
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
673
+src/pages/[owner]/[repo]/branches/index.astro:351:42 - warning ts(6133): 'e' is declared but its value is never read.
674
+
675
+351 btn.addEventListener("click", async (e: any) => {
676
+   ~
677
+
678
+src/pages/[owner]/[repo]/commits/[...ref].astro:9:1 - warning ts(6133): 'Button' is declared but its value is never read.
679
+
680
+9 import { Button } from "@/components/ui/button";
681
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
682
+
683
+src/pages/[owner]/[repo]/edit/[...ref].astro:108:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
684
+
685
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
686
+
687
+Add the `is:inline` directive explicitly to silence this hint.
688
+
689
+108 <script define:vars={{ initialContent: fileContent, repoId: repo.id, branch: currentBranch, path: filePath, owner: repo.owner, repoName: repo.name }}>
690
+   ~~~~~~~~~~~
691
+
692
+src/pages/[owner]/[repo]/insights/index.astro:75:41 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
693
+
694
+75 repo.openIssueCount = issueCountResult?.count || 0;
695
+   ~~~~~
696
+src/pages/[owner]/[repo]/insights/index.astro:65:13 - error ts(2554): Expected 0 arguments, but got 1.
697
+
698
+65 .select({ count: sql<number>`count(*)` })
699
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700
+src/pages/[owner]/[repo]/insights/index.astro:276:69 - warning ts(6133): 'i' is declared but its value is never read.
701
+
702
+276 {contributors.map((contributor, i) => (
703
+   ~
704
+src/pages/[owner]/[repo]/insights/index.astro:84:7 - warning ts(6133): 'recentCommits' is declared but its value is never read.
705
+
706
+84 const recentCommits = await getCommits(repoData.diskPath, { limit: 20 });
707
+   ~~~~~~~~~~~~~
708
+src/pages/[owner]/[repo]/insights/index.astro:9:5 - warning ts(6133): 'GitCommit' is declared but its value is never read.
709
+
710
+9 GitCommit,
711
+   ~~~~~~~~~
712
+src/pages/[owner]/[repo]/insights/index.astro:5:24 - warning ts(6133): 'desc' is declared but its value is never read.
713
+
714
+5 import { eq, and, sql, desc, gte, count } from "drizzle-orm";
715
+   ~~~~
716
+
717
+src/pages/[owner]/[repo]/pulls/[number].astro:100:11 - error ts(2554): Expected 0 arguments, but got 1.
718
+
719
+100 .select({ count: sql<number>`count(*)` })
720
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
721
+src/pages/[owner]/[repo]/pulls/[number].astro:359:50 - warning ts(6133): 'i' is declared but its value is never read.
722
+
723
+359 {stackInfo.entries.map((entry, i) => {
724
+   ~
725
+src/pages/[owner]/[repo]/pulls/[number].astro:136:5 - warning ts(6133): 'mergeError' is declared but its value is never read.
726
+
727
+136 let mergeError = "";
728
+   ~~~~~~~~~~
729
+src/pages/[owner]/[repo]/pulls/[number].astro:24:3 - warning ts(6133): 'ChevronRight' is declared but its value is never read.
730
+
731
+24 ChevronRight,
732
+   ~~~~~~~~~~~~
733
+src/pages/[owner]/[repo]/pulls/[number].astro:16:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
734
+
735
+16 CheckCircle2,
736
+   ~~~~~~~~~~~~
737
+src/pages/[owner]/[repo]/pulls/[number].astro:13:29 - warning ts(6133): 'count' is declared but its value is never read.
738
+
739
+13 import { and, eq, sql, asc, count } from "drizzle-orm";
740
+   ~~~~~
741
+src/pages/[owner]/[repo]/pulls/[number].astro:419:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
742
+
743
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
744
+
745
+Add the `is:inline` directive explicitly to silence this hint.
746
+
747
+419 define:vars={{
748
+   ~~~~~~~~~~~
749
+
750
+src/pages/[owner]/[repo]/pulls/index.astro:41:11 - error ts(2554): Expected 0 arguments, but got 1.
751
+
752
+41 .select({ count: sql<number>`count(*)` })
753
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
754
+src/pages/[owner]/[repo]/pulls/index.astro:7:30 - warning ts(6133): 'count' is declared but its value is never read.
755
+
756
+7 import { and, desc, eq, sql, count } from "drizzle-orm";
757
+   ~~~~~
758
+
759
+src/pages/[owner]/[repo]/pulls/new.astro:99:11 - error ts(2554): Expected 0 arguments, but got 1.
760
+
761
+99 .select({ count: sql<number>`count(*)` })
762
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
763
+src/pages/[owner]/[repo]/pulls/new.astro:84:5 - warning ts(6133): 'canMerge' is declared but its value is never read.
764
+
765
+84 let canMerge = false;
766
+   ~~~~~~~~
767
+src/pages/[owner]/[repo]/pulls/new.astro:83:5 - warning ts(6133): 'error' is declared but its value is never read.
768
+
769
+83 let error = "";
770
+   ~~~~~
771
+src/pages/[owner]/[repo]/pulls/new.astro:25:3 - warning ts(6133): 'ArrowRight' is declared but its value is never read.
772
+
773
+25 ArrowRight,
774
+   ~~~~~~~~~~
775
+src/pages/[owner]/[repo]/pulls/new.astro:22:24 - warning ts(6133): 'count' is declared but its value is never read.
776
+
777
+22 import { and, eq, sql, count } from "drizzle-orm";
778
+   ~~~~~
779
+src/pages/[owner]/[repo]/pulls/new.astro:336:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
780
+
781
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
782
+
783
+Add the `is:inline` directive explicitly to silence this hint.
784
+
785
+336 define:vars={{
786
+   ~~~~~~~~~~~
787
+
788
+src/pages/[owner]/[repo]/security/index.astro:47:12 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
789
+
790
+47 .get())?.count || 0;
791
+   ~~~~~
792
+src/pages/[owner]/[repo]/security/index.astro:39:11 - error ts(2554): Expected 0 arguments, but got 1.
793
+
794
+39 .select({ count: sql<number>`count(*)` })
795
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
796
+src/pages/[owner]/[repo]/security/index.astro:8:10 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
797
+
798
+8 import { AlertCircle, CheckCircle, Shield, Play, Loader2 } from "lucide-react";
799
+   ~~~~~~~~~~~
800
+src/pages/[owner]/[repo]/security/index.astro:202:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
801
+
802
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
803
+
804
+Add the `is:inline` directive explicitly to silence this hint.
805
+
806
+202 <script define:vars={{ repoOwner: repoInfo.owner, repoName: repoInfo.name }}>
807
+   ~~~~~~~~~~~
808
+
809
+src/pages/[owner]/[repo]/settings/collaborators.astro:83:10 - warning ts(6133): 'getRoleDescription' is declared but its value is never read.
810
+
811
+83 function getRoleDescription(role: string) {
812
+   ~~~~~~~~~~~~~~~~~~
813
+src/pages/[owner]/[repo]/settings/collaborators.astro:297:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
814
+
815
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
816
+
817
+Add the `is:inline` directive explicitly to silence this hint.
818
+
819
+297 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
820
+   ~~~~~~~~~~~
821
+
822
+src/pages/[owner]/[repo]/settings/index.astro:240:32 - error ts(18047): 'repo.isArchived' is possibly 'null'.
823
+
824
+240 data-archived={repo.isArchived.toString()}
825
+   ~~~~~~~~~~~~~~~
826
+src/pages/[owner]/[repo]/settings/index.astro:267:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
827
+
828
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
829
+
830
+Add the `is:inline` directive explicitly to silence this hint.
831
+
832
+267 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
833
+   ~~~~~~~~~~~
834
+
835
+src/pages/[owner]/[repo]/settings/webhooks.astro:326:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
836
+
837
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
838
+
839
+Add the `is:inline` directive explicitly to silence this hint.
840
+
841
+326 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
842
+   ~~~~~~~~~~~
843
+
844
+src/pages/[owner]/[repo]/settings/actions/runners.astro:15:18 - warning ts(6133): 'Terminal' is declared but its value is never read.
845
+
846
+15 import { Server, Terminal, Copy } from "lucide-react";
847
+   ~~~~~~~~
848
+src/pages/[owner]/[repo]/settings/actions/runners.astro:210:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
849
+
850
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
851
+
852
+Add the `is:inline` directive explicitly to silence this hint.
853
+
854
+210 <script define:vars={{ repoId: repoData.id }}>
855
+   ~~~~~~~~~~~
856
+
857
+src/pages/[owner]/[repo]/settings/branches/[id].astro:117:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
858
+
859
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
860
+
861
+Add the `is:inline` directive explicitly to silence this hint.
862
+
863
+117 <script define:vars={{ repoId: repository.id, ruleId: rule.id, owner, repo }}>
864
+   ~~~~~~~~~~~
865
+
866
+src/pages/[owner]/[repo]/settings/branches/index.astro:59:20 - error ts(18047): 'rule.requiredApprovals' is possibly 'null'.
867
+
868
+59 {rule.requiredApprovals > 0 && <span>• {rule.requiredApprovals} Approval(s)</span>}
869
+   ~~~~~~~~~~~~~~~~~~~~~~
870
+src/pages/[owner]/[repo]/settings/branches/index.astro:2:20 - error ts(2307): Cannot find module '@/layouts/RepositoryLayout.astro' or its corresponding type declarations.
871
+
872
+2 import Layout from "@/layouts/RepositoryLayout.astro";
873
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
874
+src/pages/[owner]/[repo]/settings/branches/index.astro:4:14 - warning ts(6133): 'and' is declared but its value is never read.
875
+
876
+4 import { eq, and } from "drizzle-orm";
877
+   ~~~
878
+
879
+src/pages/[owner]/[repo]/settings/branches/new.astro:152:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
880
+
881
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
882
+
883
+Add the `is:inline` directive explicitly to silence this hint.
884
+
885
+152 <script define:vars={{ repoId: repository.id, owner, repo }}>
886
+   ~~~~~~~~~~~
887
+
888
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:5:19 - warning ts(6133): 'desc' is declared but its value is never read.
889
+
890
+5 import { eq, and, desc } from "drizzle-orm";
891
+   ~~~~
892
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:176:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
893
+
894
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
895
+
896
+Add the `is:inline` directive explicitly to silence this hint.
897
+
898
+176 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name, webhookId: webhook.id }}>
899
+   ~~~~~~~~~~~
900
+
901
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:120:52 - error ts(2551): Property 'isActive' does not exist on type '{ id: string; createdAt: string; updatedAt: string; repositoryId: string; active: boolean; createdById: string | null; url: string; secret: string | null; events: unknown; contentType: string; deliveryCount: number | null; lastDeliveryStatus: string | null; lastDeliveryAt: string | null; }'. Did you mean 'active'?
902
+
903
+120 {!hook.isActive && (
904
+   ~~~~~~~~
905
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:7:52 - warning ts(6133): 'MoreVertical' is declared but its value is never read.
906
+
907
+7 import { Plus, CheckCircle2, XCircle, AlertCircle, MoreVertical } from "lucide-react";
908
+   ~~~~~~~~~~~~
909
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:7:39 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
910
+
911
+7 import { Plus, CheckCircle2, XCircle, AlertCircle, MoreVertical } from "lucide-react";
912
+   ~~~~~~~~~~~
913
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:161:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
914
+
915
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
916
+
917
+Add the `is:inline` directive explicitly to silence this hint.
918
+
919
+161 <script define:vars={{ repoId: repo.id }}>
920
+   ~~~~~~~~~~~
921
+
922
+src/pages/[owner]/[repo]/settings/webhooks/new.astro:187:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
923
+
924
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
925
+
926
+Add the `is:inline` directive explicitly to silence this hint.
927
+
928
+187 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name }}>
929
+   ~~~~~~~~~~~
930
+
931
+src/pages/[owner]/[repo]/tree/[...ref].astro:70:42 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
932
+
933
+70 const openIssueCount = issueCountResult?.count || 0;
934
+   ~~~~~
935
+src/pages/[owner]/[repo]/tree/[...ref].astro:60:11 - error ts(2554): Expected 0 arguments, but got 1.
936
+
937
+60 .select({ count: sql<number>`count(*)` })
938
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
939
+src/pages/[owner]/[repo]/tree/[...ref].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
940
+
941
+6 Tag,
942
+   ~~~
943
+
944
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:63:42 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
945
+
946
+63 const openIssueCount = issueCountResult?.count || 0;
947
+   ~~~~~
948
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:53:11 - error ts(2554): Expected 0 arguments, but got 1.
949
+
950
+53 .select({ count: sql<number>`count(*)` })
951
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
952
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:11:3 - warning ts(6133): 'FileText' is declared but its value is never read.
953
+
954
+11 FileText,
955
+   ~~~~~~~~
956
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
957
+
958
+6 Tag,
959
+   ~~~
960
+
961
+src/pages/admin/audit.astro:76:28 - error ts(2339): Property 'count' does not exist on type '{ id: string; userId: string | null; repositoryId: string | null; action: string; actorType: string; actorId: string | null; actorIp: string | null; actorUserAgent: string | null; targetType: string | null; targetId: string | null; targetName: string | null; data: string | null; createdAt: string; }'.
962
+
963
+76 const total = totalResult?.count || 0;
964
+   ~~~~~
965
+src/pages/admin/audit.astro:70:13 - error ts(2554): Expected 0 arguments, but got 1.
966
+
967
+70 db.select({ count: sql<number>`count(*)` })
968
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
969
+src/pages/admin/audit.astro:18:3 - warning ts(6133): 'ExternalLink' is declared but its value is never read.
970
+
971
+18 ExternalLink
972
+   ~~~~~~~~~~~~
973
+src/pages/admin/audit.astro:4:27 - warning ts(6133): 'eq' is declared but its value is never read.
974
+
975
+4 import { desc, sql, like, eq, or } from "drizzle-orm";
976
+   ~~
977
+
978
+src/pages/admin/repositories.astro:45:28 - error ts(2339): Property 'count' does not exist on type '{ id: string; name: string; slug: string; description: string | null; ownerId: string; ownerType: string; visibility: string; defaultBranch: string; diskPath: string; sshCloneUrl: string | null; ... 23 more ...; updatedAt: string; }'.
979
+
980
+45 const total = totalResult?.count || 0;
981
+   ~~~~~
982
+src/pages/admin/repositories.astro:39:15 - error ts(2554): Expected 0 arguments, but got 1.
983
+
984
+39 db.select({ count: sql<number>`count(*)` })
985
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
986
+src/pages/admin/repositories.astro:4:16 - warning ts(6133): 'eq' is declared but its value is never read.
987
+
988
+4 import { desc, eq, like, or, sql } from "drizzle-orm";
989
+   ~~
990
+
991
+src/pages/admin/settings.astro:7:10 - error ts(2440): Import declaration conflicts with local declaration of 'Settings'.
992
+
993
+7 import { Settings, Save, Mail, Globe, Lock } from "lucide-react";
994
+   ~~~~~~~~
995
+src/pages/admin/settings.astro:169:17 - error ts(2339): Property 'disabled' does not exist on type 'HTMLElement'.
996
+
997
+169 btn.disabled = false;
998
+   ~~~~~~~~
999
+src/pages/admin/settings.astro:169:13 - error ts(18047): 'btn' is possibly 'null'.
1000
+
1001
+169 btn.disabled = false;
1002
+   ~~~
1003
+src/pages/admin/settings.astro:168:13 - error ts(18047): 'btn' is possibly 'null'.
1004
+
1005
+168 btn.textContent = original;
1006
+   ~~~
1007
+src/pages/admin/settings.astro:152:69 - error ts(2339): Property 'checked' does not exist on type 'HTMLElement'.
1008
+
1009
+152 data.allowSignups = document.getElementById('allowSignups').checked;
1010
+   ~~~~~~~
1011
+src/pages/admin/settings.astro:152:29 - error ts(2531): Object is possibly 'null'.
1012
+
1013
+152 data.allowSignups = document.getElementById('allowSignups').checked;
1014
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1015
+src/pages/admin/settings.astro:148:39 - error ts(2345): Argument of type 'EventTarget | null' is not assignable to parameter of type 'HTMLFormElement | undefined'.
1016
+ Type 'null' is not assignable to type 'HTMLFormElement | undefined'.
1017
+
1018
+148 const formData = new FormData(e.target);
1019
+   ~~~~~~~~
1020
+src/pages/admin/settings.astro:146:13 - error ts(2339): Property 'disabled' does not exist on type 'HTMLElement'.
1021
+
1022
+146 btn.disabled = true;
1023
+   ~~~~~~~~
1024
+src/pages/admin/settings.astro:146:9 - error ts(18047): 'btn' is possibly 'null'.
1025
+
1026
+146 btn.disabled = true;
1027
+   ~~~
1028
+src/pages/admin/settings.astro:145:9 - error ts(18047): 'btn' is possibly 'null'.
1029
+
1030
+145 btn.textContent = "Saving...";
1031
+   ~~~
1032
+src/pages/admin/settings.astro:144:26 - error ts(18047): 'btn' is possibly 'null'.
1033
+
1034
+144 const original = btn.textContent;
1035
+   ~~~
1036
+src/pages/admin/settings.astro:133:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1037
+
1038
+133 document.getElementById('smtpFrom').value = config.smtpFrom || '';
1039
+   ~~~~~
1040
+src/pages/admin/settings.astro:133:17 - error ts(2531): Object is possibly 'null'.
1041
+
1042
+133 document.getElementById('smtpFrom').value = config.smtpFrom || '';
1043
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1044
+src/pages/admin/settings.astro:132:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1045
+
1046
+132 document.getElementById('smtpUser').value = config.smtpUser || '';
1047
+   ~~~~~
1048
+src/pages/admin/settings.astro:132:17 - error ts(2531): Object is possibly 'null'.
1049
+
1050
+132 document.getElementById('smtpUser').value = config.smtpUser || '';
1051
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1052
+src/pages/admin/settings.astro:131:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1053
+
1054
+131 document.getElementById('smtpPort').value = config.smtpPort || '';
1055
+   ~~~~~
1056
+src/pages/admin/settings.astro:131:17 - error ts(2531): Object is possibly 'null'.
1057
+
1058
+131 document.getElementById('smtpPort').value = config.smtpPort || '';
1059
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1060
+src/pages/admin/settings.astro:130:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1061
+
1062
+130 document.getElementById('smtpHost').value = config.smtpHost || '';
1063
+   ~~~~~
1064
+src/pages/admin/settings.astro:130:17 - error ts(2531): Object is possibly 'null'.
1065
+
1066
+130 document.getElementById('smtpHost').value = config.smtpHost || '';
1067
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1068
+src/pages/admin/settings.astro:128:57 - error ts(2339): Property 'checked' does not exist on type 'HTMLElement'.
1069
+
1070
+128 document.getElementById('allowSignups').checked = !!config.allowSignups;
1071
+   ~~~~~~~
1072
+src/pages/admin/settings.astro:128:17 - error ts(2531): Object is possibly 'null'.
1073
+
1074
+128 document.getElementById('allowSignups').checked = !!config.allowSignups;
1075
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1076
+src/pages/admin/settings.astro:127:60 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1077
+
1078
+127 document.getElementById('siteDescription').value = config.siteDescription || '';
1079
+   ~~~~~
1080
+src/pages/admin/settings.astro:127:17 - error ts(2531): Object is possibly 'null'.
1081
+
1082
+127 document.getElementById('siteDescription').value = config.siteDescription || '';
1083
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1084
+src/pages/admin/settings.astro:126:53 - error ts(2339): Property 'value' does not exist on type 'HTMLElement'.
1085
+
1086
+126 document.getElementById('siteName').value = config.siteName || '';
1087
+   ~~~~~
1088
+src/pages/admin/settings.astro:126:17 - error ts(2531): Object is possibly 'null'.
1089
+
1090
+126 document.getElementById('siteName').value = config.siteName || '';
1091
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1092
+
1093
+src/pages/admin/users.astro:106:58 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1094
+
1095
+106 <p class="text-2xl font-bold">{adminUsers?.count || 0}</p>
1096
+   ~~~~~
1097
+src/pages/admin/users.astro:95:59 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1098
+
1099
+95 <p class="text-2xl font-bold">{activeUsers?.count || 0}</p>
1100
+   ~~~~~
1101
+src/pages/admin/users.astro:84:58 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1102
+
1103
+84 <p class="text-2xl font-bold">{totalUsers?.count || 0}</p>
1104
+   ~~~~~
1105
+src/pages/admin/users.astro:54:13 - error ts(2554): Expected 0 arguments, but got 1.
1106
+
1107
+54 db.select({ count: sql<number>`count(*)` }).from(schema.users).where(eq(schema.users.isAdmin, true)).get(),
1108
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1109
+src/pages/admin/users.astro:53:13 - error ts(2554): Expected 0 arguments, but got 1.
1110
+
1111
+53 db.select({ count: sql<number>`count(*)` }).from(schema.users).where(eq(schema.users.isActive, true)).get(),
1112
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1113
+src/pages/admin/users.astro:52:13 - error ts(2554): Expected 0 arguments, but got 1.
1114
+
1115
+52 db.select({ count: sql<number>`count(*)` }).from(schema.users).get(),
1116
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1117
+src/pages/admin/users.astro:47:28 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1118
+
1119
+47 const total = totalResult?.count || 0;
1120
+   ~~~~~
1121
+src/pages/admin/users.astro:41:13 - error ts(2554): Expected 0 arguments, but got 1.
1122
+
1123
+41 db.select({ count: sql<number>`count(*)` })
1124
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1125
+src/pages/admin/users.astro:8:10 - error ts(2440): Import declaration conflicts with local declaration of 'Users'.
1126
+
1127
+8 import { Users, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1128
+   ~~~~~
1129
+src/pages/admin/users.astro:277:28 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1130
+
1131
+277 const isActive = btn.dataset.isActive === 'true';
1132
+   ~~~~~~~
1133
+src/pages/admin/users.astro:276:26 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1134
+
1135
+276 const userId = btn.dataset.userId;
1136
+   ~~~~~~~
1137
+src/pages/admin/users.astro:254:27 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1138
+
1139
+254 const isAdmin = btn.dataset.isAdmin === 'true';
1140
+   ~~~~~~~
1141
+src/pages/admin/users.astro:253:26 - error ts(2339): Property 'dataset' does not exist on type 'Element'.
1142
+
1143
+253 const userId = btn.dataset.userId;
1144
+   ~~~~~~~
1145
+
1146
+src/pages/api/ai-review-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1147
+
1148
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1149
+   ~~~~~~
1150
+
1151
+src/pages/api/automation-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1152
+
1153
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1154
+   ~~~~~~
1155
+src/pages/api/automation-rules.ts:7:14 - warning ts(6133): 'and' is declared but its value is never read.
1156
+
1157
+7 import { eq, and } from "drizzle-orm";
1158
+   ~~~
1159
+
1160
+src/pages/api/inbox-sections.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1161
+
1162
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1163
+   ~~~~~~
1164
+
1165
+src/pages/api/search.ts:3:20 - warning ts(6133): 'eq' is declared but its value is never read.
1166
+
1167
+3 import { like, or, eq, desc } from 'drizzle-orm';
1168
+   ~~
1169
+
1170
+src/pages/api/actions/trigger-test.ts:10:1 - warning ts(6133): 'eq' is declared but its value is never read.
1171
+
1172
+10 import { eq } from "drizzle-orm";
1173
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1174
+src/pages/api/actions/trigger-test.ts:8:57 - warning ts(6133): 'notFound' is declared but its value is never read.
1175
+
1176
+8 import { success, unauthorized, serverError, parseBody, notFound } from '@/lib/api';
1177
+   ~~~~~~~~
1178
+
1179
+src/pages/api/realtime/events.ts:28:48 - warning ts(6133): 'request' is declared but its value is never read.
1180
+
1181
+28 export const POST: APIRoute = async ({ locals, request }) => {
1182
+   ~~~~~~~
1183
+
1184
+src/pages/api/repos/[owner]/[repo]/protection.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1185
+
1186
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1187
+   ~~~~~~~~~~
1188
+
1189
+src/pages/api/repos/[owner]/[repo]/git/push.ts:142:26 - warning ts(6133): 'sha' is declared but its value is never read.
1190
+
1191
+142 for (const { sha, ref } of bundleRefs) {
1192
+   ~~~
1193
+src/pages/api/repos/[owner]/[repo]/git/push.ts:22:22 - warning ts(6133): 'mkdirSync' is declared but its value is never read.
1194
+
1195
+22 import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "fs";
1196
+   ~~~~~~~~~
1197
+src/pages/api/repos/[owner]/[repo]/git/push.ts:18:5 - warning ts(6133): 'getDiskPath' is declared but its value is never read.
1198
+
1199
+18 getDiskPath,
1200
+   ~~~~~~~~~~~
1201
+src/pages/api/repos/[owner]/[repo]/git/push.ts:13:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
1202
+
1203
+13 import { getRepoPath } from "@/lib/utils";
1204
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1205
+
1206
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:30 - warning ts(6133): 'number' is declared but its value is never read.
1207
+
1208
+210 const { owner, repo, number, commentId } = params;
1209
+   ~~~~~~
1210
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:24 - warning ts(6133): 'repo' is declared but its value is never read.
1211
+
1212
+210 const { owner, repo, number, commentId } = params;
1213
+   ~~~~
1214
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:30 - warning ts(6133): 'number' is declared but its value is never read.
1215
+
1216
+163 const { owner, repo, number, commentId } = params;
1217
+   ~~~~~~
1218
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:24 - warning ts(6133): 'repo' is declared but its value is never read.
1219
+
1220
+163 const { owner, repo, number, commentId } = params;
1221
+   ~~~~
1222
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:99:24 - warning ts(6133): 'repo' is declared but its value is never read.
1223
+
1224
+99 const { owner, repo, number } = params;
1225
+   ~~~~
1226
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:37:24 - warning ts(6133): 'repo' is declared but its value is never read.
1227
+
1228
+37 const { owner, repo, number } = params;
1229
+   ~~~~
1230
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1231
+
1232
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1233
+   ~~~~~~~~~~
1234
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:7:25 - warning ts(6133): 'isNull' is declared but its value is never read.
1235
+
1236
+7 import { eq, and, desc, isNull } from "drizzle-orm";
1237
+   ~~~~~~
1238
+
1239
+src/pages/api/stacks/index.ts:26:6 - warning ts(6196): 'CreateStackInput' is declared but never used.
1240
+
1241
+26 type CreateStackInput = z.infer<typeof createStackSchema>;
1242
+   ~~~~~~~~~~~~~~~~
1243
+src/pages/api/stacks/index.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1244
+
1245
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1246
+   ~~~~~~~~~~
1247
+
1248
+src/pages/api/user/notification-preferences.ts:12:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1249
+
1250
+12 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1251
+   ~~~~~~
1252
+
1253
+src/pages/api/user/tokens.ts:103:24 - warning ts(6133): 'prefix' is declared but its value is never read.
1254
+
1255
+103 const { token, prefix } = generateToken();
1256
+   ~~~~~~
1257
+src/pages/api/user/tokens.ts:79:34 - warning ts(6133): 'scopes' is declared but its value is never read.
1258
+
1259
+79 const { name, expiresIn, scopes } = parsed.data;
1260
+   ~~~~~~
1261
+src/pages/api/user/tokens.ts:26:10 - warning ts(6133): 'hashToken' is declared but its value is never read.
1262
+
1263
+26 function hashToken(token: string): string {
1264
+   ~~~~~~~~~
1265
+src/pages/api/user/tokens.ts:8:23 - warning ts(6133): 'schema' is declared but its value is never read.
1266
+
1267
+8 import { getDatabase, schema } from "@/db";
1268
+   ~~~~~~
1269
+
1270
+src/pages/settings/ai-review-rules.astro:35:38 - error ts(2353): Object literal may only specify known properties, and 'fullName' does not exist in type '{ id?: boolean | undefined; name?: boolean | undefined; slug?: boolean | undefined; description?: boolean | undefined; ownerId?: boolean | undefined; ownerType?: boolean | undefined; ... 27 more ...; updatedAt?: boolean | undefined; }'.
1271
+
1272
+35 columns: { id: true, name: true, fullName: true },
1273
+   ~~~~~~~~
1274
+src/pages/settings/ai-review-rules.astro:19:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
1275
+
1276
+19 CheckCircle2,
1277
+   ~~~~~~~~~~~~
1278
+src/pages/settings/ai-review-rules.astro:4:14 - warning ts(6133): 'and' is declared but its value is never read.
1279
+
1280
+4 import { eq, and, desc } from "drizzle-orm";
1281
+   ~~~
1282
+src/pages/settings/ai-review-rules.astro:469:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1283
+
1284
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1285
+
1286
+Add the `is:inline` directive explicitly to silence this hint.
1287
+
1288
+469 <script define:vars={{ repoId }}>
1289
+   ~~~~~~~~~~~
1290
+
1291
+src/pages/settings/automations.astro:301:61 - warning ts(6133): 'i' is declared but its value is never read.
1292
+
1293
+301 {actions.slice(0, 3).map((action, i) => (
1294
+   ~
1295
+src/pages/settings/automations.astro:437:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1296
+
1297
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1298
+
1299
+Add the `is:inline` directive explicitly to silence this hint.
1300
+
1301
+437 <script define:vars={{ repoId }}>
1302
+   ~~~~~~~~~~~
1303
+
1304
+Result (300 files):
1305
+- 58 errors
1306
+- 0 warnings
1307
+- 223 hints
1308
+
0
1309
▼lint_output_3.txt
+1274-0
1
+
2
3
+> astro check
4
+
5
+14:27:04 [types] Generated 33ms
6
+14:27:04 [check] Getting diagnostics for Astro files in /home/swadhin/owngit/OpenCodeHub...
7
+src/components/admin/AdminDashboard.tsx:141:30 - warning ts(6385): 'Github' is deprecated.
8
+
9
+141 <Github className="h-8 w-8 text-white opacity-30 hover:opacity-70 transition-opacity cursor-pointer" />
10
+   ~~~~~~
11
+src/components/admin/AdminDashboard.tsx:10:10 - warning ts(6385): 'Github' is deprecated.
12
+
13
+10 import { Github } from "lucide-react";
14
+   ~~~~~~
15
+
16
+src/components/admin/AlertBanner.tsx:2:44 - warning ts(6133): 'Bell' is declared but its value is never read.
17
+
18
+2 import { AlertTriangle, CheckCircle, Info, Bell, X } from "lucide-react";
19
+   ~~~~
20
+
21
+src/components/admin/DashboardStats.tsx:1:45 - warning ts(6133): 'useTransform' is declared but its value is never read.
22
+
23
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
24
+   ~~~~~~~~~~~~
25
+src/components/admin/DashboardStats.tsx:1:34 - warning ts(6133): 'useSpring' is declared but its value is never read.
26
+
27
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
28
+   ~~~~~~~~~
29
+src/components/admin/DashboardStats.tsx:1:18 - warning ts(6133): 'useMotionValue' is declared but its value is never read.
30
+
31
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
32
+   ~~~~~~~~~~~~~~
33
+
34
+src/components/admin/GlobeViz.tsx:199:27 - warning ts(6133): 'activities' is declared but its value is never read.
35
+
36
+199 function CSSGlobeFallback({ activities = [] }: Props) {
37
+   ~~~~~~~~~~~~~~~~~~~
38
+src/components/admin/GlobeViz.tsx:89:54 - warning ts(6133): 'i' is declared but its value is never read.
39
+
40
+89 markers: activities.slice(0, 20).map((_, i) => ({
41
+   ~
42
+
43
+src/components/admin/QuickStatsRow.tsx:2:78 - warning ts(6133): 'Zap' is declared but its value is never read.
44
+
45
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
46
+   ~~~
47
+src/components/admin/QuickStatsRow.tsx:2:68 - warning ts(6133): 'Activity' is declared but its value is never read.
48
+
49
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
50
+   ~~~~~~~~
51
+src/components/admin/QuickStatsRow.tsx:2:49 - warning ts(6133): 'Clock' is declared but its value is never read.
52
+
53
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
54
+   ~~~~~
55
+
56
+src/components/admin/SystemStatus.tsx:18:5 - warning ts(6133): 'color' is declared but its value is never read.
57
+
58
+18 color,
59
+   ~~~~~
60
+src/components/admin/SystemStatus.tsx:1:47 - warning ts(6133): 'Server' is declared but its value is never read.
61
+
62
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
63
+   ~~~~~~
64
+src/components/admin/SystemStatus.tsx:1:41 - warning ts(6133): 'Wifi' is declared but its value is never read.
65
+
66
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
67
+   ~~~~
68
+
69
+src/components/dashboard/ActivityStream.tsx:80:55 - warning ts(6133): 'i' is declared but its value is never read.
70
+
71
+80 {users.slice(0, 5).map((user, i) => (
72
+   ~
73
+src/components/dashboard/ActivityStream.tsx:2:1 - warning ts(6133): 'React' is declared but its value is never read.
74
+
75
+2 import * as React from "react";
76
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
+
78
+src/components/git/CommitGraph.tsx:209:35 - warning ts(6133): 'index' is declared but its value is never read.
79
+
80
+209 {commits.map((commit, index) => {
81
+   ~~~~~
82
+src/components/git/CommitGraph.tsx:51:11 - warning ts(6133): 'branchHeads' is declared but its value is never read.
83
+
84
+51 const branchHeads: Map<string, string> = new Map()
85
+   ~~~~~~~~~~~
86
+
87
+src/components/home/HeroSection.tsx:87:26 - warning ts(6385): 'Github' is deprecated.
88
+
89
+87 <Github className="h-4 w-4" />
90
+   ~~~~~~
91
+src/components/home/HeroSection.tsx:6:22 - warning ts(6385): 'Github' is deprecated.
92
+
93
+6 import { ArrowRight, Github, Star, GitBranch, Zap } from "lucide-react";
94
+   ~~~~~~
95
+src/components/home/HeroSection.tsx:4:1 - warning ts(6133): 'ColourfulText' is declared but its value is never read.
96
+
97
+4 import { ColourfulText } from "@/components/ui/colourful-text";
98
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
+
100
+src/components/issues/IssueDetail.tsx:68:67 - warning ts(6133): 'repoName' is declared but its value is never read.
101
+
102
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
103
+   ~~~~~~~~
104
+src/components/issues/IssueDetail.tsx:68:56 - warning ts(6133): 'repoOwner' is declared but its value is never read.
105
+
106
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
107
+   ~~~~~~~~~
108
+
109
+src/components/issues/IssuesList.tsx:14:5 - warning ts(6133): 'Filter' is declared but its value is never read.
110
+
111
+14 Filter
112
+   ~~~~~~
113
+
114
+src/components/layout/Header.astro:2:10 - warning ts(6133): 'GitBranch' is declared but its value is never read.
115
+
116
+2 import { GitBranch, Search, Bell, Plus, Menu } from "lucide-react"
117
+   ~~~~~~~~~
118
+
119
+src/components/pr/AIReviewPanel.tsx:76:5 - warning ts(6133): 'reviewId' is declared but its value is never read.
120
+
121
+76 reviewId,
122
+   ~~~~~~~~
123
+src/components/pr/AIReviewPanel.tsx:6:8 - warning ts(6133): 'React' is declared but its value is never read.
124
+
125
+6 import React, { useState } from "react";
126
+   ~~~~~
127
+
128
+src/components/pr/StackVisualization.tsx:52:5 - warning ts(6133): 'onReorder' is declared but its value is never read.
129
+
130
+52 onReorder,
131
+   ~~~~~~~~~
132
+src/components/pr/StackVisualization.tsx:45:5 - warning ts(6133): 'stackId' is declared but its value is never read.
133
+
134
+45 stackId,
135
+   ~~~~~~~
136
+
137
+src/components/pulls/PullRequestsList.tsx:14:5 - warning ts(6133): 'Sparkles' is declared but its value is never read.
138
+
139
+14 Sparkles,
140
+   ~~~~~~~~
141
+
142
+src/components/repo/FileExplorer.astro:2:20 - warning ts(6133): 'Folder' is declared but its value is never read.
143
+
144
+2 import { FileText, Folder } from "lucide-react";
145
+   ~~~~~~
146
+
147
+src/components/repo/RepoHeader.astro:3:3 - warning ts(6133): 'GitBranch' is declared but its value is never read.
148
+
149
+3 GitBranch,
150
+   ~~~~~~~~~
151
+
152
+src/components/search/GlobalSearch.tsx:17:12 - warning ts(6133): 'loading' is declared but its value is never read.
153
+
154
+17 const [loading, setLoading] = React.useState(false);
155
+   ~~~~~~~
156
+src/components/search/GlobalSearch.tsx:11:18 - warning ts(6133): 'FileText' is declared but its value is never read.
157
+
158
+11 import { Search, FileText, User, GitBranch, GitPullRequest, CircleDot, Workflow } from "lucide-react";
159
+   ~~~~~~~~
160
+
161
+src/components/ui/animated-tooltip.tsx:4:8 - warning ts(6133): 'React' is declared but its value is never read.
162
+
163
+4 import React, { useState } from "react";
164
+   ~~~~~
165
+src/components/ui/animated-tooltip.tsx:2:1 - warning ts(6133): 'cn' is declared but its value is never read.
166
+
167
+2 import { cn } from "@/lib/cn";
168
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
+
170
+src/components/ui/text-generate-effect.tsx:2:29 - warning ts(6133): 'useState' is declared but its value is never read.
171
+
172
+2 import { useEffect, useRef, useState } from "react";
173
+   ~~~~~~~~
174
+src/components/ui/text-generate-effect.tsx:2:21 - warning ts(6133): 'useRef' is declared but its value is never read.
175
+
176
+2 import { useEffect, useRef, useState } from "react";
177
+   ~~~~~~
178
+
179
+src/components/ui/text-reveal-card.tsx:3:29 - warning ts(6133): 'useTransform' is declared but its value is never read.
180
+
181
+3 import { motion, useScroll, useTransform } from "framer-motion";
182
+   ~~~~~~~~~~~~
183
+src/components/ui/text-reveal-card.tsx:3:18 - warning ts(6133): 'useScroll' is declared but its value is never read.
184
+
185
+3 import { motion, useScroll, useTransform } from "framer-motion";
186
+   ~~~~~~~~~
187
+
188
+src/db/seed-activity.ts:6:1 - warning ts(6133): 'eq' is declared but its value is never read.
189
+
190
+6 import { eq } from "drizzle-orm";
191
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
+src/db/seed-activity.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
193
+
194
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
195
+   ~~~~~
196
+src/db/seed-activity.ts:3:10 - warning ts(6133): 'repositories' is declared but its value is never read.
197
+
198
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
199
+   ~~~~~~~~~~~~
200
+
201
+src/db/seed-notifications.ts:5:32 - warning ts(6133): 'repositories' is declared but its value is never read.
202
+
203
+5 import { notifications, users, repositories } from "@/db/schema";
204
+   ~~~~~~~~~~~~
205
+src/db/seed-notifications.ts:5:25 - warning ts(6133): 'users' is declared but its value is never read.
206
+
207
+5 import { notifications, users, repositories } from "@/db/schema";
208
+   ~~~~~
209
+
210
+src/db/seed-scale.ts:25:11 - warning ts(6133): 'reposPath' is declared but its value is never read.
211
+
212
+25 const reposPath = process.env.GIT_REPOS_PATH || "./data/repos";
213
+   ~~~~~~~~~
214
+src/db/seed-scale.ts:9:1 - warning ts(6133): 'fs' is declared but its value is never read.
215
+
216
+9 import fs from "fs/promises";
217
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
+src/db/seed-scale.ts:7:1 - warning ts(6133): 'eq' is declared but its value is never read.
219
+
220
+7 import { eq } from "drizzle-orm";
221
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222
+src/db/seed-scale.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
223
+
224
+3 import { repositories, users } from "@/db/schema";
225
+   ~~~~~
226
+
227
+src/db/schema/developer-metrics.ts:7:19 - warning ts(6133): 'real' is declared but its value is never read.
228
+
229
+7 import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
230
+   ~~~~
231
+
232
+src/db/schema/pipeline-runners.ts:3:10 - warning ts(6133): 'integer' is declared but its value is never read.
233
+
234
+3 import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
235
+   ~~~~~~~
236
+
237
+src/db/schema/pull-requests.ts:8:18 - warning ts(6133): 'milestones' is declared but its value is never read.
238
+
239
+8 import { labels, milestones } from "./issues";
240
+   ~~~~~~~~~~
241
+
242
+src/db/schema/security.ts:3:1 - warning ts(6133): 'users' is declared but its value is never read.
243
+
244
+3 import { users } from "./users";
245
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246
+
247
+src/lib/ai-review.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
248
+
249
+6 import { eq, and, desc } from "drizzle-orm";
250
+   ~~~
251
+
252
+src/lib/analysis.ts:35:87 - warning ts(6133): 'force' is declared but its value is never read.
253
+
254
+35 export async function analyzeRepository(repoId: string, userId: string | null = null, force = false) {
255
+   ~~~~~
256
+src/lib/analysis.ts:4:22 - warning ts(6133): 'getRepoSize' is declared but its value is never read.
257
+
258
+4 import { getCommits, getRepoSize, listFiles, getCommitDiff } from "./git";
259
+   ~~~~~~~~~~~
260
+
261
+src/lib/auth.ts:281:22 - warning ts(6133): 'gt' is declared but its value is never read.
262
+
263
+281 const { eq, and, gt } = await import("drizzle-orm");
264
+   ~~
265
+src/lib/auth.ts:281:17 - warning ts(6133): 'and' is declared but its value is never read.
266
+
267
+281 const { eq, and, gt } = await import("drizzle-orm");
268
+   ~~~
269
+src/lib/auth.ts:280:35 - warning ts(6133): 'users' is declared but its value is never read.
270
+
271
+280 const { personalAccessTokens, users } = await import("@/db/schema/users");
272
+   ~~~~~
273
+
274
+src/lib/automations.ts:320:23 - warning ts(6133): 'notifyPrEvent' is declared but its value is never read.
275
+
276
+320 const { notifyPrEvent } = await import("./slack-notifications");
277
+   ~~~~~~~~~~~~~~~~~
278
+
279
+src/lib/conflict-automation.ts:11:1 - warning ts(6192): All imports in import declaration are unused.
280
+
281
+11 import { notifyPrEvent, notifyUserDm } from "./slack-notifications";
282
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283
+src/lib/conflict-automation.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
284
+
285
+6 import { eq, and } from "drizzle-orm";
286
+   ~~~
287
+
288
+src/lib/developer-metrics.ts:6:35 - warning ts(6133): 'lte' is declared but its value is never read.
289
+
290
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
291
+   ~~~
292
+src/lib/developer-metrics.ts:6:30 - warning ts(6133): 'gte' is declared but its value is never read.
293
+
294
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
295
+   ~~~
296
+src/lib/developer-metrics.ts:6:25 - warning ts(6133): 'sql' is declared but its value is never read.
297
+
298
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
299
+   ~~~
300
+
301
+src/lib/git-storage.ts:15:27 - warning ts(6133): 'StorageAdapter' is declared but its value is never read.
302
+
303
+15 import { getStorage, type StorageAdapter } from "./storage";
304
+   ~~~~~~~~~~~~~~
305
+src/lib/git-storage.ts:14:1 - warning ts(6133): 'Readable' is declared but its value is never read.
306
+
307
+14 import { Readable } from "stream";
308
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309
+src/lib/git-storage.ts:10:54 - warning ts(6133): 'statSync' is declared but its value is never read.
310
+
311
+10 import { existsSync, mkdirSync, rmSync, readdirSync, statSync } from "fs";
312
+   ~~~~~~~~
313
+
314
+src/lib/git.ts:1171:32 - warning ts(6133): 'reject' is declared but its value is never read.
315
+
316
+1171 return new Promise((resolve, reject) => {
317
+   ~~~~~~
318
+src/lib/git.ts:14:3 - warning ts(6133): 'releaseRepo' is declared but its value is never read.
319
+
320
+14 releaseRepo,
321
+   ~~~~~~~~~~~
322
+src/lib/git.ts:13:3 - warning ts(6133): 'acquireRepo' is declared but its value is never read.
323
+
324
+13 acquireRepo,
325
+   ~~~~~~~~~~~
326
+
327
+src/lib/lfs.ts:64:3 - warning ts(6133): 'repoDiskPath' is declared but its value is never read.
328
+
329
+64 repoDiskPath: string,
330
+   ~~~~~~~~~~~~
331
+
332
+src/lib/merge-queue.ts:11:1 - warning ts(6133): 'emitQueueEvent' is declared but its value is never read.
333
+
334
+11 import { emitQueueEvent } from "./realtime";
335
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336
+src/lib/merge-queue.ts:6:34 - warning ts(6133): 'gt' is declared but its value is never read.
337
+
338
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
339
+   ~~
340
+src/lib/merge-queue.ts:6:30 - warning ts(6133): 'lt' is declared but its value is never read.
341
+
342
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
343
+   ~~
344
+
345
+src/lib/pipeline.ts:292:15 - warning ts(6133): 'tag' is declared but its value is never read.
346
+
347
+292 const tag = payload.ref.replace("refs/tags/", "");
348
+   ~~~
349
+src/lib/pipeline.ts:238:11 - warning ts(6133): 'artifactsDir' is declared but its value is never read.
350
+
351
+238 private artifactsDir: string;
352
+   ~~~~~~~~~~~~
353
+src/lib/pipeline.ts:237:11 - warning ts(6133): 'workDir' is declared but its value is never read.
354
+
355
+237 private workDir: string;
356
+   ~~~~~~~
357
+
358
+src/lib/realtime.ts:49:61 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
359
+
360
+49 return `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
361
+   ~~~~~~
362
+
363
+src/lib/security.ts:116:15 - warning ts(6133): 'rawOutput' is declared but its value is never read.
364
+
365
+116 const rawOutput = logsBuffer.toString("utf-8");
366
+   ~~~~~~~~~
367
+src/lib/security.ts:76:15 - warning ts(6133): 'stream' is declared but its value is never read.
368
+
369
+76 const stream = await container.logs({ follow: true, stdout: true, stderr: true });
370
+   ~~~~~~
371
+src/lib/security.ts:56:15 - warning ts(6133): 'chunks' is declared but its value is never read.
372
+
373
+56 const chunks: Buffer[] = [];
374
+   ~~~~~~
375
+src/lib/security.ts:48:41 - warning ts(6133): 'event' is declared but its value is never read.
376
+
377
+48 function onProgress(event: any) { }
378
+   ~~~~~
379
+src/lib/security.ts:44:51 - warning ts(6133): 'output' is declared but its value is never read.
380
+
381
+44 function onFinished(err: any, output: any) {
382
+   ~~~~~~
383
+src/lib/security.ts:40:41 - warning ts(6133): 'reject' is declared but its value is never read.
384
+
385
+40 await new Promise((resolve, reject) => {
386
+   ~~~~~~
387
+src/lib/security.ts:15:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
388
+
389
+15 repositoryId: string
390
+   ~~~~~~~~~~~~
391
+src/lib/security.ts:5:21 - warning ts(6133): 'writeFile' is declared but its value is never read.
392
+
393
+5 import { mkdir, rm, writeFile } from "fs/promises";
394
+   ~~~~~~~~~
395
+
396
+src/lib/slack-notifications.ts:257:5 - warning ts(6133): 'event' is declared but its value is never read.
397
+
398
+257 event: string,
399
+   ~~~~~
400
+
401
+src/lib/ssh.ts:190:32 - warning ts(6133): 'accept' is declared but its value is never read.
402
+
403
+190 session.on("shell", (accept, reject) => {
404
+   ~~~~~~
405
+src/lib/ssh.ts:78:39 - warning ts(6133): 'reject' is declared but its value is never read.
406
+
407
+78 client.on("session", (accept, reject) => {
408
+   ~~~~~~
409
+src/lib/ssh.ts:37:5 - warning ts(6133): 'port' is declared but its value is never read.
410
+
411
+37 port,
412
+   ~~~~
413
+
414
+src/lib/storage.ts:1196:9 - warning ts(6133): 'eq' is declared but its value is never read.
415
+
416
+1196 const { eq } = await import("drizzle-orm");
417
+   ~~~~~~
418
+src/lib/storage.ts:1098:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
419
+
420
+1098 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
421
+   ~~~~~~~~~
422
+src/lib/storage.ts:1084:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
423
+
424
+1084 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
425
+   ~~~~~~~~~
426
+src/lib/storage.ts:971:30 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
427
+
428
+971 const chunk = buffer.slice(i, Math.min(i + chunkSize, buffer.length));
429
+   ~~~~~
430
+src/lib/storage.ts:875:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
431
+
432
+875 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
433
+   ~~~~~~~~~
434
+src/lib/storage.ts:868:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
435
+
436
+868 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
437
+   ~~~~~~~~~
438
+src/lib/storage.ts:798:21 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
439
+
440
+798 return buffer.slice(options.range.start, options.range.end + 1);
441
+   ~~~~~
442
+src/lib/storage.ts:660:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
443
+
444
+660 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
445
+   ~~~~~~~~~
446
+src/lib/storage.ts:649:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
447
+
448
+649 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
449
+   ~~~~~~~~~
450
+src/lib/storage.ts:539:51 - warning ts(6133): 'options' is declared but its value is never read.
451
+
452
+539 async put(key: string, data: Buffer | Readable, options?: PutOptions): Promise<void> {
453
+   ~~~~~~~
454
+src/lib/storage.ts:274:5 - warning ts(6133): 'expiresIn' is declared but its value is never read.
455
+
456
+274 expiresIn: number = 3600
457
+   ~~~~~~~~~
458
+
459
+src/lib/sync.ts:361:23 - warning ts(6133): 'baseHead' is declared but its value is never read.
460
+
461
+361 const baseHead = await git.revparse([baseBranch]);
462
+   ~~~~~~~~
463
+src/lib/sync.ts:360:23 - warning ts(6133): 'mergeBase' is declared but its value is never read.
464
+
465
+360 const mergeBase = await git.raw(["merge-base", baseBranch, branchName]);
466
+   ~~~~~~~~~
467
+src/lib/sync.ts:267:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
468
+
469
+267 repositoryId: string,
470
+   ~~~~~~~~~~~~
471
+src/lib/sync.ts:57:15 - warning ts(6133): 'currentBranch' is declared but its value is never read.
472
+
473
+57 const currentBranch = status.current;
474
+   ~~~~~~~~~~~~~
475
+src/lib/sync.ts:10:1 - warning ts(6133): 'generateId' is declared but its value is never read.
476
+
477
+10 import { generateId } from "./utils";
478
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479
+src/lib/sync.ts:9:20 - warning ts(6133): 'getStackForPr' is declared but its value is never read.
480
+
481
+9 import { getStack, getStackForPr, addToStack, createStack } from "./stacks";
482
+   ~~~~~~~~~~~~~
483
+src/lib/sync.ts:6:19 - warning ts(6133): 'desc' is declared but its value is never read.
484
+
485
+6 import { eq, and, desc } from "drizzle-orm";
486
+   ~~~~
487
+
488
+src/lib/workflows.ts:26:92 - warning ts(6133): 'pusherId' is declared but its value is never read.
489
+
490
+26 export async function triggerRepoWorkflows(repoId: string, commitSha: string, ref: string, pusherId: string) {
491
+   ~~~~~~~~
492
+src/lib/workflows.ts:8:1 - warning ts(6133): 'existsSync' is declared but its value is never read.
493
+
494
+8 import { existsSync } from "fs";
495
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496
+
497
+src/pages/cli.astro:5:5 - warning ts(6133): 'Cpu' is declared but its value is never read.
498
+
499
+5 Cpu,
500
+   ~~~
501
+
502
+src/pages/explore.astro:4:20 - warning ts(6133): 'sql' is declared but its value is never read.
503
+
504
+4 import { desc, eq, sql, count } from "drizzle-orm";
505
+   ~~~
506
+
507
+src/pages/inbox.astro:28:5 - warning ts(6133): 'title' is declared but its value is never read.
508
+
509
+28 let title = "Inbox";
510
+   ~~~~~
511
+src/pages/inbox.astro:15:3 - warning ts(6133): 'Bot' is declared but its value is never read.
512
+
513
+15 Bot,
514
+   ~~~
515
+src/pages/inbox.astro:13:3 - warning ts(6133): 'Search' is declared but its value is never read.
516
+
517
+13 Search,
518
+   ~~~~~~
519
+src/pages/inbox.astro:5:29 - warning ts(6133): 'ne' is declared but its value is never read.
520
+
521
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
522
+   ~~
523
+src/pages/inbox.astro:5:25 - warning ts(6133): 'or' is declared but its value is never read.
524
+
525
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
526
+   ~~
527
+
528
+src/pages/insights.astro:11:3 - warning ts(6133): 'Calendar' is declared but its value is never read.
529
+
530
+11 Calendar,
531
+   ~~~~~~~~
532
+src/pages/insights.astro:4:30 - warning ts(6133): 'sql' is declared but its value is never read.
533
+
534
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
535
+   ~~~
536
+src/pages/insights.astro:4:14 - warning ts(6133): 'desc' is declared but its value is never read.
537
+
538
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
539
+   ~~~~
540
+
541
+src/pages/issues.astro:7:7 - warning ts(6133): 'currentUser' is declared but its value is never read.
542
+
543
+7 const currentUser = Astro.locals.user;
544
+   ~~~~~~~~~~~
545
+src/pages/issues.astro:4:25 - warning ts(6133): 'sql' is declared but its value is never read.
546
+
547
+4 import { desc, eq, and, sql } from "drizzle-orm";
548
+   ~~~
549
+src/pages/issues.astro:4:20 - warning ts(6133): 'and' is declared but its value is never read.
550
+
551
+4 import { desc, eq, and, sql } from "drizzle-orm";
552
+   ~~~
553
+
554
+src/pages/merge-queue.astro:353:56 - warning ts(6133): 'index' is declared but its value is never read.
555
+
556
+353 {queueItems.map((item, index) => {
557
+   ~~~~~
558
+src/pages/merge-queue.astro:222:10 - warning ts(6133): 'timeAgo' is declared but its value is never read.
559
+
560
+222 function timeAgo(date: string) {
561
+   ~~~~~~~
562
+src/pages/merge-queue.astro:73:5 - warning ts(6133): 'lastProcessedAt' is declared but its value is never read.
563
+
564
+73 let lastProcessedAt: string | null = null;
565
+   ~~~~~~~~~~~~~~~
566
+
567
+src/pages/password-reset.astro:95:13 - warning ts(6133): 'response' is declared but its value is never read.
568
+
569
+95 const response = await fetch("/api/auth/password-reset", {
570
+   ~~~~~~~~
571
+
572
+src/pages/repositories.astro:14:53 - warning ts(6133): 'Globe' is declared but its value is never read.
573
+
574
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
575
+   ~~~~~
576
+src/pages/repositories.astro:14:47 - warning ts(6133): 'Lock' is declared but its value is never read.
577
+
578
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
579
+   ~~~~
580
+src/pages/repositories.astro:5:1 - warning ts(6192): All imports in import declaration are unused.
581
+
582
+ 5 import {
583
+  ~~~~~~~~
584
+ 6 Card,
585
+  ~~~~~~~~
586
+...
587
+ 10 CardContent,
588
+  ~~~~~~~~~~~~~~~
589
+ 11 } from "@/components/ui/card";
590
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
591
+
592
+src/pages/stars.astro:152:54 - warning ts(6385): 'event' is deprecated.
593
+
594
+152 onclick="event.preventDefault(); event.stopPropagation();"
595
+   ~~~~~
596
+src/pages/stars.astro:152:30 - warning ts(6385): 'event' is deprecated.
597
+
598
+152 onclick="event.preventDefault(); event.stopPropagation();"
599
+   ~~~~~
600
+
601
+src/pages/[owner]/[repo]/index.astro:15:19 - warning ts(6133): 'sql' is declared but its value is never read.
602
+
603
+15 import { eq, and, sql, count } from "drizzle-orm";
604
+   ~~~
605
+src/pages/[owner]/[repo]/index.astro:12:3 - warning ts(6133): 'Clock' is declared but its value is never read.
606
+
607
+12 Clock,
608
+   ~~~~~
609
+src/pages/[owner]/[repo]/index.astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
610
+
611
+6 Tag,
612
+   ~~~
613
+
614
+src/pages/[owner]/[repo]/labels.astro:245:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
615
+
616
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
617
+
618
+Add the `is:inline` directive explicitly to silence this hint.
619
+
620
+245 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
621
+   ~~~~~~~~~~~
622
+
623
+src/pages/[owner]/[repo]/merge-queue.astro:248:57 - warning ts(6133): 'i' is declared but its value is never read.
624
+
625
+248 {item.stack.entries.map((entry, i) => (
626
+   ~
627
+src/pages/[owner]/[repo]/merge-queue.astro:13:3 - warning ts(6133): 'Play' is declared but its value is never read.
628
+
629
+13 Play,
630
+   ~~~~
631
+src/pages/[owner]/[repo]/merge-queue.astro:8:19 - warning ts(6133): 'sql' is declared but its value is never read.
632
+
633
+8 import { and, eq, sql, count } from "drizzle-orm";
634
+   ~~~
635
+
636
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:18:3 - warning ts(6133): 'Monitor' is declared but its value is never read.
637
+
638
+18 Monitor,
639
+   ~~~~~~~
640
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:13:3 - warning ts(6133): 'FileText' is declared but its value is never read.
641
+
642
+13 FileText,
643
+   ~~~~~~~~
644
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:337:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
645
+
646
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
647
+
648
+Add the `is:inline` directive explicitly to silence this hint.
649
+
650
+337 <script define:vars={{ initialContent: !fileData.isBinary ? fileData.content : "" }}>
651
+   ~~~~~~~~~~~
652
+
653
+src/pages/[owner]/[repo]/branches/index.astro:16:3 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
654
+
655
+16 AlertCircle,
656
+   ~~~~~~~~~~~
657
+src/pages/[owner]/[repo]/branches/index.astro:15:3 - warning ts(6133): 'Search' is declared but its value is never read.
658
+
659
+15 Search,
660
+   ~~~~~~
661
+src/pages/[owner]/[repo]/branches/index.astro:13:3 - warning ts(6133): 'MoreHorizontal' is declared but its value is never read.
662
+
663
+13 MoreHorizontal,
664
+   ~~~~~~~~~~~~~~
665
+src/pages/[owner]/[repo]/branches/index.astro:9:19 - warning ts(6133): 'sql' is declared but its value is never read.
666
+
667
+9 import { and, eq, sql, count } from "drizzle-orm";
668
+   ~~~
669
+src/pages/[owner]/[repo]/branches/index.astro:8:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
670
+
671
+8 import { getRepoPath } from "@/lib/utils";
672
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
673
+src/pages/[owner]/[repo]/branches/index.astro:351:42 - warning ts(6133): 'e' is declared but its value is never read.
674
+
675
+351 btn.addEventListener("click", async (e: any) => {
676
+   ~
677
+
678
+src/pages/[owner]/[repo]/commits/[...ref].astro:9:1 - warning ts(6133): 'Button' is declared but its value is never read.
679
+
680
+9 import { Button } from "@/components/ui/button";
681
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
682
+
683
+src/pages/[owner]/[repo]/edit/[...ref].astro:108:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
684
+
685
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
686
+
687
+Add the `is:inline` directive explicitly to silence this hint.
688
+
689
+108 <script define:vars={{ initialContent: fileContent, repoId: repo.id, branch: currentBranch, path: filePath, owner: repo.owner, repoName: repo.name }}>
690
+   ~~~~~~~~~~~
691
+
692
+src/pages/[owner]/[repo]/insights/index.astro:75:41 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
693
+
694
+75 repo.openIssueCount = issueCountResult?.count || 0;
695
+   ~~~~~
696
+src/pages/[owner]/[repo]/insights/index.astro:65:13 - error ts(2554): Expected 0 arguments, but got 1.
697
+
698
+65 .select({ count: sql<number>`count(*)` })
699
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700
+src/pages/[owner]/[repo]/insights/index.astro:276:69 - warning ts(6133): 'i' is declared but its value is never read.
701
+
702
+276 {contributors.map((contributor, i) => (
703
+   ~
704
+src/pages/[owner]/[repo]/insights/index.astro:84:7 - warning ts(6133): 'recentCommits' is declared but its value is never read.
705
+
706
+84 const recentCommits = await getCommits(repoData.diskPath, { limit: 20 });
707
+   ~~~~~~~~~~~~~
708
+src/pages/[owner]/[repo]/insights/index.astro:9:5 - warning ts(6133): 'GitCommit' is declared but its value is never read.
709
+
710
+9 GitCommit,
711
+   ~~~~~~~~~
712
+src/pages/[owner]/[repo]/insights/index.astro:5:24 - warning ts(6133): 'desc' is declared but its value is never read.
713
+
714
+5 import { eq, and, sql, desc, gte, count } from "drizzle-orm";
715
+   ~~~~
716
+
717
+src/pages/[owner]/[repo]/pulls/[number].astro:100:11 - error ts(2554): Expected 0 arguments, but got 1.
718
+
719
+100 .select({ count: sql<number>`count(*)` })
720
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
721
+src/pages/[owner]/[repo]/pulls/[number].astro:359:50 - warning ts(6133): 'i' is declared but its value is never read.
722
+
723
+359 {stackInfo.entries.map((entry, i) => {
724
+   ~
725
+src/pages/[owner]/[repo]/pulls/[number].astro:136:5 - warning ts(6133): 'mergeError' is declared but its value is never read.
726
+
727
+136 let mergeError = "";
728
+   ~~~~~~~~~~
729
+src/pages/[owner]/[repo]/pulls/[number].astro:24:3 - warning ts(6133): 'ChevronRight' is declared but its value is never read.
730
+
731
+24 ChevronRight,
732
+   ~~~~~~~~~~~~
733
+src/pages/[owner]/[repo]/pulls/[number].astro:16:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
734
+
735
+16 CheckCircle2,
736
+   ~~~~~~~~~~~~
737
+src/pages/[owner]/[repo]/pulls/[number].astro:13:29 - warning ts(6133): 'count' is declared but its value is never read.
738
+
739
+13 import { and, eq, sql, asc, count } from "drizzle-orm";
740
+   ~~~~~
741
+src/pages/[owner]/[repo]/pulls/[number].astro:419:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
742
+
743
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
744
+
745
+Add the `is:inline` directive explicitly to silence this hint.
746
+
747
+419 define:vars={{
748
+   ~~~~~~~~~~~
749
+
750
+src/pages/[owner]/[repo]/pulls/index.astro:41:11 - error ts(2554): Expected 0 arguments, but got 1.
751
+
752
+41 .select({ count: sql<number>`count(*)` })
753
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
754
+src/pages/[owner]/[repo]/pulls/index.astro:7:30 - warning ts(6133): 'count' is declared but its value is never read.
755
+
756
+7 import { and, desc, eq, sql, count } from "drizzle-orm";
757
+   ~~~~~
758
+
759
+src/pages/[owner]/[repo]/pulls/new.astro:99:11 - error ts(2554): Expected 0 arguments, but got 1.
760
+
761
+99 .select({ count: sql<number>`count(*)` })
762
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
763
+src/pages/[owner]/[repo]/pulls/new.astro:84:5 - warning ts(6133): 'canMerge' is declared but its value is never read.
764
+
765
+84 let canMerge = false;
766
+   ~~~~~~~~
767
+src/pages/[owner]/[repo]/pulls/new.astro:83:5 - warning ts(6133): 'error' is declared but its value is never read.
768
+
769
+83 let error = "";
770
+   ~~~~~
771
+src/pages/[owner]/[repo]/pulls/new.astro:25:3 - warning ts(6133): 'ArrowRight' is declared but its value is never read.
772
+
773
+25 ArrowRight,
774
+   ~~~~~~~~~~
775
+src/pages/[owner]/[repo]/pulls/new.astro:22:24 - warning ts(6133): 'count' is declared but its value is never read.
776
+
777
+22 import { and, eq, sql, count } from "drizzle-orm";
778
+   ~~~~~
779
+src/pages/[owner]/[repo]/pulls/new.astro:336:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
780
+
781
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
782
+
783
+Add the `is:inline` directive explicitly to silence this hint.
784
+
785
+336 define:vars={{
786
+   ~~~~~~~~~~~
787
+
788
+src/pages/[owner]/[repo]/security/index.astro:47:12 - error ts(2339): Property 'count' does not exist on type '{ id: string; repositoryId: string; number: number; title: string; body: string | null; state: string; authorId: string; assigneeId: string | null; milestoneId: string | null; isPinned: boolean | null; ... 7 more ...; updatedAt: string; }'.
789
+
790
+47 .get())?.count || 0;
791
+   ~~~~~
792
+src/pages/[owner]/[repo]/security/index.astro:39:11 - error ts(2554): Expected 0 arguments, but got 1.
793
+
794
+39 .select({ count: sql<number>`count(*)` })
795
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
796
+src/pages/[owner]/[repo]/security/index.astro:8:10 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
797
+
798
+8 import { AlertCircle, CheckCircle, Shield, Play, Loader2 } from "lucide-react";
799
+   ~~~~~~~~~~~
800
+src/pages/[owner]/[repo]/security/index.astro:202:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
801
+
802
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
803
+
804
+Add the `is:inline` directive explicitly to silence this hint.
805
+
806
+202 <script define:vars={{ repoOwner: repoInfo.owner, repoName: repoInfo.name }}>
807
+   ~~~~~~~~~~~
808
+
809
+src/pages/[owner]/[repo]/settings/collaborators.astro:83:10 - warning ts(6133): 'getRoleDescription' is declared but its value is never read.
810
+
811
+83 function getRoleDescription(role: string) {
812
+   ~~~~~~~~~~~~~~~~~~
813
+src/pages/[owner]/[repo]/settings/collaborators.astro:297:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
814
+
815
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
816
+
817
+Add the `is:inline` directive explicitly to silence this hint.
818
+
819
+297 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
820
+   ~~~~~~~~~~~
821
+
822
+src/pages/[owner]/[repo]/settings/index.astro:240:32 - error ts(18047): 'repo.isArchived' is possibly 'null'.
823
+
824
+240 data-archived={repo.isArchived.toString()}
825
+   ~~~~~~~~~~~~~~~
826
+src/pages/[owner]/[repo]/settings/index.astro:267:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
827
+
828
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
829
+
830
+Add the `is:inline` directive explicitly to silence this hint.
831
+
832
+267 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
833
+   ~~~~~~~~~~~
834
+
835
+src/pages/[owner]/[repo]/settings/webhooks.astro:326:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
836
+
837
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
838
+
839
+Add the `is:inline` directive explicitly to silence this hint.
840
+
841
+326 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
842
+   ~~~~~~~~~~~
843
+
844
+src/pages/[owner]/[repo]/settings/actions/runners.astro:15:18 - warning ts(6133): 'Terminal' is declared but its value is never read.
845
+
846
+15 import { Server, Terminal, Copy } from "lucide-react";
847
+   ~~~~~~~~
848
+src/pages/[owner]/[repo]/settings/actions/runners.astro:210:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
849
+
850
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
851
+
852
+Add the `is:inline` directive explicitly to silence this hint.
853
+
854
+210 <script define:vars={{ repoId: repoData.id }}>
855
+   ~~~~~~~~~~~
856
+
857
+src/pages/[owner]/[repo]/settings/branches/[id].astro:117:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
858
+
859
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
860
+
861
+Add the `is:inline` directive explicitly to silence this hint.
862
+
863
+117 <script define:vars={{ repoId: repository.id, ruleId: rule.id, owner, repo }}>
864
+   ~~~~~~~~~~~
865
+
866
+src/pages/[owner]/[repo]/settings/branches/index.astro:101:29 - error ts(2339): Property 'requireStatusChecks' does not exist on type '{ id: string; createdAt: string; updatedAt: string; repositoryId: string; active: boolean | null; createdById: string | null; pattern: string; requiresPr: boolean | null; requiredApprovals: number | null; dismissStaleReviews: boolean | null; requireCodeOwnerReviews: boolean | null; allowForcePushes: boolean | null; }'.
867
+
868
+101 {rule.requireStatusChecks ? "Required" : "Optional"}
869
+   ~~~~~~~~~~~~~~~~~~~
870
+src/pages/[owner]/[repo]/settings/branches/index.astro:5:14 - warning ts(6133): 'and' is declared but its value is never read.
871
+
872
+5 import { eq, and } from "drizzle-orm";
873
+   ~~~
874
+
875
+src/pages/[owner]/[repo]/settings/branches/new.astro:152:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
876
+
877
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
878
+
879
+Add the `is:inline` directive explicitly to silence this hint.
880
+
881
+152 <script define:vars={{ repoId: repository.id, owner, repo }}>
882
+   ~~~~~~~~~~~
883
+
884
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:5:19 - warning ts(6133): 'desc' is declared but its value is never read.
885
+
886
+5 import { eq, and, desc } from "drizzle-orm";
887
+   ~~~~
888
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:176:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
889
+
890
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
891
+
892
+Add the `is:inline` directive explicitly to silence this hint.
893
+
894
+176 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name, webhookId: webhook.id }}>
895
+   ~~~~~~~~~~~
896
+
897
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:12:5 - warning ts(6133): 'MoreVertical' is declared but its value is never read.
898
+
899
+12 MoreVertical,
900
+   ~~~~~~~~~~~~
901
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:11:5 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
902
+
903
+11 AlertCircle,
904
+   ~~~~~~~~~~~
905
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:210:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
906
+
907
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
908
+
909
+Add the `is:inline` directive explicitly to silence this hint.
910
+
911
+210 <script define:vars={{ repoId: repo.id }}>
912
+   ~~~~~~~~~~~
913
+
914
+src/pages/[owner]/[repo]/settings/webhooks/new.astro:187:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
915
+
916
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
917
+
918
+Add the `is:inline` directive explicitly to silence this hint.
919
+
920
+187 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name }}>
921
+   ~~~~~~~~~~~
922
+
923
+src/pages/[owner]/[repo]/tree/[...ref].astro:60:11 - error ts(2554): Expected 0 arguments, but got 1.
924
+
925
+60 .select({ count: sql<number>`count(*)` })
926
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
927
+src/pages/[owner]/[repo]/tree/[...ref].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
928
+
929
+6 Tag,
930
+   ~~~
931
+
932
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:53:11 - error ts(2554): Expected 0 arguments, but got 1.
933
+
934
+53 .select({ count: sql<number>`count(*)` })
935
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
936
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:11:3 - warning ts(6133): 'FileText' is declared but its value is never read.
937
+
938
+11 FileText,
939
+   ~~~~~~~~
940
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
941
+
942
+6 Tag,
943
+   ~~~
944
+
945
+src/pages/admin/audit.astro:72:13 - error ts(2554): Expected 0 arguments, but got 1.
946
+
947
+72 .select({ count: sql<number>`count(*)` })
948
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
949
+src/pages/admin/audit.astro:18:3 - warning ts(6133): 'ExternalLink' is declared but its value is never read.
950
+
951
+18 ExternalLink,
952
+   ~~~~~~~~~~~~
953
+src/pages/admin/audit.astro:4:27 - warning ts(6133): 'eq' is declared but its value is never read.
954
+
955
+4 import { desc, sql, like, eq, or } from "drizzle-orm";
956
+   ~~
957
+
958
+src/pages/admin/repositories.astro:47:13 - error ts(2554): Expected 0 arguments, but got 1.
959
+
960
+47 .select({ count: sql<number>`count(*)` })
961
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
962
+src/pages/admin/repositories.astro:4:16 - warning ts(6133): 'eq' is declared but its value is never read.
963
+
964
+4 import { desc, eq, like, or, sql } from "drizzle-orm";
965
+   ~~
966
+
967
+src/pages/admin/users.astro:236:24 - error ts(2304): Cannot find name 'ChevronRight'.
968
+
969
+236 <ChevronRight className="h-4 w-4" />
970
+   ~~~~~~~~~~~~
971
+src/pages/admin/users.astro:228:24 - error ts(2304): Cannot find name 'ChevronLeft'.
972
+
973
+228 <ChevronLeft className="h-4 w-4" />
974
+   ~~~~~~~~~~~
975
+src/pages/admin/users.astro:206:32 - error ts(2304): Cannot find name 'Ban'.
976
+
977
+206 <Ban className="h-4 w-4" />
978
+   ~~~
979
+src/pages/admin/users.astro:198:32 - error ts(2304): Cannot find name 'Shield'.
980
+
981
+198 <Shield className="h-4 w-4" />
982
+   ~~~~~~
983
+src/pages/admin/users.astro:179:28 - error ts(2304): Cannot find name 'Shield'.
984
+
985
+179 <Shield className="h-3 w-3" /> Admin
986
+   ~~~~~~
987
+src/pages/admin/users.astro:172:28 - error ts(2304): Cannot find name 'Ban'.
988
+
989
+172 <Ban className="h-3 w-3" /> Banned
990
+   ~~~
991
+src/pages/admin/users.astro:168:28 - error ts(2304): Cannot find name 'CheckCircle'.
992
+
993
+168 <CheckCircle className="h-3 w-3" /> Active
994
+   ~~~~~~~~~~~
995
+src/pages/admin/users.astro:115:12 - error ts(2304): Cannot find name 'Search'.
996
+
997
+115 <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
998
+   ~~~~~~
999
+src/pages/admin/users.astro:106:58 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1000
+
1001
+106 <p class="text-2xl font-bold">{adminUsers?.count || 0}</p>
1002
+   ~~~~~
1003
+src/pages/admin/users.astro:102:16 - error ts(2304): Cannot find name 'Shield'.
1004
+
1005
+102 <Shield className="h-5 w-5 text-orange-500" />
1006
+   ~~~~~~
1007
+src/pages/admin/users.astro:95:59 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1008
+
1009
+95 <p class="text-2xl font-bold">{activeUsers?.count || 0}</p>
1010
+   ~~~~~
1011
+src/pages/admin/users.astro:91:16 - error ts(2304): Cannot find name 'CheckCircle'.
1012
+
1013
+91 <CheckCircle className="h-5 w-5 text-green-500" />
1014
+   ~~~~~~~~~~~
1015
+src/pages/admin/users.astro:84:58 - error ts(2339): Property 'count' does not exist on type '{ id: string; username: string; email: string; passwordHash: string | null; displayName: string | null; bio: string | null; avatarUrl: string | null; location: string | null; website: string | null; ... 8 more ...; updatedAt: string; }'.
1016
+
1017
+84 <p class="text-2xl font-bold">{totalUsers?.count || 0}</p>
1018
+   ~~~~~
1019
+src/pages/admin/users.astro:54:13 - error ts(2554): Expected 0 arguments, but got 1.
1020
+
1021
+54 db.select({ count: sql<number>`count(*)` }).from(schema.users).where(eq(schema.users.isAdmin, true)).get(),
1022
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1023
+src/pages/admin/users.astro:53:13 - error ts(2554): Expected 0 arguments, but got 1.
1024
+
1025
+53 db.select({ count: sql<number>`count(*)` }).from(schema.users).where(eq(schema.users.isActive, true)).get(),
1026
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1027
+src/pages/admin/users.astro:52:13 - error ts(2554): Expected 0 arguments, but got 1.
1028
+
1029
+52 db.select({ count: sql<number>`count(*)` }).from(schema.users).get(),
1030
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1031
+src/pages/admin/users.astro:41:13 - error ts(2554): Expected 0 arguments, but got 1.
1032
+
1033
+41 db.select({ count: sql<number>`count(*)` })
1034
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1035
+src/pages/admin/users.astro:8:90 - error ts(2304): Cannot find name 'from'.
1036
+
1037
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1038
+   ~~~~
1039
+src/pages/admin/users.astro:8:75 - error ts(2304): Cannot find name 'ChevronRight'.
1040
+
1041
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1042
+   ~~~~~~~~~~~~
1043
+src/pages/admin/users.astro:8:62 - error ts(2304): Cannot find name 'ChevronLeft'.
1044
+
1045
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1046
+   ~~~~~~~~~~~
1047
+src/pages/admin/users.astro:8:54 - error ts(2304): Cannot find name 'Search'.
1048
+
1049
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1050
+   ~~~~~~
1051
+src/pages/admin/users.astro:8:41 - error ts(2304): Cannot find name 'CheckCircle'.
1052
+
1053
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1054
+   ~~~~~~~~~~~
1055
+src/pages/admin/users.astro:8:36 - error ts(2304): Cannot find name 'Ban'.
1056
+
1057
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1058
+   ~~~
1059
+src/pages/admin/users.astro:8:28 - error ts(2304): Cannot find name 'Shield'.
1060
+
1061
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1062
+   ~~~~~~
1063
+src/pages/admin/users.astro:8:17 - error ts(2695): Left side of comma operator is unused and has no side effects.
1064
+
1065
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1066
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1067
+src/pages/admin/users.astro:8:17 - error ts(2695): Left side of comma operator is unused and has no side effects.
1068
+
1069
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1070
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1071
+src/pages/admin/users.astro:8:17 - error ts(2695): Left side of comma operator is unused and has no side effects.
1072
+
1073
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1074
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1075
+src/pages/admin/users.astro:8:17 - error ts(2695): Left side of comma operator is unused and has no side effects.
1076
+
1077
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1078
+   ~~~~~~~~~~~~~~~~~~~~~~
1079
+src/pages/admin/users.astro:8:17 - error ts(2695): Left side of comma operator is unused and has no side effects.
1080
+
1081
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1082
+   ~~~~~~~~~~~~~~~~~
1083
+src/pages/admin/users.astro:8:17 - error ts(2695): Left side of comma operator is unused and has no side effects.
1084
+
1085
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1086
+   ~~~~~~~~~
1087
+src/pages/admin/users.astro:8:17 - error ts(2304): Cannot find name 'UsersIcon'.
1088
+
1089
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1090
+   ~~~~~~~~~
1091
+src/pages/admin/users.astro:8:14 - error ts(2503): Cannot find namespace 'as'.
1092
+
1093
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1094
+   ~~
1095
+src/pages/admin/users.astro:8:14 - error ts(2304): Cannot find name 'as'.
1096
+
1097
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1098
+   ~~
1099
+src/pages/admin/users.astro:8:90 - error ts(1434): Unexpected keyword or identifier.
1100
+
1101
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1102
+   ~~~~
1103
+src/pages/admin/users.astro:8:88 - error ts(1128): Declaration or statement expected.
1104
+
1105
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1106
+   ~
1107
+src/pages/admin/users.astro:8:17 - error ts(1005): ';' expected.
1108
+
1109
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1110
+   ~~~~~~~~~
1111
+src/pages/admin/users.astro:8:14 - error ts(1005): '=' expected.
1112
+
1113
+8 import Users as UsersIcon, Shield, Ban, CheckCircle, Search, ChevronLeft, ChevronRight } from "lucide-react";
1114
+   ~~
1115
+
1116
+src/pages/api/ai-review-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1117
+
1118
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1119
+   ~~~~~~
1120
+
1121
+src/pages/api/automation-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1122
+
1123
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1124
+   ~~~~~~
1125
+src/pages/api/automation-rules.ts:7:14 - warning ts(6133): 'and' is declared but its value is never read.
1126
+
1127
+7 import { eq, and } from "drizzle-orm";
1128
+   ~~~
1129
+
1130
+src/pages/api/inbox-sections.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1131
+
1132
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1133
+   ~~~~~~
1134
+
1135
+src/pages/api/search.ts:3:20 - warning ts(6133): 'eq' is declared but its value is never read.
1136
+
1137
+3 import { like, or, eq, desc } from 'drizzle-orm';
1138
+   ~~
1139
+
1140
+src/pages/api/actions/trigger-test.ts:10:1 - warning ts(6133): 'eq' is declared but its value is never read.
1141
+
1142
+10 import { eq } from "drizzle-orm";
1143
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1144
+src/pages/api/actions/trigger-test.ts:8:57 - warning ts(6133): 'notFound' is declared but its value is never read.
1145
+
1146
+8 import { success, unauthorized, serverError, parseBody, notFound } from '@/lib/api';
1147
+   ~~~~~~~~
1148
+
1149
+src/pages/api/realtime/events.ts:28:48 - warning ts(6133): 'request' is declared but its value is never read.
1150
+
1151
+28 export const POST: APIRoute = async ({ locals, request }) => {
1152
+   ~~~~~~~
1153
+
1154
+src/pages/api/repos/[owner]/[repo]/protection.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1155
+
1156
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1157
+   ~~~~~~~~~~
1158
+
1159
+src/pages/api/repos/[owner]/[repo]/git/push.ts:142:26 - warning ts(6133): 'sha' is declared but its value is never read.
1160
+
1161
+142 for (const { sha, ref } of bundleRefs) {
1162
+   ~~~
1163
+src/pages/api/repos/[owner]/[repo]/git/push.ts:22:22 - warning ts(6133): 'mkdirSync' is declared but its value is never read.
1164
+
1165
+22 import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "fs";
1166
+   ~~~~~~~~~
1167
+src/pages/api/repos/[owner]/[repo]/git/push.ts:18:5 - warning ts(6133): 'getDiskPath' is declared but its value is never read.
1168
+
1169
+18 getDiskPath,
1170
+   ~~~~~~~~~~~
1171
+src/pages/api/repos/[owner]/[repo]/git/push.ts:13:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
1172
+
1173
+13 import { getRepoPath } from "@/lib/utils";
1174
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1175
+
1176
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:30 - warning ts(6133): 'number' is declared but its value is never read.
1177
+
1178
+210 const { owner, repo, number, commentId } = params;
1179
+   ~~~~~~
1180
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:24 - warning ts(6133): 'repo' is declared but its value is never read.
1181
+
1182
+210 const { owner, repo, number, commentId } = params;
1183
+   ~~~~
1184
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:30 - warning ts(6133): 'number' is declared but its value is never read.
1185
+
1186
+163 const { owner, repo, number, commentId } = params;
1187
+   ~~~~~~
1188
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:24 - warning ts(6133): 'repo' is declared but its value is never read.
1189
+
1190
+163 const { owner, repo, number, commentId } = params;
1191
+   ~~~~
1192
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:99:24 - warning ts(6133): 'repo' is declared but its value is never read.
1193
+
1194
+99 const { owner, repo, number } = params;
1195
+   ~~~~
1196
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:37:24 - warning ts(6133): 'repo' is declared but its value is never read.
1197
+
1198
+37 const { owner, repo, number } = params;
1199
+   ~~~~
1200
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1201
+
1202
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1203
+   ~~~~~~~~~~
1204
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:7:25 - warning ts(6133): 'isNull' is declared but its value is never read.
1205
+
1206
+7 import { eq, and, desc, isNull } from "drizzle-orm";
1207
+   ~~~~~~
1208
+
1209
+src/pages/api/stacks/index.ts:26:6 - warning ts(6196): 'CreateStackInput' is declared but never used.
1210
+
1211
+26 type CreateStackInput = z.infer<typeof createStackSchema>;
1212
+   ~~~~~~~~~~~~~~~~
1213
+src/pages/api/stacks/index.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1214
+
1215
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1216
+   ~~~~~~~~~~
1217
+
1218
+src/pages/api/user/notification-preferences.ts:12:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1219
+
1220
+12 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1221
+   ~~~~~~
1222
+
1223
+src/pages/api/user/tokens.ts:103:24 - warning ts(6133): 'prefix' is declared but its value is never read.
1224
+
1225
+103 const { token, prefix } = generateToken();
1226
+   ~~~~~~
1227
+src/pages/api/user/tokens.ts:79:34 - warning ts(6133): 'scopes' is declared but its value is never read.
1228
+
1229
+79 const { name, expiresIn, scopes } = parsed.data;
1230
+   ~~~~~~
1231
+src/pages/api/user/tokens.ts:26:10 - warning ts(6133): 'hashToken' is declared but its value is never read.
1232
+
1233
+26 function hashToken(token: string): string {
1234
+   ~~~~~~~~~
1235
+src/pages/api/user/tokens.ts:8:23 - warning ts(6133): 'schema' is declared but its value is never read.
1236
+
1237
+8 import { getDatabase, schema } from "@/db";
1238
+   ~~~~~~
1239
+
1240
+src/pages/settings/ai-review-rules.astro:19:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
1241
+
1242
+19 CheckCircle2,
1243
+   ~~~~~~~~~~~~
1244
+src/pages/settings/ai-review-rules.astro:4:14 - warning ts(6133): 'and' is declared but its value is never read.
1245
+
1246
+4 import { eq, and, desc } from "drizzle-orm";
1247
+   ~~~
1248
+src/pages/settings/ai-review-rules.astro:475:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1249
+
1250
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1251
+
1252
+Add the `is:inline` directive explicitly to silence this hint.
1253
+
1254
+475 <script define:vars={{ repoId }}>
1255
+   ~~~~~~~~~~~
1256
+
1257
+src/pages/settings/automations.astro:301:61 - warning ts(6133): 'i' is declared but its value is never read.
1258
+
1259
+301 {actions.slice(0, 3).map((action, i) => (
1260
+   ~
1261
+src/pages/settings/automations.astro:437:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1262
+
1263
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1264
+
1265
+Add the `is:inline` directive explicitly to silence this hint.
1266
+
1267
+437 <script define:vars={{ repoId }}>
1268
+   ~~~~~~~~~~~
1269
+
1270
+Result (300 files):
1271
+- 50 errors
1272
+- 0 warnings
1273
+- 223 hints
1274
+
0
1275
▼lint_output_final.txt
+1082-0
1
+
2
3
+> astro check
4
+
5
+14:32:33 [types] Generated 34ms
6
+14:32:33 [check] Getting diagnostics for Astro files in /home/swadhin/owngit/OpenCodeHub...
7
+src/components/admin/AdminDashboard.tsx:141:30 - warning ts(6385): 'Github' is deprecated.
8
+
9
+141 <Github className="h-8 w-8 text-white opacity-30 hover:opacity-70 transition-opacity cursor-pointer" />
10
+   ~~~~~~
11
+src/components/admin/AdminDashboard.tsx:10:10 - warning ts(6385): 'Github' is deprecated.
12
+
13
+10 import { Github } from "lucide-react";
14
+   ~~~~~~
15
+
16
+src/components/admin/AlertBanner.tsx:2:44 - warning ts(6133): 'Bell' is declared but its value is never read.
17
+
18
+2 import { AlertTriangle, CheckCircle, Info, Bell, X } from "lucide-react";
19
+   ~~~~
20
+
21
+src/components/admin/DashboardStats.tsx:1:45 - warning ts(6133): 'useTransform' is declared but its value is never read.
22
+
23
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
24
+   ~~~~~~~~~~~~
25
+src/components/admin/DashboardStats.tsx:1:34 - warning ts(6133): 'useSpring' is declared but its value is never read.
26
+
27
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
28
+   ~~~~~~~~~
29
+src/components/admin/DashboardStats.tsx:1:18 - warning ts(6133): 'useMotionValue' is declared but its value is never read.
30
+
31
+1 import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
32
+   ~~~~~~~~~~~~~~
33
+
34
+src/components/admin/GlobeViz.tsx:199:27 - warning ts(6133): 'activities' is declared but its value is never read.
35
+
36
+199 function CSSGlobeFallback({ activities = [] }: Props) {
37
+   ~~~~~~~~~~~~~~~~~~~
38
+src/components/admin/GlobeViz.tsx:89:54 - warning ts(6133): 'i' is declared but its value is never read.
39
+
40
+89 markers: activities.slice(0, 20).map((_, i) => ({
41
+   ~
42
+
43
+src/components/admin/QuickStatsRow.tsx:2:78 - warning ts(6133): 'Zap' is declared but its value is never read.
44
+
45
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
46
+   ~~~
47
+src/components/admin/QuickStatsRow.tsx:2:68 - warning ts(6133): 'Activity' is declared but its value is never read.
48
+
49
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
50
+   ~~~~~~~~
51
+src/components/admin/QuickStatsRow.tsx:2:49 - warning ts(6133): 'Clock' is declared but its value is never read.
52
+
53
+2 import { GitCommit, GitMerge, CircleDot, Users, Clock, TrendingUp, Activity, Zap } from "lucide-react";
54
+   ~~~~~
55
+
56
+src/components/admin/SystemStatus.tsx:18:5 - warning ts(6133): 'color' is declared but its value is never read.
57
+
58
+18 color,
59
+   ~~~~~
60
+src/components/admin/SystemStatus.tsx:1:47 - warning ts(6133): 'Server' is declared but its value is never read.
61
+
62
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
63
+   ~~~~~~
64
+src/components/admin/SystemStatus.tsx:1:41 - warning ts(6133): 'Wifi' is declared but its value is never read.
65
+
66
+1 import { HardDrive, Cpu, Zap, Activity, Wifi, Server } from "lucide-react";
67
+   ~~~~
68
+
69
+src/components/dashboard/ActivityStream.tsx:80:55 - warning ts(6133): 'i' is declared but its value is never read.
70
+
71
+80 {users.slice(0, 5).map((user, i) => (
72
+   ~
73
+src/components/dashboard/ActivityStream.tsx:2:1 - warning ts(6133): 'React' is declared but its value is never read.
74
+
75
+2 import * as React from "react";
76
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
+
78
+src/components/git/CommitGraph.tsx:209:35 - warning ts(6133): 'index' is declared but its value is never read.
79
+
80
+209 {commits.map((commit, index) => {
81
+   ~~~~~
82
+src/components/git/CommitGraph.tsx:51:11 - warning ts(6133): 'branchHeads' is declared but its value is never read.
83
+
84
+51 const branchHeads: Map<string, string> = new Map()
85
+   ~~~~~~~~~~~
86
+
87
+src/components/home/HeroSection.tsx:87:26 - warning ts(6385): 'Github' is deprecated.
88
+
89
+87 <Github className="h-4 w-4" />
90
+   ~~~~~~
91
+src/components/home/HeroSection.tsx:6:22 - warning ts(6385): 'Github' is deprecated.
92
+
93
+6 import { ArrowRight, Github, Star, GitBranch, Zap } from "lucide-react";
94
+   ~~~~~~
95
+src/components/home/HeroSection.tsx:4:1 - warning ts(6133): 'ColourfulText' is declared but its value is never read.
96
+
97
+4 import { ColourfulText } from "@/components/ui/colourful-text";
98
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
+
100
+src/components/issues/IssueDetail.tsx:68:67 - warning ts(6133): 'repoName' is declared but its value is never read.
101
+
102
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
103
+   ~~~~~~~~
104
+src/components/issues/IssueDetail.tsx:68:56 - warning ts(6133): 'repoOwner' is declared but its value is never read.
105
+
106
+68 export default function IssueDetail({ issue, bodyHtml, repoOwner, repoName }: Props) {
107
+   ~~~~~~~~~
108
+
109
+src/components/issues/IssuesList.tsx:14:5 - warning ts(6133): 'Filter' is declared but its value is never read.
110
+
111
+14 Filter
112
+   ~~~~~~
113
+
114
+src/components/layout/Header.astro:2:10 - warning ts(6133): 'GitBranch' is declared but its value is never read.
115
+
116
+2 import { GitBranch, Search, Bell, Plus, Menu } from "lucide-react"
117
+   ~~~~~~~~~
118
+
119
+src/components/pr/AIReviewPanel.tsx:76:5 - warning ts(6133): 'reviewId' is declared but its value is never read.
120
+
121
+76 reviewId,
122
+   ~~~~~~~~
123
+src/components/pr/AIReviewPanel.tsx:6:8 - warning ts(6133): 'React' is declared but its value is never read.
124
+
125
+6 import React, { useState } from "react";
126
+   ~~~~~
127
+
128
+src/components/pr/StackVisualization.tsx:52:5 - warning ts(6133): 'onReorder' is declared but its value is never read.
129
+
130
+52 onReorder,
131
+   ~~~~~~~~~
132
+src/components/pr/StackVisualization.tsx:45:5 - warning ts(6133): 'stackId' is declared but its value is never read.
133
+
134
+45 stackId,
135
+   ~~~~~~~
136
+
137
+src/components/pulls/PullRequestsList.tsx:14:5 - warning ts(6133): 'Sparkles' is declared but its value is never read.
138
+
139
+14 Sparkles,
140
+   ~~~~~~~~
141
+
142
+src/components/repo/FileExplorer.astro:2:20 - warning ts(6133): 'Folder' is declared but its value is never read.
143
+
144
+2 import { FileText, Folder } from "lucide-react";
145
+   ~~~~~~
146
+
147
+src/components/repo/RepoHeader.astro:3:3 - warning ts(6133): 'GitBranch' is declared but its value is never read.
148
+
149
+3 GitBranch,
150
+   ~~~~~~~~~
151
+
152
+src/components/search/GlobalSearch.tsx:17:12 - warning ts(6133): 'loading' is declared but its value is never read.
153
+
154
+17 const [loading, setLoading] = React.useState(false);
155
+   ~~~~~~~
156
+src/components/search/GlobalSearch.tsx:11:18 - warning ts(6133): 'FileText' is declared but its value is never read.
157
+
158
+11 import { Search, FileText, User, GitBranch, GitPullRequest, CircleDot, Workflow } from "lucide-react";
159
+   ~~~~~~~~
160
+
161
+src/components/ui/animated-tooltip.tsx:4:8 - warning ts(6133): 'React' is declared but its value is never read.
162
+
163
+4 import React, { useState } from "react";
164
+   ~~~~~
165
+src/components/ui/animated-tooltip.tsx:2:1 - warning ts(6133): 'cn' is declared but its value is never read.
166
+
167
+2 import { cn } from "@/lib/cn";
168
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
+
170
+src/components/ui/text-generate-effect.tsx:2:29 - warning ts(6133): 'useState' is declared but its value is never read.
171
+
172
+2 import { useEffect, useRef, useState } from "react";
173
+   ~~~~~~~~
174
+src/components/ui/text-generate-effect.tsx:2:21 - warning ts(6133): 'useRef' is declared but its value is never read.
175
+
176
+2 import { useEffect, useRef, useState } from "react";
177
+   ~~~~~~
178
+
179
+src/components/ui/text-reveal-card.tsx:3:29 - warning ts(6133): 'useTransform' is declared but its value is never read.
180
+
181
+3 import { motion, useScroll, useTransform } from "framer-motion";
182
+   ~~~~~~~~~~~~
183
+src/components/ui/text-reveal-card.tsx:3:18 - warning ts(6133): 'useScroll' is declared but its value is never read.
184
+
185
+3 import { motion, useScroll, useTransform } from "framer-motion";
186
+   ~~~~~~~~~
187
+
188
+src/db/seed-activity.ts:6:1 - warning ts(6133): 'eq' is declared but its value is never read.
189
+
190
+6 import { eq } from "drizzle-orm";
191
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
+src/db/seed-activity.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
193
+
194
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
195
+   ~~~~~
196
+src/db/seed-activity.ts:3:10 - warning ts(6133): 'repositories' is declared but its value is never read.
197
+
198
+3 import { repositories, users, pullRequests, pullRequestReviews, pullRequestComments } from "@/db/schema";
199
+   ~~~~~~~~~~~~
200
+
201
+src/db/seed-notifications.ts:5:32 - warning ts(6133): 'repositories' is declared but its value is never read.
202
+
203
+5 import { notifications, users, repositories } from "@/db/schema";
204
+   ~~~~~~~~~~~~
205
+src/db/seed-notifications.ts:5:25 - warning ts(6133): 'users' is declared but its value is never read.
206
+
207
+5 import { notifications, users, repositories } from "@/db/schema";
208
+   ~~~~~
209
+
210
+src/db/seed-scale.ts:25:11 - warning ts(6133): 'reposPath' is declared but its value is never read.
211
+
212
+25 const reposPath = process.env.GIT_REPOS_PATH || "./data/repos";
213
+   ~~~~~~~~~
214
+src/db/seed-scale.ts:9:1 - warning ts(6133): 'fs' is declared but its value is never read.
215
+
216
+9 import fs from "fs/promises";
217
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
+src/db/seed-scale.ts:7:1 - warning ts(6133): 'eq' is declared but its value is never read.
219
+
220
+7 import { eq } from "drizzle-orm";
221
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222
+src/db/seed-scale.ts:3:24 - warning ts(6133): 'users' is declared but its value is never read.
223
+
224
+3 import { repositories, users } from "@/db/schema";
225
+   ~~~~~
226
+
227
+src/db/schema/developer-metrics.ts:7:19 - warning ts(6133): 'real' is declared but its value is never read.
228
+
229
+7 import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
230
+   ~~~~
231
+
232
+src/db/schema/pipeline-runners.ts:3:10 - warning ts(6133): 'integer' is declared but its value is never read.
233
+
234
+3 import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
235
+   ~~~~~~~
236
+
237
+src/db/schema/pull-requests.ts:8:18 - warning ts(6133): 'milestones' is declared but its value is never read.
238
+
239
+8 import { labels, milestones } from "./issues";
240
+   ~~~~~~~~~~
241
+
242
+src/db/schema/security.ts:3:1 - warning ts(6133): 'users' is declared but its value is never read.
243
+
244
+3 import { users } from "./users";
245
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246
+
247
+src/lib/ai-review.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
248
+
249
+6 import { eq, and, desc } from "drizzle-orm";
250
+   ~~~
251
+
252
+src/lib/analysis.ts:35:87 - warning ts(6133): 'force' is declared but its value is never read.
253
+
254
+35 export async function analyzeRepository(repoId: string, userId: string | null = null, force = false) {
255
+   ~~~~~
256
+src/lib/analysis.ts:4:22 - warning ts(6133): 'getRepoSize' is declared but its value is never read.
257
+
258
+4 import { getCommits, getRepoSize, listFiles, getCommitDiff } from "./git";
259
+   ~~~~~~~~~~~
260
+
261
+src/lib/auth.ts:281:22 - warning ts(6133): 'gt' is declared but its value is never read.
262
+
263
+281 const { eq, and, gt } = await import("drizzle-orm");
264
+   ~~
265
+src/lib/auth.ts:281:17 - warning ts(6133): 'and' is declared but its value is never read.
266
+
267
+281 const { eq, and, gt } = await import("drizzle-orm");
268
+   ~~~
269
+src/lib/auth.ts:280:35 - warning ts(6133): 'users' is declared but its value is never read.
270
+
271
+280 const { personalAccessTokens, users } = await import("@/db/schema/users");
272
+   ~~~~~
273
+
274
+src/lib/automations.ts:320:23 - warning ts(6133): 'notifyPrEvent' is declared but its value is never read.
275
+
276
+320 const { notifyPrEvent } = await import("./slack-notifications");
277
+   ~~~~~~~~~~~~~~~~~
278
+
279
+src/lib/conflict-automation.ts:11:1 - warning ts(6192): All imports in import declaration are unused.
280
+
281
+11 import { notifyPrEvent, notifyUserDm } from "./slack-notifications";
282
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283
+src/lib/conflict-automation.ts:6:14 - warning ts(6133): 'and' is declared but its value is never read.
284
+
285
+6 import { eq, and } from "drizzle-orm";
286
+   ~~~
287
+
288
+src/lib/developer-metrics.ts:6:35 - warning ts(6133): 'lte' is declared but its value is never read.
289
+
290
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
291
+   ~~~
292
+src/lib/developer-metrics.ts:6:30 - warning ts(6133): 'gte' is declared but its value is never read.
293
+
294
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
295
+   ~~~
296
+src/lib/developer-metrics.ts:6:25 - warning ts(6133): 'sql' is declared but its value is never read.
297
+
298
+6 import { eq, and, desc, sql, gte, lte } from "drizzle-orm";
299
+   ~~~
300
+
301
+src/lib/git-storage.ts:15:27 - warning ts(6133): 'StorageAdapter' is declared but its value is never read.
302
+
303
+15 import { getStorage, type StorageAdapter } from "./storage";
304
+   ~~~~~~~~~~~~~~
305
+src/lib/git-storage.ts:14:1 - warning ts(6133): 'Readable' is declared but its value is never read.
306
+
307
+14 import { Readable } from "stream";
308
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309
+src/lib/git-storage.ts:10:54 - warning ts(6133): 'statSync' is declared but its value is never read.
310
+
311
+10 import { existsSync, mkdirSync, rmSync, readdirSync, statSync } from "fs";
312
+   ~~~~~~~~
313
+
314
+src/lib/git.ts:1171:32 - warning ts(6133): 'reject' is declared but its value is never read.
315
+
316
+1171 return new Promise((resolve, reject) => {
317
+   ~~~~~~
318
+src/lib/git.ts:14:3 - warning ts(6133): 'releaseRepo' is declared but its value is never read.
319
+
320
+14 releaseRepo,
321
+   ~~~~~~~~~~~
322
+src/lib/git.ts:13:3 - warning ts(6133): 'acquireRepo' is declared but its value is never read.
323
+
324
+13 acquireRepo,
325
+   ~~~~~~~~~~~
326
+
327
+src/lib/lfs.ts:64:3 - warning ts(6133): 'repoDiskPath' is declared but its value is never read.
328
+
329
+64 repoDiskPath: string,
330
+   ~~~~~~~~~~~~
331
+
332
+src/lib/merge-queue.ts:11:1 - warning ts(6133): 'emitQueueEvent' is declared but its value is never read.
333
+
334
+11 import { emitQueueEvent } from "./realtime";
335
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336
+src/lib/merge-queue.ts:6:34 - warning ts(6133): 'gt' is declared but its value is never read.
337
+
338
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
339
+   ~~
340
+src/lib/merge-queue.ts:6:30 - warning ts(6133): 'lt' is declared but its value is never read.
341
+
342
+6 import { eq, and, asc, desc, lt, gt } from "drizzle-orm";
343
+   ~~
344
+
345
+src/lib/pipeline.ts:292:15 - warning ts(6133): 'tag' is declared but its value is never read.
346
+
347
+292 const tag = payload.ref.replace("refs/tags/", "");
348
+   ~~~
349
+src/lib/pipeline.ts:238:11 - warning ts(6133): 'artifactsDir' is declared but its value is never read.
350
+
351
+238 private artifactsDir: string;
352
+   ~~~~~~~~~~~~
353
+src/lib/pipeline.ts:237:11 - warning ts(6133): 'workDir' is declared but its value is never read.
354
+
355
+237 private workDir: string;
356
+   ~~~~~~~
357
+
358
+src/lib/realtime.ts:49:61 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
359
+
360
+49 return `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
361
+   ~~~~~~
362
+
363
+src/lib/security.ts:116:15 - warning ts(6133): 'rawOutput' is declared but its value is never read.
364
+
365
+116 const rawOutput = logsBuffer.toString("utf-8");
366
+   ~~~~~~~~~
367
+src/lib/security.ts:76:15 - warning ts(6133): 'stream' is declared but its value is never read.
368
+
369
+76 const stream = await container.logs({ follow: true, stdout: true, stderr: true });
370
+   ~~~~~~
371
+src/lib/security.ts:56:15 - warning ts(6133): 'chunks' is declared but its value is never read.
372
+
373
+56 const chunks: Buffer[] = [];
374
+   ~~~~~~
375
+src/lib/security.ts:48:41 - warning ts(6133): 'event' is declared but its value is never read.
376
+
377
+48 function onProgress(event: any) { }
378
+   ~~~~~
379
+src/lib/security.ts:44:51 - warning ts(6133): 'output' is declared but its value is never read.
380
+
381
+44 function onFinished(err: any, output: any) {
382
+   ~~~~~~
383
+src/lib/security.ts:40:41 - warning ts(6133): 'reject' is declared but its value is never read.
384
+
385
+40 await new Promise((resolve, reject) => {
386
+   ~~~~~~
387
+src/lib/security.ts:15:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
388
+
389
+15 repositoryId: string
390
+   ~~~~~~~~~~~~
391
+src/lib/security.ts:5:21 - warning ts(6133): 'writeFile' is declared but its value is never read.
392
+
393
+5 import { mkdir, rm, writeFile } from "fs/promises";
394
+   ~~~~~~~~~
395
+
396
+src/lib/slack-notifications.ts:257:5 - warning ts(6133): 'event' is declared but its value is never read.
397
+
398
+257 event: string,
399
+   ~~~~~
400
+
401
+src/lib/ssh.ts:190:32 - warning ts(6133): 'accept' is declared but its value is never read.
402
+
403
+190 session.on("shell", (accept, reject) => {
404
+   ~~~~~~
405
+src/lib/ssh.ts:78:39 - warning ts(6133): 'reject' is declared but its value is never read.
406
+
407
+78 client.on("session", (accept, reject) => {
408
+   ~~~~~~
409
+src/lib/ssh.ts:37:5 - warning ts(6133): 'port' is declared but its value is never read.
410
+
411
+37 port,
412
+   ~~~~
413
+
414
+src/lib/storage.ts:1196:9 - warning ts(6133): 'eq' is declared but its value is never read.
415
+
416
+1196 const { eq } = await import("drizzle-orm");
417
+   ~~~~~~
418
+src/lib/storage.ts:1098:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
419
+
420
+1098 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
421
+   ~~~~~~~~~
422
+src/lib/storage.ts:1084:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
423
+
424
+1084 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
425
+   ~~~~~~~~~
426
+src/lib/storage.ts:971:30 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
427
+
428
+971 const chunk = buffer.slice(i, Math.min(i + chunkSize, buffer.length));
429
+   ~~~~~
430
+src/lib/storage.ts:875:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
431
+
432
+875 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
433
+   ~~~~~~~~~
434
+src/lib/storage.ts:868:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
435
+
436
+868 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
437
+   ~~~~~~~~~
438
+src/lib/storage.ts:798:21 - warning ts(6387): The signature '(start?: number | undefined, end?: number | undefined): Buffer<ArrayBuffer>' of 'buffer.slice' is deprecated.
439
+
440
+798 return buffer.slice(options.range.start, options.range.end + 1);
441
+   ~~~~~
442
+src/lib/storage.ts:660:41 - warning ts(6133): 'expiresIn' is declared but its value is never read.
443
+
444
+660 async getSignedUploadUrl(key: string, expiresIn?: number): Promise<string> {
445
+   ~~~~~~~~~
446
+src/lib/storage.ts:649:35 - warning ts(6133): 'expiresIn' is declared but its value is never read.
447
+
448
+649 async getSignedUrl(key: string, expiresIn?: number): Promise<string> {
449
+   ~~~~~~~~~
450
+src/lib/storage.ts:539:51 - warning ts(6133): 'options' is declared but its value is never read.
451
+
452
+539 async put(key: string, data: Buffer | Readable, options?: PutOptions): Promise<void> {
453
+   ~~~~~~~
454
+src/lib/storage.ts:274:5 - warning ts(6133): 'expiresIn' is declared but its value is never read.
455
+
456
+274 expiresIn: number = 3600
457
+   ~~~~~~~~~
458
+
459
+src/lib/sync.ts:361:23 - warning ts(6133): 'baseHead' is declared but its value is never read.
460
+
461
+361 const baseHead = await git.revparse([baseBranch]);
462
+   ~~~~~~~~
463
+src/lib/sync.ts:360:23 - warning ts(6133): 'mergeBase' is declared but its value is never read.
464
+
465
+360 const mergeBase = await git.raw(["merge-base", baseBranch, branchName]);
466
+   ~~~~~~~~~
467
+src/lib/sync.ts:267:5 - warning ts(6133): 'repositoryId' is declared but its value is never read.
468
+
469
+267 repositoryId: string,
470
+   ~~~~~~~~~~~~
471
+src/lib/sync.ts:57:15 - warning ts(6133): 'currentBranch' is declared but its value is never read.
472
+
473
+57 const currentBranch = status.current;
474
+   ~~~~~~~~~~~~~
475
+src/lib/sync.ts:10:1 - warning ts(6133): 'generateId' is declared but its value is never read.
476
+
477
+10 import { generateId } from "./utils";
478
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479
+src/lib/sync.ts:9:20 - warning ts(6133): 'getStackForPr' is declared but its value is never read.
480
+
481
+9 import { getStack, getStackForPr, addToStack, createStack } from "./stacks";
482
+   ~~~~~~~~~~~~~
483
+src/lib/sync.ts:6:19 - warning ts(6133): 'desc' is declared but its value is never read.
484
+
485
+6 import { eq, and, desc } from "drizzle-orm";
486
+   ~~~~
487
+
488
+src/lib/workflows.ts:26:92 - warning ts(6133): 'pusherId' is declared but its value is never read.
489
+
490
+26 export async function triggerRepoWorkflows(repoId: string, commitSha: string, ref: string, pusherId: string) {
491
+   ~~~~~~~~
492
+src/lib/workflows.ts:8:1 - warning ts(6133): 'existsSync' is declared but its value is never read.
493
+
494
+8 import { existsSync } from "fs";
495
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496
+
497
+src/pages/cli.astro:5:5 - warning ts(6133): 'Cpu' is declared but its value is never read.
498
+
499
+5 Cpu,
500
+   ~~~
501
+
502
+src/pages/explore.astro:4:20 - warning ts(6133): 'sql' is declared but its value is never read.
503
+
504
+4 import { desc, eq, sql, count } from "drizzle-orm";
505
+   ~~~
506
+
507
+src/pages/inbox.astro:28:5 - warning ts(6133): 'title' is declared but its value is never read.
508
+
509
+28 let title = "Inbox";
510
+   ~~~~~
511
+src/pages/inbox.astro:15:3 - warning ts(6133): 'Bot' is declared but its value is never read.
512
+
513
+15 Bot,
514
+   ~~~
515
+src/pages/inbox.astro:13:3 - warning ts(6133): 'Search' is declared but its value is never read.
516
+
517
+13 Search,
518
+   ~~~~~~
519
+src/pages/inbox.astro:5:29 - warning ts(6133): 'ne' is declared but its value is never read.
520
+
521
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
522
+   ~~
523
+src/pages/inbox.astro:5:25 - warning ts(6133): 'or' is declared but its value is never read.
524
+
525
+5 import { eq, desc, and, or, ne } from "drizzle-orm";
526
+   ~~
527
+
528
+src/pages/insights.astro:11:3 - warning ts(6133): 'Calendar' is declared but its value is never read.
529
+
530
+11 Calendar,
531
+   ~~~~~~~~
532
+src/pages/insights.astro:4:30 - warning ts(6133): 'sql' is declared but its value is never read.
533
+
534
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
535
+   ~~~
536
+src/pages/insights.astro:4:14 - warning ts(6133): 'desc' is declared but its value is never read.
537
+
538
+4 import { eq, desc, and, gte, sql } from "drizzle-orm";
539
+   ~~~~
540
+
541
+src/pages/issues.astro:7:7 - warning ts(6133): 'currentUser' is declared but its value is never read.
542
+
543
+7 const currentUser = Astro.locals.user;
544
+   ~~~~~~~~~~~
545
+src/pages/issues.astro:4:25 - warning ts(6133): 'sql' is declared but its value is never read.
546
+
547
+4 import { desc, eq, and, sql } from "drizzle-orm";
548
+   ~~~
549
+src/pages/issues.astro:4:20 - warning ts(6133): 'and' is declared but its value is never read.
550
+
551
+4 import { desc, eq, and, sql } from "drizzle-orm";
552
+   ~~~
553
+
554
+src/pages/merge-queue.astro:353:56 - warning ts(6133): 'index' is declared but its value is never read.
555
+
556
+353 {queueItems.map((item, index) => {
557
+   ~~~~~
558
+src/pages/merge-queue.astro:222:10 - warning ts(6133): 'timeAgo' is declared but its value is never read.
559
+
560
+222 function timeAgo(date: string) {
561
+   ~~~~~~~
562
+src/pages/merge-queue.astro:73:5 - warning ts(6133): 'lastProcessedAt' is declared but its value is never read.
563
+
564
+73 let lastProcessedAt: string | null = null;
565
+   ~~~~~~~~~~~~~~~
566
+
567
+src/pages/password-reset.astro:95:13 - warning ts(6133): 'response' is declared but its value is never read.
568
+
569
+95 const response = await fetch("/api/auth/password-reset", {
570
+   ~~~~~~~~
571
+
572
+src/pages/repositories.astro:14:53 - warning ts(6133): 'Globe' is declared but its value is never read.
573
+
574
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
575
+   ~~~~~
576
+src/pages/repositories.astro:14:47 - warning ts(6133): 'Lock' is declared but its value is never read.
577
+
578
+14 import { Book, Star, GitBranch, Plus, Search, Lock, Globe } from "lucide-react";
579
+   ~~~~
580
+src/pages/repositories.astro:5:1 - warning ts(6192): All imports in import declaration are unused.
581
+
582
+ 5 import {
583
+  ~~~~~~~~
584
+ 6 Card,
585
+  ~~~~~~~~
586
+...
587
+ 10 CardContent,
588
+  ~~~~~~~~~~~~~~~
589
+ 11 } from "@/components/ui/card";
590
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
591
+
592
+src/pages/stars.astro:152:54 - warning ts(6385): 'event' is deprecated.
593
+
594
+152 onclick="event.preventDefault(); event.stopPropagation();"
595
+   ~~~~~
596
+src/pages/stars.astro:152:30 - warning ts(6385): 'event' is deprecated.
597
+
598
+152 onclick="event.preventDefault(); event.stopPropagation();"
599
+   ~~~~~
600
+
601
+src/pages/[owner]/[repo]/index.astro:15:19 - warning ts(6133): 'sql' is declared but its value is never read.
602
+
603
+15 import { eq, and, sql, count } from "drizzle-orm";
604
+   ~~~
605
+src/pages/[owner]/[repo]/index.astro:12:3 - warning ts(6133): 'Clock' is declared but its value is never read.
606
+
607
+12 Clock,
608
+   ~~~~~
609
+src/pages/[owner]/[repo]/index.astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
610
+
611
+6 Tag,
612
+   ~~~
613
+
614
+src/pages/[owner]/[repo]/labels.astro:245:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
615
+
616
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
617
+
618
+Add the `is:inline` directive explicitly to silence this hint.
619
+
620
+245 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
621
+   ~~~~~~~~~~~
622
+
623
+src/pages/[owner]/[repo]/merge-queue.astro:248:57 - warning ts(6133): 'i' is declared but its value is never read.
624
+
625
+248 {item.stack.entries.map((entry, i) => (
626
+   ~
627
+src/pages/[owner]/[repo]/merge-queue.astro:13:3 - warning ts(6133): 'Play' is declared but its value is never read.
628
+
629
+13 Play,
630
+   ~~~~
631
+src/pages/[owner]/[repo]/merge-queue.astro:8:19 - warning ts(6133): 'sql' is declared but its value is never read.
632
+
633
+8 import { and, eq, sql, count } from "drizzle-orm";
634
+   ~~~
635
+
636
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:18:3 - warning ts(6133): 'Monitor' is declared but its value is never read.
637
+
638
+18 Monitor,
639
+   ~~~~~~~
640
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:13:3 - warning ts(6133): 'FileText' is declared but its value is never read.
641
+
642
+13 FileText,
643
+   ~~~~~~~~
644
+src/pages/[owner]/[repo]/blob/[branch]/[...path].astro:337:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
645
+
646
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
647
+
648
+Add the `is:inline` directive explicitly to silence this hint.
649
+
650
+337 <script define:vars={{ initialContent: !fileData.isBinary ? fileData.content : "" }}>
651
+   ~~~~~~~~~~~
652
+
653
+src/pages/[owner]/[repo]/branches/index.astro:16:3 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
654
+
655
+16 AlertCircle,
656
+   ~~~~~~~~~~~
657
+src/pages/[owner]/[repo]/branches/index.astro:15:3 - warning ts(6133): 'Search' is declared but its value is never read.
658
+
659
+15 Search,
660
+   ~~~~~~
661
+src/pages/[owner]/[repo]/branches/index.astro:13:3 - warning ts(6133): 'MoreHorizontal' is declared but its value is never read.
662
+
663
+13 MoreHorizontal,
664
+   ~~~~~~~~~~~~~~
665
+src/pages/[owner]/[repo]/branches/index.astro:9:19 - warning ts(6133): 'sql' is declared but its value is never read.
666
+
667
+9 import { and, eq, sql, count } from "drizzle-orm";
668
+   ~~~
669
+src/pages/[owner]/[repo]/branches/index.astro:8:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
670
+
671
+8 import { getRepoPath } from "@/lib/utils";
672
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
673
+src/pages/[owner]/[repo]/branches/index.astro:351:42 - warning ts(6133): 'e' is declared but its value is never read.
674
+
675
+351 btn.addEventListener("click", async (e: any) => {
676
+   ~
677
+
678
+src/pages/[owner]/[repo]/commits/[...ref].astro:9:1 - warning ts(6133): 'Button' is declared but its value is never read.
679
+
680
+9 import { Button } from "@/components/ui/button";
681
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
682
+
683
+src/pages/[owner]/[repo]/edit/[...ref].astro:108:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
684
+
685
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
686
+
687
+Add the `is:inline` directive explicitly to silence this hint.
688
+
689
+108 <script define:vars={{ initialContent: fileContent, repoId: repo.id, branch: currentBranch, path: filePath, owner: repo.owner, repoName: repo.name }}>
690
+   ~~~~~~~~~~~
691
+
692
+src/pages/[owner]/[repo]/insights/index.astro:277:69 - warning ts(6133): 'i' is declared but its value is never read.
693
+
694
+277 {contributors.map((contributor, i) => (
695
+   ~
696
+src/pages/[owner]/[repo]/insights/index.astro:85:7 - warning ts(6133): 'recentCommits' is declared but its value is never read.
697
+
698
+85 const recentCommits = await getCommits(repoData.diskPath, { limit: 20 });
699
+   ~~~~~~~~~~~~~
700
+src/pages/[owner]/[repo]/insights/index.astro:9:5 - warning ts(6133): 'GitCommit' is declared but its value is never read.
701
+
702
+9 GitCommit,
703
+   ~~~~~~~~~
704
+src/pages/[owner]/[repo]/insights/index.astro:5:24 - warning ts(6133): 'desc' is declared but its value is never read.
705
+
706
+5 import { eq, and, sql, desc, gte, count } from "drizzle-orm";
707
+   ~~~~
708
+
709
+src/pages/[owner]/[repo]/pulls/[number].astro:100:11 - error ts(2554): Expected 0 arguments, but got 1.
710
+
711
+100 .select({ count: sql<number>`count(*)` })
712
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
713
+src/pages/[owner]/[repo]/pulls/[number].astro:359:50 - warning ts(6133): 'i' is declared but its value is never read.
714
+
715
+359 {stackInfo.entries.map((entry, i) => {
716
+   ~
717
+src/pages/[owner]/[repo]/pulls/[number].astro:136:5 - warning ts(6133): 'mergeError' is declared but its value is never read.
718
+
719
+136 let mergeError = "";
720
+   ~~~~~~~~~~
721
+src/pages/[owner]/[repo]/pulls/[number].astro:24:3 - warning ts(6133): 'ChevronRight' is declared but its value is never read.
722
+
723
+24 ChevronRight,
724
+   ~~~~~~~~~~~~
725
+src/pages/[owner]/[repo]/pulls/[number].astro:16:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
726
+
727
+16 CheckCircle2,
728
+   ~~~~~~~~~~~~
729
+src/pages/[owner]/[repo]/pulls/[number].astro:13:29 - warning ts(6133): 'count' is declared but its value is never read.
730
+
731
+13 import { and, eq, sql, asc, count } from "drizzle-orm";
732
+   ~~~~~
733
+src/pages/[owner]/[repo]/pulls/[number].astro:419:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
734
+
735
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
736
+
737
+Add the `is:inline` directive explicitly to silence this hint.
738
+
739
+419 define:vars={{
740
+   ~~~~~~~~~~~
741
+
742
+src/pages/[owner]/[repo]/pulls/index.astro:7:30 - warning ts(6133): 'count' is declared but its value is never read.
743
+
744
+7 import { and, desc, eq, sql, count } from "drizzle-orm";
745
+   ~~~~~
746
+
747
+src/pages/[owner]/[repo]/pulls/new.astro:84:5 - warning ts(6133): 'canMerge' is declared but its value is never read.
748
+
749
+84 let canMerge = false;
750
+   ~~~~~~~~
751
+src/pages/[owner]/[repo]/pulls/new.astro:83:5 - warning ts(6133): 'error' is declared but its value is never read.
752
+
753
+83 let error = "";
754
+   ~~~~~
755
+src/pages/[owner]/[repo]/pulls/new.astro:25:3 - warning ts(6133): 'ArrowRight' is declared but its value is never read.
756
+
757
+25 ArrowRight,
758
+   ~~~~~~~~~~
759
+src/pages/[owner]/[repo]/pulls/new.astro:22:24 - warning ts(6133): 'count' is declared but its value is never read.
760
+
761
+22 import { and, eq, sql, count } from "drizzle-orm";
762
+   ~~~~~
763
+src/pages/[owner]/[repo]/pulls/new.astro:337:3 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
764
+
765
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
766
+
767
+Add the `is:inline` directive explicitly to silence this hint.
768
+
769
+337 define:vars={{
770
+   ~~~~~~~~~~~
771
+
772
+src/pages/[owner]/[repo]/security/index.astro:8:10 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
773
+
774
+8 import { AlertCircle, CheckCircle, Shield, Play, Loader2 } from "lucide-react";
775
+   ~~~~~~~~~~~
776
+src/pages/[owner]/[repo]/security/index.astro:293:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
777
+
778
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
779
+
780
+Add the `is:inline` directive explicitly to silence this hint.
781
+
782
+293 <script define:vars={{ repoOwner: repoInfo.owner, repoName: repoInfo.name }}>
783
+   ~~~~~~~~~~~
784
+
785
+src/pages/[owner]/[repo]/settings/collaborators.astro:83:10 - warning ts(6133): 'getRoleDescription' is declared but its value is never read.
786
+
787
+83 function getRoleDescription(role: string) {
788
+   ~~~~~~~~~~~~~~~~~~
789
+src/pages/[owner]/[repo]/settings/collaborators.astro:297:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
790
+
791
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
792
+
793
+Add the `is:inline` directive explicitly to silence this hint.
794
+
795
+297 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
796
+   ~~~~~~~~~~~
797
+
798
+src/pages/[owner]/[repo]/settings/index.astro:267:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
799
+
800
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
801
+
802
+Add the `is:inline` directive explicitly to silence this hint.
803
+
804
+267 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
805
+   ~~~~~~~~~~~
806
+
807
+src/pages/[owner]/[repo]/settings/webhooks.astro:326:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
808
+
809
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
810
+
811
+Add the `is:inline` directive explicitly to silence this hint.
812
+
813
+326 <script define:vars={{ owner: repo.owner, repo: repo.name }}>
814
+   ~~~~~~~~~~~
815
+
816
+src/pages/[owner]/[repo]/settings/actions/runners.astro:15:18 - warning ts(6133): 'Terminal' is declared but its value is never read.
817
+
818
+15 import { Server, Terminal, Copy } from "lucide-react";
819
+   ~~~~~~~~
820
+src/pages/[owner]/[repo]/settings/actions/runners.astro:210:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
821
+
822
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
823
+
824
+Add the `is:inline` directive explicitly to silence this hint.
825
+
826
+210 <script define:vars={{ repoId: repoData.id }}>
827
+   ~~~~~~~~~~~
828
+
829
+src/pages/[owner]/[repo]/settings/branches/[id].astro:117:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
830
+
831
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
832
+
833
+Add the `is:inline` directive explicitly to silence this hint.
834
+
835
+117 <script define:vars={{ repoId: repository.id, ruleId: rule.id, owner, repo }}>
836
+   ~~~~~~~~~~~
837
+
838
+src/pages/[owner]/[repo]/settings/branches/index.astro:5:14 - warning ts(6133): 'and' is declared but its value is never read.
839
+
840
+5 import { eq, and } from "drizzle-orm";
841
+   ~~~
842
+
843
+src/pages/[owner]/[repo]/settings/branches/new.astro:152:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
844
+
845
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
846
+
847
+Add the `is:inline` directive explicitly to silence this hint.
848
+
849
+152 <script define:vars={{ repoId: repository.id, owner, repo }}>
850
+   ~~~~~~~~~~~
851
+
852
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:5:19 - warning ts(6133): 'desc' is declared but its value is never read.
853
+
854
+5 import { eq, and, desc } from "drizzle-orm";
855
+   ~~~~
856
+src/pages/[owner]/[repo]/settings/webhooks/[id].astro:176:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
857
+
858
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
859
+
860
+Add the `is:inline` directive explicitly to silence this hint.
861
+
862
+176 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name, webhookId: webhook.id }}>
863
+   ~~~~~~~~~~~
864
+
865
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:12:5 - warning ts(6133): 'MoreVertical' is declared but its value is never read.
866
+
867
+12 MoreVertical,
868
+   ~~~~~~~~~~~~
869
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:11:5 - warning ts(6133): 'AlertCircle' is declared but its value is never read.
870
+
871
+11 AlertCircle,
872
+   ~~~~~~~~~~~
873
+src/pages/[owner]/[repo]/settings/webhooks/index.astro:210:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
874
+
875
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
876
+
877
+Add the `is:inline` directive explicitly to silence this hint.
878
+
879
+210 <script define:vars={{ repoId: repo.id }}>
880
+   ~~~~~~~~~~~
881
+
882
+src/pages/[owner]/[repo]/settings/webhooks/new.astro:187:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
883
+
884
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
885
+
886
+Add the `is:inline` directive explicitly to silence this hint.
887
+
888
+187 <script define:vars={{ repoId: repo.id, owner: repo.owner, repoName: repo.name }}>
889
+   ~~~~~~~~~~~
890
+
891
+src/pages/[owner]/[repo]/tree/[...ref].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
892
+
893
+6 Tag,
894
+   ~~~
895
+
896
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:11:3 - warning ts(6133): 'FileText' is declared but its value is never read.
897
+
898
+11 FileText,
899
+   ~~~~~~~~
900
+src/pages/[owner]/[repo]/tree/[branch]/[...path].astro:6:3 - warning ts(6133): 'Tag' is declared but its value is never read.
901
+
902
+6 Tag,
903
+   ~~~
904
+
905
+src/pages/admin/audit.astro:18:3 - warning ts(6133): 'ExternalLink' is declared but its value is never read.
906
+
907
+18 ExternalLink,
908
+   ~~~~~~~~~~~~
909
+src/pages/admin/audit.astro:4:27 - warning ts(6133): 'eq' is declared but its value is never read.
910
+
911
+4 import { desc, sql, like, eq, or } from "drizzle-orm";
912
+   ~~
913
+
914
+src/pages/admin/repositories.astro:4:16 - warning ts(6133): 'eq' is declared but its value is never read.
915
+
916
+4 import { desc, eq, like, or, sql } from "drizzle-orm";
917
+   ~~
918
+
919
+src/pages/admin/users.astro:9:12 - warning ts(6133): 'UsersIcon' is declared but its value is never read.
920
+
921
+9 Users as UsersIcon,
922
+   ~~~~~~~~~
923
+
924
+src/pages/api/ai-review-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
925
+
926
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
927
+   ~~~~~~
928
+
929
+src/pages/api/automation-rules.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
930
+
931
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
932
+   ~~~~~~
933
+src/pages/api/automation-rules.ts:7:14 - warning ts(6133): 'and' is declared but its value is never read.
934
+
935
+7 import { eq, and } from "drizzle-orm";
936
+   ~~~
937
+
938
+src/pages/api/inbox-sections.ts:11:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
939
+
940
+11 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
941
+   ~~~~~~
942
+
943
+src/pages/api/search.ts:3:20 - warning ts(6133): 'eq' is declared but its value is never read.
944
+
945
+3 import { like, or, eq, desc } from 'drizzle-orm';
946
+   ~~
947
+
948
+src/pages/api/actions/trigger-test.ts:10:1 - warning ts(6133): 'eq' is declared but its value is never read.
949
+
950
+10 import { eq } from "drizzle-orm";
951
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
952
+src/pages/api/actions/trigger-test.ts:8:57 - warning ts(6133): 'notFound' is declared but its value is never read.
953
+
954
+8 import { success, unauthorized, serverError, parseBody, notFound } from '@/lib/api';
955
+   ~~~~~~~~
956
+
957
+src/pages/api/realtime/events.ts:28:48 - warning ts(6133): 'request' is declared but its value is never read.
958
+
959
+28 export const POST: APIRoute = async ({ locals, request }) => {
960
+   ~~~~~~~
961
+
962
+src/pages/api/repos/[owner]/[repo]/protection.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
963
+
964
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
965
+   ~~~~~~~~~~
966
+
967
+src/pages/api/repos/[owner]/[repo]/git/push.ts:142:26 - warning ts(6133): 'sha' is declared but its value is never read.
968
+
969
+142 for (const { sha, ref } of bundleRefs) {
970
+   ~~~
971
+src/pages/api/repos/[owner]/[repo]/git/push.ts:22:22 - warning ts(6133): 'mkdirSync' is declared but its value is never read.
972
+
973
+22 import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "fs";
974
+   ~~~~~~~~~
975
+src/pages/api/repos/[owner]/[repo]/git/push.ts:18:5 - warning ts(6133): 'getDiskPath' is declared but its value is never read.
976
+
977
+18 getDiskPath,
978
+   ~~~~~~~~~~~
979
+src/pages/api/repos/[owner]/[repo]/git/push.ts:13:1 - warning ts(6133): 'getRepoPath' is declared but its value is never read.
980
+
981
+13 import { getRepoPath } from "@/lib/utils";
982
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
983
+
984
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:30 - warning ts(6133): 'number' is declared but its value is never read.
985
+
986
+210 const { owner, repo, number, commentId } = params;
987
+   ~~~~~~
988
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:210:24 - warning ts(6133): 'repo' is declared but its value is never read.
989
+
990
+210 const { owner, repo, number, commentId } = params;
991
+   ~~~~
992
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:30 - warning ts(6133): 'number' is declared but its value is never read.
993
+
994
+163 const { owner, repo, number, commentId } = params;
995
+   ~~~~~~
996
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:163:24 - warning ts(6133): 'repo' is declared but its value is never read.
997
+
998
+163 const { owner, repo, number, commentId } = params;
999
+   ~~~~
1000
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:99:24 - warning ts(6133): 'repo' is declared but its value is never read.
1001
+
1002
+99 const { owner, repo, number } = params;
1003
+   ~~~~
1004
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:37:24 - warning ts(6133): 'repo' is declared but its value is never read.
1005
+
1006
+37 const { owner, repo, number } = params;
1007
+   ~~~~
1008
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1009
+
1010
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1011
+   ~~~~~~~~~~
1012
+src/pages/api/repos/[owner]/[repo]/pulls/[number]/comments.ts:7:25 - warning ts(6133): 'isNull' is declared but its value is never read.
1013
+
1014
+7 import { eq, and, desc, isNull } from "drizzle-orm";
1015
+   ~~~~~~
1016
+
1017
+src/pages/api/stacks/index.ts:26:6 - warning ts(6196): 'CreateStackInput' is declared but never used.
1018
+
1019
+26 type CreateStackInput = z.infer<typeof createStackSchema>;
1020
+   ~~~~~~~~~~~~~~~~
1021
+src/pages/api/stacks/index.ts:10:35 - warning ts(6133): 'badRequest' is declared but its value is never read.
1022
+
1023
+10 import { parseBody, unauthorized, badRequest, notFound, success, serverError } from "@/lib/api";
1024
+   ~~~~~~~~~~
1025
+
1026
+src/pages/api/user/notification-preferences.ts:12:56 - warning ts(6385): '(from: number, length?: number | undefined): string' is deprecated.
1027
+
1028
+12 return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1029
+   ~~~~~~
1030
+
1031
+src/pages/api/user/tokens.ts:103:24 - warning ts(6133): 'prefix' is declared but its value is never read.
1032
+
1033
+103 const { token, prefix } = generateToken();
1034
+   ~~~~~~
1035
+src/pages/api/user/tokens.ts:79:34 - warning ts(6133): 'scopes' is declared but its value is never read.
1036
+
1037
+79 const { name, expiresIn, scopes } = parsed.data;
1038
+   ~~~~~~
1039
+src/pages/api/user/tokens.ts:26:10 - warning ts(6133): 'hashToken' is declared but its value is never read.
1040
+
1041
+26 function hashToken(token: string): string {
1042
+   ~~~~~~~~~
1043
+src/pages/api/user/tokens.ts:8:23 - warning ts(6133): 'schema' is declared but its value is never read.
1044
+
1045
+8 import { getDatabase, schema } from "@/db";
1046
+   ~~~~~~
1047
+
1048
+src/pages/settings/ai-review-rules.astro:19:3 - warning ts(6133): 'CheckCircle2' is declared but its value is never read.
1049
+
1050
+19 CheckCircle2,
1051
+   ~~~~~~~~~~~~
1052
+src/pages/settings/ai-review-rules.astro:4:14 - warning ts(6133): 'and' is declared but its value is never read.
1053
+
1054
+4 import { eq, and, desc } from "drizzle-orm";
1055
+   ~~~
1056
+src/pages/settings/ai-review-rules.astro:475:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1057
+
1058
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1059
+
1060
+Add the `is:inline` directive explicitly to silence this hint.
1061
+
1062
+475 <script define:vars={{ repoId }}>
1063
+   ~~~~~~~~~~~
1064
+
1065
+src/pages/settings/automations.astro:301:61 - warning ts(6133): 'i' is declared but its value is never read.
1066
+
1067
+301 {actions.slice(0, 3).map((action, i) => (
1068
+   ~
1069
+src/pages/settings/automations.astro:437:9 - warning astro(4000): This script will be treated as if it has the `is:inline` directive because it contains an attribute. Therefore, features that require processing (e.g. using TypeScript or npm packages in the script) are unavailable.
1070
+
1071
+See docs for more details: https://docs.astro.build/en/guides/client-side-scripts/#script-processing.
1072
+
1073
+Add the `is:inline` directive explicitly to silence this hint.
1074
+
1075
+437 <script define:vars={{ repoId }}>
1076
+   ~~~~~~~~~~~
1077
+
1078
+Result (300 files):
1079
+- 1 error
1080
+- 0 warnings
1081
+- 224 hints
1082
+
0
1083