repowise 0.1.3 → 0.1.5

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.
@@ -103,7 +103,11 @@ function startCallbackServer() {
103
103
  if (error) {
104
104
  res.writeHead(200, { "Content-Type": "text/html" });
105
105
  res.end(
106
- "<html><body><h1>Authentication failed.</h1><p>You can close this tab.</p></body></html>"
106
+ callbackPage(
107
+ "Authentication Failed",
108
+ "Something went wrong. Please close this tab and try again.",
109
+ true
110
+ )
107
111
  );
108
112
  server.close();
109
113
  reject(new Error(`Authentication error: ${error}`));
@@ -111,14 +115,24 @@ function startCallbackServer() {
111
115
  }
112
116
  if (!code || !state) {
113
117
  res.writeHead(400, { "Content-Type": "text/html" });
114
- res.end("<html><body><h1>Missing parameters.</h1></body></html>");
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
+ );
115
125
  server.close();
116
126
  reject(new Error("Missing code or state in callback"));
117
127
  return;
118
128
  }
119
129
  res.writeHead(200, { "Content-Type": "text/html" });
120
130
  res.end(
121
- "<html><body><h1>Authentication successful!</h1><p>You can close this tab and return to the terminal.</p></body></html>"
131
+ callbackPage(
132
+ "Authentication Successful",
133
+ "You can close this tab and return to the terminal.",
134
+ false
135
+ )
122
136
  );
123
137
  server.close();
124
138
  resolve({ code, state });
@@ -249,6 +263,41 @@ Open this URL in your browser to authenticate:
249
263
  await storeCredentials(credentials);
250
264
  return credentials;
251
265
  }
