@deskwork/core 0.15.0 → 0.17.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 (84) hide show
  1. package/dist/doctor/rules/legacy-stage-artifact-path.d.ts +28 -0
  2. package/dist/doctor/rules/legacy-stage-artifact-path.d.ts.map +1 -0
  3. package/dist/doctor/rules/legacy-stage-artifact-path.js +232 -0
  4. package/dist/doctor/rules/legacy-stage-artifact-path.js.map +1 -0
  5. package/dist/doctor/rules/legacy-stage-artifact-path.ts +285 -0
  6. package/dist/doctor/runner.d.ts.map +1 -1
  7. package/dist/doctor/runner.js +2 -0
  8. package/dist/doctor/runner.js.map +1 -1
  9. package/dist/entry/annotations.d.ts +38 -3
  10. package/dist/entry/annotations.d.ts.map +1 -1
  11. package/dist/entry/annotations.js +164 -3
  12. package/dist/entry/annotations.js.map +1 -1
  13. package/dist/entry/approve.d.ts +21 -4
  14. package/dist/entry/approve.d.ts.map +1 -1
  15. package/dist/entry/approve.js +74 -7
  16. package/dist/entry/approve.js.map +1 -1
  17. package/dist/entry/snapshot.d.ts +51 -0
  18. package/dist/entry/snapshot.d.ts.map +1 -0
  19. package/dist/entry/snapshot.js +95 -0
  20. package/dist/entry/snapshot.js.map +1 -0
  21. package/dist/ingest-derive.d.ts +1 -1
  22. package/dist/ingest-derive.d.ts.map +1 -1
  23. package/dist/ingest-derive.js +10 -7
  24. package/dist/ingest-derive.js.map +1 -1
  25. package/dist/ingest-id.d.ts +33 -0
  26. package/dist/ingest-id.d.ts.map +1 -0
  27. package/dist/ingest-id.js +60 -0
  28. package/dist/ingest-id.js.map +1 -0
  29. package/dist/ingest.d.ts.map +1 -1
  30. package/dist/ingest.js +23 -0
  31. package/dist/ingest.js.map +1 -1
  32. package/dist/iterate/iterate.d.ts.map +1 -1
  33. package/dist/iterate/iterate.js +37 -25
  34. package/dist/iterate/iterate.js.map +1 -1
  35. package/dist/review/types.d.ts +56 -1
  36. package/dist/review/types.d.ts.map +1 -1
  37. package/dist/review/types.js.map +1 -1
  38. package/dist/schema/draft-annotation.d.ts +108 -24
  39. package/dist/schema/draft-annotation.d.ts.map +1 -1
  40. package/dist/schema/draft-annotation.js +23 -0
  41. package/dist/schema/draft-annotation.js.map +1 -1
  42. package/dist/schema/journal-events.d.ts +240 -104
  43. package/dist/schema/journal-events.d.ts.map +1 -1
  44. package/dist/scrapbook/crud-at-dir.d.ts +47 -0
  45. package/dist/scrapbook/crud-at-dir.d.ts.map +1 -0
  46. package/dist/scrapbook/crud-at-dir.js +114 -0
  47. package/dist/scrapbook/crud-at-dir.js.map +1 -0
  48. package/dist/scrapbook/crud-slug.d.ts +33 -0
  49. package/dist/scrapbook/crud-slug.d.ts.map +1 -0
  50. package/dist/scrapbook/crud-slug.js +99 -0
  51. package/dist/scrapbook/crud-slug.js.map +1 -0
  52. package/dist/scrapbook/format.d.ts +10 -0
  53. package/dist/scrapbook/format.d.ts.map +1 -0
  54. package/dist/scrapbook/format.js +41 -0
  55. package/dist/scrapbook/format.js.map +1 -0
  56. package/dist/scrapbook/listing.d.ts +94 -0
  57. package/dist/scrapbook/listing.d.ts.map +1 -0
  58. package/dist/scrapbook/listing.js +167 -0
  59. package/dist/scrapbook/listing.js.map +1 -0
  60. package/dist/scrapbook/paths.d.ts +115 -0
  61. package/dist/scrapbook/paths.d.ts.map +1 -0
  62. package/dist/scrapbook/paths.js +149 -0
  63. package/dist/scrapbook/paths.js.map +1 -0
  64. package/dist/scrapbook/read.d.ts +54 -0
  65. package/dist/scrapbook/read.d.ts.map +1 -0
  66. package/dist/scrapbook/read.js +62 -0
  67. package/dist/scrapbook/read.js.map +1 -0
  68. package/dist/scrapbook/seed.d.ts +19 -0
  69. package/dist/scrapbook/seed.d.ts.map +1 -0
  70. package/dist/scrapbook/seed.js +46 -0
  71. package/dist/scrapbook/seed.js.map +1 -0
  72. package/dist/scrapbook/types.d.ts +44 -0
  73. package/dist/scrapbook/types.d.ts.map +1 -0
  74. package/dist/scrapbook/types.js +11 -0
  75. package/dist/scrapbook/types.js.map +1 -0
  76. package/dist/scrapbook/validation.d.ts +28 -0
  77. package/dist/scrapbook/validation.d.ts.map +1 -0
  78. package/dist/scrapbook/validation.js +98 -0
  79. package/dist/scrapbook/validation.js.map +1 -0
  80. package/dist/scrapbook.d.ts +43 -277
  81. package/dist/scrapbook.d.ts.map +1 -1
  82. package/dist/scrapbook.js +42 -535
  83. package/dist/scrapbook.js.map +1 -1
  84. package/package.json +5 -1
