repowise 0.1.4 → 0.1.6
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/bin/repowise.js +116 -14
- package/dist/src/commands/create.d.ts +1 -1
- package/dist/src/commands/create.d.ts.map +1 -1
- package/dist/src/commands/create.js +237 -2
- package/dist/src/commands/create.js.map +1 -1
- package/dist/src/commands/listen.d.ts +3 -2
- package/dist/src/commands/listen.d.ts.map +1 -1
- package/dist/src/commands/listen.js +45 -3
- package/dist/src/commands/listen.js.map +1 -1
- package/dist/src/commands/login.d.ts +4 -1
- package/dist/src/commands/login.d.ts.map +1 -1
- package/dist/src/commands/login.js +56 -2
- package/dist/src/commands/login.js.map +1 -1
- package/dist/src/commands/logout.d.ts +1 -1
- package/dist/src/commands/logout.d.ts.map +1 -1
- package/dist/src/commands/logout.js +10 -2
- package/dist/src/commands/logout.js.map +1 -1
- package/dist/src/commands/start.d.ts +2 -0
- package/dist/src/commands/start.d.ts.map +1 -0
- package/dist/src/commands/start.js +17 -0
- package/dist/src/commands/start.js.map +1 -0
- package/dist/src/commands/status.d.ts +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/status.js +61 -2
- package/dist/src/commands/status.js.map +1 -1
- package/dist/src/commands/stop.d.ts +2 -0
- package/dist/src/commands/stop.d.ts.map +1 -0
- package/dist/src/commands/stop.js +17 -0
- package/dist/src/commands/stop.js.map +1 -0
- package/dist/src/lib/ai-tools.d.ts +23 -0
- package/dist/src/lib/ai-tools.d.ts.map +1 -0
- package/dist/src/lib/ai-tools.js +193 -0
- package/dist/src/lib/ai-tools.js.map +1 -0
- package/dist/src/lib/api.d.ts.map +1 -1
- package/dist/src/lib/api.js +25 -4
- package/dist/src/lib/api.js.map +1 -1
- package/dist/src/lib/auth.d.ts +18 -0
- package/dist/src/lib/auth.d.ts.map +1 -1
- package/dist/src/lib/auth.js +251 -7
- package/dist/src/lib/auth.js.map +1 -1
- package/dist/src/lib/config.d.ts +2 -0
- package/dist/src/lib/config.d.ts.map +1 -1
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/env.d.ts +10 -0
- package/dist/src/lib/env.d.ts.map +1 -0
- package/dist/src/lib/env.js +26 -0
- package/dist/src/lib/env.js.map +1 -0
- package/dist/src/lib/interview-handler.d.ts +2 -0
- package/dist/src/lib/interview-handler.d.ts.map +1 -0
- package/dist/src/lib/interview-handler.js +96 -0
- package/dist/src/lib/interview-handler.js.map +1 -0
- package/dist/src/lib/progress-renderer.d.ts +69 -0
- package/dist/src/lib/progress-renderer.d.ts.map +1 -0
- package/dist/src/lib/progress-renderer.js +186 -0
- package/dist/src/lib/progress-renderer.js.map +1 -0
- package/dist/src/lib/prompts.d.ts +6 -1
- package/dist/src/lib/prompts.d.ts.map +1 -1
- package/dist/src/lib/prompts.js +21 -3
- package/dist/src/lib/prompts.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/tsup.config.d.ts +3 -0
- package/dist/tsup.config.d.ts.map +1 -0
- package/dist/tsup.config.js +18 -0
- package/dist/tsup.config.js.map +1 -0
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -102,20 +102,38 @@ function startCallbackServer() {
|
|
|
102
102
|
const error = url.searchParams.get("error");
|
|
103
103
|
if (error) {
|
|
104
104
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
105
|
-
res.end(
|
|
105
|
+
res.end(
|
|
106
|
+
callbackPage(
|
|
107
|
+
"Authentication Failed",
|
|
108
|
+
"Something went wrong. Please close this tab and try again.",
|
|
109
|
+
true
|
|
110
|
+
)
|
|
111
|
+
);
|
|
106
112
|
server.close();
|
|
107
113
|
reject(new Error(`Authentication error: ${error}`));
|
|
108
114
|
return;
|
|
109
115
|
}
|
|
110
116
|
if (!code || !state) {
|
|
111
117
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
112
|
-
res.end(
|
|
118
|
+
res.end(
|
|
119
|
+
callbackPage(
|
|
120
|
+
"Missing Parameters",
|
|
121
|
+
"The callback was missing required data. Please close this tab and try again.",
|
|
122
|
+
true
|
|
123
|
+
)
|
|
124
|
+
);
|
|
113
125
|
server.close();
|
|
114
126
|
reject(new Error("Missing code or state in callback"));
|
|
115
127
|
return;
|
|
116
128
|
}
|
|
117
129
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
118
|
-
res.end(
|
|
130
|
+
res.end(
|
|
131
|
+
callbackPage(
|
|
132
|
+
"Authentication Successful",
|
|
133
|
+
"You can close this tab and return to the terminal.",
|
|
134
|
+
false
|
|
135
|
+
)
|
|
136
|
+
);
|
|
119
137
|
server.close();
|
|
120
138
|
resolve({ code, state });
|
|
121
139
|
});
|
|
@@ -574,16 +592,32 @@ var init_config = __esm({
|
|
|
574
592
|
// src/lib/interview-handler.ts
|
|
575
593
|
import chalk2 from "chalk";
|
|
576
594
|
import { input } from "@inquirer/prompts";
|
|
577
|
-
async function handleInterview(syncId, questionId, questionText, questionContext) {
|
|
595
|
+
async function handleInterview(syncId, questionId, questionText, questionContext, estimatedQuestions) {
|
|
578
596
|
questionCounter++;
|
|
597
|
+
if (questionCounter === 1) {
|
|
598
|
+
console.log("");
|
|
599
|
+
console.log(chalk2.cyan.bold(" \u2500\u2500 Interview \u2500\u2500"));
|
|
600
|
+
console.log(chalk2.dim(" Help us understand your project better. Answer a few short"));
|
|
601
|
+
console.log(chalk2.dim(" questions so we can generate more relevant context files."));
|
|
602
|
+
if (estimatedQuestions) {
|
|
603
|
+
console.log(
|
|
604
|
+
chalk2.dim(
|
|
605
|
+
` The AI estimates ${chalk2.white(`~${estimatedQuestions}`)} questions based on your codebase.`
|
|
606
|
+
)
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
console.log(chalk2.dim(' Type "skip" to skip a question, "done" to finish early.'));
|
|
610
|
+
}
|
|
579
611
|
console.log("");
|
|
580
|
-
console.log(
|
|
612
|
+
console.log(
|
|
613
|
+
chalk2.cyan.bold(
|
|
614
|
+
` Question ${questionCounter}${estimatedQuestions ? `/${estimatedQuestions}` : ""}`
|
|
615
|
+
)
|
|
616
|
+
);
|
|
581
617
|
if (questionContext) {
|
|
582
618
|
console.log(chalk2.dim(` ${questionContext}`));
|
|
583
619
|
}
|
|
584
620
|
console.log(` ${questionText}`);
|
|
585
|
-
console.log(chalk2.dim(' Type "skip" to skip, "done" to finish interview early.'));
|
|
586
|
-
console.log(chalk2.dim(" (Auto-skips after 5 minutes of inactivity)"));
|
|
587
621
|
let answer;
|
|
588
622
|
try {
|
|
589
623
|
answer = await Promise.race([
|
|
@@ -705,9 +739,55 @@ var init_progress_renderer = __esm({
|
|
|
705
739
|
if (result.existingDocs.length > 0) {
|
|
706
740
|
console.log(` ${chalk3.dim("Existing docs:")} ${result.existingDocs.join(", ")}`);
|
|
707
741
|
}
|
|
742
|
+
if (result.fileTree && result.fileTree.length > 0) {
|
|
743
|
+
this.renderTree(result.fileTree);
|
|
744
|
+
}
|
|
708
745
|
console.log("");
|
|
709
746
|
spinner.start();
|
|
710
747
|
}
|
|
748
|
+
renderTree(entries) {
|
|
749
|
+
console.log("");
|
|
750
|
+
console.log(chalk3.cyan.bold(" \u2500\u2500 Project Structure \u2500\u2500"));
|
|
751
|
+
const root = { name: "", type: "tree", children: /* @__PURE__ */ new Map() };
|
|
752
|
+
for (const entry of entries) {
|
|
753
|
+
const parts = entry.path.split("/");
|
|
754
|
+
let current = root;
|
|
755
|
+
for (let i = 0; i < parts.length; i++) {
|
|
756
|
+
const part = parts[i];
|
|
757
|
+
if (!current.children.has(part)) {
|
|
758
|
+
const isLast = i === parts.length - 1;
|
|
759
|
+
current.children.set(part, {
|
|
760
|
+
name: part,
|
|
761
|
+
type: isLast ? entry.type : "tree",
|
|
762
|
+
children: /* @__PURE__ */ new Map()
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
current = current.children.get(part);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
const printNode = (node, prefix, isLast) => {
|
|
769
|
+
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
770
|
+
const display = node.type === "tree" ? chalk3.bold.dim(`${node.name}/`) : node.name;
|
|
771
|
+
console.log(` ${prefix}${connector}${display}`);
|
|
772
|
+
const sorted = [...node.children.values()].sort((a, b) => {
|
|
773
|
+
if (a.type === "tree" && b.type !== "tree") return -1;
|
|
774
|
+
if (a.type !== "tree" && b.type === "tree") return 1;
|
|
775
|
+
return a.name.localeCompare(b.name);
|
|
776
|
+
});
|
|
777
|
+
const childPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
778
|
+
sorted.forEach((child, idx) => {
|
|
779
|
+
printNode(child, childPrefix, idx === sorted.length - 1);
|
|
780
|
+
});
|
|
781
|
+
};
|
|
782
|
+
const topLevel = [...root.children.values()].sort((a, b) => {
|
|
783
|
+
if (a.type === "tree" && b.type !== "tree") return -1;
|
|
784
|
+
if (a.type !== "tree" && b.type === "tree") return 1;
|
|
785
|
+
return a.name.localeCompare(b.name);
|
|
786
|
+
});
|
|
787
|
+
topLevel.forEach((child, idx) => {
|
|
788
|
+
printNode(child, "", idx === topLevel.length - 1);
|
|
789
|
+
});
|
|
790
|
+
}
|
|
711
791
|
renderScanSummary(summary, spinner) {
|
|
712
792
|
if (this.scanSummaryShown) return;
|
|
713
793
|
this.scanSummaryShown = true;
|
|
@@ -1230,11 +1310,32 @@ async function create() {
|
|
|
1230
1310
|
);
|
|
1231
1311
|
}
|
|
1232
1312
|
spinner.start("Starting context generation pipeline...");
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1313
|
+
let syncId;
|
|
1314
|
+
try {
|
|
1315
|
+
const triggerResult = await apiRequest(`/v1/repos/${repoId}/sync`, {
|
|
1316
|
+
method: "POST",
|
|
1317
|
+
body: JSON.stringify({ scanType: "full" })
|
|
1318
|
+
});
|
|
1319
|
+
syncId = triggerResult.syncId;
|
|
1320
|
+
} catch (triggerErr) {
|
|
1321
|
+
const msg = triggerErr instanceof Error ? triggerErr.message : "";
|
|
1322
|
+
if (!msg.toLowerCase().includes("already running")) {
|
|
1323
|
+
throw triggerErr;
|
|
1324
|
+
}
|
|
1325
|
+
spinner.text = "Resuming existing pipeline...";
|
|
1326
|
+
const syncs = await apiRequest(
|
|
1327
|
+
`/v1/repos/${repoId}/syncs?limit=1`
|
|
1328
|
+
);
|
|
1329
|
+
const active = syncs.items.find(
|
|
1330
|
+
(s) => s.status === "in_progress" || s.status === "awaiting_input"
|
|
1331
|
+
);
|
|
1332
|
+
if (!active) {
|
|
1333
|
+
throw new Error("Could not find active sync to resume. Please try again.");
|
|
1334
|
+
}
|
|
1335
|
+
syncId = active.syncId;
|
|
1336
|
+
spinner.info(chalk4.cyan("Resuming existing pipeline..."));
|
|
1337
|
+
spinner.start();
|
|
1338
|
+
}
|
|
1238
1339
|
let pollAttempts = 0;
|
|
1239
1340
|
const progressRenderer = new ProgressRenderer();
|
|
1240
1341
|
while (true) {
|
|
@@ -1245,13 +1346,15 @@ async function create() {
|
|
|
1245
1346
|
}
|
|
1246
1347
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1247
1348
|
const syncResult = await apiRequest(`/v1/sync/${syncId}/status`);
|
|
1349
|
+
progressRenderer.update(syncResult, spinner);
|
|
1248
1350
|
if (syncResult.status === "awaiting_input" && syncResult.questionId && syncResult.questionText) {
|
|
1249
1351
|
spinner.stop();
|
|
1250
1352
|
await handleInterview(
|
|
1251
1353
|
syncId,
|
|
1252
1354
|
syncResult.questionId,
|
|
1253
1355
|
syncResult.questionText,
|
|
1254
|
-
syncResult.questionContext ?? void 0
|
|
1356
|
+
syncResult.questionContext ?? void 0,
|
|
1357
|
+
syncResult.discoveryResult?.estimatedInterviewQuestions
|
|
1255
1358
|
);
|
|
1256
1359
|
spinner.start("Resuming pipeline...");
|
|
1257
1360
|
continue;
|
|
@@ -1265,7 +1368,6 @@ async function create() {
|
|
|
1265
1368
|
process.exitCode = 1;
|
|
1266
1369
|
return;
|
|
1267
1370
|
}
|
|
1268
|
-
progressRenderer.update(syncResult, spinner);
|
|
1269
1371
|
}
|
|
1270
1372
|
if (repoRoot) {
|
|
1271
1373
|
spinner.start("Pulling latest changes...");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function create(): void
|
|
1
|
+
export declare function create(): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=create.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAyGA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAkQ5C"}
|
|
@@ -1,4 +1,239 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { getValidCredentials, performLogin, decodeIdToken } from '../lib/auth.js';
|
|
5
|
+
import { apiRequest } from '../lib/api.js';
|
|
6
|
+
import { selectAiTools } from '../lib/prompts.js';
|
|
7
|
+
import { updateToolConfig, scanLocalContextFiles, AI_TOOL_CONFIG } from '../lib/ai-tools.js';
|
|
8
|
+
import { getConfig, saveConfig } from '../lib/config.js';
|
|
9
|
+
import { handleInterview } from '../lib/interview-handler.js';
|
|
10
|
+
import { ProgressRenderer } from '../lib/progress-renderer.js';
|
|
11
|
+
function detectRepoRoot() {
|
|
12
|
+
return execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
|
|
13
|
+
}
|
|
14
|
+
function detectRepoName(repoRoot) {
|
|
15
|
+
try {
|
|
16
|
+
const remoteUrl = execSync('git remote get-url origin', {
|
|
17
|
+
encoding: 'utf-8',
|
|
18
|
+
cwd: repoRoot,
|
|
19
|
+
}).trim();
|
|
20
|
+
// Extract repo name from URL (handles both HTTPS and SSH)
|
|
21
|
+
const match = remoteUrl.match(/\/([^/]+?)(?:\.git)?$/);
|
|
22
|
+
if (match?.[1])
|
|
23
|
+
return match[1];
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// No remote configured — fall back to directory name
|
|
27
|
+
}
|
|
28
|
+
return repoRoot.split('/').pop() ?? 'unknown';
|
|
29
|
+
}
|
|
30
|
+
function formatElapsed(ms) {
|
|
31
|
+
const totalSeconds = Math.round(ms / 1000);
|
|
32
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
33
|
+
const seconds = totalSeconds % 60;
|
|
34
|
+
if (minutes === 0)
|
|
35
|
+
return `${seconds}s`;
|
|
36
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
37
|
+
}
|
|
38
|
+
const POLL_INTERVAL_MS = 3000;
|
|
39
|
+
const MAX_POLL_ATTEMPTS = 200; // ~10 minutes at 3s interval
|
|
40
|
+
const DEFAULT_CONTEXT_FOLDER = 'repowise-context';
|
|
41
|
+
export async function create() {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
const spinner = ora('Checking authentication...').start();
|
|
44
|
+
try {
|
|
45
|
+
// Step 1: Auth check — auto-login if not authenticated (Story 2.1)
|
|
46
|
+
let credentials = await getValidCredentials();
|
|
47
|
+
if (!credentials) {
|
|
48
|
+
spinner.info(chalk.yellow('Not logged in. Opening browser to authenticate...'));
|
|
49
|
+
credentials = await performLogin();
|
|
50
|
+
const { email } = decodeIdToken(credentials.idToken);
|
|
51
|
+
spinner.succeed(chalk.green(`Authenticated as ${chalk.bold(email)}`));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
spinner.succeed('Authenticated');
|
|
55
|
+
}
|
|
56
|
+
// Step 2: Check for pending onboarding repo from dashboard (Story 2.2)
|
|
57
|
+
let repoId;
|
|
58
|
+
let repoName;
|
|
59
|
+
let repoRoot;
|
|
60
|
+
spinner.start('Checking for pending repository...');
|
|
61
|
+
try {
|
|
62
|
+
const pending = await apiRequest('/v1/onboarding/pending');
|
|
63
|
+
if (pending?.repoId) {
|
|
64
|
+
repoId = pending.repoId;
|
|
65
|
+
repoName = pending.repoName;
|
|
66
|
+
spinner.succeed(`Found pending repository: ${chalk.bold(repoName)}`);
|
|
67
|
+
// Clear pending onboarding after pickup
|
|
68
|
+
apiRequest('/v1/onboarding/pending', { method: 'DELETE' }).catch(() => { });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// No pending onboarding API available or failed — fall through to local detection
|
|
73
|
+
}
|
|
74
|
+
// Fall back to local git detection if no pending repo
|
|
75
|
+
if (!repoId) {
|
|
76
|
+
spinner.text = 'Detecting repository...';
|
|
77
|
+
try {
|
|
78
|
+
repoRoot = detectRepoRoot();
|
|
79
|
+
repoName = detectRepoName(repoRoot);
|
|
80
|
+
spinner.succeed(`Repository: ${chalk.bold(repoName)}`);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
spinner.fail(chalk.red('Not in a git repository. Run this command from your repo directory, or select a repo on the dashboard first.'));
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Resolve repoId from API
|
|
88
|
+
try {
|
|
89
|
+
const repos = await apiRequest('/v1/repos');
|
|
90
|
+
const match = repos.find((r) => r.name === repoName || r.fullName.endsWith(`/${repoName}`));
|
|
91
|
+
if (match) {
|
|
92
|
+
repoId = match.repoId;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Could not resolve — will fail at sync trigger
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// Try to detect local repo root even with pending repo (for git pull later)
|
|
101
|
+
try {
|
|
102
|
+
repoRoot = detectRepoRoot();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Not in a git repo directory — that's ok with pending repo
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!repoId) {
|
|
109
|
+
spinner.fail(chalk.red('Could not find this repository in your RepoWise account. Connect it on the dashboard first.'));
|
|
110
|
+
process.exitCode = 1;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Step 3: AI tool selection
|
|
114
|
+
const { tools, hasOther } = await selectAiTools();
|
|
115
|
+
if (hasOther) {
|
|
116
|
+
console.log(chalk.cyan('\nFor AI tools not listed, context files still work with any tool that reads the filesystem.\nRequest support for your tool at: https://dashboard.repowise.ai/support/ai-tools'));
|
|
117
|
+
}
|
|
118
|
+
if (tools.length === 0 && !hasOther) {
|
|
119
|
+
console.log(chalk.yellow('\nNo AI tools selected. You can configure them later with `repowise config`.'));
|
|
120
|
+
}
|
|
121
|
+
// Step 4: Trigger pipeline (or resume an existing active sync)
|
|
122
|
+
spinner.start('Starting context generation pipeline...');
|
|
123
|
+
let syncId;
|
|
124
|
+
try {
|
|
125
|
+
const triggerResult = await apiRequest(`/v1/repos/${repoId}/sync`, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
body: JSON.stringify({ scanType: 'full' }),
|
|
128
|
+
});
|
|
129
|
+
syncId = triggerResult.syncId;
|
|
130
|
+
}
|
|
131
|
+
catch (triggerErr) {
|
|
132
|
+
const msg = triggerErr instanceof Error ? triggerErr.message : '';
|
|
133
|
+
if (!msg.toLowerCase().includes('already running')) {
|
|
134
|
+
throw triggerErr;
|
|
135
|
+
}
|
|
136
|
+
// A sync is already in progress — find it and resume polling
|
|
137
|
+
spinner.text = 'Resuming existing pipeline...';
|
|
138
|
+
const syncs = await apiRequest(`/v1/repos/${repoId}/syncs?limit=1`);
|
|
139
|
+
const active = syncs.items.find((s) => s.status === 'in_progress' || s.status === 'awaiting_input');
|
|
140
|
+
if (!active) {
|
|
141
|
+
throw new Error('Could not find active sync to resume. Please try again.');
|
|
142
|
+
}
|
|
143
|
+
syncId = active.syncId;
|
|
144
|
+
spinner.info(chalk.cyan('Resuming existing pipeline...'));
|
|
145
|
+
spinner.start();
|
|
146
|
+
}
|
|
147
|
+
// Step 5: Poll for completion with enriched progress display
|
|
148
|
+
let pollAttempts = 0;
|
|
149
|
+
const progressRenderer = new ProgressRenderer();
|
|
150
|
+
while (true) {
|
|
151
|
+
if (++pollAttempts > MAX_POLL_ATTEMPTS) {
|
|
152
|
+
spinner.fail(chalk.red('Pipeline timed out. Check dashboard for status.'));
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
157
|
+
const syncResult = await apiRequest(`/v1/sync/${syncId}/status`);
|
|
158
|
+
// Update progress display first so discovery/scan sections render
|
|
159
|
+
// even if the status already jumped to awaiting_input or completed
|
|
160
|
+
progressRenderer.update(syncResult, spinner);
|
|
161
|
+
// Handle interview questions (Story 3.2)
|
|
162
|
+
if (syncResult.status === 'awaiting_input' &&
|
|
163
|
+
syncResult.questionId &&
|
|
164
|
+
syncResult.questionText) {
|
|
165
|
+
spinner.stop();
|
|
166
|
+
await handleInterview(syncId, syncResult.questionId, syncResult.questionText, syncResult.questionContext ?? undefined, syncResult.discoveryResult?.estimatedInterviewQuestions);
|
|
167
|
+
spinner.start('Resuming pipeline...');
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (syncResult.status === 'completed') {
|
|
171
|
+
spinner.succeed('Context generation complete');
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
if (syncResult.status === 'failed') {
|
|
175
|
+
spinner.fail(chalk.red(`Pipeline failed: ${syncResult.error ?? 'Unknown error'}`));
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Step 6: Git pull to get context files
|
|
181
|
+
if (repoRoot) {
|
|
182
|
+
spinner.start('Pulling latest changes...');
|
|
183
|
+
try {
|
|
184
|
+
execSync('git pull', { cwd: repoRoot, encoding: 'utf-8', stdio: 'pipe' });
|
|
185
|
+
spinner.succeed('Pulled latest changes');
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
spinner.warn(chalk.yellow('Could not pull latest changes. You may need to run `git pull` manually.'));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Step 7: Collect context files
|
|
192
|
+
const contextFolder = DEFAULT_CONTEXT_FOLDER;
|
|
193
|
+
let contextFiles = [];
|
|
194
|
+
if (repoRoot) {
|
|
195
|
+
contextFiles = await scanLocalContextFiles(repoRoot, contextFolder);
|
|
196
|
+
}
|
|
197
|
+
// Step 8: Configure AI tools
|
|
198
|
+
if (tools.length > 0 && repoRoot) {
|
|
199
|
+
spinner.start('Configuring AI tools...');
|
|
200
|
+
const results = [];
|
|
201
|
+
for (const tool of tools) {
|
|
202
|
+
const { created: wasCreated } = await updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
|
|
203
|
+
const config = AI_TOOL_CONFIG[tool];
|
|
204
|
+
const action = wasCreated ? 'Created' : 'Updated';
|
|
205
|
+
results.push(` ${action} ${config.filePath}`);
|
|
206
|
+
}
|
|
207
|
+
spinner.succeed('AI tools configured');
|
|
208
|
+
console.log(chalk.dim(results.join('\n')));
|
|
209
|
+
}
|
|
210
|
+
// Step 9: Save config
|
|
211
|
+
const existingConfig = await getConfig();
|
|
212
|
+
await saveConfig({
|
|
213
|
+
...existingConfig,
|
|
214
|
+
aiTools: tools,
|
|
215
|
+
contextFolder,
|
|
216
|
+
});
|
|
217
|
+
// Step 10: Auto-start listener
|
|
218
|
+
try {
|
|
219
|
+
const { install } = await import('@repowise/listener/service-installer');
|
|
220
|
+
const { startBackground } = await import('@repowise/listener/process-manager');
|
|
221
|
+
await install();
|
|
222
|
+
await startBackground();
|
|
223
|
+
console.log(chalk.green('Listener started — your context will stay in sync automatically.'));
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
console.log(chalk.yellow('Warning: Could not start listener automatically. Run `repowise listen --install` to enable auto-start.'));
|
|
227
|
+
}
|
|
228
|
+
// Step 11: Completion summary with elapsed time (Story 2.3)
|
|
229
|
+
const elapsed = formatElapsed(Date.now() - startTime);
|
|
230
|
+
console.log(chalk.green(`\n${chalk.bold('Setup complete!')} Your AI tools now have access to project context for ${chalk.bold(repoName)}.`));
|
|
231
|
+
console.log(chalk.dim(`Total time: ${elapsed}`));
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
const message = err instanceof Error ? err.message : 'Create failed';
|
|
235
|
+
spinner.fail(chalk.red(message));
|
|
236
|
+
process.exitCode = 1;
|
|
237
|
+
}
|
|
3
238
|
}
|
|
4
239
|
//# sourceMappingURL=create.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM;
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listen.d.ts","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"listen.d.ts","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,CAAC,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C/F"}
|
|
@@ -1,5 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { getValidCredentials } from '../lib/auth.js';
|
|
2
|
+
export async function listen(options) {
|
|
3
|
+
if (options.install) {
|
|
4
|
+
try {
|
|
5
|
+
const { install } = await import('@repowise/listener/service-installer');
|
|
6
|
+
await install();
|
|
7
|
+
console.log('Auto-start service installed. The listener will start on boot.');
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
11
|
+
console.error(`Failed to install auto-start service: ${message}`);
|
|
12
|
+
console.error('You can still run the listener manually with `repowise listen`.');
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (options.uninstall) {
|
|
18
|
+
try {
|
|
19
|
+
const { uninstall } = await import('@repowise/listener/service-installer');
|
|
20
|
+
await uninstall();
|
|
21
|
+
console.log('Auto-start service removed.');
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
25
|
+
console.error(`Failed to uninstall auto-start service: ${message}`);
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const credentials = await getValidCredentials();
|
|
31
|
+
if (!credentials) {
|
|
32
|
+
console.error('Not logged in. Run `repowise login` first.');
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log('Starting RepoWise listener...');
|
|
37
|
+
// Dynamic import to avoid hard dependency on listener package
|
|
38
|
+
try {
|
|
39
|
+
const { startListener } = await import('@repowise/listener/main');
|
|
40
|
+
await startListener();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
console.error('Failed to start listener. Ensure @repowise/listener is installed.');
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
}
|
|
4
46
|
}
|
|
5
47
|
//# sourceMappingURL=listen.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listen.js","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"listen.js","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAmD;IAC9E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,sCAAsC,CAAC,CAAC;YACzE,MAAM,OAAO,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;QAChF,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;YAClE,OAAO,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;YACjF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,sCAAsC,CAAC,CAAC;YAC3E,MAAM,SAAS,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAChD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAE7C,8DAA8D;IAC9D,IAAI,CAAC;QACH,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;QAClE,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACnF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DrE"}
|
|
@@ -1,4 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { generateCodeVerifier, generateCodeChallenge, generateState, getAuthorizeUrl, startCallbackServer, exchangeCodeForTokens, storeCredentials, decodeIdToken, } from '../lib/auth.js';
|
|
4
|
+
export async function login(options = {}) {
|
|
5
|
+
const spinner = ora('Preparing login...').start();
|
|
6
|
+
try {
|
|
7
|
+
// Generate PKCE and state
|
|
8
|
+
const codeVerifier = generateCodeVerifier();
|
|
9
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
10
|
+
const state = generateState();
|
|
11
|
+
// Build authorize URL
|
|
12
|
+
const authorizeUrl = getAuthorizeUrl(codeChallenge, state);
|
|
13
|
+
// Start callback server first
|
|
14
|
+
const callbackPromise = startCallbackServer();
|
|
15
|
+
// Open browser or print URL
|
|
16
|
+
if (options.browser === false) {
|
|
17
|
+
spinner.stop();
|
|
18
|
+
console.log(`\nOpen this URL in your browser to authenticate:\n`);
|
|
19
|
+
console.log(chalk.cyan(authorizeUrl));
|
|
20
|
+
console.log(`\nWaiting for authentication...`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
spinner.text = 'Opening browser for authentication...';
|
|
24
|
+
try {
|
|
25
|
+
const open = (await import('open')).default;
|
|
26
|
+
await open(authorizeUrl);
|
|
27
|
+
spinner.text = 'Waiting for authentication in browser...';
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Fall back to printing URL if open fails
|
|
31
|
+
spinner.stop();
|
|
32
|
+
console.log(`\nCould not open browser automatically. Open this URL:\n`);
|
|
33
|
+
console.log(chalk.cyan(authorizeUrl));
|
|
34
|
+
console.log(`\nWaiting for authentication...`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Wait for callback
|
|
38
|
+
const { code, state: returnedState } = await callbackPromise;
|
|
39
|
+
// Validate state
|
|
40
|
+
if (returnedState !== state) {
|
|
41
|
+
throw new Error('State mismatch — possible CSRF attack. Please try again.');
|
|
42
|
+
}
|
|
43
|
+
spinner.start('Exchanging authorization code...');
|
|
44
|
+
// Exchange code for tokens
|
|
45
|
+
const credentials = await exchangeCodeForTokens(code, codeVerifier);
|
|
46
|
+
// Store credentials
|
|
47
|
+
await storeCredentials(credentials);
|
|
48
|
+
// Decode ID token for display
|
|
49
|
+
const { email } = decodeIdToken(credentials.idToken);
|
|
50
|
+
spinner.succeed(chalk.green(`Logged in as ${chalk.bold(email)}`));
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : 'Login failed';
|
|
54
|
+
spinner.fail(chalk.red(message));
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
}
|
|
3
57
|
}
|
|
4
58
|
//# sourceMappingURL=login.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK;
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function logout(): void
|
|
1
|
+
export declare function logout(): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=logout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/commands/logout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/commands/logout.ts"],"names":[],"mappings":"AAGA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAU5C"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { clearCredentials, getStoredCredentials } from '../lib/auth.js';
|
|
3
|
+
export async function logout() {
|
|
4
|
+
const creds = await getStoredCredentials();
|
|
5
|
+
if (!creds) {
|
|
6
|
+
console.log(chalk.yellow('Not logged in.'));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
await clearCredentials();
|
|
10
|
+
console.log(chalk.green('Logged out successfully.'));
|
|
3
11
|
}
|
|
4
12
|
//# sourceMappingURL=logout.js.map
|