repowise 0.1.86 → 0.1.87
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 +192 -24
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -1831,6 +1831,101 @@ import { dirname as dirname6, join as join18 } from "path";
|
|
|
1831
1831
|
import chalk5 from "chalk";
|
|
1832
1832
|
import ora from "ora";
|
|
1833
1833
|
|
|
1834
|
+
// ../../packages/shared/src/constants/tiers.ts
|
|
1835
|
+
var SUBSCRIPTION_TIERS = {
|
|
1836
|
+
STARTER: "starter",
|
|
1837
|
+
PRO: "pro",
|
|
1838
|
+
TEAM: "team"
|
|
1839
|
+
};
|
|
1840
|
+
var TIER_LIMITS = {
|
|
1841
|
+
[SUBSCRIPTION_TIERS.STARTER]: {
|
|
1842
|
+
maxRepos: 1,
|
|
1843
|
+
maxSeats: 1,
|
|
1844
|
+
maxSyncsPerMonth: 10,
|
|
1845
|
+
maxConcurrentSyncs: 1,
|
|
1846
|
+
bedrockEndpoint: "public"
|
|
1847
|
+
},
|
|
1848
|
+
[SUBSCRIPTION_TIERS.PRO]: {
|
|
1849
|
+
maxRepos: 2,
|
|
1850
|
+
maxSeats: 1,
|
|
1851
|
+
maxSyncsPerMonth: 30,
|
|
1852
|
+
maxConcurrentSyncs: 2,
|
|
1853
|
+
bedrockEndpoint: "public"
|
|
1854
|
+
},
|
|
1855
|
+
[SUBSCRIPTION_TIERS.TEAM]: {
|
|
1856
|
+
maxRepos: 3,
|
|
1857
|
+
maxSeats: 999999,
|
|
1858
|
+
maxSyncsPerMonth: 30,
|
|
1859
|
+
maxConcurrentSyncs: 10,
|
|
1860
|
+
bedrockEndpoint: "public"
|
|
1861
|
+
}
|
|
1862
|
+
};
|
|
1863
|
+
|
|
1864
|
+
// ../../packages/shared/src/constants/roles.ts
|
|
1865
|
+
var ROLES = {
|
|
1866
|
+
OWNER: "owner",
|
|
1867
|
+
ADMIN: "admin",
|
|
1868
|
+
REPO_MANAGER: "repo_manager",
|
|
1869
|
+
MEMBER: "member"
|
|
1870
|
+
};
|
|
1871
|
+
var PERMISSIONS = {
|
|
1872
|
+
[ROLES.OWNER]: {
|
|
1873
|
+
connectRepos: true,
|
|
1874
|
+
viewSync: true,
|
|
1875
|
+
triggerRetry: true,
|
|
1876
|
+
configWatcher: true,
|
|
1877
|
+
inviteMembers: true,
|
|
1878
|
+
manageBilling: true,
|
|
1879
|
+
configAiTools: true,
|
|
1880
|
+
manageTeam: true
|
|
1881
|
+
},
|
|
1882
|
+
[ROLES.ADMIN]: {
|
|
1883
|
+
connectRepos: true,
|
|
1884
|
+
viewSync: true,
|
|
1885
|
+
triggerRetry: true,
|
|
1886
|
+
configWatcher: true,
|
|
1887
|
+
inviteMembers: true,
|
|
1888
|
+
manageBilling: false,
|
|
1889
|
+
configAiTools: true,
|
|
1890
|
+
manageTeam: true
|
|
1891
|
+
},
|
|
1892
|
+
[ROLES.REPO_MANAGER]: {
|
|
1893
|
+
connectRepos: true,
|
|
1894
|
+
viewSync: true,
|
|
1895
|
+
triggerRetry: true,
|
|
1896
|
+
configWatcher: true,
|
|
1897
|
+
inviteMembers: false,
|
|
1898
|
+
manageBilling: false,
|
|
1899
|
+
configAiTools: true,
|
|
1900
|
+
manageTeam: false
|
|
1901
|
+
},
|
|
1902
|
+
[ROLES.MEMBER]: {
|
|
1903
|
+
connectRepos: false,
|
|
1904
|
+
viewSync: true,
|
|
1905
|
+
triggerRetry: true,
|
|
1906
|
+
configWatcher: false,
|
|
1907
|
+
inviteMembers: false,
|
|
1908
|
+
manageBilling: false,
|
|
1909
|
+
configAiTools: true,
|
|
1910
|
+
manageTeam: false
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
function hasPermission(role, permission) {
|
|
1914
|
+
return PERMISSIONS[role][permission];
|
|
1915
|
+
}
|
|
1916
|
+
var ROLE_PRIORITY = [
|
|
1917
|
+
ROLES.OWNER,
|
|
1918
|
+
ROLES.ADMIN,
|
|
1919
|
+
ROLES.REPO_MANAGER,
|
|
1920
|
+
ROLES.MEMBER
|
|
1921
|
+
];
|
|
1922
|
+
function resolveRole(groups) {
|
|
1923
|
+
for (const role of ROLE_PRIORITY) {
|
|
1924
|
+
if (groups.includes(role)) return role;
|
|
1925
|
+
}
|
|
1926
|
+
return ROLES.MEMBER;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1834
1929
|
// src/lib/auth.ts
|
|
1835
1930
|
import { createHash, randomBytes } from "crypto";
|
|
1836
1931
|
import { readFile as readFile7, writeFile as writeFile9, mkdir as mkdir9, chmod as chmod4, unlink as unlink7 } from "fs/promises";
|
|
@@ -2110,7 +2205,11 @@ function decodeIdToken(idToken) {
|
|
|
2110
2205
|
const parts = idToken.split(".");
|
|
2111
2206
|
if (parts.length < 2) return { email: "unknown" };
|
|
2112
2207
|
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
2113
|
-
return {
|
|
2208
|
+
return {
|
|
2209
|
+
email: payload.email ?? "unknown",
|
|
2210
|
+
tenantId: payload["custom:tenant_id"],
|
|
2211
|
+
groups: payload["cognito:groups"]
|
|
2212
|
+
};
|
|
2114
2213
|
} catch {
|
|
2115
2214
|
return { email: "unknown" };
|
|
2116
2215
|
}
|
|
@@ -2428,10 +2527,57 @@ function detectRepoName(repoRoot) {
|
|
|
2428
2527
|
}
|
|
2429
2528
|
|
|
2430
2529
|
// src/lib/interview-handler.ts
|
|
2530
|
+
import { createInterface } from "readline";
|
|
2431
2531
|
import chalk3 from "chalk";
|
|
2432
|
-
import { input } from "@inquirer/prompts";
|
|
2433
2532
|
var INTERVIEW_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2434
2533
|
var MAX_QUESTIONS = 10;
|
|
2534
|
+
function multilineInput() {
|
|
2535
|
+
return new Promise((resolve, reject) => {
|
|
2536
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2537
|
+
const lines = [];
|
|
2538
|
+
let lastLineTime = 0;
|
|
2539
|
+
let resolved = false;
|
|
2540
|
+
const done = (value) => {
|
|
2541
|
+
if (resolved) return;
|
|
2542
|
+
resolved = true;
|
|
2543
|
+
rl.close();
|
|
2544
|
+
resolve(value);
|
|
2545
|
+
};
|
|
2546
|
+
rl.setPrompt(" > ");
|
|
2547
|
+
rl.prompt();
|
|
2548
|
+
rl.on("line", (line) => {
|
|
2549
|
+
const now = Date.now();
|
|
2550
|
+
const elapsed = now - lastLineTime;
|
|
2551
|
+
lastLineTime = now;
|
|
2552
|
+
const lower = line.trim().toLowerCase();
|
|
2553
|
+
if (lower === "done" || lower === "skip") {
|
|
2554
|
+
done(lower);
|
|
2555
|
+
return;
|
|
2556
|
+
}
|
|
2557
|
+
if (lines.length === 0) {
|
|
2558
|
+
if (line === "") {
|
|
2559
|
+
done("");
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
lines.push(line);
|
|
2563
|
+
rl.setPrompt(" > ");
|
|
2564
|
+
rl.prompt();
|
|
2565
|
+
return;
|
|
2566
|
+
}
|
|
2567
|
+
if (elapsed > 50 && line === "") {
|
|
2568
|
+
done(lines.join("\n").trim());
|
|
2569
|
+
return;
|
|
2570
|
+
}
|
|
2571
|
+
lines.push(line);
|
|
2572
|
+
rl.setPrompt(" > ");
|
|
2573
|
+
rl.prompt();
|
|
2574
|
+
});
|
|
2575
|
+
rl.on("close", () => {
|
|
2576
|
+
done(lines.length > 0 ? lines.join("\n").trim() : "");
|
|
2577
|
+
});
|
|
2578
|
+
rl.on("error", reject);
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2435
2581
|
var questionCounter = 0;
|
|
2436
2582
|
async function handleInterview(syncId, questionId, questionText, questionContext, estimatedQuestions) {
|
|
2437
2583
|
questionCounter++;
|
|
@@ -2452,14 +2598,11 @@ async function handleInterview(syncId, questionId, questionText, questionContext
|
|
|
2452
2598
|
console.log(chalk3.dim(` ${questionContext}`));
|
|
2453
2599
|
}
|
|
2454
2600
|
console.log(` ${questionText}`);
|
|
2455
|
-
console.log(chalk3.dim(' (Enter to skip \xB7 "done" to finish early)'));
|
|
2601
|
+
console.log(chalk3.dim(' (Enter to submit \xB7 Enter to skip \xB7 "done" to finish early)'));
|
|
2456
2602
|
let answer;
|
|
2457
2603
|
try {
|
|
2458
2604
|
answer = await Promise.race([
|
|
2459
|
-
|
|
2460
|
-
message: chalk3.cyan(">"),
|
|
2461
|
-
theme: { prefix: " " }
|
|
2462
|
-
}),
|
|
2605
|
+
multilineInput(),
|
|
2463
2606
|
new Promise(
|
|
2464
2607
|
(_, reject) => setTimeout(() => reject(new Error("INTERVIEW_TIMEOUT")), INTERVIEW_TIMEOUT_MS)
|
|
2465
2608
|
)
|
|
@@ -2650,6 +2793,11 @@ var ProgressRenderer = class {
|
|
|
2650
2793
|
spinner.stop();
|
|
2651
2794
|
console.log("");
|
|
2652
2795
|
console.log(chalk4.cyan.bold(" \u2500\u2500 Code Analysis \u2500\u2500"));
|
|
2796
|
+
console.log(
|
|
2797
|
+
chalk4.cyan(
|
|
2798
|
+
" \u2615 This takes a few minutes \u2014 grab a coffee, we'll handle the rest!"
|
|
2799
|
+
)
|
|
2800
|
+
);
|
|
2653
2801
|
console.log(chalk4.dim(" Analyzing your codebase structure, functions, and relationships."));
|
|
2654
2802
|
spinner.start();
|
|
2655
2803
|
}
|
|
@@ -2669,11 +2817,6 @@ var ProgressRenderer = class {
|
|
|
2669
2817
|
this.generationHeaderShown = true;
|
|
2670
2818
|
spinner.stop();
|
|
2671
2819
|
console.log(chalk4.cyan.bold(" \u2500\u2500 Context Generation \u2500\u2500"));
|
|
2672
|
-
console.log(
|
|
2673
|
-
chalk4.cyan(
|
|
2674
|
-
" \u2615 This takes a few minutes \u2014 grab a coffee, we'll handle the rest!"
|
|
2675
|
-
)
|
|
2676
|
-
);
|
|
2677
2820
|
console.log("");
|
|
2678
2821
|
spinner.start();
|
|
2679
2822
|
}
|
|
@@ -2776,7 +2919,7 @@ var ProgressRenderer = class {
|
|
|
2776
2919
|
getSpinnerText(syncResult) {
|
|
2777
2920
|
const overallPct = computeOverallProgress(syncResult);
|
|
2778
2921
|
const stepLabel = syncResult.stepLabel ?? syncResult.currentStep ?? "Processing";
|
|
2779
|
-
if (syncResult.scanProgress && !syncResult.scanProgress.summary) {
|
|
2922
|
+
if (syncResult.scanProgress && !syncResult.scanProgress.summary && syncResult.currentStep === "scan-and-generate") {
|
|
2780
2923
|
const sp = syncResult.scanProgress;
|
|
2781
2924
|
const pct = sp.totalBatches > 0 ? Math.round(sp.currentBatch / sp.totalBatches * 100) : 0;
|
|
2782
2925
|
return `Scanning batch ${sp.currentBatch}/${sp.totalBatches} ${chalk4.dim(`(${pct}%)`)}`;
|
|
@@ -2922,26 +3065,51 @@ async function create() {
|
|
|
2922
3065
|
try {
|
|
2923
3066
|
const pricing = await apiRequest(`/v1/repos/${repoId}/rescan-pricing`);
|
|
2924
3067
|
if (pricing.lastFullScanAt) {
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
3068
|
+
const { groups } = decodeIdToken(credentials.idToken);
|
|
3069
|
+
const role = resolveRole(groups ?? []);
|
|
3070
|
+
const canRescan = hasPermission(role, "connectRepos");
|
|
3071
|
+
if (!canRescan) {
|
|
2929
3072
|
spinner.fail(chalk5.red("This repository already has context generated."));
|
|
2930
3073
|
console.log(
|
|
2931
3074
|
chalk5.cyan(
|
|
2932
3075
|
`
|
|
2933
|
-
|
|
3076
|
+
As a team member, run: ${chalk5.bold("repowise member")}
|
|
2934
3077
|
This will download context and configure your AI tools.
|
|
2935
3078
|
`
|
|
2936
3079
|
)
|
|
2937
3080
|
);
|
|
3081
|
+
process.exitCode = 1;
|
|
3082
|
+
return;
|
|
3083
|
+
}
|
|
3084
|
+
if (pricing.allowed && pricing.isFree) {
|
|
3085
|
+
spinner.succeed(chalk5.cyan("Free rescan available. Will trigger a full rescan."));
|
|
3086
|
+
useFreeRescan = true;
|
|
3087
|
+
} else if (pricing.allowed) {
|
|
3088
|
+
spinner.stop();
|
|
3089
|
+
const costText = pricing.estimatedCost && pricing.estimatedCost > 0 ? `$${pricing.estimatedCost.toFixed(2)}` : "pay-as-you-go (based on actual processing cost)";
|
|
2938
3090
|
console.log(
|
|
2939
|
-
chalk5.
|
|
2940
|
-
`
|
|
2941
|
-
|
|
2942
|
-
`
|
|
3091
|
+
chalk5.yellow(
|
|
3092
|
+
`
|
|
3093
|
+
This repository already has context generated.
|
|
3094
|
+
A full rescan will cost: ${chalk5.bold(costText)}`
|
|
2943
3095
|
)
|
|
2944
3096
|
);
|
|
3097
|
+
if (pricing.costWarning) {
|
|
3098
|
+
console.log(chalk5.dim(` ${pricing.costWarning}`));
|
|
3099
|
+
}
|
|
3100
|
+
const { confirm: confirm2 } = await import("@inquirer/prompts");
|
|
3101
|
+
const proceed = await confirm2({
|
|
3102
|
+
message: "Proceed with paid full rescan?",
|
|
3103
|
+
default: false
|
|
3104
|
+
});
|
|
3105
|
+
if (!proceed) {
|
|
3106
|
+
console.log(chalk5.dim("\n To sync recent changes, use: repowise sync\n"));
|
|
3107
|
+
process.exitCode = 0;
|
|
3108
|
+
return;
|
|
3109
|
+
}
|
|
3110
|
+
useFreeRescan = true;
|
|
3111
|
+
} else {
|
|
3112
|
+
spinner.fail(chalk5.red(pricing.reason ?? "Cannot rescan at this time."));
|
|
2945
3113
|
process.exitCode = 1;
|
|
2946
3114
|
return;
|
|
2947
3115
|
}
|
|
@@ -3913,8 +4081,8 @@ async function config() {
|
|
|
3913
4081
|
}
|
|
3914
4082
|
patch.deliveryMode = newMode;
|
|
3915
4083
|
} else if (setting === "monitoredBranch") {
|
|
3916
|
-
const { input
|
|
3917
|
-
const newBranch = await
|
|
4084
|
+
const { input } = await import("@inquirer/prompts");
|
|
4085
|
+
const newBranch = await input({
|
|
3918
4086
|
message: "Monitored branch",
|
|
3919
4087
|
default: currentBranch
|
|
3920
4088
|
});
|