@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.
- package/bin/octopus.js +2 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +86 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/knowledge/add.d.ts +2 -0
- package/dist/commands/knowledge/add.js +33 -0
- package/dist/commands/knowledge/add.js.map +1 -0
- package/dist/commands/knowledge/index.d.ts +2 -0
- package/dist/commands/knowledge/index.js +10 -0
- package/dist/commands/knowledge/index.js.map +1 -0
- package/dist/commands/knowledge/list.d.ts +2 -0
- package/dist/commands/knowledge/list.js +32 -0
- package/dist/commands/knowledge/list.js.map +1 -0
- package/dist/commands/knowledge/remove.d.ts +2 -0
- package/dist/commands/knowledge/remove.js +20 -0
- package/dist/commands/knowledge/remove.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +142 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +16 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pr/index.d.ts +2 -0
- package/dist/commands/pr/index.js +6 -0
- package/dist/commands/pr/index.js.map +1 -0
- package/dist/commands/pr/review.d.ts +2 -0
- package/dist/commands/pr/review.js +47 -0
- package/dist/commands/pr/review.js.map +1 -0
- package/dist/commands/repo/analyze.d.ts +2 -0
- package/dist/commands/repo/analyze.js +48 -0
- package/dist/commands/repo/analyze.js.map +1 -0
- package/dist/commands/repo/chat.d.ts +2 -0
- package/dist/commands/repo/chat.js +67 -0
- package/dist/commands/repo/chat.js.map +1 -0
- package/dist/commands/repo/index-cmd.d.ts +2 -0
- package/dist/commands/repo/index-cmd.js +47 -0
- package/dist/commands/repo/index-cmd.js.map +1 -0
- package/dist/commands/repo/index.d.ts +2 -0
- package/dist/commands/repo/index.js +14 -0
- package/dist/commands/repo/index.js.map +1 -0
- package/dist/commands/repo/list.d.ts +2 -0
- package/dist/commands/repo/list.js +32 -0
- package/dist/commands/repo/list.js.map +1 -0
- package/dist/commands/repo/status.d.ts +2 -0
- package/dist/commands/repo/status.js +45 -0
- package/dist/commands/repo/status.js.map +1 -0
- package/dist/commands/usage.d.ts +2 -0
- package/dist/commands/usage.js +41 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +27 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +11 -0
- package/dist/lib/api-client.js +90 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/config-store.d.ts +8 -0
- package/dist/lib/config-store.js +57 -0
- package/dist/lib/config-store.js.map +1 -0
- package/dist/lib/output.d.ts +11 -0
- package/dist/lib/output.js +103 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/repo-resolver.d.ts +7 -0
- package/dist/lib/repo-resolver.js +64 -0
- package/dist/lib/repo-resolver.js.map +1 -0
- package/dist/lib/spinner.d.ts +3 -0
- package/dist/lib/spinner.js +17 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
package/bin/octopus.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { loadConfig, saveConfig } from "../lib/config-store.js";
|
|
3
|
+
import { success, error, heading, table } from "../lib/output.js";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
export const configCommand = new Command("config")
|
|
6
|
+
.description("Manage CLI configuration");
|
|
7
|
+
configCommand
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List all profiles")
|
|
10
|
+
.action(() => {
|
|
11
|
+
const config = loadConfig();
|
|
12
|
+
const profiles = Object.entries(config.profiles);
|
|
13
|
+
if (profiles.length === 0) {
|
|
14
|
+
console.log("No profiles configured. Run 'octopus login' to get started.");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
heading("Profiles");
|
|
18
|
+
const rows = profiles.map(([name, p]) => [
|
|
19
|
+
name === config.activeProfile ? chalk.green(`* ${name}`) : ` ${name}`,
|
|
20
|
+
p.orgSlug,
|
|
21
|
+
p.apiUrl,
|
|
22
|
+
p.token.slice(0, 8) + "...",
|
|
23
|
+
]);
|
|
24
|
+
table(rows, ["Profile", "Org", "API URL", "Token"]);
|
|
25
|
+
console.log();
|
|
26
|
+
});
|
|
27
|
+
configCommand
|
|
28
|
+
.command("set <key> <value>")
|
|
29
|
+
.description("Set a config value (apiUrl, activeProfile)")
|
|
30
|
+
.action((key, value) => {
|
|
31
|
+
const config = loadConfig();
|
|
32
|
+
if (key === "activeProfile") {
|
|
33
|
+
if (!config.profiles[value]) {
|
|
34
|
+
error(`Profile "${value}" not found.`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
config.activeProfile = value;
|
|
38
|
+
saveConfig(config);
|
|
39
|
+
success(`Active profile set to "${value}".`);
|
|
40
|
+
}
|
|
41
|
+
else if (key === "apiUrl") {
|
|
42
|
+
try {
|
|
43
|
+
new URL(value);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
error(`Invalid URL format: ${value}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const profile = config.profiles[config.activeProfile];
|
|
50
|
+
if (!profile) {
|
|
51
|
+
error("No active profile. Run 'octopus login' first.");
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
profile.apiUrl = value;
|
|
55
|
+
saveConfig(config);
|
|
56
|
+
success(`API URL set to "${value}".`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
error(`Unknown config key: ${key}. Valid keys: apiUrl, activeProfile`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
configCommand
|
|
64
|
+
.command("get <key>")
|
|
65
|
+
.description("Get a config value")
|
|
66
|
+
.action((key) => {
|
|
67
|
+
const config = loadConfig();
|
|
68
|
+
const profile = config.profiles[config.activeProfile];
|
|
69
|
+
if (key === "activeProfile") {
|
|
70
|
+
console.log(config.activeProfile);
|
|
71
|
+
}
|
|
72
|
+
else if (key === "apiUrl") {
|
|
73
|
+
console.log(profile?.apiUrl ?? "not set");
|
|
74
|
+
}
|
|
75
|
+
else if (key === "orgSlug") {
|
|
76
|
+
console.log(profile?.orgSlug ?? "not set");
|
|
77
|
+
}
|
|
78
|
+
else if (key === "orgId") {
|
|
79
|
+
console.log(profile?.orgId ?? "not set");
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
error(`Unknown config key: ${key}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { basename } from "node:path";
|
|
4
|
+
import { apiPost } from "../../lib/api-client.js";
|
|
5
|
+
import { error, success } from "../../lib/output.js";
|
|
6
|
+
import { withSpinner } from "../../lib/spinner.js";
|
|
7
|
+
export const knowledgeAddCommand = new Command("add")
|
|
8
|
+
.argument("<file>", "File path to add as knowledge document")
|
|
9
|
+
.option("--title <title>", "Document title (defaults to filename)")
|
|
10
|
+
.description("Add a file to the knowledge base")
|
|
11
|
+
.action(async (filePath, opts) => {
|
|
12
|
+
try {
|
|
13
|
+
let content;
|
|
14
|
+
try {
|
|
15
|
+
content = readFileSync(filePath, "utf-8");
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
error(`Could not read file: ${filePath}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const fileName = basename(filePath);
|
|
22
|
+
const title = opts.title ?? fileName;
|
|
23
|
+
const result = await withSpinner(`Uploading ${fileName}...`, async () => {
|
|
24
|
+
return apiPost("/api/cli/knowledge", { title, content, fileName });
|
|
25
|
+
});
|
|
26
|
+
success(`Added "${result.document.title}" (${result.document.id})`);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
error(err instanceof Error ? err.message : "Failed to add document");
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/commands/knowledge/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC;KAClD,QAAQ,CAAC,QAAQ,EAAE,wCAAwC,CAAC;KAC5D,MAAM,CAAC,iBAAiB,EAAE,uCAAuC,CAAC;KAClE,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAwB,EAAE,EAAE;IAC3D,IAAI,CAAC;QACH,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC;QAErC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,aAAa,QAAQ,KAAK,EAAE,KAAK,IAAI,EAAE;YACtE,OAAO,OAAO,CACZ,oBAAoB,EACpB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAC7B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,UAAU,MAAM,CAAC,QAAQ,CAAC,KAAK,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { knowledgeListCommand } from "./list.js";
|
|
3
|
+
import { knowledgeAddCommand } from "./add.js";
|
|
4
|
+
import { knowledgeRemoveCommand } from "./remove.js";
|
|
5
|
+
export const knowledgeCommand = new Command("knowledge")
|
|
6
|
+
.description("Manage knowledge base documents");
|
|
7
|
+
knowledgeCommand.addCommand(knowledgeListCommand);
|
|
8
|
+
knowledgeCommand.addCommand(knowledgeAddCommand);
|
|
9
|
+
knowledgeCommand.addCommand(knowledgeRemoveCommand);
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/knowledge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC;KACrD,WAAW,CAAC,iCAAiC,CAAC,CAAC;AAElD,gBAAgB,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAClD,gBAAgB,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AACjD,gBAAgB,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC"}
|
|
@@ -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 knowledgeListCommand = new Command("list")
|
|
6
|
+
.description("List knowledge base documents")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const { documents } = await withSpinner("Fetching documents...", async () => {
|
|
10
|
+
return apiGet("/api/cli/knowledge");
|
|
11
|
+
});
|
|
12
|
+
if (documents.length === 0) {
|
|
13
|
+
console.log("No knowledge documents found. Use 'octopus knowledge add' to add one.");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const rows = documents.map((d) => [
|
|
17
|
+
d.id.slice(0, 8),
|
|
18
|
+
d.title,
|
|
19
|
+
d.sourceType,
|
|
20
|
+
statusBadge(d.status),
|
|
21
|
+
String(d.totalChunks),
|
|
22
|
+
formatDate(d.createdAt),
|
|
23
|
+
]);
|
|
24
|
+
table(rows, ["ID", "Title", "Type", "Status", "Chunks", "Created"]);
|
|
25
|
+
console.log(`\n${documents.length} documents total`);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
error(err instanceof Error ? err.message : "Failed to list documents");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/knowledge/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,oBAAoB,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KACpD,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,WAAW,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YAC1E,OAAO,MAAM,CAAqC,oBAAoB,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;YACrF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAChC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAChB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,UAAU;YACZ,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;YACrB,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;YACrB,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;SACxB,CAAC,CAAC;QAEH,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,MAAM,kBAAkB,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { apiDelete } from "../../lib/api-client.js";
|
|
3
|
+
import { error, success } from "../../lib/output.js";
|
|
4
|
+
import { withSpinner } from "../../lib/spinner.js";
|
|
5
|
+
export const knowledgeRemoveCommand = new Command("remove")
|
|
6
|
+
.argument("<id>", "Document ID to remove")
|
|
7
|
+
.description("Remove a knowledge document (soft delete)")
|
|
8
|
+
.action(async (id) => {
|
|
9
|
+
try {
|
|
10
|
+
await withSpinner("Removing document...", async () => {
|
|
11
|
+
return apiDelete(`/api/cli/knowledge/${id}`);
|
|
12
|
+
});
|
|
13
|
+
success(`Document ${id} removed.`);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
error(err instanceof Error ? err.message : "Failed to remove document");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../../src/commands/knowledge/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KACxD,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;KACzC,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACnD,OAAO,SAAS,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { setProfile, getApiUrl } from "../lib/config-store.js";
|
|
4
|
+
import { success, error, info } from "../lib/output.js";
|
|
5
|
+
import { withSpinner } from "../lib/spinner.js";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
const MAX_POLL_ATTEMPTS = 200;
|
|
8
|
+
const POLL_INTERVAL_MS = 2000;
|
|
9
|
+
function openBrowser(url) {
|
|
10
|
+
try {
|
|
11
|
+
new URL(url);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new Error("Invalid authorization URL");
|
|
15
|
+
}
|
|
16
|
+
const cmd = process.platform === "darwin"
|
|
17
|
+
? "open"
|
|
18
|
+
: process.platform === "win32"
|
|
19
|
+
? "start"
|
|
20
|
+
: "xdg-open";
|
|
21
|
+
spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
|
|
22
|
+
}
|
|
23
|
+
async function deviceFlow(apiUrl, profile) {
|
|
24
|
+
// Step 1: Request a device code
|
|
25
|
+
const deviceRes = await fetch(`${apiUrl}/api/cli/auth/device`, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
});
|
|
28
|
+
if (!deviceRes.ok) {
|
|
29
|
+
if (deviceRes.status === 404) {
|
|
30
|
+
throw new Error("Device authorization endpoint not found. Is the server up to date?");
|
|
31
|
+
}
|
|
32
|
+
if (deviceRes.status === 429) {
|
|
33
|
+
throw new Error("Too many login attempts. Please wait a minute and try again.");
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Failed to initiate login (HTTP ${deviceRes.status}). Is the server running?`);
|
|
36
|
+
}
|
|
37
|
+
const deviceData = (await deviceRes.json());
|
|
38
|
+
const deviceCode = deviceData.deviceCode;
|
|
39
|
+
const expiresAt = deviceData.expiresAt;
|
|
40
|
+
if (typeof deviceCode !== "string" || typeof expiresAt !== "string") {
|
|
41
|
+
throw new Error("Invalid response from device authorization endpoint");
|
|
42
|
+
}
|
|
43
|
+
// Step 2: Open browser
|
|
44
|
+
const authorizeUrl = `${apiUrl}/cli/authorize?code=${deviceCode}`;
|
|
45
|
+
info("");
|
|
46
|
+
info("Opening browser to authorize...");
|
|
47
|
+
info(chalk.dim(authorizeUrl));
|
|
48
|
+
info("");
|
|
49
|
+
openBrowser(authorizeUrl);
|
|
50
|
+
info("Waiting for authorization (press Ctrl+C to cancel)...");
|
|
51
|
+
// Step 3: Poll for token
|
|
52
|
+
const expiry = new Date(expiresAt).getTime();
|
|
53
|
+
let attempts = 0;
|
|
54
|
+
while (attempts < MAX_POLL_ATTEMPTS) {
|
|
55
|
+
if (Date.now() > expiry) {
|
|
56
|
+
throw new Error("Authorization timed out. Please try again.");
|
|
57
|
+
}
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
59
|
+
attempts++;
|
|
60
|
+
let pollRes;
|
|
61
|
+
try {
|
|
62
|
+
pollRes = await fetch(`${apiUrl}/api/cli/auth/poll?device_code=${deviceCode}`);
|
|
63
|
+
}
|
|
64
|
+
catch (networkError) {
|
|
65
|
+
if (attempts > 5) {
|
|
66
|
+
throw new Error(`Network error during authorization: ${networkError instanceof Error ? networkError.message : String(networkError)}`);
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (pollRes.status === 410) {
|
|
71
|
+
throw new Error("Authorization expired. Please try again.");
|
|
72
|
+
}
|
|
73
|
+
if (!pollRes.ok && pollRes.status !== 200) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const data = (await pollRes.json());
|
|
77
|
+
if (data.status === "approved" && data.token && data.organization) {
|
|
78
|
+
setProfile(profile, {
|
|
79
|
+
apiUrl,
|
|
80
|
+
token: data.token,
|
|
81
|
+
orgSlug: data.organization.slug,
|
|
82
|
+
orgId: data.organization.id,
|
|
83
|
+
});
|
|
84
|
+
const userName = data.user?.name || "Unknown User";
|
|
85
|
+
const userEmail = data.user?.email ? ` (${data.user.email})` : "";
|
|
86
|
+
info("");
|
|
87
|
+
success(`Logged in as ${userName}${userEmail} — org: ${data.organization.name}`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw new Error("Authorization timed out after too many attempts.");
|
|
92
|
+
}
|
|
93
|
+
async function tokenFlow(token, apiUrl, profile) {
|
|
94
|
+
const result = await withSpinner("Verifying token...", async () => {
|
|
95
|
+
const res = await fetch(`${apiUrl}/api/cli/auth/verify`, {
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: {
|
|
98
|
+
Authorization: `Bearer ${token}`,
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok) {
|
|
103
|
+
const body = (await res.json().catch(() => ({})));
|
|
104
|
+
throw new Error(body.error ?? "Invalid token");
|
|
105
|
+
}
|
|
106
|
+
return res.json();
|
|
107
|
+
});
|
|
108
|
+
setProfile(profile, {
|
|
109
|
+
apiUrl,
|
|
110
|
+
token,
|
|
111
|
+
orgSlug: result.organization.slug,
|
|
112
|
+
orgId: result.organization.id,
|
|
113
|
+
});
|
|
114
|
+
success(`Logged in as ${result.user.name} (${result.user.email}) — org: ${result.organization.name}`);
|
|
115
|
+
}
|
|
116
|
+
export const loginCommand = new Command("login")
|
|
117
|
+
.description("Authenticate with Octopus (opens browser or use --token)")
|
|
118
|
+
.option("--token <token>", "API token (oct_...) — skip browser auth")
|
|
119
|
+
.option("--api-url <url>", "API base URL")
|
|
120
|
+
.option("--profile <name>", "Profile name", "default")
|
|
121
|
+
.action(async (opts) => {
|
|
122
|
+
const apiUrl = opts.apiUrl ?? getApiUrl();
|
|
123
|
+
try {
|
|
124
|
+
if (opts.token) {
|
|
125
|
+
// Direct token flow
|
|
126
|
+
if (!opts.token.startsWith("oct_")) {
|
|
127
|
+
error("Invalid token format. Token must start with 'oct_'.");
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
await tokenFlow(opts.token, apiUrl, opts.profile);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// Device authorization flow (browser-based)
|
|
134
|
+
await deviceFlow(apiUrl, opts.profile);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
error(err instanceof Error ? err.message : "Login failed");
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { removeProfile, loadConfig } from "../lib/config-store.js";
|
|
3
|
+
import { success, warn } from "../lib/output.js";
|
|
4
|
+
export const logoutCommand = new Command("logout")
|
|
5
|
+
.description("Remove saved credentials")
|
|
6
|
+
.option("--profile <name>", "Profile to remove", "default")
|
|
7
|
+
.action((opts) => {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
if (!config.profiles[opts.profile]) {
|
|
10
|
+
warn(`Profile "${opts.profile}" not found.`);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
removeProfile(opts.profile);
|
|
14
|
+
success(`Logged out from profile "${opts.profile}".`);
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,SAAS,CAAC;KAC1D,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IACf,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,cAAc,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,4BAA4B,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/pr/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;KACvC,WAAW,CAAC,yBAAyB,CAAC,CAAC;AAE1C,SAAS,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { resolveRepo } from "../../lib/repo-resolver.js";
|
|
3
|
+
import { apiPost } from "../../lib/api-client.js";
|
|
4
|
+
import { error, info } from "../../lib/output.js";
|
|
5
|
+
import { createSpinner } from "../../lib/spinner.js";
|
|
6
|
+
/**
|
|
7
|
+
* Parse PR identifier — supports:
|
|
8
|
+
* - PR number: 123
|
|
9
|
+
* - GitHub URL: https://github.com/owner/repo/pull/123
|
|
10
|
+
*/
|
|
11
|
+
function parsePrArg(arg) {
|
|
12
|
+
// Try as a number
|
|
13
|
+
const num = parseInt(arg, 10);
|
|
14
|
+
if (!isNaN(num)) {
|
|
15
|
+
return { prNumber: num };
|
|
16
|
+
}
|
|
17
|
+
// Try as a GitHub URL
|
|
18
|
+
const match = arg.match(/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)/);
|
|
19
|
+
if (match) {
|
|
20
|
+
return { prNumber: parseInt(match[2], 10), repoFullName: match[1] };
|
|
21
|
+
}
|
|
22
|
+
// Try as a Bitbucket URL
|
|
23
|
+
const bbMatch = arg.match(/bitbucket\.org\/([^/]+\/[^/]+)\/pull-requests\/(\d+)/);
|
|
24
|
+
if (bbMatch) {
|
|
25
|
+
return { prNumber: parseInt(bbMatch[2], 10), repoFullName: bbMatch[1] };
|
|
26
|
+
}
|
|
27
|
+
throw new Error(`Invalid PR identifier: "${arg}". Use a PR number or URL.`);
|
|
28
|
+
}
|
|
29
|
+
export const prReviewCommand = new Command("review")
|
|
30
|
+
.argument("<pr>", "PR number or URL (e.g. 123 or https://github.com/owner/repo/pull/123)")
|
|
31
|
+
.description("Trigger an AI review on a pull request")
|
|
32
|
+
.action(async (prArg) => {
|
|
33
|
+
try {
|
|
34
|
+
const spinner = createSpinner("Resolving pull request...").start();
|
|
35
|
+
const { prNumber, repoFullName } = parsePrArg(prArg);
|
|
36
|
+
const repo = await resolveRepo(repoFullName);
|
|
37
|
+
spinner.text = `Starting review for ${repo.fullName} PR #${prNumber}...`;
|
|
38
|
+
await apiPost(`/api/cli/repos/${repo.id}/review`, { prNumber });
|
|
39
|
+
spinner.succeed(`Review triggered for ${repo.fullName} PR #${prNumber}`);
|
|
40
|
+
info("The review will be posted as a comment on the PR when complete.");
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
error(err instanceof Error ? err.message : "Failed to trigger review");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/commands/pr/review.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,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAW,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,kBAAkB;IAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,sBAAsB;IACtB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACpE,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,yBAAyB;IACzB,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAClF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,4BAA4B,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KACjD,QAAQ,CAAC,MAAM,EAAE,uEAAuE,CAAC;KACzF,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAC;QACnE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAErD,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,GAAG,uBAAuB,IAAI,CAAC,QAAQ,QAAQ,QAAQ,KAAK,CAAC;QAEzE,MAAM,OAAO,CAAC,kBAAkB,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,OAAO,CAAC,wBAAwB,IAAI,CAAC,QAAQ,QAAQ,QAAQ,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,iEAAiE,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 } from "../../lib/output.js";
|
|
5
|
+
import { createSpinner } from "../../lib/spinner.js";
|
|
6
|
+
export const repoAnalyzeCommand = new Command("analyze")
|
|
7
|
+
.argument("[repo]", "Repository name or full name (auto-detects from git remote)")
|
|
8
|
+
.description("Run AI analysis on a repository")
|
|
9
|
+
.action(async (repoArg) => {
|
|
10
|
+
try {
|
|
11
|
+
const spinner = createSpinner("Resolving repository...").start();
|
|
12
|
+
const repo = await resolveRepo(repoArg);
|
|
13
|
+
spinner.text = `Starting analysis for ${repo.fullName}...`;
|
|
14
|
+
await apiPost(`/api/cli/repos/${repo.id}/analyze`);
|
|
15
|
+
spinner.text = `Analyzing ${repo.fullName}...`;
|
|
16
|
+
// Poll for completion (max 10 minutes)
|
|
17
|
+
let analysisStatus = "analyzing";
|
|
18
|
+
let attempts = 0;
|
|
19
|
+
const maxAttempts = 200;
|
|
20
|
+
while (analysisStatus === "analyzing" && 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
|
+
analysisStatus = updated.analysisStatus;
|
|
25
|
+
if (analysisStatus === "done" || analysisStatus === "completed") {
|
|
26
|
+
spinner.succeed(`Analysis complete for ${repo.fullName}`);
|
|
27
|
+
if (updated.purpose)
|
|
28
|
+
info(`Purpose: ${updated.purpose}`);
|
|
29
|
+
if (updated.summary)
|
|
30
|
+
info(`Summary: ${updated.summary}`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (analysisStatus === "failed") {
|
|
34
|
+
spinner.fail(`Analysis failed for ${repo.fullName}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (attempts >= maxAttempts) {
|
|
39
|
+
spinner.fail(`Analysis timed out for ${repo.fullName} after ${maxAttempts * 3}s`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
error(err instanceof Error ? err.message : "Failed to analyze repository");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/commands/repo/analyze.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,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACrD,QAAQ,CAAC,QAAQ,EAAE,6DAA6D,CAAC;KACjF,WAAW,CAAC,iCAAiC,CAAC;KAC9C,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,yBAAyB,IAAI,CAAC,QAAQ,KAAK,CAAC;QAE3D,MAAM,OAAO,CAAC,kBAAkB,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,GAAG,aAAa,IAAI,CAAC,QAAQ,KAAK,CAAC;QAE/C,uCAAuC;QACvC,IAAI,cAAc,GAAG,WAAW,CAAC;QACjC,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,MAAM,WAAW,GAAG,GAAG,CAAC;QACxB,OAAO,cAAc,KAAK,WAAW,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;YAChE,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,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;YAExC,IAAI,cAAc,KAAK,MAAM,IAAI,cAAc,KAAK,WAAW,EAAE,CAAC;gBAChE,OAAO,CAAC,OAAO,CAAC,yBAAyB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC1D,IAAI,OAAO,CAAC,OAAO;oBAAE,IAAI,CAAC,YAAY,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzD,IAAI,OAAO,CAAC,OAAO;oBAAE,IAAI,CAAC,YAAY,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YAED,IAAI,cAAc,KAAK,QAAQ,EAAE,CAAC;gBAChC,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,8BAA8B,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { createInterface } from "node:readline/promises";
|
|
3
|
+
import { stdin, stdout } from "node:process";
|
|
4
|
+
import { resolveRepo } from "../../lib/repo-resolver.js";
|
|
5
|
+
import { apiStream } from "../../lib/api-client.js";
|
|
6
|
+
import { error, info } from "../../lib/output.js";
|
|
7
|
+
import { withSpinner } from "../../lib/spinner.js";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
export const repoChatCommand = new Command("chat")
|
|
10
|
+
.argument("[repo]", "Repository name or full name (auto-detects from git remote)")
|
|
11
|
+
.description("Start an interactive chat about a repository")
|
|
12
|
+
.action(async (repoArg) => {
|
|
13
|
+
try {
|
|
14
|
+
const repo = await withSpinner("Resolving repository...", async () => {
|
|
15
|
+
return resolveRepo(repoArg);
|
|
16
|
+
});
|
|
17
|
+
info(`Chatting about ${chalk.bold(repo.fullName)}. Type 'exit' or Ctrl+C to quit.\n`);
|
|
18
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
19
|
+
let conversationId = null;
|
|
20
|
+
let isClosed = false;
|
|
21
|
+
rl.on("close", () => { isClosed = true; });
|
|
22
|
+
const promptUser = async () => {
|
|
23
|
+
try {
|
|
24
|
+
if (isClosed)
|
|
25
|
+
return;
|
|
26
|
+
const message = await rl.question(chalk.cyan("you> "));
|
|
27
|
+
if (!message.trim()) {
|
|
28
|
+
await promptUser();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (message.trim().toLowerCase() === "exit") {
|
|
32
|
+
rl.close();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
process.stdout.write(chalk.green("octopus> "));
|
|
36
|
+
await apiStream("/api/cli/chat", {
|
|
37
|
+
message,
|
|
38
|
+
conversationId,
|
|
39
|
+
repoId: repo.id,
|
|
40
|
+
}, (data) => {
|
|
41
|
+
if (data.type === "conversation_id") {
|
|
42
|
+
conversationId = data.id;
|
|
43
|
+
}
|
|
44
|
+
else if (data.type === "delta") {
|
|
45
|
+
process.stdout.write(data.text);
|
|
46
|
+
}
|
|
47
|
+
else if (data.type === "error") {
|
|
48
|
+
process.stdout.write(chalk.red(`\nError: ${data.message}`));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
process.stdout.write("\n\n");
|
|
52
|
+
await promptUser();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (isClosed || err.code === "ERR_USE_AFTER_CLOSE")
|
|
56
|
+
return;
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
await promptUser();
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
error(err instanceof Error ? err.message : "Chat failed");
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/commands/repo/chat.ts"],"names":[],"mappings":"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"}
|