@akon-labs/nexus-cli 0.1.11-rc.2 → 0.1.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.
Files changed (57) hide show
  1. package/dist/cli.js +588 -63
  2. package/dist/core/graph-rail-store.d.ts +10 -0
  3. package/dist/core/graph-rail-store.d.ts.map +1 -1
  4. package/dist/core/graph-rail-store.js +9 -0
  5. package/dist/core/graph-rail-store.js.map +1 -1
  6. package/dist/core/keybindings.d.ts +2 -1
  7. package/dist/core/keybindings.d.ts.map +1 -1
  8. package/dist/core/keybindings.js +4 -1
  9. package/dist/core/keybindings.js.map +1 -1
  10. package/dist/extensions/gitnexus/client.d.ts.map +1 -1
  11. package/dist/extensions/gitnexus/client.js +45 -14
  12. package/dist/extensions/gitnexus/client.js.map +1 -1
  13. package/dist/extensions/gitnexus/hub-api.d.ts +56 -0
  14. package/dist/extensions/gitnexus/hub-api.d.ts.map +1 -0
  15. package/dist/extensions/gitnexus/hub-api.js +105 -0
  16. package/dist/extensions/gitnexus/hub-api.js.map +1 -0
  17. package/dist/extensions/gitnexus/index-repo.d.ts +50 -0
  18. package/dist/extensions/gitnexus/index-repo.d.ts.map +1 -0
  19. package/dist/extensions/gitnexus/index-repo.js +162 -0
  20. package/dist/extensions/gitnexus/index-repo.js.map +1 -0
  21. package/dist/extensions/gitnexus/index.d.ts.map +1 -1
  22. package/dist/extensions/gitnexus/index.js +135 -15
  23. package/dist/extensions/gitnexus/index.js.map +1 -1
  24. package/dist/extensions/gitnexus/resolve.d.ts +9 -0
  25. package/dist/extensions/gitnexus/resolve.d.ts.map +1 -1
  26. package/dist/extensions/gitnexus/resolve.js +52 -2
  27. package/dist/extensions/gitnexus/resolve.js.map +1 -1
  28. package/dist/index.js +588 -63
  29. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  30. package/dist/modes/interactive/components/assistant-message.js +2 -0
  31. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  32. package/dist/modes/interactive/components/command-palette.d.ts +2 -1
  33. package/dist/modes/interactive/components/command-palette.d.ts.map +1 -1
  34. package/dist/modes/interactive/components/command-palette.js +11 -4
  35. package/dist/modes/interactive/components/command-palette.js.map +1 -1
  36. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  37. package/dist/modes/interactive/components/footer.js +9 -3
  38. package/dist/modes/interactive/components/footer.js.map +1 -1
  39. package/dist/modes/interactive/components/graph-rail.d.ts.map +1 -1
  40. package/dist/modes/interactive/components/graph-rail.js +18 -3
  41. package/dist/modes/interactive/components/graph-rail.js.map +1 -1
  42. package/dist/modes/interactive/components/keybinding-hints.d.ts +1 -0
  43. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  44. package/dist/modes/interactive/components/keybinding-hints.js +7 -1
  45. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  46. package/dist/modes/interactive/components/landing-panel.d.ts.map +1 -1
  47. package/dist/modes/interactive/components/landing-panel.js +15 -2
  48. package/dist/modes/interactive/components/landing-panel.js.map +1 -1
  49. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  50. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  51. package/dist/modes/interactive/interactive-mode.js +35 -5
  52. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  53. package/dist/rpc-entry.js +588 -63
  54. package/dist/vendor/ai.js +14 -14
  55. package/dist/vendor/tui.js +1 -1
  56. package/npm-shrinkwrap.json +2 -2
  57. package/package.json +1 -1
@@ -11,10 +11,12 @@ import { GitNexusClient, GitNexusClientError } from "./client.js";
11
11
  import { resolveGitNexusConfig, resolveHubUrl, saveGitNexusConfig } from "./config.js";
