@design-intelligence/ghost 0.20.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 (269) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +75 -0
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +19 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/cli.d.ts +4 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +29 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/checks-command.d.ts +9 -0
  12. package/dist/commands/checks-command.d.ts.map +1 -0
  13. package/dist/commands/checks-command.js +45 -0
  14. package/dist/commands/checks-command.js.map +1 -0
  15. package/dist/commands/command-discovery.d.ts +57 -0
  16. package/dist/commands/command-discovery.d.ts.map +1 -0
  17. package/dist/commands/command-discovery.js +220 -0
  18. package/dist/commands/command-discovery.js.map +1 -0
  19. package/dist/commands/errors.d.ts +7 -0
  20. package/dist/commands/errors.d.ts.map +1 -0
  21. package/dist/commands/errors.js +19 -0
  22. package/dist/commands/errors.js.map +1 -0
  23. package/dist/commands/export-command.d.ts +3 -0
  24. package/dist/commands/export-command.d.ts.map +1 -0
  25. package/dist/commands/export-command.js +157 -0
  26. package/dist/commands/export-command.js.map +1 -0
  27. package/dist/commands/fingerprint-commands.d.ts +10 -0
  28. package/dist/commands/fingerprint-commands.d.ts.map +1 -0
  29. package/dist/commands/fingerprint-commands.js +74 -0
  30. package/dist/commands/fingerprint-commands.js.map +1 -0
  31. package/dist/commands/gather-command.d.ts +3 -0
  32. package/dist/commands/gather-command.d.ts.map +1 -0
  33. package/dist/commands/gather-command.js +152 -0
  34. package/dist/commands/gather-command.js.map +1 -0
  35. package/dist/commands/init-command.d.ts +3 -0
  36. package/dist/commands/init-command.d.ts.map +1 -0
  37. package/dist/commands/init-command.js +79 -0
  38. package/dist/commands/init-command.js.map +1 -0
  39. package/dist/commands/manifest-command.d.ts +9 -0
  40. package/dist/commands/manifest-command.d.ts.map +1 -0
  41. package/dist/commands/manifest-command.js +33 -0
  42. package/dist/commands/manifest-command.js.map +1 -0
  43. package/dist/commands/pull-command.d.ts +3 -0
  44. package/dist/commands/pull-command.d.ts.map +1 -0
  45. package/dist/commands/pull-command.js +224 -0
  46. package/dist/commands/pull-command.js.map +1 -0
  47. package/dist/commands/pulse-command.d.ts +3 -0
  48. package/dist/commands/pulse-command.d.ts.map +1 -0
  49. package/dist/commands/pulse-command.js +257 -0
  50. package/dist/commands/pulse-command.js.map +1 -0
  51. package/dist/commands/review-command.d.ts +3 -0
  52. package/dist/commands/review-command.d.ts.map +1 -0
  53. package/dist/commands/review-command.js +77 -0
  54. package/dist/commands/review-command.js.map +1 -0
  55. package/dist/commands/skill-command.d.ts +3 -0
  56. package/dist/commands/skill-command.d.ts.map +1 -0
  57. package/dist/commands/skill-command.js +96 -0
  58. package/dist/commands/skill-command.js.map +1 -0
  59. package/dist/fingerprint.d.ts +5 -0
  60. package/dist/fingerprint.d.ts.map +1 -0
  61. package/dist/fingerprint.js +3 -0
  62. package/dist/fingerprint.js.map +1 -0
  63. package/dist/ghost-core/catalog/assemble.d.ts +30 -0
  64. package/dist/ghost-core/catalog/assemble.d.ts.map +1 -0
  65. package/dist/ghost-core/catalog/assemble.js +38 -0
  66. package/dist/ghost-core/catalog/assemble.js.map +1 -0
  67. package/dist/ghost-core/catalog/closest.d.ts +16 -0
  68. package/dist/ghost-core/catalog/closest.d.ts.map +1 -0
  69. package/dist/ghost-core/catalog/closest.js +63 -0
  70. package/dist/ghost-core/catalog/closest.js.map +1 -0
  71. package/dist/ghost-core/catalog/index.d.ts +10 -0
  72. package/dist/ghost-core/catalog/index.d.ts.map +1 -0
  73. package/dist/ghost-core/catalog/index.js +9 -0
  74. package/dist/ghost-core/catalog/index.js.map +1 -0
  75. package/dist/ghost-core/catalog/menu.d.ts +36 -0
  76. package/dist/ghost-core/catalog/menu.d.ts.map +1 -0
  77. package/dist/ghost-core/catalog/menu.js +27 -0
  78. package/dist/ghost-core/catalog/menu.js.map +1 -0
  79. package/dist/ghost-core/catalog/types.d.ts +37 -0
  80. package/dist/ghost-core/catalog/types.d.ts.map +1 -0
  81. package/dist/ghost-core/catalog/types.js +2 -0
  82. package/dist/ghost-core/catalog/types.js.map +1 -0
  83. package/dist/ghost-core/check/index.d.ts +12 -0
  84. package/dist/ghost-core/check/index.d.ts.map +1 -0
  85. package/dist/ghost-core/check/index.js +12 -0
  86. package/dist/ghost-core/check/index.js.map +1 -0
  87. package/dist/ghost-core/check/lint.d.ts +9 -0
  88. package/dist/ghost-core/check/lint.d.ts.map +1 -0
  89. package/dist/ghost-core/check/lint.js +119 -0
  90. package/dist/ghost-core/check/lint.js.map +1 -0
  91. package/dist/ghost-core/check/load.d.ts +7 -0
  92. package/dist/ghost-core/check/load.d.ts.map +1 -0
  93. package/dist/ghost-core/check/load.js +44 -0
  94. package/dist/ghost-core/check/load.js.map +1 -0
  95. package/dist/ghost-core/check/parse.d.ts +12 -0
  96. package/dist/ghost-core/check/parse.d.ts.map +1 -0
  97. package/dist/ghost-core/check/parse.js +13 -0
  98. package/dist/ghost-core/check/parse.js.map +1 -0
  99. package/dist/ghost-core/check/source-ref.d.ts +27 -0
  100. package/dist/ghost-core/check/source-ref.d.ts.map +1 -0
  101. package/dist/ghost-core/check/source-ref.js +58 -0
  102. package/dist/ghost-core/check/source-ref.js.map +1 -0
  103. package/dist/ghost-core/check/types.d.ts +48 -0
  104. package/dist/ghost-core/check/types.d.ts.map +1 -0
  105. package/dist/ghost-core/check/types.js +4 -0
  106. package/dist/ghost-core/check/types.js.map +1 -0
  107. package/dist/ghost-core/errors.d.ts +30 -0
  108. package/dist/ghost-core/errors.d.ts.map +1 -0
  109. package/dist/ghost-core/errors.js +33 -0
  110. package/dist/ghost-core/errors.js.map +1 -0
  111. package/dist/ghost-core/glob.d.ts +5 -0
  112. package/dist/ghost-core/glob.d.ts.map +1 -0
  113. package/dist/ghost-core/glob.js +68 -0
  114. package/dist/ghost-core/glob.js.map +1 -0
  115. package/dist/ghost-core/glossary.d.ts +38 -0
  116. package/dist/ghost-core/glossary.d.ts.map +1 -0
  117. package/dist/ghost-core/glossary.js +76 -0
  118. package/dist/ghost-core/glossary.js.map +1 -0
  119. package/dist/ghost-core/index.d.ts +13 -0
  120. package/dist/ghost-core/index.d.ts.map +1 -0
  121. package/dist/ghost-core/index.js +19 -0
  122. package/dist/ghost-core/index.js.map +1 -0
  123. package/dist/ghost-core/markdown.d.ts +15 -0
  124. package/dist/ghost-core/markdown.d.ts.map +1 -0
  125. package/dist/ghost-core/markdown.js +30 -0
  126. package/dist/ghost-core/markdown.js.map +1 -0
  127. package/dist/ghost-core/material-transport.d.ts +43 -0
  128. package/dist/ghost-core/material-transport.d.ts.map +1 -0
  129. package/dist/ghost-core/material-transport.js +231 -0
  130. package/dist/ghost-core/material-transport.js.map +1 -0
  131. package/dist/ghost-core/materials.d.ts +14 -0
  132. package/dist/ghost-core/materials.d.ts.map +1 -0
  133. package/dist/ghost-core/materials.js +52 -0
  134. package/dist/ghost-core/materials.js.map +1 -0
  135. package/dist/ghost-core/node/index.d.ts +11 -0
  136. package/dist/ghost-core/node/index.d.ts.map +1 -0
  137. package/dist/ghost-core/node/index.js +11 -0
  138. package/dist/ghost-core/node/index.js.map +1 -0
  139. package/dist/ghost-core/node/parse.d.ts +16 -0
  140. package/dist/ghost-core/node/parse.d.ts.map +1 -0
  141. package/dist/ghost-core/node/parse.js +55 -0
  142. package/dist/ghost-core/node/parse.js.map +1 -0
  143. package/dist/ghost-core/node/schema.d.ts +17 -0
  144. package/dist/ghost-core/node/schema.d.ts.map +1 -0
  145. package/dist/ghost-core/node/schema.js +49 -0
  146. package/dist/ghost-core/node/schema.js.map +1 -0
  147. package/dist/ghost-core/node/serialize.d.ts +11 -0
  148. package/dist/ghost-core/node/serialize.d.ts.map +1 -0
  149. package/dist/ghost-core/node/serialize.js +21 -0
  150. package/dist/ghost-core/node/serialize.js.map +1 -0
  151. package/dist/ghost-core/node/steering.d.ts +18 -0
  152. package/dist/ghost-core/node/steering.d.ts.map +1 -0
  153. package/dist/ghost-core/node/steering.js +65 -0
  154. package/dist/ghost-core/node/steering.js.map +1 -0
  155. package/dist/ghost-core/node/types.d.ts +42 -0
  156. package/dist/ghost-core/node/types.d.ts.map +1 -0
  157. package/dist/ghost-core/node/types.js +2 -0
  158. package/dist/ghost-core/node/types.js.map +1 -0
  159. package/dist/ghost-core/package-manifest.d.ts +12 -0
  160. package/dist/ghost-core/package-manifest.d.ts.map +1 -0
  161. package/dist/ghost-core/package-manifest.js +14 -0
  162. package/dist/ghost-core/package-manifest.js.map +1 -0
  163. package/dist/ghost-core/skill-bundle-loader.d.ts +28 -0
  164. package/dist/ghost-core/skill-bundle-loader.d.ts.map +1 -0
  165. package/dist/ghost-core/skill-bundle-loader.js +51 -0
  166. package/dist/ghost-core/skill-bundle-loader.js.map +1 -0
  167. package/dist/index.d.ts +5 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +5 -0
  170. package/dist/index.js.map +1 -0
  171. package/dist/internal/fs.d.ts +4 -0
  172. package/dist/internal/fs.d.ts.map +1 -0
  173. package/dist/internal/fs.js +24 -0
  174. package/dist/internal/fs.js.map +1 -0
  175. package/dist/observability-events.d.ts +27 -0
  176. package/dist/observability-events.d.ts.map +1 -0
  177. package/dist/observability-events.js +56 -0
  178. package/dist/observability-events.js.map +1 -0
  179. package/dist/package-version.d.ts +3 -0
  180. package/dist/package-version.d.ts.map +1 -0
  181. package/dist/package-version.js +10 -0
  182. package/dist/package-version.js.map +1 -0
  183. package/dist/review/baseline.d.ts +11 -0
  184. package/dist/review/baseline.d.ts.map +1 -0
  185. package/dist/review/baseline.js +35 -0
  186. package/dist/review/baseline.js.map +1 -0
  187. package/dist/review/diff.d.ts +7 -0
  188. package/dist/review/diff.d.ts.map +1 -0
  189. package/dist/review/diff.js +41 -0
  190. package/dist/review/diff.js.map +1 -0
  191. package/dist/review/glob.d.ts +2 -0
  192. package/dist/review/glob.d.ts.map +1 -0
  193. package/dist/review/glob.js +2 -0
  194. package/dist/review/glob.js.map +1 -0
  195. package/dist/review/probes.d.ts +13 -0
  196. package/dist/review/probes.d.ts.map +1 -0
  197. package/dist/review/probes.js +45 -0
  198. package/dist/review/probes.js.map +1 -0
  199. package/dist/review/resolve.d.ts +29 -0
  200. package/dist/review/resolve.d.ts.map +1 -0
  201. package/dist/review/resolve.js +87 -0
  202. package/dist/review/resolve.js.map +1 -0
  203. package/dist/review/review-packet.d.ts +40 -0
  204. package/dist/review/review-packet.d.ts.map +1 -0
  205. package/dist/review/review-packet.js +139 -0
  206. package/dist/review/review-packet.js.map +1 -0
  207. package/dist/scan/check-files.d.ts +23 -0
  208. package/dist/scan/check-files.d.ts.map +1 -0
  209. package/dist/scan/check-files.js +90 -0
  210. package/dist/scan/check-files.js.map +1 -0
  211. package/dist/scan/check-scaffold.d.ts +7 -0
  212. package/dist/scan/check-scaffold.d.ts.map +1 -0
  213. package/dist/scan/check-scaffold.js +37 -0
  214. package/dist/scan/check-scaffold.js.map +1 -0
  215. package/dist/scan/constants.d.ts +21 -0
  216. package/dist/scan/constants.d.ts.map +1 -0
  217. package/dist/scan/constants.js +21 -0
  218. package/dist/scan/constants.js.map +1 -0
  219. package/dist/scan/file-kind.d.ts +12 -0
  220. package/dist/scan/file-kind.d.ts.map +1 -0
  221. package/dist/scan/file-kind.js +114 -0
  222. package/dist/scan/file-kind.js.map +1 -0
  223. package/dist/scan/fingerprint-package-loader.d.ts +5 -0
  224. package/dist/scan/fingerprint-package-loader.d.ts.map +1 -0
  225. package/dist/scan/fingerprint-package-loader.js +105 -0
  226. package/dist/scan/fingerprint-package-loader.js.map +1 -0
  227. package/dist/scan/fingerprint-package.d.ts +58 -0
  228. package/dist/scan/fingerprint-package.d.ts.map +1 -0
  229. package/dist/scan/fingerprint-package.js +301 -0
  230. package/dist/scan/fingerprint-package.js.map +1 -0
  231. package/dist/scan/index.d.ts +3 -0
  232. package/dist/scan/index.d.ts.map +1 -0
  233. package/dist/scan/index.js +3 -0
  234. package/dist/scan/index.js.map +1 -0
  235. package/dist/scan/lint.d.ts +15 -0
  236. package/dist/scan/lint.d.ts.map +1 -0
  237. package/dist/scan/lint.js +2 -0
  238. package/dist/scan/lint.js.map +1 -0
  239. package/dist/scan/node-files.d.ts +25 -0
  240. package/dist/scan/node-files.d.ts.map +1 -0
  241. package/dist/scan/node-files.js +114 -0
  242. package/dist/scan/node-files.js.map +1 -0
  243. package/dist/scan/package-paths.d.ts +10 -0
  244. package/dist/scan/package-paths.d.ts.map +1 -0
  245. package/dist/scan/package-paths.js +49 -0
  246. package/dist/scan/package-paths.js.map +1 -0
  247. package/dist/scan/steering-template.d.ts +8 -0
  248. package/dist/scan/steering-template.d.ts.map +1 -0
  249. package/dist/scan/steering-template.js +266 -0
  250. package/dist/scan/steering-template.js.map +1 -0
  251. package/dist/scan/tarball.d.ts +23 -0
  252. package/dist/scan/tarball.d.ts.map +1 -0
  253. package/dist/scan/tarball.js +145 -0
  254. package/dist/scan/tarball.js.map +1 -0
  255. package/dist/scan/templates.d.ts +24 -0
  256. package/dist/scan/templates.d.ts.map +1 -0
  257. package/dist/scan/templates.js +295 -0
  258. package/dist/scan/templates.js.map +1 -0
  259. package/dist/skill-bundle/SKILL.md +140 -0
  260. package/dist/skill-bundle/references/authoring-scenarios.md +147 -0
  261. package/dist/skill-bundle/references/blocks.md +180 -0
  262. package/dist/skill-bundle/references/brief.md +49 -0
  263. package/dist/skill-bundle/references/capture.md +377 -0
  264. package/dist/skill-bundle/references/recall.md +38 -0
  265. package/dist/skill-bundle/references/schema.md +119 -0
  266. package/dist/skill-bundle/references/self-check.md +65 -0
  267. package/dist/skill-bundle/references/steering-audit.md +61 -0
  268. package/dist/skill-bundle/references/wild.md +30 -0
  269. package/package.json +79 -0
