codowave 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -0
- package/dist/index.js +572 -646
- package/dist/index.js.map +1 -1
- package/package.json +4 -6
package/dist/index.js
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var __esm = (fn, res) => function __init() {
|
|
4
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
-
};
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { Command as Command7 } from "commander";
|
|
10
3
|
|
|
11
4
|
// src/config.ts
|
|
12
5
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
13
6
|
import { join } from "path";
|
|
14
7
|
import { homedir } from "os";
|
|
15
8
|
import { z } from "zod";
|
|
9
|
+
var AIProviderSchema = z.object({
|
|
10
|
+
provider: z.enum(["openai", "anthropic", "minimax", "ollama", "custom"]),
|
|
11
|
+
apiKey: z.string().min(1),
|
|
12
|
+
model: z.string().default(""),
|
|
13
|
+
baseUrl: z.string().url().optional()
|
|
14
|
+
});
|
|
15
|
+
var ConfigSchema = z.object({
|
|
16
|
+
apiKey: z.string().min(1),
|
|
17
|
+
apiUrl: z.string().url().default("https://api.codowave.com"),
|
|
18
|
+
repos: z.array(
|
|
19
|
+
z.object({
|
|
20
|
+
owner: z.string(),
|
|
21
|
+
name: z.string(),
|
|
22
|
+
id: z.string().optional()
|
|
23
|
+
})
|
|
24
|
+
).default([]),
|
|
25
|
+
ai: AIProviderSchema.optional()
|
|
26
|
+
});
|
|
27
|
+
var CONFIG_DIR = join(homedir(), ".codowave");
|
|
28
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
16
29
|
function readConfig() {
|
|
17
30
|
if (!existsSync(CONFIG_FILE)) {
|
|
18
31
|
return null;
|
|
@@ -61,32 +74,11 @@ function updateConfig(updates) {
|
|
|
61
74
|
function getConfigPath() {
|
|
62
75
|
return CONFIG_FILE;
|
|
63
76
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
provider: z.enum(["openai", "anthropic", "minimax", "ollama", "custom"]),
|
|
70
|
-
apiKey: z.string().min(1),
|
|
71
|
-
model: z.string().default(""),
|
|
72
|
-
baseUrl: z.string().url().optional()
|
|
73
|
-
});
|
|
74
|
-
ConfigSchema = z.object({
|
|
75
|
-
apiKey: z.string().min(1),
|
|
76
|
-
apiUrl: z.string().url().default("https://api.codowave.com"),
|
|
77
|
-
repos: z.array(
|
|
78
|
-
z.object({
|
|
79
|
-
owner: z.string(),
|
|
80
|
-
name: z.string(),
|
|
81
|
-
id: z.string().optional()
|
|
82
|
-
})
|
|
83
|
-
).default([]),
|
|
84
|
-
ai: AIProviderSchema.optional()
|
|
85
|
-
});
|
|
86
|
-
CONFIG_DIR = join(homedir(), ".codowave");
|
|
87
|
-
CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
88
|
-
}
|
|
89
|
-
});
|
|
77
|
+
|
|
78
|
+
// src/commands/init.tsx
|
|
79
|
+
import { Command } from "commander";
|
|
80
|
+
import pc2 from "picocolors";
|
|
81
|
+
import { render } from "ink";
|
|
90
82
|
|
|
91
83
|
// src/components/init/GithubAppStep.tsx
|
|
92
84
|
import { useState, useEffect } from "react";
|
|
@@ -98,277 +90,282 @@ import {
|
|
|
98
90
|
import Spinner from "ink-spinner";
|
|
99
91
|
import pc from "picocolors";
|
|
100
92
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
101
|
-
var GithubAppStep
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
93
|
+
var GithubAppStep = ({ apiUrl, onComplete, onCancel }) => {
|
|
94
|
+
const [step, setStep] = useState("api-key");
|
|
95
|
+
const [apiKey, setApiKey] = useState("");
|
|
96
|
+
const [repos, setRepos] = useState([]);
|
|
97
|
+
const [selectedRepos, setSelectedRepos] = useState(/* @__PURE__ */ new Set());
|
|
98
|
+
const [currentSelection, setCurrentSelection] = useState(0);
|
|
99
|
+
const [loading, setLoading] = useState(false);
|
|
100
|
+
const [error, setError] = useState(null);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (step === "repos" && apiKey && repos.length === 0 && !loading) {
|
|
103
|
+
fetchRepos();
|
|
104
|
+
}
|
|
105
|
+
}, [step, apiKey]);
|
|
106
|
+
async function fetchRepos() {
|
|
107
|
+
setLoading(true);
|
|
108
|
+
setError(null);
|
|
109
|
+
try {
|
|
110
|
+
const response = await fetch(`${apiUrl}/api/v1/repos`, {
|
|
111
|
+
headers: {
|
|
112
|
+
Authorization: `Bearer ${apiKey}`,
|
|
113
|
+
"Content-Type": "application/json"
|
|
116
114
|
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
const response = await fetch(`${apiUrl}/api/v1/repos`, {
|
|
123
|
-
headers: {
|
|
124
|
-
Authorization: `Bearer ${apiKey}`,
|
|
125
|
-
"Content-Type": "application/json"
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
if (!response.ok) {
|
|
129
|
-
if (response.status === 401) {
|
|
130
|
-
throw new Error("Invalid API key. Please check and try again.");
|
|
131
|
-
}
|
|
132
|
-
throw new Error(`Failed to fetch repositories: ${response.status}`);
|
|
133
|
-
}
|
|
134
|
-
const data = await response.json();
|
|
135
|
-
const fetchedRepos = data.repos || data.repositories || [];
|
|
136
|
-
setRepos(fetchedRepos);
|
|
137
|
-
if (fetchedRepos.length > 0) {
|
|
138
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
139
|
-
for (let i = 0; i < fetchedRepos.length; i++) {
|
|
140
|
-
allIndices.add(i);
|
|
141
|
-
}
|
|
142
|
-
setSelectedRepos(allIndices);
|
|
143
|
-
}
|
|
144
|
-
} catch (err) {
|
|
145
|
-
setError(err instanceof Error ? err.message : "Failed to fetch repositories");
|
|
146
|
-
} finally {
|
|
147
|
-
setLoading(false);
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
if (response.status === 401) {
|
|
118
|
+
throw new Error("Invalid API key. Please check and try again.");
|
|
148
119
|
}
|
|
120
|
+
throw new Error(`Failed to fetch repositories: ${response.status}`);
|
|
149
121
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
122
|
+
const data = await response.json();
|
|
123
|
+
const fetchedRepos = data.repos || data.repositories || [];
|
|
124
|
+
setRepos(fetchedRepos);
|
|
125
|
+
if (fetchedRepos.length > 0) {
|
|
126
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
127
|
+
for (let i = 0; i < fetchedRepos.length; i++) {
|
|
128
|
+
allIndices.add(i);
|
|
154
129
|
}
|
|
155
|
-
|
|
156
|
-
setStep("repos");
|
|
130
|
+
setSelectedRepos(allIndices);
|
|
157
131
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
132
|
+
} catch (err) {
|
|
133
|
+
setError(err instanceof Error ? err.message : "Failed to fetch repositories");
|
|
134
|
+
} finally {
|
|
135
|
+
setLoading(false);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function handleApiKeySubmit() {
|
|
139
|
+
if (!apiKey.trim()) {
|
|
140
|
+
setError("API key cannot be empty");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
setError(null);
|
|
144
|
+
setStep("repos");
|
|
145
|
+
}
|
|
146
|
+
function handleConfirm() {
|
|
147
|
+
const selected = Array.from(selectedRepos).map((i) => repos[i]).filter((repo) => repo !== void 0);
|
|
148
|
+
onComplete(apiKey, selected);
|
|
149
|
+
}
|
|
150
|
+
function handleGoBack() {
|
|
151
|
+
setStep("api-key");
|
|
152
|
+
setError(null);
|
|
153
|
+
}
|
|
154
|
+
useInput((input, key) => {
|
|
155
|
+
if (step === "api-key") {
|
|
156
|
+
if (key.return) {
|
|
157
|
+
handleApiKeySubmit();
|
|
158
|
+
return;
|
|
161
159
|
}
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
if (key.escape) {
|
|
161
|
+
onCancel();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (key.backspace || input === "\b") {
|
|
165
|
+
setApiKey((prev) => prev.slice(0, -1));
|
|
164
166
|
setError(null);
|
|
167
|
+
return;
|
|
165
168
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (key.escape) {
|
|
173
|
-
onCancel();
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
if (key.backspace || input === "\b") {
|
|
177
|
-
setApiKey((prev) => prev.slice(0, -1));
|
|
178
|
-
setError(null);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (input && !key.ctrl && !key.meta) {
|
|
182
|
-
setApiKey((prev) => prev + input);
|
|
183
|
-
setError(null);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
} else if (step === "repos") {
|
|
187
|
-
if (key.escape) {
|
|
188
|
-
handleGoBack();
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (key.return) {
|
|
192
|
-
handleConfirm();
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
if (input === " ") {
|
|
196
|
-
toggleRepo(currentSelection);
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
if (key.upArrow) {
|
|
200
|
-
setCurrentSelection((prev) => Math.max(0, prev - 1));
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (key.downArrow) {
|
|
204
|
-
setCurrentSelection((prev) => Math.min(repos.length - 1, prev + 1));
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
if (input === "a" || input === "A") {
|
|
208
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
209
|
-
for (let i = 0; i < repos.length; i++) {
|
|
210
|
-
allIndices.add(i);
|
|
211
|
-
}
|
|
212
|
-
setSelectedRepos(allIndices);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
if (input === "n" || input === "N") {
|
|
216
|
-
setSelectedRepos(/* @__PURE__ */ new Set());
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
function toggleRepo(index) {
|
|
222
|
-
const newSelected = new Set(selectedRepos);
|
|
223
|
-
if (newSelected.has(index)) {
|
|
224
|
-
newSelected.delete(index);
|
|
225
|
-
} else {
|
|
226
|
-
newSelected.add(index);
|
|
227
|
-
}
|
|
228
|
-
setSelectedRepos(newSelected);
|
|
169
|
+
if (input && !key.ctrl && !key.meta) {
|
|
170
|
+
setApiKey((prev) => prev + input);
|
|
171
|
+
setError(null);
|
|
172
|
+
return;
|
|
229
173
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
235
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "> " }),
|
|
236
|
-
/* @__PURE__ */ jsx(Text, { children: apiKey }),
|
|
237
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "_" })
|
|
238
|
-
] }),
|
|
239
|
-
error && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: pc.red("\u2716 " + error) }) }),
|
|
240
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
241
|
-
"Press ",
|
|
242
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Enter" }),
|
|
243
|
-
" to continue, ",
|
|
244
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Esc" }),
|
|
245
|
-
" to cancel"
|
|
246
|
-
] }) })
|
|
247
|
-
] });
|
|
174
|
+
} else if (step === "repos") {
|
|
175
|
+
if (key.escape) {
|
|
176
|
+
handleGoBack();
|
|
177
|
+
return;
|
|
248
178
|
}
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
loading && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
253
|
-
/* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
254
|
-
" Loading repositories..."
|
|
255
|
-
] }) }),
|
|
256
|
-
error && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: pc.red("\u2716 " + error) }) }),
|
|
257
|
-
!loading && !error && repos.length === 0 && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No repositories found for this API key." }) }),
|
|
258
|
-
!loading && repos.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: repos.map((repo, index) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
259
|
-
/* @__PURE__ */ jsx(Text, { children: index === currentSelection ? " > " : " " }),
|
|
260
|
-
/* @__PURE__ */ jsxs(Text, { color: selectedRepos.has(index) ? "green" : "gray", children: [
|
|
261
|
-
"[",
|
|
262
|
-
selectedRepos.has(index) ? "\u2713" : " ",
|
|
263
|
-
"]"
|
|
264
|
-
] }),
|
|
265
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
266
|
-
/* @__PURE__ */ jsx(Text, { bold: index === currentSelection, children: /* @__PURE__ */ jsxs(Text, { dimColor: !selectedRepos.has(index), children: [
|
|
267
|
-
repo.owner,
|
|
268
|
-
"/",
|
|
269
|
-
repo.name
|
|
270
|
-
] }) })
|
|
271
|
-
] }, index)) }),
|
|
272
|
-
!loading && repos.length > 0 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
273
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "\u2191/\u2193" }),
|
|
274
|
-
" navigate | ",
|
|
275
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Space" }),
|
|
276
|
-
" toggle | ",
|
|
277
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "A" }),
|
|
278
|
-
" all | ",
|
|
279
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "N" }),
|
|
280
|
-
" none"
|
|
281
|
-
] }) }),
|
|
282
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
283
|
-
"Selected: ",
|
|
284
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: selectedRepos.size }),
|
|
285
|
-
" / ",
|
|
286
|
-
repos.length,
|
|
287
|
-
" repos | ",
|
|
288
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Enter" }),
|
|
289
|
-
" confirm | ",
|
|
290
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Esc" }),
|
|
291
|
-
" back"
|
|
292
|
-
] }) })
|
|
293
|
-
] });
|
|
179
|
+
if (key.return) {
|
|
180
|
+
handleConfirm();
|
|
181
|
+
return;
|
|
294
182
|
}
|
|
295
|
-
|
|
296
|
-
|
|
183
|
+
if (input === " ") {
|
|
184
|
+
toggleRepo(currentSelection);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (key.upArrow) {
|
|
188
|
+
setCurrentSelection((prev) => Math.max(0, prev - 1));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (key.downArrow) {
|
|
192
|
+
setCurrentSelection((prev) => Math.min(repos.length - 1, prev + 1));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (input === "a" || input === "A") {
|
|
196
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
197
|
+
for (let i = 0; i < repos.length; i++) {
|
|
198
|
+
allIndices.add(i);
|
|
199
|
+
}
|
|
200
|
+
setSelectedRepos(allIndices);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (input === "n" || input === "N") {
|
|
204
|
+
setSelectedRepos(/* @__PURE__ */ new Set());
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
function toggleRepo(index) {
|
|
210
|
+
const newSelected = new Set(selectedRepos);
|
|
211
|
+
if (newSelected.has(index)) {
|
|
212
|
+
newSelected.delete(index);
|
|
213
|
+
} else {
|
|
214
|
+
newSelected.add(index);
|
|
215
|
+
}
|
|
216
|
+
setSelectedRepos(newSelected);
|
|
297
217
|
}
|
|
298
|
-
|
|
218
|
+
if (step === "api-key") {
|
|
219
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingY: 1, children: [
|
|
220
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2550\u2550\u2550 GitHub App Setup \u2550\u2550\u2550" }) }),
|
|
221
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { children: "Enter your Codowave API key:" }) }),
|
|
222
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
223
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "> " }),
|
|
224
|
+
/* @__PURE__ */ jsx(Text, { children: apiKey }),
|
|
225
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "_" })
|
|
226
|
+
] }),
|
|
227
|
+
error && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: pc.red("\u2716 " + error) }) }),
|
|
228
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
229
|
+
"Press ",
|
|
230
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Enter" }),
|
|
231
|
+
" to continue, ",
|
|
232
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Esc" }),
|
|
233
|
+
" to cancel"
|
|
234
|
+
] }) })
|
|
235
|
+
] });
|
|
236
|
+
}
|
|
237
|
+
if (step === "repos") {
|
|
238
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingY: 1, children: [
|
|
239
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2550\u2550\u2550 Select Repositories \u2550\u2550\u2550" }) }),
|
|
240
|
+
loading && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
241
|
+
/* @__PURE__ */ jsx(Spinner, { type: "dots" }),
|
|
242
|
+
" Loading repositories..."
|
|
243
|
+
] }) }),
|
|
244
|
+
error && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: pc.red("\u2716 " + error) }) }),
|
|
245
|
+
!loading && !error && repos.length === 0 && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No repositories found for this API key." }) }),
|
|
246
|
+
!loading && repos.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: repos.map((repo, index) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
247
|
+
/* @__PURE__ */ jsx(Text, { children: index === currentSelection ? " > " : " " }),
|
|
248
|
+
/* @__PURE__ */ jsxs(Text, { color: selectedRepos.has(index) ? "green" : "gray", children: [
|
|
249
|
+
"[",
|
|
250
|
+
selectedRepos.has(index) ? "\u2713" : " ",
|
|
251
|
+
"]"
|
|
252
|
+
] }),
|
|
253
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
254
|
+
/* @__PURE__ */ jsx(Text, { bold: index === currentSelection, children: /* @__PURE__ */ jsxs(Text, { dimColor: !selectedRepos.has(index), children: [
|
|
255
|
+
repo.owner,
|
|
256
|
+
"/",
|
|
257
|
+
repo.name
|
|
258
|
+
] }) })
|
|
259
|
+
] }, index)) }),
|
|
260
|
+
!loading && repos.length > 0 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
261
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "\u2191/\u2193" }),
|
|
262
|
+
" navigate | ",
|
|
263
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Space" }),
|
|
264
|
+
" toggle | ",
|
|
265
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "A" }),
|
|
266
|
+
" all | ",
|
|
267
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "N" }),
|
|
268
|
+
" none"
|
|
269
|
+
] }) }),
|
|
270
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
271
|
+
"Selected: ",
|
|
272
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: selectedRepos.size }),
|
|
273
|
+
" / ",
|
|
274
|
+
repos.length,
|
|
275
|
+
" repos | ",
|
|
276
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Enter" }),
|
|
277
|
+
" confirm | ",
|
|
278
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Esc" }),
|
|
279
|
+
" back"
|
|
280
|
+
] }) })
|
|
281
|
+
] });
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
};
|
|
299
285
|
|
|
300
286
|
// src/commands/init.tsx
|
|
301
|
-
var init_exports = {};
|
|
302
|
-
__export(init_exports, {
|
|
303
|
-
initCommand: () => initCommand
|
|
304
|
-
});
|
|
305
|
-
import { Command } from "commander";
|
|
306
|
-
import pc2 from "picocolors";
|
|
307
|
-
import { render } from "ink";
|
|
308
287
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
309
|
-
var initCommand
|
|
310
|
-
|
|
311
|
-
"
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
let capturedApiKey = "";
|
|
328
|
-
let capturedRepos = [];
|
|
329
|
-
const { waitUntilExit } = render(
|
|
330
|
-
/* @__PURE__ */ jsx2(
|
|
331
|
-
GithubAppStep,
|
|
332
|
-
{
|
|
333
|
-
apiUrl,
|
|
334
|
-
onComplete: (apiKey, repos) => {
|
|
335
|
-
capturedApiKey = apiKey;
|
|
336
|
-
capturedRepos = repos;
|
|
337
|
-
wizardComplete = true;
|
|
338
|
-
},
|
|
339
|
-
onCancel: () => {
|
|
340
|
-
process.exit(0);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
)
|
|
344
|
-
);
|
|
345
|
-
await waitUntilExit();
|
|
346
|
-
if (!wizardComplete) {
|
|
347
|
-
return;
|
|
288
|
+
var initCommand = new Command("init").description("Initialize Codowave and connect your GitHub repositories").option("--api-key <key>", "Codowave API key (non-interactive mode)").option("--api-url <url>", "Codowave API URL").option("--github-app-id <id>", "GitHub App ID").option("--github-app-private-key <key>", "GitHub App private key path").option("--repos <repos>", "Comma-separated list of repos (owner/repo)").action(async (opts) => {
|
|
289
|
+
const existingConfig = readConfig();
|
|
290
|
+
const defaultApiUrl = "https://api.codowave.com";
|
|
291
|
+
if (opts.apiKey) {
|
|
292
|
+
const config2 = {
|
|
293
|
+
apiKey: opts.apiKey,
|
|
294
|
+
apiUrl: opts.apiUrl || existingConfig?.apiUrl || defaultApiUrl,
|
|
295
|
+
githubAppId: opts.githubAppId || "",
|
|
296
|
+
githubAppPrivateKey: opts.githubAppPrivateKey || "",
|
|
297
|
+
repos: opts.repos ? opts.repos.split(",").map((r) => {
|
|
298
|
+
const [owner, name] = r.trim().split("/");
|
|
299
|
+
return { owner, name };
|
|
300
|
+
}) : [],
|
|
301
|
+
autopilot: existingConfig?.autopilot ?? true,
|
|
302
|
+
labels: existingConfig?.labels || {
|
|
303
|
+
approved: "status/approved",
|
|
304
|
+
inProgress: "status/in-progress",
|
|
305
|
+
merged: "status/merged"
|
|
348
306
|
}
|
|
349
|
-
|
|
350
|
-
|
|
307
|
+
};
|
|
308
|
+
writeConfig(config2);
|
|
309
|
+
console.log(pc2.green("\n\u2705 Codowave initialized successfully!\n"));
|
|
310
|
+
console.log(` API URL: ${pc2.cyan(config2.apiUrl)}`);
|
|
311
|
+
console.log(` Repos: ${pc2.cyan(config2.repos.map((r) => `${r.owner}/${r.name}`).join(", ") || "none")}`);
|
|
312
|
+
console.log(pc2.gray(`
|
|
313
|
+
Config: ${getConfigPath()}
|
|
314
|
+
`));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const apiUrl = existingConfig?.apiUrl || defaultApiUrl;
|
|
318
|
+
if (existingConfig?.apiKey) {
|
|
319
|
+
console.log(pc2.yellow("\n\u26A0 Codowave is already initialized.\n"));
|
|
320
|
+
console.log(` API URL: ${pc2.cyan(existingConfig.apiUrl)}`);
|
|
321
|
+
console.log(` Config: ${getConfigPath()}`);
|
|
322
|
+
console.log(pc2.gray("\n Run with --api-key to reconfigure non-interactively.\n"));
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
let wizardComplete = false;
|
|
326
|
+
let capturedApiKey = "";
|
|
327
|
+
let capturedRepos = [];
|
|
328
|
+
const { waitUntilExit } = render(
|
|
329
|
+
/* @__PURE__ */ jsx2(
|
|
330
|
+
GithubAppStep,
|
|
331
|
+
{
|
|
351
332
|
apiUrl,
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
333
|
+
onComplete: (apiKey, repos) => {
|
|
334
|
+
capturedApiKey = apiKey;
|
|
335
|
+
capturedRepos = repos;
|
|
336
|
+
wizardComplete = true;
|
|
337
|
+
},
|
|
338
|
+
onCancel: () => {
|
|
339
|
+
process.exit(0);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
);
|
|
344
|
+
await waitUntilExit();
|
|
345
|
+
if (!wizardComplete) {
|
|
346
|
+
return;
|
|
362
347
|
}
|
|
348
|
+
const config = {
|
|
349
|
+
apiKey: capturedApiKey,
|
|
350
|
+
apiUrl,
|
|
351
|
+
repos: capturedRepos,
|
|
352
|
+
autopilot: true,
|
|
353
|
+
labels: {
|
|
354
|
+
approved: "status/approved",
|
|
355
|
+
inProgress: "status/in-progress",
|
|
356
|
+
merged: "status/merged"
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
writeConfig(config);
|
|
360
|
+
console.log(pc2.green("\n\u2705 Codowave initialized successfully!\n"));
|
|
361
|
+
console.log(pc2.gray(` Config: ${getConfigPath()}
|
|
362
|
+
`));
|
|
363
363
|
});
|
|
364
364
|
|
|
365
365
|
// src/commands/run.ts
|
|
366
|
-
var run_exports = {};
|
|
367
|
-
__export(run_exports, {
|
|
368
|
-
runCommand: () => runCommand
|
|
369
|
-
});
|
|
370
366
|
import { Command as Command2 } from "commander";
|
|
371
367
|
import pc3 from "picocolors";
|
|
368
|
+
var demoRuns = /* @__PURE__ */ new Map();
|
|
372
369
|
function parseIssue(input) {
|
|
373
370
|
const urlMatch = input.match(/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/);
|
|
374
371
|
if (urlMatch && urlMatch[1] && urlMatch[2] && urlMatch[3]) {
|
|
@@ -479,79 +476,67 @@ function streamDemoRun(run) {
|
|
|
479
476
|
process.exit(1);
|
|
480
477
|
});
|
|
481
478
|
}
|
|
482
|
-
var
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
const runId = await triggerRun(config, parsed);
|
|
517
|
-
console.log(pc3.green(`\u2713 Run triggered: ${runId}`));
|
|
518
|
-
if (_options.stream) {
|
|
519
|
-
console.log(pc3.blue("\nStreaming run progress..."));
|
|
520
|
-
} else {
|
|
521
|
-
console.log(pc3.gray(`
|
|
479
|
+
var runCommand = new Command2("run").description("Trigger Codowave to process a GitHub issue").argument("<issue>", "GitHub issue number, URL (https://github.com/owner/repo/issues/123), or owner/repo#123").option("-r, --repo <owner/repo>", "Target repository (e.g. owner/repo)").option("-s, --stream", "Stream run progress (SSE)", false).action(async (_issueArg, _options) => {
|
|
480
|
+
try {
|
|
481
|
+
const parsed = parseIssue(_issueArg);
|
|
482
|
+
if (!parsed) {
|
|
483
|
+
console.error(pc3.red("Invalid issue format. Use:"));
|
|
484
|
+
console.error(" - Issue number: 123");
|
|
485
|
+
console.error(" - Full URL: https://github.com/owner/repo/issues/123");
|
|
486
|
+
console.error(" - Short form: owner/repo#123");
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
if (_options.repo) {
|
|
490
|
+
const parts = _options.repo.split("/");
|
|
491
|
+
const owner = parts[0] || "";
|
|
492
|
+
const repo = parts[1] || "";
|
|
493
|
+
parsed.owner = owner;
|
|
494
|
+
parsed.repo = repo;
|
|
495
|
+
}
|
|
496
|
+
let config = null;
|
|
497
|
+
try {
|
|
498
|
+
config = readConfig();
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
if (config && config.apiKey && config.repos.length > 0) {
|
|
502
|
+
console.log(pc3.blue("Connecting to Codowave API..."));
|
|
503
|
+
if (!parsed.owner || !parsed.repo) {
|
|
504
|
+
console.error(pc3.red("Repository required. Use -r option or include in issue URL."));
|
|
505
|
+
process.exit(1);
|
|
506
|
+
}
|
|
507
|
+
const runId = await triggerRun(config, parsed);
|
|
508
|
+
console.log(pc3.green(`\u2713 Run triggered: ${runId}`));
|
|
509
|
+
if (_options.stream) {
|
|
510
|
+
console.log(pc3.blue("\nStreaming run progress..."));
|
|
511
|
+
} else {
|
|
512
|
+
console.log(pc3.gray(`
|
|
522
513
|
Run started. Use \`codowave status ${runId}\` to check progress.`));
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
514
|
+
}
|
|
515
|
+
} else {
|
|
516
|
+
console.log(pc3.yellow("\u26A0 No config found. Running in demo mode.\n"));
|
|
517
|
+
const run = createDemoRun(parsed);
|
|
518
|
+
if (_options.stream || !process.stdout.isTTY) {
|
|
519
|
+
streamDemoRun(run);
|
|
520
|
+
} else {
|
|
521
|
+
console.log(pc3.green(`\u2713 Run started: ${run.id}`));
|
|
522
|
+
console.log(pc3.gray(`
|
|
532
523
|
Use \`codowave status ${run.id}\` to check progress.`));
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
524
|
+
console.log(pc3.gray(`Use \`codowave logs ${run.id} -f\` to follow logs.`));
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
} catch (err) {
|
|
528
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
529
|
+
console.error(pc3.red(`
|
|
539
530
|
\u2716 Error: ${message}
|
|
540
531
|
`));
|
|
541
|
-
|
|
542
|
-
}
|
|
543
|
-
});
|
|
532
|
+
process.exit(1);
|
|
544
533
|
}
|
|
545
534
|
});
|
|
546
535
|
|
|
547
536
|
// src/commands/status.ts
|
|
548
|
-
var status_exports = {};
|
|
549
|
-
__export(status_exports, {
|
|
550
|
-
getRun: () => getRun,
|
|
551
|
-
statusCommand: () => statusCommand
|
|
552
|
-
});
|
|
553
537
|
import { Command as Command3 } from "commander";
|
|
554
538
|
import pc4 from "picocolors";
|
|
539
|
+
var demoRuns2 = /* @__PURE__ */ new Map();
|
|
555
540
|
function initDemoData() {
|
|
556
541
|
if (demoRuns2.size === 0) {
|
|
557
542
|
const demoRun = {
|
|
@@ -645,345 +630,286 @@ function formatDuration(startedAt, completedAt) {
|
|
|
645
630
|
const remainingMinutes = minutes % 60;
|
|
646
631
|
return `${hours}h ${remainingMinutes}m`;
|
|
647
632
|
}
|
|
648
|
-
var
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
}
|
|
696
|
-
console.log("");
|
|
697
|
-
} catch (err) {
|
|
698
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
699
|
-
console.error(pc4.red("\n=== Error: " + message + " ===\n"));
|
|
700
|
-
process.exit(1);
|
|
701
|
-
}
|
|
702
|
-
});
|
|
633
|
+
var statusCommand = new Command3("status").description("Show the status of a Codowave run").argument("[run-id]", "Run ID (defaults to latest)").option("-r, --repo <owner/repo>", "Filter by repository").action(async (_runId, _options) => {
|
|
634
|
+
try {
|
|
635
|
+
let config;
|
|
636
|
+
try {
|
|
637
|
+
config = readConfig();
|
|
638
|
+
} catch {
|
|
639
|
+
}
|
|
640
|
+
const run = getRun(_runId);
|
|
641
|
+
if (!run) {
|
|
642
|
+
console.log(pc4.yellow("No runs found. Run `codowave run <issue>` to start a new run."));
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (_options?.repo && run.repo !== _options.repo) {
|
|
646
|
+
console.log(pc4.yellow("No run found for repository " + _options.repo));
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
console.log(pc4.bold("\n=== Run Status ===\n"));
|
|
650
|
+
console.log(pc4.bold("ID: ") + run.id);
|
|
651
|
+
console.log(pc4.bold("Repo: ") + run.repo);
|
|
652
|
+
console.log(pc4.bold("Issue: ") + run.issue);
|
|
653
|
+
console.log(pc4.bold("Status: ") + formatStatus(run.status));
|
|
654
|
+
console.log(pc4.bold("Branch: ") + (run.branchName || pc4.gray("(none)")));
|
|
655
|
+
if (run.prNumber) {
|
|
656
|
+
console.log(pc4.bold("PR: ") + "#" + run.prNumber + " - " + (run.prTitle || ""));
|
|
657
|
+
}
|
|
658
|
+
if (run.startedAt) {
|
|
659
|
+
console.log(pc4.bold("Started: ") + new Date(run.startedAt).toLocaleString());
|
|
660
|
+
}
|
|
661
|
+
if (run.completedAt) {
|
|
662
|
+
console.log(pc4.bold("Duration: ") + formatDuration(run.startedAt, run.completedAt));
|
|
663
|
+
} else if (run.startedAt) {
|
|
664
|
+
console.log(pc4.bold("Duration: ") + pc4.blue("running... ") + formatDuration(run.startedAt));
|
|
665
|
+
}
|
|
666
|
+
if (run.errorMessage) {
|
|
667
|
+
console.log(pc4.bold("Error: ") + pc4.red(run.errorMessage));
|
|
668
|
+
}
|
|
669
|
+
console.log(pc4.bold("\n=== Stages ===\n"));
|
|
670
|
+
for (const stage of run.stages) {
|
|
671
|
+
const statusIcon = formatStageStatus(stage.status);
|
|
672
|
+
const statusText = pc4.bold("[" + stage.status + "]");
|
|
673
|
+
console.log(" " + statusIcon + " " + pc4.bold(stage.name.padEnd(20)) + " " + statusText);
|
|
674
|
+
}
|
|
675
|
+
console.log("");
|
|
676
|
+
} catch (err) {
|
|
677
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
678
|
+
console.error(pc4.red("\n=== Error: " + message + " ===\n"));
|
|
679
|
+
process.exit(1);
|
|
703
680
|
}
|
|
704
681
|
});
|
|
705
682
|
|
|
706
683
|
// src/commands/logs.ts
|
|
707
|
-
var logs_exports = {};
|
|
708
|
-
__export(logs_exports, {
|
|
709
|
-
logsCommand: () => logsCommand
|
|
710
|
-
});
|
|
711
684
|
import { Command as Command4 } from "commander";
|
|
712
685
|
import pc5 from "picocolors";
|
|
713
|
-
var logsCommand
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
console.log(
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
} else if (stage.status === "pending") {
|
|
763
|
-
console.log(pc5.gray("(pending)"));
|
|
764
|
-
} else if (stage.status === "running") {
|
|
765
|
-
console.log(pc5.blue("(running...)"));
|
|
766
|
-
} else if (stage.status === "skipped") {
|
|
767
|
-
console.log(pc5.gray("(skipped)"));
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
if (_options?.follow && run.status === "in_progress") {
|
|
771
|
-
console.log(pc5.blue("\n--- Following live logs (Ctrl+C to exit) ---\n"));
|
|
772
|
-
console.log(pc5.gray("(Live streaming would connect to API SSE endpoint in production)"));
|
|
773
|
-
let dots = 0;
|
|
774
|
-
const interval = setInterval(() => {
|
|
775
|
-
dots = (dots + 1) % 4;
|
|
776
|
-
process.stdout.write(pc5.blue("\r" + " ".repeat(dots) + " waiting for updates..."));
|
|
777
|
-
}, 500);
|
|
778
|
-
process.on("SIGINT", () => {
|
|
779
|
-
clearInterval(interval);
|
|
780
|
-
console.log(pc5.gray("\n\n(Stopped following)"));
|
|
781
|
-
process.exit(0);
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
console.log("");
|
|
785
|
-
} catch (err) {
|
|
786
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
787
|
-
console.error(pc5.red("\n=== Error: " + message + " ===\n"));
|
|
788
|
-
process.exit(1);
|
|
686
|
+
var logsCommand = new Command4("logs").description("Stream logs for a Codowave run").argument("[run-id]", "Run ID (defaults to latest)").option("-f, --follow", "Follow log output (SSE stream)").option("-s, --stage <name>", "Show logs for a specific stage").option("--no-color", "Disable colored output").action(async (_runId, _options) => {
|
|
687
|
+
try {
|
|
688
|
+
let config;
|
|
689
|
+
try {
|
|
690
|
+
config = readConfig();
|
|
691
|
+
} catch {
|
|
692
|
+
}
|
|
693
|
+
const run = getRun(_runId);
|
|
694
|
+
if (!run) {
|
|
695
|
+
console.log(pc5.yellow("No runs found. Run `codowave run <issue>` to start a new run."));
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
if (_options?.stage) {
|
|
699
|
+
const stage = run.stages.find((s) => s.name === _options.stage);
|
|
700
|
+
if (!stage) {
|
|
701
|
+
console.log(pc5.red('Stage "' + _options.stage + '" not found.'));
|
|
702
|
+
console.log(pc5.gray("Available stages: ") + run.stages.map((s) => s.name).join(", "));
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
console.log(pc5.bold("\n=== Logs: " + stage.name + " ===\n"));
|
|
706
|
+
console.log(pc5.bold("Status: ") + stage.status);
|
|
707
|
+
if (stage.logs) {
|
|
708
|
+
console.log(pc5.gray("\n--- Output ---\n"));
|
|
709
|
+
console.log(stage.logs);
|
|
710
|
+
} else {
|
|
711
|
+
console.log(pc5.gray("\n(no logs available yet)"));
|
|
712
|
+
}
|
|
713
|
+
if (_options.follow && stage.status === "running") {
|
|
714
|
+
console.log(pc5.blue("\n--- Following live logs (Ctrl+C to exit) ---\n"));
|
|
715
|
+
console.log(pc5.gray("(Live streaming would connect to API SSE endpoint in production)"));
|
|
716
|
+
}
|
|
717
|
+
console.log("");
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
console.log(pc5.bold("\n=== Logs: " + run.id + " ===\n"));
|
|
721
|
+
console.log(pc5.bold("Issue: ") + run.issue);
|
|
722
|
+
console.log(pc5.bold("Status: ") + run.status);
|
|
723
|
+
console.log("");
|
|
724
|
+
for (const stage of run.stages) {
|
|
725
|
+
const statusIcon = stage.status === "completed" ? "[+]" : stage.status === "failed" ? "[x]" : stage.status === "running" ? "[~]" : "[ ]";
|
|
726
|
+
console.log(pc5.bold("\n" + statusIcon + " " + stage.name + "\n"));
|
|
727
|
+
if (stage.logs) {
|
|
728
|
+
console.log(stage.logs);
|
|
729
|
+
} else if (stage.status === "pending") {
|
|
730
|
+
console.log(pc5.gray("(pending)"));
|
|
731
|
+
} else if (stage.status === "running") {
|
|
732
|
+
console.log(pc5.blue("(running...)"));
|
|
733
|
+
} else if (stage.status === "skipped") {
|
|
734
|
+
console.log(pc5.gray("(skipped)"));
|
|
789
735
|
}
|
|
790
|
-
}
|
|
736
|
+
}
|
|
737
|
+
if (_options?.follow && run.status === "in_progress") {
|
|
738
|
+
console.log(pc5.blue("\n--- Following live logs (Ctrl+C to exit) ---\n"));
|
|
739
|
+
console.log(pc5.gray("(Live streaming would connect to API SSE endpoint in production)"));
|
|
740
|
+
let dots = 0;
|
|
741
|
+
const interval = setInterval(() => {
|
|
742
|
+
dots = (dots + 1) % 4;
|
|
743
|
+
process.stdout.write(pc5.blue("\r" + " ".repeat(dots) + " waiting for updates..."));
|
|
744
|
+
}, 500);
|
|
745
|
+
process.on("SIGINT", () => {
|
|
746
|
+
clearInterval(interval);
|
|
747
|
+
console.log(pc5.gray("\n\n(Stopped following)"));
|
|
748
|
+
process.exit(0);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
console.log("");
|
|
752
|
+
} catch (err) {
|
|
753
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
754
|
+
console.error(pc5.red("\n=== Error: " + message + " ===\n"));
|
|
755
|
+
process.exit(1);
|
|
791
756
|
}
|
|
792
757
|
});
|
|
793
758
|
|
|
794
759
|
// src/commands/config-cmd.ts
|
|
795
|
-
var config_cmd_exports = {};
|
|
796
|
-
__export(config_cmd_exports, {
|
|
797
|
-
configCommand: () => configCommand
|
|
798
|
-
});
|
|
799
760
|
import { Command as Command5 } from "commander";
|
|
800
761
|
import pc6 from "picocolors";
|
|
801
|
-
var configCommand;
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
console.log(pc6.bold("\n\u{1F4E6} Configured Repositories:\n"));
|
|
827
|
-
config.repos.forEach((repo, index) => {
|
|
828
|
-
console.log(` ${index + 1}. ${pc6.cyan(`${repo.owner}/${repo.name}`)}`);
|
|
829
|
-
if (repo.id) {
|
|
830
|
-
console.log(` ${pc6.gray("ID: " + repo.id)}`);
|
|
831
|
-
}
|
|
832
|
-
});
|
|
833
|
-
console.log("");
|
|
834
|
-
}
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
const value = config[key];
|
|
838
|
-
if (value === void 0) {
|
|
839
|
-
console.error(pc6.red(`\u2716 Unknown config key: ${key}`));
|
|
840
|
-
console.log(pc6.gray(` Run \`codowave config list\` to see available options.`));
|
|
841
|
-
process.exit(1);
|
|
842
|
-
}
|
|
843
|
-
console.log(value);
|
|
844
|
-
} catch (err) {
|
|
845
|
-
console.error(pc6.red(`\u2716 ${err instanceof Error ? err.message : String(err)}`));
|
|
846
|
-
process.exit(1);
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
configCommand.command("set <key> <value>").description("Set a config value").action((key, value) => {
|
|
850
|
-
try {
|
|
851
|
-
const validKeys = ["apiKey", "apiUrl"];
|
|
852
|
-
if (!validKeys.includes(key)) {
|
|
853
|
-
console.error(pc6.red(`\u2716 Cannot set '${key}' directly.`));
|
|
854
|
-
console.log(pc6.gray(` For 'repos', use \`codowave init\` to manage repositories.`));
|
|
855
|
-
console.log(pc6.gray(` Run \`codowave config list\` to see available options.`));
|
|
856
|
-
process.exit(1);
|
|
857
|
-
}
|
|
858
|
-
if (key === "apiUrl") {
|
|
859
|
-
try {
|
|
860
|
-
new URL(value);
|
|
861
|
-
} catch {
|
|
862
|
-
console.error(pc6.red(`\u2716 Invalid URL: ${value}`));
|
|
863
|
-
process.exit(1);
|
|
762
|
+
var configCommand = new Command5("config").description("Get or set Codowave configuration values");
|
|
763
|
+
configCommand.command("list").description("List all available config options").action(() => {
|
|
764
|
+
console.log(pc6.bold("\n\u{1F4CB} Available Config Options:\n"));
|
|
765
|
+
console.log(` ${pc6.cyan("apiKey")} ${pc6.gray("\u2014 Your Codowave API key")}`);
|
|
766
|
+
console.log(` ${pc6.cyan("apiUrl")} ${pc6.gray("\u2014 API endpoint URL (default: https://api.codowave.com)")}`);
|
|
767
|
+
console.log(` ${pc6.cyan("repos")} ${pc6.gray("\u2014 List of configured repositories")}`);
|
|
768
|
+
console.log(` ${pc6.cyan("configPath")} ${pc6.gray("\u2014 Path to the config file")}`);
|
|
769
|
+
console.log("");
|
|
770
|
+
});
|
|
771
|
+
configCommand.command("get <key>").description("Get a config value").action((key) => {
|
|
772
|
+
try {
|
|
773
|
+
const config = readConfigOrThrow();
|
|
774
|
+
if (key === "configPath") {
|
|
775
|
+
console.log(pc6.green(getConfigPath()));
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (key === "repos") {
|
|
779
|
+
if (config.repos.length === 0) {
|
|
780
|
+
console.log(pc6.yellow("No repos configured."));
|
|
781
|
+
} else {
|
|
782
|
+
console.log(pc6.bold("\n\u{1F4E6} Configured Repositories:\n"));
|
|
783
|
+
config.repos.forEach((repo, index) => {
|
|
784
|
+
console.log(` ${index + 1}. ${pc6.cyan(`${repo.owner}/${repo.name}`)}`);
|
|
785
|
+
if (repo.id) {
|
|
786
|
+
console.log(` ${pc6.gray("ID: " + repo.id)}`);
|
|
864
787
|
}
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
const newConfig = updateConfig(updates);
|
|
868
|
-
console.log(pc6.green(`\u2713 Updated ${key}`));
|
|
869
|
-
console.log(pc6.gray(` ${key} = ${newConfig[key]}`));
|
|
870
|
-
} catch (err) {
|
|
871
|
-
console.error(pc6.red(`\u2716 ${err instanceof Error ? err.message : String(err)}`));
|
|
872
|
-
process.exit(1);
|
|
788
|
+
});
|
|
789
|
+
console.log("");
|
|
873
790
|
}
|
|
874
|
-
|
|
875
|
-
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const value = config[key];
|
|
794
|
+
if (value === void 0) {
|
|
795
|
+
console.error(pc6.red(`\u2716 Unknown config key: ${key}`));
|
|
796
|
+
console.log(pc6.gray(` Run \`codowave config list\` to see available options.`));
|
|
797
|
+
process.exit(1);
|
|
798
|
+
}
|
|
799
|
+
console.log(value);
|
|
800
|
+
} catch (err) {
|
|
801
|
+
console.error(pc6.red(`\u2716 ${err instanceof Error ? err.message : String(err)}`));
|
|
802
|
+
process.exit(1);
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
configCommand.command("set <key> <value>").description("Set a config value").action((key, value) => {
|
|
806
|
+
try {
|
|
807
|
+
const validKeys = ["apiKey", "apiUrl"];
|
|
808
|
+
if (!validKeys.includes(key)) {
|
|
809
|
+
console.error(pc6.red(`\u2716 Cannot set '${key}' directly.`));
|
|
810
|
+
console.log(pc6.gray(` For 'repos', use \`codowave init\` to manage repositories.`));
|
|
811
|
+
console.log(pc6.gray(` Run \`codowave config list\` to see available options.`));
|
|
812
|
+
process.exit(1);
|
|
813
|
+
}
|
|
814
|
+
if (key === "apiUrl") {
|
|
876
815
|
try {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
console.
|
|
880
|
-
console.log(` ${pc6.cyan("apiUrl")}: ${config.apiUrl}`);
|
|
881
|
-
console.log(` ${pc6.cyan("repos")}: ${config.repos.length} repository(s) configured`);
|
|
882
|
-
console.log(` ${pc6.cyan("configPath")}: ${pc6.gray(getConfigPath())}`);
|
|
883
|
-
if (config.repos.length > 0) {
|
|
884
|
-
console.log(pc6.bold(pc6.gray("\n Repositories:")));
|
|
885
|
-
config.repos.forEach((repo) => {
|
|
886
|
-
console.log(` \u2022 ${repo.owner}/${repo.name}${repo.id ? pc6.gray(` (${repo.id})`) : ""}`);
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
console.log("");
|
|
890
|
-
} catch (err) {
|
|
891
|
-
console.error(pc6.red(`\u2716 ${err instanceof Error ? err.message : String(err)}`));
|
|
816
|
+
new URL(value);
|
|
817
|
+
} catch {
|
|
818
|
+
console.error(pc6.red(`\u2716 Invalid URL: ${value}`));
|
|
892
819
|
process.exit(1);
|
|
893
820
|
}
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
});
|
|
821
|
+
}
|
|
822
|
+
const updates = { [key]: value };
|
|
823
|
+
const newConfig = updateConfig(updates);
|
|
824
|
+
console.log(pc6.green(`\u2713 Updated ${key}`));
|
|
825
|
+
console.log(pc6.gray(` ${key} = ${newConfig[key]}`));
|
|
826
|
+
} catch (err) {
|
|
827
|
+
console.error(pc6.red(`\u2716 ${err instanceof Error ? err.message : String(err)}`));
|
|
828
|
+
process.exit(1);
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
configCommand.command("show").description("Show all current config values").action(() => {
|
|
832
|
+
try {
|
|
833
|
+
const config = readConfigOrThrow();
|
|
834
|
+
console.log(pc6.bold("\n\u2699\uFE0F Current Configuration:\n"));
|
|
835
|
+
console.log(` ${pc6.cyan("apiKey")}: ${config.apiKey ? pc6.green("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022") + pc6.gray(" (hidden)") : pc6.yellow("not set")}`);
|
|
836
|
+
console.log(` ${pc6.cyan("apiUrl")}: ${config.apiUrl}`);
|
|
837
|
+
console.log(` ${pc6.cyan("repos")}: ${config.repos.length} repository(s) configured`);
|
|
838
|
+
console.log(` ${pc6.cyan("configPath")}: ${pc6.gray(getConfigPath())}`);
|
|
839
|
+
if (config.repos.length > 0) {
|
|
840
|
+
console.log(pc6.bold(pc6.gray("\n Repositories:")));
|
|
841
|
+
config.repos.forEach((repo) => {
|
|
842
|
+
console.log(` \u2022 ${repo.owner}/${repo.name}${repo.id ? pc6.gray(` (${repo.id})`) : ""}`);
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
console.log("");
|
|
846
|
+
} catch (err) {
|
|
847
|
+
console.error(pc6.red(`\u2716 ${err instanceof Error ? err.message : String(err)}`));
|
|
848
|
+
process.exit(1);
|
|
898
849
|
}
|
|
899
850
|
});
|
|
851
|
+
configCommand.action(() => {
|
|
852
|
+
configCommand.help();
|
|
853
|
+
});
|
|
900
854
|
|
|
901
855
|
// src/commands/connect.ts
|
|
902
|
-
var connect_exports = {};
|
|
903
|
-
__export(connect_exports, {
|
|
904
|
-
connectCommand: () => connectCommand,
|
|
905
|
-
performConnect: () => performConnect
|
|
906
|
-
});
|
|
907
856
|
import { Command as Command6 } from "commander";
|
|
908
857
|
import pc7 from "picocolors";
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
console.log(pc7.gray(" and enter the device code above.\n"));
|
|
942
|
-
console.log(pc7.yellow(" \u2139\uFE0F This is a stub implementation."));
|
|
943
|
-
console.log(pc7.gray(" In production, this would poll for OAuth completion.\n"));
|
|
944
|
-
console.log(pc7.blue(" 3. Would save Pro token and switch API URL...\n"));
|
|
945
|
-
console.log(pc7.bold("What would happen:\n"));
|
|
946
|
-
console.log(` \u2022 Save Pro API token to ${getConfigPath()}`);
|
|
947
|
-
console.log(` \u2022 Set apiUrl to ${PRO_API_URL}`);
|
|
948
|
-
console.log("");
|
|
949
|
-
console.log(pc7.gray("Run with ") + pc7.cyan("CODOWAVE_CONNECT=1") + pc7.gray(" to enable (not implemented yet)"));
|
|
950
|
-
console.log("");
|
|
951
|
-
} catch (err) {
|
|
952
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
953
|
-
console.error(pc7.red(`
|
|
858
|
+
var PRO_API_URL = "https://api.codowave.com";
|
|
859
|
+
var connectCommand = new Command6("connect").description("Connect to Codowave Pro (upgrade from OSS)").action(async () => {
|
|
860
|
+
try {
|
|
861
|
+
console.log(pc7.bold("\n\u{1F517} Codowave Connect\n"));
|
|
862
|
+
console.log(pc7.gray("This command upgrades your OSS installation to Codowave Pro.\n"));
|
|
863
|
+
const config = readConfig();
|
|
864
|
+
const isAlreadyPro = config?.apiUrl === PRO_API_URL;
|
|
865
|
+
if (isAlreadyPro) {
|
|
866
|
+
console.log(pc7.green("\u2713 You are already connected to Codowave Pro!"));
|
|
867
|
+
console.log(pc7.gray(` API URL: ${config?.apiUrl}`));
|
|
868
|
+
console.log("");
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
console.log(pc7.blue("Starting OAuth device flow...\n"));
|
|
872
|
+
console.log(pc7.gray(" 1. Requesting device code..."));
|
|
873
|
+
const deviceCode = `CODOWAVE-${Date.now().toString(36).toUpperCase()}`;
|
|
874
|
+
const verificationUri = "https://codowave.com/activate";
|
|
875
|
+
console.log(pc7.green("\n \u26A0\uFE0F Device Code: ") + pc7.bold(deviceCode));
|
|
876
|
+
console.log(pc7.gray("\n 2. Please visit: ") + pc7.cyan(verificationUri));
|
|
877
|
+
console.log(pc7.gray(" and enter the device code above.\n"));
|
|
878
|
+
console.log(pc7.yellow(" \u2139\uFE0F This is a stub implementation."));
|
|
879
|
+
console.log(pc7.gray(" In production, this would poll for OAuth completion.\n"));
|
|
880
|
+
console.log(pc7.blue(" 3. Would save Pro token and switch API URL...\n"));
|
|
881
|
+
console.log(pc7.bold("What would happen:\n"));
|
|
882
|
+
console.log(` \u2022 Save Pro API token to ${getConfigPath()}`);
|
|
883
|
+
console.log(` \u2022 Set apiUrl to ${PRO_API_URL}`);
|
|
884
|
+
console.log("");
|
|
885
|
+
console.log(pc7.gray("Run with ") + pc7.cyan("CODOWAVE_CONNECT=1") + pc7.gray(" to enable (not implemented yet)"));
|
|
886
|
+
console.log("");
|
|
887
|
+
} catch (err) {
|
|
888
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
889
|
+
console.error(pc7.red(`
|
|
954
890
|
\u2716 Error: ${message}
|
|
955
891
|
`));
|
|
956
|
-
|
|
957
|
-
}
|
|
958
|
-
});
|
|
892
|
+
process.exit(1);
|
|
959
893
|
}
|
|
960
894
|
});
|
|
961
895
|
|
|
962
896
|
// src/index.ts
|
|
963
|
-
init_config();
|
|
964
|
-
import { Command as Command7 } from "commander";
|
|
965
897
|
import { createRequire } from "module";
|
|
966
898
|
var require2 = createRequire(import.meta.url);
|
|
967
899
|
var { version } = require2("../package.json");
|
|
968
900
|
var VERSION = version;
|
|
969
901
|
var program = new Command7();
|
|
970
902
|
program.name("codowave").description("Codowave OSS CLI \u2014 AI-powered coding agent for your GitHub repositories").version(VERSION, "-v, --version", "Output the current version").option("--api-url <url>", "Override the Codowave API URL");
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
program.addCommand(initCommand2);
|
|
978
|
-
program.addCommand(runCommand2);
|
|
979
|
-
program.addCommand(statusCommand2);
|
|
980
|
-
program.addCommand(logsCommand2);
|
|
981
|
-
program.addCommand(configCommand2);
|
|
982
|
-
program.addCommand(connectCommand2);
|
|
903
|
+
program.addCommand(initCommand);
|
|
904
|
+
program.addCommand(runCommand);
|
|
905
|
+
program.addCommand(statusCommand);
|
|
906
|
+
program.addCommand(logsCommand);
|
|
907
|
+
program.addCommand(configCommand);
|
|
908
|
+
program.addCommand(connectCommand);
|
|
983
909
|
var args = process.argv.slice(2);
|
|
984
910
|
var isInitOrHelp = args[0] === "init" || args.includes("--help") || args.includes("-h") || args.includes("--version") || args.includes("-v") || args.length === 0;
|
|
985
911
|
if (!isInitOrHelp) {
|
|
986
|
-
const config =
|
|
912
|
+
const config = readConfig();
|
|
987
913
|
if (!config?.apiUrl) {
|
|
988
914
|
console.log("\n\u274C Codowave not initialized. Run: codowave init\n");
|
|
989
915
|
process.exit(1);
|