replen 0.4.0 → 0.4.1

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/commands.js +29 -11
  2. package/package.json +1 -1
package/dist/commands.js CHANGED
@@ -173,11 +173,14 @@ export async function runStarred(argv) {
173
173
  // One-shot "is there anything new" check. Used in two modes:
174
174
  // 1. interactive (`replen check-new`): always prints — useful for ad-hoc
175
175
  // "did anything land?" before opening Claude Code.
176
- // 2. hook (`replen check-new --hook`): SILENT when nothing's new. Tight
177
- // timeout so a slow API can't stall every Claude Code session opening.
178
- // Errors are swallowed and never fail the session. Output is shaped
179
- // so Claude Code's SessionStart-hook stdout injection naturally
180
- // surfaces the matches in the agent's opening context.
176
+ // 2. hook (`replen check-new --hook`): SILENT when nothing's new. Bounded
177
+ // timeout (5s) so a slow API can't stall every Claude Code session
178
+ // opening. Uses AbortController to actually cancel the in-flight fetch
179
+ // on timeout without that, an aborted hook would still let the server
180
+ // finish + bump the cursor, "consuming" the matches without ever
181
+ // surfacing them. Errors are swallowed and never fail the session.
182
+ // Output is shaped so Claude Code's SessionStart-hook stdout injection
183
+ // naturally surfaces the matches in the agent's opening context.
181
184
  export async function runCheckNew(argv) {
182
185
  const hookMode = hasFlag(argv, "--hook");
183
186
  const json = hasFlag(argv, "--json");
@@ -199,12 +202,27 @@ export async function runCheckNew(argv) {
199
202
  let r;
200
203
  try {
201
204
  if (hookMode) {
202
- // Tight timeout so a slow API never blocks a session open. AbortSignal
203
- // would be cleaner but apiGet doesn't surface it; race a manual timer.
204
- r = await Promise.race([
205
- apiGet(cfg, "/api/mcp/check-new", query),
206
- new Promise((_, reject) => setTimeout(() => reject(new Error("hook-timeout")), 2000)),
207
- ]);
205
+ // Direct fetch with AbortController so the timeout actually cancels
206
+ // the request (apiGet has no signal). Without this, a "timed out"
207
+ // hook would still let the server complete the call and bump the
208
+ // cursor, silently consuming the matches.
209
+ const ctrl = new AbortController();
210
+ const timer = setTimeout(() => ctrl.abort(), 5000);
211
+ try {
212
+ const url = new URL(cfg.base + "/api/mcp/check-new");
213
+ if (query.repo !== undefined)
214
+ url.searchParams.set("repo", query.repo);
215
+ const res = await fetch(url, {
216
+ headers: { "x-digest-token": cfg.token, accept: "application/json" },
217
+ signal: ctrl.signal,
218
+ });
219
+ if (!res.ok)
220
+ throw new Error(`HTTP ${res.status}`);
221
+ r = (await res.json());
222
+ }
223
+ finally {
224
+ clearTimeout(timer);
225
+ }
208
226
  }
209
227
  else {
210
228
  r = await apiGet(cfg, "/api/mcp/check-new", query);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replen",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Smarter AI Development workflows. The AI that asks 'can we do this better?' - replen reads your codebase against the live ecosystem and surfaces drop-in libraries, ideas to port, and patterns to learn from. Calm cadence: 1-3 actionable matches a month. One-command setup: opens a browser to sign in, then wires the MCP server into Claude Code / Codex.",
5
5
  "type": "module",
6
6
  "bin": {