repomind 0.12.0 → 0.14.0

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 (2) hide show
  1. package/dist/index.js +184 -50
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -77407,24 +77407,80 @@ var TokenExpiredError = class extends Error {
77407
77407
  }
77408
77408
  };
77409
77409
  var PlanLimitError = class extends Error {
77410
- constructor(plan, used, limit) {
77411
- super(`Plan limit reached: ${used}/${limit}`);
77412
- this.plan = plan;
77413
- this.used = used;
77414
- this.limit = limit;
77410
+ plan;
77411
+ used;
77412
+ limit;
77413
+ // Codigo de maquina do motivo (no_plan/past_due/canceled/quota_exceeded), quando
77414
+ // a API o envia. Permite UX propria sem fazer parse de string.
77415
+ reason;
77416
+ // Mensagem pronta para exibir. Preferir esta a montar cópia no cliente.
77417
+ displayMessage;
77418
+ action;
77419
+ constructor(info3) {
77420
+ super(`Plan limit reached: ${info3.used}/${info3.limit}`);
77415
77421
  this.name = "PlanLimitError";
77422
+ this.plan = info3.plan;
77423
+ this.used = info3.used;
77424
+ this.limit = info3.limit;
77425
+ this.reason = info3.reason;
77426
+ this.displayMessage = info3.displayMessage;
77427
+ this.action = info3.action;
77416
77428
  }
77417
77429
  };
77418
- function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch) {
77430
+ function planLimitErrorFromBody(errBody) {
77431
+ const used = Number(errBody.used ?? 0);
77432
+ const limit = Number(errBody.limit ?? 0);
77433
+ const rawAction = errBody.action;
77434
+ const action = rawAction && typeof rawAction.label === "string" && typeof rawAction.url === "string" ? { label: rawAction.label, url: rawAction.url } : { label: "Fa\xE7a upgrade", url: `${WEB_BASE_URL}/dashboard/plano` };
77435
+ const displayMessage = typeof errBody.message === "string" && errBody.message.length > 0 ? errBody.message : `Limite do plano atingido (${used}/${limit} commits este m\xEAs)`;
77436
+ return new PlanLimitError({
77437
+ plan: String(errBody.plan ?? "unknown"),
77438
+ used,
77439
+ limit,
77440
+ reason: typeof errBody.reason === "string" ? errBody.reason : void 0,
77441
+ displayMessage,
77442
+ action
77443
+ });
77444
+ }
77445
+ var OutdatedCliError = class extends Error {
77446
+ constructor(currentVersion, minVersion, latestVersion) {
77447
+ super(`CLI desatualizado: ${currentVersion} < ${minVersion}`);
77448
+ this.currentVersion = currentVersion;
77449
+ this.minVersion = minVersion;
77450
+ this.latestVersion = latestVersion;
77451
+ this.name = "OutdatedCliError";
77452
+ }
77453
+ };
77454
+ var CLI_VERSION_HEADER = "X-RepoMind-CLI-Version";
77455
+ var CLI_LATEST_HEADER = "X-RepoMind-CLI-Latest";
77456
+ function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch, cliVersion = "0.14.0") {
77457
+ let latestCliVersion = null;
77458
+ function baseHeaders(token) {
77459
+ return {
77460
+ "Content-Type": "application/json",
77461
+ [CLI_VERSION_HEADER]: cliVersion,
77462
+ ...token ? { Authorization: `Bearer ${token}` } : {}
77463
+ };
77464
+ }
77465
+ function captureLatest(res) {
77466
+ const latest = res.headers.get(CLI_LATEST_HEADER);
77467
+ if (latest) latestCliVersion = latest;
77468
+ }
77469
+ function throwIfOutdated(status, errBody) {
77470
+ if (status === 426 && errBody.error === "cli_outdated") {
77471
+ throw new OutdatedCliError(
77472
+ cliVersion,
77473
+ String(errBody.minVersion ?? ""),
77474
+ String(errBody.latestVersion ?? "")
77475
+ );
77476
+ }
77477
+ }
77419
77478
  async function request2(method, path2, token, body, timeoutMs) {
77420
77479
  let res;
77421
77480
  try {
77422
77481
  res = await fetchFn(`${baseUrl}${path2}`, {
77423
77482
  method,
77424
- headers: {
77425
- "Content-Type": "application/json",
77426
- ...token ? { Authorization: `Bearer ${token}` } : {}
77427
- },
77483
+ headers: baseHeaders(token),
77428
77484
  ...body !== void 0 ? { body: JSON.stringify(body) } : {},
77429
77485
  signal: AbortSignal.timeout(timeoutMs ?? FETCH_TIMEOUT_MS)
77430
77486
  });
@@ -77435,6 +77491,7 @@ function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch) {
77435
77491
  err instanceof Error ? err.message : "network error"
77436
77492
  );
77437
77493
  }
77494
+ captureLatest(res);
77438
77495
  if (!res.ok) {
77439
77496
  const errBody = await res.json().catch(() => ({}));
77440
77497
  if (DEBUG)
@@ -77446,12 +77503,9 @@ function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch) {
77446
77503
  throw new TokenExpiredError();
77447
77504
  }
77448
77505
  if (res.status === 402 && errBody.error === "plan_limit_reached") {
77449
- throw new PlanLimitError(
77450
- String(errBody.plan ?? "unknown"),
77451
- Number(errBody.used ?? 0),
77452
- Number(errBody.limit ?? 0)
77453
- );
77506
+ throw planLimitErrorFromBody(errBody);
77454
77507
  }
77508
+ throwIfOutdated(res.status, errBody);
77455
77509
  const msg = errBody.detail ? `${errBody.error}: ${errBody.detail}` : String(errBody.error ?? "request failed");
77456
77510
  throw new ApiError(res.status, msg);
77457
77511
  }
