vidpipe 1.3.8 → 1.3.9

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/README.md CHANGED
@@ -96,6 +96,9 @@ vidpipe --watch-dir ~/Videos/Recordings
96
96
  # Generate a saved idea bank for future recordings
97
97
  vidpipe ideate --topics "GitHub Copilot, Azure, TypeScript" --count 4
98
98
 
99
+ # Add a single idea with AI enrichment
100
+ vidpipe ideate --add --topic "Building CI/CD with GitHub Actions"
101
+
99
102
  # Full example with options
100
103
  vidpipe \
101
104
  --watch-dir ~/Videos/Recordings \
@@ -162,6 +165,17 @@ vidpipe doctor # Check all prerequisites
162
165
  | `--format <format>` | Output format: `table` (default) or `json` |
163
166
  | `--output <dir>` | Ideas directory (default: `./ideas`) |
164
167
  | `--brand <path>` | Brand config path (default: `./brand.json`) |
168
+ | `--add` | Create a single idea (AI-enriched by default) |
169
+ | `--topic <topic>` | Topic for the idea (required with `--add`) |
170
+ | `--hook <hook>` | Opening hook (AI-generated if omitted) |
171
+ | `--audience <audience>` | Target audience (default: `"developers"`) |
172
+ | `--platforms <list>` | Comma-separated platforms: `youtube,tiktok,instagram,linkedin,x` |
173
+ | `--key-takeaway <msg>` | Core message (AI-generated if omitted) |
174
+ | `--talking-points <list>` | Comma-separated talking points |
175
+ | `--tags <list>` | Comma-separated categorization tags |
176
+ | `--publish-by <date>` | Publish-by date (default: 14 days from now) |
177
+ | `--trend-context <text>` | Trend research context |
178
+ | `--no-ai` | Skip AI research agent, use CLI values + defaults |
165
179
 
166
180
  ---
167
181
 
@@ -233,6 +247,21 @@ vidpipe ideate --list --format json
233
247
  vidpipe process video.mp4 --ideas 12,15
234
248
  ```
235
249
 
250
+ ### Manual Idea Creation
251
+
252
+ Add a single idea with AI enrichment or direct CLI values:
253
+
254
+ ```bash
255
+ # AI-researched — full IdeationAgent with MCP research tools
256
+ vidpipe ideate --add --topic "Building CI/CD with GitHub Actions"
257
+
258
+ # Direct — skip AI, use CLI flags + defaults
259
+ vidpipe ideate --add --topic "Quick Demo" --no-ai --hook "Ship it live" --audience "developers"
260
+
261
+ # JSON output for programmatic consumers (e.g., VidRecord Electron app)
262
+ vidpipe ideate --add --topic "My Topic" --format json
263
+ ```
264
+
236
265
  ### How It Works
237
266
 
238
267
  The **IdeationAgent** uses MCP tools (Exa web search, YouTube, Perplexity) to research trending topics in your niche before generating ideas. Each idea includes:
package/dist/cli.js CHANGED
@@ -11557,12 +11557,13 @@ function isStringArray(value) {
11557
11557
  function hasField(source, field) {
11558
11558
  return Object.prototype.hasOwnProperty.call(source, field);
11559
11559
  }
11560
- function normalizeCount(count) {
11560
+ function normalizeCount(count, allowSingle) {
11561
+ const min = allowSingle ? 1 : MIN_IDEA_COUNT;
11561
11562
  if (typeof count !== "number" || Number.isNaN(count)) {
11562
- return MIN_IDEA_COUNT;
11563
+ return min;
11563
11564
  }
11564
11565
  const rounded = Math.round(count);
11565
- return Math.min(MAX_IDEA_COUNT, Math.max(MIN_IDEA_COUNT, rounded));
11566
+ return Math.min(MAX_IDEA_COUNT, Math.max(min, rounded));
11566
11567
  }
11567
11568
  function normalizeSeedTopics(seedTopics) {
11568
11569
  return (seedTopics ?? []).map((topic) => topic.trim()).filter((topic) => topic.length > 0);
@@ -12207,7 +12208,7 @@ var IdeationAgent = class extends BaseAgent {
12207
12208
  };
12208
12209
  async function generateIdeas(options = {}) {
12209
12210
  const seedTopics = normalizeSeedTopics(options.seedTopics);
12210
- const count = normalizeCount(options.count);
12211
+ const count = normalizeCount(options.count, options.singleTopic);
12211
12212
  const config2 = getConfig();
12212
12213
  const previousBrandPath = config2.BRAND_PATH;
12213
12214
  if (options.brandPath) {
@@ -13161,8 +13162,14 @@ function generateIdeas3(...args) {
13161
13162
  }
13162
13163
 
13163
13164
  // src/L7-app/commands/ideate.ts
13165
+ init_types();
13166
+ var VALID_PLATFORMS = new Set(Object.values(Platform));
13164
13167
  async function runIdeate(options = {}) {
13165
13168
  initConfig();
13169
+ if (options.add) {
13170
+ await handleAdd(options);
13171
+ return;
13172
+ }
13166
13173
  if (options.list) {
13167
13174
  const ideas2 = await listIdeas();
13168
13175
  const filtered = options.status ? ideas2.filter((idea) => idea.status === options.status) : ideas2;
@@ -13251,6 +13258,71 @@ ${filtered.length} idea(s) total`);
13251
13258
  console.log("Use `vidpipe ideate --list` to view all ideas.");
13252
13259
  console.log("Use `vidpipe process video.mp4 --ideas <issueNumber1>,<issueNumber2>` to link ideas to a recording.");
