@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing.js","sourceRoot":"","sources":["../../src/scrapbook/listing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Scrapbook path resolvers.
3
+ *
4
+ * Public surface (entry-aware family — refactor-proof):
5
+ * - `scrapbookDirAtPath(projectRoot, config, site, relPath)` — resolve
6
+ * a scrapbook dir for an arbitrary fs-relative path under the site's
7
+ * content directory.
8
+ * - `scrapbookDirForEntry(projectRoot, config, site, entry, index)` —
9
+ * the canonical resolver. Looks up the entry's bound file via the
10
+ * content index when the entry has an id; falls back to the private
11
+ * slug-template path internally for legacy / pre-sidecar entries.
12
+ * - `scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts)` — resolve
13
+ * a filename inside an already-resolved scrapbook dir, with
14
+ * traversal protection.
15
+ *
16
+ * Private (internal — no longer exported from `@deskwork/core/scrapbook`):
17
+ * - `_scrapbookDirSlug(projectRoot, config, site, slug)` — resolve a
18
+ * scrapbook dir by slug-template addressing
19
+ * (`<contentDir>/<slug>/scrapbook`). Used as the fallback inside
20
+ * `scrapbookDirForEntry` when an entry has no id binding yet, and
21
+ * by other internal helpers in the scrapbook module family that
22
+ * accept a slug. The legacy public name `scrapbookDir` was removed
23
+ * in #192 because it gave callers a way to write to the wrong path
24
+ * for entries whose on-disk file diverges from the slug template.
25
+ * - `_scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts)`
26
+ * — resolve a filename via the slug-template path. Used internally
27
+ * by the legacy slug-keyed read helpers (`readScrapbookFile`,
28
+ * `listScrapbook`, `countScrapbook`).
29
+ *
30
+ * The private helpers are not re-exported from the barrel
31
+ * (`packages/core/src/scrapbook.ts`) and are not in
32
+ * `package.json#exports["./scrapbook"]`. External callers must go
33
+ * through `scrapbookDirForEntry` (entry-aware) or `scrapbookDirAtPath`
34
+ * (path-aware).
35
+ */
36
+ import type { DeskworkConfig } from '../config.ts';
37
+ import type { ContentIndex } from '../content-index.ts';
38
+ import { type ScrapbookLocation } from './types.ts';
39
+ /**
40
+ * INTERNAL — slug-template scrapbook dir resolver.
41
+ *
42
+ * Resolves to `<contentDir>/<slug>/scrapbook`. Used as the fallback
43
+ * inside `scrapbookDirForEntry` when an entry has no id binding yet,
44
+ * and by the legacy slug-keyed read helpers
45
+ * (`readScrapbookFile`, `listScrapbook`, `countScrapbook`).
46
+ *
47
+ * NOT exported publicly post-#192 — see file-level docstring.
48
+ */
49
+ export declare function _scrapbookDirSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string): string;
50
+ /**
51
+ * INTERNAL — slug-template scrapbook file path.
52
+ *
53
+ * NOT exported publicly post-#192. Mirrors `scrapbookFilePathAtDir`
54
+ * but takes a slug instead of a pre-resolved dir.
55
+ */
56
+ export declare function _scrapbookFilePathSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, opts?: ScrapbookLocation): string;
57
+ /**
58
+ * Resolve the scrapbook directory for an arbitrary path under the site's
59
+ * content directory. Used by Phase 19c+ callers (e.g. the studio) that
60
+ * already know the fs-relative path of an organizational or tracked node
61
+ * and don't want to re-derive it through the slug regex. The path may
62
+ * contain `/` segments; no `..` or absolute paths allowed.
63
+ *
64
+ * Path-shape validation matches `assertSlug` since the on-disk layout
65
+ * is the same shape — kebab-case segments separated by `/`. Different
66
+ * helper, same constraint.
67
+ */
68
+ export declare function scrapbookDirAtPath(projectRoot: string, config: DeskworkConfig, site: string, relPath: string): string;
69
+ /**
70
+ * Resolve the scrapbook directory for a tracked calendar entry.
71
+ *
72
+ * This is the canonical public scrapbook-dir resolver post-#192. Callers
73
+ * that previously reached for `scrapbookDir(slug)` go through this
74
+ * helper instead — pass `{ slug }` (id optional) and the resolver will
75
+ * still walk the right path.
76
+ *
77
+ * Derives the scrapbook location from the parent directory of the
78
+ * entry's content file (located via `findEntryFile`, which prefers the
79
+ * frontmatter-id index over the slug template). Falls back to the
80
+ * private slug-template helper (`_scrapbookDirSlug`) for entries that
81
+ * haven't been bound to frontmatter yet (pre-doctor state) — the
82
+ * fallback is internal and the operator never sees a different code
83
+ * path.
84
+ *
85
+ * Refactor-proof: when the operator renames an entry's directory on
86
+ * disk, the next request rebuilds the index and the scrapbook now
87
+ * lives at the new path automatically.
88
+ *
89
+ * @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
90
+ * used both as the legacy fallback and to locate the
91
+ * `<dirname>/scrapbook/` when the entry has no id yet.
92
+ * @param index Optional pre-built index (per-request memoization). When
93
+ * omitted, this function builds one.
94
+ */
95
+ export declare function scrapbookDirForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
96
+ id?: string;
97
+ slug: string;
98
+ }, index?: ContentIndex): string;
99
+ /**
100
+ * Resolve a filename inside an already-resolved scrapbook directory.
101
+ * Mirrors `listScrapbookAtDir` — used by callers that have already
102
+ * resolved the on-disk dir via `scrapbookDirForEntry` (id-driven) or
103
+ * `scrapbookDirAtPath` (fs-path-driven).
104
+ *
105
+ * Security guards:
106
+ * - `assertFilename` blocks dotfiles / `..` / absolute paths in the filename
107
+ * - the `startsWith(dir + '/')` containment check blocks any traversal
108
+ * that slipped through (so `secret/` always sits inside the top-level
109
+ * scrapbook dir)
110
+ *
111
+ * The slug-shape validator is bypassed because the caller has already
112
+ * proven the directory exists in the content tree by other means.
113
+ */
114
+ export declare function scrapbookFilePathAtDir(scrapbookDirAbs: string, filename: string, opts?: ScrapbookLocation): string;
115
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/scrapbook/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOxD,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMnE;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM,CAIR;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,MAAM,CAMR;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,MAAM,CAIR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpC,KAAK,CAAC,EAAE,YAAY,GACnB,MAAM,CAoBR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,MAAM,CAUR"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Scrapbook path resolvers.
3
+ *
4
+ * Public surface (entry-aware family — refactor-proof):
5
+ * - `scrapbookDirAtPath(projectRoot, config, site, relPath)` — resolve
6
+ * a scrapbook dir for an arbitrary fs-relative path under the site's
7
+ * content directory.
8
+ * - `scrapbookDirForEntry(projectRoot, config, site, entry, index)` —
9
+ * the canonical resolver. Looks up the entry's bound file via the
10
+ * content index when the entry has an id; falls back to the private
11
+ * slug-template path internally for legacy / pre-sidecar entries.
12
+ * - `scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts)` — resolve
13
+ * a filename inside an already-resolved scrapbook dir, with
14
+ * traversal protection.
15
+ *
16
+ * Private (internal — no longer exported from `@deskwork/core/scrapbook`):
17
+ * - `_scrapbookDirSlug(projectRoot, config, site, slug)` — resolve a
18
+ * scrapbook dir by slug-template addressing
19
+ * (`<contentDir>/<slug>/scrapbook`). Used as the fallback inside
20
+ * `scrapbookDirForEntry` when an entry has no id binding yet, and
21
+ * by other internal helpers in the scrapbook module family that
22
+ * accept a slug. The legacy public name `scrapbookDir` was removed
23
+ * in #192 because it gave callers a way to write to the wrong path
24
+ * for entries whose on-disk file diverges from the slug template.
25
+ * - `_scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts)`
26
+ * — resolve a filename via the slug-template path. Used internally
27
+ * by the legacy slug-keyed read helpers (`readScrapbookFile`,
28
+ * `listScrapbook`, `countScrapbook`).
29
+ *
30
+ * The private helpers are not re-exported from the barrel
31
+ * (`packages/core/src/scrapbook.ts`) and are not in
32
+ * `package.json#exports["./scrapbook"]`. External callers must go
33
+ * through `scrapbookDirForEntry` (entry-aware) or `scrapbookDirAtPath`
34
+ * (path-aware).
35
+ */
36
+ import { dirname, join, resolve } from 'node:path';
37
+ import { findEntryFile, resolveBlogPostDir, resolveContentDir, } from "../paths.js";
38
+ import { assertFilename, assertSlug } from "./validation.js";
39
+ import { SECRET_SUBDIR } from "./types.js";
40
+ // ---------------------------------------------------------------------------
41
+ // Private — slug-template (used as fallback inside the entry-aware family)
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * INTERNAL — slug-template scrapbook dir resolver.
45
+ *
46
+ * Resolves to `<contentDir>/<slug>/scrapbook`. Used as the fallback
47
+ * inside `scrapbookDirForEntry` when an entry has no id binding yet,
48
+ * and by the legacy slug-keyed read helpers
49
+ * (`readScrapbookFile`, `listScrapbook`, `countScrapbook`).
50
+ *
51
+ * NOT exported publicly post-#192 — see file-level docstring.
52
+ */
53
+ export function _scrapbookDirSlug(projectRoot, config, site, slug) {
54
+ assertSlug(slug);
55
+ const articleDir = resolveBlogPostDir(projectRoot, config, site, slug);
56
+ return join(articleDir, 'scrapbook');
57
+ }
58
+ /**
59
+ * INTERNAL — slug-template scrapbook file path.
60
+ *
61
+ * NOT exported publicly post-#192. Mirrors `scrapbookFilePathAtDir`
62
+ * but takes a slug instead of a pre-resolved dir.
63
+ */
64
+ export function _scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts = {}) {
65
+ return scrapbookFilePathAtDir(_scrapbookDirSlug(projectRoot, config, site, slug), filename, opts);
66
+ }
67
+ // ---------------------------------------------------------------------------
68
+ // Public — path-driven + entry-aware resolvers
69
+ // ---------------------------------------------------------------------------
70
+ /**
71
+ * Resolve the scrapbook directory for an arbitrary path under the site's
72
+ * content directory. Used by Phase 19c+ callers (e.g. the studio) that
73
+ * already know the fs-relative path of an organizational or tracked node
74
+ * and don't want to re-derive it through the slug regex. The path may
75
+ * contain `/` segments; no `..` or absolute paths allowed.
76
+ *
77
+ * Path-shape validation matches `assertSlug` since the on-disk layout
78
+ * is the same shape — kebab-case segments separated by `/`. Different
79
+ * helper, same constraint.
80
+ */
81
+ export function scrapbookDirAtPath(projectRoot, config, site, relPath) {
82
+ assertSlug(relPath);
83
+ const articleDir = join(resolveContentDir(projectRoot, config, site), relPath);
84
+ return join(articleDir, 'scrapbook');
85
+ }
86
+ /**
87
+ * Resolve the scrapbook directory for a tracked calendar entry.
88
+ *
89
+ * This is the canonical public scrapbook-dir resolver post-#192. Callers
90
+ * that previously reached for `scrapbookDir(slug)` go through this
91
+ * helper instead — pass `{ slug }` (id optional) and the resolver will
92
+ * still walk the right path.
93
+ *
94
+ * Derives the scrapbook location from the parent directory of the
95
+ * entry's content file (located via `findEntryFile`, which prefers the
96
+ * frontmatter-id index over the slug template). Falls back to the
97
+ * private slug-template helper (`_scrapbookDirSlug`) for entries that
98
+ * haven't been bound to frontmatter yet (pre-doctor state) — the
99
+ * fallback is internal and the operator never sees a different code
100
+ * path.
101
+ *
102
+ * Refactor-proof: when the operator renames an entry's directory on
103
+ * disk, the next request rebuilds the index and the scrapbook now
104
+ * lives at the new path automatically.
105
+ *
106
+ * @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
107
+ * used both as the legacy fallback and to locate the
108
+ * `<dirname>/scrapbook/` when the entry has no id yet.
109
+ * @param index Optional pre-built index (per-request memoization). When
110
+ * omitted, this function builds one.
111
+ */
112
+ export function scrapbookDirForEntry(projectRoot, config, site, entry, index) {
113
+ const entryId = entry.id ?? '';
114
+ const file = findEntryFile(projectRoot, config, site, entryId, index,
115
+ // Legacy fallback ON — we want a usable path even for pre-doctor entries.
116
+ { slug: entry.slug });
117
+ if (file === undefined) {
118
+ // No id binding AND no template fallback resolved (template should
119
+ // always resolve since it's just slug substitution; this branch is
120
+ // defensive for empty slugs / future template variants).
121
+ throw new Error(`Cannot resolve scrapbook dir: entry has no id binding and no template fallback (slug="${entry.slug}")`);
122
+ }
123
+ return join(dirname(file), 'scrapbook');
124
+ }
125
+ /**
126
+ * Resolve a filename inside an already-resolved scrapbook directory.
127
+ * Mirrors `listScrapbookAtDir` — used by callers that have already
128
+ * resolved the on-disk dir via `scrapbookDirForEntry` (id-driven) or
129
+ * `scrapbookDirAtPath` (fs-path-driven).
130
+ *
131
+ * Security guards:
132
+ * - `assertFilename` blocks dotfiles / `..` / absolute paths in the filename
133
+ * - the `startsWith(dir + '/')` containment check blocks any traversal
134
+ * that slipped through (so `secret/` always sits inside the top-level
135
+ * scrapbook dir)
136
+ *
137
+ * The slug-shape validator is bypassed because the caller has already
138
+ * proven the directory exists in the content tree by other means.
139
+ */
140
+ export function scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts = {}) {
141
+ assertFilename(filename);
142
+ const target = opts.secret ? join(scrapbookDirAbs, SECRET_SUBDIR) : scrapbookDirAbs;
143
+ const abs = resolve(target, filename);
144
+ if (!abs.startsWith(scrapbookDirAbs + '/') && abs !== scrapbookDirAbs) {
145
+ throw new Error(`resolved path escapes scrapbook dir: "${filename}" → ${abs}`);
146
+ }
147
+ return abs;
148
+ }
149
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/scrapbook/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Read primitives — return file metadata + content as a Buffer.
3
+ *
4
+ * Three addressing modes match the listing/path module:
5
+ * - `readScrapbookFile` — slug-template (legacy public; uses the
6
+ * private `_scrapbookDirSlug` internally).
7
+ * - `readScrapbookFileAtDir` — already-resolved scrapbook dir.
8
+ * - `readScrapbookFileForEntry` — entry-aware via
9
+ * `scrapbookDirForEntry`; the binary endpoint
10
+ * `/api/dev/scrapbook-file?entryId=...` uses this so projects whose
11
+ * feature-doc layout doesn't match the kebab-case slug template
12
+ * can still serve scrapbook assets.
13
+ *
14
+ * Same security guards as the writes via `scrapbookFilePathAtDir`.
15
+ */
16
+ import type { DeskworkConfig } from '../config.ts';
17
+ import type { ContentIndex } from '../content-index.ts';
18
+ import type { ScrapbookItemKind, ScrapbookLocation } from './types.ts';
19
+ interface ReadResult {
20
+ name: string;
21
+ kind: ScrapbookItemKind;
22
+ size: number;
23
+ mtime: string;
24
+ content: Buffer;
25
+ }
26
+ export declare function readScrapbookFile(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, opts?: ScrapbookLocation): ReadResult;
27
+ /**
28
+ * Read a scrapbook file given the absolute scrapbook directory. Used
29
+ * by callers that have already resolved the on-disk dir via
30
+ * `scrapbookDirForEntry` (id-driven) or `scrapbookDirAtPath`
31
+ * (fs-path-driven) and don't want to re-derive through the slug
32
+ * template. Mirrors the listing-side primitive `listScrapbookAtDir`.
33
+ *
34
+ * Same security guards as `readScrapbookFile` (filename validation +
35
+ * path-traversal containment) via `scrapbookFilePathAtDir`.
36
+ */
37
+ export declare function readScrapbookFileAtDir(scrapbookDirAbs: string, filename: string, opts?: ScrapbookLocation): ReadResult;
38
+ /**
39
+ * Read a scrapbook file for a tracked calendar entry. Mirrors
40
+ * `listScrapbookForEntry` / `countScrapbookForEntry` — id-driven
41
+ * resolution via `scrapbookDirForEntry`, slug fallback for pre-bound
42
+ * entries. Used by the studio's `/api/dev/scrapbook-file?entryId=...`
43
+ * variant so projects whose feature-doc layout doesn't match the
44
+ * kebab-case slug template (e.g. `docs/<version>/<status>/<feature>/`)
45
+ * can still serve scrapbook assets — `scrapbookDirAtPath`'s slug
46
+ * validator would otherwise reject any path with dots or uppercase
47
+ * segments.
48
+ */
49
+ export declare function readScrapbookFileForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
50
+ id?: string;
51
+ slug: string;
52
+ }, filename: string, opts?: ScrapbookLocation, index?: ContentIndex): ReadResult;
53
+ export {};
54
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/scrapbook/read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEvE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,UAAU,CAMZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,UAAU,CAaZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,EAC5B,KAAK,CAAC,EAAE,YAAY,GACnB,UAAU,CAMZ"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Read primitives — return file metadata + content as a Buffer.
3
+ *
4
+ * Three addressing modes match the listing/path module:
5
+ * - `readScrapbookFile` — slug-template (legacy public; uses the
6
+ * private `_scrapbookDirSlug` internally).
7
+ * - `readScrapbookFileAtDir` — already-resolved scrapbook dir.
8
+ * - `readScrapbookFileForEntry` — entry-aware via
9
+ * `scrapbookDirForEntry`; the binary endpoint
10
+ * `/api/dev/scrapbook-file?entryId=...` uses this so projects whose
11
+ * feature-doc layout doesn't match the kebab-case slug template
12
+ * can still serve scrapbook assets.
13
+ *
14
+ * Same security guards as the writes via `scrapbookFilePathAtDir`.
15
+ */
16
+ import { existsSync, readFileSync, statSync } from 'node:fs';
17
+ import { _scrapbookDirSlug, scrapbookDirForEntry, scrapbookFilePathAtDir, } from "./paths.js";
18
+ import { classify } from "./validation.js";
19
+ export function readScrapbookFile(projectRoot, config, site, slug, filename, opts = {}) {
20
+ return readScrapbookFileAtDir(_scrapbookDirSlug(projectRoot, config, site, slug), filename, opts);
21
+ }
22
+ /**
23
+ * Read a scrapbook file given the absolute scrapbook directory. Used
24
+ * by callers that have already resolved the on-disk dir via
25
+ * `scrapbookDirForEntry` (id-driven) or `scrapbookDirAtPath`
26
+ * (fs-path-driven) and don't want to re-derive through the slug
27
+ * template. Mirrors the listing-side primitive `listScrapbookAtDir`.
28
+ *
29
+ * Same security guards as `readScrapbookFile` (filename validation +
30
+ * path-traversal containment) via `scrapbookFilePathAtDir`.
31
+ */
32
+ export function readScrapbookFileAtDir(scrapbookDirAbs, filename, opts = {}) {
33
+ const abs = scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts);
34
+ if (!existsSync(abs))
35
+ throw new Error(`not found: ${filename}`);
36
+ const st = statSync(abs);
37
+ if (!st.isFile())
38
+ throw new Error(`not a file: ${filename}`);
39
+ const content = readFileSync(abs);
40
+ return {
41
+ name: filename,
42
+ kind: classify(filename),
43
+ size: st.size,
44
+ mtime: st.mtime.toISOString(),
45
+ content,
46
+ };
47
+ }
48
+ /**
49
+ * Read a scrapbook file for a tracked calendar entry. Mirrors
50
+ * `listScrapbookForEntry` / `countScrapbookForEntry` — id-driven
51
+ * resolution via `scrapbookDirForEntry`, slug fallback for pre-bound
52
+ * entries. Used by the studio's `/api/dev/scrapbook-file?entryId=...`
53
+ * variant so projects whose feature-doc layout doesn't match the
54
+ * kebab-case slug template (e.g. `docs/<version>/<status>/<feature>/`)
55
+ * can still serve scrapbook assets — `scrapbookDirAtPath`'s slug
56
+ * validator would otherwise reject any path with dots or uppercase
57
+ * segments.
58
+ */
59
+ export function readScrapbookFileForEntry(projectRoot, config, site, entry, filename, opts = {}, index) {
60
+ return readScrapbookFileAtDir(scrapbookDirForEntry(projectRoot, config, site, entry, index), filename, opts);
61
+ }
62
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/scrapbook/read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG7D,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAW3C,MAAM,UAAU,iBAAiB,CAC/B,WAAmB,EACnB,MAAsB,EACtB,IAAY,EACZ,IAAY,EACZ,QAAgB,EAChB,OAA0B,EAAE;IAE5B,OAAO,sBAAsB,CAC3B,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,EAClD,QAAQ,EACR,IAAI,CACL,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CACpC,eAAuB,EACvB,QAAgB,EAChB,OAA0B,EAAE;IAE5B,MAAM,GAAG,GAAG,sBAAsB,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;IAChE,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC;QACxB,IAAI,EAAE,EAAE,CAAC,IAAI;QACb,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE;QAC7B,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAmB,EACnB,MAAsB,EACtB,IAAY,EACZ,KAAoC,EACpC,QAAgB,EAChB,OAA0B,EAAE,EAC5B,KAAoB;IAEpB,OAAO,sBAAsB,CAC3B,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAC7D,QAAQ,EACR,IAAI,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Scrapbook seed helpers — scaffolding written at plan time so every
3
+ * Planned article gets a scrapbook home with a templated README.
4
+ */
5
+ import type { DeskworkConfig } from '../config.ts';
6
+ import type { ScrapbookItem } from './types.ts';
7
+ /**
8
+ * Seed a scrapbook's `README.md` at plan time. Idempotent — if the
9
+ * README already exists, returns null without touching it. Used by
10
+ * the plan skill so every Planned article gets a scrapbook home with
11
+ * a template that names the article and invites receipts.
12
+ *
13
+ * Slug-keyed because plan-time callers operate against a freshly-
14
+ * minted calendar entry whose on-disk file may not yet exist; the
15
+ * slug-template path is the only stable address available at that
16
+ * stage. Routes through the private slug-template helpers internally.
17
+ */
18
+ export declare function seedScrapbookReadme(projectRoot: string, config: DeskworkConfig, site: string, slug: string, title: string): ScrapbookItem | null;
19
+ //# sourceMappingURL=seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/scrapbook/seed.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,aAAa,GAAG,IAAI,CAgCtB"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Scrapbook seed helpers — scaffolding written at plan time so every
3
+ * Planned article gets a scrapbook home with a templated README.
4
+ */
5
+ import { existsSync } from 'node:fs';
6
+ import { _createScrapbookMarkdownSlug } from "./crud-slug.js";
7
+ import { _scrapbookFilePathSlug } from "./paths.js";
8
+ /**
9
+ * Seed a scrapbook's `README.md` at plan time. Idempotent — if the
10
+ * README already exists, returns null without touching it. Used by
11
+ * the plan skill so every Planned article gets a scrapbook home with
12
+ * a template that names the article and invites receipts.
13
+ *
14
+ * Slug-keyed because plan-time callers operate against a freshly-
15
+ * minted calendar entry whose on-disk file may not yet exist; the
16
+ * slug-template path is the only stable address available at that
17
+ * stage. Routes through the private slug-template helpers internally.
18
+ */
19
+ export function seedScrapbookReadme(projectRoot, config, site, slug, title) {
20
+ const abs = _scrapbookFilePathSlug(projectRoot, config, site, slug, 'README.md');
21
+ if (existsSync(abs))
22
+ return null;
23
+ const now = new Date().toISOString().slice(0, 10);
24
+ const body = [
25
+ `# Scrapbook — ${title}`,
26
+ '',
27
+ `Planned ${now}. Working notes, research, receipts, and references`,
28
+ `for the \`${slug}\` dispatch. Committed to git alongside the article;`,
29
+ 'not baked to the public site.',
30
+ '',
31
+ '## Receipts',
32
+ '',
33
+ '- ',
34
+ '',
35
+ '## Notes',
36
+ '',
37
+ '- ',
38
+ '',
39
+ '## References',
40
+ '',
41
+ '- ',
42
+ '',
43
+ ].join('\n');
44
+ return _createScrapbookMarkdownSlug(projectRoot, config, site, slug, 'README.md', body);
45
+ }
46
+ //# sourceMappingURL=seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.js","sourceRoot":"","sources":["../../src/scrapbook/seed.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGpD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,MAAsB,EACtB,IAAY,EACZ,IAAY,EACZ,KAAa;IAEb,MAAM,GAAG,GAAG,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IACjF,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG;QACX,iBAAiB,KAAK,EAAE;QACxB,EAAE;QACF,WAAW,GAAG,qDAAqD;QACnE,aAAa,IAAI,sDAAsD;QACvE,+BAA+B;QAC/B,EAAE;QACF,aAAa;QACb,EAAE;QACF,IAAI;QACJ,EAAE;QACF,UAAU;QACV,EAAE;QACF,IAAI;QACJ,EAAE;QACF,eAAe;QACf,EAAE;QACF,IAAI;QACJ,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,4BAA4B,CACjC,WAAW,EACX,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,WAAW,EACX,IAAI,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Scrapbook public types — value-level shapes shared by every helper in
3
+ * the scrapbook module family.
4
+ *
5
+ * Split out of the legacy monolithic `scrapbook.ts` per #202 (file-size
6
+ * cap) so callers can import just the type surface without pulling in
7
+ * the fs-touching primitives.
8
+ */
9
+ /** Type buckets for scrapbook entries — keyed by extension via `classify`. */
10
+ export type ScrapbookItemKind = 'md' | 'json' | 'js' | 'img' | 'txt' | 'other';
11
+ export interface ScrapbookItem {
12
+ name: string;
13
+ kind: ScrapbookItemKind;
14
+ size: number;
15
+ mtime: string;
16
+ }
17
+ export interface ScrapbookSummary {
18
+ site: string;
19
+ /**
20
+ * The scrapbook's location identifier — a slug for entries tied to a
21
+ * calendar row, or any directory path within `contentDir` for
22
+ * scrapbooks that hang off purely organizational nodes (e.g. an
23
+ * intermediate project directory that isn't itself a calendar entry).
24
+ */
25
+ slug: string;
26
+ dir: string;
27
+ exists: boolean;
28
+ /** Files at the top of `scrapbook/` (public/published-side notes). */
29
+ items: ScrapbookItem[];
30
+ /**
31
+ * Files inside `scrapbook/secret/` — never to be published. Operators
32
+ * can drop research, drafts, or sensitive notes here knowing the host
33
+ * project's content collection patterns won't pick them up.
34
+ */
35
+ secretItems: ScrapbookItem[];
36
+ }
37
+ /** Options that select between the public scrapbook root and `secret/`. */
38
+ export interface ScrapbookLocation {
39
+ /** When true, the file lives under `scrapbook/secret/`. Default: false. */
40
+ secret?: boolean;
41
+ }
42
+ /** Well-known subdirectory name for editorially-private scrapbook items. */
43
+ export declare const SECRET_SUBDIR = "secret";
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scrapbook/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,8EAA8E;AAC9E,MAAM,MAAM,iBAAiB,GACzB,IAAI,GACJ,MAAM,GACN,IAAI,GACJ,KAAK,GACL,KAAK,GACL,OAAO,CAAC;AAEZ,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,sEAAsE;IACtE,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB;;;;OAIG;IACH,WAAW,EAAE,aAAa,EAAE,CAAC;CAC9B;AAED,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,eAAO,MAAM,aAAa,WAAW,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Scrapbook public types — value-level shapes shared by every helper in
3
+ * the scrapbook module family.
4
+ *
5
+ * Split out of the legacy monolithic `scrapbook.ts` per #202 (file-size
6
+ * cap) so callers can import just the type surface without pulling in
7
+ * the fs-touching primitives.
8
+ */
9
+ /** Well-known subdirectory name for editorially-private scrapbook items. */
10
+ export const SECRET_SUBDIR = 'secret';
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/scrapbook/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA6CH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Scrapbook validation + classification helpers.
3
+ *
4
+ * Slug + filename validation runs at every fs entry point; a `..` or
5
+ * absolute path that slips through here would let a malicious request
6
+ * read or write outside the scrapbook tree. The route layer relies on
7
+ * these helpers for traversal protection.
8
+ */
9
+ import type { ScrapbookItemKind } from './types.ts';
10
+ /**
11
+ * A single slug segment — kebab-case lowercase. Used both for flat
12
+ * slugs and as the building block of hierarchical paths.
13
+ */
14
+ declare const SLUG_SEGMENT_RE: RegExp;
15
+ export declare function assertSlug(slug: string): void;
16
+ /**
17
+ * Split a hierarchical slug into its segments. Each segment is a
18
+ * standalone kebab-case identifier.
19
+ */
20
+ export declare function slugSegments(slug: string): string[];
21
+ /**
22
+ * True if a slug refers to a nested entry (has at least one `/`).
23
+ */
24
+ export declare function isNestedSlug(slug: string): boolean;
25
+ export { SLUG_SEGMENT_RE };
26
+ export declare function assertFilename(name: string): void;
27
+ export declare function classify(filename: string): ScrapbookItemKind;
28
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/scrapbook/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMpD;;;GAGG;AACH,QAAA,MAAM,eAAe,QAAyB,CAAC;AAW/C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI7C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAID,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAmBjD;AAMD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA6B5D"}