@@ -77463,9 +77517,8 @@ function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch) {
77463
77517
  res = await fetchFn(`${baseUrl}${path2}`, {
77464
77518
  method: "POST",
77465
77519
  headers: {
77466
- "Content-Type": "application/json",
77467
- Accept: "text/event-stream",
77468
- ...token ? { Authorization: `Bearer ${token}` } : {}
77520
+ ...baseHeaders(token),
77521
+ Accept: "text/event-stream"
77469
77522
  },
77470
77523
  body: JSON.stringify(body),
77471
77524
  signal: AbortSignal.timeout(timeoutMs ?? STREAM_TIMEOUT_MS)
@@ -77477,17 +77530,15 @@ function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch) {
77477
77530
  err instanceof Error ? err.message : "network error"
77478
77531
  );
77479
77532
  }
77533
+ captureLatest(res);
77480
77534
  if (!res.ok) {
77481
77535
  const errBody = await res.json().catch(() => ({}));
77482
77536
  if (DEBUG)
77483
77537
  console.error(`[api-client] POST ${path2} \u2192 ${res.status}`, errBody);
77484
77538
  if (res.status === 402 && errBody.error === "plan_limit_reached") {
77485
- throw new PlanLimitError(
77486
- String(errBody.plan ?? "unknown"),
77487
- Number(errBody.used ?? 0),
77488
- Number(errBody.limit ?? 0)
77489
- );
77539
+ throw planLimitErrorFromBody(errBody);
77490
77540
  }
77541
+ throwIfOutdated(res.status, errBody);
77491
77542
  const msg = errBody.detail ? `${errBody.error}: ${errBody.detail}` : String(errBody.error ?? "request failed");
77492
77543
  throw new ApiError(res.status, msg);
77493
77544
  }
@@ -77500,7 +77551,10 @@ function createApiClient(baseUrl = DEFAULT_BASE_URL2, fetchFn = fetch) {
77500
77551
  get(path2, token) {
77501
77552
  return request2("GET", path2, token);
77502
77553
  },
77503
- postStream
77554
+ postStream,
77555
+ getLatestCliVersion() {
77556
+ return latestCliVersion;
77557
+ }
77504
77558
  };
77505
77559
  }
77506
77560
  var apiClient = createApiClient();
@@ -86148,6 +86202,17 @@ async function readRepoConfig(cwd2 = process.cwd()) {
86148
86202
  }