@@ -0,0 +1,15 @@
1
+ export type LintSeverity = "error" | "warning" | "info";
2
+ export interface LintIssue {
3
+ severity: LintSeverity;
4
+ rule: string;
5
+ message: string;
6
+ /** Dotted path in the file (e.g. "intent.principles[0].evidence"). */
7
+ path?: string;
8
+ }
9
+ export interface LintReport {
10
+ issues: LintIssue[];
11
+ errors: number;
12
+ warnings: number;
13
+ info: number;
14
+ }
15
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/scan/lint.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/scan/lint.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import { type PlacedNode } from "#ghost-core";
2
+ export interface LoadedNodeFiles {
3
+ nodes: PlacedNode[];
4
+ /** Files that failed lint, with their first error message (path-relative id). */
5
+ invalid: Array<{
6
+ file: string;
7
+ message: string;
8
+ }>;
9
+ }
10
+ /**
11
+ * Load authored prose nodes from the package directory. The corpus is flat:
12
+ * there is no hierarchy, no inheritance, no edges. Nesting into directories is a
13
+ * browsing convenience only.
14
+ *
15
+ * Every `*.md` file under the package directory is a node. Its id is its path
16
+ * with `.md` dropped, uniformly (`marketing/email.md` → `marketing/email`,
17
+ * `index.md` → `index`). The reserved root entries — `manifest.yml`,
18
+ * `glossary.md`, `materials/`, and `checks/` — are skipped.
19
+ *
20
+ * A file that fails per-node lint is collected in `invalid` (with its first
21
+ * error) and skipped rather than throwing, so one bad node does not block
22
+ * loading the rest. A missing package directory or empty corpus yields no nodes.
23
+ */
24
+ export declare function loadNodeFiles(packageDir: string): Promise<LoadedNodeFiles>;
25
+ //# sourceMappingURL=node-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-files.d.ts","sourceRoot":"","sources":["../../src/scan/node-files.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAa,MAAM,aAAa,CAAC;AAuBzD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,iFAAiF;IACjF,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAU1B"}
@@ -0,0 +1,114 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { parseNode } from "#ghost-core";
4
+ import { FINGERPRINT_MANIFEST_FILENAME, GHOST_GLOSSARY_FILENAME, GHOST_MATERIALS_DIR, } from "./constants.js";
5
+ /**
6
+ * Reserved package-root entries that are never nodes: the manifest (the
7
+ * package anchor), the glossary, `materials/` (bundled materials), and
8
+ * `checks/` (review checks — feed-back only, never generation context). The
9
+ * list is closed. `haunts/` is the legacy pre-flat checks location, kept
10
+ * reserved so stale packages do not misload its contents as nodes.
11
+ */
12
+ const RESERVED_ROOT_ENTRIES = new Set([
13
+ FINGERPRINT_MANIFEST_FILENAME,
14
+ "manifest.yaml",
15
+ GHOST_GLOSSARY_FILENAME,
16
+ GHOST_MATERIALS_DIR,
17
+ "checks",
18
+ "haunts",
19
+ ]);
20
+ /**
21
+ * Load authored prose nodes from the package directory. The corpus is flat:
22
+ * there is no hierarchy, no inheritance, no edges. Nesting into directories is a
23
+ * browsing convenience only.
24
+ *
25
+ * Every `*.md` file under the package directory is a node. Its id is its path
26
+ * with `.md` dropped, uniformly (`marketing/email.md` → `marketing/email`,
27
+ * `index.md` → `index`). The reserved root entries — `manifest.yml`,
28
+ * `glossary.md`, `materials/`, and `checks/` — are skipped.
29
+ *
30
+ * A file that fails per-node lint is collected in `invalid` (with its first
31
+ * error) and skipped rather than throwing, so one bad node does not block
32
+ * loading the rest. A missing package directory or empty corpus yields no nodes.
33
+ */
34
+ export async function loadNodeFiles(packageDir) {
35
+ const nodes = [];
36
+ const invalid = [];
37
+ await walk(packageDir, "", true, nodes, invalid);
38
+ // Deterministic order by id, mirroring the old sorted readdir.
39
+ nodes.sort((a, b) => a.id.localeCompare(b.id));
40
+ invalid.sort((a, b) => a.file.localeCompare(b.file));
41
+ return { nodes, invalid };
42
+ }
43
+ async function walk(packageDir, relDir, isRoot, nodes, invalid) {
44
+ const absDir = relDir === "" ? packageDir : join(packageDir, relDir);
45
+ let entries;
46
+ try {
47
+ const dirents = await readdir(absDir, { withFileTypes: true });
48
+ entries = dirents.map((d) => ({ name: d.name, isDir: d.isDirectory() }));
49
+ }
50
+ catch {
51
+ return;
52
+ }
53
+ for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
54
+ if (isRoot && RESERVED_ROOT_ENTRIES.has(entry.name))
55
+ continue;
56
+ if (entry.name.startsWith("."))
57
+ continue;
58
+ const relPath = relDir === "" ? entry.name : `${relDir}/${entry.name}`;
59
+ if (entry.isDir) {
60
+ await walk(packageDir, relPath, false, nodes, invalid);
61
+ continue;
62
+ }
63
+ if (!entry.name.endsWith(".md"))
64
+ continue;
65
+ const raw = await readFile(join(packageDir, relPath), "utf-8");
66
+ const { node, report } = parseNode(raw);
67
+ if (node === null || report.errors > 0) {
68
+ const first = report.issues.find((issue) => issue.severity === "error");
69
+ invalid.push({
70
+ file: relPath,
71
+ message: first?.message ?? "invalid node",
72
+ });
73
+ continue;
74
+ }
75
+ const { id, kind, slug } = locate(relPath);
76
+ nodes.push({
77
+ id,
78
+ ...(kind !== undefined ? { kind } : {}),
79
+ slug,
80
+ doc: node,
81
+ });
82
+ }
83
+ }
84
+ /**
85
+ * Compute a node's id and filename kind/slug from its package-relative path.
86
+ *
87
+ * The rule is uniform: the **id** is the path with `.md` dropped. The **kind**
88
+ * is the leaf filename's first dotted segment, and only exists when the leaf
89
+ * has a dot; the **slug** is the rest of the leaf. A kind never changes a
90
+ * node's identity path. `index.md` is an ordinary node with id `index` — by
91
+ * convention the human-curated front door, but nothing special to the loader.
92
+ * - `index.md` → id `index`, slug `index` (no kind).
93
+ * - `voice.md` → id `voice`, slug `voice` (no kind).
94
+ * - `principle.density.md` → id `principle.density`, kind `principle`, slug `density`.
95
+ * - `a/principle.trust.md` → id `a/principle.trust`, kind `principle`, slug `trust`.
96
+ */
97
+ function locate(relPath) {
98
+ const withoutExt = relPath.replace(/\.md$/, "");
99
+ const segments = withoutExt.split("/");
100
+ const leaf = segments[segments.length - 1] ?? "";
101
+ const id = withoutExt;
102
+ // A dotted leaf splits into kind (first segment) and slug (the remainder);
103
+ // a bare leaf is all slug with no kind.
104
+ const dot = leaf.indexOf(".");
105
+ if (dot > 0) {
106
+ return {
107
+ id,
108
+ kind: leaf.slice(0, dot),
109
+ slug: leaf.slice(dot + 1),
110
+ };
111
+ }
112
+ return { id, slug: leaf };
113
+ }
114
+ //# sourceMappingURL=node-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-files.js","sourceRoot":"","sources":["../../src/scan/node-files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Neutral home for the load-bearing package-path helpers: direct package
3
+ * addressing (no nesting machinery), consumed by fingerprint-commands,
4
+ * init-command, monorepo-init-command, and the scan/index re-exports.
5
+ */
6
+ export declare function resolveGitRoot(cwd?: string): Promise<string>;
7
+ export declare function normalizeGhostDir(ghostDir?: string): string;
8
+ export declare const GHOST_PACKAGE_DIR_ENV = "GHOST_PACKAGE_DIR";
9
+ export declare function resolveGhostDirDefault(explicitGhostDir?: unknown, env?: NodeJS.ProcessEnv): string;
10
+ //# sourceMappingURL=package-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-paths.d.ts","sourceRoot":"","sources":["../../src/scan/package-paths.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AAEH,wBAAsB,cAAc,CAAC,GAAG,SAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAazE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,SAA0B,GAAG,MAAM,CA2B5E;AAED,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD,wBAAgB,sBAAsB,CACpC,gBAAgB,CAAC,EAAE,OAAO,EAC1B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAMR"}
@@ -0,0 +1,49 @@
1
+ import { execFile } from "node:child_process";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import { promisify } from "node:util";
4
+ import { UsageError } from "#ghost-core";
5
+ import { FINGERPRINT_PACKAGE_DIR } from "./constants.js";
6
+ const execFileAsync = promisify(execFile);
7
+ /**
8
+ * Neutral home for the load-bearing package-path helpers: direct package
9
+ * addressing (no nesting machinery), consumed by fingerprint-commands,
10
+ * init-command, monorepo-init-command, and the scan/index re-exports.
11
+ */
12
+ export async function resolveGitRoot(cwd = process.cwd()) {
13
+ try {
14
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
15
+ cwd,
16
+ });
17
+ return resolve(stdout.trim());
18
+ }
19
+ catch {
20
+ return resolve(cwd);
21
+ }
22
+ }
23
+ export function normalizeGhostDir(ghostDir = FINGERPRINT_PACKAGE_DIR) {
24
+ const normalized = ghostDir
25
+ .trim()
26
+ .replaceAll("\\", "/")
27
+ .replace(/\/+/g, "/")
28
+ .replace(/\/$/g, "");
29
+ if (!normalized) {
30
+ throw new UsageError("GHOST_PACKAGE_DIR must not be empty");
31
+ }
32
+ if (isAbsolute(ghostDir) ||
33
+ normalized.startsWith("/") ||
34
+ /^[A-Za-z]:/.test(normalized)) {
35
+ throw new UsageError("GHOST_PACKAGE_DIR must be a relative directory path");
36
+ }
37
+ const segments = normalized.split("/");
38
+ if (segments.some((segment) => segment === "." || segment === ".." || segment === "")) {
39
+ throw new UsageError("GHOST_PACKAGE_DIR must not contain '.', '..', or empty path segments");
40
+ }
41
+ return normalized;
42
+ }
43
+ export const GHOST_PACKAGE_DIR_ENV = "GHOST_PACKAGE_DIR";
44
+ export function resolveGhostDirDefault(explicitGhostDir, env = process.env) {
45
+ return normalizeGhostDir(typeof explicitGhostDir === "string"
46
+ ? explicitGhostDir
47
+ : env[GHOST_PACKAGE_DIR_ENV]);
48
+ }
49
+ //# sourceMappingURL=package-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-paths.js","sourceRoot":"","sources":["../../src/scan/package-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;;GAIG;AAEH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACtD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CACpC,KAAK,EACL,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChC;YACE,GAAG;SACJ,CACF,CAAC;QACF,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAQ,GAAG,uBAAuB;IAClE,MAAM,UAAU,GAAG,QAAQ;SACxB,IAAI,EAAE;SACN,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvB,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,UAAU,CAAC,qCAAqC,CAAC,CAAC;IAC9D,CAAC;IACD,IACE,UAAU,CAAC,QAAQ,CAAC;QACpB,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC;QAC1B,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAC7B,CAAC;QACD,MAAM,IAAI,UAAU,CAAC,qDAAqD,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,IACE,QAAQ,CAAC,IAAI,CACX,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,EAAE,CACnE,EACD,CAAC;QACD,MAAM,IAAI,UAAU,CAClB,sEAAsE,CACvE,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAAC;AAEzD,MAAM,UAAU,sBAAsB,CACpC,gBAA0B,EAC1B,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,iBAAiB,CACtB,OAAO,gBAAgB,KAAK,QAAQ;QAClC,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAC/B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { GhostInitTemplate, TemplateFile } from "./templates.js";
2
+ interface SteeringTemplateDeps {
3
+ manifestFile(): TemplateFile;
4
+ gitignoreFile(): TemplateFile;
5
+ }
6
+ export declare function createSteeringTemplate({ manifestFile, gitignoreFile, }: SteeringTemplateDeps): GhostInitTemplate;
7
+ export {};
8
+ //# sourceMappingURL=steering-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steering-template.d.ts","sourceRoot":"","sources":["../../src/scan/steering-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEtE,UAAU,oBAAoB;IAC5B,YAAY,IAAI,YAAY,CAAC;IAC7B,aAAa,IAAI,YAAY,CAAC;CAC/B;AAED,wBAAgB,sBAAsB,CAAC,EACrC,YAAY,EACZ,aAAa,GACd,EAAE,oBAAoB,GAAG,iBAAiB,CAE1C"}
@@ -0,0 +1,266 @@
1
+ export function createSteeringTemplate({ manifestFile, gitignoreFile, }) {
2
+ return STEERING_TEMPLATE_FACTORY(manifestFile, gitignoreFile);
3
+ }
4
+ /**
5
+ * Steering starter: named truths for pre-generation steering. The extra kinds
6
+ * are vocabulary only: no schema or selection behavior changes.
7
+ */
8
+ function STEERING_TEMPLATE_FACTORY(manifestFile, gitignoreFile) {
9
+ return {
10
+ name: "steering",
11
+ description: "Steering starter: stance, patterns, exemplars, materials.",
12
+ files() {
13
+ return [
14
+ manifestFile(),
15
+ gitignoreFile(),
16
+ {
17
+ relativePath: "glossary.md",
18
+ content: `---
19
+ kinds:
20
+ - name: principle
21
+ - name: condition
22
+ - name: pattern
23
+ - name: exemplar
24
+ - name: anti-goal
25
+ posture: guard
26
+ - name: asset
27
+ - name: decision
28
+ - name: concept
29
+ # - { name: provocation, posture: wild, purpose: a deliberate provocation past the fingerprint — surfaced only on request }
30
+ ---
31
+
32
+ # principle
33
+
34
+ Durable stance, tradeoff, or invariant. Patterns may narrow principles, never loosen them.
35
+
36
+ # condition
37
+
38
+ Situational truth. Use only when the stated situation holds.
39
+
40
+ # pattern
41
+
42
+ Reusable composition. State what is bound, what is open, and when it applies.
43
+
44
+ # exemplar
45
+
46
+ Concrete reference for form, rhythm, quality, code shape, voice, or behavior. Say what to copy and not copy.
47
+
48
+ # anti-goal
49
+
50
+ Review-critical guard posture. State not-X-instead-Y: the rejected default, the positive replacement, and how to recognize the switch.
51
+
52
+ # asset
53
+
54
+ Material truth about concrete assets, tokens, components, type, motion, imagery, code, or files. \`materials\` locates; prose explains.
55
+
56
+ # decision
57
+
58
+ Worked tradeoff trace: what was chosen, what was rejected, and why.
59
+
60
+ # concept
61
+
62
+ Scoped creative direction for a specific output; not permanent brand law.
63
+ `,
64
+ },
65
+ {
66
+ relativePath: "index.md",
67
+ content: `---
68
+ description: Always read first — the steering front door, non-negotiables, and silence posture.
69
+ ---
70
+
71
+ This fingerprint is demo content for **Morrow Ledger**, a small bookkeeping product for independent studios. It steers agent-generated product and brand work; it is not a component API or complete archive.
72
+
73
+ ## Before you trust this fingerprint
74
+
75
+ Everything in this starter package is demo content. It is intentionally opinionated so you can see the shape of useful steering: hard truths, refusal lines, material locators, patterns, exemplars, and tradeoff traces. Keep any structure that helps, but replace the claims, paths, examples, and decisions with real product truth before using this fingerprint to guide generation.
76
+
77
+ ## Non-negotiables
78
+
79
+ The lines below are demo non-negotiables for inspiration and guidance. Replace them with your real hard truths:
80
+
81
+ - Morrow Ledger sounds like a careful bookkeeper, not a growth coach.
82
+ - Use slate ink, ledger green, and quiet amber before inventing new color.
83
+ - Preserve the composition floor in \`principle.composition\`.
84
+ - Avoid the generic generated defaults named in \`anti-goal.*\`.
85
+ - Label provisional reasoning when this fingerprint is silent.
86
+
87
+ ## How to read the corpus
88
+
89
+ \`principle.*\` gives stance and hard floor. \`pattern.*\` gives bound/open structure. \`exemplar.*\` shows form and quality. \`anti-goal.*\` names likely wrong outputs. \`asset.*\` points to materials. \`decision.*\` explains tradeoffs. \`concept.*\` is scoped direction, not law. The starter nodes are teaching examples, not defaults Ghost believes about your brand.
90
+
91
+ ## Silence posture
92
+
93
+ When this fingerprint is silent, proceed provisionally from local conventions only when safe. Ask before brand-defining, irreversible, legal, privacy-sensitive, or high-risk choices.
94
+ `,
95
+ },
96
+ {
97
+ relativePath: "principle.stance.md",
98
+ content: `---
99
+ description: Core stance and tradeoffs — gather when a task needs brand decision-making beyond exact materials.
100
+ ---
101
+
102
+ Morrow Ledger helps independent studios know what changed in their money without making finance feel like a performance dashboard.
103
+
104
+ Forced choices:
105
+
106
+ - **Clarity beats momentum.** When a line could sound exciting or precise, choose precise. Write "3 invoices are 14+ days late" instead of "Cash flow needs attention."
107
+ - **Evidence beats reassurance.** Pair every claim with the number, date, file, or account behind it. Never say "all set" unless the surface shows what was checked.
108
+ - **Calm beats clever.** Use plain verbs: sent, due, matched, missing, paid. Avoid pep-talk verbs: crush, unlock, supercharge.
109
+ - **Small business time is scarce.** Lead with the next accountable action and its cost: "Review 2 unmatched deposits — about 4 minutes."
110
+
111
+ The brand earns trust by making the boring truth easy to act on. If the work feels motivational, it is drifting.
112
+
113
+ `,
114
+ },
115
+ {
116
+ relativePath: "principle.composition.md",
117
+ content: `---
118
+ description: Composition floor — hard layout invariants that hold whether or not a pattern matches the ask.
119
+ ---
120
+
121
+ These demo invariants show the kind of floor that steers generation. Replace them with real hard lines that apply to every generated surface unless a narrower condition explicitly says otherwise. Patterns narrow them; nothing loosens them.
122
+
123
+ For Morrow Ledger:
124
+
125
+ - **One ledger fact leads.** Every surface opens with one factual sentence or number. If two facts compete, choose the one that changes what the user does next.
126
+ - **Maximum three figures above the fold.** A figure is any amount, count, date, or percentage. If there are four, demote one into details instead of shrinking type.
127
+ - **Actions are accountable verbs.** Primary actions begin with Review, Match, Send, Export, or Mark. Never use generic "Continue" when the action can be named.
128
+ - **Whitespace before boxes.** Separate sections with 24px vertical space first, a 1px #D8DED8 rule second, and a card only when the content has its own state.
129
+
130
+ Token sketch for demos:
131
+
132
+ \`\`\`css
133
+ :root {
134
+ --morrow-ink: #17201b;
135
+ --morrow-ledger: #2f6f4f;
136
+ --morrow-amber: #b7791f;
137
+ --morrow-paper: #f7f5ef;
138
+ }
139
+ \`\`\`
140
+
141
+ `,
142
+ },
143
+ {
144
+ relativePath: "anti-goal.generic-generated-output.md",
145
+ content: `---
146
+ description: The generic generated output this fingerprint rejects.
147
+ ---
148
+
149
+ This is demo anti-goal content. Replace it with the defaults this brand actually refuses.
150
+
151
+ Not: a rounded-card SaaS dashboard full of gradients, celebratory deltas, and "You're crushing it" copy.
152
+
153
+ Instead: a ledger-first surface with one leading fact, muted paper background, accountable next action, and evidence close to the claim.
154
+
155
+ Concrete replacements:
156
+
157
+ - Not "Revenue is up 24% 🎉" — instead "July receipts are $4,820 higher than June; 2 invoices explain most of the change."
158
+ - Not a decorative blob or fake chart preview — instead a compact list of the source transactions or invoices.
159
+ - Not "Oops, something went wrong" — instead "We could not match deposit 1042. Choose the invoice or mark it as owner contribution."
160
+
161
+ A technically correct output can still be off-brand if any product could ship it. This guard is review-critical because generic finance optimism is the most likely model default.
162
+ `,
163
+ },
164
+ {
165
+ relativePath: "pattern.status-with-next-step.md",
166
+ content: `---
167
+ description: Status of an ongoing thing plus the single next step — use when the task asks where something stands or what happens next.
168
+ ---
169
+
170
+ This is a demo pattern for inspiration and guidance. Replace it with a real reusable pattern from your product.
171
+
172
+ Applies when the surface explains the state of something in flight: invoice payment, bank sync, export, tax packet, or reconciliation.
173
+
174
+ **Bound (do not redecide):**
175
+
176
+ - Status line first, exactly one sentence, no more than 11 words.
177
+ - One evidence row with amount, date, and source.
178
+ - One primary next step last, beginning with an accountable verb.
179
+
180
+ **Open (within limits):**
181
+
182
+ - Evidence may be a table row or two-item list.
183
+ - Use amber only for a user action needed within 7 days.
184
+
185
+ ## Skeleton
186
+
187
+ \`\`\`tsx
188
+ <section className="morrow-status">
189
+ <p className="eyebrow">{scope}</p>
190
+ <h1>{statusSentence}</h1>
191
+ <p>{meaningSentence}</p>
192
+ <dl>{amountDateSource}</dl>
193
+ <button>{accountableNextStep}</button>
194
+ </section>
195
+ \`\`\`
196
+
197
+ `,
198
+ },
199
+ {
200
+ relativePath: "exemplar.annotated-reference.md",
201
+ content: `---
202
+ description: Annotated reference — replace with a sample that shows form, rhythm, quality, voice, or code shape.
203
+ materials:
204
+ - src/components/status-card.tsx
205
+ ---
206
+
207
+ This is demo exemplar content. Replace \`src/components/status-card.tsx\` with a real screenshot, file, URL, or implementation path.
208
+
209
+ Normative for: density, evidence placement, accountable action language.
210
+
211
+ Annotated reference:
212
+
213
+ \`\`\`tsx
214
+ <aside className="rounded-none border-l border-[#D8DED8] bg-[#F7F5EF] p-6 text-[#17201B]">
215
+ <p className="text-xs uppercase tracking-[0.14em] text-[#2F6F4F]">Bank sync</p>
216
+ <h2 className="mt-3 text-2xl font-semibold">3 deposits need matching</h2>
217
+ <p className="mt-2 max-w-prose text-sm">They total $8,410 and arrived between Jul 12 and Jul 15.</p>
218
+ <button className="mt-6 border border-[#17201B] px-4 py-2 text-sm">Match deposits — about 4 minutes</button>
219
+ </aside>
220
+ \`\`\`
221
+
222
+ Copy the square edge, measured evidence, and action cost. Do not copy the exact amounts or dates.
223
+ `,
224
+ },
225
+ {
226
+ relativePath: "asset.materials.md",
227
+ content: `---
228
+ description: Concrete materials the agent should inspect before inventing visual language, components, type, motion, or assets.
229
+ materials:
230
+ - src/styles/tokens.css
231
+ - src/components/**
232
+ - public/brand/**
233
+ ---
234
+
235
+ This is demo material inventory. Replace the paths with real tokens, components, SVGs, motion specs, images, or implementations.
236
+
237
+ Morrow Ledger's starter materials should resolve to real files in your repo before use:
238
+
239
+ - \`src/styles/tokens.css\` should define the ink, ledger, amber, paper, and rule colors.
240
+ - \`src/components/**\` should include the production Button, InlineAlert, and DataRow components.
241
+ - \`public/brand/**\` should include the wordmark and any blessed product screenshots.
242
+
243
+ Use this node to locate real materials. \`materials\` points to concrete files; this prose explains what they mean. Do not duplicate API docs unless the API itself is the brand truth.
244
+ `,
245
+ },
246
+ {
247
+ relativePath: "decision.tradeoff.md",
248
+ content: `---
249
+ description: Worked tradeoff — replace with a decision where the brand chose between plausible options.
250
+ ---
251
+
252
+ This is demo decision content. Replace it with a real tradeoff that helps an agent decide between plausible good answers.
253
+
254
+ Morrow Ledger tradeoff: we chose visible evidence over shorter surfaces.
255
+
256
+ - Option A: a compact success banner, "Bank sync complete." It was calm and fast, but it hid what changed.
257
+ - Option B: a slightly taller status block, "Bank sync complete; 14 transactions imported since Jul 12." It costs one extra line but gives the user a fact to trust.
258
+ - Decision: choose Option B whenever the action touches money, taxes, invoices, exports, or bank data.
259
+ - Reverses when: the evidence would expose sensitive third-party details in a shared view. Then show the count only and link to details.
260
+ `,
261
+ },
262
+ ];
263
+ },
264
+ };
265
+ }
266
+ //# sourceMappingURL=steering-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steering-template.js","sourceRoot":"","sources":["../../src/scan/steering-template.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,sBAAsB,CAAC,EACrC,YAAY,EACZ,aAAa,GACQ;IACrB,OAAO,yBAAyB,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,SAAS,yBAAyB,CAChC,YAAgC,EAChC,aAAiC;IAEjC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,2DAA2D;QACxE,KAAK;YACH,OAAO;gBACL,YAAY,EAAE;gBACd,aAAa,EAAE;gBACf;oBACE,YAAY,EAAE,aAAa;oBAC3B,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6ClB;iBACQ;gBACD;oBACE,YAAY,EAAE,UAAU;oBACxB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BlB;iBACQ;gBACD;oBACE,YAAY,EAAE,qBAAqB;oBACnC,OAAO,EAAE;;;;;;;;;;;;;;;CAelB;iBACQ;gBACD;oBACE,YAAY,EAAE,0BAA0B;oBACxC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;CAwBlB;iBACQ;gBACD;oBACE,YAAY,EAAE,uCAAuC;oBACrD,OAAO,EAAE;;;;;;;;;;;;;;;;;CAiBlB;iBACQ;gBACD;oBACE,YAAY,EAAE,kCAAkC;oBAChD,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BlB;iBACQ;gBACD;oBACE,YAAY,EAAE,iCAAiC;oBAC/C,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsBlB;iBACQ;gBACD;oBACE,YAAY,EAAE,oBAAoB;oBAClC,OAAO,EAAE;;;;;;;;;;;;;;;;;CAiBlB;iBACQ;gBACD;oBACE,YAAY,EAAE,sBAAsB;oBACpC,OAAO,EAAE;;;;;;;;;;;;CAYlB;iBACQ;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface TarballEntryInput {
2
+ /** Archive path, using forward slashes and no leading slash. */
3
+ path: string;
4
+ data: Buffer | string;
5
+ mtime?: Date;
6
+ mode?: number;
7
+ }
8
+ export interface CreateDirectoryTarballOptions {
9
+ rootDir: string;
10
+ outFile: string;
11
+ extraEntries?: TarballEntryInput[];
12
+ exclude?: (relativePath: string) => boolean;
13
+ }
14
+ /**
15
+ * Write a dependency-free `.tgz` archive for a Ghost package directory.
16
+ *
17
+ * This intentionally implements only the portable subset Ghost needs: ustar
18
+ * regular-file entries, deterministic path ordering, no symlink traversal.
19
+ */
20
+ export declare function writeDirectoryTarball(options: CreateDirectoryTarballOptions): Promise<void>;
21
+ export declare function createTarArchive(entries: TarballEntryInput[]): Buffer;
22
+ export declare function defaultArchiveName(id: string): string;
23
+ //# sourceMappingURL=tarball.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tarball.d.ts","sourceRoot":"","sources":["../../src/scan/tarball.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;CAC7C;AAYD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAyBrE;AA+HD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAErD"}