package/dist/scrapbook.js CHANGED
@@ -4,544 +4,51 @@
4
4
  * research, and references attached to an in-flight article. Committed
5
5
  * to git alongside the article; not baked to the public site.
6
6
  *
7
- * Responsibilities:
8
- * - Resolve + validate slug + filename (reject `..`, absolute paths,
9
- * and anything outside the article's scrapbook dir)
10
- * - List + read + mutate files inside one scrapbook
11
- * - Classify files by extension into the design type buckets
12
- * - Format relative mtime + total size for the studio chip / viewer
7
+ * Responsibilities (split across sibling modules under `scrapbook/`
8
+ * per #202; this file is a barrel re-export so existing
9
+ * `import from '@deskwork/core/scrapbook'` sites stay unchanged):
10
+ *
11
+ * - `scrapbook/types.ts` — public types
12
+ * - `scrapbook/validation.ts` — slug + filename validation, classify
13
+ * - `scrapbook/paths.ts` — public (entry-aware + path-aware) +
14
+ * private (slug-template) resolvers
15
+ * - `scrapbook/listing.ts` — list + count
16
+ * - `scrapbook/read.ts` — read primitives
17
+ * - `scrapbook/crud-at-dir.ts` — entry-aware CRUD primitives (post-#191)
18
+ * - `scrapbook/crud-slug.ts` — INTERNAL slug-template CRUD primitives
19
+ * - `scrapbook/seed.ts` — plan-time scaffolding
20
+ * - `scrapbook/format.ts` — UI formatters
21
+ *
22
+ * Public API surface (#192 — slug-template mutators are NO LONGER
23
+ * exported; callers go through `scrapbookDirForEntry` + the `*AtDir`
24
+ * family instead):
25
+ *
26
+ * - Types: `ScrapbookItemKind`, `ScrapbookItem`, `ScrapbookSummary`,
27
+ * `ScrapbookLocation`, `SECRET_SUBDIR`
28
+ * - Validation: `assertSlug`, `assertFilename`, `slugSegments`,
29
+ * `isNestedSlug`, `SLUG_SEGMENT_RE`, `classify`
30
+ * - Paths: `scrapbookDirAtPath`, `scrapbookDirForEntry`,
31
+ * `scrapbookFilePathAtDir`
32
+ * - Listing: `listScrapbook`, `listScrapbookAtDir`,
33
+ * `listScrapbookForEntry`, `countScrapbook`, `countScrapbookForEntry`
34
+ * - Read: `readScrapbookFile`, `readScrapbookFileAtDir`,
35
+ * `readScrapbookFileForEntry`
36
+ * - CRUD: `createScrapbookMarkdownAtDir`, `saveScrapbookFileAtDir`,
37
+ * `renameScrapbookFileAtDir`, `deleteScrapbookFileAtDir`,
38
+ * `writeScrapbookUploadAtDir`
39
+ * - Seed: `seedScrapbookReadme`
40
+ * - Format: `formatRelativeTime`, `formatSize`
13
41
  *
14
42
  * The API endpoints that wrap these helpers should 404 in PROD; this
15
43
  * library contains no PROD check of its own (enforcement stays at the
16
44
  * endpoint boundary).
17
45
  */
18
- import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, } from 'node:fs';
19
- import { dirname, extname, join, resolve } from 'node:path';
20
- import { findEntryFile, resolveBlogPostDir, resolveContentDir } from "./paths.js";
21
- /** Well-known subdirectory name for editorially-private scrapbook items. */
22
- export const SECRET_SUBDIR = 'secret';
23
- // ---------------------------------------------------------------------------
24
- // Validation
25
- // ---------------------------------------------------------------------------
26
- /**
27
- * A single slug segment — kebab-case lowercase. Used both for flat
28
- * slugs and as the building block of hierarchical paths.
29
- */
30
- const SLUG_SEGMENT_RE = /^[a-z0-9][a-z0-9-]*$/;
31
- /**
32
- * A full slug path — one or more `/`-separated kebab-case segments.
33
- * Accepts both legacy flat slugs ("scsi-over-wifi") and hierarchical
34
- * paths ("the-outbound/characters/strivers"). No leading or trailing
35
- * slash; no empty segments.
36
- */
37
- const SLUG_RE = /^[a-z0-9][a-z0-9-]*(\/[a-z0-9][a-z0-9-]*)*$/;
38
- const FILENAME_RE = /^[a-zA-Z0-9._-][a-zA-Z0-9._ -]*$/;
39
- export function assertSlug(slug) {
40
- if (!SLUG_RE.test(slug)) {
41
- throw new Error(`invalid slug "${slug}" — must match ${SLUG_RE}`);
42
- }
43
- }
44
- /**
45
- * Split a hierarchical slug into its segments. Each segment is a
46
- * standalone kebab-case identifier.
47
- */
48
- export function slugSegments(slug) {
49
- return slug.split('/');
50
- }
51
- /**
52
- * True if a slug refers to a nested entry (has at least one `/`).
53
- */
54
- export function isNestedSlug(slug) {
55
- return slug.includes('/');
56
- }
57
- // `SLUG_SEGMENT_RE` is exported for callers that need to validate one
58
- // segment at a time (e.g. when assembling a path interactively).
59
- export { SLUG_SEGMENT_RE };
60
- export function assertFilename(name) {
61
- if (!name || name === '.' || name === '..') {
62
- throw new Error(`invalid filename "${name}"`);
63
- }
64
- if (name.includes('/') || name.includes('\\') || name.includes('\0')) {
65
- throw new Error(`filename may not contain path separators: "${name}"`);
66
- }
67
- if (name.startsWith('.')) {
68
- // Dotfiles are suspicious for a dev-only operator UI. Reject.
69
- throw new Error(`filename may not start with a dot: "${name}"`);
70
- }
71
- if (!FILENAME_RE.test(name)) {
72
- throw new Error(`filename may only contain [A-Za-z0-9._ -]: "${name}"`);
73
- }
74
- if (name.length > 200) {
75
- throw new Error(`filename too long (> 200 chars): "${name}"`);
76
- }
77
- }
78
- /**
79
- * Resolve the scrapbook directory for (site, slug) and ensure the
80
- * return path stays inside the site's content directory.
81
- * Doesn't require the directory to exist.
82
- */
83
- export function scrapbookDir(projectRoot, config, site, slug) {
84
- assertSlug(slug);
85
- const articleDir = resolveBlogPostDir(projectRoot, config, site, slug);
86
- return join(articleDir, 'scrapbook');
87
- }
88
- /**
89
- * Resolve the scrapbook directory for an arbitrary path under the site's
90
- * content directory. Used by Phase 19c+ callers (e.g. the studio) that
91
- * already know the fs-relative path of an organizational or tracked node
92
- * and don't want to re-derive it through the slug regex. The path may
93
- * contain `/` segments; no `..` or absolute paths allowed.
94
- *
95
- * Path-shape validation matches `assertSlug` since the on-disk layout
96
- * is the same shape — kebab-case segments separated by `/`. Different
97
- * helper, same constraint.
98
- */
99
- export function scrapbookDirAtPath(projectRoot, config, site, relPath) {
100
- assertSlug(relPath);
101
- const articleDir = join(resolveContentDir(projectRoot, config, site), relPath);
102
- return join(articleDir, 'scrapbook');
103
- }
104
- /**
105
- * Resolve the scrapbook directory for a tracked calendar entry.
106
- *
107
- * Derives the scrapbook location from the parent directory of the
108
- * entry's content file (located via `findEntryFile`, which prefers the
109
- * frontmatter-id index over the slug template). Falls back to today's
110
- * slug-based addressing for entries that haven't been bound to
111
- * frontmatter yet (pre-doctor state).
112
- *
113
- * Refactor-proof: when the operator renames an entry's directory on
114
- * disk, the next request rebuilds the index and the scrapbook now
115
- * lives at the new path automatically.
116
- *
117
- * @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
118
- * used both as the legacy fallback and to locate the
119
- * `<dirname>/scrapbook/` when the entry has no id yet.
120
- * @param index Optional pre-built index (per-request memoization). When
121
- * omitted, this function builds one.
122
- */
123
- export function scrapbookDirForEntry(projectRoot, config, site, entry, index) {
124
- const entryId = entry.id ?? '';
125
- const file = findEntryFile(projectRoot, config, site, entryId, index,
126
- // Legacy fallback ON — we want a usable path even for pre-doctor entries.
127
- { slug: entry.slug });
128
- if (file === undefined) {
129
- // No id binding AND no template fallback resolved (template should
130
- // always resolve since it's just slug substitution; this branch is
131
- // defensive for empty slugs / future template variants).
132
- throw new Error(`Cannot resolve scrapbook dir: entry has no id binding and no template fallback (slug="${entry.slug}")`);
133
- }
134
- return join(dirname(file), 'scrapbook');
135
- }
136
- /**
137
- * Resolve a filename INSIDE a scrapbook dir and return the absolute
138
- * path. Throws if the resolved path escapes the scrapbook dir (guards
139
- * against `..` sequences that slipped through assertFilename).
140
- *
141
- * When `opts.secret` is true, the returned path is rooted at
142
- * `<scrapbook>/secret/<filename>` instead of `<scrapbook>/<filename>`.
143
- */
144
- export function scrapbookFilePath(projectRoot, config, site, slug, filename, opts = {}) {
145
- return scrapbookFilePathAtDir(scrapbookDir(projectRoot, config, site, slug), filename, opts);
146
- }
147
- /**
148
- * Resolve a filename inside an already-resolved scrapbook directory.
149
- * Mirrors `listScrapbookAtDir` — used by callers that have already
150
- * resolved the on-disk dir via `scrapbookDirForEntry` (id-driven) or
151
- * `scrapbookDirAtPath` (fs-path-driven) and don't want to re-derive
152
- * through the slug template.
153
- *
154
- * Same security guards as `scrapbookFilePath`:
155
- * - `assertFilename` blocks dotfiles / `..` / absolute paths in the filename
156
- * - the `startsWith(dir + '/')` containment check blocks any traversal
157
- * that slipped through (so `secret/` always sits inside the top-level
158
- * scrapbook dir)
159
- *
160
- * The slug-shape validator is bypassed because the caller has already
161
- * proven the directory exists in the content tree by other means.
162
- */
163
- export function scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts = {}) {
164
- assertFilename(filename);
165
- const target = opts.secret ? join(scrapbookDirAbs, SECRET_SUBDIR) : scrapbookDirAbs;
166
- const abs = resolve(target, filename);
167
- if (!abs.startsWith(scrapbookDirAbs + '/') && abs !== scrapbookDirAbs) {
168
- throw new Error(`resolved path escapes scrapbook dir: "${filename}" → ${abs}`);
169
- }
170
- return abs;
171
- }
172
- // ---------------------------------------------------------------------------
173
- // Type classification
174
- // ---------------------------------------------------------------------------
175
- export function classify(filename) {
176
- const ext = extname(filename).toLowerCase();
177
- switch (ext) {
178
- case '.md':
179
- case '.markdown':
180
- return 'md';
181
- case '.json':
182
- case '.jsonl':
183
- return 'json';
184
- case '.js':
185
- case '.mjs':
186
- case '.cjs':
187
- case '.ts':
188
- case '.tsx':
189
- case '.mts':
190
- return 'js';
191
- case '.png':
192
- case '.jpg':
193
- case '.jpeg':
194
- case '.gif':
195
- case '.webp':
196
- case '.svg':
197
- return 'img';
198
- case '.txt':
199
- case '.log':
200
- return 'txt';
201
- default:
202
- return 'other';
203
- }
204
- }
205
- // ---------------------------------------------------------------------------
206
- // Listing
207
- // ---------------------------------------------------------------------------
208
- /**
209
- * List the items in a scrapbook, sorted newest-mtime first. Returns
210
- * both public items (top-level files) and secret items (files inside
211
- * `scrapbook/secret/`). Subdirectories at the top level OTHER than
212
- * `secret/` are ignored — deskwork doesn't recurse into arbitrary
213
- * trees inside a scrapbook.
214
- */
215
- export function listScrapbook(projectRoot, config, site, slug) {
216
- const dir = scrapbookDir(projectRoot, config, site, slug);
217
- return listScrapbookAtDir(site, slug, dir);
218
- }
219
- /**
220
- * List a scrapbook by absolute directory path. Used by callers that
221
- * have already resolved the on-disk path via `scrapbookDirForEntry`
222
- * (id-driven) or `scrapbookDirAtPath` (fs-path-driven) and don't want
223
- * to re-derive through the slug template. The `slug` parameter is only
224
- * used to populate the returned summary's identifier field — it does
225
- * not influence path resolution.
226
- *
227
- * Internal primitive shared by `listScrapbook` (slug-based) and
228
- * `listScrapbookForEntry` (id-driven).
229
- */
230
- export function listScrapbookAtDir(site, slug, dir) {
231
- if (!existsSync(dir)) {
232
- return { site, slug, dir, exists: false, items: [], secretItems: [] };
233
- }
234
- const items = listFilesInDir(dir);
235
- const secretDir = join(dir, SECRET_SUBDIR);
236
- const secretItems = existsSync(secretDir) ? listFilesInDir(secretDir) : [];
237
- return { site, slug, dir, exists: true, items, secretItems };
238
- }
239
- /**
240
- * List scrapbook items for a tracked calendar entry. Resolves the
241
- * scrapbook directory via the content index when available (id binding),
242
- * falling back to slug-based addressing for entries that haven't been
243
- * bound to frontmatter yet (pre-doctor state).
244
- *
245
- * Mirrors the shape of `countScrapbookForEntry`. Used by the studio
246
- * review-page drawer + content-detail panel so writingcontrol-shape
247
- * entries (where the file path diverges from the slug template) list
248
- * items at the correct on-disk location.
249
- *
250
- * @param entry Calendar entry — `id` preferred; `slug` is both the
251
- * legacy fallback and the disambiguator the underlying
252
- * resolver uses when the index is incomplete.
253
- * @param index Optional pre-built per-request index. When omitted, the
254
- * resolver builds one on demand.
255
- */
256
- export function listScrapbookForEntry(projectRoot, config, site, entry, index) {
257
- const dir = scrapbookDirForEntry(projectRoot, config, site, entry, index);
258
- return listScrapbookAtDir(site, entry.slug, dir);
259
- }
260
- /** Internal helper — list files (not subdirs/dotfiles) at a given path. */
261
- function listFilesInDir(dir) {
262
- const items = [];
263
- for (const e of readdirSync(dir, { withFileTypes: true })) {
264
- if (!e.isFile())
265
- continue;
266
- if (e.name.startsWith('.'))
267
- continue;
268
- const abs = join(dir, e.name);
269
- const st = statSync(abs);
270
- items.push({
271
- name: e.name,
272
- kind: classify(e.name),
273
- size: st.size,
274
- mtime: st.mtime.toISOString(),
275
- });
276
- }
277
- items.sort((a, b) => b.mtime.localeCompare(a.mtime));
278
- return items;
279
- }
280
- /**
281
- * Count items inside an absolute scrapbook directory — files at the top
282
- * level plus files inside the `secret/` subdirectory. Returns 0 if the
283
- * directory doesn't exist; tolerates fs errors so a transient permission
284
- * issue or race never crashes the dashboard render. Internal primitive
285
- * shared by `countScrapbook` (slug-based) and `countScrapbookForEntry`
286
- * (id-driven).
287
- */
288
- function countScrapbookAtDir(dir) {
289
- try {
290
- if (!existsSync(dir))
291
- return 0;
292
- const top = listFilesInDir(dir);
293
- const secretDir = join(dir, SECRET_SUBDIR);
294
- const secret = existsSync(secretDir) ? listFilesInDir(secretDir) : [];
295
- return top.length + secret.length;
296
- }
297
- catch {
298
- return 0;
299
- }
300
- }
301
- /**
302
- * Total item count (public + secret). Used by the studio chip for the
303
- * badge — operators want a single "has scrapbook content" signal that
304
- * counts everything attached to this entry.
305
- *
306
- * Slug-based addressing: resolves `<contentDir>/<slug>/scrapbook/`. For
307
- * entries whose on-disk path doesn't match the slug template (e.g.
308
- * writingcontrol-shape projects where slug `the-outbound` lives at
309
- * `projects/the-outbound/index.md`), use `countScrapbookForEntry`
310
- * instead — it derives the path from the bound file via the content
311
- * index.
312
- */
313
- export function countScrapbook(projectRoot, config, site, slug) {
314
- try {
315
- const dir = scrapbookDir(projectRoot, config, site, slug);
316
- return countScrapbookAtDir(dir);
317
- }
318
- catch {
319
- return 0;
320
- }
321
- }
322
- /**
323
- * Count scrapbook items for a tracked calendar entry. Resolves the
324
- * scrapbook directory via the content index when available (id binding),
325
- * falling back to slug-based addressing for entries that haven't been
326
- * bound to frontmatter yet (pre-doctor state).
327
- *
328
- * Mirrors the shape of `scrapbookDirForEntry` — same resolver, same
329
- * legacy-slug fallback. Used by the studio dashboard chip so writing-
330
- * control-shape entries (where the file path diverges from the slug
331
- * template) report the correct count.
332
- *
333
- * @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
334
- * both the legacy fallback and the disambiguator the
335
- * underlying resolver uses when the index is incomplete.
336
- * @param index Optional pre-built per-request index. When omitted, the
337
- * resolver builds one on demand.
338
- */
339
- export function countScrapbookForEntry(projectRoot, config, site, entry, index) {
340
- try {
341
- const dir = scrapbookDirForEntry(projectRoot, config, site, entry, index);
342
- return countScrapbookAtDir(dir);
343
- }
344
- catch {
345
- return 0;
346
- }
347
- }
348
- // ---------------------------------------------------------------------------
349
- // CRUD
350
- // ---------------------------------------------------------------------------
351
- export function readScrapbookFile(projectRoot, config, site, slug, filename, opts = {}) {
352
- return readScrapbookFileAtDir(scrapbookDir(projectRoot, config, site, slug), filename, opts);
353
- }
354
- /**
355
- * Read a scrapbook file given the absolute scrapbook directory. Used
356
- * by callers that have already resolved the on-disk dir via
357
- * `scrapbookDirForEntry` (id-driven) or `scrapbookDirAtPath`
358
- * (fs-path-driven) and don't want to re-derive through the slug
359
- * template. Mirrors the listing-side primitive `listScrapbookAtDir`.
360
- *
361
- * Same security guards as `readScrapbookFile` (filename validation +
362
- * path-traversal containment) via `scrapbookFilePathAtDir`.
363
- */
364
- export function readScrapbookFileAtDir(scrapbookDirAbs, filename, opts = {}) {
365
- const abs = scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts);
366
- if (!existsSync(abs))
367
- throw new Error(`not found: ${filename}`);
368
- const st = statSync(abs);
369
- if (!st.isFile())
370
- throw new Error(`not a file: ${filename}`);
371
- const content = readFileSync(abs);
372
- return {
373
- name: filename,
374
- kind: classify(filename),
375
- size: st.size,
376
- mtime: st.mtime.toISOString(),
377
- content,
378
- };
379
- }
380
- /**
381
- * Read a scrapbook file for a tracked calendar entry. Mirrors
382
- * `listScrapbookForEntry` / `countScrapbookForEntry` — id-driven
383
- * resolution via `scrapbookDirForEntry`, slug fallback for pre-bound
384
- * entries. Used by the studio's `/api/dev/scrapbook-file?entryId=...`
385
- * variant so projects whose feature-doc layout doesn't match the
386
- * kebab-case slug template (e.g. `docs/<version>/<status>/<feature>/`)
387
- * can still serve scrapbook assets — `scrapbookDirAtPath`'s slug
388
- * validator would otherwise reject any path with dots or uppercase
389
- * segments.
390
- *
391
- * Same security guards as the slug-shape variant: `assertFilename`
392
- * blocks dotfiles / `..` / absolute paths in the filename; the
393
- * `startsWith(dir + '/')` containment check blocks any traversal that
394
- * slipped through.
395
- */
396
- export function readScrapbookFileForEntry(projectRoot, config, site, entry, filename, opts = {}, index) {
397
- return readScrapbookFileAtDir(scrapbookDirForEntry(projectRoot, config, site, entry, index), filename, opts);
398
- }
399
- /**
400
- * Create a new markdown note in the scrapbook. Creates the scrapbook
401
- * dir (and `secret/` subdir, if needed) if it doesn't exist. Refuses
402
- * to overwrite existing files.
403
- */
404
- export function createScrapbookMarkdown(projectRoot, config, site, slug, filename, body, opts = {}) {
405
- if (!filename.endsWith('.md')) {
406
- throw new Error(`create endpoint only accepts .md files: "${filename}"`);
407
- }
408
- const abs = scrapbookFilePath(projectRoot, config, site, slug, filename, opts);
409
- if (existsSync(abs)) {
410
- throw new Error(`file already exists: "${filename}"`);
411
- }
412
- mkdirSync(dirname(abs), { recursive: true });
413
- writeFileSync(abs, body, 'utf-8');
414
- const st = statSync(abs);
415
- return {
416
- name: filename,
417
- kind: 'md',
418
- size: st.size,
419
- mtime: st.mtime.toISOString(),
420
- };
421
- }
422
- /** Overwrite an existing file's contents. Refuses if the file is absent. */
423
- export function saveScrapbookFile(projectRoot, config, site, slug, filename, body, opts = {}) {
424
- const abs = scrapbookFilePath(projectRoot, config, site, slug, filename, opts);
425
- if (!existsSync(abs))
426
- throw new Error(`file not found: "${filename}"`);
427
- writeFileSync(abs, body);
428
- const st = statSync(abs);
429
- return {
430
- name: filename,
431
- kind: classify(filename),
432
- size: st.size,
433
- mtime: st.mtime.toISOString(),
434
- };
435
- }
436
- export function renameScrapbookFile(projectRoot, config, site, slug, oldName, newName, opts = {}) {
437
- const oldAbs = scrapbookFilePath(projectRoot, config, site, slug, oldName, opts);
438
- const newAbs = scrapbookFilePath(projectRoot, config, site, slug, newName, opts);
439
- if (!existsSync(oldAbs))
440
- throw new Error(`file not found: "${oldName}"`);
441
- if (existsSync(newAbs) && oldAbs !== newAbs) {
442
- throw new Error(`target name already exists: "${newName}"`);
443
- }
444
- renameSync(oldAbs, newAbs);
445
- const st = statSync(newAbs);
446
- return {
447
- name: newName,
448
- kind: classify(newName),
449
- size: st.size,
450
- mtime: st.mtime.toISOString(),
451
- };
452
- }
453
- export function deleteScrapbookFile(projectRoot, config, site, slug, filename, opts = {}) {
454
- const abs = scrapbookFilePath(projectRoot, config, site, slug, filename, opts);
455
- if (!existsSync(abs))
456
- throw new Error(`file not found: "${filename}"`);
457
- rmSync(abs);
458
- }
459
- /**
460
- * Seed a scrapbook's `README.md` at plan time. Idempotent — if the
461
- * README already exists, returns null without touching it. Used by
462
- * the plan skill so every Planned article gets a scrapbook home with
463
- * a template that names the article and invites receipts.
464
- */
465
- export function seedScrapbookReadme(projectRoot, config, site, slug, title) {
466
- const abs = scrapbookFilePath(projectRoot, config, site, slug, 'README.md');
467
- if (existsSync(abs))
468
- return null;
469
- const now = new Date().toISOString().slice(0, 10);
470
- const body = [
471
- `# Scrapbook — ${title}`,
472
- '',
473
- `Planned ${now}. Working notes, research, receipts, and references`,
474
- `for the \`${slug}\` dispatch. Committed to git alongside the article;`,
475
- 'not baked to the public site.',
476
- '',
477
- '## Receipts',
478
- '',
479
- '- ',
480
- '',
481
- '## Notes',
482
- '',
483
- '- ',
484
- '',
485
- '## References',
486
- '',
487
- '- ',
488
- '',
489
- ].join('\n');
490
- return createScrapbookMarkdown(projectRoot, config, site, slug, 'README.md', body);
491
- }
492
- /**
493
- * Write an uploaded file into the scrapbook. Filename + content come
494
- * from the multipart body upstream; we validate and persist.
495
- */
496
- export function writeScrapbookUpload(projectRoot, config, site, slug, filename, content, opts = {}) {
497
- const abs = scrapbookFilePath(projectRoot, config, site, slug, filename, opts);
498
- if (existsSync(abs)) {
499
- throw new Error(`file already exists: "${filename}" — rename first`);
500
- }
501
- mkdirSync(dirname(abs), { recursive: true });
502
- writeFileSync(abs, content);
503
- const st = statSync(abs);
504
- return {
505
- name: filename,
506
- kind: classify(filename),
507
- size: st.size,
508
- mtime: st.mtime.toISOString(),
509
- };
510
- }
511
- // ---------------------------------------------------------------------------
512
- // Formatting helpers (for the UI / chip)
513
- // ---------------------------------------------------------------------------
514
- export function formatRelativeTime(iso, now = new Date()) {
515
- const then = new Date(iso).getTime();
516
- const diff = now.getTime() - then;
517
- if (diff < 0)
518
- return 'just now';
519
- const s = Math.floor(diff / 1000);
520
- if (s < 60)
521
- return `${s}s ago`;
522
- const m = Math.floor(s / 60);
523
- if (m < 60)
524
- return `${m}m ago`;
525
- const h = Math.floor(m / 60);
526
- if (h < 48)
527
- return `${h}h ago`;
528
- const d = Math.floor(h / 24);
529
- if (d < 14)
530
- return `${d}d ago`;
531
- const w = Math.floor(d / 7);
532
- if (w < 9)
533
- return `${w}w ago`;
534
- const months = Math.floor(d / 30);
535
- if (months < 18)
536
- return `${months}mo ago`;
537
- const y = Math.floor(d / 365);
538
- return `${y}y ago`;
539
- }
540
- export function formatSize(bytes) {
541
- if (bytes < 1024)
542
- return `${bytes} B`;
543
- if (bytes < 1024 * 1024)
544
- return `${(bytes / 1024).toFixed(1)} KB`;
545
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
546
- }
46
+ export { SECRET_SUBDIR } from "./scrapbook/types.js";
47
+ export { assertFilename, assertSlug, classify, isNestedSlug, SLUG_SEGMENT_RE, slugSegments, } from "./scrapbook/validation.js";
48
+ export { scrapbookDirAtPath, scrapbookDirForEntry, scrapbookFilePathAtDir, } from "./scrapbook/paths.js";
49
+ export { countScrapbook, countScrapbookForEntry, listScrapbook, listScrapbookAtDir, listScrapbookForEntry, } from "./scrapbook/listing.js";
50
+ export { readScrapbookFile, readScrapbookFileAtDir, readScrapbookFileForEntry, } from "./scrapbook/read.js";
51
+ export { createScrapbookMarkdownAtDir, deleteScrapbookFileAtDir, renameScrapbookFileAtDir, saveScrapbookFileAtDir, writeScrapbookUploadAtDir, } from "./scrapbook/crud-at-dir.js";
52
+ export { seedScrapbookReadme } from "./scrapbook/seed.js";
53
+ export { formatRelativeTime, formatSize } from "./scrapbook/format.js";
547
54
  //# sourceMappingURL=scrapbook.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scrapbook.js","sourceRoot":"","sources":["../src/scrapbook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scrapbook.js","sourceRoot":"","sources":["../src/scrapbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAQH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EACL,cAAc,EACd,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,YAAY,GACb,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,aAAa,EACb,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deskwork/core",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "description": "Editorial calendar + review pipeline library — shared by @deskwork/cli and @deskwork/studio",
6
6
  "homepage": "https://github.com/audiocontrol-org/deskwork#readme",
@@ -80,6 +80,10 @@
80
80
  "types": "./dist/ingest.d.ts",
81
81
  "default": "./dist/ingest.js"
82
82
  },
83
+ "./ingest-id": {
84
+ "types": "./dist/ingest-id.d.ts",
85
+ "default": "./dist/ingest-id.js"
86
+ },
83
87
  "./ingest-derive": {
84
88
  "types": "./dist/ingest-derive.d.ts",
85
89
  "default": "./dist/ingest-derive.js"