@klarocards/cli 1.0.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 (166) hide show
  1. package/README.md +125 -0
  2. package/dist/commands/cheatsheet.d.ts +3 -0
  3. package/dist/commands/cheatsheet.d.ts.map +1 -0
  4. package/dist/commands/cheatsheet.js +80 -0
  5. package/dist/commands/cheatsheet.js.map +1 -0
  6. package/dist/commands/completion.d.ts +3 -0
  7. package/dist/commands/completion.d.ts.map +1 -0
  8. package/dist/commands/completion.js +191 -0
  9. package/dist/commands/completion.js.map +1 -0
  10. package/dist/commands/config.d.ts +3 -0
  11. package/dist/commands/config.d.ts.map +1 -0
  12. package/dist/commands/config.js +77 -0
  13. package/dist/commands/config.js.map +1 -0
  14. package/dist/commands/create.d.ts +3 -0
  15. package/dist/commands/create.d.ts.map +1 -0
  16. package/dist/commands/create.js +121 -0
  17. package/dist/commands/create.js.map +1 -0
  18. package/dist/commands/del.d.ts +3 -0
  19. package/dist/commands/del.d.ts.map +1 -0
  20. package/dist/commands/del.js +49 -0
  21. package/dist/commands/del.js.map +1 -0
  22. package/dist/commands/describe.d.ts +3 -0
  23. package/dist/commands/describe.d.ts.map +1 -0
  24. package/dist/commands/describe.js +105 -0
  25. package/dist/commands/describe.js.map +1 -0
  26. package/dist/commands/edit.d.ts +3 -0
  27. package/dist/commands/edit.d.ts.map +1 -0
  28. package/dist/commands/edit.js +91 -0
  29. package/dist/commands/edit.js.map +1 -0
  30. package/dist/commands/fetch.d.ts +3 -0
  31. package/dist/commands/fetch.d.ts.map +1 -0
  32. package/dist/commands/fetch.js +129 -0
  33. package/dist/commands/fetch.js.map +1 -0
  34. package/dist/commands/init.d.ts +3 -0
  35. package/dist/commands/init.d.ts.map +1 -0
  36. package/dist/commands/init.js +122 -0
  37. package/dist/commands/init.js.map +1 -0
  38. package/dist/commands/login.d.ts +7 -0
  39. package/dist/commands/login.d.ts.map +1 -0
  40. package/dist/commands/login.js +101 -0
  41. package/dist/commands/login.js.map +1 -0
  42. package/dist/commands/logout.d.ts +3 -0
  43. package/dist/commands/logout.d.ts.map +1 -0
  44. package/dist/commands/logout.js +34 -0
  45. package/dist/commands/logout.js.map +1 -0
  46. package/dist/commands/ls.d.ts +3 -0
  47. package/dist/commands/ls.d.ts.map +1 -0
  48. package/dist/commands/ls.js +174 -0
  49. package/dist/commands/ls.js.map +1 -0
  50. package/dist/commands/read.d.ts +3 -0
  51. package/dist/commands/read.d.ts.map +1 -0
  52. package/dist/commands/read.js +64 -0
  53. package/dist/commands/read.js.map +1 -0
  54. package/dist/commands/set.d.ts +3 -0
  55. package/dist/commands/set.d.ts.map +1 -0
  56. package/dist/commands/set.js +61 -0
  57. package/dist/commands/set.js.map +1 -0
  58. package/dist/commands/sync.d.ts +3 -0
  59. package/dist/commands/sync.d.ts.map +1 -0
  60. package/dist/commands/sync.js +157 -0
  61. package/dist/commands/sync.js.map +1 -0
  62. package/dist/commands/update.d.ts +4 -0
  63. package/dist/commands/update.d.ts.map +1 -0
  64. package/dist/commands/update.js +68 -0
  65. package/dist/commands/update.js.map +1 -0
  66. package/dist/commands/use.d.ts +3 -0
  67. package/dist/commands/use.d.ts.map +1 -0
  68. package/dist/commands/use.js +29 -0
  69. package/dist/commands/use.js.map +1 -0
  70. package/dist/commands/whoami.d.ts +3 -0
  71. package/dist/commands/whoami.d.ts.map +1 -0
  72. package/dist/commands/whoami.js +30 -0
  73. package/dist/commands/whoami.js.map +1 -0
  74. package/dist/completions/bash.d.ts +2 -0
  75. package/dist/completions/bash.d.ts.map +1 -0
  76. package/dist/completions/bash.js +134 -0
  77. package/dist/completions/bash.js.map +1 -0
  78. package/dist/completions/commands.d.ts +18 -0
  79. package/dist/completions/commands.d.ts.map +1 -0
  80. package/dist/completions/commands.js +173 -0
  81. package/dist/completions/commands.js.map +1 -0
  82. package/dist/completions/fish.d.ts +2 -0
  83. package/dist/completions/fish.d.ts.map +1 -0
  84. package/dist/completions/fish.js +84 -0
  85. package/dist/completions/fish.js.map +1 -0
  86. package/dist/completions/zsh.d.ts +2 -0
  87. package/dist/completions/zsh.d.ts.map +1 -0
  88. package/dist/completions/zsh.js +113 -0
  89. package/dist/completions/zsh.js.map +1 -0
  90. package/dist/index.d.ts +3 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +158 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/lib/api.d.ts +34 -0
  95. package/dist/lib/api.d.ts.map +1 -0
  96. package/dist/lib/api.js +146 -0
  97. package/dist/lib/api.js.map +1 -0
  98. package/dist/lib/completion-cache.d.ts +34 -0
  99. package/dist/lib/completion-cache.d.ts.map +1 -0
  100. package/dist/lib/completion-cache.js +99 -0
  101. package/dist/lib/completion-cache.js.map +1 -0
  102. package/dist/lib/config.d.ts +12 -0
  103. package/dist/lib/config.d.ts.map +1 -0
  104. package/dist/lib/config.js +111 -0
  105. package/dist/lib/config.js.map +1 -0
  106. package/dist/lib/connector.d.ts +17 -0
  107. package/dist/lib/connector.d.ts.map +1 -0
  108. package/dist/lib/connector.js +2 -0
  109. package/dist/lib/connector.js.map +1 -0
  110. package/dist/lib/defaults.d.ts +9 -0
  111. package/dist/lib/defaults.d.ts.map +1 -0
  112. package/dist/lib/defaults.js +58 -0
  113. package/dist/lib/defaults.js.map +1 -0
  114. package/dist/lib/trace.d.ts +4 -0
  115. package/dist/lib/trace.d.ts.map +1 -0
  116. package/dist/lib/trace.js +13 -0
  117. package/dist/lib/trace.js.map +1 -0
  118. package/dist/lib/types.d.ts +70 -0
  119. package/dist/lib/types.d.ts.map +1 -0
  120. package/dist/lib/types.js +2 -0
  121. package/dist/lib/types.js.map +1 -0
  122. package/dist/utils/content.d.ts +26 -0
  123. package/dist/utils/content.d.ts.map +1 -0
  124. package/dist/utils/content.js +52 -0
  125. package/dist/utils/content.js.map +1 -0
  126. package/dist/utils/dimensions.d.ts +17 -0
  127. package/dist/utils/dimensions.d.ts.map +1 -0
  128. package/dist/utils/dimensions.js +41 -0
  129. package/dist/utils/dimensions.js.map +1 -0
  130. package/dist/utils/editor.d.ts +14 -0
  131. package/dist/utils/editor.d.ts.map +1 -0
  132. package/dist/utils/editor.js +56 -0
  133. package/dist/utils/editor.js.map +1 -0
  134. package/dist/utils/format.d.ts +17 -0
  135. package/dist/utils/format.d.ts.map +1 -0
  136. package/dist/utils/format.js +27 -0
  137. package/dist/utils/format.js.map +1 -0
  138. package/dist/utils/markdown.d.ts +24 -0
  139. package/dist/utils/markdown.d.ts.map +1 -0
  140. package/dist/utils/markdown.js +50 -0
  141. package/dist/utils/markdown.js.map +1 -0
  142. package/dist/utils/objects.d.ts +12 -0
  143. package/dist/utils/objects.d.ts.map +1 -0
  144. package/dist/utils/objects.js +31 -0
  145. package/dist/utils/objects.js.map +1 -0
  146. package/dist/utils/slugify.d.ts +10 -0
  147. package/dist/utils/slugify.d.ts.map +1 -0
  148. package/dist/utils/slugify.js +18 -0
  149. package/dist/utils/slugify.js.map +1 -0
  150. package/dist/utils/story-editor.d.ts +15 -0
  151. package/dist/utils/story-editor.d.ts.map +1 -0
  152. package/dist/utils/story-editor.js +43 -0
  153. package/dist/utils/story-editor.js.map +1 -0
  154. package/dist/utils/story-markdown.d.ts +36 -0
  155. package/dist/utils/story-markdown.d.ts.map +1 -0
  156. package/dist/utils/story-markdown.js +114 -0
  157. package/dist/utils/story-markdown.js.map +1 -0
  158. package/dist/utils/table.d.ts +18 -0
  159. package/dist/utils/table.d.ts.map +1 -0
  160. package/dist/utils/table.js +57 -0
  161. package/dist/utils/table.js.map +1 -0
  162. package/dist/utils/validation.d.ts +8 -0
  163. package/dist/utils/validation.d.ts.map +1 -0
  164. package/dist/utils/validation.js +17 -0
  165. package/dist/utils/validation.js.map +1 -0
  166. package/package.json +45 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Get the content directory path for a project.