266
+ function callbackPage(title, message, isError) {
267
+ const icon = isError ? '<svg width="48" height="48" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke="#ef4444" stroke-width="2"/><path stroke="#ef4444" stroke-width="2" stroke-linecap="round" d="M15 9l-6 6M9 9l6 6"/></svg>' : '<svg width="48" height="48" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke="#10b981" stroke-width="2"/><path stroke="#10b981" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M8 12l3 3 5-5"/></svg>';
268
+ return `<!DOCTYPE html>
269
+ <html lang="en">
270
+ <head>
271
+ <meta charset="UTF-8">
272
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
273
+ <title>${title} \u2014 RepoWise</title>
274
+ <link rel="icon" href="https://staging.repowise.ai/favicon.svg" type="image/svg+xml">
275
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
276
+ <style>
277
+ * { margin: 0; padding: 0; box-sizing: border-box; }
278
+ body { font-family: 'Inter', system-ui, sans-serif; background: #0a0b14; color: #e4e4e7; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
279
+ .card { text-align: center; max-width: 440px; padding: 48px 40px; }
280
+ .logo { margin-bottom: 32px; }
281
+ .logo svg { height: 48px; width: auto; }
282
+ .icon { margin-bottom: 20px; }
283
+ h1 { font-size: 24px; font-weight: 700; margin-bottom: 8px; color: ${isError ? "#ef4444" : "#e4e4e7"}; }
284
+ p { font-size: 15px; color: #a1a1aa; line-height: 1.5; }
285
+ </style>
286
+ </head>
287
+ <body>
288
+ <div class="card">
289
+ <div class="logo">
290
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 50" height="48">
291
+ <text x="0" y="38" font-family="Inter, system-ui, sans-serif" font-weight="700" font-size="36" fill="#e4e4e7">Repo<tspan fill="#6c5ce7">Wise</tspan></text>
292
+ </svg>
293
+ </div>
294
+ <div class="icon">${icon}</div>
295
+ <h1>${title}</h1>
296
+ <p>${message}</p>
297
+ </div>
298
+ </body>
299
+ </html>`;
300
+ }
252
301
  function decodeIdToken(idToken) {
253
302
  try {
254
303
  const parts = idToken.split(".");
@@ -674,9 +723,55 @@ var init_progress_renderer = __esm({
674
723
  if (result.existingDocs.length > 0) {
675
724
  console.log(` ${chalk3.dim("Existing docs:")} ${result.existingDocs.join(", ")}`);
676
725
  }
726
+ if (result.fileTree && result.fileTree.length > 0) {
727
+ this.renderTree(result.fileTree);
728
+ }
677
729
  console.log("");
678
730
  spinner.start();
679
731
  }
732
+ renderTree(entries) {
733
+ console.log("");
734
+ console.log(chalk3.cyan.bold(" \u2500\u2500 Project Structure \u2500\u2500"));
735
+ const root = { name: "", type: "tree", children: /* @__PURE__ */ new Map() };
736
+ for (const entry of entries) {
737
+ const parts = entry.path.split("/");
738
+ let current = root;
739
+ for (let i = 0; i < parts.length; i++) {
740
+ const part = parts[i];
741
+ if (!current.children.has(part)) {
742
+ const isLast = i === parts.length - 1;
743
+ current.children.set(part, {
744
+ name: part,
745
+ type: isLast ? entry.type : "tree",
746
+ children: /* @__PURE__ */ new Map()
747
+ });
748
+ }
749
+ current = current.children.get(part);
750
+ }
751
+ }
752
+ const printNode = (node, prefix, isLast) => {
753
+ const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
754
+ const display = node.type === "tree" ? chalk3.bold.dim(`${node.name}/`) : node.name;
755
+ console.log(` ${prefix}${connector}${display}`);
756
+ const sorted = [...node.children.values()].sort((a, b) => {
757
+ if (a.type === "tree" && b.type !== "tree") return -1;
758
+ if (a.type !== "tree" && b.type === "tree") return 1;
759
+ return a.name.localeCompare(b.name);
760
+ });
761
+ const childPrefix = prefix + (isLast ? " " : "\u2502 ");
762
+ sorted.forEach((child, idx) => {
763
+ printNode(child, childPrefix, idx === sorted.length - 1);
764
+ });
765
+ };
766
+ const topLevel = [...root.children.values()].sort((a, b) => {
767
+ if (a.type === "tree" && b.type !== "tree") return -1;
768
+ if (a.type !== "tree" && b.type === "tree") return 1;
769
+ return a.name.localeCompare(b.name);
770
+ });
771
+ topLevel.forEach((child, idx) => {
772
+ printNode(child, "", idx === topLevel.length - 1);
773
+ });
774
+ }
680
775
  renderScanSummary(summary, spinner) {
681
776
  if (this.scanSummaryShown) return;
682
777
  this.scanSummaryShown = true;
@@ -1199,11 +1294,32 @@ async function create() {
1199
1294
  );
1200
1295
  }
1201
1296
  spinner.start("Starting context generation pipeline...");
1202
- const triggerResult = await apiRequest(`/v1/repos/${repoId}/sync`, {
1203
- method: "POST",
1204
- body: JSON.stringify({ scanType: "full" })
1205
- });
1206
- const syncId = triggerResult.syncId;
1297
+ let syncId;
1298
+ try {
1299
+ const triggerResult = await apiRequest(`/v1/repos/${repoId}/sync`, {
1300
+ method: "POST",
1301
+ body: JSON.stringify({ scanType: "full" })
1302
+ });
1303
+ syncId = triggerResult.syncId;
1304
+ } catch (triggerErr) {
1305
+ const msg = triggerErr instanceof Error ? triggerErr.message : "";
1306
+ if (!msg.toLowerCase().includes("already running")) {
1307
+ throw triggerErr;
1308
+ }
1309
+ spinner.text = "Resuming existing pipeline...";
1310
+ const syncs = await apiRequest(
1311
+ `/v1/repos/${repoId}/syncs?limit=1`
1312
+ );
1313
+ const active = syncs.items.find(
1314
+ (s) => s.status === "in_progress" || s.status === "awaiting_input"
1315
+ );
1316
+ if (!active) {
1317
+ throw new Error("Could not find active sync to resume. Please try again.");
1318
+ }
1319
+ syncId = active.syncId;
1320
+ spinner.info(chalk4.cyan("Resuming existing pipeline..."));
1321
+ spinner.start();
1322
+ }
1207
1323
  let pollAttempts = 0;
1208
1324
  const progressRenderer = new ProgressRenderer();
1209
1325
  while (true) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repowise",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "AI-optimized codebase context generator",
6
6
  "bin": {