13253
13260
  }
13261
+ function parseCommaSeparated(value) {
13262
+ if (!value) return [];
13263
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
13264
+ }
13265
+ function parsePlatforms(value) {
13266
+ if (!value) return ["youtube" /* YouTube */];
13267
+ const names = parseCommaSeparated(value);
13268
+ const platforms = [];
13269
+ for (const name of names) {
13270
+ const lower = name.toLowerCase();
13271
+ if (!VALID_PLATFORMS.has(lower)) {
13272
+ throw new Error(`Invalid platform "${name}". Valid platforms: ${[...VALID_PLATFORMS].join(", ")}`);
13273
+ }
13274
+ platforms.push(lower);
13275
+ }
13276
+ return platforms.length > 0 ? platforms : ["youtube" /* YouTube */];
13277
+ }
13278
+ function defaultPublishBy() {
13279
+ const date = /* @__PURE__ */ new Date();
13280
+ date.setDate(date.getDate() + 14);
13281
+ return date.toISOString().split("T")[0];
13282
+ }
13283
+ function buildDirectInput(options) {
13284
+ const topic = options.topic;
13285
+ const hook = options.hook ?? topic;
13286
+ const audience = options.audience ?? "developers";
13287
+ const platforms = parsePlatforms(options.platforms);
13288
+ const keyTakeaway = options.keyTakeaway ?? hook;
13289
+ const talkingPoints = parseCommaSeparated(options.talkingPoints);
13290
+ const tags = parseCommaSeparated(options.tags);
13291
+ const publishBy = options.publishBy ?? defaultPublishBy();
13292
+ const trendContext = options.trendContext;
13293
+ return { topic, hook, audience, keyTakeaway, talkingPoints, platforms, tags, publishBy, trendContext };
13294
+ }
13295
+ async function handleAdd(options) {
13296
+ if (!options.topic) {
13297
+ throw new Error("--topic is required when using --add");
13298
+ }
13299
+ const useAI = options.ai !== false;
13300
+ if (useAI) {
13301
+ const ideas = await generateIdeas3({
13302
+ seedTopics: [options.topic],
13303
+ count: 1,
13304
+ singleTopic: true,
13305
+ brandPath: options.brand
13306
+ });
13307
+ const idea = ideas[0];
13308
+ if (!idea) {
13309
+ throw new Error("IdeationAgent did not create an idea");
13310
+ }
13311
+ if (options.format === "json") {
13312
+ console.log(JSON.stringify(idea, null, 2));
13313
+ } else {
13314
+ console.log(`Created idea #${idea.issueNumber}: "${idea.topic}"`);
13315
+ }
13316
+ } else {
13317
+ const input = buildDirectInput(options);
13318
+ const idea = await createIdea(input);
13319
+ if (options.format === "json") {
13320
+ console.log(JSON.stringify(idea, null, 2));
13321
+ } else {
13322
+ console.log(`Created idea #${idea.issueNumber}: "${idea.topic}"`);
13323
+ }
13324
+ }
13325
+ }
13254
13326
 
13255
13327
  // src/L1-infra/http/http.ts
13256
13328
  import { default as default8 } from "express";
@@ -13885,7 +13957,7 @@ program.command("chat").description("Interactive chat session with the schedule
13885
13957
  program.command("doctor").description("Check all prerequisites and dependencies").action(async () => {
13886
13958
  await runDoctor();
13887
13959
  });
13888
- program.command("ideate").description("Generate AI-powered content ideas using trend research").option("--topics <topics>", "Comma-separated seed topics").option("--count <n>", "Number of ideas to generate (default: 5)", "5").option("--output <dir>", "Ideas directory (default: ./ideas)").option("--brand <path>", "Brand config path (default: ./brand.json)").option("--list", "List existing ideas instead of generating").option("--status <status>", "Filter by status when listing (draft|ready|recorded|published)").option("--format <format>", "Output format: table (default) or json").action(async (opts) => {
13960
+ program.command("ideate").description("Generate AI-powered content ideas using trend research").option("--topics <topics>", "Comma-separated seed topics").option("--count <n>", "Number of ideas to generate (default: 5)", "5").option("--output <dir>", "Ideas directory (default: ./ideas)").option("--brand <path>", "Brand config path (default: ./brand.json)").option("--list", "List existing ideas instead of generating").option("--status <status>", "Filter by status when listing (draft|ready|recorded|published)").option("--format <format>", "Output format: table (default) or json").option("--add", "Add a single idea (AI-researched by default, or --no-ai for direct)").option("--topic <topic>", "Idea topic/title (required with --add)").option("--hook <hook>", "Attention-grabbing hook (default: topic, --no-ai only)").option("--audience <audience>", "Target audience (default: developers, --no-ai only)").option("--platforms <platforms>", "Comma-separated platforms: tiktok,youtube,instagram,linkedin,x (--no-ai only)").option("--key-takeaway <takeaway>", "Core message the viewer should remember (--no-ai only)").option("--talking-points <points>", "Comma-separated talking points (--no-ai only)").option("--tags <tags>", "Comma-separated categorization tags (--no-ai only)").option("--publish-by <date>", "Publish deadline (ISO 8601 date, default: 14 days from now, --no-ai only)").option("--trend-context <context>", "Why this topic is timely (--no-ai only)").option("--no-ai", "Skip AI research agent \u2014 create directly from CLI flags + defaults").action(async (opts) => {
13889
13961
  initConfig();
13890
13962
  await runIdeate(opts);
13891
13963
  process.exit(0);