@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
@@ -1 +1 @@
1
- {"version":3,"file":"journal-events.d.ts","sourceRoot":"","sources":["../../src/schema/journal-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA4ExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"journal-events.d.ts","sourceRoot":"","sources":["../../src/schema/journal-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA4ExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQ7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Entry-aware CRUD primitives — operate on a pre-resolved scrapbook dir.
3
+ *
4
+ * The studio's mutation routes resolve the scrapbook directory via
5
+ * `scrapbookDirForEntry` (entry-id driven; refactor-proof) and then call
6
+ * these `*AtDir` helpers. Mirrors the listing-side `listScrapbookAtDir` /
7
+ * `readScrapbookFileAtDir` primitives.
8
+ *
9
+ * Same security guards as the slug-shape helpers via
10
+ * `scrapbookFilePathAtDir`: filename validation + path-traversal
11
+ * containment.
12
+ *
13
+ * This is the public mutation surface post-#192. The slug-template
14
+ * mutation primitives (`createScrapbookMarkdown`, `saveScrapbookFile`,
15
+ * `renameScrapbookFile`, `deleteScrapbookFile`, `writeScrapbookUpload`)
16
+ * were collapsed to private helpers in the same change — external
17
+ * callers go through these `*AtDir` functions plus a dir resolved by
18
+ * `scrapbookDirForEntry`.
19
+ */
20
+ import type { ScrapbookItem, ScrapbookLocation } from './types.ts';
21
+ /**
22
+ * Create a new markdown note inside an already-resolved scrapbook dir.
23
+ * Mirrors the legacy `createScrapbookMarkdown` (now private) but takes
24
+ * the dir directly.
25
+ */
26
+ export declare function createScrapbookMarkdownAtDir(scrapbookDirAbs: string, filename: string, body: string, opts?: ScrapbookLocation): ScrapbookItem;
27
+ /**
28
+ * Overwrite an existing file's contents inside an already-resolved scrapbook
29
+ * dir. Mirrors the legacy `saveScrapbookFile` (now private).
30
+ */
31
+ export declare function saveScrapbookFileAtDir(scrapbookDirAbs: string, filename: string, body: string | Buffer, opts?: ScrapbookLocation): ScrapbookItem;
32
+ /**
33
+ * Rename a file inside an already-resolved scrapbook dir. Mirrors the
34
+ * legacy `renameScrapbookFile` (now private).
35
+ */
36
+ export declare function renameScrapbookFileAtDir(scrapbookDirAbs: string, oldName: string, newName: string, opts?: ScrapbookLocation): ScrapbookItem;
37
+ /**
38
+ * Delete a file inside an already-resolved scrapbook dir. Mirrors the
39
+ * legacy `deleteScrapbookFile` (now private).
40
+ */
41
+ export declare function deleteScrapbookFileAtDir(scrapbookDirAbs: string, filename: string, opts?: ScrapbookLocation): void;
42
+ /**
43
+ * Write an uploaded file inside an already-resolved scrapbook dir.
44
+ * Mirrors the legacy `writeScrapbookUpload` (now private).
45
+ */
46
+ export declare function writeScrapbookUploadAtDir(scrapbookDirAbs: string, filename: string, content: Buffer, opts?: ScrapbookLocation): ScrapbookItem;
47
+ //# sourceMappingURL=crud-at-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud-at-dir.d.ts","sourceRoot":"","sources":["../../src/scrapbook/crud-at-dir.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAaH,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAiBf;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAWf;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAef;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,IAAI,CAIN;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAcf"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Entry-aware CRUD primitives — operate on a pre-resolved scrapbook dir.
3
+ *
4
+ * The studio's mutation routes resolve the scrapbook directory via
5
+ * `scrapbookDirForEntry` (entry-id driven; refactor-proof) and then call
6
+ * these `*AtDir` helpers. Mirrors the listing-side `listScrapbookAtDir` /
7
+ * `readScrapbookFileAtDir` primitives.
8
+ *
9
+ * Same security guards as the slug-shape helpers via
10
+ * `scrapbookFilePathAtDir`: filename validation + path-traversal
11
+ * containment.
12
+ *
13
+ * This is the public mutation surface post-#192. The slug-template
14
+ * mutation primitives (`createScrapbookMarkdown`, `saveScrapbookFile`,
15
+ * `renameScrapbookFile`, `deleteScrapbookFile`, `writeScrapbookUpload`)
16
+ * were collapsed to private helpers in the same change — external
17
+ * callers go through these `*AtDir` functions plus a dir resolved by
18
+ * `scrapbookDirForEntry`.
19
+ */
20
+ import { existsSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync, } from 'node:fs';
21
+ import { dirname } from 'node:path';
22
+ import { scrapbookFilePathAtDir } from "./paths.js";
23
+ import { classify } from "./validation.js";
24
+ /**
25
+ * Create a new markdown note inside an already-resolved scrapbook dir.
26
+ * Mirrors the legacy `createScrapbookMarkdown` (now private) but takes
27
+ * the dir directly.
28
+ */
29
+ export function createScrapbookMarkdownAtDir(scrapbookDirAbs, filename, body, opts = {}) {
30
+ if (!filename.endsWith('.md')) {
31
+ throw new Error(`create endpoint only accepts .md files: "${filename}"`);
32
+ }
33
+ const abs = scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts);
34
+ if (existsSync(abs)) {
35
+ throw new Error(`file already exists: "${filename}"`);
36
+ }
37
+ mkdirSync(dirname(abs), { recursive: true });
38
+ writeFileSync(abs, body, 'utf-8');
39
+ const st = statSync(abs);
40
+ return {
41
+ name: filename,
42
+ kind: 'md',
43
+ size: st.size,
44
+ mtime: st.mtime.toISOString(),
45
+ };
46
+ }
47
+ /**
48
+ * Overwrite an existing file's contents inside an already-resolved scrapbook
49
+ * dir. Mirrors the legacy `saveScrapbookFile` (now private).
50
+ */
51
+ export function saveScrapbookFileAtDir(scrapbookDirAbs, filename, body, opts = {}) {
52
+ const abs = scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts);
53
+ if (!existsSync(abs))
54
+ throw new Error(`file not found: "${filename}"`);
55
+ writeFileSync(abs, body);
56
+ const st = statSync(abs);
57
+ return {
58
+ name: filename,
59
+ kind: classify(filename),
60
+ size: st.size,
61
+ mtime: st.mtime.toISOString(),
62
+ };
63
+ }
64
+ /**
65
+ * Rename a file inside an already-resolved scrapbook dir. Mirrors the
66
+ * legacy `renameScrapbookFile` (now private).
67
+ */
68
+ export function renameScrapbookFileAtDir(scrapbookDirAbs, oldName, newName, opts = {}) {
69
+ const oldAbs = scrapbookFilePathAtDir(scrapbookDirAbs, oldName, opts);
70
+ const newAbs = scrapbookFilePathAtDir(scrapbookDirAbs, newName, opts);
71
+ if (!existsSync(oldAbs))
72
+ throw new Error(`file not found: "${oldName}"`);
73
+ if (existsSync(newAbs) && oldAbs !== newAbs) {
74
+ throw new Error(`target name already exists: "${newName}"`);
75
+ }
76
+ renameSync(oldAbs, newAbs);
77
+ const st = statSync(newAbs);
78
+ return {
79
+ name: newName,
80
+ kind: classify(newName),
81
+ size: st.size,
82
+ mtime: st.mtime.toISOString(),
83
+ };
84
+ }
85
+ /**
86
+ * Delete a file inside an already-resolved scrapbook dir. Mirrors the
87
+ * legacy `deleteScrapbookFile` (now private).
88
+ */
89
+ export function deleteScrapbookFileAtDir(scrapbookDirAbs, filename, opts = {}) {
90
+ const abs = scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts);
91
+ if (!existsSync(abs))
92
+ throw new Error(`file not found: "${filename}"`);
93
+ rmSync(abs);
94
+ }
95
+ /**
96
+ * Write an uploaded file inside an already-resolved scrapbook dir.
97
+ * Mirrors the legacy `writeScrapbookUpload` (now private).
98
+ */
99
+ export function writeScrapbookUploadAtDir(scrapbookDirAbs, filename, content, opts = {}) {
100
+ const abs = scrapbookFilePathAtDir(scrapbookDirAbs, filename, opts);
101
+ if (existsSync(abs)) {
102
+ throw new Error(`file already exists: "${filename}" — rename first`);
103
+ }
104
+ mkdirSync(dirname(abs), { recursive: true });
105
+ writeFileSync(abs, content);
106
+ const st = statSync(abs);
107
+ return {
108
+ name: filename,
109
+ kind: classify(filename),
110
+ size: st.size,
111
+ mtime: st.mtime.toISOString(),
112
+ };
113
+ }
114
+ //# sourceMappingURL=crud-at-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud-at-dir.js","sourceRoot":"","sources":["../../src/scrapbook/crud-at-dir.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * INTERNAL — slug-template CRUD primitives.
3
+ *
4
+ * These were the public mutation surface pre-#192 but are now private:
5
+ * external callers go through the entry-aware `*AtDir` family in
6
+ * `crud-at-dir.ts` after resolving the dir via `scrapbookDirForEntry`
7
+ * (or `scrapbookDirAtPath`). This module is the implementation home
8
+ * for the legacy slug-template path and is re-used inside the scrapbook
9
+ * module family — `seed.ts` calls these helpers to seed a slug-keyed
10
+ * README at plan time.
11
+ *
12
+ * NOT re-exported from the barrel (`packages/core/src/scrapbook.ts`).
13
+ *
14
+ * Same security guards as the entry-aware `*AtDir` family — filename
15
+ * validation + path-traversal containment via the underlying
16
+ * `scrapbookFilePathAtDir`.
17
+ */
18
+ import type { DeskworkConfig } from '../config.ts';
19
+ import type { ScrapbookItem, ScrapbookLocation } from './types.ts';
20
+ /**
21
+ * INTERNAL — create a new markdown note in the slug-template scrapbook.
22
+ * Used by `seed.ts`. Refuses to overwrite existing files.
23
+ */
24
+ export declare function _createScrapbookMarkdownSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, body: string, opts?: ScrapbookLocation): ScrapbookItem;
25
+ /** INTERNAL — overwrite an existing file's contents (slug-template). */
26
+ export declare function _saveScrapbookFileSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, body: string | Buffer, opts?: ScrapbookLocation): ScrapbookItem;
27
+ /** INTERNAL — rename a file (slug-template). */
28
+ export declare function _renameScrapbookFileSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string, oldName: string, newName: string, opts?: ScrapbookLocation): ScrapbookItem;
29
+ /** INTERNAL — delete a file (slug-template). */
30
+ export declare function _deleteScrapbookFileSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, opts?: ScrapbookLocation): void;
31
+ /** INTERNAL — write an uploaded file (slug-template). */
32
+ export declare function _writeScrapbookUploadSlug(projectRoot: string, config: DeskworkConfig, site: string, slug: string, filename: string, content: Buffer, opts?: ScrapbookLocation): ScrapbookItem;
33
+ //# sourceMappingURL=crud-slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud-slug.d.ts","sourceRoot":"","sources":["../../src/scrapbook/crud-slug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnE;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAiBf;AAED,wEAAwE;AACxE,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAWf;AAED,gDAAgD;AAChD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAef;AAED,gDAAgD;AAChD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,IAAI,CAIN;AAED,yDAAyD;AACzD,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAcf"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * INTERNAL — slug-template CRUD primitives.
3
+ *
4
+ * These were the public mutation surface pre-#192 but are now private:
5
+ * external callers go through the entry-aware `*AtDir` family in
6
+ * `crud-at-dir.ts` after resolving the dir via `scrapbookDirForEntry`
7
+ * (or `scrapbookDirAtPath`). This module is the implementation home
8
+ * for the legacy slug-template path and is re-used inside the scrapbook
9
+ * module family — `seed.ts` calls these helpers to seed a slug-keyed
10
+ * README at plan time.
11
+ *
12
+ * NOT re-exported from the barrel (`packages/core/src/scrapbook.ts`).
13
+ *
14
+ * Same security guards as the entry-aware `*AtDir` family — filename
15
+ * validation + path-traversal containment via the underlying
16
+ * `scrapbookFilePathAtDir`.
17
+ */
18
+ import { existsSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync, } from 'node:fs';
19
+ import { dirname } from 'node:path';
20
+ import { _scrapbookFilePathSlug } from "./paths.js";
21
+ import { classify } from "./validation.js";
22
+ /**
23
+ * INTERNAL — create a new markdown note in the slug-template scrapbook.
24
+ * Used by `seed.ts`. Refuses to overwrite existing files.
25
+ */
26
+ export function _createScrapbookMarkdownSlug(projectRoot, config, site, slug, filename, body, opts = {}) {
27
+ if (!filename.endsWith('.md')) {
28
+ throw new Error(`create endpoint only accepts .md files: "${filename}"`);
29
+ }
30
+ const abs = _scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts);
31
+ if (existsSync(abs)) {
32
+ throw new Error(`file already exists: "${filename}"`);
33
+ }
34
+ mkdirSync(dirname(abs), { recursive: true });
35
+ writeFileSync(abs, body, 'utf-8');
36
+ const st = statSync(abs);
37
+ return {
38
+ name: filename,
39
+ kind: 'md',
40
+ size: st.size,
41
+ mtime: st.mtime.toISOString(),
42
+ };
43
+ }
44
+ /** INTERNAL — overwrite an existing file's contents (slug-template). */
45
+ export function _saveScrapbookFileSlug(projectRoot, config, site, slug, filename, body, opts = {}) {
46
+ const abs = _scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts);
47
+ if (!existsSync(abs))
48
+ throw new Error(`file not found: "${filename}"`);
49
+ writeFileSync(abs, body);
50
+ const st = statSync(abs);
51
+ return {
52
+ name: filename,
53
+ kind: classify(filename),
54
+ size: st.size,
55
+ mtime: st.mtime.toISOString(),
56
+ };
57
+ }
58
+ /** INTERNAL — rename a file (slug-template). */
59
+ export function _renameScrapbookFileSlug(projectRoot, config, site, slug, oldName, newName, opts = {}) {
60
+ const oldAbs = _scrapbookFilePathSlug(projectRoot, config, site, slug, oldName, opts);
61
+ const newAbs = _scrapbookFilePathSlug(projectRoot, config, site, slug, newName, opts);
62
+ if (!existsSync(oldAbs))
63
+ throw new Error(`file not found: "${oldName}"`);
64
+ if (existsSync(newAbs) && oldAbs !== newAbs) {
65
+ throw new Error(`target name already exists: "${newName}"`);
66
+ }
67
+ renameSync(oldAbs, newAbs);
68
+ const st = statSync(newAbs);
69
+ return {
70
+ name: newName,
71
+ kind: classify(newName),
72
+ size: st.size,
73
+ mtime: st.mtime.toISOString(),
74
+ };
75
+ }
76
+ /** INTERNAL — delete a file (slug-template). */
77
+ export function _deleteScrapbookFileSlug(projectRoot, config, site, slug, filename, opts = {}) {
78
+ const abs = _scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts);
79
+ if (!existsSync(abs))
80
+ throw new Error(`file not found: "${filename}"`);
81
+ rmSync(abs);
82
+ }
83
+ /** INTERNAL — write an uploaded file (slug-template). */
84
+ export function _writeScrapbookUploadSlug(projectRoot, config, site, slug, filename, content, opts = {}) {
85
+ const abs = _scrapbookFilePathSlug(projectRoot, config, site, slug, filename, opts);
86
+ if (existsSync(abs)) {
87
+ throw new Error(`file already exists: "${filename}" — rename first`);
88
+ }
89
+ mkdirSync(dirname(abs), { recursive: true });
90
+ writeFileSync(abs, content);
91
+ const st = statSync(abs);
92
+ return {
93
+ name: filename,
94
+ kind: classify(filename),
95
+ size: st.size,
96
+ mtime: st.mtime.toISOString(),
97
+ };
98
+ }
99
+ //# sourceMappingURL=crud-slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud-slug.js","sourceRoot":"","sources":["../../src/scrapbook/crud-slug.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Formatting helpers for the studio chip / viewer.
3
+ *
4
+ * Pure stringly-typed conversions — no fs, no config — so the studio
5
+ * client can import these without pulling in the rest of the scrapbook
6
+ * module family.
7
+ */
8
+ export declare function formatRelativeTime(iso: string, now?: Date): string;
9
+ export declare function formatSize(bytes: number): string;
10
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/scrapbook/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAkB9E;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Formatting helpers for the studio chip / viewer.
3
+ *
4
+ * Pure stringly-typed conversions — no fs, no config — so the studio
5
+ * client can import these without pulling in the rest of the scrapbook
6
+ * module family.
7
+ */
8
+ export function formatRelativeTime(iso, now = new Date()) {
9
+ const then = new Date(iso).getTime();
10
+ const diff = now.getTime() - then;
11
+ if (diff < 0)
12
+ return 'just now';
13
+ const s = Math.floor(diff / 1000);
14
+ if (s < 60)
15
+ return `${s}s ago`;
16
+ const m = Math.floor(s / 60);
17
+ if (m < 60)
18
+ return `${m}m ago`;
19
+ const h = Math.floor(m / 60);
20
+ if (h < 48)
21
+ return `${h}h ago`;
22
+ const d = Math.floor(h / 24);
23
+ if (d < 14)
24
+ return `${d}d ago`;
25
+ const w = Math.floor(d / 7);
26
+ if (w < 9)
27
+ return `${w}w ago`;
28
+ const months = Math.floor(d / 30);
29
+ if (months < 18)
30
+ return `${months}mo ago`;
31
+ const y = Math.floor(d / 365);
32
+ return `${y}y ago`;
33
+ }
34
+ export function formatSize(bytes) {
35
+ if (bytes < 1024)
36
+ return `${bytes} B`;
37
+ if (bytes < 1024 * 1024)
38
+ return `${(bytes / 1024).toFixed(1)} KB`;
39
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
40
+ }
41
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/scrapbook/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,MAAY,IAAI,IAAI,EAAE;IACpE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;IAClC,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IAChC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE;QAAE,OAAO,GAAG,MAAM,QAAQ,CAAC;IAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAC9B,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACpD,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Scrapbook listing + counting helpers.
3
+ *
4
+ * Read-only inventory of a scrapbook directory: sorted item lists +
5
+ * total counts, with a public/secret split.
6
+ *
7
+ * Three addressing modes — slug-template (`listScrapbook` /
8
+ * `countScrapbook`), pre-resolved dir (`listScrapbookAtDir`), and
9
+ * entry-aware (`listScrapbookForEntry` / `countScrapbookForEntry`).
10
+ * The slug-template variants stay public because read-side callers
11
+ * (the studio scrapbook viewer page, the dashboard chip count) operate
12
+ * on a path key that's structurally a slug; the legacy entry point is
13
+ * still useful at that boundary. The mutation side (#192) collapsed
14
+ * to entry-aware only.
15
+ */
16
+ import type { DeskworkConfig } from '../config.ts';
17
+ import type { ContentIndex } from '../content-index.ts';
18
+ import { type ScrapbookSummary } from './types.ts';
19
+ /**
20
+ * List the items in a scrapbook, sorted newest-mtime first. Returns
21
+ * both public items (top-level files) and secret items (files inside
22
+ * `scrapbook/secret/`). Subdirectories at the top level OTHER than
23
+ * `secret/` are ignored — deskwork doesn't recurse into arbitrary
24
+ * trees inside a scrapbook.
25
+ */
26
+ export declare function listScrapbook(projectRoot: string, config: DeskworkConfig, site: string, slug: string): ScrapbookSummary;
27
+ /**
28
+ * List a scrapbook by absolute directory path. Used by callers that
29
+ * have already resolved the on-disk path via `scrapbookDirForEntry`
30
+ * (id-driven) or `scrapbookDirAtPath` (fs-path-driven) and don't want
31
+ * to re-derive through the slug template. The `slug` parameter is only
32
+ * used to populate the returned summary's identifier field — it does
33
+ * not influence path resolution.
34
+ *
35
+ * Internal primitive shared by `listScrapbook` (slug-based) and
36
+ * `listScrapbookForEntry` (id-driven).
37
+ */
38
+ export declare function listScrapbookAtDir(site: string, slug: string, dir: string): ScrapbookSummary;
39
+ /**
40
+ * List scrapbook items for a tracked calendar entry. Resolves the
41
+ * scrapbook directory via the content index when available (id binding),
42
+ * falling back to slug-based addressing for entries that haven't been
43
+ * bound to frontmatter yet (pre-doctor state).
44
+ *
45
+ * Mirrors the shape of `countScrapbookForEntry`. Used by the studio
46
+ * review-page drawer + content-detail panel so writingcontrol-shape
47
+ * entries (where the file path diverges from the slug template) list
48
+ * items at the correct on-disk location.
49
+ *
50
+ * @param entry Calendar entry — `id` preferred; `slug` is both the
51
+ * legacy fallback and the disambiguator the underlying
52
+ * resolver uses when the index is incomplete.
53
+ * @param index Optional pre-built per-request index. When omitted, the
54
+ * resolver builds one on demand.
55
+ */
56
+ export declare function listScrapbookForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
57
+ id?: string;
58
+ slug: string;
59
+ }, index?: ContentIndex): ScrapbookSummary;
60
+ /**
61
+ * Total item count (public + secret). Used by the studio chip for the
62
+ * badge — operators want a single "has scrapbook content" signal that
63
+ * counts everything attached to this entry.
64
+ *
65
+ * Slug-based addressing: resolves `<contentDir>/<slug>/scrapbook/`. For
66
+ * entries whose on-disk path doesn't match the slug template (e.g.
67
+ * writingcontrol-shape projects where slug `the-outbound` lives at
68
+ * `projects/the-outbound/index.md`), use `countScrapbookForEntry`
69
+ * instead — it derives the path from the bound file via the content
70
+ * index.
71
+ */
72
+ export declare function countScrapbook(projectRoot: string, config: DeskworkConfig, site: string, slug: string): number;
73
+ /**
74
+ * Count scrapbook items for a tracked calendar entry. Resolves the
75
+ * scrapbook directory via the content index when available (id binding),
76
+ * falling back to slug-based addressing for entries that haven't been
77
+ * bound to frontmatter yet (pre-doctor state).
78
+ *
79
+ * Mirrors the shape of `scrapbookDirForEntry` — same resolver, same
80
+ * legacy-slug fallback. Used by the studio dashboard chip so writing-
81
+ * control-shape entries (where the file path diverges from the slug
82
+ * template) report the correct count.
83
+ *
84
+ * @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
85
+ * both the legacy fallback and the disambiguator the
86
+ * underlying resolver uses when the index is incomplete.
87
+ * @param index Optional pre-built per-request index. When omitted, the
88
+ * resolver builds one on demand.
89
+ */
90
+ export declare function countScrapbookForEntry(projectRoot: string, config: DeskworkConfig, site: string, entry: {
91
+ id?: string;
92
+ slug: string;
93
+ }, index?: ContentIndex): number;
94
+ //# sourceMappingURL=listing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing.d.ts","sourceRoot":"","sources":["../../src/scrapbook/listing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAMpB;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,gBAAgB,CAGlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,gBAAgB,CAQlB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CACnC,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,gBAAgB,CAGlB;AA6CD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM,CAOR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,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,CAOR"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Scrapbook listing + counting helpers.
3
+ *
4
+ * Read-only inventory of a scrapbook directory: sorted item lists +
5
+ * total counts, with a public/secret split.
6
+ *
7
+ * Three addressing modes — slug-template (`listScrapbook` /
8
+ * `countScrapbook`), pre-resolved dir (`listScrapbookAtDir`), and
9
+ * entry-aware (`listScrapbookForEntry` / `countScrapbookForEntry`).
10
+ * The slug-template variants stay public because read-side callers
11
+ * (the studio scrapbook viewer page, the dashboard chip count) operate
12
+ * on a path key that's structurally a slug; the legacy entry point is
13
+ * still useful at that boundary. The mutation side (#192) collapsed
14
+ * to entry-aware only.
15
+ */
16
+ import { existsSync, readdirSync, statSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { _scrapbookDirSlug, scrapbookDirForEntry } from "./paths.js";
19
+ import { classify } from "./validation.js";
20
+ import { SECRET_SUBDIR, } from "./types.js";
21
+ // ---------------------------------------------------------------------------
22
+ // Listing
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * List the items in a scrapbook, sorted newest-mtime first. Returns
26
+ * both public items (top-level files) and secret items (files inside
27
+ * `scrapbook/secret/`). Subdirectories at the top level OTHER than
28
+ * `secret/` are ignored — deskwork doesn't recurse into arbitrary
29
+ * trees inside a scrapbook.
30
+ */
31
+ export function listScrapbook(projectRoot, config, site, slug) {
32
+ const dir = _scrapbookDirSlug(projectRoot, config, site, slug);
33
+ return listScrapbookAtDir(site, slug, dir);
34
+ }
35
+ /**
36
+ * List a scrapbook by absolute directory path. Used by callers that
37
+ * have already resolved the on-disk path via `scrapbookDirForEntry`
38
+ * (id-driven) or `scrapbookDirAtPath` (fs-path-driven) and don't want
39
+ * to re-derive through the slug template. The `slug` parameter is only
40
+ * used to populate the returned summary's identifier field — it does
41
+ * not influence path resolution.
42
+ *
43
+ * Internal primitive shared by `listScrapbook` (slug-based) and
44
+ * `listScrapbookForEntry` (id-driven).
45
+ */
46
+ export function listScrapbookAtDir(site, slug, dir) {
47
+ if (!existsSync(dir)) {
48
+ return { site, slug, dir, exists: false, items: [], secretItems: [] };
49
+ }
50
+ const items = listFilesInDir(dir);
51
+ const secretDir = join(dir, SECRET_SUBDIR);
52
+ const secretItems = existsSync(secretDir) ? listFilesInDir(secretDir) : [];
53
+ return { site, slug, dir, exists: true, items, secretItems };
54
+ }
55
+ /**
56
+ * List scrapbook items for a tracked calendar entry. Resolves the
57
+ * scrapbook directory via the content index when available (id binding),
58
+ * falling back to slug-based addressing for entries that haven't been
59
+ * bound to frontmatter yet (pre-doctor state).
60
+ *
61
+ * Mirrors the shape of `countScrapbookForEntry`. Used by the studio
62
+ * review-page drawer + content-detail panel so writingcontrol-shape
63
+ * entries (where the file path diverges from the slug template) list
64
+ * items at the correct on-disk location.
65
+ *
66
+ * @param entry Calendar entry — `id` preferred; `slug` is both the
67
+ * legacy fallback and the disambiguator the underlying
68
+ * resolver uses when the index is incomplete.
69
+ * @param index Optional pre-built per-request index. When omitted, the
70
+ * resolver builds one on demand.
71
+ */
72
+ export function listScrapbookForEntry(projectRoot, config, site, entry, index) {
73
+ const dir = scrapbookDirForEntry(projectRoot, config, site, entry, index);
74
+ return listScrapbookAtDir(site, entry.slug, dir);
75
+ }
76
+ /** Internal helper — list files (not subdirs/dotfiles) at a given path. */
77
+ function listFilesInDir(dir) {
78
+ const items = [];
79
+ for (const e of readdirSync(dir, { withFileTypes: true })) {
80
+ if (!e.isFile())
81
+ continue;
82
+ if (e.name.startsWith('.'))
83
+ continue;
84
+ const abs = join(dir, e.name);
85
+ const st = statSync(abs);
86
+ items.push({
87
+ name: e.name,
88
+ kind: classify(e.name),
89
+ size: st.size,
90
+ mtime: st.mtime.toISOString(),
91
+ });
92
+ }
93
+ items.sort((a, b) => b.mtime.localeCompare(a.mtime));
94
+ return items;
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Counting
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Count items inside an absolute scrapbook directory — files at the top
101
+ * level plus files inside the `secret/` subdirectory. Returns 0 if the
102
+ * directory doesn't exist; tolerates fs errors so a transient permission
103
+ * issue or race never crashes the dashboard render. Internal primitive
104
+ * shared by `countScrapbook` (slug-based) and `countScrapbookForEntry`
105
+ * (id-driven).
106
+ */
107
+ function countScrapbookAtDir(dir) {
108
+ try {
109
+ if (!existsSync(dir))
110
+ return 0;
111
+ const top = listFilesInDir(dir);
112
+ const secretDir = join(dir, SECRET_SUBDIR);
113
+ const secret = existsSync(secretDir) ? listFilesInDir(secretDir) : [];
114
+ return top.length + secret.length;
115
+ }
116
+ catch {
117
+ return 0;
118
+ }
119
+ }
120
+ /**
121
+ * Total item count (public + secret). Used by the studio chip for the
122
+ * badge — operators want a single "has scrapbook content" signal that
123
+ * counts everything attached to this entry.
124
+ *
125
+ * Slug-based addressing: resolves `<contentDir>/<slug>/scrapbook/`. For
126
+ * entries whose on-disk path doesn't match the slug template (e.g.
127
+ * writingcontrol-shape projects where slug `the-outbound` lives at
128
+ * `projects/the-outbound/index.md`), use `countScrapbookForEntry`
129
+ * instead — it derives the path from the bound file via the content
130
+ * index.
131
+ */
132
+ export function countScrapbook(projectRoot, config, site, slug) {
133
+ try {
134
+ const dir = _scrapbookDirSlug(projectRoot, config, site, slug);
135
+ return countScrapbookAtDir(dir);
136
+ }
137
+ catch {
138
+ return 0;
139
+ }
140
+ }
141
+ /**
142
+ * Count scrapbook items for a tracked calendar entry. Resolves the
143
+ * scrapbook directory via the content index when available (id binding),
144
+ * falling back to slug-based addressing for entries that haven't been
145
+ * bound to frontmatter yet (pre-doctor state).
146
+ *
147
+ * Mirrors the shape of `scrapbookDirForEntry` — same resolver, same
148
+ * legacy-slug fallback. Used by the studio dashboard chip so writing-
149
+ * control-shape entries (where the file path diverges from the slug
150
+ * template) report the correct count.
151
+ *
152
+ * @param entry Calendar entry — `id` preferred (Phase 19+); `slug` is
153
+ * both the legacy fallback and the disambiguator the
154
+ * underlying resolver uses when the index is incomplete.
155
+ * @param index Optional pre-built per-request index. When omitted, the
156
+ * resolver builds one on demand.
157
+ */
158
+ export function countScrapbookForEntry(projectRoot, config, site, entry, index) {
159
+ try {
160
+ const dir = scrapbookDirForEntry(projectRoot, config, site, entry, index);
161
+ return countScrapbookAtDir(dir);
162
+ }
163
+ catch {
164
+ return 0;
165
+ }
166
+ }
167
+ //# sourceMappingURL=listing.js.map