@deskwork/studio 0.9.5

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 (93) hide show
  1. package/dist/build-client-assets.d.ts +51 -0
  2. package/dist/build-client-assets.d.ts.map +1 -0
  3. package/dist/build-client-assets.js +341 -0
  4. package/dist/build-client-assets.js.map +1 -0
  5. package/dist/components/scrapbook-item.d.ts +108 -0
  6. package/dist/components/scrapbook-item.d.ts.map +1 -0
  7. package/dist/components/scrapbook-item.js +205 -0
  8. package/dist/components/scrapbook-item.js.map +1 -0
  9. package/dist/lib/editorial-skills-catalogue.d.ts +33 -0
  10. package/dist/lib/editorial-skills-catalogue.d.ts.map +1 -0
  11. package/dist/lib/editorial-skills-catalogue.js +211 -0
  12. package/dist/lib/editorial-skills-catalogue.js.map +1 -0
  13. package/dist/lib/override-render.d.ts +41 -0
  14. package/dist/lib/override-render.d.ts.map +1 -0
  15. package/dist/lib/override-render.js +80 -0
  16. package/dist/lib/override-render.js.map +1 -0
  17. package/dist/listen.d.ts +78 -0
  18. package/dist/listen.d.ts.map +1 -0
  19. package/dist/listen.js +155 -0
  20. package/dist/listen.js.map +1 -0
  21. package/dist/pages/chrome.d.ts +26 -0
  22. package/dist/pages/chrome.d.ts.map +1 -0
  23. package/dist/pages/chrome.js +50 -0
  24. package/dist/pages/chrome.js.map +1 -0
  25. package/dist/pages/content-detail.d.ts +14 -0
  26. package/dist/pages/content-detail.d.ts.map +1 -0
  27. package/dist/pages/content-detail.js +279 -0
  28. package/dist/pages/content-detail.js.map +1 -0
  29. package/dist/pages/content.d.ts +39 -0
  30. package/dist/pages/content.d.ts.map +1 -0
  31. package/dist/pages/content.js +414 -0
  32. package/dist/pages/content.js.map +1 -0
  33. package/dist/pages/dashboard.d.ts +32 -0
  34. package/dist/pages/dashboard.d.ts.map +1 -0
  35. package/dist/pages/dashboard.js +803 -0
  36. package/dist/pages/dashboard.js.map +1 -0
  37. package/dist/pages/help.d.ts +24 -0
  38. package/dist/pages/help.d.ts.map +1 -0
  39. package/dist/pages/help.js +433 -0
  40. package/dist/pages/help.js.map +1 -0
  41. package/dist/pages/html.d.ts +35 -0
  42. package/dist/pages/html.d.ts.map +1 -0
  43. package/dist/pages/html.js +73 -0
  44. package/dist/pages/html.js.map +1 -0
  45. package/dist/pages/index.d.ts +21 -0
  46. package/dist/pages/index.d.ts.map +1 -0
  47. package/dist/pages/index.js +174 -0
  48. package/dist/pages/index.js.map +1 -0
  49. package/dist/pages/layout.d.ts +33 -0
  50. package/dist/pages/layout.d.ts.map +1 -0
  51. package/dist/pages/layout.js +50 -0
  52. package/dist/pages/layout.js.map +1 -0
  53. package/dist/pages/review-scrapbook-drawer.d.ts +20 -0
  54. package/dist/pages/review-scrapbook-drawer.d.ts.map +1 -0
  55. package/dist/pages/review-scrapbook-drawer.js +98 -0
  56. package/dist/pages/review-scrapbook-drawer.js.map +1 -0
  57. package/dist/pages/review.d.ts +68 -0
  58. package/dist/pages/review.d.ts.map +1 -0
  59. package/dist/pages/review.js +434 -0
  60. package/dist/pages/review.js.map +1 -0
  61. package/dist/pages/scrapbook.d.ts +21 -0
  62. package/dist/pages/scrapbook.d.ts.map +1 -0
  63. package/dist/pages/scrapbook.js +250 -0
  64. package/dist/pages/scrapbook.js.map +1 -0
  65. package/dist/pages/shortform.d.ts +17 -0
  66. package/dist/pages/shortform.d.ts.map +1 -0
  67. package/dist/pages/shortform.js +142 -0
  68. package/dist/pages/shortform.js.map +1 -0
  69. package/dist/request-context.d.ts +52 -0
  70. package/dist/request-context.d.ts.map +1 -0
  71. package/dist/request-context.js +84 -0
  72. package/dist/request-context.js.map +1 -0
  73. package/dist/routes/api.d.ts +36 -0
  74. package/dist/routes/api.d.ts.map +1 -0
  75. package/dist/routes/api.js +175 -0
  76. package/dist/routes/api.js.map +1 -0
  77. package/dist/routes/scrapbook-file.d.ts +19 -0
  78. package/dist/routes/scrapbook-file.d.ts.map +1 -0
  79. package/dist/routes/scrapbook-file.js +77 -0
  80. package/dist/routes/scrapbook-file.js.map +1 -0
  81. package/dist/routes/scrapbook-mutations.d.ts +33 -0
  82. package/dist/routes/scrapbook-mutations.d.ts.map +1 -0
  83. package/dist/routes/scrapbook-mutations.js +310 -0
  84. package/dist/routes/scrapbook-mutations.js.map +1 -0
  85. package/dist/server.d.ts +52 -0
  86. package/dist/server.d.ts.map +1 -0
  87. package/dist/server.js +581 -0
  88. package/dist/server.js.map +1 -0
  89. package/dist/tailscale.d.ts +63 -0
  90. package/dist/tailscale.d.ts.map +1 -0
  91. package/dist/tailscale.js +118 -0
  92. package/dist/tailscale.js.map +1 -0
  93. package/package.json +60 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrapbook-mutations.js","sourceRoot":"","sources":["../../src/routes/scrapbook-mutations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @deskwork/studio — local web server for the editorial review surface.