12
12
  import { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from "./device-auth.js";
13
13
  import { formatCreditBalance, readGatewayCache, refreshGatewayPolicy, registerAutoProvider } from "./gateway.js";
14
+ import { GitNexusHubApi } from "./hub-api.js";
15
+ import { monitorRepoIndex, runIndexRepoCommand } from "./index-repo.js";
14
16
  import { spawnObservatoryFetch } from "./observatory.js";
15
17
  import { buildGitNexusPrompt } from "./prompt.js";
16
18
  import { withGitNexusRenderer } from "./render.js";
17
- import { gitRemoteSlug, matchCurrentRepo, parseRepoInventory, } from "./resolve.js";
19
+ import { currentGitHubRemote, gitRemoteSlug, matchCurrentRepo, parseRepoInventory, } from "./resolve.js";
18
20
  import { createGitNexusTools } from "./tools.js";
19
21
  /** Resolve workflow skills in source mode and bundled dist/cli.js mode. */
20
22
  export function resolveGitNexusSkillsDir(moduleUrl = import.meta.url, pathExists = existsSync) {
@@ -41,6 +43,7 @@ export default function gitnexusExtension(pi) {
41
43
  let delegationRegistered = false;
42
44
  let startupNotice;
43
45
  let loginRequired = false;
46
+ let indexMonitorController;
44
47
  const cwd = process.cwd();
45
48
  // Nexus Agent must also register at factory time: the initial model is
46
49
  // resolved before session_start fires, and a provider that appears after
@@ -69,31 +72,47 @@ export default function gitnexusExtension(pi) {
69
72
  // behaves as plain grep until connect() provides a client + current repo.
70
73
  registerAugmentedGrep(pi, cwd, () => activeClient, () => current?.name);
71
74
  registerChangeTracking(pi, cwd);
72
- async function connect() {
75
+ function clearConnectionState(notice, requiresLogin = false) {
73
76
  inventory = undefined;
74
77
  current = undefined;
75
78
  activeClient = undefined;
76
- startupNotice = undefined;
77
- loginRequired = false;
79
+ startupNotice = notice;
80
+ loginRequired = requiresLogin;
81
+ }
82
+ async function connect(signal) {
83
+ signal?.throwIfAborted();
78
84
  const config = resolveGitNexusConfig();
79
- if (!config)
85
+ if (!config) {
86
+ clearConnectionState();
80
87
  return;
88
+ }
81
89
  const client = new GitNexusClient(config);
90
+ let nextInventory;
82
91
  try {
83
- const listResult = await client.callTool("list_repos", {});
84
- inventory = parseRepoInventory(GitNexusClient.text(listResult));
92
+ const listResult = await client.callTool("list_repos", {}, signal);
93
+ signal?.throwIfAborted();
94
+ nextInventory = parseRepoInventory(GitNexusClient.text(listResult));
85
95
  }
86
96
  catch (error) {
97
+ signal?.throwIfAborted();
87
98
  const reason = error instanceof GitNexusClientError ? error.message : String(error);
88
99
  if (error instanceof GitNexusClientError && error.kind === "auth") {
89
- loginRequired = true;
100
+ clearConnectionState(undefined, true);
90
101
  return;
91
102
  }
92
- startupNotice = `GitNexus unavailable: ${reason}`;
103
+ clearConnectionState(`GitNexus unavailable: ${reason}`);
93
104
  return;
94
105
  }
95
- current = matchCurrentRepo(inventory, gitRemoteSlug(cwd));
106
+ const nextCurrent = matchCurrentRepo(nextInventory, gitRemoteSlug(cwd));
107
+ const nextStartupNotice = nextCurrent
108
+ ? `GitNexus: connected — ${nextCurrent.name} (${nextCurrent.symbols} symbols, indexed ${nextCurrent.indexedAt}), ${nextInventory.repos.length} repos available.`
109
+ : `GitNexus: connected — current directory is not indexed; ${nextInventory.repos.length} indexed repos remain queryable. Run /gitnexus-index to index this repo and unlock local graph context.`;
110
+ signal?.throwIfAborted();
111
+ inventory = nextInventory;
112
+ current = nextCurrent;
96
113
  activeClient = client;
114
+ startupNotice = nextStartupNotice;
115
+ loginRequired = false;
97
116
  graphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));
98
117
  // Observatory (community map) rides a detached subprocess + temp-file
99
118
  // handoff — in-process hub calls made after startup can starve in some
@@ -122,15 +141,108 @@ export default function gitnexusExtension(pi) {
122
141
  pi.registerTool(withGitNexusRenderer(tool));
123
142
  toolsRegistered = true;
124
143
  }
125
- startupNotice = current
126
- ? `GitNexus: connected — ${current.name} (${current.symbols} symbols, indexed ${current.indexedAt}), ${inventory.repos.length} repos available.`
127
- : `GitNexus: connected — current directory is not indexed; ${inventory.repos.length} indexed repos remain queryable. Index this repo from the Hub dashboard to unlock local graph context.`;
144
+ }
145
+ async function requestRepositoryIndex(targetCwd, branch, ui) {
146
+ if (/\s/.test(branch)) {
147
+ const message = "Branch names containing whitespace are not supported.";
148
+ ui.notify(message, "error");
149
+ return;
150
+ }
151
+ const config = resolveGitNexusConfig();
152
+ if (!config) {
153
+ const message = "GitNexus is not signed in. Run /login.";
154
+ ui.notify(message, "warning");
155
+ return;
156
+ }
157
+ const remote = currentGitHubRemote(targetCwd);
158
+ if (!remote) {
159
+ const message = `No supported github.com origin was found in ${targetCwd}.`;
160
+ ui.notify(message, "error");
161
+ return;
162
+ }
163
+ indexMonitorController?.abort();
164
+ graphRailStore.setIndexProgress(undefined);
165
+ const controller = new AbortController();
166
+ indexMonitorController = controller;
167
+ const releaseController = () => {
168
+ if (indexMonitorController === controller)
169
+ indexMonitorController = undefined;
170
+ };
171
+ try {
172
+ const api = new GitNexusHubApi(config);
173
+ const result = await runIndexRepoCommand({ api, remote, branch, ui, signal: controller.signal });
174
+ if (controller.signal.aborted || indexMonitorController !== controller) {
175
+ releaseController();
176
+ return;
177
+ }
178
+ if (result.kind === "blocked") {
179
+ releaseController();
180
+ return;
181
+ }
182
+ if (result.kind === "cancelled") {
183
+ releaseController();
184
+ ui.notify("Repository indexing cancelled.", "info");
185
+ return;
186
+ }
187
+ if (result.kind === "ready") {
188
+ const message = `${remote.fullName} is already indexed; no reindex was started.`;
189
+ ui.notify(message, "info");
190
+ await connect(controller.signal);
191
+ releaseController();
192
+ return;
193
+ }
194
+ void monitorRepoIndex({
195
+ api,
196
+ repoId: result.repoId,
197
+ ui: {
198
+ notify: (message, level) => ui.notify(message, level),
199
+ setStatus: (key, text) => {
200
+ if (indexMonitorController !== controller)
201
+ return;
202
+ ui.setStatus(key, text);
203
+ },
204
+ },
205
+ signal: controller.signal,
206
+ onProgress: (progress) => {
207
+ if (indexMonitorController !== controller)
208
+ return;
209
+ graphRailStore.setIndexProgress(progress);
210
+ },
211
+ onReady: async () => {
212
+ if (controller.signal.aborted || indexMonitorController !== controller)
213
+ return;
214
+ await connect(controller.signal);
215
+ if (controller.signal.aborted || indexMonitorController !== controller)
216
+ return;
217
+ ui.notify(`${remote.fullName} (${branch}) is indexed and ready.`, "info");
218
+ },
219
+ })
220
+ .catch((error) => {
221
+ if (controller.signal.aborted)
222
+ return;
223
+ const message = error instanceof Error ? error.message : String(error);
224
+ ui.notify(`GitNexus indexing monitor failed: ${message}`, "error");
225
+ })
226
+ .finally(releaseController);
227
+ return;
228
+ }
229
+ catch (error) {
230
+ releaseController();
231
+ if (controller.signal.aborted)
232
+ return;
233
+ const reason = error instanceof Error ? error.message : String(error);
234
+ const message = `GitNexus repository indexing failed: ${reason}`;
235
+ ui.notify(message, "error");
236
+ }
128
237
  }
129
238
  pi.on("session_start", async (_event, ctx) => {
130
239
  await connect();
131
240
  updateCreditStatus(ctx);
132
- if (startupNotice)
133
- ctx.ui.notify(startupNotice, inventory ? "info" : "warning");
241
+ if (startupNotice && !inventory)
242
+ ctx.ui.notify(startupNotice, "warning");
243
+ });
244
+ pi.on("session_shutdown", () => {
245
+ indexMonitorController?.abort();
134
246
  });
135
247
  pi.on("agent_settled", async (_event, ctx) => {
136
248
  if (!gatewayPolicy || ctx.model?.provider !== "gitnexus")
@@ -211,6 +323,7 @@ export default function gitnexusExtension(pi) {
211
323
  description: "Show GitNexus connection status",
212
324
  handler: async (_args, ctx) => {
213
325
  const config = resolveGitNexusConfig();
326
+ await connect();
214
327
  if (config)
215
328
  gatewayPolicy = await refreshGatewayPolicy(config);
216
329
  updateCreditStatus(ctx);
@@ -226,5 +339,12 @@ export default function gitnexusExtension(pi) {
226
339
  ctx.ui.notify(`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}${creditLine ? `, ${creditLine}` : ""}`, "info");
227
340
  },
228
341
  });
342
+ pi.registerCommand("gitnexus-index", {
343
+ description: "Index the current repository in GitNexus (optional branch)",
344
+ handler: async (args, ctx) => {
345
+ const branch = args.trim() || "default";
346
+ await requestRepositoryIndex(cwd, branch, ctx.ui);
347
+ },
348
+ });
229
349
  }
230
350
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { graphRailStore } from \"../../core/graph-rail-store.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport {\n\tapplyNexusSubagentEnvAliases,\n\tisDelegatedWorkerProcess,\n\tisExternalDelegationMode,\n\tregisterDelegateTaskTool,\n} from \"../subagent/index.ts\";\nimport { registerAugmentedGrep } from \"./augment.ts\";\nimport { registerChangeTracking } from \"./changes.ts\";\nimport { GitNexusClient, GitNexusClientError } from \"./client.ts\";\nimport { resolveGitNexusConfig, resolveHubUrl, saveGitNexusConfig } from \"./config.ts\";\nimport { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from \"./device-auth.ts\";\nimport { formatCreditBalance, readGatewayCache, refreshGatewayPolicy, registerAutoProvider } from \"./gateway.ts\";\nimport { spawnObservatoryFetch } from \"./observatory.ts\";\nimport { buildGitNexusPrompt } from \"./prompt.ts\";\nimport { withGitNexusRenderer } from \"./render.ts\";\nimport {\n\tgitRemoteSlug,\n\ttype IndexedRepo,\n\tmatchCurrentRepo,\n\tparseRepoInventory,\n\ttype RepoInventory,\n} from \"./resolve.ts\";\nimport { createGitNexusTools } from \"./tools.ts\";\n\n/** Resolve workflow skills in source mode and bundled dist/cli.js mode. */\nexport function resolveGitNexusSkillsDir(\n\tmoduleUrl: string = import.meta.url,\n\tpathExists: (path: string) => boolean = existsSync,\n): string | undefined {\n\tconst candidates = [\n\t\tfileURLToPath(new URL(\"./skills/\", moduleUrl)),\n\t\tfileURLToPath(new URL(\"./extensions/gitnexus/skills/\", moduleUrl)),\n\t];\n\treturn candidates.find(pathExists);\n}\n\n/**\n * GitNexus built-in extension: connects nexus-cli to the GitNexus hub.\n *\n * - session_start: resolve config + repo inventory, register the six graph\n * tools and the augmented grep. No token / hub down / repo unindexed all\n * degrade to a plain coding agent (graph is additive, never load-bearing).\n * - before_agent_start: append the GitNexus guidance block (ported from the\n * CLAUDE.md generator) to the system prompt.\n */\nexport default function gitnexusExtension(pi: ExtensionAPI): void {\n\tlet inventory: RepoInventory | undefined;\n\tlet current: IndexedRepo | undefined;\n\tlet activeClient: GitNexusClient | undefined;\n\tlet toolsRegistered = false;\n\tlet delegationRegistered = false;\n\tlet startupNotice: string | undefined;\n\tlet loginRequired = false;\n\n\tconst cwd = process.cwd();\n\n\t// Nexus Agent must also register at factory time: the initial model is\n\t// resolved before session_start fires, and a provider that appears after\n\t// that is invisible to it. Reads the policy cache the startup gate wrote.\n\tapplyNexusSubagentEnvAliases();\n\tlet gatewayPolicy = readGatewayCache();\n\tconst initialConfig = resolveGitNexusConfig();\n\tregisterAutoProvider(pi, initialConfig, gatewayPolicy);\n\n\tfunction registerDelegationIfAvailable(): void {\n\t\tif (\n\t\t\tdelegationRegistered ||\n\t\t\tisDelegatedWorkerProcess() ||\n\t\t\tisExternalDelegationMode() ||\n\t\t\t!resolveGitNexusConfig() ||\n\t\t\t!gatewayPolicy?.delegation\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tregisterDelegateTaskTool(pi, gatewayPolicy.delegation);\n\t\tdelegationRegistered = true;\n\t}\n\n\tregisterDelegationIfAvailable();\n\n\tfunction updateCreditStatus(ctx: { ui: { setStatus(key: string, text: string | undefined): void } }): void {\n\t\tctx.ui.setStatus(\"nexus-credits\", formatCreditBalance(gatewayPolicy));\n\t}\n\n\t// Built-in tool overrides must happen at factory time (like the bash-spawn-hook\n\t// example) — session_start registrations only add NEW names reliably. The wrapper\n\t// behaves as plain grep until connect() provides a client + current repo.\n\tregisterAugmentedGrep(\n\t\tpi,\n\t\tcwd,\n\t\t() => activeClient,\n\t\t() => current?.name,\n\t);\n\tregisterChangeTracking(pi, cwd);\n\n\tasync function connect(): Promise<void> {\n\t\tinventory = undefined;\n\t\tcurrent = undefined;\n\t\tactiveClient = undefined;\n\t\tstartupNotice = undefined;\n\t\tloginRequired = false;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) return;\n\t\tconst client = new GitNexusClient(config);\n\t\ttry {\n\t\t\tconst listResult = await client.callTool(\"list_repos\", {});\n\t\t\tinventory = parseRepoInventory(GitNexusClient.text(listResult));\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof GitNexusClientError ? error.message : String(error);\n\t\t\tif (error instanceof GitNexusClientError && error.kind === \"auth\") {\n\t\t\t\tloginRequired = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstartupNotice = `GitNexus unavailable: ${reason}`;\n\t\t\treturn;\n\t\t}\n\n\t\tcurrent = matchCurrentRepo(inventory, gitRemoteSlug(cwd));\n\t\tactiveClient = client;\n\t\tgraphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));\n\t\t// Observatory (community map) rides a detached subprocess + temp-file\n\t\t// handoff — in-process hub calls made after startup can starve in some\n\t\t// environments, a fresh process never does. The UI picks the file up\n\t\t// lazily via tryLoadObservatoryCache.\n\t\tif (current) spawnObservatoryFetch(config, current.name);\n\t\tgraphRailStore.setRepo(\n\t\t\tcurrent\n\t\t\t\t? {\n\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\tsymbols: current.symbols,\n\t\t\t\t\t\trelationships: current.relationships,\n\t\t\t\t\t\tindexedAt: current.indexedAt,\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tname: \"\",\n\t\t\t\t\t\tsymbols: \"0\",\n\t\t\t\t\t\trelationships: \"0\",\n\t\t\t\t\t\tindexedAt: \"\",\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t},\n\t\t\tcurrent !== undefined,\n\t\t);\n\t\tif (!toolsRegistered) {\n\t\t\tconst ctx = { client, currentRepo: () => current?.name, cwd };\n\t\t\tfor (const tool of createGitNexusTools(ctx)) pi.registerTool(withGitNexusRenderer(tool));\n\t\t\ttoolsRegistered = true;\n\t\t}\n\n\t\tstartupNotice = current\n\t\t\t? `GitNexus: connected — ${current.name} (${current.symbols} symbols, indexed ${current.indexedAt}), ${inventory.repos.length} repos available.`\n\t\t\t: `GitNexus: connected — current directory is not indexed; ${inventory.repos.length} indexed repos remain queryable. Index this repo from the Hub dashboard to unlock local graph context.`;\n\t}\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tawait connect();\n\t\tupdateCreditStatus(ctx);\n\t\tif (startupNotice) ctx.ui.notify(startupNotice, inventory ? \"info\" : \"warning\");\n\t});\n\n\tpi.on(\"agent_settled\", async (_event, ctx) => {\n\t\tif (!gatewayPolicy || ctx.model?.provider !== \"gitnexus\") return;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\tregisterDelegationIfAvailable();\n\t\tupdateCreditStatus(ctx);\n\t});\n\n\t// Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,\n\t// refactoring, pr-review, guide) — same SKILL.md content the Claude plugin\n\t// ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.\n\t// Skipped entirely when the user already has gitnexus skills (project or\n\t// global) so the startup screen doesn't report shadowed duplicates.\n\tpi.on(\"resources_discover\", (event) => {\n\t\tconst hasOwnGitnexusSkills =\n\t\t\texistsSync(join(event.cwd, \".agents\", \"skills\", \"gitnexus\")) ||\n\t\t\texistsSync(join(homedir(), \".agents\", \"skills\", \"gitnexus-debugging\"));\n\t\tif (hasOwnGitnexusSkills) return;\n\t\tconst skillsDir = resolveGitNexusSkillsDir();\n\t\tif (!skillsDir) return;\n\t\treturn { skillPaths: [skillsDir] };\n\t});\n\n\tpi.on(\"before_agent_start\", (event) => {\n\t\tif (!inventory) return;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n\\n${buildGitNexusPrompt(inventory, current)}` };\n\t});\n\n\tpi.registerCommand(\"gitnexus-login\", {\n\t\tdescription: \"Sign in to GitNexus (implementation of /login → GitNexus account; accepts a pasted token)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst hubUrl = resolveHubUrl();\n\t\t\tconst pasted = args.trim();\n\n\t\t\t// Pasting a token stays supported for CI and headless installs.\n\t\t\tif (pasted) {\n\t\t\t\ttry {\n\t\t\t\t\tawait new GitNexusClient({ hubUrl, token: pasted }).callTool(\"list_repos\", {});\n\t\t\t\t\tconst path = saveGitNexusConfig({ hubUrl, token: pasted });\n\t\t\t\t\tawait connect();\n\t\t\t\t\tctx.ui.notify(`GitNexus token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst deviceName = defaultDeviceName();\n\t\t\t\tconst fingerprint = deviceFingerprint();\n\t\t\t\tconst start = await startDeviceAuth(hubUrl, { deviceName, deviceFingerprint: fingerprint });\n\t\t\t\tconst link = start.verificationUrlComplete ?? start.verificationUrl;\n\t\t\t\t// The link carries the code, so an opened browser needs no typing.\n\t\t\t\t// Print it too: the launcher is best effort and can be headless.\n\t\t\t\tctx.ui.notify(`Code ${start.userCode} — opening ${link}`, \"info\");\n\t\t\t\topenBrowser(link);\n\n\t\t\t\tconst result = await pollDeviceAuth(hubUrl, start);\n\t\t\t\tconst config = {\n\t\t\t\t\thubUrl: result.hubUrl,\n\t\t\t\t\ttoken: result.token,\n\t\t\t\t\tdeviceFingerprint: fingerprint,\n\t\t\t\t\tdeviceName,\n\t\t\t\t};\n\t\t\t\tawait new GitNexusClient(config).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig(config);\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`Signed in. Token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-status\", {\n\t\tdescription: \"Show GitNexus connection status\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tconst config = resolveGitNexusConfig();\n\t\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\t\tupdateCreditStatus(ctx);\n\t\t\tif (!inventory) {\n\t\t\t\tconst message = loginRequired\n\t\t\t\t\t? \"GitNexus session expired. Run /login to sign in again.\"\n\t\t\t\t\t: (startupNotice ?? \"GitNexus: not signed in. Run /login.\");\n\t\t\t\tctx.ui.notify(message, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst repoLine = current ? `current repo: ${current.name}` : \"current repo: not indexed\";\n\t\t\tconst creditLine = formatCreditBalance(gatewayPolicy);\n\t\t\tctx.ui.notify(\n\t\t\t\t`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}${creditLine ? `, ${creditLine}` : \"\"}`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { graphRailStore } from \"../../core/graph-rail-store.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport {\n\tapplyNexusSubagentEnvAliases,\n\tisDelegatedWorkerProcess,\n\tisExternalDelegationMode,\n\tregisterDelegateTaskTool,\n} from \"../subagent/index.ts\";\nimport { registerAugmentedGrep } from \"./augment.ts\";\nimport { registerChangeTracking } from \"./changes.ts\";\nimport { GitNexusClient, GitNexusClientError } from \"./client.ts\";\nimport { resolveGitNexusConfig, resolveHubUrl, saveGitNexusConfig } from \"./config.ts\";\nimport { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from \"./device-auth.ts\";\nimport { formatCreditBalance, readGatewayCache, refreshGatewayPolicy, registerAutoProvider } from \"./gateway.ts\";\nimport { GitNexusHubApi } from \"./hub-api.ts\";\nimport { type IndexRepoUi, monitorRepoIndex, runIndexRepoCommand } from \"./index-repo.ts\";\nimport { spawnObservatoryFetch } from \"./observatory.ts\";\nimport { buildGitNexusPrompt } from \"./prompt.ts\";\nimport { withGitNexusRenderer } from \"./render.ts\";\nimport {\n\tcurrentGitHubRemote,\n\tgitRemoteSlug,\n\ttype IndexedRepo,\n\tmatchCurrentRepo,\n\tparseRepoInventory,\n\ttype RepoInventory,\n} from \"./resolve.ts\";\nimport { createGitNexusTools } from \"./tools.ts\";\n\n/** Resolve workflow skills in source mode and bundled dist/cli.js mode. */\nexport function resolveGitNexusSkillsDir(\n\tmoduleUrl: string = import.meta.url,\n\tpathExists: (path: string) => boolean = existsSync,\n): string | undefined {\n\tconst candidates = [\n\t\tfileURLToPath(new URL(\"./skills/\", moduleUrl)),\n\t\tfileURLToPath(new URL(\"./extensions/gitnexus/skills/\", moduleUrl)),\n\t];\n\treturn candidates.find(pathExists);\n}\n\n/**\n * GitNexus built-in extension: connects nexus-cli to the GitNexus hub.\n *\n * - session_start: resolve config + repo inventory, register the six graph\n * tools and the augmented grep. No token / hub down / repo unindexed all\n * degrade to a plain coding agent (graph is additive, never load-bearing).\n * - before_agent_start: append the GitNexus guidance block (ported from the\n * CLAUDE.md generator) to the system prompt.\n */\nexport default function gitnexusExtension(pi: ExtensionAPI): void {\n\tlet inventory: RepoInventory | undefined;\n\tlet current: IndexedRepo | undefined;\n\tlet activeClient: GitNexusClient | undefined;\n\tlet toolsRegistered = false;\n\tlet delegationRegistered = false;\n\tlet startupNotice: string | undefined;\n\tlet loginRequired = false;\n\tlet indexMonitorController: AbortController | undefined;\n\n\tconst cwd = process.cwd();\n\n\t// Nexus Agent must also register at factory time: the initial model is\n\t// resolved before session_start fires, and a provider that appears after\n\t// that is invisible to it. Reads the policy cache the startup gate wrote.\n\tapplyNexusSubagentEnvAliases();\n\tlet gatewayPolicy = readGatewayCache();\n\tconst initialConfig = resolveGitNexusConfig();\n\tregisterAutoProvider(pi, initialConfig, gatewayPolicy);\n\n\tfunction registerDelegationIfAvailable(): void {\n\t\tif (\n\t\t\tdelegationRegistered ||\n\t\t\tisDelegatedWorkerProcess() ||\n\t\t\tisExternalDelegationMode() ||\n\t\t\t!resolveGitNexusConfig() ||\n\t\t\t!gatewayPolicy?.delegation\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tregisterDelegateTaskTool(pi, gatewayPolicy.delegation);\n\t\tdelegationRegistered = true;\n\t}\n\n\tregisterDelegationIfAvailable();\n\n\tfunction updateCreditStatus(ctx: { ui: { setStatus(key: string, text: string | undefined): void } }): void {\n\t\tctx.ui.setStatus(\"nexus-credits\", formatCreditBalance(gatewayPolicy));\n\t}\n\n\t// Built-in tool overrides must happen at factory time (like the bash-spawn-hook\n\t// example) — session_start registrations only add NEW names reliably. The wrapper\n\t// behaves as plain grep until connect() provides a client + current repo.\n\tregisterAugmentedGrep(\n\t\tpi,\n\t\tcwd,\n\t\t() => activeClient,\n\t\t() => current?.name,\n\t);\n\tregisterChangeTracking(pi, cwd);\n\n\tfunction clearConnectionState(notice?: string, requiresLogin = false): void {\n\t\tinventory = undefined;\n\t\tcurrent = undefined;\n\t\tactiveClient = undefined;\n\t\tstartupNotice = notice;\n\t\tloginRequired = requiresLogin;\n\t}\n\n\tasync function connect(signal?: AbortSignal): Promise<void> {\n\t\tsignal?.throwIfAborted();\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) {\n\t\t\tclearConnectionState();\n\t\t\treturn;\n\t\t}\n\t\tconst client = new GitNexusClient(config);\n\t\tlet nextInventory: RepoInventory;\n\t\ttry {\n\t\t\tconst listResult = await client.callTool(\"list_repos\", {}, signal);\n\t\t\tsignal?.throwIfAborted();\n\t\t\tnextInventory = parseRepoInventory(GitNexusClient.text(listResult));\n\t\t} catch (error) {\n\t\t\tsignal?.throwIfAborted();\n\t\t\tconst reason = error instanceof GitNexusClientError ? error.message : String(error);\n\t\t\tif (error instanceof GitNexusClientError && error.kind === \"auth\") {\n\t\t\t\tclearConnectionState(undefined, true);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearConnectionState(`GitNexus unavailable: ${reason}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst nextCurrent = matchCurrentRepo(nextInventory, gitRemoteSlug(cwd));\n\t\tconst nextStartupNotice = nextCurrent\n\t\t\t? `GitNexus: connected — ${nextCurrent.name} (${nextCurrent.symbols} symbols, indexed ${nextCurrent.indexedAt}), ${nextInventory.repos.length} repos available.`\n\t\t\t: `GitNexus: connected — current directory is not indexed; ${nextInventory.repos.length} indexed repos remain queryable. Run /gitnexus-index to index this repo and unlock local graph context.`;\n\t\tsignal?.throwIfAborted();\n\t\tinventory = nextInventory;\n\t\tcurrent = nextCurrent;\n\t\tactiveClient = client;\n\t\tstartupNotice = nextStartupNotice;\n\t\tloginRequired = false;\n\t\tgraphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));\n\t\t// Observatory (community map) rides a detached subprocess + temp-file\n\t\t// handoff — in-process hub calls made after startup can starve in some\n\t\t// environments, a fresh process never does. The UI picks the file up\n\t\t// lazily via tryLoadObservatoryCache.\n\t\tif (current) spawnObservatoryFetch(config, current.name);\n\t\tgraphRailStore.setRepo(\n\t\t\tcurrent\n\t\t\t\t? {\n\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\tsymbols: current.symbols,\n\t\t\t\t\t\trelationships: current.relationships,\n\t\t\t\t\t\tindexedAt: current.indexedAt,\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tname: \"\",\n\t\t\t\t\t\tsymbols: \"0\",\n\t\t\t\t\t\trelationships: \"0\",\n\t\t\t\t\t\tindexedAt: \"\",\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t},\n\t\t\tcurrent !== undefined,\n\t\t);\n\t\tif (!toolsRegistered) {\n\t\t\tconst ctx = { client, currentRepo: () => current?.name, cwd };\n\t\t\tfor (const tool of createGitNexusTools(ctx)) pi.registerTool(withGitNexusRenderer(tool));\n\t\t\ttoolsRegistered = true;\n\t\t}\n\t}\n\n\tasync function requestRepositoryIndex(targetCwd: string, branch: string, ui: IndexRepoUi): Promise<void> {\n\t\tif (/\\s/.test(branch)) {\n\t\t\tconst message = \"Branch names containing whitespace are not supported.\";\n\t\t\tui.notify(message, \"error\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) {\n\t\t\tconst message = \"GitNexus is not signed in. Run /login.\";\n\t\t\tui.notify(message, \"warning\");\n\t\t\treturn;\n\t\t}\n\t\tconst remote = currentGitHubRemote(targetCwd);\n\t\tif (!remote) {\n\t\t\tconst message = `No supported github.com origin was found in ${targetCwd}.`;\n\t\t\tui.notify(message, \"error\");\n\t\t\treturn;\n\t\t}\n\n\t\tindexMonitorController?.abort();\n\t\tgraphRailStore.setIndexProgress(undefined);\n\t\tconst controller = new AbortController();\n\t\tindexMonitorController = controller;\n\t\tconst releaseController = () => {\n\t\t\tif (indexMonitorController === controller) indexMonitorController = undefined;\n\t\t};\n\n\t\ttry {\n\t\t\tconst api = new GitNexusHubApi(config);\n\t\t\tconst result = await runIndexRepoCommand({ api, remote, branch, ui, signal: controller.signal });\n\t\t\tif (controller.signal.aborted || indexMonitorController !== controller) {\n\t\t\t\treleaseController();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result.kind === \"blocked\") {\n\t\t\t\treleaseController();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result.kind === \"cancelled\") {\n\t\t\t\treleaseController();\n\t\t\t\tui.notify(\"Repository indexing cancelled.\", \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result.kind === \"ready\") {\n\t\t\t\tconst message = `${remote.fullName} is already indexed; no reindex was started.`;\n\t\t\t\tui.notify(message, \"info\");\n\t\t\t\tawait connect(controller.signal);\n\t\t\t\treleaseController();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvoid monitorRepoIndex({\n\t\t\t\tapi,\n\t\t\t\trepoId: result.repoId,\n\t\t\t\tui: {\n\t\t\t\t\tnotify: (message, level) => ui.notify(message, level),\n\t\t\t\t\tsetStatus: (key, text) => {\n\t\t\t\t\t\tif (indexMonitorController !== controller) return;\n\t\t\t\t\t\tui.setStatus(key, text);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsignal: controller.signal,\n\t\t\t\tonProgress: (progress) => {\n\t\t\t\t\tif (indexMonitorController !== controller) return;\n\t\t\t\t\tgraphRailStore.setIndexProgress(progress);\n\t\t\t\t},\n\t\t\t\tonReady: async () => {\n\t\t\t\t\tif (controller.signal.aborted || indexMonitorController !== controller) return;\n\t\t\t\t\tawait connect(controller.signal);\n\t\t\t\t\tif (controller.signal.aborted || indexMonitorController !== controller) return;\n\t\t\t\t\tui.notify(`${remote.fullName} (${branch}) is indexed and ready.`, \"info\");\n\t\t\t\t},\n\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\tif (controller.signal.aborted) return;\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tui.notify(`GitNexus indexing monitor failed: ${message}`, \"error\");\n\t\t\t\t})\n\t\t\t\t.finally(releaseController);\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\treleaseController();\n\t\t\tif (controller.signal.aborted) return;\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\tconst message = `GitNexus repository indexing failed: ${reason}`;\n\t\t\tui.notify(message, \"error\");\n\t\t}\n\t}\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tawait connect();\n\t\tupdateCreditStatus(ctx);\n\t\tif (startupNotice && !inventory) ctx.ui.notify(startupNotice, \"warning\");\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tindexMonitorController?.abort();\n\t});\n\n\tpi.on(\"agent_settled\", async (_event, ctx) => {\n\t\tif (!gatewayPolicy || ctx.model?.provider !== \"gitnexus\") return;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\tregisterDelegationIfAvailable();\n\t\tupdateCreditStatus(ctx);\n\t});\n\n\t// Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,\n\t// refactoring, pr-review, guide) — same SKILL.md content the Claude plugin\n\t// ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.\n\t// Skipped entirely when the user already has gitnexus skills (project or\n\t// global) so the startup screen doesn't report shadowed duplicates.\n\tpi.on(\"resources_discover\", (event) => {\n\t\tconst hasOwnGitnexusSkills =\n\t\t\texistsSync(join(event.cwd, \".agents\", \"skills\", \"gitnexus\")) ||\n\t\t\texistsSync(join(homedir(), \".agents\", \"skills\", \"gitnexus-debugging\"));\n\t\tif (hasOwnGitnexusSkills) return;\n\t\tconst skillsDir = resolveGitNexusSkillsDir();\n\t\tif (!skillsDir) return;\n\t\treturn { skillPaths: [skillsDir] };\n\t});\n\n\tpi.on(\"before_agent_start\", (event) => {\n\t\tif (!inventory) return;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n\\n${buildGitNexusPrompt(inventory, current)}` };\n\t});\n\n\tpi.registerCommand(\"gitnexus-login\", {\n\t\tdescription: \"Sign in to GitNexus (implementation of /login → GitNexus account; accepts a pasted token)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst hubUrl = resolveHubUrl();\n\t\t\tconst pasted = args.trim();\n\n\t\t\t// Pasting a token stays supported for CI and headless installs.\n\t\t\tif (pasted) {\n\t\t\t\ttry {\n\t\t\t\t\tawait new GitNexusClient({ hubUrl, token: pasted }).callTool(\"list_repos\", {});\n\t\t\t\t\tconst path = saveGitNexusConfig({ hubUrl, token: pasted });\n\t\t\t\t\tawait connect();\n\t\t\t\t\tctx.ui.notify(`GitNexus token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst deviceName = defaultDeviceName();\n\t\t\t\tconst fingerprint = deviceFingerprint();\n\t\t\t\tconst start = await startDeviceAuth(hubUrl, { deviceName, deviceFingerprint: fingerprint });\n\t\t\t\tconst link = start.verificationUrlComplete ?? start.verificationUrl;\n\t\t\t\t// The link carries the code, so an opened browser needs no typing.\n\t\t\t\t// Print it too: the launcher is best effort and can be headless.\n\t\t\t\tctx.ui.notify(`Code ${start.userCode} — opening ${link}`, \"info\");\n\t\t\t\topenBrowser(link);\n\n\t\t\t\tconst result = await pollDeviceAuth(hubUrl, start);\n\t\t\t\tconst config = {\n\t\t\t\t\thubUrl: result.hubUrl,\n\t\t\t\t\ttoken: result.token,\n\t\t\t\t\tdeviceFingerprint: fingerprint,\n\t\t\t\t\tdeviceName,\n\t\t\t\t};\n\t\t\t\tawait new GitNexusClient(config).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig(config);\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`Signed in. Token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-status\", {\n\t\tdescription: \"Show GitNexus connection status\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tconst config = resolveGitNexusConfig();\n\t\t\tawait connect();\n\t\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\t\tupdateCreditStatus(ctx);\n\t\t\tif (!inventory) {\n\t\t\t\tconst message = loginRequired\n\t\t\t\t\t? \"GitNexus session expired. Run /login to sign in again.\"\n\t\t\t\t\t: (startupNotice ?? \"GitNexus: not signed in. Run /login.\");\n\t\t\t\tctx.ui.notify(message, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst repoLine = current ? `current repo: ${current.name}` : \"current repo: not indexed\";\n\t\t\tconst creditLine = formatCreditBalance(gatewayPolicy);\n\t\t\tctx.ui.notify(\n\t\t\t\t`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}${creditLine ? `, ${creditLine}` : \"\"}`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-index\", {\n\t\tdescription: \"Index the current repository in GitNexus (optional branch)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst branch = args.trim() || \"default\";\n\t\t\tawait requestRepositoryIndex(cwd, branch, ctx.ui);\n\t\t},\n\t});\n}\n"]}
@@ -13,8 +13,17 @@ export interface RepoInventory {
13
13
  repos: IndexedRepo[];
14
14
  groups: IndexedGroup[];
15
15
  }
16
+ export interface GitHubRemote {
17
+ name: string;
18
+ fullName: string;
19
+ cloneUrl: string;
20
+ }
16
21
  /** Parse the markdown returned by the hub list_repos tool. */
17
22
  export declare function parseRepoInventory(markdown: string): RepoInventory;
23
+ /** Parse a supported GitHub origin without preserving credentials or URL parameters. */
24
+ export declare function parseGitHubRemote(remoteUrl: string): GitHubRemote | undefined;
25
+ /** Resolve the current repository's origin as a canonical GitHub remote. */
26
+ export declare function currentGitHubRemote(cwd: string): GitHubRemote | undefined;
18
27
  /** Read the git remote of cwd and normalize to "owner/name" (undefined outside a repo). */
19
28
  export declare function gitRemoteSlug(cwd: string): string | undefined;
20
29
  /** Match the cwd's remote against the hub inventory. Exact slug first, then name suffix. */
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/extensions/gitnexus/resolve.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAuBlE;AAED,2FAA2F;AAC3F,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAY7D;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAO5G","sourcesContent":["import { spawnSync } from \"node:child_process\";\n\n/** One indexed repo as reported by the hub's list_repos tool. */\nexport interface IndexedRepo {\n\tname: string;\n\tsymbols: string;\n\trelationships: string;\n\tindexedAt: string;\n}\n\nexport interface IndexedGroup {\n\tname: string;\n\trepoCount: string;\n}\n\nexport interface RepoInventory {\n\trepos: IndexedRepo[];\n\tgroups: IndexedGroup[];\n}\n\n/** Parse the markdown returned by the hub list_repos tool. */\nexport function parseRepoInventory(markdown: string): RepoInventory {\n\tconst repos: IndexedRepo[] = [];\n\tconst groups: IndexedGroup[] = [];\n\tconst repoRe = /^- \\*\\*([^*]+)\\*\\* \\(([\\d,]+) symbols, ([\\d,]+) relationships\\) — indexed (.+)$/;\n\tconst groupRe = /^- \\*\\*(@[^*]+)\\*\\* \\((\\d+) repos?/;\n\tfor (const line of markdown.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tconst repoMatch = repoRe.exec(trimmed);\n\t\tif (repoMatch?.[1] && repoMatch[2] && repoMatch[3] && repoMatch[4]) {\n\t\t\trepos.push({\n\t\t\t\tname: repoMatch[1],\n\t\t\t\tsymbols: repoMatch[2],\n\t\t\t\trelationships: repoMatch[3],\n\t\t\t\tindexedAt: repoMatch[4],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst groupMatch = groupRe.exec(trimmed);\n\t\tif (groupMatch?.[1] && groupMatch[2]) {\n\t\t\tgroups.push({ name: groupMatch[1], repoCount: groupMatch[2] });\n\t\t}\n\t}\n\treturn { repos, groups };\n}\n\n/** Read the git remote of cwd and normalize to \"owner/name\" (undefined outside a repo). */\nexport function gitRemoteSlug(cwd: string): string | undefined {\n\tconst result = spawnSync(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n\t\tcwd,\n\t\tencoding: \"utf8\",\n\t\ttimeout: 3000,\n\t});\n\tif (result.status !== 0) return undefined;\n\tconst url = (result.stdout ?? \"\").trim();\n\tif (!url) return undefined;\n\t// https://github.com/owner/name(.git) | git@github.com:owner/name(.git)\n\tconst match = /[/:]([^/:]+\\/[^/:]+?)(?:\\.git)?$/.exec(url);\n\treturn match?.[1];\n}\n\n/** Match the cwd's remote against the hub inventory. Exact slug first, then name suffix. */\nexport function matchCurrentRepo(inventory: RepoInventory, slug: string | undefined): IndexedRepo | undefined {\n\tif (!slug) return undefined;\n\tconst lower = slug.toLowerCase();\n\tconst exact = inventory.repos.find((r) => r.name.toLowerCase() === lower);\n\tif (exact) return exact;\n\tconst name = lower.split(\"/\")[1] ?? lower;\n\treturn inventory.repos.find((r) => r.name.toLowerCase().endsWith(`/${name}`));\n}\n"]}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/extensions/gitnexus/resolve.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAuBlE;AAaD,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAwB7E;AAUD,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAGzE;AAED,2FAA2F;AAC3F,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7D;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAO5G","sourcesContent":["import { spawnSync } from \"node:child_process\";\n\n/** One indexed repo as reported by the hub's list_repos tool. */\nexport interface IndexedRepo {\n\tname: string;\n\tsymbols: string;\n\trelationships: string;\n\tindexedAt: string;\n}\n\nexport interface IndexedGroup {\n\tname: string;\n\trepoCount: string;\n}\n\nexport interface RepoInventory {\n\trepos: IndexedRepo[];\n\tgroups: IndexedGroup[];\n}\n\nexport interface GitHubRemote {\n\tname: string;\n\tfullName: string;\n\tcloneUrl: string;\n}\n\n/** Parse the markdown returned by the hub list_repos tool. */\nexport function parseRepoInventory(markdown: string): RepoInventory {\n\tconst repos: IndexedRepo[] = [];\n\tconst groups: IndexedGroup[] = [];\n\tconst repoRe = /^- \\*\\*([^*]+)\\*\\* \\(([\\d,]+) symbols, ([\\d,]+) relationships\\) — indexed (.+)$/;\n\tconst groupRe = /^- \\*\\*(@[^*]+)\\*\\* \\((\\d+) repos?/;\n\tfor (const line of markdown.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tconst repoMatch = repoRe.exec(trimmed);\n\t\tif (repoMatch?.[1] && repoMatch[2] && repoMatch[3] && repoMatch[4]) {\n\t\t\trepos.push({\n\t\t\t\tname: repoMatch[1],\n\t\t\t\tsymbols: repoMatch[2],\n\t\t\t\trelationships: repoMatch[3],\n\t\t\t\tindexedAt: repoMatch[4],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst groupMatch = groupRe.exec(trimmed);\n\t\tif (groupMatch?.[1] && groupMatch[2]) {\n\t\t\tgroups.push({ name: groupMatch[1], repoCount: groupMatch[2] });\n\t\t}\n\t}\n\treturn { repos, groups };\n}\n\nfunction gitOriginUrl(cwd: string): string | undefined {\n\tconst result = spawnSync(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n\t\tcwd,\n\t\tencoding: \"utf8\",\n\t\ttimeout: 3000,\n\t});\n\tif (result.status !== 0) return undefined;\n\tconst url = (result.stdout ?? \"\").trim();\n\treturn url || undefined;\n}\n\n/** Parse a supported GitHub origin without preserving credentials or URL parameters. */\nexport function parseGitHubRemote(remoteUrl: string): GitHubRemote | undefined {\n\tif (!remoteUrl || /\\s/.test(remoteUrl)) return undefined;\n\n\tconst scpMatch = /^git@github\\.com:([^/]+)\\/([^/]+)$/.exec(remoteUrl);\n\tif (scpMatch?.[1] && scpMatch[2]) return normalizeGitHubRemote(scpMatch[1], scpMatch[2]);\n\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(remoteUrl);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (parsed.hostname !== \"github.com\" || parsed.port || parsed.search || parsed.hash) return undefined;\n\tif (parsed.protocol === \"https:\") {\n\t\tif (parsed.username || parsed.password) return undefined;\n\t} else if (parsed.protocol === \"ssh:\") {\n\t\tif (parsed.username !== \"git\" || parsed.password) return undefined;\n\t} else {\n\t\treturn undefined;\n\t}\n\n\tconst pathMatch = /^\\/([^/]+)\\/([^/]+)$/.exec(parsed.pathname);\n\tif (!pathMatch?.[1] || !pathMatch[2]) return undefined;\n\treturn normalizeGitHubRemote(pathMatch[1], pathMatch[2]);\n}\n\nfunction normalizeGitHubRemote(owner: string, rawName: string): GitHubRemote | undefined {\n\tconst name = rawName.endsWith(\".git\") ? rawName.slice(0, -4) : rawName;\n\tif (!/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/.test(owner)) return undefined;\n\tif (name.length > 100 || !/^[A-Za-z0-9._-]+$/.test(name) || name === \".\" || name === \"..\") return undefined;\n\tconst fullName = `${owner}/${name}`;\n\treturn { name, fullName, cloneUrl: `https://github.com/${fullName}.git` };\n}\n\n/** Resolve the current repository's origin as a canonical GitHub remote. */\nexport function currentGitHubRemote(cwd: string): GitHubRemote | undefined {\n\tconst remoteUrl = gitOriginUrl(cwd);\n\treturn remoteUrl ? parseGitHubRemote(remoteUrl) : undefined;\n}\n\n/** Read the git remote of cwd and normalize to \"owner/name\" (undefined outside a repo). */\nexport function gitRemoteSlug(cwd: string): string | undefined {\n\tconst url = gitOriginUrl(cwd);\n\tif (!url) return undefined;\n\t// https://github.com/owner/name(.git) | git@github.com:owner/name(.git)\n\tconst match = /[/:]([^/:]+\\/[^/:]+?)(?:\\.git)?$/.exec(url);\n\treturn match?.[1];\n}\n\n/** Match the cwd's remote against the hub inventory. Exact slug first, then name suffix. */\nexport function matchCurrentRepo(inventory: RepoInventory, slug: string | undefined): IndexedRepo | undefined {\n\tif (!slug) return undefined;\n\tconst lower = slug.toLowerCase();\n\tconst exact = inventory.repos.find((r) => r.name.toLowerCase() === lower);\n\tif (exact) return exact;\n\tconst name = lower.split(\"/\")[1] ?? lower;\n\treturn inventory.repos.find((r) => r.name.toLowerCase().endsWith(`/${name}`));\n}\n"]}
@@ -24,8 +24,7 @@ export function parseRepoInventory(markdown) {
24
24
  }