3
+ */
4
+ export declare function getContentDir(project: string): string;
5
+ /**
6
+ * Ensure the content directory exists, creating it if necessary.
7
+ * Returns the directory path.
8
+ */
9
+ export declare function ensureContentDir(project: string): string;
10
+ /**
11
+ * List all markdown files in the content directory for a project.
12
+ * Returns an array of filenames (not full paths).
13
+ */
14
+ export declare function listContentFiles(project: string): string[];
15
+ /**
16
+ * Extract the card identifier from a content filename.
17
+ * Filename format: {identifier}-{slugified-title}.md
18
+ * Returns null if the filename doesn't match the expected pattern.
19
+ */
20
+ export declare function extractIdentifierFromFilename(filename: string): number | null;
21
+ /**
22
+ * Build a content filename from identifier and title.
23
+ * Format: {identifier}-{slugified-title}.md
24
+ */
25
+ export declare function buildContentFilename(identifier: string | number, title: string): string;
26
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/utils/content.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM7E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvF"}
@@ -0,0 +1,52 @@
1
+ import { join } from 'node:path';
2
+ import { existsSync, mkdirSync, readdirSync } from 'node:fs';
3
+ import { getConfigDir } from '../lib/config.js';
4
+ import { slugify } from './slugify.js';
5
+ /**
6
+ * Get the content directory path for a project.
7
+ */
8
+ export function getContentDir(project) {
9
+ return join(getConfigDir(), 'content', project);
10
+ }
11
+ /**
12
+ * Ensure the content directory exists, creating it if necessary.
13
+ * Returns the directory path.
14
+ */
15
+ export function ensureContentDir(project) {
16
+ const dir = getContentDir(project);
17
+ if (!existsSync(dir)) {
18
+ mkdirSync(dir, { recursive: true });
19
+ }
20
+ return dir;
21
+ }
22
+ /**
23
+ * List all markdown files in the content directory for a project.
24
+ * Returns an array of filenames (not full paths).
25
+ */
26
+ export function listContentFiles(project) {
27
+ const dir = getContentDir(project);
28
+ if (!existsSync(dir)) {
29
+ return [];
30
+ }
31
+ return readdirSync(dir).filter(f => f.endsWith('.md'));
32
+ }
33
+ /**
34
+ * Extract the card identifier from a content filename.
35
+ * Filename format: {identifier}-{slugified-title}.md
36
+ * Returns null if the filename doesn't match the expected pattern.
37
+ */
38
+ export function extractIdentifierFromFilename(filename) {
39
+ const match = filename.match(/^(\d+)-.*\.md$/);
40
+ if (!match) {
41
+ return null;
42
+ }
43
+ return parseInt(match[1], 10);
44
+ }
45
+ /**
46
+ * Build a content filename from identifier and title.
47
+ * Format: {identifier}-{slugified-title}.md
48
+ */
49
+ export function buildContentFilename(identifier, title) {
50
+ return `${identifier}-${slugify(title)}.md`;
51
+ }
52
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/utils/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAAgB;IAC5D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAA2B,EAAE,KAAa;IAC7E,OAAO,GAAG,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Split command line args into regular args and key=value dimensions.
3
+ * @param args - Array of command line arguments
4
+ * @returns Object with regularArgs and dimensionArgs separated
5
+ */
6
+ export declare function splitArgs(args: string[]): {
7
+ regularArgs: string[];
8
+ dimensionArgs: string[];
9
+ };
10
+ /**
11
+ * Parse dimension arguments from command line (key=value format).
12
+ * @param dimensionArgs - Array of dimension strings in "key=value" format
13
+ * @returns Object mapping dimension keys to values
14
+ * @throws Error if any dimension is not in "key=value" format
15
+ */
16
+ export declare function parseDimensions(dimensionArgs?: string[]): Record<string, string>;
17
+ //# sourceMappingURL=dimensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dimensions.d.ts","sourceRoot":"","sources":["../../src/utils/dimensions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,CAa5F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkBhF"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Split command line args into regular args and key=value dimensions.
3
+ * @param args - Array of command line arguments
4
+ * @returns Object with regularArgs and dimensionArgs separated
5
+ */
6
+ export function splitArgs(args) {
7
+ const regularArgs = [];
8
+ const dimensionArgs = [];
9
+ for (const arg of args) {
10
+ if (arg.includes('=')) {
11
+ dimensionArgs.push(arg);
12
+ }
13
+ else {
14
+ regularArgs.push(arg);
15
+ }
16
+ }
17
+ return { regularArgs, dimensionArgs };
18
+ }
19
+ /**
20
+ * Parse dimension arguments from command line (key=value format).
21
+ * @param dimensionArgs - Array of dimension strings in "key=value" format
22
+ * @returns Object mapping dimension keys to values
23
+ * @throws Error if any dimension is not in "key=value" format
24
+ */
25
+ export function parseDimensions(dimensionArgs) {
26
+ const dimensions = {};
27
+ if (!dimensionArgs) {
28
+ return dimensions;
29
+ }
30
+ for (const arg of dimensionArgs) {
31
+ const eqIndex = arg.indexOf('=');
32
+ if (eqIndex === -1) {
33
+ throw new Error(`Invalid dimension format: "${arg}". Expected format: key=value`);
34
+ }
35
+ const key = arg.substring(0, eqIndex);
36
+ const value = arg.substring(eqIndex + 1);
37
+ dimensions[key] = value;
38
+ }
39
+ return dimensions;
40
+ }
41
+ //# sourceMappingURL=dimensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dimensions.js","sourceRoot":"","sources":["../../src/utils/dimensions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,aAAwB;IACtD,MAAM,UAAU,GAA2B,EAAE,CAAC;IAE9C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,+BAA+B,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QACzC,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Get the user's preferred editor from environment variables.
3
+ * Follows the same convention as git: $VISUAL, then $EDITOR, then 'vi'.
4
+ */
5
+ export declare function getEditor(): string;
6
+ /**
7
+ * Open content in the user's editor and return the edited content.
8
+ *
9
+ * @param content - Initial content to edit
10
+ * @param filename - Optional filename hint for the temp file (for syntax highlighting)
11
+ * @returns The edited content, or null if the editor exited with an error
12
+ */
13
+ export declare function openInEditor(content: string, filename?: string): string | null;
14
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/utils/editor.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,MAAM,GAAG,IAAI,CAuCjF"}
@@ -0,0 +1,56 @@
1
+ import { spawnSync } from 'child_process';
2
+ import { writeFileSync, readFileSync, unlinkSync } from 'fs';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ /**
6
+ * Get the user's preferred editor from environment variables.
7
+ * Follows the same convention as git: $VISUAL, then $EDITOR, then 'vi'.
8
+ */
9
+ export function getEditor() {
10
+ return process.env.VISUAL || process.env.EDITOR || 'vi';
11
+ }
12
+ const MAX_FILENAME_LENGTH = 100;
13
+ /**
14
+ * Open content in the user's editor and return the edited content.
15
+ *
16
+ * @param content - Initial content to edit
17
+ * @param filename - Optional filename hint for the temp file (for syntax highlighting)
18
+ * @returns The edited content, or null if the editor exited with an error
19
+ */
20
+ export function openInEditor(content, filename = 'edit.md') {
21
+ // Truncate filename to avoid ENAMETOOLONG errors
22
+ const safeName = filename.length > MAX_FILENAME_LENGTH
23
+ ? filename.slice(0, MAX_FILENAME_LENGTH - 3) + '.md'
24
+ : filename;
25
+ const tempPath = join(tmpdir(), `klaro-${Date.now()}-${safeName}`);
26
+ try {
27
+ // Write content to temp file
28
+ writeFileSync(tempPath, content, 'utf-8');
29
+ // Get editor command
30
+ const editor = getEditor();
31
+ // Spawn editor and wait for it to close
32
+ // Parse editor command to handle cases like "code --wait"
33
+ const parts = editor.split(/\s+/);
34
+ const cmd = parts[0];
35
+ const args = [...parts.slice(1), tempPath];
36
+ const result = spawnSync(cmd, args, {
37
+ stdio: 'inherit',
38
+ });
39
+ if (result.status !== 0) {
40
+ return null;
41
+ }
42
+ // Read edited content
43
+ const edited = readFileSync(tempPath, 'utf-8');
44
+ return edited;
45
+ }
46
+ finally {
47
+ // Clean up temp file
48
+ try {
49
+ unlinkSync(tempPath);
50
+ }
51
+ catch {
52
+ // Ignore cleanup errors
53
+ }
54
+ }
55
+ }
56
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/utils/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B;;;GAGG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC;AAC1D,CAAC;AAED,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,QAAQ,GAAG,SAAS;IAChE,iDAAiD;IACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,mBAAmB;QACpD,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,GAAG,CAAC,CAAC,GAAG,KAAK;QACpD,CAAC,CAAC,QAAQ,CAAC;IACb,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAC;IAEnE,IAAI,CAAC;QACH,6BAA6B;QAC7B,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAE1C,qBAAqB;QACrB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAE3B,wCAAwC;QACxC,0DAA0D;QAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE;YAClC,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,sBAAsB;QACtB,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,qBAAqB;QACrB,IAAI,CAAC;YACH,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Truncate a string to a maximum length, adding ellipsis if truncated.
3
+ */
4
+ export declare function truncate(str: string, maxLength: number): string;
5
+ /**
6
+ * Format dimension values for display.
7
+ * Shows up to 6 IDs, with ellipsis if there are more.
8
+ * Filters out null IDs.
9
+ *
10
+ * @param values - Array of dimension values with id and optional label
11
+ * @returns Formatted string of IDs
12
+ */
13
+ export declare function formatDimensionValues(values: Array<{
14
+ id: number | null;
15
+ label?: string;
16
+ }> | undefined): string;
17
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,GAC/D,MAAM,CAOR"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Truncate a string to a maximum length, adding ellipsis if truncated.
3
+ */
4
+ export function truncate(str, maxLength) {
5
+ if (maxLength < 4)
6
+ return str.slice(0, maxLength);
7
+ if (str.length <= maxLength)
8
+ return str;
9
+ return str.slice(0, maxLength - 1) + '…';
10
+ }
11
+ /**
12
+ * Format dimension values for display.
13
+ * Shows up to 6 IDs, with ellipsis if there are more.
14
+ * Filters out null IDs.
15
+ *
16
+ * @param values - Array of dimension values with id and optional label
17
+ * @returns Formatted string of IDs
18
+ */
19
+ export function formatDimensionValues(values) {
20
+ if (!values || values.length === 0) {
21
+ return '';
22
+ }
23
+ const filtered = values.filter(v => v.id !== null);
24
+ const ids = filtered.slice(0, 6).map(v => v.id);
25
+ return filtered.length > 6 ? `${ids.join(', ')}, ...` : ids.join(', ');
26
+ }
27
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,SAAiB;IACrD,IAAI,SAAS,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAgE;IAEhE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAChD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Render markdown text with terminal formatting (colors, styles).
3
+ */
4
+ export declare function renderMarkdown(text: string): string;
5
+ /**
6
+ * Extract YAML frontmatter from markdown content.
7
+ *
8
+ * @param markdown - Markdown content that may contain frontmatter
9
+ * @returns Object with frontmatter (including delimiters) and content
10
+ */
11
+ export declare function extractFrontmatter(markdown: string): {
12
+ frontmatter: string;
13
+ content: string;
14
+ };
15
+ /**
16
+ * Render markdown with terminal formatting, preserving YAML frontmatter as-is.
17
+ * Frontmatter is not rendered as markdown but preserved verbatim.
18
+ *
19
+ * @param markdown - Markdown content that may contain frontmatter
20
+ * @param raw - If true, return markdown unchanged
21
+ * @returns Formatted string with frontmatter preserved
22
+ */
23
+ export declare function renderMarkdownWithFrontmatter(markdown: string, raw: boolean): string;
24
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAc7F;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAYpF"}
@@ -0,0 +1,50 @@
1
+ import { marked } from 'marked';
2
+ import { markedTerminal } from 'marked-terminal';
3
+ // Configure marked with terminal renderer
4
+ // Type assertion needed due to outdated @types/marked-terminal
5
+ marked.use(markedTerminal());
6
+ /**
7
+ * Render markdown text with terminal formatting (colors, styles).
8
+ */
9
+ export function renderMarkdown(text) {
10
+ return marked.parse(text);
11
+ }
12
+ /**
13
+ * Extract YAML frontmatter from markdown content.
14
+ *
15
+ * @param markdown - Markdown content that may contain frontmatter
16
+ * @returns Object with frontmatter (including delimiters) and content
17
+ */
18
+ export function extractFrontmatter(markdown) {
19
+ if (!markdown.startsWith('---')) {
20
+ return { frontmatter: '', content: markdown };
21
+ }
22
+ const endIndex = markdown.indexOf('---', 3);
23
+ if (endIndex === -1) {
24
+ return { frontmatter: '', content: markdown };
25
+ }
26
+ return {
27
+ frontmatter: markdown.slice(0, endIndex + 3),
28
+ content: markdown.slice(endIndex + 3).trim(),
29
+ };
30
+ }
31
+ /**
32
+ * Render markdown with terminal formatting, preserving YAML frontmatter as-is.
33
+ * Frontmatter is not rendered as markdown but preserved verbatim.
34
+ *
35
+ * @param markdown - Markdown content that may contain frontmatter
36
+ * @param raw - If true, return markdown unchanged
37
+ * @returns Formatted string with frontmatter preserved
38
+ */
39
+ export function renderMarkdownWithFrontmatter(markdown, raw) {
40
+ if (raw) {
41
+ return markdown;
42
+ }
43
+ const { frontmatter, content } = extractFrontmatter(markdown);
44
+ const renderedContent = renderMarkdown(content);
45
+ if (frontmatter) {
46
+ return frontmatter + '\n\n' + renderedContent;
47
+ }
48
+ return renderedContent;
49
+ }
50
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmB,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,0CAA0C;AAC1C,+DAA+D;AAC/D,MAAM,CAAC,GAAG,CAAC,cAAc,EAAgC,CAAC,CAAC;AAE3D;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAW,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAChD,CAAC;IAED,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC;QAC5C,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;KAC7C,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAAgB,EAAE,GAAY;IAC1E,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,WAAW,GAAG,MAAM,GAAG,eAAe,CAAC;IAChD,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Deep merge two objects recursively.
3
+ * Properties from source override properties in target.
4
+ * Nested objects are merged recursively.
5
+ * Arrays and non-object values are replaced, not merged.
6
+ *
7
+ * @param target - Base object to merge into
8
+ * @param source - Object with values to merge from
9
+ * @returns New merged object
10
+ */
11
+ export declare function deepMerge<T extends object>(target: T, source: Partial<T>): T;
12
+ //# sourceMappingURL=objects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../src/utils/objects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAuB5E"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Deep merge two objects recursively.
3
+ * Properties from source override properties in target.
4
+ * Nested objects are merged recursively.
5
+ * Arrays and non-object values are replaced, not merged.
6
+ *
7
+ * @param target - Base object to merge into
8
+ * @param source - Object with values to merge from
9
+ * @returns New merged object
10
+ */
11
+ export function deepMerge(target, source) {
12
+ const result = { ...target };
13
+ for (const key of Object.keys(source)) {
14
+ const sourceValue = source[key];
15
+ const targetValue = result[key];
16
+ if (sourceValue !== undefined &&
17
+ typeof sourceValue === 'object' &&
18
+ sourceValue !== null &&
19
+ !Array.isArray(sourceValue) &&
20
+ typeof targetValue === 'object' &&
21
+ targetValue !== null &&
22
+ !Array.isArray(targetValue)) {
23
+ result[key] = deepMerge(targetValue, sourceValue);
24
+ }
25
+ else if (sourceValue !== undefined) {
26
+ result[key] = sourceValue;
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ //# sourceMappingURL=objects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"objects.js","sourceRoot":"","sources":["../../src/utils/objects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAmB,MAAS,EAAE,MAAkB;IACvE,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAO,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAmB,EAAE,CAAC;QACxD,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,IACE,WAAW,KAAK,SAAS;YACzB,OAAO,WAAW,KAAK,QAAQ;YAC/B,WAAW,KAAK,IAAI;YACpB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;YAC3B,OAAO,WAAW,KAAK,QAAQ;YAC/B,WAAW,KAAK,IAAI;YACpB,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAC3B,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACrB,WAAqB,EACrB,WAAqB,CACR,CAAC;QAClB,CAAC;aAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,GAAG,WAAyB,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Convert a string to a URL-friendly slug.
3
+ * - Removes accents (normalizes to NFD and strips diacritics)
4
+ * - Converts to lowercase
5
+ * - Replaces spaces and special characters with dashes
6
+ * - Collapses multiple dashes
7
+ * - Trims leading/trailing dashes
8
+ */
9
+ export declare function slugify(text: string): string;
10
+ //# sourceMappingURL=slugify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../src/utils/slugify.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ5C"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Convert a string to a URL-friendly slug.
3
+ * - Removes accents (normalizes to NFD and strips diacritics)
4
+ * - Converts to lowercase
5
+ * - Replaces spaces and special characters with dashes
6
+ * - Collapses multiple dashes
7
+ * - Trims leading/trailing dashes
8
+ */
9
+ export function slugify(text) {
10
+ return text
11
+ .normalize('NFD') // Decompose accents (é -> e + ́)
12
+ .replace(/[\u0300-\u036f]/g, '') // Remove diacritics
13
+ .toLowerCase()
14
+ .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with dashes
15
+ .replace(/^-+|-+$/g, '') // Trim leading/trailing dashes
16
+ .replace(/-+/g, '-'); // Collapse multiple dashes
17
+ }
18
+ //# sourceMappingURL=slugify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify.js","sourceRoot":"","sources":["../../src/utils/slugify.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI;SACR,SAAS,CAAC,KAAK,CAAC,CAAoB,iCAAiC;SACrE,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAK,oBAAoB;SACxD,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAS,uCAAuC;SAC3E,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAa,+BAA+B;SACnE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAgB,2BAA2B;AACpE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Story, UpdateStoryInput } from '../lib/types.js';
2
+ export interface EditStoryResult {
3
+ changed: boolean;
4
+ update?: UpdateStoryInput;
5
+ error?: string;
6
+ }
7
+ /**
8
+ * Open a story in the editor and return the parsed changes.
9
+ *
10
+ * @param story - The story to edit
11
+ * @param dimensions - Optional dimensions to include in YAML frontmatter
12
+ * @returns Result object with changed flag, update data, or error
13
+ */
14
+ export declare function editStoryInEditor(story: Story, dimensions?: string[]): EditStoryResult;
15
+ //# sourceMappingURL=story-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story-editor.d.ts","sourceRoot":"","sources":["../../src/utils/story-editor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAK/D,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,eAAe,CAiCtF"}
@@ -0,0 +1,43 @@
1
+ import { formatStoryMarkdown, parseStoryMarkdown } from './story-markdown.js';
2
+ import { openInEditor } from './editor.js';
3
+ import { slugify } from './slugify.js';
4
+ /**
5
+ * Open a story in the editor and return the parsed changes.
6
+ *
7
+ * @param story - The story to edit
8
+ * @param dimensions - Optional dimensions to include in YAML frontmatter
9
+ * @returns Result object with changed flag, update data, or error
10
+ */
11
+ export function editStoryInEditor(story, dimensions) {
12
+ const markdown = formatStoryMarkdown(story, dimensions);
13
+ const filename = `${story.identifier}-${slugify(story.title)}.md`;
14
+ const edited = openInEditor(markdown, filename);
15
+ if (edited === null) {
16
+ return { changed: false, error: 'Editor exited with an error' };
17
+ }
18
+ if (edited.trim() === markdown.trim()) {
19
+ return { changed: false };
20
+ }
21
+ try {
22
+ const parsed = parseStoryMarkdown(edited);
23
+ const update = {
24
+ identifier: parseInt(story.identifier, 10),
25
+ title: parsed.title,
26
+ specification: parsed.specification ?? '',
27
+ };
28
+ // Add dimensions if present
29
+ if (parsed.dimensions) {
30
+ for (const [key, value] of Object.entries(parsed.dimensions)) {
31
+ if (typeof value === 'string' || typeof value === 'number') {
32
+ update[key] = value;
33
+ }
34
+ }
35
+ }
36
+ return { changed: true, update };
37
+ }
38
+ catch (error) {
39
+ const message = error instanceof Error ? error.message : 'Failed to parse edited content';
40
+ return { changed: false, error: message };
41
+ }
42
+ }
43
+ //# sourceMappingURL=story-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story-editor.js","sourceRoot":"","sources":["../../src/utils/story-editor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQvC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY,EAAE,UAAqB;IACnE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;IAClE,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEhD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC;IAClE,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAqB;YAC/B,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC;YAC1C,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;SAC1C,CAAC;QACF,4BAA4B;QAC5B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC3D,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAC;QAC1F,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC5C,CAAC;AACH,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { Story } from '../lib/types.js';
2
+ export interface ParsedStory {
3
+ title: string;
4
+ specification?: string;
5
+ dimensions?: Record<string, unknown>;
6
+ }
7
+ /**
8
+ * Format a story as markdown output.
9
+ *
10
+ * - toptitle: first line of the title
11
+ * - summary: remaining lines of the title (if any)
12
+ * - description: the specification field
13
+ * - dimensions: optional array of dimension names to include as YAML frontmatter
14
+ */
15
+ export declare function formatStoryMarkdown(story: Story, dimensions?: string[]): string;
16
+ /**
17
+ * Parse markdown back into story fields.
18
+ *
19
+ * Format expected:
20
+ * ```
21
+ * ---
22
+ * dimension: value
23
+ * ---
24
+ *
25
+ * # toptitle
26
+ *
27
+ * [summary - optional]
28
+ *
29
+ * [description - optional]
30
+ * ```
31
+ *
32
+ * If two content blocks exist (separated by blank line), first is summary, second is description.
33
+ * If only one content block exists, it's treated as description.
34
+ */
35
+ export declare function parseStoryMarkdown(markdown: string): ParsedStory;
36
+ //# sourceMappingURL=story-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story-markdown.d.ts","sourceRoot":"","sources":["../../src/utils/story-markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAwC/E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA4DhE"}