@telepat/ideon 0.1.19 → 0.1.20

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 +78 -35
  2. package/package.json +1 -1
package/dist/ideon.js CHANGED
@@ -1362,7 +1362,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
1362
1362
  // package.json
1363
1363
  var package_default = {
1364
1364
  name: "@telepat/ideon",
1365
- version: "0.1.19",
1365
+ version: "0.1.20",
1366
1366
  description: "CLI for generating rich articles and images from ideas.",
1367
1367
  type: "module",
1368
1368
  repository: {
@@ -2284,9 +2284,10 @@ function buildArticlePlanJsonSchema(targetLengthWords) {
2284
2284
  items: {
2285
2285
  type: "object",
2286
2286
  additionalProperties: false,
2287
- required: ["description"],
2287
+ required: ["description", "anchorAfterSection"],
2288
2288
  properties: {
2289
- description: { type: "string" }
2289
+ description: { type: "string" },
2290
+ anchorAfterSection: { type: "number", minimum: 1 }
2290
2291
  }
2291
2292
  }
2292
2293
  }
@@ -2323,8 +2324,9 @@ function buildArticlePlanMessages(idea, options) {
2323
2324
  "- Each section description should name the mechanism, evidence type, or practical action that makes the section useful.",
2324
2325
  "- Sections are article-only structure and must not be treated as requirements for non-article channels.",
2325
2326
  "- Include a cover image description and 2 to 3 inline image descriptions.",
2327
+ "- Each inline image must specify which section it follows (anchorAfterSection, 1-based index). Choose sections where visual reinforcement adds the most value.",
2328
+ "- Image descriptions should capture the general concept and mood \u2014 the exact text-to-image prompt will be refined later using the actual section content.",
2326
2329
  "- Image descriptions must be concrete and contextual, not generic stock-photo phrasing.",
2327
- "- Do not include section placement for inline images \u2014 placement is determined automatically after writing.",
2328
2330
  "",
2329
2331
  "Shared content brief context:",
2330
2332
  `- description: ${options.contentBrief.description}`,
@@ -2343,7 +2345,7 @@ function buildArticlePlanMessages(idea, options) {
2343
2345
  "- outroBrief: string",
2344
2346
  `- sections: array of ${sectionCounts.label} objects, each with title and description strings`,
2345
2347
  "- coverImageDescription: string",
2346
- "- inlineImages: array of 2 to 3 objects, each with a description string only",
2348
+ "- inlineImages: array of 2 to 3 objects, each with a description string and an anchorAfterSection number (1-based section index)",
2347
2349
  "",
2348
2350
  "Do not omit any required fields. Return strict JSON only."
2349
2351
  ].join("\n")
@@ -2358,7 +2360,8 @@ var articleSectionPlanSchema = z5.object({
2358
2360
  description: z5.string().min(1)
2359
2361
  });
2360
2362
  var inlineImagePlanSchema = z5.object({
2361
- description: z5.string().min(1)
2363
+ description: z5.string().min(1),
2364
+ anchorAfterSection: z5.number().int().min(1)
2362
2365
  });
2363
2366
  var articlePlanSchema = z5.object({
2364
2367
  title: z5.string().min(1),
@@ -2409,11 +2412,15 @@ async function planArticle({
2409
2412
  });
2410
2413
  const normalizedSlug = slugify(basePlan.slug || basePlan.title);
2411
2414
  const uniqueSlug = await resolveUniqueSlug(markdownOutputDir, normalizedSlug);
2415
+ const sectionCount = basePlan.sections.length;
2412
2416
  return {
2413
2417
  ...basePlan,
2414
2418
  slug: uniqueSlug,
2415
2419
  keywords: basePlan.keywords.slice(0, 8),
2416
- inlineImages: basePlan.inlineImages.slice(0, 3)
2420
+ inlineImages: basePlan.inlineImages.slice(0, 3).map((img) => ({
2421
+ ...img,
2422
+ anchorAfterSection: Math.max(1, Math.min(sectionCount, img.anchorAfterSection))
2423
+ }))
2417
2424
  };
2418
2425
  }
2419
2426
  function buildDryRunPlan(idea, contentBrief) {
@@ -2451,10 +2458,12 @@ function buildDryRunPlan(idea, contentBrief) {
2451
2458
  coverImageDescription: "A refined editorial workspace with notebooks, sketches, and glowing structured outlines, cinematic but minimal.",
2452
2459
  inlineImages: [
2453
2460
  {
2454
- description: "A rough idea evolving into a structured article outline on a desk full of notes."
2461
+ description: "A rough idea evolving into a structured article outline on a desk full of notes.",
2462
+ anchorAfterSection: 2
2455
2463
  },
2456
2464
  {
2457
- description: "A collaborative editorial scene where human judgment and AI suggestions coexist."
2465
+ description: "A collaborative editorial scene where human judgment and AI suggestions coexist.",
2466
+ anchorAfterSection: 4
2458
2467
  }
2459
2468
  ]
2460
2469
  };
@@ -2956,24 +2965,8 @@ function sumKnownCosts(values) {
2956
2965
 
2957
2966
  // src/images/renderImages.ts
2958
2967
  var MIN_IMAGE_BYTES = 1024;
2959
- function selectImageSlots(plan, sections, options) {
2968
+ function buildImageSlots(plan, sections, options) {
2960
2969
  const sectionCount = sections.length;
2961
- let defaultInlineCount;
2962
- if (sectionCount <= 3) {
2963
- defaultInlineCount = 0;
2964
- } else if (sectionCount <= 6) {
2965
- defaultInlineCount = 1;
2966
- } else {
2967
- defaultInlineCount = 2;
2968
- }
2969
- const availableInlineCount = Math.min(defaultInlineCount, plan.inlineImages.length, sectionCount);
2970
- let inlineCount;
2971
- const maxImages = options?.maxImages;
2972
- if (maxImages !== void 0 && maxImages >= 1) {
2973
- inlineCount = Math.min(availableInlineCount, Math.max(0, maxImages - 1));
2974
- } else {
2975
- inlineCount = availableInlineCount;
2976
- }
2977
2970
  const slots = [
2978
2971
  {
2979
2972
  id: "cover",
@@ -2983,17 +2976,22 @@ function selectImageSlots(plan, sections, options) {
2983
2976
  anchorAfterSection: null
2984
2977
  }
2985
2978
  ];
2979
+ let inlineCount = plan.inlineImages.length;
2980
+ const maxImages = options?.maxImages;
2981
+ if (maxImages !== void 0 && maxImages >= 1) {
2982
+ inlineCount = Math.min(inlineCount, Math.max(0, maxImages - 1));
2983
+ }
2986
2984
  for (let i = 0; i < inlineCount; i++) {
2987
- const anchorAfterSection = Math.max(
2988
- 1,
2989
- Math.min(sectionCount, Math.round((i + 1) / (inlineCount + 1) * sectionCount))
2990
- );
2985
+ const img = plan.inlineImages[i];
2986
+ if (!img) {
2987
+ continue;
2988
+ }
2991
2989
  slots.push({
2992
2990
  id: `inline-${i + 1}`,
2993
2991
  kind: "inline",
2994
2992
  prompt: "",
2995
- description: plan.inlineImages[i]?.description ?? "",
2996
- anchorAfterSection
2993
+ description: img.description,
2994
+ anchorAfterSection: Math.max(1, Math.min(sectionCount, img.anchorAfterSection))
2997
2995
  });
2998
2996
  }
2999
2997
  return slots;
@@ -3760,7 +3758,8 @@ var pipelineArtifactSummarySchema = z6.object({
3760
3758
  markdownPath: z6.string().min(1),
3761
3759
  assetDir: z6.string().min(1),
3762
3760
  analyticsPath: z6.string().min(1).default("unknown.analytics.json"),
3763
- interactionsPath: z6.string().min(1).default("unknown.interactions.json")
3761
+ interactionsPath: z6.string().min(1).default("unknown.interactions.json"),
3762
+ planPath: z6.string().min(1).nullable().default(null)
3764
3763
  });
3765
3764
  var resolvedPathsSchema = z6.object({
3766
3765
  markdownOutputDir: z6.string().min(1),
@@ -4282,7 +4281,7 @@ async function runPipelineShell(input, options = {}) {
4282
4281
  options.onUpdate?.(cloneStages(stages));
4283
4282
  } else {
4284
4283
  imagePrompts = await expandImagePrompts({
4285
- slots: selectImageSlots(plan, text.sections, { maxImages: options.maxImages }),
4284
+ slots: buildImageSlots(plan, text.sections, { maxImages: options.maxImages }),
4286
4285
  planContext: plan,
4287
4286
  sections: text.sections,
4288
4287
  settings: input.config.settings,
@@ -4445,6 +4444,10 @@ async function runPipelineShell(input, options = {}) {
4445
4444
  sourceJob: input.job
4446
4445
  })
4447
4446
  );
4447
+ const planPath = plan ? path8.join(generationDir, "plan.md") : null;
4448
+ if (plan && planPath) {
4449
+ await writeUtf8File(planPath, renderPlanMarkdown(plan));
4450
+ }
4448
4451
  const primaryFilePrefix = toFilePrefix(primaryTarget.contentType);
4449
4452
  const primaryMarkdownPath = path8.join(generationDir, `${primaryFilePrefix}-1.md`);
4450
4453
  const sharedAssetDir = generationDir;
@@ -4962,7 +4965,8 @@ async function runPipelineShell(input, options = {}) {
4962
4965
  markdownPath: primaryMarkdownPathForArtifact,
4963
4966
  assetDir: sharedAssetDir,
4964
4967
  analyticsPath,
4965
- interactionsPath
4968
+ interactionsPath,
4969
+ planPath
4966
4970
  };
4967
4971
  writeSession = await patchWriteSession(
4968
4972
  {
@@ -5344,6 +5348,45 @@ function buildRunJobDefinition(input) {
5344
5348
  }
5345
5349
  };
5346
5350
  }
5351
+ function renderPlanMarkdown(plan) {
5352
+ const yamlKeywords = plan.keywords.map((kw) => ` - "${kw}"`).join("\n");
5353
+ const sectionsRows = plan.sections.map((section, index) => `| ${index + 1} | ${section.title} | ${section.description} |`).join("\n");
5354
+ const inlineImageRows = plan.inlineImages.map((img, index) => `| Inline ${index + 1} | ${img.description} |`).join("\n");
5355
+ const imageRows = `| Cover | ${plan.coverImageDescription} |
5356
+ ${inlineImageRows}`;
5357
+ return `---
5358
+ title: "${plan.title.replace(/"/g, '\\"')}"
5359
+ subtitle: "${plan.subtitle.replace(/"/g, '\\"')}"
5360
+ slug: "${plan.slug}"
5361
+ keywords:
5362
+ ${yamlKeywords}
5363
+ ---
5364
+
5365
+ ## Description
5366
+
5367
+ ${plan.description}
5368
+
5369
+ ## Introduction Brief
5370
+
5371
+ ${plan.introBrief}
5372
+
5373
+ ## Sections
5374
+
5375
+ | # | Title | Description |
5376
+ |---|-------|-------------|
5377
+ ${sectionsRows}
5378
+
5379
+ ## Outro Brief
5380
+
5381
+ ${plan.outroBrief}
5382
+
5383
+ ## Image Plan
5384
+
5385
+ | Type | Description |
5386
+ |------|-------------|
5387
+ ${imageRows}
5388
+ `;
5389
+ }
5347
5390
  function asWriteStageId(stageId) {
5348
5391
  if (stageId === "shared-brief" || stageId === "planning" || stageId === "sections" || stageId === "image-prompts" || stageId === "images" || stageId === "output" || stageId === "links") {
5349
5392
  return stageId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telepat/ideon",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "CLI for generating rich articles and images from ideas.",
5
5
  "type": "module",
6
6
  "repository": {