repowisestage 0.0.69 → 0.0.71
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 +632 -284
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -3133,7 +3133,7 @@ var init_telemetry = __esm({
|
|
|
3133
3133
|
// bin/repowise.ts
|
|
3134
3134
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3135
3135
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3136
|
-
import { dirname as dirname23, join as
|
|
3136
|
+
import { dirname as dirname23, join as join62 } from "path";
|
|
3137
3137
|
import { Command } from "commander";
|
|
3138
3138
|
|
|
3139
3139
|
// ../listener/dist/main.js
|
|
@@ -8007,10 +8007,10 @@ async function ensureServerConsent(opts) {
|
|
|
8007
8007
|
});
|
|
8008
8008
|
if (!res.ok)
|
|
8009
8009
|
return;
|
|
8010
|
-
const
|
|
8010
|
+
const fs31 = await import("fs/promises");
|
|
8011
8011
|
const path = await import("path");
|
|
8012
|
-
await
|
|
8013
|
-
await
|
|
8012
|
+
await fs31.mkdir(path.dirname(opts.markerPath), { recursive: true });
|
|
8013
|
+
await fs31.writeFile(opts.markerPath, (/* @__PURE__ */ new Date()).toISOString() + "\n", {
|
|
8014
8014
|
encoding: "utf-8",
|
|
8015
8015
|
mode: 384
|
|
8016
8016
|
});
|
|
@@ -10510,6 +10510,33 @@ function sleep(ms) {
|
|
|
10510
10510
|
}, ms);
|
|
10511
10511
|
});
|
|
10512
10512
|
}
|
|
10513
|
+
async function waitForCredentials(isRunning2) {
|
|
10514
|
+
let changed = false;
|
|
10515
|
+
let watcher = null;
|
|
10516
|
+
try {
|
|
10517
|
+
const fs31 = await import("fs");
|
|
10518
|
+
watcher = fs31.watch(getConfigDir(), (_event, filename) => {
|
|
10519
|
+
if (!filename || filename === "credentials.json")
|
|
10520
|
+
changed = true;
|
|
10521
|
+
});
|
|
10522
|
+
} catch {
|
|
10523
|
+
}
|
|
10524
|
+
try {
|
|
10525
|
+
while (isRunning2()) {
|
|
10526
|
+
await sleep(changed ? 0 : 1e4);
|
|
10527
|
+
changed = false;
|
|
10528
|
+
if (!isRunning2())
|
|
10529
|
+
break;
|
|
10530
|
+
const fresh = await getValidCredentials({ forceRefresh: true });
|
|
10531
|
+
if (fresh)
|
|
10532
|
+
return fresh;
|
|
10533
|
+
}
|
|
10534
|
+
return null;
|
|
10535
|
+
} finally {
|
|
10536
|
+
if (watcher)
|
|
10537
|
+
watcher.close();
|
|
10538
|
+
}
|
|
10539
|
+
}
|
|
10513
10540
|
function decodeEmailFromIdToken(idToken) {
|
|
10514
10541
|
try {
|
|
10515
10542
|
const payload = JSON.parse(Buffer.from(idToken.split(".")[1], "base64url").toString());
|
|
@@ -10741,6 +10768,9 @@ async function checkStaleContext(repos, state, groups) {
|
|
|
10741
10768
|
}
|
|
10742
10769
|
return dirty;
|
|
10743
10770
|
}
|
|
10771
|
+
function mcpAiToolsKey(aiTools) {
|
|
10772
|
+
return JSON.stringify([...aiTools ?? []].sort());
|
|
10773
|
+
}
|
|
10744
10774
|
async function reconcileMcpConfigs(repos, packageName) {
|
|
10745
10775
|
const shimCmd = packageName;
|
|
10746
10776
|
const { contextFolder, aiTools, graphOnly } = await readRawToolConfig();
|
|
@@ -10909,12 +10939,15 @@ async function startListener() {
|
|
|
10909
10939
|
process.exitCode = 1;
|
|
10910
10940
|
return;
|
|
10911
10941
|
}
|
|
10912
|
-
|
|
10942
|
+
let credentials = await getValidCredentials();
|
|
10913
10943
|
if (!credentials) {
|
|
10914
|
-
console.
|
|
10915
|
-
await
|
|
10916
|
-
|
|
10917
|
-
|
|
10944
|
+
console.warn("Not logged in. Run `repowise login` \u2014 the listener will start automatically once you sign in.");
|
|
10945
|
+
credentials = await waitForCredentials(() => running);
|
|
10946
|
+
if (!credentials) {
|
|
10947
|
+
await releaseLockAndExit();
|
|
10948
|
+
return;
|
|
10949
|
+
}
|
|
10950
|
+
console.log("Logged in \u2014 starting RepoWise listener.");
|
|
10918
10951
|
}
|
|
10919
10952
|
let state;
|
|
10920
10953
|
try {
|
|
@@ -10981,6 +11014,7 @@ async function startListener() {
|
|
|
10981
11014
|
let pollIntervalMs = 5e3;
|
|
10982
11015
|
let pollCycleCount = 0;
|
|
10983
11016
|
const RECONCILE_EVERY_N_CYCLES = 60;
|
|
11017
|
+
let lastMcpAiToolsKey = null;
|
|
10984
11018
|
const origLog = console.log.bind(console);
|
|
10985
11019
|
const origError = console.error.bind(console);
|
|
10986
11020
|
const origWarn = console.warn.bind(console);
|
|
@@ -11203,6 +11237,19 @@ async function startListener() {
|
|
|
11203
11237
|
void warmReposLsp(newRepos, mcpRuntime.lspWorkspaces, config2.lspOverrides).catch(() => {
|
|
11204
11238
|
});
|
|
11205
11239
|
}
|
|
11240
|
+
void reconcileMcpConfigs(newRepos, packageName).catch((err) => {
|
|
11241
|
+
console.warn("[mcp-config] front-load for newly-registered repo(s) failed:", err instanceof Error ? err.message : String(err));
|
|
11242
|
+
});
|
|
11243
|
+
}
|
|
11244
|
+
const aiToolsKey = mcpAiToolsKey((await readRawToolConfig()).aiTools);
|
|
11245
|
+
if (lastMcpAiToolsKey === null) {
|
|
11246
|
+
lastMcpAiToolsKey = aiToolsKey;
|
|
11247
|
+
} else if (aiToolsKey !== lastMcpAiToolsKey) {
|
|
11248
|
+
lastMcpAiToolsKey = aiToolsKey;
|
|
11249
|
+
console.log("[config-sync] AI-tool selection changed \u2014 front-loading MCP config");
|
|
11250
|
+
void reconcileMcpConfigs(freshRepos, packageName).catch((err) => {
|
|
11251
|
+
console.warn("[mcp-config] front-load for aiTools change failed:", err instanceof Error ? err.message : String(err));
|
|
11252
|
+
});
|
|
11206
11253
|
}
|
|
11207
11254
|
} catch {
|
|
11208
11255
|
}
|
|
@@ -11453,8 +11500,8 @@ async function startListener() {
|
|
|
11453
11500
|
await sleep(5e3);
|
|
11454
11501
|
if (!running)
|
|
11455
11502
|
break;
|
|
11456
|
-
const
|
|
11457
|
-
if (
|
|
11503
|
+
const fresh2 = await getValidCredentials({ forceRefresh: true });
|
|
11504
|
+
if (fresh2) {
|
|
11458
11505
|
console.log("Credentials recovered \u2014 resuming listener");
|
|
11459
11506
|
recovered = true;
|
|
11460
11507
|
break;
|
|
@@ -11475,29 +11522,9 @@ async function startListener() {
|
|
|
11475
11522
|
} catch {
|
|
11476
11523
|
}
|
|
11477
11524
|
}
|
|
11478
|
-
const
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
try {
|
|
11482
|
-
const fs30 = await import("fs");
|
|
11483
|
-
watcher = fs30.watch(credentialsPath, () => {
|
|
11484
|
-
credentialsChanged = true;
|
|
11485
|
-
});
|
|
11486
|
-
} catch {
|
|
11487
|
-
}
|
|
11488
|
-
while (running) {
|
|
11489
|
-
await sleep(credentialsChanged ? 0 : 1e4);
|
|
11490
|
-
credentialsChanged = false;
|
|
11491
|
-
if (!running)
|
|
11492
|
-
break;
|
|
11493
|
-
const fresh = await getValidCredentials({ forceRefresh: true });
|
|
11494
|
-
if (fresh) {
|
|
11495
|
-
console.log("Re-authenticated \u2014 resuming listener");
|
|
11496
|
-
break;
|
|
11497
|
-
}
|
|
11498
|
-
}
|
|
11499
|
-
if (watcher)
|
|
11500
|
-
watcher.close();
|
|
11525
|
+
const fresh = await waitForCredentials(() => running);
|
|
11526
|
+
if (fresh)
|
|
11527
|
+
console.log("Re-authenticated \u2014 resuming listener");
|
|
11501
11528
|
continue;
|
|
11502
11529
|
}
|
|
11503
11530
|
pollIntervalMs = minPollInterval;
|
|
@@ -11651,7 +11678,7 @@ async function showWelcome(currentVersion) {
|
|
|
11651
11678
|
|
|
11652
11679
|
// src/commands/create.ts
|
|
11653
11680
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11654
|
-
import { dirname as dirname19, join as
|
|
11681
|
+
import { dirname as dirname19, join as join50 } from "path";
|
|
11655
11682
|
init_src();
|
|
11656
11683
|
import chalk8 from "chalk";
|
|
11657
11684
|
import ora from "ora";
|
|
@@ -12010,25 +12037,26 @@ async function apiRequest(path, options) {
|
|
|
12010
12037
|
// src/lib/prompts.ts
|
|
12011
12038
|
import { checkbox, confirm, Separator } from "@inquirer/prompts";
|
|
12012
12039
|
import chalk2 from "chalk";
|
|
12013
|
-
async function selectAiTools() {
|
|
12040
|
+
async function selectAiTools(opts) {
|
|
12041
|
+
const checkedSet = new Set(opts?.defaults ?? []);
|
|
12014
12042
|
const choices = [
|
|
12015
12043
|
new Separator(chalk2.dim("\u2500\u2500 Popular \u2500\u2500")),
|
|
12016
|
-
{ name: "Cursor", value: "cursor" },
|
|
12017
|
-
{ name: "Claude Code", value: "claude-code" },
|
|
12018
|
-
{ name: "GitHub Copilot", value: "copilot" },
|
|
12019
|
-
{ name: "Windsurf", value: "windsurf" },
|
|
12044
|
+
{ name: "Cursor", value: "cursor", checked: checkedSet.has("cursor") },
|
|
12045
|
+
{ name: "Claude Code", value: "claude-code", checked: checkedSet.has("claude-code") },
|
|
12046
|
+
{ name: "GitHub Copilot", value: "copilot", checked: checkedSet.has("copilot") },
|
|
12047
|
+
{ name: "Windsurf", value: "windsurf", checked: checkedSet.has("windsurf") },
|
|
12020
12048
|
new Separator(chalk2.dim("\u2500\u2500 More Tools \u2500\u2500")),
|
|
12021
|
-
{ name: "Cline", value: "cline" },
|
|
12022
|
-
{ name: "Codex", value: "codex" },
|
|
12049
|
+
{ name: "Cline", value: "cline", checked: checkedSet.has("cline") },
|
|
12050
|
+
{ name: "Codex", value: "codex", checked: checkedSet.has("codex") },
|
|
12023
12051
|
// Roo Code shut down 2026-05-15; Kilo Code is the community successor.
|
|
12024
|
-
{ name: "Kilo Code", value: "kilo" },
|
|
12025
|
-
{ name: "Gemini CLI", value: "gemini" },
|
|
12052
|
+
{ name: "Kilo Code", value: "kilo", checked: checkedSet.has("kilo") },
|
|
12053
|
+
{ name: "Gemini CLI", value: "gemini", checked: checkedSet.has("gemini") },
|
|
12026
12054
|
new Separator(chalk2.dim("\u2500\u2500 Cloud Agents \u2500\u2500")),
|
|
12027
|
-
{ name: "Warp", value: "warp" },
|
|
12028
|
-
{ name: "JetBrains Junie", value: "junie" },
|
|
12029
|
-
{ name: "Google Jules", value: "jules" },
|
|
12030
|
-
{ name: "Amp", value: "amp" },
|
|
12031
|
-
{ name: "Devin", value: "devin" },
|
|
12055
|
+
{ name: "Warp", value: "warp", checked: checkedSet.has("warp") },
|
|
12056
|
+
{ name: "JetBrains Junie", value: "junie", checked: checkedSet.has("junie") },
|
|
12057
|
+
{ name: "Google Jules", value: "jules", checked: checkedSet.has("jules") },
|
|
12058
|
+
{ name: "Amp", value: "amp", checked: checkedSet.has("amp") },
|
|
12059
|
+
{ name: "Devin", value: "devin", checked: checkedSet.has("devin") },
|
|
12032
12060
|
new Separator(chalk2.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),
|
|
12033
12061
|
{ name: "Other (manual setup)", value: "other" }
|
|
12034
12062
|
];
|
|
@@ -12051,11 +12079,126 @@ async function selectAiTools() {
|
|
|
12051
12079
|
}
|
|
12052
12080
|
}
|
|
12053
12081
|
|
|
12082
|
+
// src/lib/setup-tools.ts
|
|
12083
|
+
async function writeToolConfigsForRepo(opts) {
|
|
12084
|
+
const { repoRoot, tools, repoName, contextFolder, contextFiles, variant, migrateLegacy } = opts;
|
|
12085
|
+
const results = [];
|
|
12086
|
+
const written = /* @__PURE__ */ new Set();
|
|
12087
|
+
for (const tool of tools) {
|
|
12088
|
+
const config2 = AI_TOOL_CONFIG[tool];
|
|
12089
|
+
if (written.has(config2.filePath)) continue;
|
|
12090
|
+
written.add(config2.filePath);
|
|
12091
|
+
if (migrateLegacy && config2.legacyFilePath) {
|
|
12092
|
+
await migrateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles, variant);
|
|
12093
|
+
}
|
|
12094
|
+
const { created } = await updateToolConfig(
|
|
12095
|
+
repoRoot,
|
|
12096
|
+
tool,
|
|
12097
|
+
repoName,
|
|
12098
|
+
contextFolder,
|
|
12099
|
+
contextFiles,
|
|
12100
|
+
variant
|
|
12101
|
+
);
|
|
12102
|
+
results.push(`${created ? "Created" : "Updated"} ${config2.filePath}`);
|
|
12103
|
+
}
|
|
12104
|
+
if (!written.has("AGENTS.md")) {
|
|
12105
|
+
const { created } = await updateToolConfig(
|
|
12106
|
+
repoRoot,
|
|
12107
|
+
"codex",
|
|
12108
|
+
repoName,
|
|
12109
|
+
contextFolder,
|
|
12110
|
+
contextFiles,
|
|
12111
|
+
variant
|
|
12112
|
+
);
|
|
12113
|
+
results.push(`${created ? "Created" : "Updated"} AGENTS.md`);
|
|
12114
|
+
}
|
|
12115
|
+
if (tools.includes("claude-code")) {
|
|
12116
|
+
const { relPath } = await writeClaudeHooksToRepo(repoRoot, contextFolder, variant);
|
|
12117
|
+
results.push(`Configured ${relPath} (RepoWise-first + SubagentStart hooks, local-only)`);
|
|
12118
|
+
}
|
|
12119
|
+
return results;
|
|
12120
|
+
}
|
|
12121
|
+
|
|
12122
|
+
// src/lib/mcp-resolver.ts
|
|
12123
|
+
import { basename as basename4, join as join45 } from "path";
|
|
12124
|
+
import { promises as fs21 } from "fs";
|
|
12125
|
+
var MCP_WRITER_TOOLS = /* @__PURE__ */ new Set([
|
|
12126
|
+
"claude-code",
|
|
12127
|
+
"cursor",
|
|
12128
|
+
"copilot",
|
|
12129
|
+
"codex",
|
|
12130
|
+
"windsurf",
|
|
12131
|
+
"cline",
|
|
12132
|
+
"gemini"
|
|
12133
|
+
]);
|
|
12134
|
+
function mcpPathFor(tool, repoRoot, home) {
|
|
12135
|
+
switch (tool) {
|
|
12136
|
+
case "claude-code":
|
|
12137
|
+
return { path: join45(repoRoot, ".mcp.json"), scope: "repo" };
|
|
12138
|
+
case "cursor":
|
|
12139
|
+
return { path: join45(repoRoot, ".cursor", "mcp.json"), scope: "repo" };
|
|
12140
|
+
case "copilot":
|
|
12141
|
+
return { path: join45(repoRoot, ".vscode", "mcp.json"), scope: "repo" };
|
|
12142
|
+
case "codex":
|
|
12143
|
+
return { path: join45(home, ".codex", "mcp.json"), scope: "global" };
|
|
12144
|
+
case "windsurf":
|
|
12145
|
+
return { path: join45(home, ".codeium", "windsurf", "mcp_config.json"), scope: "global" };
|
|
12146
|
+
case "cline":
|
|
12147
|
+
return { path: join45(home, ".cline", "mcp.json"), scope: "global" };
|
|
12148
|
+
case "gemini":
|
|
12149
|
+
return { path: join45(home, ".gemini", "settings.json"), scope: "global" };
|
|
12150
|
+
default:
|
|
12151
|
+
return null;
|
|
12152
|
+
}
|
|
12153
|
+
}
|
|
12154
|
+
function mcpServerKeyFor(repoRoot) {
|
|
12155
|
+
return `RepoWise MCP for ${basename4(repoRoot)}`;
|
|
12156
|
+
}
|
|
12157
|
+
function mcpConfigTargetForTool(tool, opts) {
|
|
12158
|
+
const loc = mcpPathFor(tool, opts.repoRoot, opts.home);
|
|
12159
|
+
if (!loc) return null;
|
|
12160
|
+
return { tool, path: loc.path, scope: loc.scope, serverKey: mcpServerKeyFor(opts.repoRoot) };
|
|
12161
|
+
}
|
|
12162
|
+
async function mcpConfigState(target) {
|
|
12163
|
+
let raw;
|
|
12164
|
+
try {
|
|
12165
|
+
raw = await fs21.readFile(target.path, "utf-8");
|
|
12166
|
+
} catch {
|
|
12167
|
+
return "absent";
|
|
12168
|
+
}
|
|
12169
|
+
try {
|
|
12170
|
+
const parsed = JSON.parse(raw);
|
|
12171
|
+
return parsed.mcpServers && target.serverKey in parsed.mcpServers ? "configured" : "pending";
|
|
12172
|
+
} catch {
|
|
12173
|
+
return "absent";
|
|
12174
|
+
}
|
|
12175
|
+
}
|
|
12176
|
+
function mcpActivationHint(tool, repoName) {
|
|
12177
|
+
if (!MCP_WRITER_TOOLS.has(tool)) return null;
|
|
12178
|
+
if (tool === "claude-code") {
|
|
12179
|
+
return `In Claude Code, run \`/mcp\` and approve the "RepoWise MCP for ${repoName}" server.`;
|
|
12180
|
+
}
|
|
12181
|
+
return `Reload your AI tool and approve the "RepoWise MCP for ${repoName}" server when prompted.`;
|
|
12182
|
+
}
|
|
12183
|
+
async function mcpStatusForRepo(opts) {
|
|
12184
|
+
const repoName = basename4(opts.repoRoot);
|
|
12185
|
+
const out = [];
|
|
12186
|
+
for (const tool of opts.aiTools) {
|
|
12187
|
+
const target = mcpConfigTargetForTool(tool, { repoRoot: opts.repoRoot, home: opts.home });
|
|
12188
|
+
if (!target) continue;
|
|
12189
|
+
const state = await mcpConfigState(target);
|
|
12190
|
+
if (state === "absent") continue;
|
|
12191
|
+
const configured = state === "configured";
|
|
12192
|
+
out.push({ tool, configured, hint: configured ? null : mcpActivationHint(tool, repoName) });
|
|
12193
|
+
}
|
|
12194
|
+
return out;
|
|
12195
|
+
}
|
|
12196
|
+
|
|
12054
12197
|
// src/lib/gitignore.ts
|
|
12055
12198
|
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
|
|
12056
|
-
import { join as
|
|
12199
|
+
import { join as join46 } from "path";
|
|
12057
12200
|
function ensureGitignore(repoRoot, entry) {
|
|
12058
|
-
const gitignorePath =
|
|
12201
|
+
const gitignorePath = join46(repoRoot, ".gitignore");
|
|
12059
12202
|
if (existsSync2(gitignorePath)) {
|
|
12060
12203
|
const content = readFileSync2(gitignorePath, "utf-8");
|
|
12061
12204
|
const lines = content.split("\n").map((l) => l.trim());
|
|
@@ -12072,7 +12215,7 @@ function ensureGitignore(repoRoot, entry) {
|
|
|
12072
12215
|
// src/lib/graph-cache.ts
|
|
12073
12216
|
init_config_dir();
|
|
12074
12217
|
import { mkdirSync, writeFileSync as writeFileSync2, renameSync, unlinkSync } from "fs";
|
|
12075
|
-
import { dirname as dirname18, join as
|
|
12218
|
+
import { dirname as dirname18, join as join47 } from "path";
|
|
12076
12219
|
var SAFE_REPO_ID = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
12077
12220
|
function assertSafeRepoId2(repoId) {
|
|
12078
12221
|
if (!repoId || typeof repoId !== "string" || !SAFE_REPO_ID.test(repoId) || repoId === "." || repoId === ".." || repoId.startsWith(".")) {
|
|
@@ -12081,7 +12224,7 @@ function assertSafeRepoId2(repoId) {
|
|
|
12081
12224
|
}
|
|
12082
12225
|
function graphCachePath(repoId) {
|
|
12083
12226
|
assertSafeRepoId2(repoId);
|
|
12084
|
-
return
|
|
12227
|
+
return join47(getConfigDir(), "graphs", `${repoId}.json`);
|
|
12085
12228
|
}
|
|
12086
12229
|
function isUsableGraph(parsed) {
|
|
12087
12230
|
if (typeof parsed !== "object" || parsed === null) return false;
|
|
@@ -12697,17 +12840,27 @@ var ProgressRenderer = class {
|
|
|
12697
12840
|
if (generating) {
|
|
12698
12841
|
const genBaseName = generating.fileName.split("/").pop() ?? generating.fileName;
|
|
12699
12842
|
const isCore = CORE_FILES.has(genBaseName);
|
|
12700
|
-
const
|
|
12843
|
+
const sectionFiles2 = gp.fileStatuses.filter((f) => {
|
|
12701
12844
|
const bn = f.fileName.split("/").pop() ?? f.fileName;
|
|
12702
12845
|
return isCore ? CORE_FILES.has(bn) : !CORE_FILES.has(bn);
|
|
12703
12846
|
});
|
|
12704
|
-
const sectionCompleted =
|
|
12705
|
-
return `${generating.fileName} (${sectionCompleted}/${
|
|
12847
|
+
const sectionCompleted = sectionFiles2.filter((f) => f.status === "completed").length;
|
|
12848
|
+
return `${generating.fileName} (${sectionCompleted}/${sectionFiles2.length}) ${chalk4.dim(`(${overallPct}%)`)}`;
|
|
12706
12849
|
}
|
|
12707
12850
|
const allDone = gp.fileStatuses.every((f) => f.status === "completed");
|
|
12708
12851
|
if (allDone) {
|
|
12709
12852
|
return `${stepLabel}... ${chalk4.dim(`(${overallPct}%)`)}`;
|
|
12710
12853
|
}
|
|
12854
|
+
const baseNameOf = (f) => f.fileName.split("/").pop() ?? f.fileName;
|
|
12855
|
+
const coreFiles = gp.fileStatuses.filter((f) => CORE_FILES.has(baseNameOf(f)));
|
|
12856
|
+
const optionalFiles = gp.fileStatuses.filter((f) => !CORE_FILES.has(baseNameOf(f)));
|
|
12857
|
+
const coreDone = coreFiles.length > 0 && coreFiles.every((f) => f.status === "completed");
|
|
12858
|
+
const sectionFiles = coreDone && optionalFiles.length > 0 ? optionalFiles : coreFiles;
|
|
12859
|
+
if (sectionFiles.length > 0) {
|
|
12860
|
+
const sectionCompleted = sectionFiles.filter((f) => f.status === "completed").length;
|
|
12861
|
+
const name = gp.currentFileName || stepLabel;
|
|
12862
|
+
return `${name} (${sectionCompleted}/${sectionFiles.length}) ${chalk4.dim(`(${overallPct}%)`)}`;
|
|
12863
|
+
}
|
|
12711
12864
|
}
|
|
12712
12865
|
}
|
|
12713
12866
|
return `${stepLabel}... ${chalk4.dim(`(${overallPct}%)`)}`;
|
|
@@ -12798,8 +12951,8 @@ async function promptDepInstallConsent(missing, opts) {
|
|
|
12798
12951
|
import chalk6 from "chalk";
|
|
12799
12952
|
|
|
12800
12953
|
// src/lib/dep-installer.ts
|
|
12801
|
-
import { promises as
|
|
12802
|
-
import { join as
|
|
12954
|
+
import { promises as fs22 } from "fs";
|
|
12955
|
+
import { join as join48 } from "path";
|
|
12803
12956
|
var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
12804
12957
|
"typescript",
|
|
12805
12958
|
"javascript",
|
|
@@ -12809,14 +12962,14 @@ var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
|
12809
12962
|
]);
|
|
12810
12963
|
var exists = async (p) => {
|
|
12811
12964
|
try {
|
|
12812
|
-
await
|
|
12965
|
+
await fs22.access(p);
|
|
12813
12966
|
return true;
|
|
12814
12967
|
} catch {
|
|
12815
12968
|
return false;
|
|
12816
12969
|
}
|
|
12817
12970
|
};
|
|
12818
12971
|
async function fileExists16(repoRoot, name) {
|
|
12819
|
-
return exists(
|
|
12972
|
+
return exists(join48(repoRoot, name));
|
|
12820
12973
|
}
|
|
12821
12974
|
async function detectNodePackageManager(repoRoot) {
|
|
12822
12975
|
if (await fileExists16(repoRoot, "pnpm-lock.yaml")) {
|
|
@@ -12893,13 +13046,13 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
|
|
|
12893
13046
|
// src/lib/dep-installer-runner.ts
|
|
12894
13047
|
import { spawn as spawn11 } from "child_process";
|
|
12895
13048
|
import { createWriteStream as createWriteStream3 } from "fs";
|
|
12896
|
-
import { promises as
|
|
12897
|
-
import { join as
|
|
13049
|
+
import { promises as fs23 } from "fs";
|
|
13050
|
+
import { join as join49 } from "path";
|
|
12898
13051
|
var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12899
13052
|
async function runMissingDepInstalls(opts) {
|
|
12900
13053
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
12901
|
-
const logPath2 =
|
|
12902
|
-
await
|
|
13054
|
+
const logPath2 = join49(getConfigDir2(), `install-log.${safeRepoId}.txt`);
|
|
13055
|
+
await fs23.mkdir(getConfigDir2(), { recursive: true });
|
|
12903
13056
|
const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
|
|
12904
13057
|
stream.on("error", () => {
|
|
12905
13058
|
});
|
|
@@ -12945,7 +13098,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
|
|
|
12945
13098
|
}
|
|
12946
13099
|
async function runPipFlow(repoRoot, stream, timeoutMs) {
|
|
12947
13100
|
await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
|
|
12948
|
-
const venvPip = process.platform === "win32" ?
|
|
13101
|
+
const venvPip = process.platform === "win32" ? join49(".venv", "Scripts", "pip.exe") : join49(".venv", "bin", "pip");
|
|
12949
13102
|
await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
|
|
12950
13103
|
}
|
|
12951
13104
|
function runSimple(cmd, repoRoot, stream, timeoutMs) {
|
|
@@ -13283,9 +13436,7 @@ async function create() {
|
|
|
13283
13436
|
}
|
|
13284
13437
|
if (tools.length === 0 && !hasOther) {
|
|
13285
13438
|
console.log(
|
|
13286
|
-
chalk8.yellow(
|
|
13287
|
-
"\nNo AI tools selected. You can configure them later with `repowise config`."
|
|
13288
|
-
)
|
|
13439
|
+
chalk8.yellow("\nNo AI tools selected. You can set them up later with `repowise tools`.")
|
|
13289
13440
|
);
|
|
13290
13441
|
}
|
|
13291
13442
|
if (repoRoot) {
|
|
@@ -13518,7 +13669,7 @@ async function create() {
|
|
|
13518
13669
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
13519
13670
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
13520
13671
|
if (files.length > 0) {
|
|
13521
|
-
const contextDir =
|
|
13672
|
+
const contextDir = join50(repoRoot, DEFAULT_CONTEXT_FOLDER);
|
|
13522
13673
|
mkdirSync2(contextDir, { recursive: true });
|
|
13523
13674
|
let downloadedCount = 0;
|
|
13524
13675
|
let failedCount = 0;
|
|
@@ -13532,7 +13683,7 @@ async function create() {
|
|
|
13532
13683
|
const response = await fetch(presignedUrl);
|
|
13533
13684
|
if (response.ok) {
|
|
13534
13685
|
const content = await response.text();
|
|
13535
|
-
const filePath =
|
|
13686
|
+
const filePath = join50(contextDir, file.fileName);
|
|
13536
13687
|
mkdirSync2(dirname19(filePath), { recursive: true });
|
|
13537
13688
|
writeFileSync3(filePath, content, "utf-8");
|
|
13538
13689
|
downloadedCount++;
|
|
@@ -13616,51 +13767,17 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13616
13767
|
}
|
|
13617
13768
|
if (repoRoot) {
|
|
13618
13769
|
spinner.start("Configuring AI tools...");
|
|
13619
|
-
const results =
|
|
13620
|
-
|
|
13621
|
-
|
|
13622
|
-
|
|
13623
|
-
|
|
13624
|
-
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
repoRoot,
|
|
13629
|
-
tool,
|
|
13630
|
-
repoName,
|
|
13631
|
-
contextFolder,
|
|
13632
|
-
contextFiles,
|
|
13633
|
-
toolVariant
|
|
13634
|
-
);
|
|
13635
|
-
}
|
|
13636
|
-
const { created: wasCreated } = await updateToolConfig(
|
|
13637
|
-
repoRoot,
|
|
13638
|
-
tool,
|
|
13639
|
-
repoName,
|
|
13640
|
-
contextFolder,
|
|
13641
|
-
contextFiles,
|
|
13642
|
-
toolVariant
|
|
13643
|
-
);
|
|
13644
|
-
const action = wasCreated ? "Created" : "Updated";
|
|
13645
|
-
results.push(` ${action} ${config2.filePath}`);
|
|
13646
|
-
}
|
|
13647
|
-
if (!written.has("AGENTS.md")) {
|
|
13648
|
-
const { created: wasCreated } = await updateToolConfig(
|
|
13649
|
-
repoRoot,
|
|
13650
|
-
"codex",
|
|
13651
|
-
repoName,
|
|
13652
|
-
contextFolder,
|
|
13653
|
-
contextFiles,
|
|
13654
|
-
toolVariant
|
|
13655
|
-
);
|
|
13656
|
-
results.push(` ${wasCreated ? "Created" : "Updated"} AGENTS.md`);
|
|
13657
|
-
}
|
|
13658
|
-
if (tools.includes("claude-code")) {
|
|
13659
|
-
const { relPath } = await writeClaudeHooksToRepo(repoRoot, contextFolder, toolVariant);
|
|
13660
|
-
results.push(` Configured ${relPath} (RepoWise-first + SubagentStart hooks, local-only)`);
|
|
13661
|
-
}
|
|
13770
|
+
const results = await writeToolConfigsForRepo({
|
|
13771
|
+
repoRoot,
|
|
13772
|
+
tools,
|
|
13773
|
+
repoName,
|
|
13774
|
+
contextFolder,
|
|
13775
|
+
contextFiles,
|
|
13776
|
+
variant: graphOnly ? "graph" : "full",
|
|
13777
|
+
migrateLegacy: true
|
|
13778
|
+
});
|
|
13662
13779
|
spinner.succeed("AI tools configured");
|
|
13663
|
-
console.log(chalk8.dim(results.join("\n")));
|
|
13780
|
+
console.log(chalk8.dim(results.map((r) => ` ${r}`).join("\n")));
|
|
13664
13781
|
}
|
|
13665
13782
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
13666
13783
|
const updatedRepos = [];
|
|
@@ -13769,6 +13886,11 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13769
13886
|
console.log(
|
|
13770
13887
|
` ${chalk8.cyan("\u2022")} Open Claude Code / Cursor and ask: "What does this repo do?"`
|
|
13771
13888
|
);
|
|
13889
|
+
if (tools.some((t) => MCP_WRITER_TOOLS.has(t))) {
|
|
13890
|
+
console.log(
|
|
13891
|
+
` ${chalk8.cyan("\u2022")} If your AI tool asks to approve the "RepoWise MCP" server, approve it (in Claude Code, run ${chalk8.cyan("/mcp")}) \u2014 it can take a minute to appear.`
|
|
13892
|
+
);
|
|
13893
|
+
}
|
|
13772
13894
|
console.log(
|
|
13773
13895
|
` ${chalk8.cyan("\u2022")} Head to the dashboard \u2192 "Complete Onboarding" to explore quality scores and gaps.`
|
|
13774
13896
|
);
|
|
@@ -13783,7 +13905,7 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13783
13905
|
|
|
13784
13906
|
// src/commands/member.ts
|
|
13785
13907
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
13786
|
-
import { dirname as dirname20, join as
|
|
13908
|
+
import { dirname as dirname20, join as join51, resolve, sep } from "path";
|
|
13787
13909
|
import chalk9 from "chalk";
|
|
13788
13910
|
import ora2 from "ora";
|
|
13789
13911
|
var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
|
|
@@ -13937,7 +14059,7 @@ async function member() {
|
|
|
13937
14059
|
spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
|
|
13938
14060
|
const { tools } = await selectAiTools();
|
|
13939
14061
|
spinner.start("Downloading context files...");
|
|
13940
|
-
const contextDir =
|
|
14062
|
+
const contextDir = join51(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
13941
14063
|
mkdirSync3(contextDir, { recursive: true });
|
|
13942
14064
|
let downloadedCount = 0;
|
|
13943
14065
|
let failedCount = 0;
|
|
@@ -13982,35 +14104,14 @@ async function member() {
|
|
|
13982
14104
|
{
|
|
13983
14105
|
spinner.start("Configuring AI tools...");
|
|
13984
14106
|
const contextFiles = await scanLocalContextFiles(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
13985
|
-
const configured =
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
tool,
|
|
13994
|
-
repoName,
|
|
13995
|
-
DEFAULT_CONTEXT_FOLDER2,
|
|
13996
|
-
contextFiles
|
|
13997
|
-
);
|
|
13998
|
-
configured.push(`${created ? "Created" : "Updated"} ${config2.filePath}`);
|
|
13999
|
-
}
|
|
14000
|
-
if (!written.has("AGENTS.md")) {
|
|
14001
|
-
const { created } = await updateToolConfig(
|
|
14002
|
-
repoRoot,
|
|
14003
|
-
"codex",
|
|
14004
|
-
repoName,
|
|
14005
|
-
DEFAULT_CONTEXT_FOLDER2,
|
|
14006
|
-
contextFiles
|
|
14007
|
-
);
|
|
14008
|
-
configured.push(`${created ? "Created" : "Updated"} AGENTS.md`);
|
|
14009
|
-
}
|
|
14010
|
-
if (tools.includes("claude-code")) {
|
|
14011
|
-
const { relPath } = await writeClaudeHooksToRepo(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
14012
|
-
configured.push(`Configured ${relPath} (RepoWise-first + SubagentStart hooks, local-only)`);
|
|
14013
|
-
}
|
|
14107
|
+
const configured = await writeToolConfigsForRepo({
|
|
14108
|
+
repoRoot,
|
|
14109
|
+
tools,
|
|
14110
|
+
repoName,
|
|
14111
|
+
contextFolder: DEFAULT_CONTEXT_FOLDER2,
|
|
14112
|
+
contextFiles
|
|
14113
|
+
// member historically passed no variant and did not migrate legacy paths.
|
|
14114
|
+
});
|
|
14014
14115
|
spinner.succeed("AI tools configured");
|
|
14015
14116
|
for (const msg of configured) {
|
|
14016
14117
|
console.log(chalk9.dim(` ${msg}`));
|
|
@@ -14131,19 +14232,20 @@ async function member() {
|
|
|
14131
14232
|
}
|
|
14132
14233
|
|
|
14133
14234
|
// src/commands/login.ts
|
|
14235
|
+
import { homedir as homedir9 } from "os";
|
|
14134
14236
|
import chalk10 from "chalk";
|
|
14135
14237
|
import ora3 from "ora";
|
|
14136
14238
|
|
|
14137
14239
|
// src/lib/tenant-graph-purge.ts
|
|
14138
|
-
import { promises as
|
|
14240
|
+
import { promises as fs24 } from "fs";
|
|
14139
14241
|
import { homedir as homedir8 } from "os";
|
|
14140
|
-
import { join as
|
|
14242
|
+
import { join as join52 } from "path";
|
|
14141
14243
|
async function purgeForeignGraphs(validRepoIds, home = homedir8()) {
|
|
14142
|
-
const graphsDir =
|
|
14244
|
+
const graphsDir = join52(home, ".repowise", "graphs");
|
|
14143
14245
|
const result = { kept: [], removed: [] };
|
|
14144
14246
|
let entries;
|
|
14145
14247
|
try {
|
|
14146
|
-
entries = await
|
|
14248
|
+
entries = await fs24.readdir(graphsDir);
|
|
14147
14249
|
} catch (err) {
|
|
14148
14250
|
if (err.code === "ENOENT") return result;
|
|
14149
14251
|
throw err;
|
|
@@ -14157,15 +14259,15 @@ async function purgeForeignGraphs(validRepoIds, home = homedir8()) {
|
|
|
14157
14259
|
result.kept.push(entry);
|
|
14158
14260
|
continue;
|
|
14159
14261
|
}
|
|
14160
|
-
const path =
|
|
14262
|
+
const path = join52(graphsDir, entry);
|
|
14161
14263
|
try {
|
|
14162
|
-
const stat8 = await
|
|
14264
|
+
const stat8 = await fs24.lstat(path);
|
|
14163
14265
|
if (stat8.isSymbolicLink()) {
|
|
14164
|
-
await
|
|
14266
|
+
await fs24.unlink(path);
|
|
14165
14267
|
result.removed.push(entry);
|
|
14166
14268
|
continue;
|
|
14167
14269
|
}
|
|
14168
|
-
await
|
|
14270
|
+
await fs24.rm(path, { recursive: true, force: true });
|
|
14169
14271
|
result.removed.push(entry);
|
|
14170
14272
|
} catch {
|
|
14171
14273
|
}
|
|
@@ -14229,6 +14331,23 @@ Waiting for authentication...`);
|
|
|
14229
14331
|
}
|
|
14230
14332
|
} catch {
|
|
14231
14333
|
}
|
|
14334
|
+
try {
|
|
14335
|
+
const repoRoot = detectRepoRoot();
|
|
14336
|
+
const cfg = await getConfig();
|
|
14337
|
+
const registered = (cfg.repos ?? []).some((r) => r.localPath === repoRoot);
|
|
14338
|
+
const tools = cfg.aiTools ?? [];
|
|
14339
|
+
if (registered && tools.length > 0) {
|
|
14340
|
+
const pending = (await mcpStatusForRepo({ repoRoot, home: homedir9(), aiTools: tools })).filter((s) => !s.configured);
|
|
14341
|
+
if (pending.length > 0) {
|
|
14342
|
+
console.log("");
|
|
14343
|
+
console.log(chalk10.dim(" To finish enabling RepoWise in your AI tools:"));
|
|
14344
|
+
for (const p of pending) {
|
|
14345
|
+
if (p.hint) console.log(chalk10.dim(` \u2022 ${p.hint}`));
|
|
14346
|
+
}
|
|
14347
|
+
}
|
|
14348
|
+
}
|
|
14349
|
+
} catch {
|
|
14350
|
+
}
|
|
14232
14351
|
} catch (err) {
|
|
14233
14352
|
const message = err instanceof Error ? err.message : "Login failed";
|
|
14234
14353
|
spinner.fail(chalk10.red(message));
|
|
@@ -14250,11 +14369,21 @@ async function logout() {
|
|
|
14250
14369
|
|
|
14251
14370
|
// src/commands/status.ts
|
|
14252
14371
|
import { readFile as readFile16 } from "fs/promises";
|
|
14253
|
-
import { basename as
|
|
14372
|
+
import { basename as basename5, join as join53 } from "path";
|
|
14373
|
+
import { homedir as homedir10 } from "os";
|
|
14374
|
+
|
|
14375
|
+
// ../../packages/shared/dist/lib/creds.js
|
|
14376
|
+
function isCredsHardExpired(creds) {
|
|
14377
|
+
if (!creds || typeof creds.expiresAt !== "number")
|
|
14378
|
+
return true;
|
|
14379
|
+
return Date.now() >= creds.expiresAt;
|
|
14380
|
+
}
|
|
14381
|
+
|
|
14382
|
+
// src/commands/status.ts
|
|
14254
14383
|
async function status() {
|
|
14255
14384
|
const configDir = getConfigDir2();
|
|
14256
|
-
const STATE_PATH =
|
|
14257
|
-
const CONFIG_PATH =
|
|
14385
|
+
const STATE_PATH = join53(configDir, "listener-state.json");
|
|
14386
|
+
const CONFIG_PATH = join53(configDir, "config.json");
|
|
14258
14387
|
let state = null;
|
|
14259
14388
|
try {
|
|
14260
14389
|
const data = await readFile16(STATE_PATH, "utf-8");
|
|
@@ -14276,33 +14405,74 @@ async function status() {
|
|
|
14276
14405
|
} else {
|
|
14277
14406
|
console.log("Auto-start: disabled");
|
|
14278
14407
|
}
|
|
14408
|
+
let creds = null;
|
|
14409
|
+
try {
|
|
14410
|
+
creds = await getStoredCredentials2();
|
|
14411
|
+
} catch {
|
|
14412
|
+
}
|
|
14413
|
+
if (isCredsHardExpired(creds)) {
|
|
14414
|
+
console.log("Authentication: not logged in \u2014 run `repowise login`");
|
|
14415
|
+
} else {
|
|
14416
|
+
let email = null;
|
|
14417
|
+
try {
|
|
14418
|
+
const decoded = creds?.idToken ? decodeIdToken(creds.idToken).email : null;
|
|
14419
|
+
email = decoded && decoded !== "unknown" ? decoded : null;
|
|
14420
|
+
} catch {
|
|
14421
|
+
}
|
|
14422
|
+
console.log(`Authentication: logged in${email ? ` as ${email}` : ""}`);
|
|
14423
|
+
}
|
|
14279
14424
|
console.log("");
|
|
14280
14425
|
if (!state || Object.keys(state.repos).length === 0) {
|
|
14281
14426
|
console.log("No sync history. Run `repowise listen` to start syncing.");
|
|
14282
14427
|
return;
|
|
14283
14428
|
}
|
|
14284
14429
|
const repoNames = /* @__PURE__ */ new Map();
|
|
14430
|
+
const repoPaths = /* @__PURE__ */ new Map();
|
|
14431
|
+
let aiTools = [];
|
|
14285
14432
|
try {
|
|
14286
14433
|
const configData = await readFile16(CONFIG_PATH, "utf-8");
|
|
14287
14434
|
const config2 = JSON.parse(configData);
|
|
14288
14435
|
for (const repo of config2.repos ?? []) {
|
|
14289
|
-
repoNames.set(repo.repoId,
|
|
14436
|
+
repoNames.set(repo.repoId, basename5(repo.localPath));
|
|
14437
|
+
repoPaths.set(repo.repoId, repo.localPath);
|
|
14290
14438
|
}
|
|
14439
|
+
aiTools = config2.aiTools ?? [];
|
|
14291
14440
|
} catch {
|
|
14292
14441
|
}
|
|
14293
14442
|
console.log("Watched Repos:");
|
|
14443
|
+
const home = homedir10();
|
|
14294
14444
|
for (const [repoId, repoState] of Object.entries(state.repos)) {
|
|
14295
14445
|
const name = repoNames.get(repoId);
|
|
14296
14446
|
const label = name ? `${name} (${repoId.slice(0, 8)})` : repoId;
|
|
14297
14447
|
const syncTime = repoState.lastSyncTimestamp ? new Date(repoState.lastSyncTimestamp).toLocaleString() : "never";
|
|
14298
14448
|
const commit = repoState.lastSyncCommitSha ? repoState.lastSyncCommitSha.slice(0, 7) : "none";
|
|
14299
14449
|
console.log(` ${label}: last sync ${syncTime} (commit: ${commit})`);
|
|
14450
|
+
const localPath = repoPaths.get(repoId);
|
|
14451
|
+
if (localPath && aiTools.length > 0) {
|
|
14452
|
+
try {
|
|
14453
|
+
const statuses = await mcpStatusForRepo({ repoRoot: localPath, home, aiTools });
|
|
14454
|
+
if (statuses.length > 0) {
|
|
14455
|
+
const pending = statuses.filter((s) => !s.configured);
|
|
14456
|
+
if (pending.length === 0) {
|
|
14457
|
+
console.log(` MCP: active in all ${statuses.length} tool(s)`);
|
|
14458
|
+
} else {
|
|
14459
|
+
console.log(
|
|
14460
|
+
` MCP: ${statuses.length - pending.length}/${statuses.length} tool(s) active \u2014 to finish:`
|
|
14461
|
+
);
|
|
14462
|
+
for (const p of pending) {
|
|
14463
|
+
if (p.hint) console.log(` \u2022 ${p.hint}`);
|
|
14464
|
+
}
|
|
14465
|
+
}
|
|
14466
|
+
}
|
|
14467
|
+
} catch {
|
|
14468
|
+
}
|
|
14469
|
+
}
|
|
14300
14470
|
}
|
|
14301
14471
|
}
|
|
14302
14472
|
|
|
14303
14473
|
// src/commands/sync.ts
|
|
14304
14474
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
14305
|
-
import { dirname as dirname21, join as
|
|
14475
|
+
import { dirname as dirname21, join as join54 } from "path";
|
|
14306
14476
|
import chalk12 from "chalk";
|
|
14307
14477
|
import ora4 from "ora";
|
|
14308
14478
|
var POLL_INTERVAL_MS2 = 3e3;
|
|
@@ -14451,7 +14621,7 @@ async function sync() {
|
|
|
14451
14621
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
14452
14622
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
14453
14623
|
if (files.length > 0) {
|
|
14454
|
-
const contextDir =
|
|
14624
|
+
const contextDir = join54(repoRoot, DEFAULT_CONTEXT_FOLDER3);
|
|
14455
14625
|
mkdirSync4(contextDir, { recursive: true });
|
|
14456
14626
|
let downloadedCount = 0;
|
|
14457
14627
|
let failedCount = 0;
|
|
@@ -14465,7 +14635,7 @@ async function sync() {
|
|
|
14465
14635
|
const response = await fetch(presignedUrl);
|
|
14466
14636
|
if (response.ok) {
|
|
14467
14637
|
const content = await response.text();
|
|
14468
|
-
const filePath =
|
|
14638
|
+
const filePath = join54(contextDir, file.fileName);
|
|
14469
14639
|
mkdirSync4(dirname21(filePath), { recursive: true });
|
|
14470
14640
|
writeFileSync5(filePath, content, "utf-8");
|
|
14471
14641
|
downloadedCount++;
|
|
@@ -14718,10 +14888,158 @@ async function config() {
|
|
|
14718
14888
|
}
|
|
14719
14889
|
}
|
|
14720
14890
|
|
|
14891
|
+
// src/commands/tools.ts
|
|
14892
|
+
import { basename as basename6 } from "path";
|
|
14893
|
+
import chalk14 from "chalk";
|
|
14894
|
+
import ora6 from "ora";
|
|
14895
|
+
var DEFAULT_CONTEXT_FOLDER4 = "repowise-context";
|
|
14896
|
+
var VALID_TOOLS = Object.keys(AI_TOOL_CONFIG);
|
|
14897
|
+
async function resolveRepoOrExit() {
|
|
14898
|
+
let creds = null;
|
|
14899
|
+
try {
|
|
14900
|
+
creds = await getValidCredentials2();
|
|
14901
|
+
} catch {
|
|
14902
|
+
creds = null;
|
|
14903
|
+
}
|
|
14904
|
+
if (!creds) {
|
|
14905
|
+
console.error(chalk14.red("Not logged in. Run `repowise login` first."));
|
|
14906
|
+
process.exitCode = 1;
|
|
14907
|
+
return null;
|
|
14908
|
+
}
|
|
14909
|
+
let repoRoot;
|
|
14910
|
+
try {
|
|
14911
|
+
repoRoot = detectRepoRoot();
|
|
14912
|
+
} catch {
|
|
14913
|
+
console.error(chalk14.red("Not inside a git repository \u2014 `cd` into your repo first."));
|
|
14914
|
+
process.exitCode = 1;
|
|
14915
|
+
return null;
|
|
14916
|
+
}
|
|
14917
|
+
const config2 = await getConfig();
|
|
14918
|
+
const registered = (config2.repos ?? []).some((r) => r.localPath === repoRoot);
|
|
14919
|
+
if (!registered) {
|
|
14920
|
+
console.error(
|
|
14921
|
+
chalk14.red("This repo isn't set up with RepoWise yet. Run `repowise create` first.")
|
|
14922
|
+
);
|
|
14923
|
+
process.exitCode = 1;
|
|
14924
|
+
return null;
|
|
14925
|
+
}
|
|
14926
|
+
return {
|
|
14927
|
+
repoRoot,
|
|
14928
|
+
repoName: detectRepoName(repoRoot),
|
|
14929
|
+
current: config2.aiTools ?? [],
|
|
14930
|
+
contextFolder: config2.contextFolder ?? DEFAULT_CONTEXT_FOLDER4,
|
|
14931
|
+
variant: config2.graphOnly ? "graph" : "full"
|
|
14932
|
+
};
|
|
14933
|
+
}
|
|
14934
|
+
async function applyToolSelection(ctx, next) {
|
|
14935
|
+
const added = next.filter((t) => !ctx.current.includes(t));
|
|
14936
|
+
const spinner = ora6("Configuring AI tools...").start();
|
|
14937
|
+
const contextFiles = await scanLocalContextFiles(ctx.repoRoot, ctx.contextFolder);
|
|
14938
|
+
const results = await writeToolConfigsForRepo({
|
|
14939
|
+
repoRoot: ctx.repoRoot,
|
|
14940
|
+
tools: next,
|
|
14941
|
+
repoName: ctx.repoName,
|
|
14942
|
+
contextFolder: ctx.contextFolder,
|
|
14943
|
+
contextFiles,
|
|
14944
|
+
variant: ctx.variant,
|
|
14945
|
+
migrateLegacy: true
|
|
14946
|
+
});
|
|
14947
|
+
await mergeAndSaveConfig({ aiTools: next });
|
|
14948
|
+
spinner.succeed("AI tools configured");
|
|
14949
|
+
console.log(chalk14.dim(results.map((r) => ` ${r}`).join("\n")));
|
|
14950
|
+
try {
|
|
14951
|
+
await ensureListenerRunning();
|
|
14952
|
+
} catch {
|
|
14953
|
+
}
|
|
14954
|
+
const serverRepoName = basename6(ctx.repoRoot);
|
|
14955
|
+
const newMcp = added.filter((t) => MCP_WRITER_TOOLS.has(t));
|
|
14956
|
+
if (newMcp.length > 0) {
|
|
14957
|
+
console.log("");
|
|
14958
|
+
console.log(
|
|
14959
|
+
chalk14.dim(
|
|
14960
|
+
" The listener will wire these into your AI tools' MCP within a few seconds, then:"
|
|
14961
|
+
)
|
|
14962
|
+
);
|
|
14963
|
+
for (const t of newMcp) {
|
|
14964
|
+
const hint = mcpActivationHint(t, serverRepoName);
|
|
14965
|
+
if (hint) console.log(chalk14.dim(` \u2022 ${hint}`));
|
|
14966
|
+
}
|
|
14967
|
+
}
|
|
14968
|
+
}
|
|
14969
|
+
async function pickUnion(ctx) {
|
|
14970
|
+
const { tools: picked, hasOther } = await selectAiTools({ defaults: ctx.current });
|
|
14971
|
+
const removed = ctx.current.filter((t) => !picked.includes(t));
|
|
14972
|
+
if (removed.length > 0) {
|
|
14973
|
+
console.log(
|
|
14974
|
+
chalk14.yellow(`Note: removing tools isn't supported yet \u2014 keeping ${removed.join(", ")}.`)
|
|
14975
|
+
);
|
|
14976
|
+
}
|
|
14977
|
+
return { next: Array.from(/* @__PURE__ */ new Set([...ctx.current, ...picked])), hasOther };
|
|
14978
|
+
}
|
|
14979
|
+
function reportNothingNew(hasOther) {
|
|
14980
|
+
if (hasOther) {
|
|
14981
|
+
console.log(
|
|
14982
|
+
chalk14.dim(
|
|
14983
|
+
"For tools not listed, the instruction files work with any tool that reads the filesystem.\nTo request full support for a new AI tool, email support@repowise.ai"
|
|
14984
|
+
)
|
|
14985
|
+
);
|
|
14986
|
+
} else {
|
|
14987
|
+
console.log(chalk14.dim("No new tools added."));
|
|
14988
|
+
}
|
|
14989
|
+
}
|
|
14990
|
+
async function toolsPick() {
|
|
14991
|
+
const ctx = await resolveRepoOrExit();
|
|
14992
|
+
if (!ctx) return;
|
|
14993
|
+
const { next, hasOther } = await pickUnion(ctx);
|
|
14994
|
+
if (next.length === ctx.current.length) {
|
|
14995
|
+
reportNothingNew(hasOther);
|
|
14996
|
+
return;
|
|
14997
|
+
}
|
|
14998
|
+
await applyToolSelection(ctx, next);
|
|
14999
|
+
}
|
|
15000
|
+
async function toolsAdd(list) {
|
|
15001
|
+
const ctx = await resolveRepoOrExit();
|
|
15002
|
+
if (!ctx) return;
|
|
15003
|
+
let next;
|
|
15004
|
+
let hasOther = false;
|
|
15005
|
+
if (list.length === 0) {
|
|
15006
|
+
({ next, hasOther } = await pickUnion(ctx));
|
|
15007
|
+
} else {
|
|
15008
|
+
const invalid = list.filter((t) => !VALID_TOOLS.includes(t));
|
|
15009
|
+
if (invalid.length > 0) {
|
|
15010
|
+
console.error(chalk14.red(`Unknown tool(s): ${invalid.join(", ")}`));
|
|
15011
|
+
console.error(chalk14.dim(`Valid tools: ${VALID_TOOLS.join(", ")}`));
|
|
15012
|
+
process.exitCode = 1;
|
|
15013
|
+
return;
|
|
15014
|
+
}
|
|
15015
|
+
next = Array.from(/* @__PURE__ */ new Set([...ctx.current, ...list]));
|
|
15016
|
+
}
|
|
15017
|
+
if (next.length === ctx.current.length) {
|
|
15018
|
+
if (list.length === 0) reportNothingNew(hasOther);
|
|
15019
|
+
else console.log(chalk14.dim("Nothing new to add \u2014 those tools are already configured."));
|
|
15020
|
+
return;
|
|
15021
|
+
}
|
|
15022
|
+
await applyToolSelection(ctx, next);
|
|
15023
|
+
}
|
|
15024
|
+
async function toolsList() {
|
|
15025
|
+
const ctx = await resolveRepoOrExit();
|
|
15026
|
+
if (!ctx) return;
|
|
15027
|
+
if (ctx.current.length === 0) {
|
|
15028
|
+
console.log("No AI tools configured. Run `repowise tools` to add some.");
|
|
15029
|
+
return;
|
|
15030
|
+
}
|
|
15031
|
+
console.log(chalk14.bold("Configured AI tools:"));
|
|
15032
|
+
for (const t of ctx.current) {
|
|
15033
|
+
const label = AI_TOOL_CONFIG[t]?.label ?? t;
|
|
15034
|
+
const suffix = MCP_WRITER_TOOLS.has(t) ? "" : chalk14.dim(" (instruction files only)");
|
|
15035
|
+
console.log(` \u2022 ${label}${suffix}`);
|
|
15036
|
+
}
|
|
15037
|
+
}
|
|
15038
|
+
|
|
14721
15039
|
// src/commands/mcp-log.ts
|
|
14722
15040
|
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
14723
15041
|
import { mkdir as mkdir19, readFile as readFile17, stat as stat7, writeFile as writeFile18 } from "fs/promises";
|
|
14724
|
-
import { dirname as dirname22, join as
|
|
15042
|
+
import { dirname as dirname22, join as join55 } from "path";
|
|
14725
15043
|
var FLAG_FILE = "mcp-log.flag";
|
|
14726
15044
|
var LOG_FILE = "mcp-log.jsonl.enc";
|
|
14727
15045
|
var KEY_FILE = "mcp-log.key";
|
|
@@ -14729,10 +15047,10 @@ var ENDPOINT_FILE = "listener.endpoint";
|
|
|
14729
15047
|
var IV_BYTES2 = 12;
|
|
14730
15048
|
var TAG_BYTES2 = 16;
|
|
14731
15049
|
function flagPath() {
|
|
14732
|
-
return
|
|
15050
|
+
return join55(getConfigDir2(), FLAG_FILE);
|
|
14733
15051
|
}
|
|
14734
15052
|
function logPath() {
|
|
14735
|
-
return
|
|
15053
|
+
return join55(getConfigDir2(), LOG_FILE);
|
|
14736
15054
|
}
|
|
14737
15055
|
async function writeFlag(flag) {
|
|
14738
15056
|
const path = flagPath();
|
|
@@ -14773,14 +15091,14 @@ async function trySendConsentToServer() {
|
|
|
14773
15091
|
let apiUrl = null;
|
|
14774
15092
|
let token = null;
|
|
14775
15093
|
try {
|
|
14776
|
-
const body = await readFile17(
|
|
15094
|
+
const body = await readFile17(join55(getConfigDir2(), "config.json"), "utf-8");
|
|
14777
15095
|
const parsed = JSON.parse(body);
|
|
14778
15096
|
apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
|
|
14779
15097
|
} catch {
|
|
14780
15098
|
return false;
|
|
14781
15099
|
}
|
|
14782
15100
|
try {
|
|
14783
|
-
const body = await readFile17(
|
|
15101
|
+
const body = await readFile17(join55(getConfigDir2(), "credentials.json"), "utf-8");
|
|
14784
15102
|
const parsed = JSON.parse(body);
|
|
14785
15103
|
token = parsed.idToken ?? null;
|
|
14786
15104
|
} catch {
|
|
@@ -14850,7 +15168,7 @@ async function mcpLogStatus() {
|
|
|
14850
15168
|
process.stderr.write("Log size: no file yet\n");
|
|
14851
15169
|
}
|
|
14852
15170
|
try {
|
|
14853
|
-
const endpointBody = await readFile17(
|
|
15171
|
+
const endpointBody = await readFile17(join55(getConfigDir2(), ENDPOINT_FILE), "utf-8");
|
|
14854
15172
|
const match = /endpoint=([^\n]+)/.exec(endpointBody);
|
|
14855
15173
|
process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
|
|
14856
15174
|
`);
|
|
@@ -14881,7 +15199,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14881
15199
|
const key = await readKey();
|
|
14882
15200
|
if (!key) {
|
|
14883
15201
|
process.stderr.write(
|
|
14884
|
-
`No encryption key at ${
|
|
15202
|
+
`No encryption key at ${join55(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
|
|
14885
15203
|
`
|
|
14886
15204
|
);
|
|
14887
15205
|
return;
|
|
@@ -14957,7 +15275,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14957
15275
|
}
|
|
14958
15276
|
async function readKey() {
|
|
14959
15277
|
try {
|
|
14960
|
-
const body = await readFile17(
|
|
15278
|
+
const body = await readFile17(join55(getConfigDir2(), KEY_FILE), "utf-8");
|
|
14961
15279
|
const parsed = Buffer.from(body.trim(), "base64");
|
|
14962
15280
|
if (parsed.length !== 32) return null;
|
|
14963
15281
|
return parsed;
|
|
@@ -14997,11 +15315,11 @@ async function mcpLog(subcommand, flags = {}) {
|
|
|
14997
15315
|
}
|
|
14998
15316
|
|
|
14999
15317
|
// src/commands/query/_shared.ts
|
|
15000
|
-
import
|
|
15318
|
+
import chalk15 from "chalk";
|
|
15001
15319
|
|
|
15002
15320
|
// src/lib/graph-loader.ts
|
|
15003
|
-
import { promises as
|
|
15004
|
-
import { join as
|
|
15321
|
+
import { promises as fs25 } from "fs";
|
|
15322
|
+
import { join as join56, resolve as resolve2 } from "path";
|
|
15005
15323
|
import { gunzipSync } from "zlib";
|
|
15006
15324
|
var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
|
|
15007
15325
|
var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
|
|
@@ -15018,8 +15336,8 @@ var GraphNotFoundError = class extends Error {
|
|
|
15018
15336
|
var cache = /* @__PURE__ */ new Map();
|
|
15019
15337
|
async function loadGraph(repoRoot = process.cwd()) {
|
|
15020
15338
|
const root = resolve2(repoRoot);
|
|
15021
|
-
const gzPath =
|
|
15022
|
-
const plainPath =
|
|
15339
|
+
const gzPath = join56(root, GZIPPED_GRAPH_PATH);
|
|
15340
|
+
const plainPath = join56(root, RELATIVE_GRAPH_PATH);
|
|
15023
15341
|
const cached = cache.get(root);
|
|
15024
15342
|
if (cached) {
|
|
15025
15343
|
return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
|
|
@@ -15027,14 +15345,14 @@ async function loadGraph(repoRoot = process.cwd()) {
|
|
|
15027
15345
|
let graphPath = null;
|
|
15028
15346
|
let raw = null;
|
|
15029
15347
|
try {
|
|
15030
|
-
raw = await
|
|
15348
|
+
raw = await fs25.readFile(gzPath);
|
|
15031
15349
|
graphPath = gzPath;
|
|
15032
15350
|
} catch (err) {
|
|
15033
15351
|
if (err.code !== "ENOENT") throw err;
|
|
15034
15352
|
}
|
|
15035
15353
|
if (!raw) {
|
|
15036
15354
|
try {
|
|
15037
|
-
raw = await
|
|
15355
|
+
raw = await fs25.readFile(plainPath);
|
|
15038
15356
|
graphPath = plainPath;
|
|
15039
15357
|
} catch (err) {
|
|
15040
15358
|
if (err.code === "ENOENT") {
|
|
@@ -15237,7 +15555,7 @@ async function loadService() {
|
|
|
15237
15555
|
return createGraphQueryService(graph);
|
|
15238
15556
|
} catch (err) {
|
|
15239
15557
|
if (err instanceof GraphNotFoundError) {
|
|
15240
|
-
process.stderr.write(
|
|
15558
|
+
process.stderr.write(chalk15.red(`\u2717 ${err.message}
|
|
15241
15559
|
`));
|
|
15242
15560
|
process.exit(err.exitCode);
|
|
15243
15561
|
}
|
|
@@ -15433,14 +15751,14 @@ function registerQueryCommand(program2) {
|
|
|
15433
15751
|
}
|
|
15434
15752
|
|
|
15435
15753
|
// src/commands/uninstall.ts
|
|
15436
|
-
import { promises as
|
|
15437
|
-
import { homedir as
|
|
15438
|
-
import { join as
|
|
15439
|
-
import
|
|
15754
|
+
import { promises as fs29 } from "fs";
|
|
15755
|
+
import { homedir as homedir12 } from "os";
|
|
15756
|
+
import { join as join60 } from "path";
|
|
15757
|
+
import chalk16 from "chalk";
|
|
15440
15758
|
|
|
15441
15759
|
// src/lib/cleanup/marker-blocks.ts
|
|
15442
|
-
import { promises as
|
|
15443
|
-
import { join as
|
|
15760
|
+
import { promises as fs26 } from "fs";
|
|
15761
|
+
import { join as join57 } from "path";
|
|
15444
15762
|
var MARKER_START = "<!-- repowise-start -->";
|
|
15445
15763
|
var MARKER_END = "<!-- repowise-end -->";
|
|
15446
15764
|
var CONTEXT_FILES = [
|
|
@@ -15456,7 +15774,7 @@ var CONTEXT_FILES = [
|
|
|
15456
15774
|
async function stripMarkerBlock(filePath) {
|
|
15457
15775
|
let raw;
|
|
15458
15776
|
try {
|
|
15459
|
-
raw = await
|
|
15777
|
+
raw = await fs26.readFile(filePath, "utf-8");
|
|
15460
15778
|
} catch (err) {
|
|
15461
15779
|
if (err.code === "ENOENT")
|
|
15462
15780
|
return { path: filePath, status: "missing" };
|
|
@@ -15471,16 +15789,16 @@ async function stripMarkerBlock(filePath) {
|
|
|
15471
15789
|
const after = raw.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
|
|
15472
15790
|
const stripped = (before + (before && after ? "\n\n" : "") + after).trim();
|
|
15473
15791
|
if (stripped.length === 0) {
|
|
15474
|
-
await
|
|
15792
|
+
await fs26.unlink(filePath);
|
|
15475
15793
|
return { path: filePath, status: "deleted" };
|
|
15476
15794
|
}
|
|
15477
|
-
await
|
|
15795
|
+
await fs26.writeFile(filePath, stripped + "\n", "utf-8");
|
|
15478
15796
|
return { path: filePath, status: "stripped" };
|
|
15479
15797
|
}
|
|
15480
15798
|
async function stripAllMarkerBlocks(repoRoot) {
|
|
15481
15799
|
const out = [];
|
|
15482
15800
|
for (const relative of CONTEXT_FILES) {
|
|
15483
|
-
const full =
|
|
15801
|
+
const full = join57(repoRoot, relative);
|
|
15484
15802
|
const result = await stripMarkerBlock(full).catch((err) => ({
|
|
15485
15803
|
path: full,
|
|
15486
15804
|
status: "untouched",
|
|
@@ -15492,25 +15810,25 @@ async function stripAllMarkerBlocks(repoRoot) {
|
|
|
15492
15810
|
}
|
|
15493
15811
|
|
|
15494
15812
|
// src/lib/cleanup/mcp-configs.ts
|
|
15495
|
-
import { promises as
|
|
15496
|
-
import { join as
|
|
15813
|
+
import { promises as fs27 } from "fs";
|
|
15814
|
+
import { join as join58 } from "path";
|
|
15497
15815
|
function mcpConfigPaths(repoRoot, home) {
|
|
15498
15816
|
return [
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
|
|
15507
|
-
|
|
15817
|
+
join58(repoRoot, ".mcp.json"),
|
|
15818
|
+
join58(repoRoot, ".cursor", "mcp.json"),
|
|
15819
|
+
join58(repoRoot, ".vscode", "mcp.json"),
|
|
15820
|
+
join58(repoRoot, ".roo", "mcp.json"),
|
|
15821
|
+
join58(home, ".cline", "mcp.json"),
|
|
15822
|
+
join58(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
15823
|
+
join58(home, ".gemini", "settings.json"),
|
|
15824
|
+
join58(home, ".codex", "mcp.json"),
|
|
15825
|
+
join58(home, ".roo", "mcp.json")
|
|
15508
15826
|
];
|
|
15509
15827
|
}
|
|
15510
15828
|
async function removeRepowiseFromConfig(path, serverName) {
|
|
15511
15829
|
let raw;
|
|
15512
15830
|
try {
|
|
15513
|
-
raw = await
|
|
15831
|
+
raw = await fs27.readFile(path, "utf-8");
|
|
15514
15832
|
} catch (err) {
|
|
15515
15833
|
if (err.code === "ENOENT") return { path, status: "not-found" };
|
|
15516
15834
|
return { path, status: "error", error: err.message };
|
|
@@ -15530,7 +15848,7 @@ async function removeRepowiseFromConfig(path, serverName) {
|
|
|
15530
15848
|
} else {
|
|
15531
15849
|
next.mcpServers = servers;
|
|
15532
15850
|
}
|
|
15533
|
-
await
|
|
15851
|
+
await fs27.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
15534
15852
|
return { path, status: "removed" };
|
|
15535
15853
|
}
|
|
15536
15854
|
async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
@@ -15543,17 +15861,17 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
|
15543
15861
|
}
|
|
15544
15862
|
|
|
15545
15863
|
// src/lib/cleanup/local-state.ts
|
|
15546
|
-
import { promises as
|
|
15547
|
-
import { homedir as
|
|
15548
|
-
import { join as
|
|
15864
|
+
import { promises as fs28 } from "fs";
|
|
15865
|
+
import { homedir as homedir11 } from "os";
|
|
15866
|
+
import { join as join59, resolve as resolve3 } from "path";
|
|
15549
15867
|
async function clearLocalState(homeOverride) {
|
|
15550
|
-
const home = homeOverride ??
|
|
15551
|
-
const target = resolve3(
|
|
15868
|
+
const home = homeOverride ?? homedir11();
|
|
15869
|
+
const target = resolve3(join59(home, ".repowise"));
|
|
15552
15870
|
if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
|
|
15553
15871
|
return { path: target, status: "error", error: "refused: not under home" };
|
|
15554
15872
|
}
|
|
15555
15873
|
try {
|
|
15556
|
-
await
|
|
15874
|
+
await fs28.rm(target, { recursive: true, force: false });
|
|
15557
15875
|
return { path: target, status: "removed" };
|
|
15558
15876
|
} catch (err) {
|
|
15559
15877
|
if (err.code === "ENOENT")
|
|
@@ -15583,7 +15901,7 @@ async function stopAndUninstallService(uninstaller) {
|
|
|
15583
15901
|
// src/commands/uninstall.ts
|
|
15584
15902
|
async function uninstall2(opts = {}) {
|
|
15585
15903
|
const tier = opts.tier ?? "uninstall";
|
|
15586
|
-
const home = opts.home ??
|
|
15904
|
+
const home = opts.home ?? homedir12();
|
|
15587
15905
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
15588
15906
|
const loadRepoIds = opts.loadRepoIds ?? defaultLoadRepoIds;
|
|
15589
15907
|
const report = { tier, removed: [], preserved: [], skipped: [] };
|
|
@@ -15592,7 +15910,7 @@ async function uninstall2(opts = {}) {
|
|
|
15592
15910
|
else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
|
|
15593
15911
|
if (tier === "stop") return report;
|
|
15594
15912
|
try {
|
|
15595
|
-
await
|
|
15913
|
+
await fs29.unlink(join60(home, ".repowise", "credentials.json"));
|
|
15596
15914
|
report.removed.push("credentials");
|
|
15597
15915
|
} catch (err) {
|
|
15598
15916
|
if (err.code !== "ENOENT") {
|
|
@@ -15619,7 +15937,7 @@ async function uninstall2(opts = {}) {
|
|
|
15619
15937
|
const allPaths = mcpConfigPaths(repoRoot, home);
|
|
15620
15938
|
for (const p of allPaths) {
|
|
15621
15939
|
try {
|
|
15622
|
-
await
|
|
15940
|
+
await fs29.access(p);
|
|
15623
15941
|
} catch {
|
|
15624
15942
|
}
|
|
15625
15943
|
}
|
|
@@ -15631,7 +15949,7 @@ async function uninstall2(opts = {}) {
|
|
|
15631
15949
|
}
|
|
15632
15950
|
async function defaultLoadRepoIds(home) {
|
|
15633
15951
|
try {
|
|
15634
|
-
const raw = await
|
|
15952
|
+
const raw = await fs29.readFile(join60(home, ".repowise", "config.json"), "utf-8");
|
|
15635
15953
|
const parsed = JSON.parse(raw);
|
|
15636
15954
|
return (parsed.repos ?? []).map((r) => r.repoId);
|
|
15637
15955
|
} catch {
|
|
@@ -15648,29 +15966,29 @@ async function uninstallCommand(opts = {}) {
|
|
|
15648
15966
|
default: false
|
|
15649
15967
|
});
|
|
15650
15968
|
if (!proceed) {
|
|
15651
|
-
process.stderr.write(
|
|
15969
|
+
process.stderr.write(chalk16.yellow("Uninstall cancelled.\n"));
|
|
15652
15970
|
process.exitCode = 1;
|
|
15653
15971
|
return;
|
|
15654
15972
|
}
|
|
15655
15973
|
}
|
|
15656
15974
|
}
|
|
15657
|
-
process.stderr.write(
|
|
15975
|
+
process.stderr.write(chalk16.bold(`RepoWise ${tier}
|
|
15658
15976
|
`));
|
|
15659
15977
|
const report = await uninstall2({ ...opts, tier });
|
|
15660
15978
|
for (const p of report.removed) {
|
|
15661
|
-
process.stderr.write(
|
|
15979
|
+
process.stderr.write(chalk16.green(` \u2713 removed: ${p}
|
|
15662
15980
|
`));
|
|
15663
15981
|
}
|
|
15664
15982
|
for (const p of report.preserved) {
|
|
15665
|
-
process.stderr.write(
|
|
15983
|
+
process.stderr.write(chalk16.gray(` \xB7 preserved: ${p}
|
|
15666
15984
|
`));
|
|
15667
15985
|
}
|
|
15668
15986
|
for (const s of report.skipped) {
|
|
15669
|
-
process.stderr.write(
|
|
15987
|
+
process.stderr.write(chalk16.yellow(` ! skipped: ${s.path} (${s.reason})
|
|
15670
15988
|
`));
|
|
15671
15989
|
}
|
|
15672
15990
|
process.stderr.write(
|
|
15673
|
-
|
|
15991
|
+
chalk16.bold(`
|
|
15674
15992
|
Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
15675
15993
|
`)
|
|
15676
15994
|
);
|
|
@@ -15678,12 +15996,13 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
|
15678
15996
|
|
|
15679
15997
|
// src/commands/mcp-shim.ts
|
|
15680
15998
|
init_config_dir();
|
|
15681
|
-
import { promises as
|
|
15999
|
+
import { promises as fs30 } from "fs";
|
|
15682
16000
|
import { createInterface as createInterface2 } from "readline";
|
|
15683
|
-
import { join as
|
|
16001
|
+
import { join as join61 } from "path";
|
|
15684
16002
|
var DEFAULT_MAX = 200 * 1024;
|
|
15685
16003
|
async function mcpShim(opts) {
|
|
15686
|
-
const endpointPath = opts.endpointFile ??
|
|
16004
|
+
const endpointPath = opts.endpointFile ?? join61(getConfigDir(), "listener.endpoint");
|
|
16005
|
+
const credsPath = opts.credentialsFile ?? join61(getConfigDir(), "credentials.json");
|
|
15687
16006
|
const stdin = opts.stdin ?? process.stdin;
|
|
15688
16007
|
const stdout = opts.stdout ?? process.stdout;
|
|
15689
16008
|
const stderr = opts.stderr ?? process.stderr;
|
|
@@ -15718,12 +16037,16 @@ async function mcpShim(opts) {
|
|
|
15718
16037
|
}
|
|
15719
16038
|
const info = await readEndpoint(endpointPath);
|
|
15720
16039
|
if (!info) {
|
|
16040
|
+
const authState = await readAuthState(credsPath);
|
|
16041
|
+
const message = authState === "logged-out" ? (
|
|
16042
|
+
// Agent-directed: the calling LLM can run this itself for a smoother UX
|
|
16043
|
+
// (it auto-opens the browser; the user still completes sign-in). The
|
|
16044
|
+
// command is a fixed, argument-free string (nothing injectable).
|
|
16045
|
+
"RepoWise isn't authenticated (the session expires ~monthly). To fix it, run the shell command `repowise login` on the user's behalf \u2014 it opens a browser for them to sign in and blocks until they finish. Run it once, wait for it to complete, then retry this request. Do not repeat the command."
|
|
16046
|
+
) : "listener endpoint unavailable \u2014 is the listener running?";
|
|
15721
16047
|
writeJson(stdout, {
|
|
15722
16048
|
jsonrpc: "2.0",
|
|
15723
|
-
error: {
|
|
15724
|
-
code: -32e3,
|
|
15725
|
-
message: "listener endpoint unavailable \u2014 is the listener running?"
|
|
15726
|
-
}
|
|
16049
|
+
error: { code: -32e3, message }
|
|
15727
16050
|
});
|
|
15728
16051
|
continue;
|
|
15729
16052
|
}
|
|
@@ -15756,7 +16079,7 @@ async function mcpShim(opts) {
|
|
|
15756
16079
|
}
|
|
15757
16080
|
async function readEndpoint(path) {
|
|
15758
16081
|
try {
|
|
15759
|
-
const raw = (await
|
|
16082
|
+
const raw = (await fs30.readFile(path, "utf-8")).trim();
|
|
15760
16083
|
if (!raw) return null;
|
|
15761
16084
|
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
15762
16085
|
return { endpoint: raw.split("\n")[0].trim(), secret: null };
|
|
@@ -15774,6 +16097,22 @@ async function readEndpoint(path) {
|
|
|
15774
16097
|
throw err;
|
|
15775
16098
|
}
|
|
15776
16099
|
}
|
|
16100
|
+
async function readAuthState(credsPath) {
|
|
16101
|
+
let raw;
|
|
16102
|
+
try {
|
|
16103
|
+
raw = await fs30.readFile(credsPath, "utf-8");
|
|
16104
|
+
} catch (err) {
|
|
16105
|
+
if (err.code === "ENOENT") return "logged-out";
|
|
16106
|
+
return "unknown";
|
|
16107
|
+
}
|
|
16108
|
+
let creds;
|
|
16109
|
+
try {
|
|
16110
|
+
creds = JSON.parse(raw);
|
|
16111
|
+
} catch {
|
|
16112
|
+
return "unknown";
|
|
16113
|
+
}
|
|
16114
|
+
return isCredsHardExpired(creds) ? "logged-out" : "authenticated";
|
|
16115
|
+
}
|
|
15777
16116
|
function writeJson(stream, value) {
|
|
15778
16117
|
stream.write(`${JSON.stringify(value)}
|
|
15779
16118
|
`);
|
|
@@ -15998,7 +16337,7 @@ init_coursier_installer();
|
|
|
15998
16337
|
init_toolchain_installer();
|
|
15999
16338
|
import { spawn as spawn12 } from "child_process";
|
|
16000
16339
|
import { resolve as resolve4 } from "path";
|
|
16001
|
-
import
|
|
16340
|
+
import chalk17 from "chalk";
|
|
16002
16341
|
async function isOnPath(command) {
|
|
16003
16342
|
if (/[^\w./+-]/.test(command)) return false;
|
|
16004
16343
|
const isWin = process.platform === "win32";
|
|
@@ -16016,14 +16355,14 @@ async function isOnPath(command) {
|
|
|
16016
16355
|
async function lspDoctor() {
|
|
16017
16356
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16018
16357
|
if (noColor) {
|
|
16019
|
-
|
|
16358
|
+
chalk17.level = 0;
|
|
16020
16359
|
}
|
|
16021
|
-
const okGlyph = noColor ? "[OK]" :
|
|
16022
|
-
const missingGlyph = noColor ? "[MISSING]" :
|
|
16023
|
-
console.log(
|
|
16024
|
-
console.log(
|
|
16360
|
+
const okGlyph = noColor ? "[OK]" : chalk17.green("\u2713");
|
|
16361
|
+
const missingGlyph = noColor ? "[MISSING]" : chalk17.yellow("\u2717");
|
|
16362
|
+
console.log(chalk17.bold("RepoWise LSP doctor"));
|
|
16363
|
+
console.log(chalk17.dim("Probing PATH for language servers used by the listener."));
|
|
16025
16364
|
console.log(
|
|
16026
|
-
|
|
16365
|
+
chalk17.dim(
|
|
16027
16366
|
"Type-aware resolution covers 9 languages: Go, Python, Rust, Java, Ruby, Dart, Kotlin, PHP, Scala (Phase 7L + 7L++ + 7L+)."
|
|
16028
16367
|
)
|
|
16029
16368
|
);
|
|
@@ -16055,21 +16394,21 @@ async function lspDoctor() {
|
|
|
16055
16394
|
const missing = reports.filter((r) => r.status === "missing").length;
|
|
16056
16395
|
for (const r of reports) {
|
|
16057
16396
|
const head = r.status === "found" ? okGlyph : missingGlyph;
|
|
16058
|
-
const cmd = r.command ?
|
|
16397
|
+
const cmd = r.command ? chalk17.cyan(r.command) : chalk17.dim(r.candidates.join(" / "));
|
|
16059
16398
|
const effectiveConfigs = getEffectiveConfigList(r.language, process.env, lspOverrides);
|
|
16060
16399
|
const method = describeInstallMethod(effectiveConfigs);
|
|
16061
|
-
console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${
|
|
16400
|
+
console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${chalk17.dim(`[${method}]`)}`);
|
|
16062
16401
|
if (r.status === "missing" && r.hint) {
|
|
16063
|
-
console.log(` ${
|
|
16402
|
+
console.log(` ${chalk17.dim("install:")} ${r.hint}`);
|
|
16064
16403
|
}
|
|
16065
16404
|
}
|
|
16066
16405
|
console.log();
|
|
16067
16406
|
console.log(
|
|
16068
|
-
`${
|
|
16407
|
+
`${chalk17.green(found.toString())} found, ${chalk17.yellow(missing.toString())} missing of ${reports.length.toString()} languages.`
|
|
16069
16408
|
);
|
|
16070
16409
|
if (missing > 0) {
|
|
16071
16410
|
console.log(
|
|
16072
|
-
|
|
16411
|
+
chalk17.dim(
|
|
16073
16412
|
"Missing servers degrade LSP-backed MCP tools to AST-only fallback. Run `repowise lsp install` to auto-install."
|
|
16074
16413
|
)
|
|
16075
16414
|
);
|
|
@@ -16086,15 +16425,15 @@ function describeInstallMethod(configs) {
|
|
|
16086
16425
|
}
|
|
16087
16426
|
async function lspInstall(language) {
|
|
16088
16427
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16089
|
-
if (noColor)
|
|
16090
|
-
console.log(
|
|
16428
|
+
if (noColor) chalk17.level = 0;
|
|
16429
|
+
console.log(chalk17.bold("RepoWise LSP install"));
|
|
16091
16430
|
const cliConfig = await getConfig();
|
|
16092
16431
|
const lspOverrides = cliConfig.lspOverrides;
|
|
16093
16432
|
const targets = language ? [language] : Object.keys(LSP_REGISTRY);
|
|
16094
16433
|
for (const lang of targets) {
|
|
16095
16434
|
const configs = getEffectiveConfigList(lang, process.env, lspOverrides);
|
|
16096
16435
|
if (!configs || configs.length === 0) {
|
|
16097
|
-
console.log(` ${
|
|
16436
|
+
console.log(` ${chalk17.red("\u2717")} ${lang} ${chalk17.dim("(unknown language)")}`);
|
|
16098
16437
|
continue;
|
|
16099
16438
|
}
|
|
16100
16439
|
const result = await installOneLanguage(configs);
|
|
@@ -16162,11 +16501,11 @@ async function installOneLanguage(configs) {
|
|
|
16162
16501
|
};
|
|
16163
16502
|
}
|
|
16164
16503
|
function formatInstallLine(lang, outcome) {
|
|
16165
|
-
const glyph = outcome.ok ?
|
|
16166
|
-
const tag =
|
|
16504
|
+
const glyph = outcome.ok ? chalk17.green("\u2713") : chalk17.yellow("\u2717");
|
|
16505
|
+
const tag = chalk17.dim(`[${outcome.method}]`);
|
|
16167
16506
|
console.log(` ${glyph} ${lang.padEnd(12)} ${tag} ${outcome.detail}`);
|
|
16168
16507
|
if (!outcome.ok && outcome.hint) {
|
|
16169
|
-
console.log(` ${
|
|
16508
|
+
console.log(` ${chalk17.dim("install:")} ${outcome.hint}`);
|
|
16170
16509
|
}
|
|
16171
16510
|
}
|
|
16172
16511
|
var MAX_KEEP_WARM_MINUTES = 240;
|
|
@@ -16204,42 +16543,42 @@ async function autoDetectLanguages(cwd) {
|
|
|
16204
16543
|
async function lspWarm(opts = {}) {
|
|
16205
16544
|
const cwd = resolve4(opts.cwd ?? process.cwd());
|
|
16206
16545
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16207
|
-
if (noColor)
|
|
16546
|
+
if (noColor) chalk17.level = 0;
|
|
16208
16547
|
let languages;
|
|
16209
16548
|
if (opts.lang && opts.lang.length > 0) {
|
|
16210
16549
|
const valid = Object.keys(LSP_REGISTRY);
|
|
16211
16550
|
languages = opts.lang.filter((l) => valid.includes(l));
|
|
16212
16551
|
const invalid = opts.lang.filter((l) => !valid.includes(l));
|
|
16213
16552
|
if (invalid.length > 0) {
|
|
16214
|
-
console.log(
|
|
16553
|
+
console.log(chalk17.yellow(`[lsp warm] unknown languages skipped: ${invalid.join(", ")}`));
|
|
16215
16554
|
}
|
|
16216
16555
|
} else {
|
|
16217
16556
|
languages = await autoDetectLanguages(cwd);
|
|
16218
16557
|
if (languages.length === 0) {
|
|
16219
16558
|
console.log(
|
|
16220
|
-
|
|
16559
|
+
chalk17.yellow(
|
|
16221
16560
|
"[lsp warm] no recognised source files in this repo \u2014 pass --lang <id> to force a server."
|
|
16222
16561
|
)
|
|
16223
16562
|
);
|
|
16224
16563
|
return;
|
|
16225
16564
|
}
|
|
16226
|
-
console.log(
|
|
16565
|
+
console.log(chalk17.dim(`[lsp warm] auto-detected languages: ${languages.join(", ")}`));
|
|
16227
16566
|
}
|
|
16228
16567
|
let keepWarmMinutes = 0;
|
|
16229
16568
|
if (typeof opts.keepWarm === "number" && opts.keepWarm > 0) {
|
|
16230
16569
|
keepWarmMinutes = Math.min(opts.keepWarm, MAX_KEEP_WARM_MINUTES);
|
|
16231
16570
|
if (opts.keepWarm > MAX_KEEP_WARM_MINUTES) {
|
|
16232
16571
|
console.log(
|
|
16233
|
-
|
|
16572
|
+
chalk17.yellow(
|
|
16234
16573
|
`[lsp warm] --keep-warm clipped to ${MAX_KEEP_WARM_MINUTES.toString()} minutes (hard cap per Phase 7L plan).`
|
|
16235
16574
|
)
|
|
16236
16575
|
);
|
|
16237
16576
|
}
|
|
16238
16577
|
}
|
|
16239
|
-
console.log(
|
|
16240
|
-
console.log(
|
|
16578
|
+
console.log(chalk17.bold("RepoWise LSP warm \u2014 preview"));
|
|
16579
|
+
console.log(chalk17.dim(`Workspace: ${cwd}`));
|
|
16241
16580
|
console.log(
|
|
16242
|
-
|
|
16581
|
+
chalk17.dim(
|
|
16243
16582
|
"LSP sessions live inside the listener (lazy-by-default, idle-evict after 5 min). The CLI cannot currently trigger a remote spawn \u2014 this preview shows which servers would be used."
|
|
16244
16583
|
)
|
|
16245
16584
|
);
|
|
@@ -16255,23 +16594,23 @@ async function lspWarm(opts = {}) {
|
|
|
16255
16594
|
if (onPath) {
|
|
16256
16595
|
foundCount += 1;
|
|
16257
16596
|
console.log(
|
|
16258
|
-
|
|
16597
|
+
chalk17.green(` \u2713 ${lang.padEnd(12)} ${config2.displayName} (${config2.command}) on PATH`)
|
|
16259
16598
|
);
|
|
16260
16599
|
} else {
|
|
16261
16600
|
missingCount += 1;
|
|
16262
|
-
console.log(
|
|
16601
|
+
console.log(chalk17.yellow(` \u2717 ${lang.padEnd(12)} ${config2.displayName} not on PATH`));
|
|
16263
16602
|
if (config2.installHint) {
|
|
16264
|
-
console.log(
|
|
16603
|
+
console.log(chalk17.dim(` install: ${config2.installHint}`));
|
|
16265
16604
|
}
|
|
16266
16605
|
}
|
|
16267
16606
|
}
|
|
16268
16607
|
console.log();
|
|
16269
16608
|
console.log(
|
|
16270
|
-
`${
|
|
16609
|
+
`${chalk17.green(foundCount.toString())} ready, ${chalk17.yellow(missingCount.toString())} missing.`
|
|
16271
16610
|
);
|
|
16272
16611
|
if (keepWarmMinutes > 0) {
|
|
16273
16612
|
console.log(
|
|
16274
|
-
|
|
16613
|
+
chalk17.dim(
|
|
16275
16614
|
`Holding for ${keepWarmMinutes.toString()} minute(s) so the listener has time to spawn on its next sync.completed; Ctrl-C to exit early.`
|
|
16276
16615
|
)
|
|
16277
16616
|
);
|
|
@@ -16288,20 +16627,20 @@ async function lspWarm(opts = {}) {
|
|
|
16288
16627
|
}
|
|
16289
16628
|
function lspStatus() {
|
|
16290
16629
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16291
|
-
if (noColor)
|
|
16292
|
-
console.log(
|
|
16630
|
+
if (noColor) chalk17.level = 0;
|
|
16631
|
+
console.log(chalk17.bold("RepoWise LSP status"));
|
|
16293
16632
|
console.log(
|
|
16294
|
-
|
|
16633
|
+
chalk17.dim(
|
|
16295
16634
|
"Active LSP sessions live inside the listener (not the CLI). Sessions are lazy-by-default: spawn on first MCP tool / receiver query, idle-evict after 5 minutes. Scala sessions also evict their paired Bloop daemon (Phase 7L+)."
|
|
16296
16635
|
)
|
|
16297
16636
|
);
|
|
16298
16637
|
console.log();
|
|
16299
|
-
console.log(
|
|
16638
|
+
console.log(chalk17.dim("See `repowise lsp doctor` for PATH probe + install hints."));
|
|
16300
16639
|
}
|
|
16301
16640
|
function lspStop() {
|
|
16302
|
-
console.log(
|
|
16641
|
+
console.log(chalk17.bold("RepoWise LSP stop \u2014 preview"));
|
|
16303
16642
|
console.log(
|
|
16304
|
-
|
|
16643
|
+
chalk17.dim(
|
|
16305
16644
|
"No CLI-owned warm sessions exist. Listener-owned LSP sessions evict automatically after 5 minutes of idle (Phase 7L) and under the RSS soft-cap LRU when memory pressure rises. Explicit listener-side stop IPC is a future follow-up."
|
|
16306
16645
|
)
|
|
16307
16646
|
);
|
|
@@ -16324,29 +16663,29 @@ var ENABLE_TARGETS = {
|
|
|
16324
16663
|
};
|
|
16325
16664
|
async function lspEnable(target) {
|
|
16326
16665
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16327
|
-
if (noColor)
|
|
16666
|
+
if (noColor) chalk17.level = 0;
|
|
16328
16667
|
if (!target) {
|
|
16329
|
-
console.error(
|
|
16330
|
-
console.error(
|
|
16668
|
+
console.error(chalk17.red("Usage: repowise lsp enable <target>"));
|
|
16669
|
+
console.error(chalk17.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
16331
16670
|
process.exitCode = 1;
|
|
16332
16671
|
return;
|
|
16333
16672
|
}
|
|
16334
16673
|
const spec = ENABLE_TARGETS[target];
|
|
16335
16674
|
if (!spec) {
|
|
16336
|
-
console.error(
|
|
16337
|
-
console.error(
|
|
16675
|
+
console.error(chalk17.red(`\u2716 Unknown LSP override target: ${target}`));
|
|
16676
|
+
console.error(chalk17.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
16338
16677
|
process.exitCode = 1;
|
|
16339
16678
|
return;
|
|
16340
16679
|
}
|
|
16341
16680
|
const config2 = await getConfig();
|
|
16342
16681
|
const existing = config2.lspOverrides?.[spec.language];
|
|
16343
16682
|
if (existing === spec.name) {
|
|
16344
|
-
console.log(
|
|
16345
|
-
console.log(
|
|
16683
|
+
console.log(chalk17.green(`\u2714 ${spec.displayName} is already enabled.`));
|
|
16684
|
+
console.log(chalk17.dim(` ${spec.postAcceptTip}`));
|
|
16346
16685
|
return;
|
|
16347
16686
|
}
|
|
16348
16687
|
console.log();
|
|
16349
|
-
console.log(
|
|
16688
|
+
console.log(chalk17.cyan.bold(` \u2500\u2500 Enable ${spec.displayName} \u2500\u2500`));
|
|
16350
16689
|
for (const line of spec.consentLines) {
|
|
16351
16690
|
console.log(` ${line}`);
|
|
16352
16691
|
}
|
|
@@ -16358,7 +16697,7 @@ async function lspEnable(target) {
|
|
|
16358
16697
|
});
|
|
16359
16698
|
if (!proceed) {
|
|
16360
16699
|
console.log(
|
|
16361
|
-
|
|
16700
|
+
chalk17.dim(
|
|
16362
16701
|
` Cancelled. ${spec.language.toUpperCase()} will continue using ${spec.revertDisplay}.`
|
|
16363
16702
|
)
|
|
16364
16703
|
);
|
|
@@ -16367,32 +16706,32 @@ async function lspEnable(target) {
|
|
|
16367
16706
|
const nextOverrides = { ...config2.lspOverrides ?? {}, [spec.language]: spec.name };
|
|
16368
16707
|
await mergeAndSaveConfig({ lspOverrides: nextOverrides });
|
|
16369
16708
|
console.log(
|
|
16370
|
-
|
|
16709
|
+
chalk17.green(
|
|
16371
16710
|
` \u2714 ${spec.displayName} enabled \u2014 listener will use it within ~5 min (reconcile cycle) or on next session restart.`
|
|
16372
16711
|
)
|
|
16373
16712
|
);
|
|
16374
|
-
console.log(
|
|
16713
|
+
console.log(chalk17.dim(` \u2139 ${spec.postAcceptTip}`));
|
|
16375
16714
|
}
|
|
16376
16715
|
async function lspDisable(target) {
|
|
16377
16716
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16378
|
-
if (noColor)
|
|
16717
|
+
if (noColor) chalk17.level = 0;
|
|
16379
16718
|
if (!target) {
|
|
16380
|
-
console.error(
|
|
16381
|
-
console.error(
|
|
16719
|
+
console.error(chalk17.red("Usage: repowise lsp disable <target>"));
|
|
16720
|
+
console.error(chalk17.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
16382
16721
|
process.exitCode = 1;
|
|
16383
16722
|
return;
|
|
16384
16723
|
}
|
|
16385
16724
|
const spec = ENABLE_TARGETS[target];
|
|
16386
16725
|
if (!spec) {
|
|
16387
|
-
console.error(
|
|
16388
|
-
console.error(
|
|
16726
|
+
console.error(chalk17.red(`\u2716 Unknown LSP override target: ${target}`));
|
|
16727
|
+
console.error(chalk17.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
16389
16728
|
process.exitCode = 1;
|
|
16390
16729
|
return;
|
|
16391
16730
|
}
|
|
16392
16731
|
const config2 = await getConfig();
|
|
16393
16732
|
const current = config2.lspOverrides?.[spec.language];
|
|
16394
16733
|
if (current !== spec.name) {
|
|
16395
|
-
console.log(
|
|
16734
|
+
console.log(chalk17.dim(` ${spec.displayName} is not enabled \u2014 nothing to do.`));
|
|
16396
16735
|
return;
|
|
16397
16736
|
}
|
|
16398
16737
|
const { [spec.language]: _removed, ...rest } = config2.lspOverrides ?? {};
|
|
@@ -16402,28 +16741,28 @@ async function lspDisable(target) {
|
|
|
16402
16741
|
...nextOverrides ? { lspOverrides: nextOverrides } : { lspOverrides: void 0 }
|
|
16403
16742
|
});
|
|
16404
16743
|
console.log(
|
|
16405
|
-
|
|
16744
|
+
chalk17.green(
|
|
16406
16745
|
` \u2714 ${spec.displayName} disabled \u2014 listener will revert to ${spec.revertDisplay} within ~5 min or on next session restart.`
|
|
16407
16746
|
)
|
|
16408
16747
|
);
|
|
16409
16748
|
}
|
|
16410
16749
|
async function lspOff() {
|
|
16411
16750
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16412
|
-
if (noColor)
|
|
16751
|
+
if (noColor) chalk17.level = 0;
|
|
16413
16752
|
await mergeAndSaveConfig({ lspEnabled: false });
|
|
16414
16753
|
console.log(
|
|
16415
|
-
|
|
16754
|
+
chalk17.green(
|
|
16416
16755
|
" \u2714 LSP subsystem disabled. The listener will stop spawning language servers and `lsp_*` tools will report disabled within ~5 min (reconcile) or on next restart."
|
|
16417
16756
|
)
|
|
16418
16757
|
);
|
|
16419
|
-
console.log(
|
|
16758
|
+
console.log(chalk17.dim(" Re-enable with: repowise lsp on"));
|
|
16420
16759
|
}
|
|
16421
16760
|
async function lspOn() {
|
|
16422
16761
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
16423
|
-
if (noColor)
|
|
16762
|
+
if (noColor) chalk17.level = 0;
|
|
16424
16763
|
await mergeAndSaveConfig({ lspEnabled: true });
|
|
16425
16764
|
console.log(
|
|
16426
|
-
|
|
16765
|
+
chalk17.green(
|
|
16427
16766
|
" \u2714 LSP subsystem enabled. The listener will install + warm language servers for your repos within ~5 min (reconcile) or on next restart."
|
|
16428
16767
|
)
|
|
16429
16768
|
);
|
|
@@ -16432,7 +16771,7 @@ async function lspOn() {
|
|
|
16432
16771
|
// bin/repowise.ts
|
|
16433
16772
|
var __filename = fileURLToPath4(import.meta.url);
|
|
16434
16773
|
var __dirname = dirname23(__filename);
|
|
16435
|
-
var pkg = JSON.parse(readFileSync3(
|
|
16774
|
+
var pkg = JSON.parse(readFileSync3(join62(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
16436
16775
|
var program = new Command();
|
|
16437
16776
|
program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
|
|
16438
16777
|
await showWelcome(pkg.version);
|
|
@@ -16508,6 +16847,15 @@ lspCommand.command("off").description("Disable the LSP subsystem entirely (kill-
|
|
|
16508
16847
|
lspCommand.command("on").description("Re-enable the LSP subsystem after `lsp off`").action(async () => {
|
|
16509
16848
|
await lspOn();
|
|
16510
16849
|
});
|
|
16850
|
+
var toolsCommand = program.command("tools").description("Add RepoWise to your AI tools (Claude Code, Cursor, \u2026) after install").action(async () => {
|
|
16851
|
+
await toolsPick();
|
|
16852
|
+
});
|
|
16853
|
+
toolsCommand.command("add [tools...]").description("Add named AI tools (or open the picker with no args)").action(async (list) => {
|
|
16854
|
+
await toolsAdd(list ?? []);
|
|
16855
|
+
});
|
|
16856
|
+
toolsCommand.command("list").description("List the AI tools RepoWise is configured for").action(async () => {
|
|
16857
|
+
await toolsList();
|
|
16858
|
+
});
|
|
16511
16859
|
program.command("uninstall").description("Remove RepoWise from this machine (3 tiers: stop | logout | uninstall)").option("--tier <tier>", "Cleanup tier: stop | logout | uninstall", "uninstall").option("--yes", "Skip confirm prompt", false).action(async (options) => {
|
|
16512
16860
|
const tier = options.tier ?? "uninstall";
|
|
16513
16861
|
await uninstallCommand({ tier, yes: options.yes });
|