githits 0.4.10 → 0.4.11
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/dist/cli.js +1047 -336
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-mw1910qd.js → chunk-2w48kb4c.js} +2 -2
- package/dist/shared/{chunk-p9ak72j0.js → chunk-5xd5rcm9.js} +50 -16
- package/dist/shared/{chunk-fvpvx4x4.js → chunk-agpezzpd.js} +1 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -62,11 +62,11 @@ import {
|
|
|
62
62
|
shouldRunUpdateCheck,
|
|
63
63
|
startTelemetrySpan,
|
|
64
64
|
withTelemetrySpan
|
|
65
|
-
} from "./shared/chunk-
|
|
65
|
+
} from "./shared/chunk-5xd5rcm9.js";
|
|
66
66
|
import {
|
|
67
67
|
__require,
|
|
68
68
|
version
|
|
69
|
-
} from "./shared/chunk-
|
|
69
|
+
} from "./shared/chunk-agpezzpd.js";
|
|
70
70
|
|
|
71
71
|
// src/cli.ts
|
|
72
72
|
import { Command } from "commander";
|
|
@@ -3619,9 +3619,9 @@ function isSeverityLabel(value) {
|
|
|
3619
3619
|
// src/shared/package-upgrade-review-request.ts
|
|
3620
3620
|
var DEFAULT_CHANGELOG_LIMIT = 20;
|
|
3621
3621
|
function buildPackageUpgradeReviewRequest(input) {
|
|
3622
|
-
const batch = input.packages;
|
|
3623
|
-
const hasBatch = batch
|
|
3624
|
-
const hasSingle = input.registry
|
|
3622
|
+
const batch = input.packages?.filter((pkg) => !isBlankPackageInput(pkg));
|
|
3623
|
+
const hasBatch = Array.isArray(batch) && batch.length > 0;
|
|
3624
|
+
const hasSingle = hasNonBlankValue(input.registry) || hasNonBlankValue(input.packageName) || hasNonBlankValue(input.currentVersion) || hasNonBlankValue(input.targetVersion);
|
|
3625
3625
|
if (hasBatch && hasSingle) {
|
|
3626
3626
|
throw new InvalidPackageSpecError("Pass either packages[] or registry/package_name/current_version/target_version, not both.");
|
|
3627
3627
|
}
|
|
@@ -3661,6 +3661,12 @@ function buildUpgradeDependencyProbeParams(pkg, version2, options) {
|
|
|
3661
3661
|
includeDependencyChanges: options.includeDependencyChanges
|
|
3662
3662
|
};
|
|
3663
3663
|
}
|
|
3664
|
+
function hasNonBlankValue(value) {
|
|
3665
|
+
return value !== undefined && value.trim().length > 0;
|
|
3666
|
+
}
|
|
3667
|
+
function isBlankPackageInput(input) {
|
|
3668
|
+
return !(hasNonBlankValue(input.registry) || hasNonBlankValue(input.packageName) || hasNonBlankValue(input.currentVersion) || hasNonBlankValue(input.targetVersion));
|
|
3669
|
+
}
|
|
3664
3670
|
function parseBatch(packages) {
|
|
3665
3671
|
if (!Array.isArray(packages) || packages.length === 0) {
|
|
3666
3672
|
throw new InvalidPackageSpecError("packages[] must contain at least one upgrade.");
|
|
@@ -6311,10 +6317,11 @@ function buildUnifiedSearchParams(input) {
|
|
|
6311
6317
|
};
|
|
6312
6318
|
}
|
|
6313
6319
|
function resolveTargets(target, targets) {
|
|
6314
|
-
|
|
6320
|
+
const nonEmptyTargets = targets?.length ? targets : undefined;
|
|
6321
|
+
if (target && nonEmptyTargets) {
|
|
6315
6322
|
throw new InvalidArgumentError("Provide either `target` for one search target or `targets` for multiple, not both.");
|
|
6316
6323
|
}
|
|
6317
|
-
const resolved = target ? [target] :
|
|
6324
|
+
const resolved = target ? [target] : nonEmptyTargets ?? [];
|
|
6318
6325
|
if (resolved.length === 0) {
|
|
6319
6326
|
throw new InvalidArgumentError("Provide either `target` for one search target or `targets` for multiple; neither was set.");
|
|
6320
6327
|
}
|
|
@@ -8076,7 +8083,7 @@ grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
|
|
|
8076
8083
|
match in --verbose output; full payload in --json).`;
|
|
8077
8084
|
function registerCodeGrepCommand(pkgCommand) {
|
|
8078
8085
|
return pkgCommand.command("grep").summary("Deterministic text grep over indexed dependency source").description(PKG_GREP_DESCRIPTION).argument("[spec-or-pattern]", "Spec mode: package spec (e.g. npm:express). Repo mode (with --repo-url): the pattern.").argument("[pattern-or-prefix]", "Spec mode: the pattern. Repo mode: optional path-prefix.").argument("[path-prefix]", "Spec mode only: optional path-prefix. Ignored with --repo-url.").option("--repo-url <url>", "Repository URL addressing (defaults to the repo default branch)").option("--git-ref <ref>", "Optional tag, commit, branch, or HEAD for --repo-url.").option("--path <path>", "Exact file path to grep").option("--glob <glob>", "Glob scope (repeatable)", collectRepeatable2, []).option("--ext <ext>", "Extension filter without leading dot (repeatable)", collectRepeatable2, []).option("--regex", "Interpret the pattern as RE2 regex").option("--case-sensitive", "Enable ASCII case-sensitive matching").option("-C, --context <n>", "Context lines before and after each match (0-10)").option("-B, --before-context <n>", "Context lines before each match (0-10)").option("-A, --after-context <n>", "Context lines after each match (0-10)").option("--exclude-docs", "Skip files classified as documentation").option("--exclude-tests", "Skip files classified as tests").option("--limit <n>", "Max matches to return on this page (1-1000, default 50)").option("--per-file-limit <n>", "Cap matches per file within this page (0-1000, 0 = unlimited)").option("--cursor <cursor>", "Opaque nextCursor from a previous grep result").option("--symbol-field <field>", `Repeatable; surfaces in --json and under each --verbose match. ${GREP_REPO_SYMBOL_FIELDS_NOTE}`, collectRepeatable2, []).option("--wait <ms>", `Indexing wait timeout (0-${MAX_WAIT_TIMEOUT_MS}, default ${DEFAULT_WAIT_TIMEOUT_MS})`).option("-v, --verbose", "Render grouped output with file headers").option("--json", "Emit the JSON envelope").action(async (arg1, arg2, arg3, options) => {
|
|
8079
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
8086
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-2w48kb4c.js");
|
|
8080
8087
|
const deps = await createContainer2();
|
|
8081
8088
|
await pkgGrepAction(arg1, arg2, arg3, options, {
|
|
8082
8089
|
codeNavigationService: deps.codeNavigationService,
|
|
@@ -9044,7 +9051,7 @@ function registerExampleCommand(program) {
|
|
|
9044
9051
|
});
|
|
9045
9052
|
}
|
|
9046
9053
|
async function loadContainer() {
|
|
9047
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
9054
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-2w48kb4c.js");
|
|
9048
9055
|
return createContainer2();
|
|
9049
9056
|
}
|
|
9050
9057
|
// src/commands/feedback.ts
|
|
@@ -9117,6 +9124,7 @@ import {
|
|
|
9117
9124
|
parse as parseJsonc,
|
|
9118
9125
|
printParseErrorCode
|
|
9119
9126
|
} from "jsonc-parser";
|
|
9127
|
+
import { parse as parseToml2, stringify as stringifyToml } from "smol-toml";
|
|
9120
9128
|
import {
|
|
9121
9129
|
isMap,
|
|
9122
9130
|
isScalar,
|
|
@@ -9199,6 +9207,23 @@ function parseYamlConfigObject(content) {
|
|
|
9199
9207
|
};
|
|
9200
9208
|
}
|
|
9201
9209
|
}
|
|
9210
|
+
function parseTomlConfigObject(content) {
|
|
9211
|
+
const normalizedContent = normalizeConfigContent(content);
|
|
9212
|
+
if (normalizedContent.trim() === "") {
|
|
9213
|
+
return { value: {} };
|
|
9214
|
+
}
|
|
9215
|
+
try {
|
|
9216
|
+
const parsed = parseToml2(normalizedContent);
|
|
9217
|
+
if (!isPlainObject(parsed)) {
|
|
9218
|
+
return { error: "Config file root is not a TOML object" };
|
|
9219
|
+
}
|
|
9220
|
+
return { value: parsed };
|
|
9221
|
+
} catch (err) {
|
|
9222
|
+
return {
|
|
9223
|
+
error: `Invalid TOML: ${err instanceof Error ? err.message : String(err)}`
|
|
9224
|
+
};
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
9202
9227
|
function formatYamlError(error2) {
|
|
9203
9228
|
if (error2 instanceof Error) {
|
|
9204
9229
|
return error2.message;
|
|
@@ -9378,6 +9403,9 @@ function parseConfigObjectForFormat(content, format = "json") {
|
|
|
9378
9403
|
if (format === "yaml") {
|
|
9379
9404
|
return parseYamlConfigObject(content);
|
|
9380
9405
|
}
|
|
9406
|
+
if (format === "toml") {
|
|
9407
|
+
return parseTomlConfigObject(content);
|
|
9408
|
+
}
|
|
9381
9409
|
const parsed = parseConfigObject(content);
|
|
9382
9410
|
if (parsed.format === "invalid") {
|
|
9383
9411
|
return { error: parsed.error };
|
|
@@ -9389,11 +9417,24 @@ function renderConfigObjectForFormat(config, format = "json") {
|
|
|
9389
9417
|
const rendered = stringifyYaml(config);
|
|
9390
9418
|
return rendered.endsWith(`
|
|
9391
9419
|
`) ? rendered : `${rendered}
|
|
9420
|
+
`;
|
|
9421
|
+
}
|
|
9422
|
+
if (format === "toml") {
|
|
9423
|
+
const rendered = stringifyToml(config);
|
|
9424
|
+
return rendered.endsWith(`
|
|
9425
|
+
`) ? rendered : `${rendered}
|
|
9392
9426
|
`;
|
|
9393
9427
|
}
|
|
9394
9428
|
return `${JSON.stringify(config, null, 2)}
|
|
9395
9429
|
`;
|
|
9396
9430
|
}
|
|
9431
|
+
function getConfigObjectFormatName(format = "json") {
|
|
9432
|
+
if (format === "yaml")
|
|
9433
|
+
return "YAML";
|
|
9434
|
+
if (format === "toml")
|
|
9435
|
+
return "TOML";
|
|
9436
|
+
return "JSON";
|
|
9437
|
+
}
|
|
9397
9438
|
function isPlainObject(value) {
|
|
9398
9439
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9399
9440
|
}
|
|
@@ -9520,7 +9561,7 @@ function mergeServerConfig(existingContent, serversKey, serverName, serverConfig
|
|
|
9520
9561
|
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
9521
9562
|
return {
|
|
9522
9563
|
status: "parse_error",
|
|
9523
|
-
error: `"${serversKey}" is not a
|
|
9564
|
+
error: `"${serversKey}" is not a ${getConfigObjectFormatName(format)} object`
|
|
9524
9565
|
};
|
|
9525
9566
|
}
|
|
9526
9567
|
const serversObj = servers;
|
|
@@ -9557,7 +9598,7 @@ function removeServerConfig(existingContent, serversKey, serverName, format = "j
|
|
|
9557
9598
|
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
9558
9599
|
return {
|
|
9559
9600
|
status: "parse_error",
|
|
9560
|
-
error: `"${serversKey}" is not a
|
|
9601
|
+
error: `"${serversKey}" is not a ${getConfigObjectFormatName(format)} object`
|
|
9561
9602
|
};
|
|
9562
9603
|
}
|
|
9563
9604
|
const serversObj = servers;
|
|
@@ -9623,7 +9664,7 @@ async function getConfigUninstallCheckStatus(config, fs) {
|
|
|
9623
9664
|
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
9624
9665
|
return {
|
|
9625
9666
|
status: "failed",
|
|
9626
|
-
message: `Cannot parse ${config.configPath}: "${config.serversKey}" is not a ${config.format
|
|
9667
|
+
message: `Cannot parse ${config.configPath}: "${config.serversKey}" is not a ${getConfigObjectFormatName(config.format)} object. File left unchanged.`
|
|
9627
9668
|
};
|
|
9628
9669
|
}
|
|
9629
9670
|
const hasEntry = getMatchingServerKeys(servers, config.serverName).length > 0;
|
|
@@ -9688,7 +9729,7 @@ var ALREADY_EXISTS_PATTERNS = [
|
|
|
9688
9729
|
var ALREADY_ABSENT_PATTERNS = [
|
|
9689
9730
|
/(?:plugin|extension|server|mcp server)\s+["']?githits["']?\s+(?:was\s+)?not\s+found/i,
|
|
9690
9731
|
/["']?githits["']?\s+(?:plugin|extension|server)?\s*(?:does\s+not\s+exist|is\s+not\s+installed|not\s+installed)/i,
|
|
9691
|
-
/(?:package\s+)?["']?pi-mcp-adapter["']?\s+(?:is\s+)?not\s+installed/i,
|
|
9732
|
+
/(?:package\s+)?["']?pi-mcp-adapter["']?\s+(?:(?:is\s+)?not\s+installed|not\s+found)/i,
|
|
9692
9733
|
/unknown\s+(?:plugin|extension|server)\s+["']?githits["']?/i,
|
|
9693
9734
|
/marketplace\s+["']?githits-plugins["']?\s+(?:was\s+)?not\s+found/i
|
|
9694
9735
|
];
|
|
@@ -9733,15 +9774,15 @@ async function executeCliUninstallCommand(cmd, execService) {
|
|
|
9733
9774
|
try {
|
|
9734
9775
|
const result = await execService.exec(cmd.command, cmd.args);
|
|
9735
9776
|
const combined = `${result.stdout} ${result.stderr}`;
|
|
9736
|
-
if (result.exitCode === 0) {
|
|
9737
|
-
return { status: "removed", message: "Removed successfully" };
|
|
9738
|
-
}
|
|
9739
9777
|
if (isAlreadyAbsentOutput(combined)) {
|
|
9740
9778
|
return {
|
|
9741
9779
|
status: "not_configured",
|
|
9742
9780
|
message: `GitHits not configured via ${cmd.command}`
|
|
9743
9781
|
};
|
|
9744
9782
|
}
|
|
9783
|
+
if (result.exitCode === 0) {
|
|
9784
|
+
return { status: "removed", message: "Removed successfully" };
|
|
9785
|
+
}
|
|
9745
9786
|
const detail = result.stderr.trim() || result.stdout.trim();
|
|
9746
9787
|
return {
|
|
9747
9788
|
status: "failed",
|
|
@@ -10045,6 +10086,48 @@ function getHermesHomeDir(fs) {
|
|
|
10045
10086
|
function getHermesConfigPath(fs) {
|
|
10046
10087
|
return fs.joinPath(getHermesHomeDir(fs), "config.yaml");
|
|
10047
10088
|
}
|
|
10089
|
+
function getStandardMcpServerConfig() {
|
|
10090
|
+
return {
|
|
10091
|
+
command: GITHITS_MCP_COMMAND,
|
|
10092
|
+
args: [...GITHITS_MCP_ARGS]
|
|
10093
|
+
};
|
|
10094
|
+
}
|
|
10095
|
+
function getVsCodeMcpServerConfig() {
|
|
10096
|
+
return {
|
|
10097
|
+
type: "stdio",
|
|
10098
|
+
...getStandardMcpServerConfig()
|
|
10099
|
+
};
|
|
10100
|
+
}
|
|
10101
|
+
function getProjectPath(fs) {
|
|
10102
|
+
return fs.getCwd();
|
|
10103
|
+
}
|
|
10104
|
+
function getProjectJsonConfig(fs, relativePath, serversKey, serverConfig = getStandardMcpServerConfig()) {
|
|
10105
|
+
return {
|
|
10106
|
+
method: "config-file",
|
|
10107
|
+
configPath: fs.joinPath(getProjectPath(fs), ...relativePath),
|
|
10108
|
+
serversKey,
|
|
10109
|
+
serverName: GITHITS_SERVER_NAME,
|
|
10110
|
+
serverConfig
|
|
10111
|
+
};
|
|
10112
|
+
}
|
|
10113
|
+
function getUnsupportedProjectSetup(reason) {
|
|
10114
|
+
return { supported: false, reason };
|
|
10115
|
+
}
|
|
10116
|
+
function getAgentSetupConfig(agent, fs, scope = "user", context) {
|
|
10117
|
+
if (scope === "project") {
|
|
10118
|
+
if (agent.projectSetup?.supported) {
|
|
10119
|
+
return agent.projectSetup.getSetupConfig(fs, context);
|
|
10120
|
+
}
|
|
10121
|
+
return null;
|
|
10122
|
+
}
|
|
10123
|
+
return agent.getSetupConfig(fs, context);
|
|
10124
|
+
}
|
|
10125
|
+
function getProjectSetupUnsupportedReason(agent) {
|
|
10126
|
+
if (agent.projectSetup?.supported) {
|
|
10127
|
+
return null;
|
|
10128
|
+
}
|
|
10129
|
+
return agent.projectSetup?.reason ?? "project-level MCP config not verified";
|
|
10130
|
+
}
|
|
10048
10131
|
function getOpenCodeDesktopDetectPaths(fs) {
|
|
10049
10132
|
const userDataRoot = getUserDataRoot(fs);
|
|
10050
10133
|
return [
|
|
@@ -10155,7 +10238,11 @@ var claudeCode = {
|
|
|
10155
10238
|
args: ["plugin", "marketplace", "remove", CLAUDE_GITHITS_MARKETPLACE]
|
|
10156
10239
|
}
|
|
10157
10240
|
]
|
|
10158
|
-
})
|
|
10241
|
+
}),
|
|
10242
|
+
projectSetup: {
|
|
10243
|
+
supported: true,
|
|
10244
|
+
getSetupConfig: (fs) => getProjectJsonConfig(fs, [".mcp.json"], "mcpServers")
|
|
10245
|
+
}
|
|
10159
10246
|
};
|
|
10160
10247
|
var cursor = {
|
|
10161
10248
|
name: "Cursor",
|
|
@@ -10168,11 +10255,12 @@ var cursor = {
|
|
|
10168
10255
|
configPath: fs.joinPath(fs.getHomeDir(), ".cursor", "mcp.json"),
|
|
10169
10256
|
serversKey: "mcpServers",
|
|
10170
10257
|
serverName: GITHITS_SERVER_NAME,
|
|
10171
|
-
serverConfig:
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
|
|
10258
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10259
|
+
}),
|
|
10260
|
+
projectSetup: {
|
|
10261
|
+
supported: true,
|
|
10262
|
+
getSetupConfig: (fs) => getProjectJsonConfig(fs, [".cursor", "mcp.json"], "mcpServers")
|
|
10263
|
+
}
|
|
10176
10264
|
};
|
|
10177
10265
|
var windsurf = {
|
|
10178
10266
|
name: "Windsurf",
|
|
@@ -10185,11 +10273,9 @@ var windsurf = {
|
|
|
10185
10273
|
configPath: fs.joinPath(fs.getHomeDir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
10186
10274
|
serversKey: "mcpServers",
|
|
10187
10275
|
serverName: GITHITS_SERVER_NAME,
|
|
10188
|
-
serverConfig:
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
}
|
|
10192
|
-
})
|
|
10276
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10277
|
+
}),
|
|
10278
|
+
projectSetup: getUnsupportedProjectSetup("project-level MCP config not verified for Windsurf")
|
|
10193
10279
|
};
|
|
10194
10280
|
var claudeDesktop = {
|
|
10195
10281
|
name: "Claude Desktop",
|
|
@@ -10216,12 +10302,10 @@ var claudeDesktop = {
|
|
|
10216
10302
|
configPath: fs.joinPath(appData, "claude_desktop_config.json"),
|
|
10217
10303
|
serversKey: "mcpServers",
|
|
10218
10304
|
serverName: GITHITS_SERVER_NAME,
|
|
10219
|
-
serverConfig:
|
|
10220
|
-
command: GITHITS_MCP_COMMAND,
|
|
10221
|
-
args: [...GITHITS_MCP_ARGS]
|
|
10222
|
-
}
|
|
10305
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10223
10306
|
};
|
|
10224
|
-
}
|
|
10307
|
+
},
|
|
10308
|
+
projectSetup: getUnsupportedProjectSetup("Claude Desktop uses user-level desktop config")
|
|
10225
10309
|
};
|
|
10226
10310
|
var codexCli = {
|
|
10227
10311
|
name: "Codex CLI",
|
|
@@ -10251,7 +10335,18 @@ var codexCli = {
|
|
|
10251
10335
|
args: ["mcp", "remove", "githits"]
|
|
10252
10336
|
}
|
|
10253
10337
|
]
|
|
10254
|
-
})
|
|
10338
|
+
}),
|
|
10339
|
+
projectSetup: {
|
|
10340
|
+
supported: true,
|
|
10341
|
+
getSetupConfig: (fs) => ({
|
|
10342
|
+
method: "config-file",
|
|
10343
|
+
format: "toml",
|
|
10344
|
+
configPath: fs.joinPath(getProjectPath(fs), ".codex", "config.toml"),
|
|
10345
|
+
serversKey: "mcp_servers",
|
|
10346
|
+
serverName: "githits",
|
|
10347
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10348
|
+
})
|
|
10349
|
+
}
|
|
10255
10350
|
};
|
|
10256
10351
|
var pi = {
|
|
10257
10352
|
name: "Pi",
|
|
@@ -10284,8 +10379,7 @@ var pi = {
|
|
|
10284
10379
|
serversKey: "mcpServers",
|
|
10285
10380
|
serverName: GITHITS_SERVER_NAME,
|
|
10286
10381
|
serverConfig: {
|
|
10287
|
-
|
|
10288
|
-
args: [...GITHITS_MCP_ARGS],
|
|
10382
|
+
...getStandardMcpServerConfig(),
|
|
10289
10383
|
lifecycle: "eager"
|
|
10290
10384
|
}
|
|
10291
10385
|
}
|
|
@@ -10321,6 +10415,32 @@ var pi = {
|
|
|
10321
10415
|
}
|
|
10322
10416
|
]
|
|
10323
10417
|
};
|
|
10418
|
+
},
|
|
10419
|
+
projectSetup: {
|
|
10420
|
+
supported: true,
|
|
10421
|
+
getSetupConfig: (fs, context) => {
|
|
10422
|
+
const piCommand = context?.command ?? "pi";
|
|
10423
|
+
return {
|
|
10424
|
+
method: "composite",
|
|
10425
|
+
steps: [
|
|
10426
|
+
{
|
|
10427
|
+
method: "cli",
|
|
10428
|
+
commands: [
|
|
10429
|
+
{
|
|
10430
|
+
command: piCommand,
|
|
10431
|
+
args: ["install", "npm:pi-mcp-adapter"]
|
|
10432
|
+
}
|
|
10433
|
+
],
|
|
10434
|
+
checkCommand: {
|
|
10435
|
+
command: piCommand,
|
|
10436
|
+
args: ["list"],
|
|
10437
|
+
configuredPattern: PI_ADAPTER_CONFIGURED_PATTERN
|
|
10438
|
+
}
|
|
10439
|
+
},
|
|
10440
|
+
getProjectJsonConfig(fs, [".mcp.json"], "mcpServers")
|
|
10441
|
+
]
|
|
10442
|
+
};
|
|
10443
|
+
}
|
|
10324
10444
|
}
|
|
10325
10445
|
};
|
|
10326
10446
|
var vscode = {
|
|
@@ -10339,11 +10459,12 @@ var vscode = {
|
|
|
10339
10459
|
configPath: fs.joinPath(appData, "User", "mcp.json"),
|
|
10340
10460
|
serversKey: "servers",
|
|
10341
10461
|
serverName: GITHITS_SERVER_NAME,
|
|
10342
|
-
serverConfig:
|
|
10343
|
-
command: GITHITS_MCP_COMMAND,
|
|
10344
|
-
args: [...GITHITS_MCP_ARGS]
|
|
10345
|
-
}
|
|
10462
|
+
serverConfig: getVsCodeMcpServerConfig()
|
|
10346
10463
|
};
|
|
10464
|
+
},
|
|
10465
|
+
projectSetup: {
|
|
10466
|
+
supported: true,
|
|
10467
|
+
getSetupConfig: (fs) => getProjectJsonConfig(fs, [".vscode", "mcp.json"], "servers", getVsCodeMcpServerConfig())
|
|
10347
10468
|
}
|
|
10348
10469
|
};
|
|
10349
10470
|
var cline = {
|
|
@@ -10357,11 +10478,9 @@ var cline = {
|
|
|
10357
10478
|
configPath: fs.joinPath(fs.getHomeDir(), ".cline", "data", "settings", "cline_mcp_settings.json"),
|
|
10358
10479
|
serversKey: "mcpServers",
|
|
10359
10480
|
serverName: GITHITS_SERVER_NAME,
|
|
10360
|
-
serverConfig:
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
}
|
|
10364
|
-
})
|
|
10481
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10482
|
+
}),
|
|
10483
|
+
projectSetup: getUnsupportedProjectSetup("Cline MCP settings are documented as user-level config; project MCP auto-load not verified")
|
|
10365
10484
|
};
|
|
10366
10485
|
var geminiCli = {
|
|
10367
10486
|
name: "Gemini CLI",
|
|
@@ -10397,7 +10516,11 @@ var geminiCli = {
|
|
|
10397
10516
|
args: ["extensions", "uninstall", "githits"]
|
|
10398
10517
|
}
|
|
10399
10518
|
]
|
|
10400
|
-
})
|
|
10519
|
+
}),
|
|
10520
|
+
projectSetup: {
|
|
10521
|
+
supported: true,
|
|
10522
|
+
getSetupConfig: (fs) => getProjectJsonConfig(fs, [".gemini", "settings.json"], "mcpServers")
|
|
10523
|
+
}
|
|
10401
10524
|
};
|
|
10402
10525
|
async function isGeminiExtensionInstalledFromFilesystem(fs) {
|
|
10403
10526
|
const extensionManifestPath = fs.joinPath(fs.getHomeDir(), ".gemini", "extensions", "githits", "gemini-extension.json");
|
|
@@ -10414,11 +10537,9 @@ var googleAntigravity = {
|
|
|
10414
10537
|
configPath: fs.joinPath(fs.getHomeDir(), ".gemini", "antigravity", "mcp_config.json"),
|
|
10415
10538
|
serversKey: "mcpServers",
|
|
10416
10539
|
serverName: GITHITS_SERVER_NAME,
|
|
10417
|
-
serverConfig:
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
}
|
|
10421
|
-
})
|
|
10540
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10541
|
+
}),
|
|
10542
|
+
projectSetup: getUnsupportedProjectSetup("Google Antigravity project-level MCP config not verified")
|
|
10422
10543
|
};
|
|
10423
10544
|
var openCode = {
|
|
10424
10545
|
name: "OpenCode",
|
|
@@ -10437,7 +10558,15 @@ var openCode = {
|
|
|
10437
10558
|
command: [...GITHITS_MCP_INVOCATION],
|
|
10438
10559
|
enabled: true
|
|
10439
10560
|
}
|
|
10440
|
-
})
|
|
10561
|
+
}),
|
|
10562
|
+
projectSetup: {
|
|
10563
|
+
supported: true,
|
|
10564
|
+
getSetupConfig: (fs) => getProjectJsonConfig(fs, ["opencode.json"], "mcp", {
|
|
10565
|
+
type: "local",
|
|
10566
|
+
command: [...GITHITS_MCP_INVOCATION],
|
|
10567
|
+
enabled: true
|
|
10568
|
+
})
|
|
10569
|
+
}
|
|
10441
10570
|
};
|
|
10442
10571
|
var hermesAgent = {
|
|
10443
10572
|
name: "Hermes Agent",
|
|
@@ -10452,11 +10581,9 @@ var hermesAgent = {
|
|
|
10452
10581
|
configPath: getHermesConfigPath(fs),
|
|
10453
10582
|
serversKey: "mcp_servers",
|
|
10454
10583
|
serverName: GITHITS_SERVER_NAME,
|
|
10455
|
-
serverConfig:
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
}
|
|
10459
|
-
})
|
|
10584
|
+
serverConfig: getStandardMcpServerConfig()
|
|
10585
|
+
}),
|
|
10586
|
+
projectSetup: getUnsupportedProjectSetup("Hermes Agent project-level MCP config not verified")
|
|
10460
10587
|
};
|
|
10461
10588
|
var agentDefinitions = [
|
|
10462
10589
|
claudeCode,
|
|
@@ -10472,7 +10599,7 @@ var agentDefinitions = [
|
|
|
10472
10599
|
openCode,
|
|
10473
10600
|
hermesAgent
|
|
10474
10601
|
];
|
|
10475
|
-
async function scanSingleAgent(agent, fs, execService) {
|
|
10602
|
+
async function scanSingleAgent(agent, fs, execService, scope) {
|
|
10476
10603
|
let detected = false;
|
|
10477
10604
|
let setupContext;
|
|
10478
10605
|
if (agent.detectCommand) {
|
|
@@ -10523,7 +10650,14 @@ async function scanSingleAgent(agent, fs, execService) {
|
|
|
10523
10650
|
if (!detected) {
|
|
10524
10651
|
return { status: "not_detected", agent };
|
|
10525
10652
|
}
|
|
10526
|
-
const config = agent
|
|
10653
|
+
const config = getAgentSetupConfig(agent, fs, scope, setupContext);
|
|
10654
|
+
if (!config) {
|
|
10655
|
+
return {
|
|
10656
|
+
status: "unsupported",
|
|
10657
|
+
agent,
|
|
10658
|
+
reason: getProjectSetupUnsupportedReason(agent) ?? "project-level MCP config not verified"
|
|
10659
|
+
};
|
|
10660
|
+
}
|
|
10527
10661
|
const scannedAgent = {
|
|
10528
10662
|
...agent,
|
|
10529
10663
|
resolvedSetupConfig: config,
|
|
@@ -10552,10 +10686,11 @@ async function scanAgents(definitions, fs, execService, options = {}) {
|
|
|
10552
10686
|
const result = {
|
|
10553
10687
|
needsSetup: [],
|
|
10554
10688
|
alreadyConfigured: [],
|
|
10555
|
-
notDetected: []
|
|
10689
|
+
notDetected: [],
|
|
10690
|
+
unsupported: []
|
|
10556
10691
|
};
|
|
10557
10692
|
let completed = 0;
|
|
10558
|
-
const outcomes = await Promise.all(definitions.map((agent) => scanSingleAgent(agent, fs, execService).then((outcome) => {
|
|
10693
|
+
const outcomes = await Promise.all(definitions.map((agent) => scanSingleAgent(agent, fs, execService, options.scope ?? "user").then((outcome) => {
|
|
10559
10694
|
completed += 1;
|
|
10560
10695
|
options.onProgress?.({
|
|
10561
10696
|
completed,
|
|
@@ -10569,6 +10704,11 @@ async function scanAgents(definitions, fs, execService, options = {}) {
|
|
|
10569
10704
|
result.alreadyConfigured.push(outcome.agent);
|
|
10570
10705
|
} else if (outcome.status === "needs_setup") {
|
|
10571
10706
|
result.needsSetup.push(outcome.agent);
|
|
10707
|
+
} else if (outcome.status === "unsupported") {
|
|
10708
|
+
result.unsupported.push({
|
|
10709
|
+
agent: outcome.agent,
|
|
10710
|
+
reason: outcome.reason
|
|
10711
|
+
});
|
|
10572
10712
|
} else {
|
|
10573
10713
|
result.notDetected.push(outcome.agent);
|
|
10574
10714
|
}
|
|
@@ -10594,6 +10734,9 @@ function createInitLoginOutput() {
|
|
|
10594
10734
|
function getResolvedSetupConfig(agent, fileSystemService) {
|
|
10595
10735
|
return agent.resolvedSetupConfig ?? agent.getSetupConfig(fileSystemService, agent.resolvedSetupContext);
|
|
10596
10736
|
}
|
|
10737
|
+
function getLegacyProjectSetupStatePath(fileSystemService) {
|
|
10738
|
+
return fileSystemService.joinPath(fileSystemService.getCwd(), ".githits", "init", "project-setup.json");
|
|
10739
|
+
}
|
|
10597
10740
|
function getPiConfigFileUninstall(agent, fileSystemService) {
|
|
10598
10741
|
if (agent.id !== "pi") {
|
|
10599
10742
|
return null;
|
|
@@ -10609,13 +10752,27 @@ function formatCommand(command, useColors) {
|
|
|
10609
10752
|
return colorizeBrand(command, "secondary", useColors, { bold: true });
|
|
10610
10753
|
}
|
|
10611
10754
|
var AGENT_SAFE_CLI = "npx -y githits@latest";
|
|
10612
|
-
var AGENT_DETECT_COMMAND = `${AGENT_SAFE_CLI} init --detect-agents`;
|
|
10613
|
-
var AGENT_INSTALL_COMMAND = `${AGENT_SAFE_CLI} init --install-agents`;
|
|
10614
10755
|
var AGENT_LOGIN_COMMAND = `${AGENT_SAFE_CLI} login`;
|
|
10615
10756
|
var AGENT_LOGIN_NO_BROWSER_COMMAND = `${AGENT_SAFE_CLI} login --no-browser`;
|
|
10616
10757
|
var AGENTIC_INIT_YES_WARNING = "Do not run `githits init -y` or `githits init --yes` unless the user explicitly asks to configure every detected tool.";
|
|
10617
|
-
|
|
10618
|
-
|
|
10758
|
+
function getAgentDetectCommand(scope) {
|
|
10759
|
+
return `${AGENT_SAFE_CLI} init ${scope === "project" ? "--project " : ""}--detect-agents`;
|
|
10760
|
+
}
|
|
10761
|
+
function getAgentInstallCommand(scope) {
|
|
10762
|
+
return `${AGENT_SAFE_CLI} init ${scope === "project" ? "--project " : ""}--install-agents`;
|
|
10763
|
+
}
|
|
10764
|
+
function getAgenticVerifyCommand(scope) {
|
|
10765
|
+
return `${getAgentDetectCommand(scope)} --json`;
|
|
10766
|
+
}
|
|
10767
|
+
function getAgenticVerifyInstruction(scope) {
|
|
10768
|
+
return `After a successful --install-agents run, verify with ${getAgenticVerifyCommand(scope)} instead of running init again.`;
|
|
10769
|
+
}
|
|
10770
|
+
function getAgenticJsonVerifyInstruction(scope) {
|
|
10771
|
+
return `Do not run init again after a successful --install-agents run; verify with ${getAgenticVerifyCommand(scope)} instead.`;
|
|
10772
|
+
}
|
|
10773
|
+
function formatInstallCommand(ids, scope) {
|
|
10774
|
+
return `${getAgentInstallCommand(scope)} ${ids.join(",")}`;
|
|
10775
|
+
}
|
|
10619
10776
|
function printReadyNextSteps() {
|
|
10620
10777
|
console.log(" GitHits is now connected to your coding agents.");
|
|
10621
10778
|
console.log();
|
|
@@ -10648,6 +10805,22 @@ function printAuthNotCheckedNextSteps(useColors) {
|
|
|
10648
10805
|
console.log(" If your agent asks you to sign in, run:");
|
|
10649
10806
|
console.log(` ${formatCommand("npx githits@latest login", useColors)}`);
|
|
10650
10807
|
}
|
|
10808
|
+
function printProjectAuthRequiredNextSteps(useColors) {
|
|
10809
|
+
console.log(" GitHits MCP is configured for this project, but sign-in is still needed.");
|
|
10810
|
+
console.log();
|
|
10811
|
+
console.log(" Open an MCP-compatible coding agent in this project so it loads the project config.");
|
|
10812
|
+
console.log();
|
|
10813
|
+
console.log(" Sign in when you're ready:");
|
|
10814
|
+
console.log(` ${formatCommand("npx githits@latest login", useColors)}`);
|
|
10815
|
+
}
|
|
10816
|
+
function printProjectAuthNotCheckedNextSteps(useColors) {
|
|
10817
|
+
console.log(" GitHits MCP is configured for this project. Sign-in was not checked.");
|
|
10818
|
+
console.log();
|
|
10819
|
+
console.log(" Open an MCP-compatible coding agent in this project so it loads the project config.");
|
|
10820
|
+
console.log();
|
|
10821
|
+
console.log(" If your agent asks you to sign in, run:");
|
|
10822
|
+
console.log(` ${formatCommand("npx githits@latest login", useColors)}`);
|
|
10823
|
+
}
|
|
10651
10824
|
function printAgenticLoginInstructions(useColors) {
|
|
10652
10825
|
console.log(" Authentication is still required before agents can use GitHits.");
|
|
10653
10826
|
console.log();
|
|
@@ -10678,25 +10851,38 @@ function printNonInteractiveInitGuidance(useColors) {
|
|
|
10678
10851
|
console.log();
|
|
10679
10852
|
console.log(" If you are an AI coding agent helping a user install GitHits:");
|
|
10680
10853
|
console.log();
|
|
10681
|
-
console.log(" 1.
|
|
10682
|
-
console.log(
|
|
10854
|
+
console.log(" 1. Ask the user whether GitHits should be installed for:");
|
|
10855
|
+
console.log(" - this user account on this machine, or");
|
|
10856
|
+
console.log(" - only this project/repo via project-local MCP files.");
|
|
10857
|
+
console.log();
|
|
10858
|
+
console.log(" 2. For user-level install, run:");
|
|
10859
|
+
console.log(` ${formatCommand(getAgentDetectCommand("user"), useColors)}`);
|
|
10683
10860
|
console.log();
|
|
10684
|
-
console.log("
|
|
10861
|
+
console.log(" For project-level install, run:");
|
|
10862
|
+
console.log(` ${formatCommand(getAgentDetectCommand("project"), useColors)}`);
|
|
10685
10863
|
console.log();
|
|
10686
|
-
console.log(" 3.
|
|
10864
|
+
console.log(" 3. Show the detected tools to the user.");
|
|
10687
10865
|
console.log();
|
|
10688
|
-
console.log(" 4.
|
|
10689
|
-
console.log(
|
|
10866
|
+
console.log(" 4. Ask which tools should receive the GitHits MCP server.");
|
|
10867
|
+
console.log();
|
|
10868
|
+
console.log(" For project-level install, explain that config files are written into this repo and may be committed.");
|
|
10869
|
+
console.log();
|
|
10870
|
+
console.log(" 5. Only after approval, run the matching install command:");
|
|
10871
|
+
console.log(` ${formatCommand(`${getAgentInstallCommand("user")} <ids>`, useColors)}`);
|
|
10872
|
+
console.log(` ${formatCommand(`${getAgentInstallCommand("project")} <ids>`, useColors)}`);
|
|
10690
10873
|
console.log();
|
|
10691
10874
|
console.log(` ${AGENTIC_INIT_YES_WARNING}`);
|
|
10692
|
-
console.log(` ${
|
|
10875
|
+
console.log(` ${getAgenticVerifyInstruction("user")}`);
|
|
10876
|
+
console.log(` ${getAgenticVerifyInstruction("project")}`);
|
|
10693
10877
|
}
|
|
10694
10878
|
function printNonInteractiveYesRejected(useColors) {
|
|
10695
10879
|
console.error("Non-interactive `githits init --yes` is not supported because it can configure tools without explicit per-tool approval.");
|
|
10696
10880
|
console.error();
|
|
10697
10881
|
console.error("Use the agent-safe staged flow instead:");
|
|
10698
|
-
console.error(` ${formatCommand(
|
|
10699
|
-
console.error(` ${formatCommand(`${
|
|
10882
|
+
console.error(` ${formatCommand(getAgentDetectCommand("user"), useColors)}`);
|
|
10883
|
+
console.error(` ${formatCommand(`${getAgentInstallCommand("user")} <ids>`, useColors)}`);
|
|
10884
|
+
console.error(` ${formatCommand(getAgentDetectCommand("project"), useColors)}`);
|
|
10885
|
+
console.error(` ${formatCommand(`${getAgentInstallCommand("project")} <ids>`, useColors)}`);
|
|
10700
10886
|
process.exitCode = 1;
|
|
10701
10887
|
}
|
|
10702
10888
|
var GITHITS_ASCII_LOGO = String.raw`
|
|
@@ -10787,6 +10973,30 @@ var INIT_INTENT_CHOICES = [
|
|
|
10787
10973
|
description: "Leave setup without making changes."
|
|
10788
10974
|
}
|
|
10789
10975
|
];
|
|
10976
|
+
var INIT_SCOPE_CHOICES = [
|
|
10977
|
+
{
|
|
10978
|
+
name: "User-level config",
|
|
10979
|
+
value: "user",
|
|
10980
|
+
description: "Configure GitHits for your detected tools on this machine."
|
|
10981
|
+
},
|
|
10982
|
+
{
|
|
10983
|
+
name: "Project-level config",
|
|
10984
|
+
value: "project",
|
|
10985
|
+
description: "Configure project-local MCP files for tools that support workspace config."
|
|
10986
|
+
}
|
|
10987
|
+
];
|
|
10988
|
+
var INIT_UNINSTALL_SCOPE_CHOICES = [
|
|
10989
|
+
{
|
|
10990
|
+
name: "User-level config",
|
|
10991
|
+
value: "user",
|
|
10992
|
+
description: "Remove GitHits from detected tools on this machine."
|
|
10993
|
+
},
|
|
10994
|
+
{
|
|
10995
|
+
name: "Project-level config",
|
|
10996
|
+
value: "project",
|
|
10997
|
+
description: "Remove GitHits from supported project-local MCP files."
|
|
10998
|
+
}
|
|
10999
|
+
];
|
|
10790
11000
|
var AUTH_RECOVERY_CHOICES = [
|
|
10791
11001
|
{ name: "Retry sign in", value: "retry" },
|
|
10792
11002
|
{
|
|
@@ -10861,8 +11071,9 @@ function printSkillsInstructions(useColors) {
|
|
|
10861
11071
|
console.log(` ${formatCommand("npx githits@latest login", useColors)}`);
|
|
10862
11072
|
console.log();
|
|
10863
11073
|
}
|
|
10864
|
-
function startSafeInitScan(fileSystemService, execService, onProgress) {
|
|
11074
|
+
function startSafeInitScan(fileSystemService, execService, scope = "user", onProgress) {
|
|
10865
11075
|
return scanAgents(agentDefinitions, fileSystemService, execService, {
|
|
11076
|
+
scope,
|
|
10866
11077
|
onProgress
|
|
10867
11078
|
}).then((scan) => ({ ok: true, scan })).catch((error2) => ({
|
|
10868
11079
|
ok: false,
|
|
@@ -10949,50 +11160,85 @@ function buildInitAgentChoices(scan) {
|
|
|
10949
11160
|
}))
|
|
10950
11161
|
];
|
|
10951
11162
|
}
|
|
10952
|
-
function printScanSummary(scan, useColors) {
|
|
10953
|
-
const detected = scan.needsSetup.length + scan.alreadyConfigured.length;
|
|
11163
|
+
function printScanSummary(scan, useColors, scope = "user") {
|
|
11164
|
+
const detected = scan.needsSetup.length + scan.alreadyConfigured.length + scan.unsupported.length;
|
|
11165
|
+
const projectSupported = scan.needsSetup.length + scan.alreadyConfigured.length;
|
|
10954
11166
|
for (const agent of scan.alreadyConfigured) {
|
|
10955
11167
|
printTask("success", agent.name, "already configured", useColors);
|
|
10956
11168
|
}
|
|
10957
11169
|
for (const agent of scan.needsSetup) {
|
|
10958
11170
|
printTask("warning", agent.name, "needs setup", useColors);
|
|
10959
11171
|
}
|
|
11172
|
+
for (const { agent, reason } of scan.unsupported) {
|
|
11173
|
+
printTask("skipped", agent.name, scope === "project" ? "no project-level config" : reason, useColors);
|
|
11174
|
+
}
|
|
10960
11175
|
if (scan.notDetected.length > 0) {
|
|
10961
11176
|
printTask("skipped", `${scan.notDetected.length} supported tool${scan.notDetected.length !== 1 ? "s" : ""} not found`, formatAgentNames(scan.notDetected), useColors);
|
|
10962
11177
|
}
|
|
10963
11178
|
if (detected > 0) {
|
|
10964
11179
|
console.log();
|
|
10965
|
-
|
|
11180
|
+
if (scope === "project") {
|
|
11181
|
+
console.log(` Found ${detected} tool${detected !== 1 ? "s" : ""}. ${projectSupported} support${projectSupported === 1 ? "s" : ""} project-level config.`);
|
|
11182
|
+
} else {
|
|
11183
|
+
console.log(` Found ${detected} supported tool${detected !== 1 ? "s" : ""}.`);
|
|
11184
|
+
}
|
|
10966
11185
|
}
|
|
10967
11186
|
}
|
|
11187
|
+
function printProjectScopeExplanation(useColors) {
|
|
11188
|
+
console.log();
|
|
11189
|
+
console.log(` ${warning("Project-level config is available for some tools.", useColors)}`);
|
|
11190
|
+
console.log(" Tools without project-level config are shown below but won't be selected.");
|
|
11191
|
+
}
|
|
10968
11192
|
function buildStagedAgentEntries(scan) {
|
|
10969
11193
|
const statuses = new Map;
|
|
10970
|
-
for (const agent of scan.needsSetup)
|
|
10971
|
-
statuses.set(agent.id, "needs_setup");
|
|
11194
|
+
for (const agent of scan.needsSetup) {
|
|
11195
|
+
statuses.set(agent.id, { status: "needs_setup" });
|
|
11196
|
+
}
|
|
10972
11197
|
for (const agent of scan.alreadyConfigured) {
|
|
10973
|
-
statuses.set(agent.id, "already_configured");
|
|
10974
|
-
}
|
|
10975
|
-
for (const agent of scan.notDetected)
|
|
10976
|
-
statuses.set(agent.id, "not_detected");
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
11198
|
+
statuses.set(agent.id, { status: "already_configured" });
|
|
11199
|
+
}
|
|
11200
|
+
for (const agent of scan.notDetected) {
|
|
11201
|
+
statuses.set(agent.id, { status: "not_detected" });
|
|
11202
|
+
}
|
|
11203
|
+
for (const { agent, reason } of scan.unsupported) {
|
|
11204
|
+
statuses.set(agent.id, {
|
|
11205
|
+
status: "unsupported_project_config",
|
|
11206
|
+
reason
|
|
11207
|
+
});
|
|
11208
|
+
}
|
|
11209
|
+
return agentDefinitions.map((agent) => {
|
|
11210
|
+
const entry = statuses.get(agent.id);
|
|
11211
|
+
return {
|
|
11212
|
+
id: agent.id,
|
|
11213
|
+
name: agent.name,
|
|
11214
|
+
status: entry?.status ?? "not_detected",
|
|
11215
|
+
...entry?.reason ? { reason: entry.reason } : {}
|
|
11216
|
+
};
|
|
11217
|
+
});
|
|
10982
11218
|
}
|
|
10983
|
-
function printAgenticDetectSummary(scan, useColors) {
|
|
11219
|
+
function printAgenticDetectSummary(scan, useColors, scope) {
|
|
10984
11220
|
const entries = buildStagedAgentEntries(scan);
|
|
10985
11221
|
const detected = entries.filter((entry) => entry.status !== "not_detected");
|
|
10986
11222
|
const installable = entries.filter((entry) => entry.status === "needs_setup");
|
|
11223
|
+
const unsupported = entries.filter((entry) => entry.status === "unsupported_project_config");
|
|
11224
|
+
const configured = entries.filter((entry) => entry.status === "already_configured");
|
|
10987
11225
|
const notDetected = entries.filter((entry) => entry.status === "not_detected");
|
|
10988
|
-
console.log(
|
|
11226
|
+
console.log(`Detected tools (${scope === "project" ? "project-level" : "user-level"} install):`);
|
|
10989
11227
|
console.log();
|
|
11228
|
+
if (scope === "project") {
|
|
11229
|
+
console.log(" Project-level install writes MCP config files into this repo. These files may be committed.");
|
|
11230
|
+
console.log(" Tools without verified project config are shown as unsupported and cannot be installed with --project.");
|
|
11231
|
+
console.log();
|
|
11232
|
+
}
|
|
10990
11233
|
if (detected.length === 0) {
|
|
10991
11234
|
console.log(" None detected.");
|
|
10992
11235
|
} else {
|
|
10993
11236
|
console.log(" ID Tool Status");
|
|
10994
11237
|
for (const entry of detected) {
|
|
10995
|
-
console.log(` ${entry.id.padEnd(18)} ${entry.name.padEnd(21)} ${entry.status.
|
|
11238
|
+
console.log(` ${entry.id.padEnd(18)} ${entry.name.padEnd(21)} ${entry.status.replaceAll("_", " ")}`);
|
|
11239
|
+
if (entry.status === "unsupported_project_config" && entry.reason) {
|
|
11240
|
+
console.log(` ${"".padEnd(18)} ${"".padEnd(21)} ${entry.reason}`);
|
|
11241
|
+
}
|
|
10996
11242
|
}
|
|
10997
11243
|
}
|
|
10998
11244
|
console.log();
|
|
@@ -11007,12 +11253,25 @@ function printAgenticDetectSummary(scan, useColors) {
|
|
|
11007
11253
|
return;
|
|
11008
11254
|
}
|
|
11009
11255
|
if (installable.length === 0) {
|
|
11256
|
+
if (scope === "project" && unsupported.length > 0) {
|
|
11257
|
+
console.log("No detected tools can be installed with project-level config.");
|
|
11258
|
+
console.log();
|
|
11259
|
+
console.log("Next step for agents:");
|
|
11260
|
+
if (configured.length > 0) {
|
|
11261
|
+
console.log(" Tell the user GitHits is already configured for the detected project-configurable tools.");
|
|
11262
|
+
}
|
|
11263
|
+
console.log(" Tell the user the other detected tools do not have verified project-level MCP support.");
|
|
11264
|
+
console.log(` Offer user-level install with ${getAgentDetectCommand("user")} if they want GitHits for those tools.`);
|
|
11265
|
+
console.log(` ${AGENTIC_INIT_YES_WARNING}`);
|
|
11266
|
+
console.log(` Do not run init again as a verification step; use ${getAgenticVerifyCommand(scope)} if verification is needed.`);
|
|
11267
|
+
return;
|
|
11268
|
+
}
|
|
11010
11269
|
console.log("No detected tools need setup.");
|
|
11011
11270
|
console.log();
|
|
11012
11271
|
console.log("Next step for agents:");
|
|
11013
11272
|
console.log(" Tell the user that GitHits is already configured for detected tools.");
|
|
11014
11273
|
console.log(` ${AGENTIC_INIT_YES_WARNING}`);
|
|
11015
|
-
console.log(
|
|
11274
|
+
console.log(` Do not run init again as a verification step; use ${getAgenticVerifyCommand(scope)} if verification is needed.`);
|
|
11016
11275
|
return;
|
|
11017
11276
|
}
|
|
11018
11277
|
const installableIds = installable.map((entry) => entry.id);
|
|
@@ -11022,27 +11281,86 @@ function printAgenticDetectSummary(scan, useColors) {
|
|
|
11022
11281
|
console.log(` "GitHits can be installed for ${installable.map((entry) => entry.name).join(", ")}. Which should I configure?"`);
|
|
11023
11282
|
console.log();
|
|
11024
11283
|
console.log(" If the user approves all detected tools needing setup, run:");
|
|
11025
|
-
console.log(` ${formatCommand(
|
|
11284
|
+
console.log(` ${formatCommand(formatInstallCommand(installableIds, scope), useColors)}`);
|
|
11285
|
+
if (scope === "project") {
|
|
11286
|
+
console.log();
|
|
11287
|
+
console.log(" Before running it, tell the user this writes project-local MCP files into the current repo and only configures tools with verified project support.");
|
|
11288
|
+
}
|
|
11026
11289
|
console.log();
|
|
11027
11290
|
console.log(` ${AGENTIC_INIT_YES_WARNING}`);
|
|
11028
|
-
console.log(` ${
|
|
11291
|
+
console.log(` ${getAgenticVerifyInstruction(scope)}`);
|
|
11029
11292
|
}
|
|
11030
|
-
function printAgenticDetectJson(scan) {
|
|
11293
|
+
function printAgenticDetectJson(scan, scope) {
|
|
11031
11294
|
const entries = buildStagedAgentEntries(scan);
|
|
11032
11295
|
const installableIds = entries.filter((entry) => entry.status === "needs_setup").map((entry) => entry.id);
|
|
11296
|
+
const detected = entries.filter((entry) => entry.status !== "not_detected");
|
|
11297
|
+
const configured = entries.filter((entry) => entry.status === "already_configured");
|
|
11298
|
+
const unsupported = entries.filter((entry) => entry.status === "unsupported_project_config");
|
|
11299
|
+
const instructions = buildAgenticDetectJsonInstructions({
|
|
11300
|
+
scope,
|
|
11301
|
+
detectedCount: detected.length,
|
|
11302
|
+
installableCount: installableIds.length,
|
|
11303
|
+
configuredCount: configured.length,
|
|
11304
|
+
unsupportedCount: unsupported.length
|
|
11305
|
+
});
|
|
11033
11306
|
console.log(JSON.stringify({
|
|
11034
11307
|
mode: "detect-agents",
|
|
11308
|
+
scope,
|
|
11035
11309
|
agents: entries,
|
|
11036
11310
|
installableIds,
|
|
11037
|
-
suggestedCommand: installableIds.length > 0 ?
|
|
11038
|
-
instructions
|
|
11311
|
+
suggestedCommand: installableIds.length > 0 ? formatInstallCommand(installableIds, scope) : null,
|
|
11312
|
+
instructions
|
|
11313
|
+
}, null, 2));
|
|
11314
|
+
}
|
|
11315
|
+
function buildAgenticDetectJsonInstructions(input) {
|
|
11316
|
+
const {
|
|
11317
|
+
scope,
|
|
11318
|
+
detectedCount,
|
|
11319
|
+
installableCount,
|
|
11320
|
+
configuredCount,
|
|
11321
|
+
unsupportedCount
|
|
11322
|
+
} = input;
|
|
11323
|
+
if (detectedCount === 0) {
|
|
11324
|
+
return [
|
|
11325
|
+
"No supported AI coding tools were detected.",
|
|
11326
|
+
"Tell the user to install a supported coding tool, then run detection again."
|
|
11327
|
+
];
|
|
11328
|
+
}
|
|
11329
|
+
if (installableCount === 0) {
|
|
11330
|
+
if (scope === "project" && unsupportedCount > 0) {
|
|
11331
|
+
return [
|
|
11332
|
+
"Show detected tools to the user.",
|
|
11333
|
+
...configuredCount > 0 ? [
|
|
11334
|
+
"Explain that GitHits is already configured for detected project-configurable tools."
|
|
11335
|
+
] : [
|
|
11336
|
+
"Explain that no detected tools have verified project-level MCP support."
|
|
11337
|
+
],
|
|
11338
|
+
"Explain that tools with unsupported_project_config status cannot be installed with --project.",
|
|
11339
|
+
"Do not ask the user to choose project install IDs.",
|
|
11340
|
+
`Offer user-level detection with ${getAgentDetectCommand("user")} if they want GitHits for unsupported project tools.`,
|
|
11341
|
+
AGENTIC_INIT_YES_WARNING,
|
|
11342
|
+
getAgenticJsonVerifyInstruction(scope)
|
|
11343
|
+
];
|
|
11344
|
+
}
|
|
11345
|
+
return [
|
|
11039
11346
|
"Show detected tools to the user.",
|
|
11040
|
-
"
|
|
11041
|
-
"
|
|
11347
|
+
"Tell the user that GitHits is already configured for detected tools.",
|
|
11348
|
+
"Do not ask the user to choose install IDs.",
|
|
11042
11349
|
AGENTIC_INIT_YES_WARNING,
|
|
11043
|
-
|
|
11044
|
-
]
|
|
11045
|
-
}
|
|
11350
|
+
getAgenticJsonVerifyInstruction(scope)
|
|
11351
|
+
];
|
|
11352
|
+
}
|
|
11353
|
+
return [
|
|
11354
|
+
"Show detected tools to the user.",
|
|
11355
|
+
...scope === "project" ? [
|
|
11356
|
+
"Explain that project-level install writes MCP config files into the current repo and those files may be committed.",
|
|
11357
|
+
"Do not offer agent IDs with unsupported_project_config status for project install."
|
|
11358
|
+
] : [],
|
|
11359
|
+
"Ask which tools should receive the GitHits MCP server.",
|
|
11360
|
+
"Only run --install-agents with user-approved IDs.",
|
|
11361
|
+
AGENTIC_INIT_YES_WARNING,
|
|
11362
|
+
getAgenticJsonVerifyInstruction(scope)
|
|
11363
|
+
];
|
|
11046
11364
|
}
|
|
11047
11365
|
function getStagedModeCount(options) {
|
|
11048
11366
|
return [
|
|
@@ -11086,8 +11404,10 @@ function findAgentsByIds(scan, ids) {
|
|
|
11086
11404
|
}
|
|
11087
11405
|
function validateInstallAgentIds(scan, ids) {
|
|
11088
11406
|
const supportedIds = new Set(agentDefinitions.map((agent) => agent.id));
|
|
11089
|
-
const
|
|
11407
|
+
const installableAgents = [...scan.needsSetup, ...scan.alreadyConfigured];
|
|
11408
|
+
const detectedIds = installableAgents.map((agent) => agent.id);
|
|
11090
11409
|
const detectedIdSet = new Set(detectedIds);
|
|
11410
|
+
const unsupported = new Map(scan.unsupported.map(({ agent, reason }) => [agent.id, reason]));
|
|
11091
11411
|
if (ids.length === 0) {
|
|
11092
11412
|
return {
|
|
11093
11413
|
ok: false,
|
|
@@ -11103,6 +11423,15 @@ function validateInstallAgentIds(scan, ids) {
|
|
|
11103
11423
|
detectedIds
|
|
11104
11424
|
};
|
|
11105
11425
|
}
|
|
11426
|
+
const unsupportedIds = ids.filter((id) => unsupported.has(id));
|
|
11427
|
+
if (unsupportedIds.length > 0) {
|
|
11428
|
+
const details = unsupportedIds.map((id) => `${id}: ${unsupported.get(id)}`).join("; ");
|
|
11429
|
+
return {
|
|
11430
|
+
ok: false,
|
|
11431
|
+
message: `Agent ID${unsupportedIds.length !== 1 ? "s" : ""} cannot use project-level install: ${details}.`,
|
|
11432
|
+
detectedIds
|
|
11433
|
+
};
|
|
11434
|
+
}
|
|
11106
11435
|
const undetected = ids.filter((id) => !detectedIdSet.has(id));
|
|
11107
11436
|
if (undetected.length > 0) {
|
|
11108
11437
|
return {
|
|
@@ -11125,6 +11454,17 @@ function printInstallValidationFailure(failure, json) {
|
|
|
11125
11454
|
}
|
|
11126
11455
|
process.exitCode = 1;
|
|
11127
11456
|
}
|
|
11457
|
+
function failUnknownInitAction(action) {
|
|
11458
|
+
failInitArgument(`Unknown init action: ${action}. Use "githits init uninstall" to remove GitHits MCP config.`, false);
|
|
11459
|
+
}
|
|
11460
|
+
async function resolveProjectSetupScope(options, fileSystemService) {
|
|
11461
|
+
const projectPath = fileSystemService.getCwd();
|
|
11462
|
+
if (!await fileSystemService.isDirectory(projectPath)) {
|
|
11463
|
+
failInitArgument(`Current directory does not exist or is not a directory: ${projectPath}`, options.json);
|
|
11464
|
+
return null;
|
|
11465
|
+
}
|
|
11466
|
+
return { projectPath };
|
|
11467
|
+
}
|
|
11128
11468
|
function hasUsableInstallOutcome(outcomes) {
|
|
11129
11469
|
return outcomes.some((outcome) => outcome.status === "success" || outcome.status === "already_configured");
|
|
11130
11470
|
}
|
|
@@ -11162,46 +11502,54 @@ function buildAgenticInstallAuthPayload(authStatus) {
|
|
|
11162
11502
|
noBrowserCommand: AGENT_LOGIN_NO_BROWSER_COMMAND
|
|
11163
11503
|
};
|
|
11164
11504
|
}
|
|
11165
|
-
function buildAgenticInstallInstructions(authStatus) {
|
|
11505
|
+
function buildAgenticInstallInstructions(authStatus, scope) {
|
|
11166
11506
|
if (authStatus === "authenticated") {
|
|
11167
|
-
return [
|
|
11507
|
+
return [
|
|
11508
|
+
scope === "project" ? "Open a new coding agent session in this project so it reloads project MCP config." : "Open a new coding agent session so it reloads MCP config.",
|
|
11509
|
+
getAgenticJsonVerifyInstruction(scope)
|
|
11510
|
+
];
|
|
11168
11511
|
}
|
|
11169
11512
|
if (authStatus === "required") {
|
|
11170
11513
|
return [
|
|
11171
11514
|
`Ask the user before running ${AGENT_LOGIN_COMMAND}.`,
|
|
11172
11515
|
"Browser sign-in happens outside chat and terminal input.",
|
|
11173
|
-
"Do not ask the user to paste passwords, tokens, cookies, or OAuth codes into chat."
|
|
11516
|
+
"Do not ask the user to paste passwords, tokens, cookies, or OAuth codes into chat.",
|
|
11517
|
+
getAgenticJsonVerifyInstruction(scope)
|
|
11174
11518
|
];
|
|
11175
11519
|
}
|
|
11176
11520
|
return [
|
|
11177
11521
|
"Sign-in status was not checked.",
|
|
11178
|
-
`If the user is not already signed in, ask before running ${AGENT_LOGIN_COMMAND}
|
|
11522
|
+
`If the user is not already signed in, ask before running ${AGENT_LOGIN_COMMAND}.`,
|
|
11523
|
+
getAgenticJsonVerifyInstruction(scope)
|
|
11179
11524
|
];
|
|
11180
11525
|
}
|
|
11181
|
-
function printAgenticInstallJson(outcomes, authStatus) {
|
|
11526
|
+
function printAgenticInstallJson(outcomes, authStatus, scope) {
|
|
11182
11527
|
const canAuthenticate = hasUsableInstallOutcome(outcomes);
|
|
11183
11528
|
console.log(JSON.stringify({
|
|
11184
11529
|
mode: "install-agents",
|
|
11530
|
+
scope,
|
|
11185
11531
|
outcomes,
|
|
11186
11532
|
auth: canAuthenticate ? buildAgenticInstallAuthPayload(authStatus) : {
|
|
11187
11533
|
required: false,
|
|
11188
11534
|
status: "not_applicable",
|
|
11189
11535
|
reason: "Fix installation errors before starting sign-in."
|
|
11190
11536
|
},
|
|
11191
|
-
instructions: canAuthenticate ? buildAgenticInstallInstructions(authStatus) : ["Fix installation errors before asking the user to sign in."]
|
|
11537
|
+
instructions: canAuthenticate ? buildAgenticInstallInstructions(authStatus, scope) : ["Fix installation errors before asking the user to sign in."]
|
|
11192
11538
|
}, null, 2));
|
|
11193
11539
|
}
|
|
11194
11540
|
async function runDetectAgentsMode(options, fileSystemService, execService, useColors) {
|
|
11195
|
-
const
|
|
11541
|
+
const scope = options.project ? "project" : "user";
|
|
11542
|
+
const scan = await scanAgents(agentDefinitions, fileSystemService, execService, { scope });
|
|
11196
11543
|
if (options.json) {
|
|
11197
|
-
printAgenticDetectJson(scan);
|
|
11544
|
+
printAgenticDetectJson(scan, scope);
|
|
11198
11545
|
return;
|
|
11199
11546
|
}
|
|
11200
|
-
printAgenticDetectSummary(scan, useColors);
|
|
11547
|
+
printAgenticDetectSummary(scan, useColors, scope);
|
|
11201
11548
|
}
|
|
11202
11549
|
async function runInstallAgentsMode(options, fileSystemService, execService, createLoginDeps, useColors) {
|
|
11550
|
+
const scope = options.project ? "project" : "user";
|
|
11203
11551
|
const requestedIds = parseAgentIdList(options.installAgents);
|
|
11204
|
-
const scan = await scanAgents(agentDefinitions, fileSystemService, execService);
|
|
11552
|
+
const scan = await scanAgents(agentDefinitions, fileSystemService, execService, { scope });
|
|
11205
11553
|
const validation = validateInstallAgentIds(scan, requestedIds);
|
|
11206
11554
|
if (!validation.ok) {
|
|
11207
11555
|
printInstallValidationFailure(validation, options.json);
|
|
@@ -11212,7 +11560,7 @@ async function runInstallAgentsMode(options, fileSystemService, execService, cre
|
|
|
11212
11560
|
console.log("Installing GitHits MCP:");
|
|
11213
11561
|
console.log();
|
|
11214
11562
|
}
|
|
11215
|
-
const outcomes = await installSelectedAgents(agents, scan, fileSystemService, execService, useColors, !options.json);
|
|
11563
|
+
const outcomes = await installSelectedAgents(agents, scan, fileSystemService, execService, useColors, !options.json, scope);
|
|
11216
11564
|
const failed = outcomes.filter((outcome) => outcome.status === "failed");
|
|
11217
11565
|
const canAuthenticate = hasUsableInstallOutcome(outcomes);
|
|
11218
11566
|
const authStatus = canAuthenticate ? await getStagedInstallAuthStatus(createLoginDeps) : "not_checked";
|
|
@@ -11220,7 +11568,7 @@ async function runInstallAgentsMode(options, fileSystemService, execService, cre
|
|
|
11220
11568
|
process.exitCode = 1;
|
|
11221
11569
|
}
|
|
11222
11570
|
if (options.json) {
|
|
11223
|
-
printAgenticInstallJson(outcomes, authStatus);
|
|
11571
|
+
printAgenticInstallJson(outcomes, authStatus, scope);
|
|
11224
11572
|
return;
|
|
11225
11573
|
}
|
|
11226
11574
|
console.log();
|
|
@@ -11235,12 +11583,19 @@ async function runInstallAgentsMode(options, fileSystemService, execService, cre
|
|
|
11235
11583
|
console.log();
|
|
11236
11584
|
if (canAuthenticate) {
|
|
11237
11585
|
if (authStatus === "authenticated") {
|
|
11238
|
-
|
|
11586
|
+
if (scope === "project") {
|
|
11587
|
+
console.log(" GitHits MCP is installed for this project and you are already signed in.");
|
|
11588
|
+
console.log();
|
|
11589
|
+
console.log(" Open a new coding agent session in this project so it reloads project MCP config.");
|
|
11590
|
+
} else {
|
|
11591
|
+
printAgenticAlreadyAuthenticated();
|
|
11592
|
+
}
|
|
11239
11593
|
} else if (authStatus === "required") {
|
|
11240
11594
|
printAgenticLoginInstructions(useColors);
|
|
11241
11595
|
} else {
|
|
11242
11596
|
printAgenticAuthNotChecked(useColors);
|
|
11243
11597
|
}
|
|
11598
|
+
console.log(` ${getAgenticVerifyInstruction(scope)}`);
|
|
11244
11599
|
} else {
|
|
11245
11600
|
console.log("Fix installation errors before starting sign-in.");
|
|
11246
11601
|
}
|
|
@@ -11355,66 +11710,460 @@ function printPostSetupNextSteps(authStatus, useColors) {
|
|
|
11355
11710
|
printAuthNotCheckedNextSteps(useColors);
|
|
11356
11711
|
}
|
|
11357
11712
|
}
|
|
11358
|
-
|
|
11359
|
-
|
|
11360
|
-
if (
|
|
11361
|
-
|
|
11713
|
+
function printProjectNextSteps(authStatus, useColors) {
|
|
11714
|
+
printSection(5, shouldPrintReady(authStatus) ? "Ready" : "Next Steps", useColors);
|
|
11715
|
+
if (shouldPrintReady(authStatus)) {
|
|
11716
|
+
printReadyNextSteps();
|
|
11717
|
+
} else if (authStatus === "failed_continue") {
|
|
11718
|
+
printProjectAuthRequiredNextSteps(useColors);
|
|
11719
|
+
} else {
|
|
11720
|
+
printProjectAuthNotCheckedNextSteps(useColors);
|
|
11362
11721
|
}
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11722
|
+
}
|
|
11723
|
+
function printScopedNextSteps(scope, authStatus, useColors) {
|
|
11724
|
+
if (scope === "project") {
|
|
11725
|
+
printProjectNextSteps(authStatus, useColors);
|
|
11726
|
+
return;
|
|
11368
11727
|
}
|
|
11369
|
-
|
|
11370
|
-
ok: false,
|
|
11371
|
-
message: `${agent.name} verification failed: agent not detected after setup.`
|
|
11372
|
-
};
|
|
11728
|
+
printPostSetupNextSteps(authStatus, useColors);
|
|
11373
11729
|
}
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
if (result.status === "success" || result.status === "already_configured") {
|
|
11378
|
-
const verification = await verifyAgentConfigured(agent, fileSystemService, execService);
|
|
11379
|
-
if (!verification.ok) {
|
|
11380
|
-
result = {
|
|
11381
|
-
status: "failed",
|
|
11382
|
-
message: agent.id === "gemini-cli" ? "Gemini installation did not complete. Retry, or run: gemini extensions install --consent https://github.com/githits-com/githits-cli" : verification.message ?? `${agent.name} verification failed after setup.`
|
|
11383
|
-
};
|
|
11384
|
-
}
|
|
11730
|
+
function getConfigFileSetups(setup) {
|
|
11731
|
+
if (setup.method === "config-file") {
|
|
11732
|
+
return [setup];
|
|
11385
11733
|
}
|
|
11386
|
-
|
|
11734
|
+
if (setup.method === "composite") {
|
|
11735
|
+
return setup.steps.filter((step) => step.method === "config-file");
|
|
11736
|
+
}
|
|
11737
|
+
return [];
|
|
11387
11738
|
}
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11739
|
+
function getTomlSetups(setup) {
|
|
11740
|
+
return getConfigFileSetups(setup).filter((step) => step.format === "toml");
|
|
11741
|
+
}
|
|
11742
|
+
async function hasExistingConfigContent(config, fileSystemService) {
|
|
11743
|
+
try {
|
|
11744
|
+
return (await fileSystemService.readFile(config.configPath)).trim().length > 0;
|
|
11745
|
+
} catch {
|
|
11746
|
+
return false;
|
|
11747
|
+
}
|
|
11748
|
+
}
|
|
11749
|
+
async function printTomlRewriteWarnings(agents, fileSystemService, useColors) {
|
|
11750
|
+
const seen = new Set;
|
|
11392
11751
|
for (const agent of agents) {
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
}
|
|
11402
|
-
continue;
|
|
11403
|
-
}
|
|
11404
|
-
const finishTask = printResults ? installTasks.start(agent.name) : () => {};
|
|
11405
|
-
let result;
|
|
11406
|
-
try {
|
|
11407
|
-
result = await executeAgentSetupWithVerification(agent, fileSystemService, execService);
|
|
11408
|
-
} finally {
|
|
11409
|
-
finishTask();
|
|
11752
|
+
const setup = getResolvedSetupConfig(agent, fileSystemService);
|
|
11753
|
+
for (const config of getTomlSetups(setup)) {
|
|
11754
|
+
if (seen.has(config.configPath))
|
|
11755
|
+
continue;
|
|
11756
|
+
if (!await hasExistingConfigContent(config, fileSystemService))
|
|
11757
|
+
continue;
|
|
11758
|
+
seen.add(config.configPath);
|
|
11759
|
+
printTask("warning", config.configPath, "existing TOML comments/formatting will not be preserved", useColors);
|
|
11410
11760
|
}
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11761
|
+
}
|
|
11762
|
+
}
|
|
11763
|
+
async function getProjectUninstallPlan(fileSystemService) {
|
|
11764
|
+
const seenConfig = new Set;
|
|
11765
|
+
const plan = {
|
|
11766
|
+
configRemovals: []
|
|
11767
|
+
};
|
|
11768
|
+
for (const agent of agentDefinitions) {
|
|
11769
|
+
const setup = getAgentSetupConfig(agent, fileSystemService, "project");
|
|
11770
|
+
if (!setup)
|
|
11771
|
+
continue;
|
|
11772
|
+
for (const configSetup of getConfigFileSetups(setup)) {
|
|
11773
|
+
const key = `${configSetup.configPath}\x00${configSetup.serversKey}\x00${configSetup.serverName.toLowerCase()}`;
|
|
11774
|
+
if (seenConfig.has(key))
|
|
11775
|
+
continue;
|
|
11776
|
+
seenConfig.add(key);
|
|
11777
|
+
plan.configRemovals.push(configSetup);
|
|
11778
|
+
}
|
|
11779
|
+
}
|
|
11780
|
+
return plan;
|
|
11781
|
+
}
|
|
11782
|
+
async function cleanupLegacyProjectSetupState(fileSystemService) {
|
|
11783
|
+
const statePath = getLegacyProjectSetupStatePath(fileSystemService);
|
|
11784
|
+
try {
|
|
11785
|
+
if (!await fileSystemService.exists(statePath)) {
|
|
11786
|
+
return { removed: [], failed: [] };
|
|
11787
|
+
}
|
|
11788
|
+
await fileSystemService.deleteFile(statePath);
|
|
11789
|
+
return { removed: [statePath], failed: [] };
|
|
11790
|
+
} catch (err) {
|
|
11791
|
+
return {
|
|
11792
|
+
removed: [],
|
|
11793
|
+
failed: [
|
|
11794
|
+
{
|
|
11795
|
+
path: statePath,
|
|
11796
|
+
reason: `Could not remove legacy project setup marker: ${err instanceof Error ? err.message : String(err)}`
|
|
11797
|
+
}
|
|
11798
|
+
]
|
|
11799
|
+
};
|
|
11800
|
+
}
|
|
11801
|
+
}
|
|
11802
|
+
function printProjectUninstallSummary(summary) {
|
|
11803
|
+
const totalRemoved = summary.removed.length + summary.legacyRemoved.length;
|
|
11804
|
+
console.log();
|
|
11805
|
+
if (summary.failed.length === 0) {
|
|
11806
|
+
if (summary.removed.length > 0) {
|
|
11807
|
+
console.log(" Done! GitHits MCP configuration was removed from this project.");
|
|
11808
|
+
} else if (summary.legacyRemoved.length > 0) {
|
|
11809
|
+
console.log(" Done! Removed legacy GitHits project setup marker. No project MCP config entries were found.");
|
|
11810
|
+
} else {
|
|
11811
|
+
console.log(" No project GitHits MCP configuration found.");
|
|
11812
|
+
}
|
|
11813
|
+
} else {
|
|
11814
|
+
console.log(" Project uninstall completed with errors.");
|
|
11815
|
+
}
|
|
11816
|
+
console.log(` Removed ${totalRemoved} item${totalRemoved !== 1 ? "s" : ""}. Skipped ${summary.skipped.length} config path${summary.skipped.length !== 1 ? "s" : ""} without GitHits.`);
|
|
11817
|
+
if (summary.failed.length > 0) {
|
|
11818
|
+
console.log(` Failed to remove ${summary.failed.length} item${summary.failed.length !== 1 ? "s" : ""}:`);
|
|
11819
|
+
for (const failure of summary.failed) {
|
|
11820
|
+
console.log(` - ${failure.path}: ${failure.reason}`);
|
|
11821
|
+
}
|
|
11822
|
+
}
|
|
11823
|
+
console.log();
|
|
11824
|
+
}
|
|
11825
|
+
async function runProjectMcpUninstall(options, deps, useColors) {
|
|
11826
|
+
const { fileSystemService, promptService } = deps;
|
|
11827
|
+
const isInteractive = deps.isInteractive ?? true;
|
|
11828
|
+
const scope = await resolveProjectSetupScope({}, fileSystemService);
|
|
11829
|
+
if (!scope)
|
|
11830
|
+
return;
|
|
11831
|
+
const projectPlan = await getProjectUninstallPlan(fileSystemService);
|
|
11832
|
+
console.log(`
|
|
11833
|
+
${colorize("Remove GitHits from this project's MCP config.", "bold", useColors)}`);
|
|
11834
|
+
console.log(` ${colorize("Removes GitHits entries from supported project-local MCP files.", "dim", useColors)}
|
|
11835
|
+
`);
|
|
11836
|
+
console.log(` Project: ${scope.projectPath}`);
|
|
11837
|
+
for (const setup of projectPlan.configRemovals) {
|
|
11838
|
+
console.log(` Config: ${setup.configPath}`);
|
|
11839
|
+
}
|
|
11840
|
+
console.log();
|
|
11841
|
+
const checks = await Promise.all(projectPlan.configRemovals.map(async (setup) => ({
|
|
11842
|
+
setup,
|
|
11843
|
+
check: await getConfigUninstallCheckStatus(setup, fileSystemService)
|
|
11844
|
+
})));
|
|
11845
|
+
const configured = checks.filter((entry) => entry.check.status === "configured");
|
|
11846
|
+
const failedChecks = checks.filter((entry) => entry.check.status === "failed");
|
|
11847
|
+
for (const { setup, check } of failedChecks) {
|
|
11848
|
+
printTask("failed", setup.configPath, check.message, useColors);
|
|
11849
|
+
}
|
|
11850
|
+
const skipped = checks.filter((entry) => entry.check.status === "not_configured").map((entry) => entry.setup.configPath);
|
|
11851
|
+
const legacyStatePath = getLegacyProjectSetupStatePath(fileSystemService);
|
|
11852
|
+
const legacyProbeFailures = [];
|
|
11853
|
+
let hasLegacyState = false;
|
|
11854
|
+
try {
|
|
11855
|
+
hasLegacyState = await fileSystemService.exists(legacyStatePath);
|
|
11856
|
+
} catch (err) {
|
|
11857
|
+
legacyProbeFailures.push({
|
|
11858
|
+
path: legacyStatePath,
|
|
11859
|
+
reason: `Could not inspect legacy project setup marker: ${err instanceof Error ? err.message : String(err)}`
|
|
11860
|
+
});
|
|
11861
|
+
}
|
|
11862
|
+
const hasWork = configured.length > 0 || hasLegacyState;
|
|
11863
|
+
if (!hasWork && failedChecks.length === 0 && legacyProbeFailures.length === 0) {
|
|
11864
|
+
printProjectUninstallSummary({
|
|
11865
|
+
removed: [],
|
|
11866
|
+
legacyRemoved: [],
|
|
11867
|
+
skipped,
|
|
11868
|
+
failed: []
|
|
11869
|
+
});
|
|
11870
|
+
return;
|
|
11871
|
+
}
|
|
11872
|
+
if (!hasWork) {
|
|
11873
|
+
const summary2 = {
|
|
11874
|
+
removed: [],
|
|
11875
|
+
legacyRemoved: [],
|
|
11876
|
+
skipped,
|
|
11877
|
+
failed: failedChecks.map(({ setup, check }) => ({
|
|
11878
|
+
path: setup.configPath,
|
|
11879
|
+
reason: check.message
|
|
11880
|
+
})).concat(legacyProbeFailures)
|
|
11881
|
+
};
|
|
11882
|
+
process.exitCode = 1;
|
|
11883
|
+
printProjectUninstallSummary(summary2);
|
|
11884
|
+
return;
|
|
11885
|
+
}
|
|
11886
|
+
if (!isInteractive && !options.yes) {
|
|
11887
|
+
console.log(" Project uninstall needs confirmation. Because this session is non-interactive, no changes were made.");
|
|
11888
|
+
console.log();
|
|
11889
|
+
console.log(" To remove GitHits from this project's MCP files, run:");
|
|
11890
|
+
console.log(` ${formatCommand("githits init uninstall --project --yes", useColors)}`);
|
|
11891
|
+
console.log();
|
|
11892
|
+
return;
|
|
11893
|
+
}
|
|
11894
|
+
if (!options.yes) {
|
|
11895
|
+
let accepted;
|
|
11896
|
+
try {
|
|
11897
|
+
accepted = await promptService.confirm("Remove GitHits MCP config from this project?", false);
|
|
11898
|
+
} catch (err) {
|
|
11899
|
+
if (err instanceof ExitPromptError) {
|
|
11900
|
+
console.log(`
|
|
11901
|
+
Uninstall cancelled. No changes made.
|
|
11902
|
+
`);
|
|
11903
|
+
return;
|
|
11904
|
+
}
|
|
11905
|
+
throw err;
|
|
11906
|
+
}
|
|
11907
|
+
if (!accepted) {
|
|
11908
|
+
printTask("skipped", "Project uninstall skipped", "no changes made", useColors);
|
|
11909
|
+
console.log();
|
|
11910
|
+
return;
|
|
11911
|
+
}
|
|
11912
|
+
}
|
|
11913
|
+
const summary = {
|
|
11914
|
+
removed: [],
|
|
11915
|
+
legacyRemoved: [],
|
|
11916
|
+
skipped,
|
|
11917
|
+
failed: failedChecks.map(({ setup, check }) => ({
|
|
11918
|
+
path: setup.configPath,
|
|
11919
|
+
reason: check.message
|
|
11920
|
+
})).concat(legacyProbeFailures)
|
|
11921
|
+
};
|
|
11922
|
+
for (const { setup } of configured) {
|
|
11923
|
+
const result = await executeConfigFileUninstall(setup, fileSystemService);
|
|
11924
|
+
if (result.status === "removed") {
|
|
11925
|
+
summary.removed.push(setup.configPath);
|
|
11926
|
+
printTask("success", "GitHits project config", `removed from ${setup.configPath}`, useColors);
|
|
11927
|
+
} else if (result.status === "not_configured") {
|
|
11928
|
+
summary.skipped.push(setup.configPath);
|
|
11929
|
+
printTask("skipped", setup.configPath, "not configured", useColors);
|
|
11930
|
+
} else {
|
|
11931
|
+
summary.failed.push({
|
|
11932
|
+
path: setup.configPath,
|
|
11933
|
+
reason: result.message
|
|
11934
|
+
});
|
|
11935
|
+
printTask("failed", setup.configPath, result.message, useColors);
|
|
11936
|
+
}
|
|
11937
|
+
}
|
|
11938
|
+
if (legacyProbeFailures.length === 0) {
|
|
11939
|
+
const legacyCleanup = await cleanupLegacyProjectSetupState(fileSystemService);
|
|
11940
|
+
for (const path of legacyCleanup.removed) {
|
|
11941
|
+
summary.legacyRemoved.push(path);
|
|
11942
|
+
printTask("success", "Legacy project setup marker", `removed ${path}`, useColors);
|
|
11943
|
+
}
|
|
11944
|
+
for (const failure of legacyCleanup.failed) {
|
|
11945
|
+
summary.failed.push(failure);
|
|
11946
|
+
printTask("failed", failure.path, failure.reason, useColors);
|
|
11947
|
+
}
|
|
11948
|
+
}
|
|
11949
|
+
if (summary.failed.length > 0) {
|
|
11950
|
+
process.exitCode = 1;
|
|
11951
|
+
}
|
|
11952
|
+
printProjectUninstallSummary(summary);
|
|
11953
|
+
}
|
|
11954
|
+
function printNonInteractiveUninstallGuidance(useColors) {
|
|
11955
|
+
console.log(" Uninstall is interactive. Because this session is non-interactive, no changes were made.");
|
|
11956
|
+
console.log();
|
|
11957
|
+
console.log(" To remove user-level GitHits MCP config, run:");
|
|
11958
|
+
console.log(` ${formatCommand("githits init uninstall --yes", useColors)}`);
|
|
11959
|
+
console.log();
|
|
11960
|
+
console.log(" To remove project-level GitHits MCP config, run:");
|
|
11961
|
+
console.log(` ${formatCommand("githits init uninstall --project --yes", useColors)}`);
|
|
11962
|
+
console.log();
|
|
11963
|
+
}
|
|
11964
|
+
async function runUserMcpUninstall(options, deps, useColors) {
|
|
11965
|
+
const { fileSystemService, promptService, execService } = deps;
|
|
11966
|
+
console.log(`
|
|
11967
|
+
${colorize("Disconnect GitHits from your coding agents.", "bold", useColors)}`);
|
|
11968
|
+
console.log(` ${colorize("Removes the local GitHits MCP configuration.", "dim", useColors)}
|
|
11969
|
+
`);
|
|
11970
|
+
console.log(` Scanning for configured agents...
|
|
11971
|
+
`);
|
|
11972
|
+
const scan = await scanAgentsForUninstall(fileSystemService, execService);
|
|
11973
|
+
for (const agent of scan.configured) {
|
|
11974
|
+
console.log(` ${colorize(`● ${agent.name} — configured`, "cyan", useColors)}`);
|
|
11975
|
+
}
|
|
11976
|
+
for (const agent of scan.notConfigured) {
|
|
11977
|
+
console.log(` ${warning(`${agent.name} — not configured`, useColors)}`);
|
|
11978
|
+
}
|
|
11979
|
+
for (const outcome of scan.failed) {
|
|
11980
|
+
console.log(` ${error(`${outcome.name} — cannot inspect config`, useColors)}`);
|
|
11981
|
+
}
|
|
11982
|
+
for (const agent of scan.notDetected) {
|
|
11983
|
+
console.log(` ${colorize(`${agent.name} — not detected`, "dim", useColors)}`);
|
|
11984
|
+
}
|
|
11985
|
+
console.log();
|
|
11986
|
+
if (scan.configured.length === 0 && scan.failed.length === 0) {
|
|
11987
|
+
console.log(` No GitHits MCP configurations found. Nothing to uninstall.
|
|
11988
|
+
`);
|
|
11989
|
+
return;
|
|
11990
|
+
}
|
|
11991
|
+
const outcomes = [...scan.failed];
|
|
11992
|
+
let alwaysMode = options.yes ?? false;
|
|
11993
|
+
for (const agent of scan.configured) {
|
|
11994
|
+
console.log(` Uninstalling from ${colorize(agent.name, "bold", useColors)}...
|
|
11995
|
+
`);
|
|
11996
|
+
const setupConfig = getResolvedSetupConfig(agent, fileSystemService);
|
|
11997
|
+
const uninstallConfig = agent.resolvedUninstallConfig ?? (setupConfig.method === "config-file" ? setupConfig : agent.getUninstallConfig?.(fileSystemService, agent.resolvedSetupContext));
|
|
11998
|
+
if (!uninstallConfig) {
|
|
11999
|
+
outcomes.push({
|
|
12000
|
+
id: agent.id,
|
|
12001
|
+
name: agent.name,
|
|
12002
|
+
status: "failed",
|
|
12003
|
+
message: `${agent.name} does not have a verified uninstall command.`
|
|
12004
|
+
});
|
|
12005
|
+
console.log(` ${error(`${agent.name} does not have a verified uninstall command.`, useColors)}
|
|
12006
|
+
`);
|
|
12007
|
+
continue;
|
|
12008
|
+
}
|
|
12009
|
+
const preview2 = formatUninstallPreview(uninstallConfig);
|
|
12010
|
+
for (const line of preview2.split(`
|
|
12011
|
+
`)) {
|
|
12012
|
+
console.log(` ${line}`);
|
|
12013
|
+
}
|
|
12014
|
+
console.log();
|
|
12015
|
+
if (!alwaysMode) {
|
|
12016
|
+
let choice;
|
|
12017
|
+
try {
|
|
12018
|
+
choice = await promptService.confirm3("Proceed?", "no");
|
|
12019
|
+
} catch (err) {
|
|
12020
|
+
if (err instanceof ExitPromptError) {
|
|
12021
|
+
console.log(`
|
|
12022
|
+
Uninstall cancelled.
|
|
12023
|
+
`);
|
|
12024
|
+
return;
|
|
12025
|
+
}
|
|
12026
|
+
throw err;
|
|
12027
|
+
}
|
|
12028
|
+
if (choice === "no") {
|
|
12029
|
+
outcomes.push({ id: agent.id, name: agent.name, status: "skipped" });
|
|
12030
|
+
console.log();
|
|
12031
|
+
continue;
|
|
12032
|
+
}
|
|
12033
|
+
if (choice === "always") {
|
|
12034
|
+
alwaysMode = true;
|
|
12035
|
+
}
|
|
12036
|
+
}
|
|
12037
|
+
let result = uninstallConfig.method === "cli" ? await executeCliUninstall(uninstallConfig, execService) : uninstallConfig.method === "config-file" ? await executeConfigFileUninstall(uninstallConfig, fileSystemService) : await executeCompositeUninstall(uninstallConfig, fileSystemService, execService);
|
|
12038
|
+
if (result.status === "removed" && !agent.skipUninstallVerification) {
|
|
12039
|
+
const verification = await verifyAgentUnconfigured(agent, fileSystemService, execService);
|
|
12040
|
+
if (!verification.ok) {
|
|
12041
|
+
result = {
|
|
12042
|
+
status: "failed",
|
|
12043
|
+
message: verification.message ?? `${agent.name} verification failed after uninstall.`,
|
|
12044
|
+
warnings: result.warnings
|
|
12045
|
+
};
|
|
12046
|
+
}
|
|
12047
|
+
}
|
|
12048
|
+
outcomes.push({
|
|
12049
|
+
id: agent.id,
|
|
12050
|
+
name: agent.name,
|
|
12051
|
+
status: result.status,
|
|
12052
|
+
message: result.status === "failed" ? result.message : undefined,
|
|
12053
|
+
warnings: result.warnings
|
|
12054
|
+
});
|
|
12055
|
+
if (result.status === "removed") {
|
|
12056
|
+
console.log(` ${success(`${agent.name} removed`, useColors)}
|
|
12057
|
+
`);
|
|
12058
|
+
for (const warn of result.warnings ?? []) {
|
|
12059
|
+
console.log(` ${warning(`Warning: ${warn}`, useColors)}`);
|
|
12060
|
+
}
|
|
12061
|
+
} else if (result.status === "not_configured") {
|
|
12062
|
+
console.log(` ${warning(`${agent.name} was not configured`, useColors)}
|
|
12063
|
+
`);
|
|
12064
|
+
} else {
|
|
12065
|
+
console.log(` ${error(result.message, useColors)}
|
|
12066
|
+
`);
|
|
12067
|
+
for (const warn of result.warnings ?? []) {
|
|
12068
|
+
console.log(` ${warning(`Warning: ${warn}`, useColors)}`);
|
|
12069
|
+
}
|
|
12070
|
+
}
|
|
12071
|
+
}
|
|
12072
|
+
const removed = outcomes.filter((o) => o.status === "removed").length;
|
|
12073
|
+
const notConfigured = outcomes.filter((o) => o.status === "not_configured").length + scan.notConfigured.length;
|
|
12074
|
+
const failed = outcomes.filter((o) => o.status === "failed").length;
|
|
12075
|
+
const skipped = outcomes.filter((o) => o.status === "skipped").length;
|
|
12076
|
+
if (failed > 0) {
|
|
12077
|
+
console.log(" Uninstall completed with errors.");
|
|
12078
|
+
} else if (removed > 0) {
|
|
12079
|
+
console.log(" Done! GitHits MCP configuration was removed.");
|
|
12080
|
+
} else if (skipped > 0) {
|
|
12081
|
+
console.log(" Uninstall skipped.");
|
|
12082
|
+
} else if (notConfigured > 0) {
|
|
12083
|
+
console.log(" No GitHits MCP configurations were active. Nothing to remove.");
|
|
12084
|
+
}
|
|
12085
|
+
if (removed > 0) {
|
|
12086
|
+
console.log(` ${removed} agent${removed !== 1 ? "s" : ""} removed.`);
|
|
12087
|
+
}
|
|
12088
|
+
if (notConfigured > 0) {
|
|
12089
|
+
console.log(` ${notConfigured} agent${notConfigured !== 1 ? "s" : ""} not configured.`);
|
|
12090
|
+
}
|
|
12091
|
+
if (skipped > 0) {
|
|
12092
|
+
console.log(` ${skipped} agent${skipped !== 1 ? "s" : ""} skipped.`);
|
|
12093
|
+
}
|
|
12094
|
+
if (failed > 0) {
|
|
12095
|
+
console.log(` ${failed} agent${failed !== 1 ? "s" : ""} failed to uninstall.`);
|
|
12096
|
+
for (const outcome of outcomes.filter((o) => o.status === "failed")) {
|
|
12097
|
+
console.log(` - ${outcome.name}: ${outcome.message ?? "Unknown error"}`);
|
|
12098
|
+
for (const warn of outcome.warnings ?? []) {
|
|
12099
|
+
console.log(` Warning: ${warn}`);
|
|
12100
|
+
}
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12103
|
+
console.log();
|
|
12104
|
+
}
|
|
12105
|
+
async function verifyAgentConfigured(agent, fileSystemService, execService, scope) {
|
|
12106
|
+
const postCheck = await scanAgents([agent], fileSystemService, execService, {
|
|
12107
|
+
scope
|
|
12108
|
+
});
|
|
12109
|
+
if (postCheck.alreadyConfigured.some((a) => a.id === agent.id)) {
|
|
12110
|
+
return { ok: true };
|
|
12111
|
+
}
|
|
12112
|
+
if (postCheck.needsSetup.some((a) => a.id === agent.id)) {
|
|
12113
|
+
return {
|
|
12114
|
+
ok: false,
|
|
12115
|
+
message: `${agent.name} verification failed: not configured after setup.`
|
|
12116
|
+
};
|
|
12117
|
+
}
|
|
12118
|
+
return {
|
|
12119
|
+
ok: false,
|
|
12120
|
+
message: `${agent.name} verification failed: agent not detected after setup.`
|
|
12121
|
+
};
|
|
12122
|
+
}
|
|
12123
|
+
async function executeAgentSetupWithVerification(agent, fileSystemService, execService, scope) {
|
|
12124
|
+
const config = getResolvedSetupConfig(agent, fileSystemService);
|
|
12125
|
+
let result = config.method === "cli" ? await executeCliSetup(config, execService) : config.method === "config-file" ? await executeConfigFileSetup(config, fileSystemService) : await executeCompositeSetup(config, fileSystemService, execService);
|
|
12126
|
+
if (result.status === "success" || result.status === "already_configured") {
|
|
12127
|
+
const verification = await verifyAgentConfigured(agent, fileSystemService, execService, scope);
|
|
12128
|
+
if (!verification.ok) {
|
|
12129
|
+
result = {
|
|
12130
|
+
status: "failed",
|
|
12131
|
+
message: agent.id === "gemini-cli" ? "Gemini installation did not complete. Retry, or run: gemini extensions install --consent https://github.com/githits-com/githits-cli" : verification.message ?? `${agent.name} verification failed after setup.`
|
|
12132
|
+
};
|
|
12133
|
+
}
|
|
12134
|
+
}
|
|
12135
|
+
return result;
|
|
12136
|
+
}
|
|
12137
|
+
async function installSelectedAgents(agents, scan, fileSystemService, execService, useColors, printResults, scope = "user") {
|
|
12138
|
+
const alreadyConfiguredIds = new Set(scan.alreadyConfigured.map((agent) => agent.id));
|
|
12139
|
+
const outcomes = [];
|
|
12140
|
+
const installTasks = createInstallTaskReporter(useColors);
|
|
12141
|
+
for (const agent of agents) {
|
|
12142
|
+
if (alreadyConfiguredIds.has(agent.id)) {
|
|
12143
|
+
outcomes.push({
|
|
12144
|
+
id: agent.id,
|
|
12145
|
+
name: agent.name,
|
|
12146
|
+
status: "already_configured"
|
|
12147
|
+
});
|
|
12148
|
+
if (printResults) {
|
|
12149
|
+
printTask("warning", agent.name, "already configured", useColors);
|
|
12150
|
+
}
|
|
12151
|
+
continue;
|
|
12152
|
+
}
|
|
12153
|
+
const finishTask = printResults ? installTasks.start(agent.name) : () => {};
|
|
12154
|
+
let result;
|
|
12155
|
+
try {
|
|
12156
|
+
result = await executeAgentSetupWithVerification(agent, fileSystemService, execService, scope);
|
|
12157
|
+
} finally {
|
|
12158
|
+
finishTask();
|
|
12159
|
+
}
|
|
12160
|
+
outcomes.push({
|
|
12161
|
+
id: agent.id,
|
|
12162
|
+
name: agent.name,
|
|
12163
|
+
status: result.status,
|
|
12164
|
+
message: result.status === "failed" ? result.message : undefined
|
|
12165
|
+
});
|
|
12166
|
+
if (!printResults) {
|
|
11418
12167
|
continue;
|
|
11419
12168
|
}
|
|
11420
12169
|
if (result.status === "success") {
|
|
@@ -11568,6 +12317,7 @@ async function initAction(options, deps) {
|
|
|
11568
12317
|
console.log();
|
|
11569
12318
|
return;
|
|
11570
12319
|
}
|
|
12320
|
+
let setupScope = options.project ? "project" : "user";
|
|
11571
12321
|
if (!options.yes) {
|
|
11572
12322
|
let intent;
|
|
11573
12323
|
try {
|
|
@@ -11589,20 +12339,39 @@ async function initAction(options, deps) {
|
|
|
11589
12339
|
console.log("\n No changes made. Run `npx githits@latest init` whenever you're ready.\n");
|
|
11590
12340
|
return;
|
|
11591
12341
|
}
|
|
12342
|
+
if (!options.project) {
|
|
12343
|
+
try {
|
|
12344
|
+
setupScope = await promptService.select(" Where should GitHits be configured?", INIT_SCOPE_CHOICES, "user");
|
|
12345
|
+
} catch (err) {
|
|
12346
|
+
if (err instanceof ExitPromptError) {
|
|
12347
|
+
console.log(`
|
|
12348
|
+
Setup cancelled. No changes made.
|
|
12349
|
+
`);
|
|
12350
|
+
return;
|
|
12351
|
+
}
|
|
12352
|
+
throw err;
|
|
12353
|
+
}
|
|
12354
|
+
}
|
|
12355
|
+
}
|
|
12356
|
+
if (setupScope === "project") {
|
|
12357
|
+
const scope = await resolveProjectSetupScope({}, fileSystemService);
|
|
12358
|
+
if (!scope)
|
|
12359
|
+
return;
|
|
12360
|
+
printProjectScopeExplanation(useColors);
|
|
11592
12361
|
}
|
|
11593
12362
|
printSection(1, "Detect tools", useColors);
|
|
11594
12363
|
console.log(" Scanning for compatible AI coding tools...");
|
|
11595
12364
|
const progress = createScanProgressReporter(useColors);
|
|
11596
|
-
const scanPromise = startSafeInitScan(fileSystemService, execService, (scanProgress) => progress.onProgress(scanProgress));
|
|
12365
|
+
const scanPromise = startSafeInitScan(fileSystemService, execService, setupScope, (scanProgress) => progress.onProgress(scanProgress));
|
|
11597
12366
|
let scan;
|
|
11598
12367
|
try {
|
|
11599
12368
|
scan = await unwrapSafeScan(scanPromise);
|
|
11600
12369
|
} finally {
|
|
11601
12370
|
progress.finish();
|
|
11602
12371
|
}
|
|
11603
|
-
printScanSummary(scan, useColors);
|
|
12372
|
+
printScanSummary(scan, useColors, setupScope);
|
|
11604
12373
|
if (scan.needsSetup.length === 0 && scan.alreadyConfigured.length === 0) {
|
|
11605
|
-
printTask("warning", "No supported AI coding tools detected", "install a supported tool and run `githits init` again", useColors);
|
|
12374
|
+
printTask("warning", setupScope === "project" ? "No project-configurable tools detected" : "No supported AI coding tools detected", setupScope === "project" ? "choose user-level config or install a project-configurable tool" : "install a supported tool and run `githits init` again", useColors);
|
|
11606
12375
|
console.log();
|
|
11607
12376
|
return;
|
|
11608
12377
|
}
|
|
@@ -11630,6 +12399,9 @@ async function initAction(options, deps) {
|
|
|
11630
12399
|
console.log();
|
|
11631
12400
|
return;
|
|
11632
12401
|
}
|
|
12402
|
+
if (toSetup.length > 0) {
|
|
12403
|
+
await printTomlRewriteWarnings(toSetup, fileSystemService, useColors);
|
|
12404
|
+
}
|
|
11633
12405
|
printSection(3, "Sign in", useColors);
|
|
11634
12406
|
const authStatus = await runInitAuthentication(options, promptService, createLoginDeps, useColors);
|
|
11635
12407
|
if (authStatus === "cancelled") {
|
|
@@ -11638,11 +12410,11 @@ async function initAction(options, deps) {
|
|
|
11638
12410
|
printSection(4, "Install and verify", useColors);
|
|
11639
12411
|
if (toSetup.length === 0) {
|
|
11640
12412
|
printTask("success", "Nothing to install", "all detected tools are already configured", useColors);
|
|
11641
|
-
|
|
12413
|
+
printScopedNextSteps(setupScope, authStatus, useColors);
|
|
11642
12414
|
console.log();
|
|
11643
12415
|
return;
|
|
11644
12416
|
}
|
|
11645
|
-
const outcomes = await installSelectedAgents(toSetup, scan, fileSystemService, execService, useColors, true);
|
|
12417
|
+
const outcomes = await installSelectedAgents(toSetup, scan, fileSystemService, execService, useColors, true, setupScope);
|
|
11646
12418
|
console.log();
|
|
11647
12419
|
const configured = outcomes.filter((o) => o.status === "success").length;
|
|
11648
12420
|
const alreadyDone = outcomes.filter((o) => o.status === "already_configured").length + scan.alreadyConfigured.length;
|
|
@@ -11650,7 +12422,7 @@ async function initAction(options, deps) {
|
|
|
11650
12422
|
if (failed > 0) {
|
|
11651
12423
|
console.log(" Setup completed with errors.");
|
|
11652
12424
|
} else if (configured > 0 || alreadyDone > 0) {
|
|
11653
|
-
|
|
12425
|
+
printScopedNextSteps(setupScope, authStatus, useColors);
|
|
11654
12426
|
}
|
|
11655
12427
|
if (failed > 0) {
|
|
11656
12428
|
console.log(` ${failed} tool${failed !== 1 ? "s" : ""} failed to configure.`);
|
|
@@ -11665,145 +12437,35 @@ async function initAction(options, deps) {
|
|
|
11665
12437
|
}
|
|
11666
12438
|
async function initUninstallAction(options, deps) {
|
|
11667
12439
|
const useColors = shouldUseColors();
|
|
11668
|
-
const {
|
|
11669
|
-
|
|
11670
|
-
|
|
11671
|
-
|
|
11672
|
-
|
|
11673
|
-
console.log(` Scanning for configured agents...
|
|
11674
|
-
`);
|
|
11675
|
-
const scan = await scanAgentsForUninstall(fileSystemService, execService);
|
|
11676
|
-
for (const agent of scan.configured) {
|
|
11677
|
-
console.log(` ${colorize(`● ${agent.name} — configured`, "cyan", useColors)}`);
|
|
11678
|
-
}
|
|
11679
|
-
for (const agent of scan.notConfigured) {
|
|
11680
|
-
console.log(` ${warning(`${agent.name} — not configured`, useColors)}`);
|
|
11681
|
-
}
|
|
11682
|
-
for (const outcome of scan.failed) {
|
|
11683
|
-
console.log(` ${error(`${outcome.name} — cannot inspect config`, useColors)}`);
|
|
11684
|
-
}
|
|
11685
|
-
for (const agent of scan.notDetected) {
|
|
11686
|
-
console.log(` ${colorize(`${agent.name} — not detected`, "dim", useColors)}`);
|
|
12440
|
+
const { promptService } = deps;
|
|
12441
|
+
const isInteractive = deps.isInteractive ?? true;
|
|
12442
|
+
if (options.project) {
|
|
12443
|
+
await runProjectMcpUninstall(options, deps, useColors);
|
|
12444
|
+
return;
|
|
11687
12445
|
}
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
console.log(` No GitHits MCP configurations found. Nothing to uninstall.
|
|
11691
|
-
`);
|
|
12446
|
+
if (!isInteractive && !options.yes) {
|
|
12447
|
+
printNonInteractiveUninstallGuidance(useColors);
|
|
11692
12448
|
return;
|
|
11693
12449
|
}
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
11698
|
-
|
|
11699
|
-
|
|
11700
|
-
|
|
11701
|
-
|
|
11702
|
-
outcomes.push({
|
|
11703
|
-
id: agent.id,
|
|
11704
|
-
name: agent.name,
|
|
11705
|
-
status: "failed",
|
|
11706
|
-
message: `${agent.name} does not have a verified uninstall command.`
|
|
11707
|
-
});
|
|
11708
|
-
console.log(` ${error(`${agent.name} does not have a verified uninstall command.`, useColors)}
|
|
11709
|
-
`);
|
|
11710
|
-
continue;
|
|
11711
|
-
}
|
|
11712
|
-
const preview2 = formatUninstallPreview(uninstallConfig);
|
|
11713
|
-
for (const line of preview2.split(`
|
|
11714
|
-
`)) {
|
|
11715
|
-
console.log(` ${line}`);
|
|
11716
|
-
}
|
|
11717
|
-
console.log();
|
|
11718
|
-
if (!alwaysMode) {
|
|
11719
|
-
let choice;
|
|
11720
|
-
try {
|
|
11721
|
-
choice = await promptService.confirm3("Proceed?");
|
|
11722
|
-
} catch (err) {
|
|
11723
|
-
if (err instanceof ExitPromptError) {
|
|
11724
|
-
console.log(`
|
|
11725
|
-
Uninstall cancelled.
|
|
11726
|
-
`);
|
|
11727
|
-
return;
|
|
11728
|
-
}
|
|
11729
|
-
throw err;
|
|
11730
|
-
}
|
|
11731
|
-
if (choice === "no") {
|
|
11732
|
-
outcomes.push({ id: agent.id, name: agent.name, status: "skipped" });
|
|
11733
|
-
console.log();
|
|
11734
|
-
continue;
|
|
11735
|
-
}
|
|
11736
|
-
if (choice === "always") {
|
|
11737
|
-
alwaysMode = true;
|
|
11738
|
-
}
|
|
11739
|
-
}
|
|
11740
|
-
let result = uninstallConfig.method === "cli" ? await executeCliUninstall(uninstallConfig, execService) : uninstallConfig.method === "config-file" ? await executeConfigFileUninstall(uninstallConfig, fileSystemService) : await executeCompositeUninstall(uninstallConfig, fileSystemService, execService);
|
|
11741
|
-
if (result.status === "removed" && !agent.skipUninstallVerification) {
|
|
11742
|
-
const verification = await verifyAgentUnconfigured(agent, fileSystemService, execService);
|
|
11743
|
-
if (!verification.ok) {
|
|
11744
|
-
result = {
|
|
11745
|
-
status: "failed",
|
|
11746
|
-
message: verification.message ?? `${agent.name} verification failed after uninstall.`,
|
|
11747
|
-
warnings: result.warnings
|
|
11748
|
-
};
|
|
11749
|
-
}
|
|
11750
|
-
}
|
|
11751
|
-
outcomes.push({
|
|
11752
|
-
id: agent.id,
|
|
11753
|
-
name: agent.name,
|
|
11754
|
-
status: result.status,
|
|
11755
|
-
message: result.status === "failed" ? result.message : undefined,
|
|
11756
|
-
warnings: result.warnings
|
|
11757
|
-
});
|
|
11758
|
-
if (result.status === "removed") {
|
|
11759
|
-
console.log(` ${success(`${agent.name} removed`, useColors)}
|
|
11760
|
-
`);
|
|
11761
|
-
for (const warn of result.warnings ?? []) {
|
|
11762
|
-
console.log(` ${warning(`Warning: ${warn}`, useColors)}`);
|
|
11763
|
-
}
|
|
11764
|
-
} else if (result.status === "not_configured") {
|
|
11765
|
-
console.log(` ${warning(`${agent.name} was not configured`, useColors)}
|
|
11766
|
-
`);
|
|
11767
|
-
} else {
|
|
11768
|
-
console.log(` ${error(result.message, useColors)}
|
|
12450
|
+
if (!options.yes) {
|
|
12451
|
+
let scope;
|
|
12452
|
+
try {
|
|
12453
|
+
scope = await promptService.select(" What should GitHits be removed from?", INIT_UNINSTALL_SCOPE_CHOICES, "user");
|
|
12454
|
+
} catch (err) {
|
|
12455
|
+
if (err instanceof ExitPromptError) {
|
|
12456
|
+
console.log(`
|
|
12457
|
+
Uninstall cancelled. No changes made.
|
|
11769
12458
|
`);
|
|
11770
|
-
|
|
11771
|
-
console.log(` ${warning(`Warning: ${warn}`, useColors)}`);
|
|
12459
|
+
return;
|
|
11772
12460
|
}
|
|
12461
|
+
throw err;
|
|
11773
12462
|
}
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
const failed = outcomes.filter((o) => o.status === "failed").length;
|
|
11778
|
-
const skipped = outcomes.filter((o) => o.status === "skipped").length;
|
|
11779
|
-
if (failed > 0) {
|
|
11780
|
-
console.log(" Uninstall completed with errors.");
|
|
11781
|
-
} else if (removed > 0) {
|
|
11782
|
-
console.log(" Done! GitHits MCP configuration was removed.");
|
|
11783
|
-
} else if (skipped > 0) {
|
|
11784
|
-
console.log(" Uninstall skipped.");
|
|
11785
|
-
} else if (notConfigured > 0) {
|
|
11786
|
-
console.log(" No GitHits MCP configurations were active. Nothing to remove.");
|
|
11787
|
-
}
|
|
11788
|
-
if (removed > 0) {
|
|
11789
|
-
console.log(` ${removed} agent${removed !== 1 ? "s" : ""} removed.`);
|
|
11790
|
-
}
|
|
11791
|
-
if (notConfigured > 0) {
|
|
11792
|
-
console.log(` ${notConfigured} agent${notConfigured !== 1 ? "s" : ""} not configured.`);
|
|
11793
|
-
}
|
|
11794
|
-
if (skipped > 0) {
|
|
11795
|
-
console.log(` ${skipped} agent${skipped !== 1 ? "s" : ""} skipped.`);
|
|
11796
|
-
}
|
|
11797
|
-
if (failed > 0) {
|
|
11798
|
-
console.log(` ${failed} agent${failed !== 1 ? "s" : ""} failed to uninstall.`);
|
|
11799
|
-
for (const outcome of outcomes.filter((o) => o.status === "failed")) {
|
|
11800
|
-
console.log(` - ${outcome.name}: ${outcome.message ?? "Unknown error"}`);
|
|
11801
|
-
for (const warn of outcome.warnings ?? []) {
|
|
11802
|
-
console.log(` Warning: ${warn}`);
|
|
11803
|
-
}
|
|
12463
|
+
if (scope === "project") {
|
|
12464
|
+
await runProjectMcpUninstall(options, deps, useColors);
|
|
12465
|
+
return;
|
|
11804
12466
|
}
|
|
11805
12467
|
}
|
|
11806
|
-
|
|
12468
|
+
await runUserMcpUninstall(options, deps, useColors);
|
|
11807
12469
|
}
|
|
11808
12470
|
function printAuthRecoveryHint(useColors) {
|
|
11809
12471
|
console.log(" You can still configure MCP, but GitHits tools will require auth.");
|
|
@@ -11821,30 +12483,45 @@ sets up Agent Skills instead. Detects supported coding tools on this machine,
|
|
|
11821
12483
|
signs you in, and configures the tools you select.`;
|
|
11822
12484
|
var INIT_UNINSTALL_DESCRIPTION = `Remove GitHits MCP server configuration from your coding agents.
|
|
11823
12485
|
|
|
11824
|
-
|
|
11825
|
-
only
|
|
11826
|
-
tokens are not removed; use \`githits logout\` to
|
|
12486
|
+
In interactive mode, asks whether to remove user-level coding-agent config or
|
|
12487
|
+
project-level MCP config. Removes only GitHits MCP/plugin entries with your
|
|
12488
|
+
confirmation. Authentication tokens are not removed; use \`githits logout\` to
|
|
12489
|
+
remove stored credentials.`;
|
|
11827
12490
|
function registerInitCommand(program) {
|
|
11828
|
-
const initCommand = program.command("init").summary("Connect GitHits to your coding agents").description(INIT_DESCRIPTION).option("-y, --yes", "Skip prompts, configure all detected tools").option("--skip-login", "Skip authentication step").option("--detect-agents", "Scan supported agents without installing").option("--install-agents <ids>", "Install MCP server for comma-separated agent IDs from --detect-agents").option("--json", "Emit JSON for --detect-agents or --install-agents").action(async (options) => {
|
|
12491
|
+
const initCommand = program.command("init").argument("[action]", "Compatibility action; use uninstall with --project").summary("Connect GitHits to your coding agents").description(INIT_DESCRIPTION).option("-y, --yes", "Skip prompts, configure all detected tools").option("--skip-login", "Skip authentication step").option("--project", "Configure project-level MCP in the current directory").option("--detect-agents", "Scan supported agents without installing").option("--install-agents <ids>", "Install MCP server for comma-separated agent IDs from --detect-agents").option("--json", "Emit JSON for --detect-agents or --install-agents").action(async (action, options) => {
|
|
11829
12492
|
const fileSystemService = new FileSystemServiceImpl;
|
|
11830
12493
|
const promptService = new PromptServiceImpl;
|
|
11831
12494
|
const execService = new ExecServiceImpl;
|
|
11832
|
-
|
|
12495
|
+
const deps = {
|
|
11833
12496
|
fileSystemService,
|
|
11834
12497
|
promptService,
|
|
11835
12498
|
execService,
|
|
11836
12499
|
createLoginDeps: () => createContainer(),
|
|
11837
12500
|
isInteractive: process.stdin.isTTY === true && process.stdout.isTTY === true
|
|
12501
|
+
};
|
|
12502
|
+
if (action !== undefined) {
|
|
12503
|
+
failUnknownInitAction(action);
|
|
12504
|
+
return;
|
|
12505
|
+
}
|
|
12506
|
+
await initAction(options, {
|
|
12507
|
+
...deps
|
|
11838
12508
|
});
|
|
11839
12509
|
});
|
|
11840
|
-
initCommand.command("uninstall").summary("Remove MCP server from
|
|
12510
|
+
initCommand.command("uninstall").summary("Remove MCP server from coding agents or project config").description(INIT_UNINSTALL_DESCRIPTION).option("-y, --yes", "Skip prompts, uninstall user-level config", false).option("--project", "Remove project-level MCP from the current directory", false).action(async (options, command) => {
|
|
12511
|
+
const parentOptions = command.parent?.opts() ?? {};
|
|
12512
|
+
const resolvedOptions = {
|
|
12513
|
+
...options,
|
|
12514
|
+
yes: options.yes || parentOptions.yes,
|
|
12515
|
+
project: options.project || parentOptions.project
|
|
12516
|
+
};
|
|
11841
12517
|
const fileSystemService = new FileSystemServiceImpl;
|
|
11842
12518
|
const promptService = new PromptServiceImpl;
|
|
11843
12519
|
const execService = new ExecServiceImpl;
|
|
11844
|
-
await initUninstallAction(
|
|
12520
|
+
await initUninstallAction(resolvedOptions, {
|
|
11845
12521
|
fileSystemService,
|
|
11846
12522
|
promptService,
|
|
11847
|
-
execService
|
|
12523
|
+
execService,
|
|
12524
|
+
isInteractive: process.stdin.isTTY === true && process.stdout.isTTY === true
|
|
11848
12525
|
});
|
|
11849
12526
|
});
|
|
11850
12527
|
}
|
|
@@ -12088,8 +12765,13 @@ function resolveCodeTarget(target) {
|
|
|
12088
12765
|
return mappedInvalidTargetResult(error2);
|
|
12089
12766
|
}
|
|
12090
12767
|
}
|
|
12091
|
-
const
|
|
12092
|
-
const
|
|
12768
|
+
const registry = normaliseOptionalValue(target.registry)?.toLowerCase();
|
|
12769
|
+
const packageName = normaliseOptionalValue(target.package_name);
|
|
12770
|
+
const version2 = normaliseOptionalValue(target.version);
|
|
12771
|
+
const repoUrl = normaliseOptionalValue(target.repo_url);
|
|
12772
|
+
const gitRef = normaliseOptionalValue(target.git_ref);
|
|
12773
|
+
const hasPackageTarget = registry !== undefined || packageName !== undefined;
|
|
12774
|
+
const hasRepoTarget = repoUrl !== undefined || gitRef !== undefined;
|
|
12093
12775
|
if (hasPackageTarget && hasRepoTarget) {
|
|
12094
12776
|
return invalidTargetResult("Invalid target: provide either registry + package_name or repo_url with optional git_ref, not both.");
|
|
12095
12777
|
}
|
|
@@ -12097,23 +12779,29 @@ function resolveCodeTarget(target) {
|
|
|
12097
12779
|
return invalidTargetResult("Missing target: provide registry + package_name or repo_url.");
|
|
12098
12780
|
}
|
|
12099
12781
|
if (hasPackageTarget) {
|
|
12100
|
-
if (!
|
|
12782
|
+
if (!registry || !packageName) {
|
|
12101
12783
|
return invalidTargetResult("Incomplete package target: both registry and package_name are required.");
|
|
12102
12784
|
}
|
|
12103
12785
|
return {
|
|
12104
|
-
registry: toCodeNavigationRegistry(
|
|
12105
|
-
packageName
|
|
12106
|
-
version:
|
|
12786
|
+
registry: toCodeNavigationRegistry(registry),
|
|
12787
|
+
packageName,
|
|
12788
|
+
version: version2
|
|
12107
12789
|
};
|
|
12108
12790
|
}
|
|
12109
|
-
if (!
|
|
12791
|
+
if (!repoUrl) {
|
|
12110
12792
|
return invalidTargetResult("Incomplete repository target: repo_url is required.");
|
|
12111
12793
|
}
|
|
12112
12794
|
return {
|
|
12113
|
-
repoUrl
|
|
12114
|
-
gitRef
|
|
12795
|
+
repoUrl,
|
|
12796
|
+
gitRef
|
|
12115
12797
|
};
|
|
12116
12798
|
}
|
|
12799
|
+
function normaliseOptionalValue(value) {
|
|
12800
|
+
if (value === undefined)
|
|
12801
|
+
return;
|
|
12802
|
+
const trimmed = value.trim();
|
|
12803
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
12804
|
+
}
|
|
12117
12805
|
function mappedInvalidTargetResult(error2) {
|
|
12118
12806
|
const mapped = mapCodeNavigationError(error2);
|
|
12119
12807
|
return errorResult(JSON.stringify({
|
|
@@ -12410,7 +13098,7 @@ function buildPackageChangelogParams(input) {
|
|
|
12410
13098
|
};
|
|
12411
13099
|
}
|
|
12412
13100
|
function resolveAddressing(input) {
|
|
12413
|
-
const hasSpec =
|
|
13101
|
+
const hasSpec = hasNonBlankValue2(input.registry) || hasNonBlankValue2(input.packageName);
|
|
12414
13102
|
const hasRepoUrl = Boolean(input.repoUrl?.trim());
|
|
12415
13103
|
if (hasSpec && hasRepoUrl) {
|
|
12416
13104
|
throw new InvalidPackageSpecError("Provide either `<spec>` (registry + name) or `--repo-url` / `repo_url`, not both.");
|
|
@@ -12436,6 +13124,9 @@ function resolveAddressing(input) {
|
|
|
12436
13124
|
const registry = toPkgseerRegistry(normalisedRegistryArg);
|
|
12437
13125
|
return { registry, packageName };
|
|
12438
13126
|
}
|
|
13127
|
+
function hasNonBlankValue2(value) {
|
|
13128
|
+
return value !== undefined && value.trim().length > 0;
|
|
13129
|
+
}
|
|
12439
13130
|
function normaliseGitRef(raw) {
|
|
12440
13131
|
if (raw === undefined)
|
|
12441
13132
|
return;
|
|
@@ -13247,11 +13938,13 @@ function createSearchTool(service) {
|
|
|
13247
13938
|
annotations: { readOnlyHint: true },
|
|
13248
13939
|
handler: async (args) => {
|
|
13249
13940
|
try {
|
|
13250
|
-
const
|
|
13941
|
+
const effectiveTarget = isBlankSearchTarget(args.target) ? undefined : args.target;
|
|
13942
|
+
const resolvedTarget = effectiveTarget ? resolveSearchTarget(effectiveTarget) : undefined;
|
|
13251
13943
|
if (resolvedTarget && "content" in resolvedTarget)
|
|
13252
13944
|
return resolvedTarget;
|
|
13253
|
-
const effectiveTargets = args.targets?.
|
|
13254
|
-
const
|
|
13945
|
+
const effectiveTargets = args.targets?.filter((target) => !isBlankSearchTarget(target));
|
|
13946
|
+
const nonEmptyTargets = effectiveTargets?.length ? effectiveTargets : undefined;
|
|
13947
|
+
const resolvedTargets = nonEmptyTargets?.map((entry) => resolveSearchTarget(entry));
|
|
13255
13948
|
const resolvedTargetsError = resolvedTargets?.find((entry) => ("content" in entry));
|
|
13256
13949
|
if (resolvedTargetsError) {
|
|
13257
13950
|
return resolvedTargetsError;
|
|
@@ -13289,6 +13982,19 @@ function createSearchTool(service) {
|
|
|
13289
13982
|
}
|
|
13290
13983
|
};
|
|
13291
13984
|
}
|
|
13985
|
+
function isBlankSearchTarget(target) {
|
|
13986
|
+
if (target === undefined)
|
|
13987
|
+
return true;
|
|
13988
|
+
if (typeof target === "string")
|
|
13989
|
+
return target.trim().length === 0;
|
|
13990
|
+
return !(normaliseOptionalValue2(target.registry) || normaliseOptionalValue2(target.package_name) || normaliseOptionalValue2(target.version) || normaliseOptionalValue2(target.repo_url) || normaliseOptionalValue2(target.git_ref));
|
|
13991
|
+
}
|
|
13992
|
+
function normaliseOptionalValue2(value) {
|
|
13993
|
+
if (value === undefined)
|
|
13994
|
+
return;
|
|
13995
|
+
const trimmed = value.trim();
|
|
13996
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
13997
|
+
}
|
|
13292
13998
|
function isResolvedSearchTarget(target) {
|
|
13293
13999
|
return !("content" in target);
|
|
13294
14000
|
}
|
|
@@ -13306,8 +14012,13 @@ function resolveSearchTarget(target) {
|
|
|
13306
14012
|
}));
|
|
13307
14013
|
}
|
|
13308
14014
|
}
|
|
13309
|
-
const
|
|
13310
|
-
const
|
|
14015
|
+
const registry = normaliseOptionalValue2(target.registry)?.toLowerCase();
|
|
14016
|
+
const packageName = normaliseOptionalValue2(target.package_name);
|
|
14017
|
+
const version2 = normaliseOptionalValue2(target.version);
|
|
14018
|
+
const repoUrl = normaliseOptionalValue2(target.repo_url);
|
|
14019
|
+
const gitRef = normaliseOptionalValue2(target.git_ref);
|
|
14020
|
+
const hasPackageTarget = registry !== undefined || packageName !== undefined;
|
|
14021
|
+
const hasRepoTarget = repoUrl !== undefined || gitRef !== undefined;
|
|
13311
14022
|
if (hasPackageTarget && hasRepoTarget) {
|
|
13312
14023
|
return invalidSearchTargetResult("Invalid target: provide either registry + package_name or repo_url with optional git_ref, not both.");
|
|
13313
14024
|
}
|
|
@@ -13315,19 +14026,19 @@ function resolveSearchTarget(target) {
|
|
|
13315
14026
|
return invalidSearchTargetResult("Missing target: provide registry + package_name or repo_url.");
|
|
13316
14027
|
}
|
|
13317
14028
|
if (hasPackageTarget) {
|
|
13318
|
-
if (!
|
|
14029
|
+
if (!registry || !packageName) {
|
|
13319
14030
|
return invalidSearchTargetResult("Incomplete package target: both registry and package_name are required.");
|
|
13320
14031
|
}
|
|
13321
14032
|
return {
|
|
13322
|
-
registry: toCodeNavigationRegistry(
|
|
13323
|
-
packageName
|
|
13324
|
-
version:
|
|
14033
|
+
registry: toCodeNavigationRegistry(registry),
|
|
14034
|
+
packageName,
|
|
14035
|
+
version: version2
|
|
13325
14036
|
};
|
|
13326
14037
|
}
|
|
13327
|
-
if (!
|
|
14038
|
+
if (!repoUrl) {
|
|
13328
14039
|
return invalidSearchTargetResult("Incomplete repository target: repo_url is required.");
|
|
13329
14040
|
}
|
|
13330
|
-
return { repoUrl
|
|
14041
|
+
return { repoUrl, gitRef };
|
|
13331
14042
|
}
|
|
13332
14043
|
function invalidSearchTargetResult(message) {
|
|
13333
14044
|
return errorResult(JSON.stringify({
|
|
@@ -14292,7 +15003,7 @@ function requireSearchService(deps) {
|
|
|
14292
15003
|
return deps.codeNavigationService;
|
|
14293
15004
|
}
|
|
14294
15005
|
async function loadContainer2() {
|
|
14295
|
-
const { createContainer: createContainer2 } = await import("./shared/chunk-
|
|
15006
|
+
const { createContainer: createContainer2 } = await import("./shared/chunk-2w48kb4c.js");
|
|
14296
15007
|
return createContainer2();
|
|
14297
15008
|
}
|
|
14298
15009
|
function parseTargetSpecs(specs) {
|