reviewzy 0.2.0 → 0.4.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.
package/README.md CHANGED
@@ -116,10 +116,10 @@ curl http://127.0.0.1:3123/health
116
116
  ```
117
117
 
118
118
  ```json
119
- {"name":"reviewzy","version":"0.2.0","pid":4172598,"nonce":"881f0e93-8dde-4c75-b559-d2e3d3b223f0","startedAt":"2026-08-16T19:31:28.640Z"}
119
+ {"name":"reviewzy","version":"0.4.0","pid":4172598,"nonce":"881f0e93-8dde-4c75-b559-d2e3d3b223f0","startedAt":"2026-08-16T19:31:28.640Z"}
120
120
  ```
121
121
 
122
- open http://127.0.0.1:3123/ for the dashboard.
122
+ open http://127.0.0.1:3123/ for the dashboard. it needs a current evergreen browser (chrome/edge 117+, safari 16.2+, firefox 121+); older engines get a degraded page, since no fallback sheet ships.
123
123
 
124
124
  ## Configuration
125
125
 
@@ -174,7 +174,7 @@ the blocking human-in-the-loop mcp family pops a dialog per call: no queue, no p
174
174
 
175
175
  **Can an AI agent rewrite my CLI help text without i18n keys?** yes. entries anchor on the exact current text; apply-back is a targeted replace.
176
176
 
177
- **How do I bulk-rewrite all user-facing copy in a codebase?** file batches per project, group by project or batch on the dashboard, approve in bulk with a before/after diff, then let a later agent session fetch and apply.
177
+ **How do I bulk-rewrite all user-facing copy in a codebase?** file batches per project, review one table per project on the dashboard, approve in bulk with a before/after diff, then let a later agent session fetch and apply.
178
178
 
179
179
  **How do I update the style guide my agents read?** edit it on the dashboard at `/style-guide`. a saved edit reaches agents in up to 60 seconds.
180
180
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reviewzy",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "agents draft user-facing copy, humans sign off on a dashboard, agents apply the approved words back in place",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
@@ -13,7 +13,7 @@
13
13
  "bun": ">=1.3.0"
14
14
  },
15
15
  "scripts": {
16
- "check": "tsc --noEmit && bun test",
16
+ "check": "tsc --noEmit && bun test --timeout 15000",
17
17
  "daemon": "bun run src/daemon/main.ts"
18
18
  },
19
19
  "dependencies": {
@@ -9,8 +9,8 @@ import { parseStyleGuideForm, upsertStyleGuide } from "../db/style-guide.ts";
9
9
  import type { StyleGuideForm } from "../db/style-guide.ts";
10
10
  import type { Store } from "../db/store.ts";
11
11
  import {
12
+ currentTextCard,
12
13
  dashboardPage,
13
- editorFragment,
14
14
  editorPage,
15
15
  editorViewFragment,
16
16
  editorViewGoneFragment,
@@ -155,7 +155,7 @@ export function mountDashboard(app: Hono, config: Config, store: Store): void {
155
155
  // The editor page; an unknown id is a true 404 page with the way onward.
156
156
  app.get("/entries/:id", (c) => {
157
157
  const vm = loadEditor(store, c.req.param("id"));
158
- if (vm === null) return c.html(html`<!doctype html>${notFoundPage(auth.enabled)}`, 404);
158
+ if (vm === null) return c.html(html`<!doctype html>${notFoundPage("entry")}`, 404);
159
159
  return c.html(html`<!doctype html>${editorPage(vm, undefined, auth.enabled)}`);
160
160
  });
161
161
 
@@ -199,6 +199,19 @@ export function mountDashboard(app: Hono, config: Config, store: Store): void {
199
199
  return c.html(editorViewFragment(vm, state));
200
200
  });
201
201
 
202
+ // The live diff: the current-text card re-rendered against the textarea's value, with no write.
203
+ // Only the htmx preview calls it; a plain POST has no meaning and returns to the editor.
204
+ app.post("/entries/:id/diff", async (c) => {
205
+ const id = c.req.param("id");
206
+ if (c.req.header("HX-Request") === undefined) return c.redirect(`/entries/${id}`, 303);
207
+ const form = await c.req.formData();
208
+ const raw = form.get("text");
209
+ const text = typeof raw === "string" ? raw : "";
210
+ const entry = getEntry(store, id);
211
+ if (entry === undefined) return c.text("", 404);
212
+ return c.html(currentTextCard(entry, text));
213
+ });
214
+
202
215
  // The image upload: one multipart file, converted to a data url here at the boundary after the
203
216
  // route's own mime and size checks, then appended by the store (which owns the refusals). The
204
217
  // cap is the stored data url's length, the same quantity the wire's per-item validation
@@ -374,6 +387,10 @@ export function mountDashboard(app: Hono, config: Config, store: Store): void {
374
387
  }
375
388
  return c.html(styleGuideRegionFragment(vm, state));
376
389
  });
390
+
391
+ // Any request no route served, any method: the styled not-found page. app.notFound fires only
392
+ // when no path matches, so a wrong method on a known path keeps its 405.
393
+ app.notFound((c) => c.html(html`<!doctype html>${notFoundPage("route")}`, 404));
377
394
  }
378
395
 
379
396
  /** The three filters straight off an action's POST body, kept alive across a re-render. */
@@ -486,5 +503,5 @@ function transitionEditorReply(
486
503
  if (outcome.ok) return c.redirect(`/entries/${id}`, 303);
487
504
  return c.html(html`<!doctype html>${editorPage(vm, state, signedIn)}`);
488
505
  }
489
- return c.html(editorFragment(vm, state));
506
+ return c.html(editorViewFragment(vm, state));
490
507
  }