86149
86203
  }
86150
86204
 
86205
+ // src/lib/update-check.ts
86206
+ function getUpdateInfo() {
86207
+ const latest = apiClient.getLatestCliVersion();
86208
+ if (!latest) return void 0;
86209
+ const current = "0.14.0";
86210
+ return { current, latest };
86211
+ }
86212
+
86213
+ // src/lib/update-hint.ts
86214
+ var UPDATE_COMMAND = "npm i -g repomind (ou bun add -g repomind)";
86215
+
86151
86216
  // ../../node_modules/.bun/@inkjs+ui@2.0.0+4d0808a67a30d5ab/node_modules/@inkjs/ui/build/components/badge/badge.js
86152
86217
  var import_react32 = __toESM(require_react(), 1);
86153
86218
 
@@ -88871,6 +88936,14 @@ async function* parseSSEStream(stream) {
88871
88936
  }
88872
88937
 
88873
88938
  // src/hooks/use-pipeline-stream.ts
88939
+ function tryParsePlanLimitBody(message) {
88940
+ try {
88941
+ const parsed = JSON.parse(message);
88942
+ return parsed.error === "plan_limit_reached" ? parsed : null;
88943
+ } catch {
88944
+ return null;
88945
+ }
88946
+ }
88874
88947
  function usePipelineStream(options) {
88875
88948
  const [steps, setSteps] = (0, import_react62.useState)([]);
88876
88949
  const [resultBundle, setResultBundle] = (0, import_react62.useState)(null);
@@ -89011,9 +89084,14 @@ function usePipelineStream(options) {
89011
89084
  (s) => s.status === "active" ? { ...s, status: "error" } : s
89012
89085
  )
89013
89086
  );
89087
+ const planLimitBody = tryParsePlanLimitBody(event.message);
89088
+ const raw = planLimitBody ? planLimitErrorFromBody(planLimitBody) : null;
89014
89089
  setErrorBundle({
89015
89090
  key: currentKey,
89016
- value: { message: event.message, raw: null }
89091
+ value: {
89092
+ message: raw ? raw.displayMessage : event.message,
89093
+ raw
89094
+ }
89017
89095
  });
89018
89096
  setIsStreaming(false);
89019
89097
  }
