@telepat/ideon 0.1.27 → 0.1.29

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 (2) hide show
  1. package/dist/ideon.js +72 -88
  2. package/package.json +1 -1
package/dist/ideon.js CHANGED
@@ -1424,7 +1424,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
1424
1424
  // package.json
1425
1425
  var package_default = {
1426
1426
  name: "@telepat/ideon",
1427
- version: "0.1.27",
1427
+ version: "0.1.29",
1428
1428
  description: "CLI for generating rich articles and images from ideas.",
1429
1429
  type: "module",
1430
1430
  repository: {
@@ -6152,10 +6152,45 @@ function resolveCustomLinks(existing, addRaw, removeExpressions) {
6152
6152
  }
6153
6153
 
6154
6154
  // src/cli/commands/export.ts
6155
- import { copyFile as copyFile2, mkdir as mkdir7, readFile as readFile9, stat as stat5, writeFile as writeFile6 } from "fs/promises";
6155
+ import { copyFile as copyFile2, mkdir as mkdir7, readFile as readFile10, stat as stat5, writeFile as writeFile6 } from "fs/promises";
6156
6156
  import path12 from "path";
6157
6157
 
6158
6158
  // src/output/enrichMarkdownWithLinks.ts
6159
+ import { readFile as readFile8 } from "fs/promises";
6160
+ async function loadLinksFromSidecar(markdownPath) {
6161
+ const linksPath = resolveLinksPath(markdownPath);
6162
+ let raw;
6163
+ try {
6164
+ raw = await readFile8(linksPath, "utf8");
6165
+ } catch {
6166
+ return [];
6167
+ }
6168
+ let parsed;
6169
+ try {
6170
+ parsed = JSON.parse(raw);
6171
+ } catch {
6172
+ return [];
6173
+ }
6174
+ if (typeof parsed !== "object" || parsed === null) {
6175
+ return [];
6176
+ }
6177
+ const record = parsed;
6178
+ const links = Array.isArray(record.links) ? record.links : [];
6179
+ const customLinks = Array.isArray(record.customLinks) ? record.customLinks : [];
6180
+ const filterAndMap = (entries, isCustom) => entries.filter((entry) => {
6181
+ if (typeof entry !== "object" || entry === null) {
6182
+ return false;
6183
+ }
6184
+ const e = entry;
6185
+ return typeof e.expression === "string" && typeof e.url === "string" && (e.title === null || typeof e.title === "string");
6186
+ }).map((entry) => ({
6187
+ expression: entry.expression.trim(),
6188
+ url: entry.url.trim(),
6189
+ title: entry.title,
6190
+ isCustom
6191
+ })).filter((entry) => entry.expression.length > 0 && entry.url.length > 0);
6192
+ return [...filterAndMap(customLinks, true), ...filterAndMap(links, false)];
6193
+ }
6159
6194
  function enrichMarkdownWithLinks(markdown, links) {
6160
6195
  if (links.length === 0) {
6161
6196
  return markdown;
@@ -6174,8 +6209,13 @@ function enrichMarkdownWithLinks(markdown, links) {
6174
6209
  if (isInProtectedSpan(updated, start, end)) {
6175
6210
  continue;
6176
6211
  }
6177
- updated = `${updated.slice(0, start)}[${match[0]}](${link.url})${updated.slice(end)}`;
6178
- break;
6212
+ const replacement = `[${match[0]}](${link.url})`;
6213
+ updated = `${updated.slice(0, start)}${replacement}${updated.slice(end)}`;
6214
+ if (link.isCustom) {
6215
+ expressionRegex.lastIndex = start + replacement.length;
6216
+ } else {
6217
+ break;
6218
+ }
6179
6219
  }
6180
6220
  }
6181
6221
  return updated;
@@ -6202,14 +6242,29 @@ function isInProtectedSpan(content, start, end) {
6202
6242
  return true;
6203
6243
  }
6204
6244
  }
6245
+ if (/^#{1,6}\s/.test(line)) {
6246
+ return true;
6247
+ }
6205
6248
  return false;
6206
6249
  }
6207
6250
  function escapeRegExp(value2) {
6208
- return value2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6251
+ return value2.replace(/[.*+?^{}()|[\]\\]/g, "\\$&");
6252
+ }
6253
+ function enrichWithFrontmatterGuard(markdown, links) {
6254
+ if (links.length === 0) {
6255
+ return markdown;
6256
+ }
6257
+ const frontmatterMatch = markdown.match(/^---\s*\n[\s\S]*?\n---\s*\n?/);
6258
+ if (!frontmatterMatch) {
6259
+ return enrichMarkdownWithLinks(markdown, links);
6260
+ }
6261
+ const frontmatter = frontmatterMatch[0];
6262
+ const body = markdown.slice(frontmatter.length);
6263
+ return `${frontmatter}${enrichMarkdownWithLinks(body, links)}`;
6209
6264
  }
6210
6265
 
6211
6266
  // src/server/previewHelpers.ts
6212
- import { readdir, stat as stat4, readFile as readFile8 } from "fs/promises";
6267
+ import { readdir, stat as stat4, readFile as readFile9 } from "fs/promises";
6213
6268
  import path11 from "path";
6214
6269
  var DEFAULT_PORT = 4173;
6215
6270
  var CONTENT_TYPE_ORDER = ["article", "blog-post", "x-thread", "x-post", "linkedin-post", "reddit-post", "newsletter"];
@@ -6311,7 +6366,7 @@ function extractCoverImageUrl(markdown) {
6311
6366
  return match?.[1] ?? null;
6312
6367
  }
6313
6368
  async function extractArticleMetadata(markdownPath) {
6314
- const markdown = await readFile8(markdownPath, "utf8");
6369
+ const markdown = await readFile9(markdownPath, "utf8");
6315
6370
  const fileStat = await stat4(markdownPath);
6316
6371
  const slug = extractFrontmatterSlug(markdown) ?? path11.basename(markdownPath, ".md");
6317
6372
  const title = extractHeadingTitle(stripFrontmatter2(markdown)) ?? slug;
@@ -6468,7 +6523,7 @@ async function resolvePrimaryContentType(outputs) {
6468
6523
  }
6469
6524
  const jobPath = path11.join(generationDir, "job.json");
6470
6525
  try {
6471
- const raw = await readFile8(jobPath, "utf8");
6526
+ const raw = await readFile9(jobPath, "utf8");
6472
6527
  const parsed = JSON.parse(raw);
6473
6528
  const targets = Array.isArray(parsed.contentTargets) ? parsed.contentTargets : Array.isArray(parsed.settings?.contentTargets) ? parsed.settings.contentTargets : [];
6474
6529
  const primary = targets.find((target) => target?.role === "primary" && typeof target.contentType === "string");
@@ -6509,7 +6564,7 @@ async function runOutputCommand(options, dependencies = {}) {
6509
6564
  );
6510
6565
  }
6511
6566
  const sourceMarkdownPath = articleOutput.sourcePath;
6512
- const sourceMarkdown = await readFile9(sourceMarkdownPath, "utf8");
6567
+ const sourceMarkdown = await readFile10(sourceMarkdownPath, "utf8");
6513
6568
  const slug = extractFrontmatterSlug2(sourceMarkdown) ?? path12.basename(sourceMarkdownPath, ".md");
6514
6569
  const exportFilename = `${slug}.md`;
6515
6570
  const destinationDir = await resolveDestinationDir(options.destinationPath, cwd2);
@@ -6520,7 +6575,7 @@ async function runOutputCommand(options, dependencies = {}) {
6520
6575
  );
6521
6576
  }
6522
6577
  await mkdir7(destinationDir, { recursive: true });
6523
- const links = await loadLinks(sourceMarkdownPath);
6578
+ const links = await loadLinksFromSidecar(sourceMarkdownPath);
6524
6579
  const enrichedMarkdown = enrichWithFrontmatterGuard(sourceMarkdown, links);
6525
6580
  const sourceDir = path12.dirname(sourceMarkdownPath);
6526
6581
  const allFiles = await listFilesRecursively(sourceDir, () => true);
@@ -6572,51 +6627,6 @@ async function fileExists2(filePath) {
6572
6627
  return false;
6573
6628
  }
6574
6629
  }
