githits 0.3.2 → 0.3.3

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "GitHits plugins for Claude Code - code examples from global open source",
9
- "version": "0.3.2"
9
+ "version": "0.3.3"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githits",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Code examples from global open source for developers and AI assistants",
5
5
  "author": {
6
6
  "name": "GitHits"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githits",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Code examples from global open source for developers and AI assistants",
5
5
  "author": {
6
6
  "name": "GitHits"
package/dist/cli.js CHANGED
@@ -49,11 +49,11 @@ import {
49
49
  shouldRunUpdateCheck,
50
50
  startTelemetrySpan,
51
51
  withTelemetrySpan
52
- } from "./shared/chunk-zarrkzvq.js";
52
+ } from "./shared/chunk-2d202fpq.js";
53
53
  import {
54
54
  __require,
55
55
  version
56
- } from "./shared/chunk-w5kw8sef.js";
56
+ } from "./shared/chunk-tze0rsay.js";
57
57
 
58
58
  // src/cli.ts
59
59
  import { Command } from "commander";
@@ -4140,6 +4140,127 @@ function buildRange2(envelope) {
4140
4140
  return `${envelope.totalLines} lines`;
4141
4141
  return;
4142
4142
  }
4143
+ // src/shared/auto-login.ts
4144
+ var AUTO_LOGIN_ELIGIBLE_COMMANDS = new Set([
4145
+ "init",
4146
+ "example",
4147
+ "languages",
4148
+ "feedback",
4149
+ "search",
4150
+ "search-status",
4151
+ "code files",
4152
+ "code read",
4153
+ "code grep",
4154
+ "docs list",
4155
+ "docs read",
4156
+ "pkg info",
4157
+ "pkg vulns",
4158
+ "pkg deps",
4159
+ "pkg changelog"
4160
+ ]);
4161
+ function getCommandPath(command) {
4162
+ const names = [];
4163
+ let current = command;
4164
+ while (current) {
4165
+ const name = current.name();
4166
+ if (name && name !== "githits") {
4167
+ names.unshift(name);
4168
+ }
4169
+ current = current.parent ?? null;
4170
+ }
4171
+ return names;
4172
+ }
4173
+ function isAutoLoginEligibleCommand(command, runtime = {
4174
+ stdinIsTTY: Boolean(process.stdin.isTTY),
4175
+ stdoutIsTTY: Boolean(process.stdout.isTTY)
4176
+ }) {
4177
+ const commandPath = getCommandPath(command).join(" ");
4178
+ if (commandPath === "init" && command.opts().skipLogin === true) {
4179
+ return false;
4180
+ }
4181
+ if (!AUTO_LOGIN_ELIGIBLE_COMMANDS.has(commandPath)) {
4182
+ return false;
4183
+ }
4184
+ if (!runtime.stdinIsTTY || !runtime.stdoutIsTTY) {
4185
+ return false;
4186
+ }
4187
+ return true;
4188
+ }
4189
+ async function maybeAutoLoginBeforeCommand(command, deps) {
4190
+ if (!isAutoLoginEligibleCommand(command, {
4191
+ stdinIsTTY: deps.stdinIsTTY ?? Boolean(process.stdin.isTTY),
4192
+ stdoutIsTTY: deps.stdoutIsTTY ?? Boolean(process.stdout.isTTY)
4193
+ })) {
4194
+ return { status: "skipped" };
4195
+ }
4196
+ const container = await deps.createContainer();
4197
+ if (container.hasValidToken) {
4198
+ return { status: "already-authenticated" };
4199
+ }
4200
+ const result = await deps.loginFlow({}, container);
4201
+ switch (result.status) {
4202
+ case "success":
4203
+ return { status: "authenticated", message: result.message };
4204
+ case "already_authenticated":
4205
+ return { status: "already-authenticated", message: result.message };
4206
+ case "failed":
4207
+ return { status: "failed", message: result.message };
4208
+ }
4209
+ }
4210
+
4211
+ // src/shared/root-cli-pre-action.ts
4212
+ function createRootCliPreAction(deps) {
4213
+ return async (thisCommand, actionCommand) => {
4214
+ if (thisCommand.opts().color === false) {
4215
+ process.env.NO_COLOR = "1";
4216
+ }
4217
+ const command = actionCommand ?? thisCommand;
4218
+ const authResult = await maybeAutoLoginBeforeCommand(command, {
4219
+ ...deps,
4220
+ stdinIsTTY: deps.stdinIsTTY,
4221
+ stdoutIsTTY: deps.stdoutIsTTY
4222
+ });
4223
+ if (authResult.status === "authenticated") {
4224
+ const continuationMessage = getPostLoginContinuationMessage(command);
4225
+ if (continuationMessage) {
4226
+ console.error(continuationMessage);
4227
+ }
4228
+ }
4229
+ if (authResult.status !== "failed") {
4230
+ return;
4231
+ }
4232
+ console.error(`${authResult.message}
4233
+ `);
4234
+ console.error("Run `githits login` to try again.");
4235
+ (deps.exit ?? process.exit)(1);
4236
+ };
4237
+ }
4238
+ function getPostLoginContinuationMessage(command) {
4239
+ switch (getCommandPath(command).join(" ")) {
4240
+ case "init":
4241
+ return "Authentication complete. Continuing setup...";
4242
+ case "example":
4243
+ return "Authentication complete. Running example search...";
4244
+ case "languages":
4245
+ return "Authentication complete. Loading supported languages...";
4246
+ case "feedback":
4247
+ return "Authentication complete. Submitting feedback...";
4248
+ case "search":
4249
+ case "search-status":
4250
+ case "code files":
4251
+ case "code read":
4252
+ case "code grep":
4253
+ case "docs list":
4254
+ case "docs read":
4255
+ case "pkg info":
4256
+ case "pkg vulns":
4257
+ case "pkg deps":
4258
+ case "pkg changelog":
4259
+ return "Authentication complete. Running command...";
4260
+ default:
4261
+ return;
4262
+ }
4263
+ }
4143
4264
  // src/shared/unified-search-request.ts