@@ -89408,10 +89486,16 @@ function CommitApp({
89408
89486
  }
89409
89487
  if (stream.error) {
89410
89488
  const e = stream.errorRaw;
89411
- if (e instanceof PlanLimitError) {
89489
+ if (e instanceof OutdatedCliError) {
89412
89490
  setErrorMsg(
89413
- `Limite do plano atingido (${e.used}/${e.limit} commits este m\xEAs)
89414
- \u2192 ${terminalLink("Fa\xE7a upgrade", `${WEB_BASE_URL}/dashboard/plano`)}`
89491
+ `Sua vers\xE3o do CLI (${e.currentVersion}) \xE9 antiga demais.
89492
+ \u2192 Atualize com: ${UPDATE_COMMAND}`
89493
+ );
89494
+ setPhase("error-api");
89495
+ } else if (e instanceof PlanLimitError) {
89496
+ setErrorMsg(
89497
+ `${e.displayMessage}
89498
+ \u2192 ${terminalLink(e.action.label, e.action.url)}`
89415
89499
  );
89416
89500
  setPhase("error-plan");
89417
89501
  } else if (e instanceof ApiError && e.status === 403) {
@@ -89502,10 +89586,16 @@ ${hookResult.output}` : "";
89502
89586
  setStreamPayload({ path: "/commit/generate", body, token });
89503
89587
  setPhase("streaming");
89504
89588
  } catch (e) {
89505
- if (e instanceof PlanLimitError) {
89589
+ if (e instanceof OutdatedCliError) {
89506
89590
  setErrorMsg(
89507
- `Limite do plano atingido (${e.used}/${e.limit} commits este m\xEAs)
89508
- \u2192 ${terminalLink("Fa\xE7a upgrade", `${WEB_BASE_URL}/dashboard/plano`)}`
89591
+ `Sua vers\xE3o do CLI (${e.currentVersion}) \xE9 antiga demais.
89592
+ \u2192 Atualize com: ${UPDATE_COMMAND}`
89593
+ );
89594
+ setPhase("error-api");
89595
+ } else if (e instanceof PlanLimitError) {
89596
+ setErrorMsg(
89597
+ `${e.displayMessage}
89598
+ \u2192 ${terminalLink(e.action.label, e.action.url)}`
89509
89599
  );
89510
89600
  setPhase("error-plan");
89511
89601
  } else if (e instanceof ApiError && e.status === 403) {
@@ -89833,10 +89923,23 @@ function parseType(msg) {
89833
89923
  const match = msg.match(/^(\w+)(?:\([^)]+\))?!?:\s*(.+)/);
89834
89924
  return { type: match?.[1] ?? "chore", description: match?.[2] ?? msg };
89835
89925
  }
89926
+ function UpdateBanner({ update }) {
89927
+ if (!update) return null;
89928
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, paddingLeft: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: C.dim, children: [
89929
+ "Nova vers\xE3o dispon\xEDvel: ",
89930
+ update.current,
89931
+ " \u2192 ",
89932
+ update.latest,
89933
+ " \xB7",
89934
+ " ",
89935
+ UPDATE_COMMAND
89936
+ ] }) });
89937
+ }
89836
89938
  function SplitDoneSummary({
89837
89939
  commits,
89838
89940
  durationMs,
89839
- totalFiles
89941
+ totalFiles,
89942
+ updateAvailable
89840
89943
  }) {
89841
89944
  const { exit } = use_app_default();
89842
89945
  (0, import_react65.useEffect)(() => {
@@ -89865,27 +89968,32 @@ function SplitDoneSummary({
89865
89968
  durationMs != null ? ` em ${(durationMs / 1e3).toFixed(1)}s` : "",
89866
89969
  totalFiles != null ? ` \xB7 ${totalFiles} arquivo${totalFiles !== 1 ? "s" : ""}` : ""
89867
89970
  ] })
89868
- ] })
89971
+ ] }),
89972
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(UpdateBanner, { update: updateAvailable })
89869
89973
  ] });
89870
89974
  }
89871
89975
  function CommitDoneSummary({
89872
89976
  message,
89873
- durationMs
89977
+ durationMs,
89978
+ updateAvailable
89874
89979
  }) {
89875
89980
  const { exit } = use_app_default();
89876
89981
  (0, import_react65.useEffect)(() => {
89877
89982
  exit();
89878
89983
  }, []);
89879
89984
  const { type, description } = parseType(message);
89880
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { paddingLeft: 1, gap: 1, alignItems: "center", children: [
89881
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: C.green, children: "\u2713" }),
89882
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TypeBadge, { type }),
89883
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: C.green, children: description }),
89884
- durationMs != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: C.dim, children: [
89885
- "\xB7 ",
89886
- (durationMs / 1e3).toFixed(1),
89887
- "s"
89888
- ] })
89985
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
89986
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { paddingLeft: 1, gap: 1, alignItems: "center", children: [
89987
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: C.green, children: "\u2713" }),
89988
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TypeBadge, { type }),
89989
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: C.green, children: description }),
89990
+ durationMs != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: C.dim, children: [
89991
+ "\xB7 ",
89992
+ (durationMs / 1e3).toFixed(1),
89993
+ "s"
89994
+ ] })
89995
+ ] }),
89996
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(UpdateBanner, { update: updateAvailable })
89889
89997
  ] });
89890
89998
  }
89891
89999
 
@@ -89924,6 +90032,12 @@ async function commitCommand() {
89924
90032
  console.log(`\u2713 ${result.message}`);
89925
90033
  console.log(" Onboarding concluido! Volte ao dashboard.");
89926
90034
  } catch (e) {
90035
+ if (e instanceof OutdatedCliError) {
90036
+ console.error(
90037
+ `\u2717 Sua vers\xE3o do CLI (${e.currentVersion}) \xE9 antiga demais. Atualize: ${UPDATE_COMMAND}`
90038
+ );
90039
+ process.exit(1);
90040
+ }
89927
90041
  const detail = e instanceof Error ? e.message : "";
89928
90042
  console.error(
89929
90043
  `\u2717 Falha ao criar commit demo.${detail ? ` ${detail}` : ""}`
@@ -89971,7 +90085,10 @@ async function commitCommand() {
89971
90085
  }
89972
90086
  if (completedMessage) {
89973
90087
  const { waitUntilExit: waitUntilExit2 } = render_default(
89974
- import_react66.default.createElement(CommitDoneSummary, { message: completedMessage })
90088
+ import_react66.default.createElement(CommitDoneSummary, {
90089
+ message: completedMessage,
90090
+ updateAvailable: getUpdateInfo()
90091
+ })
89975
90092
  );
89976
90093
  await waitUntilExit2();
89977
90094
  }
@@ -90767,10 +90884,16 @@ function PrApp({
90767
90884
  setPrBody(result.body);
90768
90885
  setPhase("result");
90769
90886
  } catch (e) {
90770
- if (e instanceof PlanLimitError) {
90887
+ if (e instanceof OutdatedCliError) {
90771
90888
  setErrorMsg(
90772
- `Limite do plano atingido (${e.used}/${e.limit} commits este m\xEAs)
90773
- \u2192 ${terminalLink("Fa\xE7a upgrade", `${WEB_BASE_URL}/dashboard/plano`)}`
90889
+ `Sua vers\xE3o do CLI (${e.currentVersion}) \xE9 antiga demais.
90890
+ \u2192 Atualize com: ${UPDATE_COMMAND}`
90891
+ );
90892
+ setPhase("error-api");
90893
+ } else if (e instanceof PlanLimitError) {
90894
+ setErrorMsg(
90895
+ `${e.displayMessage}
90896
+ \u2192 ${terminalLink(e.action.label, e.action.url)}`
90774
90897
  );
90775
90898
  setPhase("error-plan");
90776
90899
  } else if (e instanceof ApiError && e.status === 403) {
@@ -91262,9 +91385,16 @@ function SplitApp({
91262
91385
  }
91263
91386
  if (stream.error) {
91264
91387
  const e = stream.errorRaw;
91265
- if (e instanceof PlanLimitError) {
91388
+ if (e instanceof OutdatedCliError) {
91389
+ setErrorMsg(
91390
+ `Sua versao do CLI (${e.currentVersion}) e antiga demais.
91391
+ \u2192 Atualize com: ${UPDATE_COMMAND}`
91392
+ );
91393
+ setPhase("error-api");
91394
+ } else if (e instanceof PlanLimitError) {
91266
91395
  setErrorMsg(
91267
- `Limite do plano atingido (${e.used}/${e.limit} commits este mes)`
91396
+ `${e.displayMessage}
91397
+ \u2192 ${terminalLink(e.action.label, e.action.url)}`
91268
91398
  );
91269
91399
  setPhase("error-plan");
91270
91400
  } else if (e instanceof ApiError && e.status === 403) {
@@ -91966,7 +92096,10 @@ async function splitCommand() {
91966
92096
  exitImmersive();
91967
92097
  if (completedCommits.length > 0) {
91968
92098
  const { waitUntilExit: waitUntilExit2 } = render_default(
91969
- import_react77.default.createElement(SplitDoneSummary, { commits: completedCommits })
92099
+ import_react77.default.createElement(SplitDoneSummary, {
92100
+ commits: completedCommits,
92101
+ updateAvailable: getUpdateInfo()
92102
+ })
91970
92103
  );
91971
92104
  await waitUntilExit2();
91972
92105
  }
@@ -92105,6 +92238,7 @@ function CommandHelp({
92105
92238
 
92106
92239
  // src/index.ts
92107
92240
  function getVersion() {
92241
+ if ("0.14.0") return "0.14.0";
92108
92242
  try {
92109
92243
  const require2 = createRequire(import.meta.url);
92110
92244
  const pkg = require2("../package.json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repomind",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "description": "AI-powered git commit messages and repository insights",
6
6
  "keywords": [