6575
- async function loadLinks(markdownPath) {
6576
- const linksPath = resolveLinksPath(markdownPath);
6577
- let raw;
6578
- try {
6579
- raw = await readFile9(linksPath, "utf8");
6580
- } catch {
6581
- return [];
6582
- }
6583
- let parsed;
6584
- try {
6585
- parsed = JSON.parse(raw);
6586
- } catch {
6587
- return [];
6588
- }
6589
- if (typeof parsed !== "object" || parsed === null) {
6590
- return [];
6591
- }
6592
- const record = parsed;
6593
- const links = Array.isArray(record.links) ? record.links : [];
6594
- const customLinks = Array.isArray(record.customLinks) ? record.customLinks : [];
6595
- const combined = [...customLinks, ...links];
6596
- return combined.filter((entry) => {
6597
- if (typeof entry !== "object" || entry === null) {
6598
- return false;
6599
- }
6600
- const e = entry;
6601
- return typeof e.expression === "string" && typeof e.url === "string" && (e.title === null || typeof e.title === "string");
6602
- }).map((entry) => ({
6603
- expression: entry.expression.trim(),
6604
- url: entry.url.trim(),
6605
- title: entry.title
6606
- })).filter((entry) => entry.expression.length > 0 && entry.url.length > 0);
6607
- }
6608
- function enrichWithFrontmatterGuard(markdown, links) {
6609
- if (links.length === 0) {
6610
- return markdown;
6611
- }
6612
- const frontmatterMatch = markdown.match(/^---\s*\n[\s\S]*?\n---\s*\n?/);
6613
- if (!frontmatterMatch) {
6614
- return enrichMarkdownWithLinks(markdown, links);
6615
- }
6616
- const frontmatter = frontmatterMatch[0];
6617
- const body = markdown.slice(frontmatter.length);
6618
- return `${frontmatter}${enrichMarkdownWithLinks(body, links)}`;
6619
- }
6620
6630
  function extractFrontmatterSlug2(markdown) {
6621
6631
  const frontmatterMatch = markdown.match(/^---\s*\n([\s\S]*?)\n---\s*\n?/);
6622
6632
  const block = frontmatterMatch?.[1];
@@ -7498,7 +7508,7 @@ import { spawn } from "child_process";
7498
7508
  // src/server/previewServer.ts
7499
7509
  import { execFile } from "child_process";
7500
7510
  import { promisify } from "util";
7501
- import { readFile as readFile10, stat as stat6 } from "fs/promises";
7511
+ import { readFile as readFile11, stat as stat6 } from "fs/promises";
7502
7512
  import { watch as fsWatch } from "fs";
7503
7513
  import path13 from "path";
7504
7514
  import { fileURLToPath } from "url";
@@ -7598,7 +7608,7 @@ async function startPreviewServer(options) {
7598
7608
  if (options.watch) {
7599
7609
  let html2;
7600
7610
  try {
7601
- html2 = await readFile10(path13.join(previewClientDir, "index.html"), "utf8");
7611
+ html2 = await readFile11(path13.join(previewClientDir, "index.html"), "utf8");
7602
7612
  } catch {
7603
7613
  res.status(200).type("html").send(
7604
7614
  `<!doctype html><html><head><meta charset="utf-8"><title>Rebuilding\u2026</title><style>body{margin:0;display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;background:#101820;color:#e0eaf0}p{font-size:15px;opacity:.7}</style></head><body><p>Rebuilding\u2026</p><script>const s=new EventSource('/api/__reload');s.onmessage=function(){location.reload()};</script></body></html>`
@@ -7662,7 +7672,7 @@ async function getArticleContent(generationId, markdownOutputDir) {
7662
7672
  generation.outputs.map(async (output) => {
7663
7673
  let markdown = "";
7664
7674
  try {
7665
- markdown = await readFile10(output.sourcePath, "utf8");
7675
+ markdown = await readFile11(output.sourcePath, "utf8");
7666
7676
  } catch (error) {
7667
7677
  if (isMissingFileError(error)) {
7668
7678
  throw new MissingArticleError(`Generation "${generationId}" no longer exists.`);
@@ -7718,41 +7728,15 @@ function isMissingFileError(error) {
7718
7728
  }
7719
7729
  async function renderArticleHtml(markdown, generationId, sourcePath) {
7720
7730
  let content = stripFrontmatter2(markdown);
7721
- const links = await loadSavedLinks(sourcePath);
7731
+ const links = await loadLinksFromSidecar(sourcePath);
7722
7732
  content = enrichMarkdownWithLinks(content, links);
7723
7733
  const html = await marked.parse(content);
7724
7734
  return rewriteRelativeAssetUrls(html, generationId);
7725
7735
  }
7726
- async function loadSavedLinks(markdownPath) {
7727
- const linksPath = resolveLinksPath(markdownPath);
7728
- try {
7729
- const raw = await readFile10(linksPath, "utf8");
7730
- const parsed = JSON.parse(raw);
7731
- if (!Array.isArray(parsed.links)) {
7732
- return [];
7733
- }
7734
- return parsed.links.filter((entry) => {
7735
- if (typeof entry !== "object" || entry === null) {
7736
- return false;
7737
- }
7738
- const record = entry;
7739
- return typeof record.expression === "string" && typeof record.url === "string" && (record.title === null || typeof record.title === "string");
7740
- }).map((entry) => ({
7741
- expression: entry.expression.trim(),
7742
- url: entry.url.trim(),
7743
- title: entry.title
7744
- })).filter((entry) => entry.expression.length > 0 && entry.url.length > 0);
7745
- } catch (error) {
7746
- if (isMissingFileError(error)) {
7747
- return [];
7748
- }
7749
- return [];
7750
- }
7751
- }
7752
7736
  async function loadSavedInteractions(generationDir) {
7753
7737
  const interactionsPath = path13.join(generationDir, "model.interactions.json");
7754
7738
  try {
7755
- const raw = await readFile10(interactionsPath, "utf8");
7739
+ const raw = await readFile11(interactionsPath, "utf8");
7756
7740
  const parsed = JSON.parse(raw);
7757
7741
  const llmCalls = Array.isArray(parsed.llmCalls) ? parsed.llmCalls.filter(isPreviewLlmInteraction) : [];
7758
7742
  const t2iCalls = Array.isArray(parsed.t2iCalls) ? parsed.t2iCalls.filter(isPreviewT2IInteraction) : [];
@@ -7770,7 +7754,7 @@ async function loadSavedInteractions(generationDir) {
7770
7754
  async function loadSavedAnalyticsSummary(generationDir) {
7771
7755
  const analyticsPath = path13.join(generationDir, "generation.analytics.json");
7772
7756
  try {
7773
- const raw = await readFile10(analyticsPath, "utf8");
7757
+ const raw = await readFile11(analyticsPath, "utf8");
7774
7758
  const parsed = JSON.parse(raw);
7775
7759
  const summary = parsed.summary;
7776
7760
  if (!summary || typeof summary !== "object") {
@@ -7794,7 +7778,7 @@ async function loadSavedAnalyticsSummary(generationDir) {
7794
7778
  async function loadSavedMetaJson(generationDir) {
7795
7779
  const metaJsonPath = path13.join(generationDir, "meta.json");
7796
7780
  try {
7797
- const raw = await readFile10(metaJsonPath, "utf8");
7781
+ const raw = await readFile11(metaJsonPath, "utf8");
7798
7782
  return JSON.parse(raw);
7799
7783
  } catch {
7800
7784
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telepat/ideon",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "CLI for generating rich articles and images from ideas.",
5
5
  "type": "module",
6
6
  "repository": {