25
25
  return { repos, groups };
26
26
  }
27
- /** Read the git remote of cwd and normalize to "owner/name" (undefined outside a repo). */
28
- export function gitRemoteSlug(cwd) {
27
+ function gitOriginUrl(cwd) {
29
28
  const result = spawnSync("git", ["remote", "get-url", "origin"], {
30
29
  cwd,
31
30
  encoding: "utf8",
@@ -34,6 +33,57 @@ export function gitRemoteSlug(cwd) {
34
33
  if (result.status !== 0)
35
34
  return undefined;
36
35
  const url = (result.stdout ?? "").trim();
36
+ return url || undefined;
37
+ }
38
+ /** Parse a supported GitHub origin without preserving credentials or URL parameters. */
39
+ export function parseGitHubRemote(remoteUrl) {
40
+ if (!remoteUrl || /\s/.test(remoteUrl))
41
+ return undefined;
42
+ const scpMatch = /^git@github\.com:([^/]+)\/([^/]+)$/.exec(remoteUrl);
43
+ if (scpMatch?.[1] && scpMatch[2])
44
+ return normalizeGitHubRemote(scpMatch[1], scpMatch[2]);
45
+ let parsed;
46
+ try {
47
+ parsed = new URL(remoteUrl);
48
+ }
49
+ catch {
50
+ return undefined;
51
+ }
52
+ if (parsed.hostname !== "github.com" || parsed.port || parsed.search || parsed.hash)
53
+ return undefined;
54
+ if (parsed.protocol === "https:") {
55
+ if (parsed.username || parsed.password)
56
+ return undefined;
57
+ }
58
+ else if (parsed.protocol === "ssh:") {
59
+ if (parsed.username !== "git" || parsed.password)
60
+ return undefined;
61
+ }
62
+ else {
63
+ return undefined;
64
+ }
65
+ const pathMatch = /^\/([^/]+)\/([^/]+)$/.exec(parsed.pathname);
66
+ if (!pathMatch?.[1] || !pathMatch[2])
67
+ return undefined;
68
+ return normalizeGitHubRemote(pathMatch[1], pathMatch[2]);
69
+ }
70
+ function normalizeGitHubRemote(owner, rawName) {
71
+ const name = rawName.endsWith(".git") ? rawName.slice(0, -4) : rawName;
72
+ if (!/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/.test(owner))
73
+ return undefined;
74
+ if (name.length > 100 || !/^[A-Za-z0-9._-]+$/.test(name) || name === "." || name === "..")
75
+ return undefined;
76
+ const fullName = `${owner}/${name}`;
77
+ return { name, fullName, cloneUrl: `https://github.com/${fullName}.git` };
78
+ }
79
+ /** Resolve the current repository's origin as a canonical GitHub remote. */
80
+ export function currentGitHubRemote(cwd) {
81
+ const remoteUrl = gitOriginUrl(cwd);
82
+ return remoteUrl ? parseGitHubRemote(remoteUrl) : undefined;
83
+ }
84
+ /** Read the git remote of cwd and normalize to "owner/name" (undefined outside a repo). */
85
+ export function gitRemoteSlug(cwd) {
86
+ const url = gitOriginUrl(cwd);
37
87
  if (!url)
38
88
  return undefined;
39
89
  // https://github.com/owner/name(.git) | git@github.com:owner/name(.git)
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAoB/C,8DAA8D;AAC9D,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAiB;IACnE,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,MAAM,GAAmB,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,mFAAiF,CAAC;IACjG,MAAM,OAAO,GAAG,oCAAoC,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,KAAK,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;gBAClB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;gBACrB,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC3B,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;aACvB,CAAC,CAAC;YACH,SAAS;QACV,CAAC;QACD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;IACF,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAAA,CACzB;AAED,2FAA2F;AAC3F,MAAM,UAAU,aAAa,CAAC,GAAW,EAAsB;IAC9D,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE;QAChE,GAAG;QACH,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,IAAI;KACb,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,wEAAwE;IACxE,MAAM,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAAA,CAClB;AAED,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAAC,SAAwB,EAAE,IAAwB,EAA2B;IAC7G,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;IAC1E,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IAC1C,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;AAAA,CAC9E","sourcesContent":["import { spawnSync } from \"node:child_process\";\n\n/** One indexed repo as reported by the hub's list_repos tool. */\nexport interface IndexedRepo {\n\tname: string;\n\tsymbols: string;\n\trelationships: string;\n\tindexedAt: string;\n}\n\nexport interface IndexedGroup {\n\tname: string;\n\trepoCount: string;\n}\n\nexport interface RepoInventory {\n\trepos: IndexedRepo[];\n\tgroups: IndexedGroup[];\n}\n\n/** Parse the markdown returned by the hub list_repos tool. */\nexport function parseRepoInventory(markdown: string): RepoInventory {\n\tconst repos: IndexedRepo[] = [];\n\tconst groups: IndexedGroup[] = [];\n\tconst repoRe = /^- \\*\\*([^*]+)\\*\\* \\(([\\d,]+) symbols, ([\\d,]+) relationships\\) — indexed (.+)$/;\n\tconst groupRe = /^- \\*\\*(@[^*]+)\\*\\* \\((\\d+) repos?/;\n\tfor (const line of markdown.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tconst repoMatch = repoRe.exec(trimmed);\n\t\tif (repoMatch?.[1] && repoMatch[2] && repoMatch[3] && repoMatch[4]) {\n\t\t\trepos.push({\n\t\t\t\tname: repoMatch[1],\n\t\t\t\tsymbols: repoMatch[2],\n\t\t\t\trelationships: repoMatch[3],\n\t\t\t\tindexedAt: repoMatch[4],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst groupMatch = groupRe.exec(trimmed);\n\t\tif (groupMatch?.[1] && groupMatch[2]) {\n\t\t\tgroups.push({ name: groupMatch[1], repoCount: groupMatch[2] });\n\t\t}\n\t}\n\treturn { repos, groups };\n}\n\n/** Read the git remote of cwd and normalize to \"owner/name\" (undefined outside a repo). */\nexport function gitRemoteSlug(cwd: string): string | undefined {\n\tconst result = spawnSync(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n\t\tcwd,\n\t\tencoding: \"utf8\",\n\t\ttimeout: 3000,\n\t});\n\tif (result.status !== 0) return undefined;\n\tconst url = (result.stdout ?? \"\").trim();\n\tif (!url) return undefined;\n\t// https://github.com/owner/name(.git) | git@github.com:owner/name(.git)\n\tconst match = /[/:]([^/:]+\\/[^/:]+?)(?:\\.git)?$/.exec(url);\n\treturn match?.[1];\n}\n\n/** Match the cwd's remote against the hub inventory. Exact slug first, then name suffix. */\nexport function matchCurrentRepo(inventory: RepoInventory, slug: string | undefined): IndexedRepo | undefined {\n\tif (!slug) return undefined;\n\tconst lower = slug.toLowerCase();\n\tconst exact = inventory.repos.find((r) => r.name.toLowerCase() === lower);\n\tif (exact) return exact;\n\tconst name = lower.split(\"/\")[1] ?? lower;\n\treturn inventory.repos.find((r) => r.name.toLowerCase().endsWith(`/${name}`));\n}\n"]}
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\n\n/** One indexed repo as reported by the hub's list_repos tool. */\nexport interface IndexedRepo {\n\tname: string;\n\tsymbols: string;\n\trelationships: string;\n\tindexedAt: string;\n}\n\nexport interface IndexedGroup {\n\tname: string;\n\trepoCount: string;\n}\n\nexport interface RepoInventory {\n\trepos: IndexedRepo[];\n\tgroups: IndexedGroup[];\n}\n\nexport interface GitHubRemote {\n\tname: string;\n\tfullName: string;\n\tcloneUrl: string;\n}\n\n/** Parse the markdown returned by the hub list_repos tool. */\nexport function parseRepoInventory(markdown: string): RepoInventory {\n\tconst repos: IndexedRepo[] = [];\n\tconst groups: IndexedGroup[] = [];\n\tconst repoRe = /^- \\*\\*([^*]+)\\*\\* \\(([\\d,]+) symbols, ([\\d,]+) relationships\\) — indexed (.+)$/;\n\tconst groupRe = /^- \\*\\*(@[^*]+)\\*\\* \\((\\d+) repos?/;\n\tfor (const line of markdown.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tconst repoMatch = repoRe.exec(trimmed);\n\t\tif (repoMatch?.[1] && repoMatch[2] && repoMatch[3] && repoMatch[4]) {\n\t\t\trepos.push({\n\t\t\t\tname: repoMatch[1],\n\t\t\t\tsymbols: repoMatch[2],\n\t\t\t\trelationships: repoMatch[3],\n\t\t\t\tindexedAt: repoMatch[4],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst groupMatch = groupRe.exec(trimmed);\n\t\tif (groupMatch?.[1] && groupMatch[2]) {\n\t\t\tgroups.push({ name: groupMatch[1], repoCount: groupMatch[2] });\n\t\t}\n\t}\n\treturn { repos, groups };\n}\n\nfunction gitOriginUrl(cwd: string): string | undefined {\n\tconst result = spawnSync(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n\t\tcwd,\n\t\tencoding: \"utf8\",\n\t\ttimeout: 3000,\n\t});\n\tif (result.status !== 0) return undefined;\n\tconst url = (result.stdout ?? \"\").trim();\n\treturn url || undefined;\n}\n\n/** Parse a supported GitHub origin without preserving credentials or URL parameters. */\nexport function parseGitHubRemote(remoteUrl: string): GitHubRemote | undefined {\n\tif (!remoteUrl || /\\s/.test(remoteUrl)) return undefined;\n\n\tconst scpMatch = /^git@github\\.com:([^/]+)\\/([^/]+)$/.exec(remoteUrl);\n\tif (scpMatch?.[1] && scpMatch[2]) return normalizeGitHubRemote(scpMatch[1], scpMatch[2]);\n\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(remoteUrl);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (parsed.hostname !== \"github.com\" || parsed.port || parsed.search || parsed.hash) return undefined;\n\tif (parsed.protocol === \"https:\") {\n\t\tif (parsed.username || parsed.password) return undefined;\n\t} else if (parsed.protocol === \"ssh:\") {\n\t\tif (parsed.username !== \"git\" || parsed.password) return undefined;\n\t} else {\n\t\treturn undefined;\n\t}\n\n\tconst pathMatch = /^\\/([^/]+)\\/([^/]+)$/.exec(parsed.pathname);\n\tif (!pathMatch?.[1] || !pathMatch[2]) return undefined;\n\treturn normalizeGitHubRemote(pathMatch[1], pathMatch[2]);\n}\n\nfunction normalizeGitHubRemote(owner: string, rawName: string): GitHubRemote | undefined {\n\tconst name = rawName.endsWith(\".git\") ? rawName.slice(0, -4) : rawName;\n\tif (!/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/.test(owner)) return undefined;\n\tif (name.length > 100 || !/^[A-Za-z0-9._-]+$/.test(name) || name === \".\" || name === \"..\") return undefined;\n\tconst fullName = `${owner}/${name}`;\n\treturn { name, fullName, cloneUrl: `https://github.com/${fullName}.git` };\n}\n\n/** Resolve the current repository's origin as a canonical GitHub remote. */\nexport function currentGitHubRemote(cwd: string): GitHubRemote | undefined {\n\tconst remoteUrl = gitOriginUrl(cwd);\n\treturn remoteUrl ? parseGitHubRemote(remoteUrl) : undefined;\n}\n\n/** Read the git remote of cwd and normalize to \"owner/name\" (undefined outside a repo). */\nexport function gitRemoteSlug(cwd: string): string | undefined {\n\tconst url = gitOriginUrl(cwd);\n\tif (!url) return undefined;\n\t// https://github.com/owner/name(.git) | git@github.com:owner/name(.git)\n\tconst match = /[/:]([^/:]+\\/[^/:]+?)(?:\\.git)?$/.exec(url);\n\treturn match?.[1];\n}\n\n/** Match the cwd's remote against the hub inventory. Exact slug first, then name suffix. */\nexport function matchCurrentRepo(inventory: RepoInventory, slug: string | undefined): IndexedRepo | undefined {\n\tif (!slug) return undefined;\n\tconst lower = slug.toLowerCase();\n\tconst exact = inventory.repos.find((r) => r.name.toLowerCase() === lower);\n\tif (exact) return exact;\n\tconst name = lower.split(\"/\")[1] ?? lower;\n\treturn inventory.repos.find((r) => r.name.toLowerCase().endsWith(`/${name}`));\n}\n"]}