4
+ *
5
+ * Usage:
6
+ * deskwork-studio [--project-root <path>] [--port <n>] [--host <addr>]
7
+ *
8
+ * Defaults:
9
+ * --project-root process.cwd()
10
+ * --port 47321 (avoids the Astro dev server's default 4321)
11
+ * --host 127.0.0.1 (loopback only — see security note in main())
12
+ *
13
+ * The server reads .deskwork/config.json from the project root, then
14
+ * exposes:
15
+ * - GET /dev/editorial-studio — dashboard
16
+ * - GET /dev/editorial-review/<slug> — per-post review page
17
+ * - GET /dev/editorial-review-shortform — shortform review
18
+ * - POST /api/dev/editorial-review/* — 6 mutation endpoints
19
+ * - GET /api/dev/editorial-review/* — 2 read endpoints
20
+ * - GET /static/* — UI assets (HTML/CSS/JS)
21
+ *
22
+ * The handlers live in @deskwork/core/review/handlers and produce
23
+ * exactly the JSON shapes audiocontrol's Astro routes used to produce.
24
+ * The browser-side client code (ported from
25
+ * audiocontrol/src/shared/editorial-*) speaks to those endpoints
26
+ * unchanged.
27
+ */
28
+ import { Hono } from 'hono';
29
+ import { type StudioContext } from './routes/api.ts';
30
+ interface CliArgs {
31
+ projectRoot: string;
32
+ port: number;
33
+ /**
34
+ * True when the operator passed `--port` (or `-p`). When true, the
35
+ * listener refuses to auto-increment on EADDRINUSE — the operator
36
+ * asked for a specific port, so failure is surfaced loudly.
37
+ */
38
+ portExplicit: boolean;
39
+ /**
40
+ * Bind address explicitly requested by the operator via --host.
41
+ * `null` means "use the default policy" — bind to loopback AND any
42
+ * detected Tailscale interface (unless `--no-tailscale` was passed,
43
+ * in which case loopback only).
44
+ */
45
+ hostOverride: string | null;
46
+ /** When true, skip Tailscale auto-detection even if it's running. */
47
+ noTailscale: boolean;
48
+ }
49
+ export declare function parseCliArgs(argv: string[]): CliArgs;
50
+ export declare function createApp(ctx: StudioContext): Hono;
51
+ export {};
52
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAW5B,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAsBtE,UAAU,OAAO;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA8CpD;AAuJD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAuOlD"}
package/dist/server.js ADDED
@@ -0,0 +1,581 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @deskwork/studio — local web server for the editorial review surface.
4
+ *
5
+ * Usage:
6
+ * deskwork-studio [--project-root <path>] [--port <n>] [--host <addr>]
7
+ *
8
+ * Defaults:
9
+ * --project-root process.cwd()
10
+ * --port 47321 (avoids the Astro dev server's default 4321)
11
+ * --host 127.0.0.1 (loopback only — see security note in main())
12
+ *
13
+ * The server reads .deskwork/config.json from the project root, then
14
+ * exposes:
15
+ * - GET /dev/editorial-studio — dashboard
16
+ * - GET /dev/editorial-review/<slug> — per-post review page
17
+ * - GET /dev/editorial-review-shortform — shortform review
18
+ * - POST /api/dev/editorial-review/* — 6 mutation endpoints
19
+ * - GET /api/dev/editorial-review/* — 2 read endpoints
20
+ * - GET /static/* — UI assets (HTML/CSS/JS)
21
+ *
22
+ * The handlers live in @deskwork/core/review/handlers and produce
23
+ * exactly the JSON shapes audiocontrol's Astro routes used to produce.
24
+ * The browser-side client code (ported from
25
+ * audiocontrol/src/shared/editorial-*) speaks to those endpoints
26
+ * unchanged.
27
+ */
28
+ import { Hono } from 'hono';
29
+ import { serve } from '@hono/node-server';
30
+ import { serveStatic } from '@hono/node-server/serve-static';
31
+ import { listenWithAutoIncrement } from "./listen.js";
32
+ import { existsSync, realpathSync } from 'node:fs';
33
+ import { dirname, isAbsolute, resolve } from 'node:path';
34
+ import { fileURLToPath } from 'node:url';
35
+ import { readConfig } from '@deskwork/core/config';
36
+ import { readCalendar } from '@deskwork/core/calendar';
37
+ import { resolveCalendarPath } from '@deskwork/core/paths';
38
+ import { readWorkflow } from '@deskwork/core/review/pipeline';
39
+ import { createApiRouter } from "./routes/api.js";
40
+ import { serveScrapbookFile } from "./routes/scrapbook-file.js";
41
+ import { createScrapbookMutationsRouter } from "./routes/scrapbook-mutations.js";
42
+ import { buildClientAssets } from "./build-client-assets.js";
43
+ import { renderDashboard } from "./pages/dashboard.js";
44
+ import { renderReviewPage } from "./pages/review.js";
45
+ import { renderShortformPage } from "./pages/shortform.js";
46
+ import { renderHelpPage } from "./pages/help.js";
47
+ import { renderScrapbookPage } from "./pages/scrapbook.js";
48
+ import { renderContentTopLevel, renderContentProject, } from "./pages/content.js";
49
+ import { renderStudioIndex } from "./pages/index.js";
50
+ import { detectTailscale } from "./tailscale.js";
51
+ import { contentIndexMiddleware, getRequestContentIndex, } from "./request-context.js";
52
+ import { runTemplateOverride } from "./lib/override-render.js";
53
+ import { createOverrideResolver } from '@deskwork/core/overrides';
54
+ const DEFAULT_PORT = 47321;
55
+ const LOOPBACK = '127.0.0.1';
56
+ export function parseCliArgs(argv) {
57
+ let projectRoot = process.cwd();
58
+ let port = DEFAULT_PORT;
59
+ let portExplicit = false;
60
+ let hostOverride = null;
61
+ let noTailscale = false;
62
+ for (let i = 0; i < argv.length; i++) {
63
+ const a = argv[i];
64
+ if (a === '--project-root' || a === '-r') {
65
+ const next = argv[++i];
66
+ if (!next)
67
+ usage(`${a} requires a value`);
68
+ projectRoot = next;
69
+ }
70
+ else if (a.startsWith('--project-root=')) {
71
+ projectRoot = a.slice('--project-root='.length);
72
+ }
73
+ else if (a === '--port' || a === '-p') {
74
+ const next = argv[++i];
75
+ if (!next)
76
+ usage(`${a} requires a value`);
77
+ port = parseInt(next, 10);
78
+ portExplicit = true;
79
+ }
80
+ else if (a.startsWith('--port=')) {
81
+ port = parseInt(a.slice('--port='.length), 10);
82
+ portExplicit = true;
83
+ }
84
+ else if (a === '--host' || a === '-H') {
85
+ const next = argv[++i];
86
+ if (!next)
87
+ usage(`${a} requires a value`);
88
+ hostOverride = next;
89
+ }
90
+ else if (a.startsWith('--host=')) {
91
+ hostOverride = a.slice('--host='.length);
92
+ }
93
+ else if (a === '--no-tailscale') {
94
+ noTailscale = true;
95
+ }
96
+ else if (a === '--help' || a === '-h') {
97
+ usage(null);
98
+ }
99
+ else {
100
+ usage(`unknown argument: ${a}`);
101
+ }
102
+ }
103
+ if (!Number.isFinite(port) || port <= 0 || port > 65535) {
104
+ usage(`invalid port: ${port}`);
105
+ }
106
+ return {
107
+ projectRoot: isAbsolute(projectRoot) ? projectRoot : resolve(process.cwd(), projectRoot),
108
+ port,
109
+ portExplicit,
110
+ hostOverride,
111
+ noTailscale,
112
+ };
113
+ }
114
+ function usage(error) {
115
+ const out = error ? process.stderr : process.stdout;
116
+ if (error)
117
+ out.write(`error: ${error}\n\n`);
118
+ out.write('Usage: deskwork-studio [--project-root <path>] [--port <n>] [--host <addr>] [--no-tailscale]\n');
119
+ out.write('\n');
120
+ out.write('Options:\n');
121
+ out.write(' -r, --project-root <path> project root containing .deskwork/config.json\n');
122
+ out.write(' (default: cwd)\n');
123
+ out.write(` -p, --port <n> listen on this port (default: ${DEFAULT_PORT})\n`);
124
+ out.write(' -H, --host <addr> bind address. When set, the studio binds ONLY to\n');
125
+ out.write(' this address — overrides Tailscale auto-detection.\n');
126
+ out.write(' Use 0.0.0.0 to expose on every interface (LAN +\n');
127
+ out.write(' Tailscale + Wi-Fi). Studio has no auth; only do this\n');
128
+ out.write(' on trusted networks.\n');
129
+ out.write(' --no-tailscale skip Tailscale auto-detection (loopback only)\n');
130
+ out.write(' -h, --help show this message\n');
131
+ out.write('\n');
132
+ out.write('Default networking policy: bind to 127.0.0.1 (loopback) AND, if Tailscale is\n');
133
+ out.write('running on this machine, the local Tailscale interface(s). Tailscale peers can\n');
134
+ out.write("then reach the studio at the magic-DNS hostname (e.g. '<machine>.<tailnet>.ts.net').\n");
135
+ process.exit(error ? 2 : 0);
136
+ }
137
+ /**
138
+ * Resolve a UUID `id` against the calendar for `site` and return a
139
+ * `ReviewLookup` carrying both the id and the entry's display slug.
140
+ * Returns null when the id doesn't match any calendar entry — the
141
+ * caller then renders a "no galley to review" error page.
142
+ */
143
+ function resolveEntryById(ctx, site, id) {
144
+ if (!(site in ctx.config.sites))
145
+ return null;
146
+ try {
147
+ const calendarPath = resolveCalendarPath(ctx.projectRoot, ctx.config, site);
148
+ if (!existsSync(calendarPath))
149
+ return null;
150
+ const cal = readCalendar(calendarPath);
151
+ const entry = cal.entries.find((e) => e.id === id);
152
+ if (!entry || entry.id === undefined)
153
+ return null;
154
+ return { kind: 'id', entryId: entry.id, slug: entry.slug };
155
+ }
156
+ catch {
157
+ return null;
158
+ }
159
+ }
160
+ /**
161
+ * Resolve a slug to either:
162
+ * - `{ kind: 'id', entryId, slug }` when the entry has a stable id
163
+ * stamped — caller 302-redirects to the canonical id URL.
164
+ * - `{ kind: 'slug', slug }` when the entry exists but has no id
165
+ * (pre-doctor migration state) — caller renders directly.
166
+ * - `null` when no entry matches the slug — caller renders 404.
167
+ * - `'unknown-site'` when the site param isn't configured.
168
+ */
169
+ function resolveEntryBySlug(ctx, site, slug) {
170
+ if (!(site in ctx.config.sites))
171
+ return 'unknown-site';
172
+ try {
173
+ const calendarPath = resolveCalendarPath(ctx.projectRoot, ctx.config, site);
174
+ if (!existsSync(calendarPath))
175
+ return null;
176
+ const cal = readCalendar(calendarPath);
177
+ const entry = cal.entries.find((e) => e.slug === slug);
178
+ if (!entry)
179
+ return null;
180
+ if (entry.id)
181
+ return { kind: 'id', entryId: entry.id, slug: entry.slug };
182
+ return { kind: 'slug', slug: entry.slug };
183
+ }
184
+ catch {
185
+ return null;
186
+ }
187
+ }
188
+ /**
189
+ * Build the canonical id-based redirect URL while preserving the
190
+ * original request's query string (site, version, kind, etc.). The
191
+ * input URL is the absolute request URL (Hono's `c.req.url`); we
192
+ * extract just the search portion and graft it onto the new path.
193
+ */
194
+ function buildReviewRedirectUrl(entryId, requestUrl) {
195
+ let search = '';
196
+ try {
197
+ const u = new URL(requestUrl);
198
+ search = u.search;
199
+ }
200
+ catch {
201
+ search = '';
202
+ }
203
+ return `/dev/editorial-review/${entryId}${search}`;
204
+ }
205
+ /**
206
+ * Resolve the plugin tree root (`plugins/deskwork-studio/`) at runtime.
207
+ *
208
+ * Three runtime layouts (Phase 23 source-shipped re-architecture):
209
+ * - Workspace: `packages/studio/src/server.ts` (run via the workspace
210
+ * bin symlink) → plugin root is `<HERE>/../../../plugins/deskwork-studio`.
211
+ * - Marketplace (legacy node_modules layout): `<pluginRoot>/node_modules/
212
+ * @deskwork/studio/src/server.ts` → plugin root is `<HERE>/../../../..`.
213
+ * - Marketplace (materialized vendor layout, Phase 23c): npm symlinks
214
+ * `node_modules/@deskwork/studio` → `vendor/studio`, so `import.meta.url`
215
+ * resolves through the symlink to `<pluginRoot>/vendor/studio/src/server.ts`
216
+ * → plugin root is `<HERE>/../../..`. Surfaced by the Phase 23g
217
+ * `scripts/smoke-marketplace.sh` smoke test, which boots the studio
218
+ * against an extracted+materialized tree and asserts every route 200s.
219
+ *
220
+ * All candidates are tried; whichever has a `public/src/` directory
221
+ * adjacent wins. `public/src/` ships in the plugin tree only.
222
+ */
223
+ function pluginRoot() {
224
+ const here = dirname(fileURLToPath(import.meta.url));
225
+ const candidates = [
226
+ resolve(here, '..', '..', '..', 'plugins', 'deskwork-studio'),
227
+ resolve(here, '..', '..', '..', '..'),
228
+ resolve(here, '..', '..', '..'),
229
+ ];
230
+ for (const candidate of candidates) {
231
+ // Use the plugin's marker file (public/src exists in both layouts)
232
+ // to avoid grabbing an unrelated parent dir.
233
+ if (existsSync(resolve(candidate, 'public', 'src')))
234
+ return candidate;
235
+ }
236
+ throw new Error(`deskwork-studio: could not find plugin root. Tried:\n ${candidates.join('\n ')}`);
237
+ }
238
+ function publicDir() {
239
+ // CSS, source modules, and any other static assets live under
240
+ // `<pluginRoot>/public/`. Compiled client JS does NOT live here in
241
+ // the runtime-built path (Phase 23e) — see clientAssetsDir().
242
+ const root = resolve(pluginRoot(), 'public');
243
+ if (!existsSync(root)) {
244
+ throw new Error(`deskwork-studio: could not find public/ assets at ${root}`);
245
+ }
246
+ return root;
247
+ }
248
+ /**
249
+ * Path to runtime-built client modules
250
+ * (`<pluginRoot>/.runtime-cache/dist/`). Phase 23e builds into this dir
251
+ * during boot; the `/static/dist/*` mount serves from it.
252
+ */
253
+ function clientAssetsDir() {
254
+ return resolve(pluginRoot(), '.runtime-cache', 'dist');
255
+ }
256
+ export function createApp(ctx) {
257
+ const app = new Hono();
258
+ // Per-request content-index memoization. Mounted before page routes
259
+ // so every renderer in a single request shares one index per site.
260
+ // The middleware just attaches an empty cache; renderers populate it
261
+ // lazily via `getRequestContentIndex(c, ctx, site)`.
262
+ app.use('*', contentIndexMiddleware());
263
+ // API routes
264
+ app.route('/api/dev/editorial-review', createApiRouter(ctx));
265
+ // Page routes
266
+ app.get('/dev', (c) => c.html(renderStudioIndex(ctx)));
267
+ app.get('/dev/', (c) => c.html(renderStudioIndex(ctx)));
268
+ app.get('/dev/editorial-studio', async (c) => {
269
+ const getIndex = (site) => getRequestContentIndex(c, ctx, site);
270
+ // Phase 23f: per-project override check. The override module's
271
+ // `default` is called with the same args the built-in renderer
272
+ // expects: (ctx, getIndex). When no override exists, we fall
273
+ // through to the built-in dashboard.
274
+ const overridden = await runTemplateOverride(ctx, 'dashboard', [
275
+ ctx,
276
+ getIndex,
277
+ ]);
278
+ if (overridden !== null)
279
+ return c.html(overridden);
280
+ return c.html(renderDashboard(ctx, getIndex));
281
+ });
282
+ app.get('/dev/editorial-help', async (c) => {
283
+ const overridden = await runTemplateOverride(ctx, 'help', [ctx]);
284
+ if (overridden !== null)
285
+ return c.html(overridden);
286
+ return c.html(renderHelpPage(ctx));
287
+ });
288
+ app.get('/dev/editorial-review-shortform', (c) => c.html(renderShortformPage(ctx)));
289
+ // Phase 19d: id-based canonical review URL. Strict UUID-shape regex
290
+ // matched FIRST so it wins over the legacy `:slug{.+}` route below.
291
+ // Hono evaluates routes in registration order; first match wins.
292
+ //
293
+ // Phase 21c added a workflow-id branch: the dashboard's shortform
294
+ // matrix (and any other surface that knows a workflow id) deep-links
295
+ // straight to a workflow record. We try workflow-id resolution first
296
+ // because workflow journals are smaller than the calendar; entry-id
297
+ // is the existing canonical longform/outline path and stays the
298
+ // fallback when the id doesn't match a workflow.
299
+ app.get('/dev/editorial-review/:id{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}', async (c) => {
300
+ const id = c.req.param('id');
301
+ const siteParam = c.req.query('site') ?? ctx.config.defaultSite;
302
+ const getIndex = (s) => getRequestContentIndex(c, ctx, s);
303
+ const reviewQuery = {
304
+ site: c.req.query('site') ?? null,
305
+ version: c.req.query('v') ?? null,
306
+ kind: c.req.query('kind') ?? null,
307
+ };
308
+ // 1. Workflow-id branch — phase 21c.
309
+ const wf = readWorkflow(ctx.projectRoot, ctx.config, id);
310
+ if (wf !== null) {
311
+ const lookup = { kind: 'workflow', workflowId: id };
312
+ const overridden = await runTemplateOverride(ctx, 'review', [
313
+ ctx,
314
+ lookup,
315
+ reviewQuery,
316
+ getIndex,
317
+ ]);
318
+ if (overridden !== null)
319
+ return c.html(overridden);
320
+ return c.html(await renderReviewPage(ctx, lookup, reviewQuery, getIndex));
321
+ }
322
+ // 2. Entry-id branch — the legacy canonical longform/outline URL.
323
+ const lookup = resolveEntryById(ctx, siteParam, id);
324
+ const effectiveLookup = lookup ?? { kind: 'id', entryId: id, slug: id };
325
+ const overridden = await runTemplateOverride(ctx, 'review', [
326
+ ctx,
327
+ effectiveLookup,
328
+ reviewQuery,
329
+ getIndex,
330
+ ]);
331
+ if (overridden !== null)
332
+ return c.html(overridden);
333
+ return c.html(await renderReviewPage(ctx, effectiveLookup, reviewQuery, getIndex));
334
+ });
335
+ // Legacy slug route. `:slug{.+}` captures hierarchical slugs
336
+ // (`/`-separated kebab-case segments). Resolution order:
337
+ // 1. Calendar entry exists with id → 302-redirect to canonical id URL.
338
+ // 2. Calendar entry exists without id (pre-doctor) → render via
339
+ // legacy slug-keyed workflow join (no redirect).
340
+ // 3. No calendar entry → fall through to slug-keyed render anyway:
341
+ // a workflow may exist independently (test fixtures, ad-hoc
342
+ // drafts not on the calendar). The renderer's renderError path
343
+ // handles "no workflow either" with a 200 explainer page.
344
+ // Only reachable when the path doesn't match the UUID route above.
345
+ app.get('/dev/editorial-review/:slug{.+}', async (c) => {
346
+ const slug = decodeURIComponent(c.req.param('slug'));
347
+ const siteParam = c.req.query('site') ?? ctx.config.defaultSite;
348
+ const found = resolveEntryBySlug(ctx, siteParam, slug);
349
+ if (found === 'unknown-site') {
350
+ return c.notFound();
351
+ }
352
+ if (found !== null && found.kind === 'id') {
353
+ const url = buildReviewRedirectUrl(found.entryId, c.req.url);
354
+ return c.redirect(url, 302);
355
+ }
356
+ // `found === null` (no calendar entry) OR `kind: 'slug'` (entry
357
+ // present, no id). Both render through the slug-keyed legacy path.
358
+ const lookup = found !== null ? found : { kind: 'slug', slug };
359
+ const getIndex = (s) => getRequestContentIndex(c, ctx, s);
360
+ const reviewQuery = {
361
+ site: c.req.query('site') ?? null,
362
+ version: c.req.query('v') ?? null,
363
+ kind: c.req.query('kind') ?? null,
364
+ };
365
+ const overridden = await runTemplateOverride(ctx, 'review', [
366
+ ctx,
367
+ lookup,
368
+ reviewQuery,
369
+ getIndex,
370
+ ]);
371
+ if (overridden !== null)
372
+ return c.html(overridden);
373
+ return c.html(await renderReviewPage(ctx, lookup, reviewQuery, getIndex));
374
+ });
375
+ // Wildcard path — `:site` is a single segment, the trailing path
376
+ // captures arbitrarily-deep hierarchical addresses (e.g.
377
+ // `the-outbound/characters/strivers`). Hono's `:path{.+}` regex
378
+ // matcher swallows everything after the site segment.
379
+ app.get('/dev/scrapbook/:site/:path{.+}', async (c) => {
380
+ const site = c.req.param('site');
381
+ const path = decodeURIComponent(c.req.param('path'));
382
+ const overridden = await runTemplateOverride(ctx, 'scrapbook', [
383
+ ctx,
384
+ site,
385
+ path,
386
+ ]);
387
+ if (overridden !== null)
388
+ return c.html(overridden);
389
+ return c.html(renderScrapbookPage(ctx, site, path));
390
+ });
391
+ // Read-only binary endpoint for scrapbook files. Used by the
392
+ // shared scrapbook-item renderer (`components/scrapbook-item.ts`)
393
+ // to source image thumbnails, PDF iframes, and download fallbacks.
394
+ // The standalone scrapbook viewer also uses this for previews; its
395
+ // mutation endpoints (save/rename/delete/create/upload) hang off
396
+ // `/api/dev/scrapbook/*` below.
397
+ app.get('/api/dev/scrapbook-file', (c) => serveScrapbookFile(c, ctx));
398
+ // Mutation endpoints for the standalone scrapbook viewer. The
399
+ // client (`plugins/deskwork-studio/public/src/scrapbook-client.ts`)
400
+ // POSTs to /save, /rename, /delete, /create, /upload. All path
401
+ // resolution + traversal protection is delegated to
402
+ // `@deskwork/core/scrapbook` helpers — see issue #21 for the
403
+ // full contract.
404
+ app.route('/api/dev/scrapbook', createScrapbookMutationsRouter(ctx));
405
+ // Bird's-eye content view (Phase 16d). Three routes:
406
+ // GET /dev/content — top-level (sites + projects)
407
+ // GET /dev/content/:site — same shape filtered to one site
408
+ // GET /dev/content/:site/:project{.+} — drilldown for one project
409
+ // The `?node=<slug>` query param toggles the detail panel.
410
+ app.get('/dev/content', async (c) => {
411
+ const getIndex = (site) => getRequestContentIndex(c, ctx, site);
412
+ const overridden = await runTemplateOverride(ctx, 'content', [
413
+ ctx,
414
+ getIndex,
415
+ ]);
416
+ if (overridden !== null)
417
+ return c.html(overridden);
418
+ return c.html(renderContentTopLevel(ctx, getIndex));
419
+ });
420
+ app.get('/dev/content/:site', async (c) => {
421
+ const getIndex = (site) => getRequestContentIndex(c, ctx, site);
422
+ const overridden = await runTemplateOverride(ctx, 'content', [
423
+ ctx,
424
+ getIndex,
425
+ ]);
426
+ if (overridden !== null)
427
+ return c.html(overridden);
428
+ return c.html(renderContentTopLevel(ctx, getIndex));
429
+ });
430
+ app.get('/dev/content/:site/:project{.+}', async (c) => {
431
+ const site = c.req.param('site');
432
+ const project = decodeURIComponent(c.req.param('project'));
433
+ const node = c.req.query('node') ?? null;
434
+ const getIndex = (s) => getRequestContentIndex(c, ctx, s);
435
+ const overridden = await runTemplateOverride(ctx, 'content-project', [
436
+ ctx,
437
+ site,
438
+ project,
439
+ node,
440
+ getIndex,
441
+ ]);
442
+ if (overridden !== null)
443
+ return c.html(overridden);
444
+ const r = await renderContentProject(ctx, site, project, node, getIndex);
445
+ return c.html(r.html, r.status);
446
+ });
447
+ // Static assets — UI client JS, CSS, etc.
448
+ //
449
+ // Phase 23e: client modules are esbuild-built at server boot into
450
+ // <pluginRoot>/.runtime-cache/dist/. The more-specific `/static/dist/*`
451
+ // mount is registered FIRST so it wins over the catchall below for JS
452
+ // requests; CSS and other files stay served from `public/`. URL surface
453
+ // is unchanged — page renderers still emit /static/dist/<name>.js and
454
+ // /static/css/<file>.css.
455
+ app.use('/static/dist/*', serveStatic({
456
+ root: clientAssetsDir(),
457
+ rewriteRequestPath: (path) => path.replace(/^\/static\/dist/, ''),
458
+ }));
459
+ app.use('/static/*', serveStatic({
460
+ root: publicDir(),
461
+ rewriteRequestPath: (path) => path.replace(/^\/static/, ''),
462
+ }));
463
+ // Convenience root redirect to the studio index.
464
+ app.get('/', (c) => c.redirect('/dev/'));
465
+ return app;
466
+ }
467
+ async function main() {
468
+ const { projectRoot, port, portExplicit, hostOverride, noTailscale } = parseCliArgs(process.argv.slice(2));
469
+ let config;
470
+ try {
471
+ config = readConfig(projectRoot);
472
+ }
473
+ catch (err) {
474
+ const reason = err instanceof Error ? err.message : String(err);
475
+ process.stderr.write(`Could not load config: ${reason}\n`);
476
+ process.exit(1);
477
+ }
478
+ // Phase 23e: build client modules from source into the runtime cache
479
+ // BEFORE wiring routes (the `/static/dist/*` mount records its root
480
+ // at registration time and warns when the path doesn't exist yet).
481
+ // Failures abort startup — serving stale or missing JS would silently
482
+ // break the UI.
483
+ try {
484
+ const summary = await buildClientAssets({ pluginRoot: pluginRoot() });
485
+ process.stdout.write(`deskwork-studio: built ${summary.entriesBuilt} client assets ` +
486
+ `(${summary.entriesCached} cached) -> ${summary.outDir}\n`);
487
+ }
488
+ catch (err) {
489
+ const reason = err instanceof Error ? err.message : String(err);
490
+ process.stderr.write(`deskwork-studio: client asset build failed: ${reason}\n`);
491
+ process.exit(1);
492
+ }
493
+ // Phase 23f: build the override resolver once at boot so every page
494
+ // request reuses the same instance. The resolver itself is cheap, but
495
+ // threading it through `ctx` makes the dependency explicit.
496
+ const resolver = createOverrideResolver(projectRoot);
497
+ const ctx = { projectRoot, config, resolver };
498
+ const app = createApp(ctx);
499
+ // Networking policy:
500
+ // --host <addr> → bind ONLY to that address (operator override)
501
+ // --no-tailscale → loopback only
502
+ // default → loopback + auto-detected Tailscale (if running)
503
+ //
504
+ // The studio is dev-only with no auth. Loopback is always safe.
505
+ // Tailscale's tailnet is treated as a trusted network — peers on the
506
+ // same tailnet are usually devices the operator owns. LAN/Wi-Fi
507
+ // exposure stays opt-in via `--host 0.0.0.0`.
508
+ let tailscale = null;
509
+ let bindAddresses;
510
+ if (hostOverride !== null) {
511
+ bindAddresses = [hostOverride];
512
+ }
513
+ else if (noTailscale) {
514
+ bindAddresses = [LOOPBACK];
515
+ }
516
+ else {
517
+ tailscale = detectTailscale();
518
+ bindAddresses = tailscale === null ? [LOOPBACK] : [LOOPBACK, ...tailscale.ipv4];
519
+ }
520
+ // Issue #43: bind every address with EADDRINUSE handling.
521
+ // - default port: walk forward through a small range on conflict.
522
+ // - --port explicit: fail fast with a clear error.
523
+ let result;
524
+ try {
525
+ result = await listenWithAutoIncrement({
526
+ fetch: app.fetch,
527
+ port,
528
+ addresses: bindAddresses,
529
+ explicitPort: portExplicit,
530
+ }, serve);
531
+ }
532
+ catch (err) {
533
+ const reason = err instanceof Error ? err.message : String(err);
534
+ process.stderr.write(`deskwork-studio: ${reason}\n`);
535
+ process.exit(1);
536
+ }
537
+ const reachableUrls = [];
538
+ for (const addr of bindAddresses) {
539
+ reachableUrls.push(`http://${addr === LOOPBACK ? 'localhost' : addr}:${result.port}/`);
540
+ }
541
+ printBanner({
542
+ urls: reachableUrls,
543
+ projectRoot,
544
+ siteSlugs: Object.keys(config.sites),
545
+ tailscale,
546
+ port: result.port,
547
+ override: hostOverride,
548
+ autoIncrementedFrom: result.autoIncremented ? port : null,
549
+ });
550
+ }
551
+ function printBanner(b) {
552
+ process.stdout.write('deskwork-studio listening on:\n');
553
+ for (const url of b.urls) {
554
+ process.stdout.write(` ${url}\n`);
555
+ }
556
+ if (b.tailscale && b.tailscale.magicDnsName) {
557
+ process.stdout.write(` http://${b.tailscale.magicDnsName}:${b.port}/ (Tailscale magic-DNS)\n`);
558
+ }
559
+ process.stdout.write(` project: ${b.projectRoot}\n`);
560
+ process.stdout.write(` sites: ${b.siteSlugs.join(', ')}\n`);
561
+ if (b.autoIncrementedFrom !== null) {
562
+ // Issue #43: surface the auto-increment so the operator isn't
563
+ // confused when the URL doesn't match the documented default.
564
+ process.stdout.write(` note: port ${b.autoIncrementedFrom} was in use; using ${b.port} instead\n`);
565
+ }
566
+ // Loud warning when bound beyond loopback + Tailscale tailnet.
567
+ // Tailscale interfaces (100.64.0.0/10) are considered trusted; an
568
+ // explicit --host other than loopback is not.
569
+ const exposed = b.override !== null && b.override !== LOOPBACK;
570
+ if (exposed) {
571
+ process.stdout.write(` warning: bound to ${b.override}. Studio has no authentication —\n` +
572
+ ' only run this on a trusted network (Tailscale, VPN, etc.).\n');
573
+ }
574
+ }
575
+ // Only run when invoked directly, not when imported from tests. Resolve
576
+ // argv[1] to an absolute path before comparing to import.meta.url, since the
577
+ // shell may invoke us through a symlink (npm's node_modules/.bin/...).
578
+ if (process.argv[1] && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {
579
+ await main();
580
+ }
581
+ //# sourceMappingURL=server.js.map