@octp/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/bin/octopus.js +2 -0
  2. package/dist/commands/config.d.ts +2 -0
  3. package/dist/commands/config.js +86 -0
  4. package/dist/commands/config.js.map +1 -0
  5. package/dist/commands/knowledge/add.d.ts +2 -0
  6. package/dist/commands/knowledge/add.js +33 -0
  7. package/dist/commands/knowledge/add.js.map +1 -0
  8. package/dist/commands/knowledge/index.d.ts +2 -0
  9. package/dist/commands/knowledge/index.js +10 -0
  10. package/dist/commands/knowledge/index.js.map +1 -0
  11. package/dist/commands/knowledge/list.d.ts +2 -0
  12. package/dist/commands/knowledge/list.js +32 -0
  13. package/dist/commands/knowledge/list.js.map +1 -0
  14. package/dist/commands/knowledge/remove.d.ts +2 -0
  15. package/dist/commands/knowledge/remove.js +20 -0
  16. package/dist/commands/knowledge/remove.js.map +1 -0
  17. package/dist/commands/login.d.ts +2 -0
  18. package/dist/commands/login.js +142 -0
  19. package/dist/commands/login.js.map +1 -0
  20. package/dist/commands/logout.d.ts +2 -0
  21. package/dist/commands/logout.js +16 -0
  22. package/dist/commands/logout.js.map +1 -0
  23. package/dist/commands/pr/index.d.ts +2 -0
  24. package/dist/commands/pr/index.js +6 -0
  25. package/dist/commands/pr/index.js.map +1 -0
  26. package/dist/commands/pr/review.d.ts +2 -0
  27. package/dist/commands/pr/review.js +47 -0
  28. package/dist/commands/pr/review.js.map +1 -0
  29. package/dist/commands/repo/analyze.d.ts +2 -0
  30. package/dist/commands/repo/analyze.js +48 -0
  31. package/dist/commands/repo/analyze.js.map +1 -0
  32. package/dist/commands/repo/chat.d.ts +2 -0
  33. package/dist/commands/repo/chat.js +67 -0
  34. package/dist/commands/repo/chat.js.map +1 -0
  35. package/dist/commands/repo/index-cmd.d.ts +2 -0
  36. package/dist/commands/repo/index-cmd.js +47 -0
  37. package/dist/commands/repo/index-cmd.js.map +1 -0
  38. package/dist/commands/repo/index.d.ts +2 -0
  39. package/dist/commands/repo/index.js +14 -0
  40. package/dist/commands/repo/index.js.map +1 -0
  41. package/dist/commands/repo/list.d.ts +2 -0
  42. package/dist/commands/repo/list.js +32 -0
  43. package/dist/commands/repo/list.js.map +1 -0
  44. package/dist/commands/repo/status.d.ts +2 -0
  45. package/dist/commands/repo/status.js +45 -0
  46. package/dist/commands/repo/status.js.map +1 -0
  47. package/dist/commands/usage.d.ts +2 -0
  48. package/dist/commands/usage.js +41 -0
  49. package/dist/commands/usage.js.map +1 -0
  50. package/dist/commands/whoami.d.ts +2 -0
  51. package/dist/commands/whoami.js +27 -0
  52. package/dist/commands/whoami.js.map +1 -0
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.js +24 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/lib/api-client.d.ts +11 -0
  57. package/dist/lib/api-client.js +90 -0
  58. package/dist/lib/api-client.js.map +1 -0
  59. package/dist/lib/config-store.d.ts +8 -0
  60. package/dist/lib/config-store.js +57 -0
  61. package/dist/lib/config-store.js.map +1 -0
  62. package/dist/lib/output.d.ts +11 -0
  63. package/dist/lib/output.js +103 -0
  64. package/dist/lib/output.js.map +1 -0
  65. package/dist/lib/repo-resolver.d.ts +7 -0
  66. package/dist/lib/repo-resolver.js +64 -0
  67. package/dist/lib/repo-resolver.js.map +1 -0
  68. package/dist/lib/spinner.d.ts +3 -0
  69. package/dist/lib/spinner.js +17 -0
  70. package/dist/lib/spinner.js.map +1 -0
  71. package/dist/types.d.ts +54 -0
  72. package/dist/types.js +2 -0
  73. package/dist/types.js.map +1 -0
  74. package/package.json +29 -0
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const repoIndexCommand: Command;
@@ -0,0 +1,47 @@
1
+ import { Command } from "commander";
2
+ import { resolveRepo } from "../../lib/repo-resolver.js";
3
+ import { apiPost, apiGet } from "../../lib/api-client.js";
4
+ import { error, info, formatNumber, formatDuration } from "../../lib/output.js";
5
+ import { createSpinner } from "../../lib/spinner.js";
6
+ export const repoIndexCommand = new Command("index")
7
+ .argument("[repo]", "Repository name or full name (auto-detects from git remote)")
8
+ .description("Index a repository for code search")
9
+ .action(async (repoArg) => {
10
+ try {
11
+ const spinner = createSpinner("Resolving repository...").start();
12
+ const repo = await resolveRepo(repoArg);
13
+ spinner.text = `Starting index for ${repo.fullName}...`;
14
+ await apiPost(`/api/cli/repos/${repo.id}/index`);
15
+ spinner.text = `Indexing ${repo.fullName}...`;
16
+ // Poll for completion (max 10 minutes)
17
+ let status = "indexing";
18
+ let attempts = 0;
19
+ const maxAttempts = 200;
20
+ while (status === "indexing" && attempts < maxAttempts) {
21
+ attempts++;
22
+ await new Promise((r) => setTimeout(r, 3000));
23
+ const { repo: updated } = await apiGet(`/api/cli/repos/${repo.id}/status`);
24
+ status = updated.indexStatus;
25
+ if (status === "indexed") {
26
+ spinner.succeed(`Indexed ${repo.fullName}`);
27
+ info(`Files: ${updated.indexedFiles}/${updated.totalFiles}`);
28
+ info(`Chunks: ${formatNumber(updated.totalChunks)}`);
29
+ info(`Duration: ${formatDuration(updated.indexDurationMs)}`);
30
+ return;
31
+ }
32
+ if (status === "failed") {
33
+ spinner.fail(`Indexing failed for ${repo.fullName}`);
34
+ process.exit(1);
35
+ }
36
+ }
37
+ if (attempts >= maxAttempts) {
38
+ spinner.fail(`Indexing timed out for ${repo.fullName} after ${maxAttempts * 3}s`);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ catch (err) {
43
+ error(err instanceof Error ? err.message : "Failed to index repository");
44
+ process.exit(1);
45
+ }
46
+ });
47
+ //# sourceMappingURL=index-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-cmd.js","sourceRoot":"","sources":["../../../src/commands/repo/index-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAW,IAAI,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KACjD,QAAQ,CAAC,QAAQ,EAAE,6DAA6D,CAAC;KACjF,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,KAAK,EAAE,OAAgB,EAAE,EAAE;IACjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,yBAAyB,CAAC,CAAC,KAAK,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,GAAG,sBAAsB,IAAI,CAAC,QAAQ,KAAK,CAAC;QAExD,MAAM,OAAO,CAAC,kBAAkB,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,GAAG,YAAY,IAAI,CAAC,QAAQ,KAAK,CAAC;QAE9C,uCAAuC;QACvC,IAAI,MAAM,GAAG,UAAU,CAAC;QACxB,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,MAAM,WAAW,GAAG,GAAG,CAAC;QACxB,OAAO,MAAM,KAAK,UAAU,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;YACvD,QAAQ,EAAE,CAAC;YACX,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YAC9C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CACpC,kBAAkB,IAAI,CAAC,EAAE,SAAS,CACnC,CAAC;YACF,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;YAE7B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC5C,IAAI,CAAC,UAAU,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC7D,IAAI,CAAC,WAAW,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;gBACrD,IAAI,CAAC,aAAa,cAAc,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,uBAAuB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,IAAI,WAAW,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,QAAQ,UAAU,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC;YAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const repoCommand: Command;
@@ -0,0 +1,14 @@
1
+ import { Command } from "commander";
2
+ import { repoListCommand } from "./list.js";
3
+ import { repoStatusCommand } from "./status.js";
4
+ import { repoIndexCommand } from "./index-cmd.js";
5
+ import { repoAnalyzeCommand } from "./analyze.js";
6
+ import { repoChatCommand } from "./chat.js";
7
+ export const repoCommand = new Command("repo")
8
+ .description("Manage repositories");
9
+ repoCommand.addCommand(repoListCommand);
10
+ repoCommand.addCommand(repoStatusCommand);
11
+ repoCommand.addCommand(repoIndexCommand);
12
+ repoCommand.addCommand(repoAnalyzeCommand);
13
+ repoCommand.addCommand(repoChatCommand);
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/repo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,qBAAqB,CAAC,CAAC;AAEtC,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACxC,WAAW,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AAC1C,WAAW,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACzC,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AAC3C,WAAW,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const repoListCommand: Command;
@@ -0,0 +1,32 @@
1
+ import { Command } from "commander";
2
+ import { apiGet } from "../../lib/api-client.js";
3
+ import { error, table, statusBadge, formatDate } from "../../lib/output.js";
4
+ import { withSpinner } from "../../lib/spinner.js";
5
+ export const repoListCommand = new Command("list")
6
+ .description("List all repositories")
7
+ .action(async () => {
8
+ try {
9
+ const { repos } = await withSpinner("Fetching repositories...", async () => {
10
+ return apiGet("/api/cli/repos");
11
+ });
12
+ if (repos.length === 0) {
13
+ console.log("No repositories found. Connect repos in the Octopus dashboard.");
14
+ return;
15
+ }
16
+ const rows = repos.map((r) => [
17
+ r.fullName,
18
+ r.provider,
19
+ statusBadge(r.indexStatus),
20
+ statusBadge(r.analysisStatus),
21
+ String(r._count.pullRequests),
22
+ formatDate(r.indexedAt),
23
+ ]);
24
+ table(rows, ["Repository", "Provider", "Index", "Analysis", "PRs", "Last Indexed"]);
25
+ console.log(`\n${repos.length} repositories total`);
26
+ }
27
+ catch (err) {
28
+ error(err instanceof Error ? err.message : "Failed to list repos");
29
+ process.exit(1);
30
+ }
31
+ });
32
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/repo/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC/C,WAAW,CAAC,uBAAuB,CAAC;KACpC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,WAAW,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACzE,OAAO,MAAM,CAAuB,gBAAgB,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC5B,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,QAAQ;YACV,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;YAC1B,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC;YAC7B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;YAC7B,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;SACxB,CAAC,CAAC;QAEH,KAAK,CAAC,IAAI,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;QACpF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,qBAAqB,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const repoStatusCommand: Command;
@@ -0,0 +1,45 @@
1
+ import { Command } from "commander";
2
+ import { resolveRepo } from "../../lib/repo-resolver.js";
3
+ import { error, heading, statusBadge, formatDate, formatDuration, formatNumber } from "../../lib/output.js";
4
+ import { withSpinner } from "../../lib/spinner.js";
5
+ import { apiGet } from "../../lib/api-client.js";
6
+ export const repoStatusCommand = new Command("status")
7
+ .argument("[repo]", "Repository name or full name (auto-detects from git remote)")
8
+ .description("Show repository status and details")
9
+ .action(async (repoArg) => {
10
+ try {
11
+ const repo = await withSpinner("Resolving repository...", async () => {
12
+ const resolved = await resolveRepo(repoArg);
13
+ // Fetch full status
14
+ const { repo: full } = await apiGet(`/api/cli/repos/${resolved.id}/status`);
15
+ return full;
16
+ });
17
+ heading(repo.fullName);
18
+ console.log(` Provider: ${repo.provider}`);
19
+ console.log(` Default Branch: ${repo.defaultBranch}`);
20
+ console.log(` Auto Review: ${repo.autoReview ? "enabled" : "disabled"}`);
21
+ heading("Indexing");
22
+ console.log(` Status: ${statusBadge(repo.indexStatus)}`);
23
+ console.log(` Last Index: ${formatDate(repo.indexedAt)}`);
24
+ console.log(` Files: ${repo.indexedFiles}/${repo.totalFiles}`);
25
+ console.log(` Chunks: ${formatNumber(repo.totalChunks)}`);
26
+ console.log(` Vectors: ${formatNumber(repo.totalVectors ?? 0)}`);
27
+ console.log(` Duration: ${formatDuration(repo.indexDurationMs)}`);
28
+ heading("Analysis");
29
+ console.log(` Status: ${statusBadge(repo.analysisStatus)}`);
30
+ console.log(` Last Analyzed: ${formatDate(repo.analyzedAt)}`);
31
+ if (repo.purpose)
32
+ console.log(` Purpose: ${repo.purpose}`);
33
+ if (repo.summary)
34
+ console.log(` Summary: ${repo.summary}`);
35
+ heading("Stats");
36
+ console.log(` Pull Requests: ${repo._count.pullRequests}`);
37
+ console.log(` Contributors: ${repo.contributorCount ?? 0}`);
38
+ console.log();
39
+ }
40
+ catch (err) {
41
+ error(err instanceof Error ? err.message : "Failed to get repo status");
42
+ process.exit(1);
43
+ }
44
+ });
45
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/repo/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const usageCommand: Command;
@@ -0,0 +1,41 @@
1
+ import { Command } from "commander";
2
+ import { apiGet } from "../lib/api-client.js";
3
+ import { error, heading, table, formatNumber, formatUsd } from "../lib/output.js";
4
+ import { withSpinner } from "../lib/spinner.js";
5
+ import chalk from "chalk";
6
+ export const usageCommand = new Command("usage")
7
+ .description("Show monthly usage and credit balance")
8
+ .action(async () => {
9
+ try {
10
+ const data = await withSpinner("Fetching usage data...", async () => {
11
+ return apiGet("/api/cli/usage");
12
+ });
13
+ heading("Monthly Usage");
14
+ console.log(` Period: ${new Date(data.period.start).toLocaleDateString()} — now`);
15
+ console.log(` Total Spend: ${chalk.bold(formatUsd(data.totalSpend))}`);
16
+ if (data.spendLimit !== null) {
17
+ console.log(` Spend Limit: ${formatUsd(data.spendLimit)}`);
18
+ }
19
+ console.log(` Credit Balance: ${formatUsd(data.creditBalance)} (+ ${formatUsd(data.freeCreditBalance)} free)`);
20
+ if (data.breakdown.length > 0) {
21
+ heading("Breakdown");
22
+ const rows = data.breakdown
23
+ .sort((a, b) => b.cost - a.cost)
24
+ .map((row) => [
25
+ row.model,
26
+ row.operation,
27
+ String(row.count),
28
+ formatNumber(row.inputTokens),
29
+ formatNumber(row.outputTokens),
30
+ formatUsd(row.cost),
31
+ ]);
32
+ table(rows, ["Model", "Operation", "Calls", "Input", "Output", "Cost"]);
33
+ }
34
+ console.log();
35
+ }
36
+ catch (err) {
37
+ error(err instanceof Error ? err.message : "Failed to fetch usage");
38
+ process.exit(1);
39
+ }
40
+ });
41
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/commands/usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YAClE,OAAO,MAAM,CAOV,gBAAgB,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,eAAe,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QAC1F,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1E,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,oBAAoB,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,qBAAqB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAEhH,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,WAAW,CAAC,CAAC;YACrB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS;iBACxB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;iBAC/B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;gBACZ,GAAG,CAAC,KAAK;gBACT,GAAG,CAAC,SAAS;gBACb,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBACjB,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC;gBAC7B,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC;gBAC9B,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;aACpB,CAAC,CAAC;YACL,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1E,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const whoamiCommand: Command;
@@ -0,0 +1,27 @@
1
+ import { Command } from "commander";
2
+ import { apiGet } from "../lib/api-client.js";
3
+ import { error, heading } from "../lib/output.js";
4
+ import { withSpinner } from "../lib/spinner.js";
5
+ export const whoamiCommand = new Command("whoami")
6
+ .description("Show current user and organization info")
7
+ .action(async () => {
8
+ try {
9
+ const data = await withSpinner("Fetching account info...", async () => {
10
+ return apiGet("/api/cli/me");
11
+ });
12
+ heading("Account");
13
+ console.log(` Name: ${data.user.name}`);
14
+ console.log(` Email: ${data.user.email}`);
15
+ heading("Organization");
16
+ console.log(` Name: ${data.organization.name}`);
17
+ console.log(` Slug: ${data.organization.slug}`);
18
+ console.log(` Members: ${data.organization.memberCount}`);
19
+ console.log(` Repos: ${data.organization.repoCount}`);
20
+ console.log();
21
+ }
22
+ catch (err) {
23
+ error(err instanceof Error ? err.message : "Failed to fetch account info");
24
+ process.exit(1);
25
+ }
26
+ });
27
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAW,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACpE,OAAO,MAAM,CASV,aAAa,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,SAAS,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAE3C,OAAO,CAAC,cAAc,CAAC,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import { Command } from "commander";
2
+ import { loginCommand } from "./commands/login.js";
3
+ import { logoutCommand } from "./commands/logout.js";
4
+ import { whoamiCommand } from "./commands/whoami.js";
5
+ import { configCommand } from "./commands/config.js";
6
+ import { usageCommand } from "./commands/usage.js";
7
+ import { repoCommand } from "./commands/repo/index.js";
8
+ import { prCommand } from "./commands/pr/index.js";
9
+ import { knowledgeCommand } from "./commands/knowledge/index.js";
10
+ const program = new Command();
11
+ program
12
+ .name("octopus")
13
+ .description("Octopus CLI — AI-powered PR review and codebase intelligence")
14
+ .version("0.1.0");
15
+ program.addCommand(loginCommand);
16
+ program.addCommand(logoutCommand);
17
+ program.addCommand(whoamiCommand);
18
+ program.addCommand(configCommand);
19
+ program.addCommand(usageCommand);
20
+ program.addCommand(repoCommand);
21
+ program.addCommand(prCommand);
22
+ program.addCommand(knowledgeCommand);
23
+ program.parse();
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,8DAA8D,CAAC;KAC3E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AAC9B,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAErC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare class ApiError extends Error {
2
+ status: number;
3
+ constructor(status: number, message: string);
4
+ }
5
+ export declare function apiGet<T>(path: string): Promise<T>;
6
+ export declare function apiPost<T>(path: string, body?: unknown): Promise<T>;
7
+ export declare function apiDelete<T>(path: string): Promise<T>;
8
+ export declare function apiStream(path: string, body: unknown, onData: (data: {
9
+ type: string;
10
+ [key: string]: unknown;
11
+ }) => void): Promise<void>;
@@ -0,0 +1,90 @@
1
+ import { getApiUrl, getApiToken } from "./config-store.js";
2
+ export class ApiError extends Error {
3
+ status;
4
+ constructor(status, message) {
5
+ super(message);
6
+ this.status = status;
7
+ this.name = "ApiError";
8
+ }
9
+ }
10
+ function getHeaders() {
11
+ const token = getApiToken();
12
+ if (!token) {
13
+ throw new Error("Not logged in. Run 'octopus login' first.");
14
+ }
15
+ return {
16
+ Authorization: `Bearer ${token}`,
17
+ "Content-Type": "application/json",
18
+ };
19
+ }
20
+ export async function apiGet(path) {
21
+ const url = `${getApiUrl()}${path}`;
22
+ const res = await fetch(url, { headers: getHeaders() });
23
+ if (!res.ok) {
24
+ const body = await res.json().catch(() => ({ error: res.statusText }));
25
+ throw new ApiError(res.status, body.error ?? res.statusText);
26
+ }
27
+ return res.json();
28
+ }
29
+ export async function apiPost(path, body) {
30
+ const url = `${getApiUrl()}${path}`;
31
+ const res = await fetch(url, {
32
+ method: "POST",
33
+ headers: getHeaders(),
34
+ body: body !== undefined ? JSON.stringify(body) : undefined,
35
+ });
36
+ if (!res.ok) {
37
+ const data = await res.json().catch(() => ({ error: res.statusText }));
38
+ throw new ApiError(res.status, data.error ?? res.statusText);
39
+ }
40
+ return res.json();
41
+ }
42
+ export async function apiDelete(path) {
43
+ const url = `${getApiUrl()}${path}`;
44
+ const res = await fetch(url, {
45
+ method: "DELETE",
46
+ headers: getHeaders(),
47
+ });
48
+ if (!res.ok) {
49
+ const data = await res.json().catch(() => ({ error: res.statusText }));
50
+ throw new ApiError(res.status, data.error ?? res.statusText);
51
+ }
52
+ return res.json();
53
+ }
54
+ export async function apiStream(path, body, onData) {
55
+ const url = `${getApiUrl()}${path}`;
56
+ const res = await fetch(url, {
57
+ method: "POST",
58
+ headers: getHeaders(),
59
+ body: JSON.stringify(body),
60
+ });
61
+ if (!res.ok) {
62
+ const data = await res.json().catch(() => ({ error: res.statusText }));
63
+ throw new ApiError(res.status, data.error ?? res.statusText);
64
+ }
65
+ const reader = res.body?.getReader();
66
+ if (!reader)
67
+ throw new Error("No response body");
68
+ const decoder = new TextDecoder();
69
+ let buffer = "";
70
+ while (true) {
71
+ const { done, value } = await reader.read();
72
+ if (done)
73
+ break;
74
+ buffer += decoder.decode(value, { stream: true });
75
+ const lines = buffer.split("\n");
76
+ buffer = lines.pop() ?? "";
77
+ for (const line of lines) {
78
+ if (line.startsWith("data: ")) {
79
+ const data = line.slice(6).trim();
80
+ if (data === "[DONE]")
81
+ return;
82
+ try {
83
+ onData(JSON.parse(data));
84
+ }
85
+ catch { }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { CliConfig, CliProfile } from "../types.js";
2
+ export declare function loadConfig(): CliConfig;
3
+ export declare function saveConfig(config: CliConfig): void;
4
+ export declare function getActiveProfile(): CliProfile | null;
5
+ export declare function setProfile(name: string, profile: CliProfile): void;
6
+ export declare function removeProfile(name: string): void;
7
+ export declare function getApiUrl(): string;
8
+ export declare function getApiToken(): string | null;
@@ -0,0 +1,57 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const CONFIG_DIR = join(homedir(), ".config", "octopus");
5
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
6
+ function ensureConfigDir() {
7
+ if (!existsSync(CONFIG_DIR)) {
8
+ mkdirSync(CONFIG_DIR, { recursive: true });
9
+ }
10
+ }
11
+ export function loadConfig() {
12
+ try {
13
+ const data = readFileSync(CONFIG_FILE, "utf-8");
14
+ return JSON.parse(data);
15
+ }
16
+ catch {
17
+ return { profiles: {}, activeProfile: "default" };
18
+ }
19
+ }
20
+ export function saveConfig(config) {
21
+ ensureConfigDir();
22
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
23
+ try {
24
+ chmodSync(CONFIG_FILE, 0o600);
25
+ }
26
+ catch { }
27
+ }
28
+ export function getActiveProfile() {
29
+ const config = loadConfig();
30
+ return config.profiles[config.activeProfile] ?? null;
31
+ }
32
+ export function setProfile(name, profile) {
33
+ const config = loadConfig();
34
+ config.profiles[name] = profile;
35
+ config.activeProfile = name;
36
+ saveConfig(config);
37
+ }
38
+ export function removeProfile(name) {
39
+ const config = loadConfig();
40
+ delete config.profiles[name];
41
+ if (config.activeProfile === name) {
42
+ const remaining = Object.keys(config.profiles);
43
+ config.activeProfile = remaining[0] ?? "default";
44
+ }
45
+ saveConfig(config);
46
+ }
47
+ export function getApiUrl() {
48
+ return process.env.OCTOPUS_API_URL
49
+ ?? getActiveProfile()?.apiUrl
50
+ ?? "https://octopus-review.ai";
51
+ }
52
+ export function getApiToken() {
53
+ return process.env.OCTOPUS_API_KEY
54
+ ?? getActiveProfile()?.token
55
+ ?? null;
56
+ }
57
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/lib/config-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AACzD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,OAAmB;IAC1D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IAChC,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IACnD,CAAC;IACD,UAAU,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe;WAC7B,gBAAgB,EAAE,EAAE,MAAM;WAC1B,2BAA2B,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe;WAC7B,gBAAgB,EAAE,EAAE,KAAK;WACzB,IAAI,CAAC;AACZ,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare function success(msg: string): void;
2
+ export declare function error(msg: string): void;
3
+ export declare function warn(msg: string): void;
4
+ export declare function info(msg: string): void;
5
+ export declare function heading(msg: string): void;
6
+ export declare function table(rows: string[][], headers?: string[]): void;
7
+ export declare function formatDate(dateStr: string | null): string;
8
+ export declare function formatDuration(ms: number | null | undefined): string;
9
+ export declare function formatNumber(n: number): string;
10
+ export declare function formatUsd(n: number): string;
11
+ export declare function statusBadge(status: string): string;
@@ -0,0 +1,103 @@
1
+ import chalk from "chalk";
2
+ export function success(msg) {
3
+ console.log(chalk.green("✓") + " " + msg);
4
+ }
5
+ export function error(msg) {
6
+ console.error(chalk.red("✗") + " " + msg);
7
+ }
8
+ export function warn(msg) {
9
+ console.log(chalk.yellow("!") + " " + msg);
10
+ }
11
+ export function info(msg) {
12
+ console.log(chalk.blue("ℹ") + " " + msg);
13
+ }
14
+ export function heading(msg) {
15
+ console.log("\n" + chalk.bold(msg));
16
+ }
17
+ export function table(rows, headers) {
18
+ const allRows = headers ? [headers, ...rows] : rows;
19
+ // Calculate column widths
20
+ const colWidths = [];
21
+ for (const row of allRows) {
22
+ for (let i = 0; i < row.length; i++) {
23
+ colWidths[i] = Math.max(colWidths[i] ?? 0, stripAnsi(row[i]).length);
24
+ }
25
+ }
26
+ // Print header
27
+ if (headers) {
28
+ const headerLine = headers
29
+ .map((h, i) => chalk.bold(h.padEnd(colWidths[i])))
30
+ .join(" ");
31
+ console.log(headerLine);
32
+ console.log(colWidths.map((w) => "─".repeat(w)).join("──"));
33
+ }
34
+ // Print rows
35
+ const dataRows = headers ? rows : allRows;
36
+ for (const row of dataRows) {
37
+ const line = row
38
+ .map((cell, i) => {
39
+ const padding = colWidths[i] - stripAnsi(cell).length;
40
+ return cell + " ".repeat(Math.max(0, padding));
41
+ })
42
+ .join(" ");
43
+ console.log(line);
44
+ }
45
+ }
46
+ function stripAnsi(str) {
47
+ // eslint-disable-next-line no-control-regex
48
+ return str.replace(/\x1B\[[0-9;]*m/g, "");
49
+ }
50
+ export function formatDate(dateStr) {
51
+ if (!dateStr)
52
+ return "—";
53
+ const d = new Date(dateStr);
54
+ return d.toLocaleDateString("en-US", {
55
+ year: "numeric",
56
+ month: "short",
57
+ day: "numeric",
58
+ });
59
+ }
60
+ export function formatDuration(ms) {
61
+ if (!ms)
62
+ return "—";
63
+ if (ms < 1000)
64
+ return `${ms}ms`;
65
+ if (ms < 60_000)
66
+ return `${(ms / 1000).toFixed(1)}s`;
67
+ return `${(ms / 60_000).toFixed(1)}m`;
68
+ }
69
+ export function formatNumber(n) {
70
+ if (n >= 1_000_000)
71
+ return `${(n / 1_000_000).toFixed(1)}M`;
72
+ if (n >= 1_000)
73
+ return `${(n / 1_000).toFixed(1)}K`;
74
+ return n.toLocaleString();
75
+ }
76
+ export function formatUsd(n) {
77
+ if (n < 0.01)
78
+ return `$${n.toFixed(4)}`;
79
+ return `$${n.toFixed(2)}`;
80
+ }
81
+ export function statusBadge(status) {
82
+ switch (status) {
83
+ case "indexed":
84
+ case "ready":
85
+ case "completed":
86
+ case "done":
87
+ return chalk.green(status);
88
+ case "indexing":
89
+ case "analyzing":
90
+ case "reviewing":
91
+ case "processing":
92
+ return chalk.yellow(status);
93
+ case "failed":
94
+ case "error":
95
+ return chalk.red(status);
96
+ case "pending":
97
+ case "none":
98
+ return chalk.dim(status);
99
+ default:
100
+ return status;
101
+ }
102
+ }
103
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ApiRepo } from "../types.js";
2
+ /**
3
+ * Resolve a repo argument to an API repo.
4
+ * - If repoArg is provided, search by name/fullName
5
+ * - If not provided, detect from CWD git remote
6
+ */
7
+ export declare function resolveRepo(repoArg?: string): Promise<ApiRepo>;