repowisestage 0.0.26 → 0.0.28
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 +174 -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,39 @@ 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
|
+
rl.setPrompt(" > ");
|
|
2539
|
+
rl.prompt();
|
|
2540
|
+
rl.on("line", (line) => {
|
|
2541
|
+
if (line === "" && lines.length > 0) {
|
|
2542
|
+
rl.close();
|
|
2543
|
+
resolve(lines.join("\n"));
|
|
2544
|
+
} else if (line === "" && lines.length === 0) {
|
|
2545
|
+
rl.close();
|
|
2546
|
+
resolve("");
|
|
2547
|
+
} else {
|
|
2548
|
+
lines.push(line);
|
|
2549
|
+
rl.setPrompt(" > ");
|
|
2550
|
+
rl.prompt();
|
|
2551
|
+
}
|
|
2552
|
+
});
|
|
2553
|
+
rl.on("close", () => {
|
|
2554
|
+
if (lines.length > 0) {
|
|
2555
|
+
resolve(lines.join("\n"));
|
|
2556
|
+
} else {
|
|
2557
|
+
resolve("");
|
|
2558
|
+
}
|
|
2559
|
+
});
|
|
2560
|
+
rl.on("error", reject);
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2435
2563
|
var questionCounter = 0;
|
|
2436
2564
|
async function handleInterview(syncId, questionId, questionText, questionContext, estimatedQuestions) {
|
|
2437
2565
|
questionCounter++;
|
|
@@ -2452,14 +2580,11 @@ async function handleInterview(syncId, questionId, questionText, questionContext
|
|
|
2452
2580
|
console.log(chalk3.dim(` ${questionContext}`));
|
|
2453
2581
|
}
|
|
2454
2582
|
console.log(` ${questionText}`);
|
|
2455
|
-
console.log(chalk3.dim(' (Enter to skip \xB7 "done" to finish early)'));
|
|
2583
|
+
console.log(chalk3.dim(' (Empty line to submit \xB7 Enter to skip \xB7 "done" to finish early)'));
|
|
2456
2584
|
let answer;
|
|
2457
2585
|
try {
|
|
2458
2586
|
answer = await Promise.race([
|
|
2459
|
-
|
|
2460
|
-
message: chalk3.cyan(">"),
|
|
2461
|
-
theme: { prefix: " " }
|
|
2462
|
-
}),
|
|
2587
|
+
multilineInput(),
|
|
2463
2588
|
new Promise(
|
|
2464
2589
|
(_, reject) => setTimeout(() => reject(new Error("INTERVIEW_TIMEOUT")), INTERVIEW_TIMEOUT_MS)
|
|
2465
2590
|
)
|
|
@@ -2650,6 +2775,11 @@ var ProgressRenderer = class {
|
|
|
2650
2775
|
spinner.stop();
|
|
2651
2776
|
console.log("");
|
|
2652
2777
|
console.log(chalk4.cyan.bold(" \u2500\u2500 Code Analysis \u2500\u2500"));
|
|
2778
|
+
console.log(
|
|
2779
|
+
chalk4.cyan(
|
|
2780
|
+
" \u2615 This takes a few minutes \u2014 grab a coffee, we'll handle the rest!"
|
|
2781
|
+
)
|
|
2782
|
+
);
|
|
2653
2783
|
console.log(chalk4.dim(" Analyzing your codebase structure, functions, and relationships."));
|
|
2654
2784
|
spinner.start();
|
|
2655
2785
|
}
|
|
@@ -2669,11 +2799,6 @@ var ProgressRenderer = class {
|
|
|
2669
2799
|
this.generationHeaderShown = true;
|
|
2670
2800
|
spinner.stop();
|
|
2671
2801
|
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
2802
|
console.log("");
|
|
2678
2803
|
spinner.start();
|
|
2679
2804
|
}
|
|
@@ -2776,7 +2901,7 @@ var ProgressRenderer = class {
|
|
|
2776
2901
|
getSpinnerText(syncResult) {
|
|
2777
2902
|
const overallPct = computeOverallProgress(syncResult);
|
|
2778
2903
|
const stepLabel = syncResult.stepLabel ?? syncResult.currentStep ?? "Processing";
|
|
2779
|
-
if (syncResult.scanProgress && !syncResult.scanProgress.summary) {
|
|
2904
|
+
if (syncResult.scanProgress && !syncResult.scanProgress.summary && syncResult.currentStep === "scan-and-generate") {
|
|
2780
2905
|
const sp = syncResult.scanProgress;
|
|
2781
2906
|
const pct = sp.totalBatches > 0 ? Math.round(sp.currentBatch / sp.totalBatches * 100) : 0;
|
|
2782
2907
|
return `Scanning batch ${sp.currentBatch}/${sp.totalBatches} ${chalk4.dim(`(${pct}%)`)}`;
|
|
@@ -2922,26 +3047,51 @@ async function create() {
|
|
|
2922
3047
|
try {
|
|
2923
3048
|
const pricing = await apiRequest(`/v1/repos/${repoId}/rescan-pricing`);
|
|
2924
3049
|
if (pricing.lastFullScanAt) {
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
3050
|
+
const { groups } = decodeIdToken(credentials.idToken);
|
|
3051
|
+
const role = resolveRole(groups ?? []);
|
|
3052
|
+
const canRescan = hasPermission(role, "connectRepos");
|
|
3053
|
+
if (!canRescan) {
|
|
2929
3054
|
spinner.fail(chalk5.red("This repository already has context generated."));
|
|
2930
3055
|
console.log(
|
|
2931
3056
|
chalk5.cyan(
|
|
2932
3057
|
`
|
|
2933
|
-
|
|
3058
|
+
As a team member, run: ${chalk5.bold("repowise member")}
|
|
2934
3059
|
This will download context and configure your AI tools.
|
|
2935
3060
|
`
|
|
2936
3061
|
)
|
|
2937
3062
|
);
|
|
3063
|
+
process.exitCode = 1;
|
|
3064
|
+
return;
|
|
3065
|
+
}
|
|
3066
|
+
if (pricing.allowed && pricing.isFree) {
|
|
3067
|
+
spinner.succeed(chalk5.cyan("Free rescan available. Will trigger a full rescan."));
|
|
3068
|
+
useFreeRescan = true;
|
|
3069
|
+
} else if (pricing.allowed) {
|
|
3070
|
+
spinner.stop();
|
|
3071
|
+
const costText = pricing.estimatedCost && pricing.estimatedCost > 0 ? `$${pricing.estimatedCost.toFixed(2)}` : "pay-as-you-go (based on actual processing cost)";
|
|
2938
3072
|
console.log(
|
|
2939
|
-
chalk5.
|
|
2940
|
-
`
|
|
2941
|
-
|
|
2942
|
-
`
|
|
3073
|
+
chalk5.yellow(
|
|
3074
|
+
`
|
|
3075
|
+
This repository already has context generated.
|
|
3076
|
+
A full rescan will cost: ${chalk5.bold(costText)}`
|
|
2943
3077
|
)
|
|
2944
3078
|
);
|
|
3079
|
+
if (pricing.costWarning) {
|
|
3080
|
+
console.log(chalk5.dim(` ${pricing.costWarning}`));
|
|
3081
|
+
}
|
|
3082
|
+
const { confirm: confirm2 } = await import("@inquirer/prompts");
|
|
3083
|
+
const proceed = await confirm2({
|
|
3084
|
+
message: "Proceed with paid full rescan?",
|
|
3085
|
+
default: false
|
|
3086
|
+
});
|
|
3087
|
+
if (!proceed) {
|
|
3088
|
+
console.log(chalk5.dim("\n To sync recent changes, use: repowise sync\n"));
|
|
3089
|
+
process.exitCode = 0;
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
useFreeRescan = true;
|
|
3093
|
+
} else {
|
|
3094
|
+
spinner.fail(chalk5.red(pricing.reason ?? "Cannot rescan at this time."));
|
|
2945
3095
|
process.exitCode = 1;
|
|
2946
3096
|
return;
|
|
2947
3097
|
}
|
|
@@ -3913,8 +4063,8 @@ async function config() {
|
|
|
3913
4063
|
}
|
|
3914
4064
|
patch.deliveryMode = newMode;
|
|
3915
4065
|
} else if (setting === "monitoredBranch") {
|
|
3916
|
-
const { input
|
|
3917
|
-
const newBranch = await
|
|
4066
|
+
const { input } = await import("@inquirer/prompts");
|
|
4067
|
+
const newBranch = await input({
|
|
3918
4068
|
message: "Monitored branch",
|
|
3919
4069
|
default: currentBranch
|
|
3920
4070
|
});
|