@crossworks/content-core 0.232.57 → 0.232.58

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossworks/content-core",
3
- "version": "0.232.57",
3
+ "version": "0.232.58",
4
4
  "description": "Browser-safe content logic — markdown, blocks, pages, tables, formulas — shared by the server and any client. Zero server deps by design: nothing here may reach @mantle/db, node-only APIs, or the network (the jackdaw-repo-split P0 boundary).",
5
5
  "exports": {
6
6
  "./markdown": "./src/markdown-to-doc.ts",
@@ -5,6 +5,7 @@ import {
5
5
  RECALL_BODY_CHAR_BUDGET,
6
6
  assignRecallSlugs,
7
7
  parseRecallDoc,
8
+ recallOptionsMarkdown,
8
9
  recallSlug,
9
10
  } from './recall-compile';
10
11
 
@@ -152,3 +153,33 @@ describe('audit regressions', () => {
152
153
  ]);
153
154
  });
154
155
  });
156
+
157
+ describe('recallOptionsMarkdown', () => {
158
+ const OPTIONS = [
159
+ { label: 'Fleet access', targetPageId: 'aaa-fleet', useWhen: 'use when logging into a box' },
160
+ { label: 'Architecture', targetPageId: 'bbb-arch', useWhen: 'use when asking why' },
161
+ ];
162
+
163
+ it('round-trips through markdownToDoc + parseRecallDoc unchanged', () => {
164
+ const md = `Body text.\n\n${recallOptionsMarkdown(OPTIONS)}`;
165
+ const parsed = parseRecallDoc(markdownToDoc(md));
166
+ expect(parsed.issues).toEqual([]);
167
+ expect(parsed.options).toEqual(OPTIONS);
168
+ expect(parsed.bodyMarkdown).toBe('Body text.');
169
+ });
170
+
171
+ it('emits nothing for an empty list (a node with no options has no section)', () => {
172
+ expect(recallOptionsMarkdown([])).toBe('');
173
+ });
174
+
175
+ it('normalizes whitespace and strips brackets that would break the link syntax', () => {
176
+ const md = `Body.\n\n${recallOptionsMarkdown([
177
+ { label: ' Fleet\n[access] ', targetPageId: ' aaa ', useWhen: 'use when\nlogging in' },
178
+ ])}`;
179
+ const parsed = parseRecallDoc(markdownToDoc(md));
180
+ expect(parsed.issues).toEqual([]);
181
+ expect(parsed.options).toEqual([
182
+ { label: 'Fleet access', targetPageId: 'aaa', useWhen: 'use when logging in' },
183
+ ]);
184
+ });
185
+ });
@@ -275,6 +275,25 @@ export function parseRecallDoc(
275
275
  return { bodyMarkdown, useWhen, options, issues };
276
276
  }
277
277
 
278
+ /**
279
+ * The ONE writer for a node's `## Options` section. Every author path — the
280
+ * owner UI's routing editor and the agent-side authoring tools — must emit
281
+ * options through this, so human-authored and agent-authored options are
282
+ * byte-identical and always round-trip through `parseRecallDoc`. Compose a
283
+ * full body as `bodyMarkdown + '\n\n' + recallOptionsMarkdown(options)`.
284
+ */
285
+ export function recallOptionsMarkdown(
286
+ options: { label: string; targetPageId: string; useWhen: string }[],
287
+ ): string {
288
+ if (options.length === 0) return '';
289
+ const line = (v: string) => v.replace(/\s+/g, ' ').trim();
290
+ const items = options.map((o) => {
291
+ const label = line(o.label).replace(/[[\]]/g, '') || 'Untitled';
292
+ return `- [${label}](page:${o.targetPageId.trim()}) — ${line(o.useWhen)}`;
293
+ });
294
+ return `## Options\n\n${items.join('\n')}\n`;
295
+ }
296
+
278
297
  /** Kebab-case a title into a stable slug ('Fleet, access & MCP' → 'fleet-access-mcp'). */
279
298
  export function recallSlug(title: string): string {
280
299
  const slug = title