4144
4265
  var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
4145
4266
  function buildUnifiedSearchParams(input) {
@@ -5613,7 +5734,7 @@ grep run. --symbol-field hydrates enclosing symbol metadata (appears under each
5613
5734
  match in --verbose output; full payload in --json).`;
5614
5735
  function registerCodeGrepCommand(pkgCommand) {
5615
5736
  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 (requires --git-ref)").option("--git-ref <ref>", "Tag, commit, branch, or HEAD. Required with --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) => {
5616
- const { createContainer: createContainer2 } = await import("./shared/chunk-rwcs5gyy.js");
5737
+ const { createContainer: createContainer2 } = await import("./shared/chunk-b6avnx6d.js");
5617
5738
  const deps = await createContainer2();
5618
5739
  await pkgGrepAction(arg1, arg2, arg3, options, {
5619
5740
  codeNavigationService: deps.codeNavigationService,
@@ -6132,7 +6253,7 @@ function registerExampleCommand(program) {
6132
6253
  });
6133
6254
  }
6134
6255
  async function loadContainer() {
6135
- const { createContainer: createContainer2 } = await import("./shared/chunk-rwcs5gyy.js");
6256
+ const { createContainer: createContainer2 } = await import("./shared/chunk-b6avnx6d.js");
6136
6257
  return createContainer2();
6137
6258
  }
6138
6259
  // src/commands/feedback.ts
@@ -6902,6 +7023,16 @@ class ExitPromptError extends Error {
6902
7023
  name = "ExitPromptError";
6903
7024
  }
6904
7025
  // src/commands/login.ts
7026
+ var stdoutLoginOutput = {
7027
+ write: (message) => {
7028
+ console.log(message);
7029
+ }
7030
+ };
7031
+ var stderrLoginOutput = {
7032
+ write: (message) => {
7033
+ console.error(message);
7034
+ }
7035
+ };
6905
7036
  var TIMEOUT_MS = 5 * 60 * 1000;
6906
7037
  function randomPort() {
6907
7038
  return Math.floor(Math.random() * 2000) + 8000;
@@ -6933,7 +7064,7 @@ async function preflightAuthPersistence(authStorage, mcpUrl) {
6933
7064
  };
6934
7065
  }
6935
7066
  }
6936
- async function loginFlow(options, deps) {
7067
+ async function loginFlow(options, deps, output = stdoutLoginOutput) {
6937
7068
  const { authService, authStorage, browserService, mcpUrl } = deps;
6938
7069
  if (options.port !== undefined && (Number.isNaN(options.port) || options.port < 1 || options.port > 65535)) {
6939
7070
  return {
@@ -6947,10 +7078,10 @@ async function loginFlow(options, deps) {
6947
7078
  if (!isExpired) {
6948
7079
  return { status: "already_authenticated", message: "Already logged in." };
6949
7080
  }
6950
- console.log(`Token expired. Starting new login...
7081
+ output.write(`Token expired. Starting new login...
6951
7082
  `);
6952
7083
  } else if (existing && options.force) {
6953
- console.log(`Re-authenticating (--force flag)...
7084
+ output.write(`Re-authenticating (--force flag)...
6954
7085
  `);
6955
7086
  }
6956
7087
  if (!existing) {
@@ -6959,7 +7090,7 @@ async function loginFlow(options, deps) {
6959
7090
  const persistenceError = await preflightAuthPersistence(authStorage, mcpUrl);
6960
7091
  if (persistenceError)
6961
7092
  return persistenceError;
6962
- console.log("Discovering OAuth endpoints...");
7093
+ output.write("Discovering OAuth endpoints...");
6963
7094
  const metadata = await authService.discoverEndpoints(mcpUrl);
6964
7095
  let client = await authStorage.loadClient(mcpUrl);
6965
7096
  let port;
@@ -6968,7 +7099,7 @@ async function loginFlow(options, deps) {
6968
7099
  if (options.port) {
6969
7100
  redirectUri = `http://127.0.0.1:${options.port}/callback`;
6970
7101
  if (redirectUri !== client.redirectUri) {
6971
- console.log("Registering CLI client with new port...");
7102
+ output.write("Registering CLI client with new port...");
6972
7103
  const registration = await authService.registerClient({
6973
7104
  registrationEndpoint: metadata.registrationEndpoint,
6974
7105
  redirectUri
@@ -6989,7 +7120,7 @@ async function loginFlow(options, deps) {
6989
7120
  } else {
6990
7121
  port = options.port ?? randomPort();
6991
7122
  redirectUri = `http://127.0.0.1:${port}/callback`;
6992
- console.log("Registering CLI client...");
7123
+ output.write("Registering CLI client...");
6993
7124
  const registration = await authService.registerClient({
6994
7125
  registrationEndpoint: metadata.registrationEndpoint,
6995
7126
  redirectUri
@@ -7011,15 +7142,15 @@ async function loginFlow(options, deps) {
7011
7142
  });
7012
7143
  const serverPromise = authService.startCallbackServer(port, state);
7013
7144
  if (options.browser === false) {
7014
- console.log(`Open this URL in your browser:
7145
+ output.write(`Open this URL in your browser:
7015
7146
  `);
7016
- console.log(` ${authUrl}
7147
+ output.write(` ${authUrl}
7017
7148
  `);
7018
7149
  } else {
7019
- console.log("Opening browser...");
7150
+ output.write("Opening browser...");
7020
7151
  await browserService.open(authUrl);
7021
7152
  }
7022
- console.log(`Waiting for authentication...
7153
+ output.write(`Waiting for authentication...
7023
7154
  `);
7024
7155
  let timeoutId;
7025
7156
  const timeoutPromise = new Promise((_, reject) => {
@@ -7077,7 +7208,7 @@ async function loginFlow(options, deps) {
7077
7208
  };
7078
7209
  }
7079
7210
  async function loginAction(options, deps) {
7080
- const result = await loginFlow(options, deps);
7211
+ const result = await loginFlow(options, deps, stdoutLoginOutput);
7081
7212
  if (result.status === "already_authenticated") {
7082
7213
  console.log(`Already logged in.
7083
7214
  `);
@@ -9375,7 +9506,7 @@ function requireSearchService(deps) {
9375
9506
  return deps.codeNavigationService;
9376
9507
  }
9377
9508
  async function loadContainer2() {
9378
- const { createContainer: createContainer2 } = await import("./shared/chunk-rwcs5gyy.js");
9509
+ const { createContainer: createContainer2 } = await import("./shared/chunk-b6avnx6d.js");
9379
9510
  return createContainer2();
9380
9511
  }
9381
9512
  function parseTargetSpecs(specs) {
@@ -9741,12 +9872,14 @@ if (isTelemetryEnabled()) {
9741
9872
  flushTelemetry(exitCode);
9742
9873
  });
9743
9874
  }
9744
- program.name("githits").description("Code examples from global open source for your AI assistant").version(version).option("--no-color", "Disable colored output").hook("preAction", (thisCommand, actionCommand) => {
9745
- if (thisCommand.opts().color === false) {
9746
- process.env.NO_COLOR = "1";
9747
- }
9875
+ var rootCliPreAction = createRootCliPreAction({
9876
+ createContainer,
9877
+ loginFlow: (options, deps) => loginFlow(options, deps, stderrLoginOutput)
9878
+ });
9879
+ program.name("githits").description("Code examples from global open source for your AI assistant").version(version).option("--no-color", "Disable colored output").hook("preAction", async (thisCommand, actionCommand) => {
9748
9880
  const command = actionCommand ?? thisCommand;
9749
9881
  commandSpans.set(command, startTelemetrySpan(getTelemetryCommandName(command)));
9882
+ await rootCliPreAction(thisCommand, actionCommand);
9750
9883
  }).hook("postAction", (_thisCommand, actionCommand) => {
9751
9884
  endTelemetrySpan(commandSpans.get(actionCommand));
9752
9885
  }).addHelpText("after", `
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  version
3
- } from "./shared/chunk-w5kw8sef.js";
3
+ } from "./shared/chunk-tze0rsay.js";
4
4
  export {
5
5
  version
6
6
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __require,
3
3
  version
4
- } from "./chunk-w5kw8sef.js";
4
+ } from "./chunk-tze0rsay.js";
5
5
 
6
6
  // src/services/app-config-paths.ts
7
7
  var APP_DIR = "githits";
@@ -278,43 +278,121 @@ function parseRefreshTokenResponse(data) {
278
278
  }
279
279
  function successHtml(title = "Authentication successful") {
280
280
  return `<!DOCTYPE html>
281
- <html><head><title>GitHits CLI</title>
281
+ <html><head>
282
+ <title>GitHits CLI</title>
283
+ <meta charset="utf-8">
284
+ <link rel="preconnect" href="https://fonts.googleapis.com">
285
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
286
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Lexend:wght@600&display=swap" rel="stylesheet">
282
287
  <style>
288
+ *, *::before, *::after { box-sizing: border-box; }
283
289
  body {
284
- font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
290
+ margin: 0;
291
+ min-height: 100vh;
292
+ width: 100%;
293
+ padding: 16px;
294
+ background: #21262d;
295
+ color: #ffffff;
296
+ font-family: 'Inter', sans-serif;
285
297
  display: flex;
298
+ align-items: center;
286
299
  justify-content: center;
300
+ }
301
+ .content {
302
+ display: flex;
303
+ flex-direction: column;
287
304
  align-items: center;
288
- height: 100vh;
305
+ gap: 20px;
306
+ padding: 0 16px;
307
+ }
308
+ .message {
309
+ display: flex;
310
+ flex-direction: column;
311
+ align-items: center;
312
+ gap: 8px;
313
+ }
314
+ .success-icon {
315
+ width: 48px;
316
+ height: 48px;
317
+ border-radius: 50%;
318
+ border: 2px solid #57fec9;
319
+ background: transparent;
320
+ display: flex;
321
+ align-items: center;
322
+ justify-content: center;
323
+ }
324
+ .heading {
325
+ font-family: 'Lexend', sans-serif;
326
+ font-weight: 600;
327
+ font-size: 32px;
328
+ line-height: 40px;
329
+ color: #ffffff;
289
330
  margin: 0;
290
- background: radial-gradient(circle at center center, #4d3648, #3a2835, #261a22, #0d1117);
331
+ text-align: center;
332
+ text-wrap: pretty;
291
333
  }
292
- .card {
334
+ .text {
335
+ font-family: 'Inter', sans-serif;
336
+ font-weight: 400;
337
+ font-size: 16px;
338
+ line-height: 24px;
339
+ margin: 0;
293
340
  text-align: center;
294
- background: rgba(13, 17, 23, 0.75);
295
- padding: 3rem;
296
- border-radius: 16px;
297
- border: 1px solid rgba(244, 11, 166, 0.35);
298
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
299
- max-width: 720px;
300
- }
301
- h1 {
302
- color: #f40ba6;
303
- margin-bottom: 0.75rem;
304
- font-size: 3rem;
305
- font-weight: 700;
306
- }
307
- p {
308
- color: #f385a5;
309
- font-size: 1.1rem;
341
+ text-wrap: pretty;
342
+ }
343
+ .text-muted {
344
+ color: #abb2bf;
345
+ }
346
+ .tip {
347
+ font-family: 'Inter', sans-serif;
348
+ font-weight: 400;
349
+ font-size: 14px;
350
+ line-height: 20px;
351
+ color: #abb2bf;
310
352
  margin: 0;
353
+ text-align: center;
354
+ text-wrap: pretty;
355
+ }
356
+ .tip-label {
357
+ font-weight: 600;
358
+ color: #ffffff;
359
+ }
360
+ code {
361
+ font-family: 'Consolas', monospace;
362
+ font-size: 13px;
363
+ background: rgba(255, 255, 255, 0.08);
364
+ padding: 1px 6px;
365
+ border-radius: 4px;
366
+ color: #ffffff;
311
367
  }
312
368
  </style>
313
369
  </head>
314
370
  <body>
315
- <div class="card">
316
- <h1>${escapeHtml(title)}</h1>
317
- <p>You can close this window and return to the terminal.</p>
371
+ <div class="content">
372
+ <div class="success-icon" aria-hidden="true">
373
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="#57fec9" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
374
+ <polyline points="20 6 9 17 4 12" />
375
+ </svg>
376
+ </div>
377
+ <div class="message">
378
+ <h1 class="heading">${escapeHtml(title)}</h1>
379
+ <p class="text text-muted">You can close this window and return to the terminal.</p>
380
+ </div>
381
+
382
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 554 129.3" width="103" height="24" role="img" aria-label="GitHits">
383
+ <title>GitHits</title>
384
+ <defs>
385
+ <linearGradient id="wm-grad" x1="234.9" y1="64.7" x2="555.5" y2="64.7" gradientUnits="userSpaceOnUse">
386
+ <stop offset="0" style="stop-color: #ff4fae" />
387
+ <stop offset="1" style="stop-color: #ff872f" />
388
+ </linearGradient>
389
+ </defs>
390
+ <path d="M148.6,29.1c7.9,0,14.4-6.4,14.4-14.4S156.6.3,148.6.3s-14.4,6.4-14.4,14.4,6.4,14.4,14.4,14.4Z" fill="#ff4fae" />
391
+ <path d="M383.9,29.1c7.9,0,14.4-6.4,14.4-14.4s-6.4-14.4-14.4-14.4-14.4,6.4-14.4,14.4,6.4,14.4,14.4,14.4ZM396.4,40.8h-25v86.6h25V40.8ZM454.3,8.5h-25v32.3h-18.8v24h18.8v62.6h25v-62.6h18.8v-24h-18.8V8.5ZM553.1,92.2c-.9-2.6-2.2-4.9-4.1-6.9-2.2-2.4-5.1-4.4-8.8-6.2-3.7-1.8-8.2-3.4-13.4-4.9-4.1-1.1-7.3-2.1-9.6-3-2.4-.9-4.1-1.7-5.3-2.4-1.1-.8-1.9-1.7-2.5-2.9-.6-1.1-.9-2.3-.9-3.5s.2-2.4.7-3.4,1.2-1.9,2.2-2.6c1-.7,2.2-1.3,3.7-1.6s3.2-.5,5-.5,4.5.4,7.1,1.3c2.6.9,5.2,2.1,7.7,3.7,2.5,1.6,4.7,3.3,6.7,5.2l12.5-14.2c-2.8-2.8-6-5.2-9.6-7.3-3.7-2.1-7.7-3.7-11.9-4.8-4.3-1.1-8.7-1.7-13.2-1.7s-8.8.7-12.9,1.9c-4.1,1.3-7.7,3.1-10.8,5.5s-5.6,5.2-7.3,8.5c-1.8,3.3-2.6,7-2.6,11s.5,6.4,1.6,9.2c1,2.8,2.5,5.3,4.5,7.7,2.3,2.5,5.4,4.7,9.3,6.7s8.6,3.7,14.2,5.1c3.6,1,6.6,1.9,8.9,2.8,2.3.8,4,1.6,5.1,2.3,2,1.4,3,3.3,3,5.7s-.2,2.4-.7,3.5-1.2,2-2.2,2.7-2.2,1.3-3.5,1.7c-1.4.4-2.9.6-4.5.6-4.2,0-8.4-.8-12.5-2.5-4.2-1.6-7.9-4.3-11.2-8l-14.7,12.8c3.8,4.8,8.9,8.6,15.2,11.4,6.3,2.8,13.5,4.1,21.7,4.1s12.5-1.2,17.8-3.7,9.4-5.8,12.4-10.1c3-4.3,4.5-9.2,4.5-14.7s-.4-6-1.3-8.6h-.3ZM327.2,60.5h-50.2V6h-25v121.4h25v-42.8h50.2v42.8h25V6h-25v54.5Z" fill="url(#wm-grad)" />
392
+ <path d="M239.1,64.8v-24h-18.8V8.5h-25v32.3h-18.8v24h18.8v62.6h25v-62.6h18.8ZM161.1,40.8h-25v86.6h25V40.8ZM91.6,84.6h-26.8v-24h54s1.2,4.3,1.1,12.1c-.3,30.6-25.3,55.5-55.9,55.7h-.5C27.4,128.4-1.6,98.3,0,61.8,1.5,29.6,27.4,3.4,59.6,1.4c21-1.2,40,7.7,52.4,22.4l-17.2,17.2c-7.7-10.1-20.3-16.4-34.3-15.4-19.4,1.4-35,17.1-36.4,36.5-1.6,23,16.6,42.2,39.3,42.2s28-19.7,28-19.7h.2Z" fill="#ff4fae" />
393
+ </svg>
394
+
395
+ <p class="tip"><span class="tip-label">TIP:</span> Run <code>npx githits --help</code> to discover what else you can do.</p>
318
396
  </div>
319
397
  </body></html>`;
320
398
  }
@@ -356,44 +434,121 @@ function evaluateCallback(input) {
356
434
  function errorHtml(error, nextStep) {
357
435
  const nextStepHtml = nextStep ? `<p>${escapeHtml(nextStep)}</p>` : "";
358
436
  return `<!DOCTYPE html>
359
- <html><head><title>GitHits CLI</title>
437
+ <html><head>
438
+ <title>GitHits CLI</title>
439
+ <meta charset="utf-8">
440
+ <link rel="preconnect" href="https://fonts.googleapis.com">
441
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
442
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Lexend:wght@600&display=swap" rel="stylesheet">
360
443
  <style>
444
+ *, *::before, *::after { box-sizing: border-box; }
361
445
  body {
362
- font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
446
+ margin: 0;
447
+ min-height: 100vh;
448
+ width: 100%;
449
+ padding: 16px;
450
+ background: #21262d;
451
+ color: #ffffff;
452
+ font-family: 'Inter', sans-serif;
363
453
  display: flex;
454
+ align-items: center;
364
455
  justify-content: center;
456
+ }
457
+ .content {
458
+ display: flex;
459
+ flex-direction: column;
460
+ align-items: center;
461
+ gap: 20px;
462
+ padding: 0 16px;
463
+ }
464
+ .message {
465
+ display: flex;
466
+ flex-direction: column;
365
467
  align-items: center;
366
- height: 100vh;
468
+ gap: 8px;
469
+ }
470
+ .error-icon {
471
+ width: 48px;
472
+ height: 48px;
473
+ border-radius: 50%;
474
+ border: 2px solid #ff5a6a;
475
+ background: transparent;
476
+ display: flex;
477
+ align-items: center;
478
+ justify-content: center;
479
+ }
480
+ .heading {
481
+ font-family: 'Lexend', sans-serif;
482
+ font-weight: 600;
483
+ font-size: 32px;
484
+ line-height: 40px;
485
+ color: #ffffff;
367
486
  margin: 0;
368
- background: radial-gradient(circle at center center, #4d3648, #3a2835, #261a22, #0d1117);
487
+ text-align: center;
488
+ text-wrap: pretty;
369
489
  }
370
- .card {
490
+ .text {
491
+ font-family: 'Inter', sans-serif;
492
+ font-weight: 400;
493
+ font-size: 16px;
494
+ line-height: 24px;
495
+ margin: 0;
371
496
  text-align: center;
372
- background: rgba(13, 17, 23, 0.75);
373
- padding: 3rem;
374
- border-radius: 16px;
375
- border: 1px solid rgba(239, 68, 68, 0.35);
376
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
377
- max-width: 720px;
378
- }
379
- h1 {
380
- color: #ef4444;
381
- margin-bottom: 0.75rem;
382
- font-size: 3rem;
383
- font-weight: 700;
384
- }
385
- p {
386
- color: #f385a5;
387
- font-size: 1.1rem;
497
+ text-wrap: pretty;
498
+ }
499
+ .text-muted {
500
+ color: #abb2bf;
501
+ }
502
+ .footer-text {
503
+ font-family: 'Inter', sans-serif;
504
+ font-weight: 400;
505
+ font-size: 14px;
506
+ line-height: 20px;
507
+ color: #abb2bf;
388
508
  margin: 0;
509
+ text-align: center;
510
+ text-wrap: pretty;
511
+ }
512
+ .footer-link {
513
+ color: #ffffff;
514
+ text-decoration: underline;
515
+ text-underline-offset: 2px;
516
+ }
517
+ .footer-link:hover {
518
+ color: #abb2bf;
389
519
  }
390
520
  </style>
391
521
  </head>
392
522
  <body>
393
- <div class="card">
394
- <h1>Authentication failed</h1>
395
- <p>${escapeHtml(error)}</p>
523
+ <div class="content">
524
+ <div class="error-icon" aria-hidden="true">
525
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="#ff5a6a" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
526
+ <line x1="18" y1="6" x2="6" y2="18"/>
527
+ <line x1="6" y1="6" x2="18" y2="18"/>
528
+ </svg>
529
+ </div>
530
+
531
+ <div class="message">
532
+ <h1 class="heading">Authentication failed</h1>
533
+ <p class="text text-muted">${escapeHtml(error)}</p>
534
+ </div>
535
+
396
536
  ${nextStepHtml}
537
+
538
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 554 129.3" width="103" height="24" role="img" aria-label="GitHits">
539
+ <title>GitHits</title>
540
+ <defs>
541
+ <linearGradient id="wm-grad" x1="234.9" y1="64.7" x2="555.5" y2="64.7" gradientUnits="userSpaceOnUse">
542
+ <stop offset="0" style="stop-color: #ff4fae" />
543
+ <stop offset="1" style="stop-color: #ff872f" />
544
+ </linearGradient>
545
+ </defs>
546
+ <path d="M148.6,29.1c7.9,0,14.4-6.4,14.4-14.4S156.6.3,148.6.3s-14.4,6.4-14.4,14.4,6.4,14.4,14.4,14.4Z" fill="#ff4fae" />
547
+ <path d="M383.9,29.1c7.9,0,14.4-6.4,14.4-14.4s-6.4-14.4-14.4-14.4-14.4,6.4-14.4,14.4,6.4,14.4,14.4,14.4ZM396.4,40.8h-25v86.6h25V40.8ZM454.3,8.5h-25v32.3h-18.8v24h18.8v62.6h25v-62.6h18.8v-24h-18.8V8.5ZM553.1,92.2c-.9-2.6-2.2-4.9-4.1-6.9-2.2-2.4-5.1-4.4-8.8-6.2-3.7-1.8-8.2-3.4-13.4-4.9-4.1-1.1-7.3-2.1-9.6-3-2.4-.9-4.1-1.7-5.3-2.4-1.1-.8-1.9-1.7-2.5-2.9-.6-1.1-.9-2.3-.9-3.5s.2-2.4.7-3.4,1.2-1.9,2.2-2.6c1-.7,2.2-1.3,3.7-1.6s3.2-.5,5-.5,4.5.4,7.1,1.3c2.6.9,5.2,2.1,7.7,3.7,2.5,1.6,4.7,3.3,6.7,5.2l12.5-14.2c-2.8-2.8-6-5.2-9.6-7.3-3.7-2.1-7.7-3.7-11.9-4.8-4.3-1.1-8.7-1.7-13.2-1.7s-8.8.7-12.9,1.9c-4.1,1.3-7.7,3.1-10.8,5.5s-5.6,5.2-7.3,8.5c-1.8,3.3-2.6,7-2.6,11s.5,6.4,1.6,9.2c1,2.8,2.5,5.3,4.5,7.7,2.3,2.5,5.4,4.7,9.3,6.7s8.6,3.7,14.2,5.1c3.6,1,6.6,1.9,8.9,2.8,2.3.8,4,1.6,5.1,2.3,2,1.4,3,3.3,3,5.7s-.2,2.4-.7,3.5-1.2,2-2.2,2.7-2.2,1.3-3.5,1.7c-1.4.4-2.9.6-4.5.6-4.2,0-8.4-.8-12.5-2.5-4.2-1.6-7.9-4.3-11.2-8l-14.7,12.8c3.8,4.8,8.9,8.6,15.2,11.4,6.3,2.8,13.5,4.1,21.7,4.1s12.5-1.2,17.8-3.7,9.4-5.8,12.4-10.1c3-4.3,4.5-9.2,4.5-14.7s-.4-6-1.3-8.6h-.3ZM327.2,60.5h-50.2V6h-25v121.4h25v-42.8h50.2v42.8h25V6h-25v54.5Z" fill="url(#wm-grad)" />
548
+ <path d="M239.1,64.8v-24h-18.8V8.5h-25v32.3h-18.8v24h18.8v62.6h25v-62.6h18.8ZM161.1,40.8h-25v86.6h25V40.8ZM91.6,84.6h-26.8v-24h54s1.2,4.3,1.1,12.1c-.3,30.6-25.3,55.5-55.9,55.7h-.5C27.4,128.4-1.6,98.3,0,61.8,1.5,29.6,27.4,3.4,59.6,1.4c21-1.2,40,7.7,52.4,22.4l-17.2,17.2c-7.7-10.1-20.3-16.4-34.3-15.4-19.4,1.4-35,17.1-36.4,36.5-1.6,23,16.6,42.2,39.3,42.2s28-19.7,28-19.7h.2Z" fill="#ff4fae" />
549
+ </svg>
550
+
551
+ <p class="footer-text">Having trouble? Check our <a class="footer-link" href="https://app.githits.com/docs/" target="_blank" rel="noopener noreferrer">documentation</a> or contact <a class="footer-link" href="mailto:support@githits.com">support</a>.</p>
397
552
  </div>
398
553
  </body></html>`;
399
554
  }
@@ -2,8 +2,8 @@ import {
2
2
  createAuthCommandDependencies,
3
3
  createAuthStatusDependencies,
4
4
  createContainer
5
- } from "./chunk-zarrkzvq.js";
6
- import"./chunk-w5kw8sef.js";
5
+ } from "./chunk-2d202fpq.js";
6
+ import"./chunk-tze0rsay.js";
7
7
  export {
8
8
  createContainer,
9
9
  createAuthStatusDependencies,
@@ -1,6 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
  // package.json
4
- var version = "0.3.2";
4
+ var version = "0.3.3";
5
5
 
6
6
  export { __require, version };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githits",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Code examples from global open source for developers and AI assistants.",
5
5
  "mcpServers": {
6
6
  "githits": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "githits",
3
3
  "description": "CLI companion for GitHits - code examples from global open source for developers and AI assistants",
4
- "version": "0.3.2",
4
+ "version": "0.3.3",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -33,6 +33,8 @@
33
33
  "build": "bunup --dts --target node --packages=external --exports && chmod +x dist/cli.js",
34
34
  "dev": "bun run ./src/cli.ts",
35
35
  "inspector": "npx @modelcontextprotocol/inspector bun run dev mcp",
36
+ "smoke:cli": "bun run scripts/cli-smoke.ts",
37
+ "smoke:mcp": "bun run scripts/mcp-smoke.ts",
36
38
  "test": "bun test",
37
39
  "typecheck": "tsc",
38
40
  "format": "biome format --write .",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githits",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Code examples from global open source for developers and AI assistants",
5
5
  "author": {
6
6
  "name": "GitHits"