@senso-ai/cli 0.8.2 → 0.9.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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +45 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -141,7 +141,7 @@ Options: `content list` supports `--limit`, `--offset`, `--search`, `--sort`. `c
141
141
  ```
142
142
  senso generate settings Get generation settings
143
143
  senso generate update-settings Update generation settings (--data)
144
- senso generate sample Generate sample for a prompt (--prompt-id, --content-type-id)
144
+ senso generate sample Generate sample for a prompt; waits for async job by default (--prompt-id, --content-type-id, --no-wait)
145
145
  senso generate run Trigger a content engine run (--prompt-ids)
146
146
  ```
147
147
 
package/dist/cli.js CHANGED
@@ -1433,6 +1433,8 @@ function registerContentCommands(program2) {
1433
1433
  }
1434
1434
 
1435
1435
  // src/commands/generate.ts
1436
+ var SAMPLE_JOB_POLL_INTERVAL_MS = 2e3;
1437
+ var SAMPLE_JOB_TIMEOUT_MS = 18e4;
1436
1438
  function registerGenerateCommands(program2) {
1437
1439
  const gen = program2.command("generate").description("AI content generation. Configure settings, generate content samples from prompts, or trigger full content engine runs.");
1438
1440
  gen.command("settings").description("Get content generation settings. Shows whether generation and auto-publish are enabled, the content schedule, and configured publishers.").action(async () => {
@@ -1457,7 +1459,7 @@ function registerGenerateCommands(program2) {
1457
1459
  process.exit(1);
1458
1460
  }
1459
1461
  });
1460
- gen.command("sample").description("Generate an ad hoc content sample for a specific prompt and content type. Returns the generated markdown, SEO title, and publish results. Use 'prompts list' to find a prompt ID, and 'content-types list' to find a content-type ID.").requiredOption("--prompt-id <id>", "Prompt (geo question) ID to generate content for").requiredOption("--content-type-id <id>", "Content type ID that defines the output format (use 'content-types list' to find)").option("--destination <dest>", "Publisher slug to publish to immediately after generation. Omit to save as draft only.").action(async (cmdOpts) => {
1462
+ gen.command("sample").description("Generate an ad hoc content sample for a specific prompt and content type. Submits an async job, waits for completion by default, then returns the generated markdown, SEO title, and publish results. Use 'prompts list' to find a prompt ID, and 'content-types list' to find a content-type ID.").requiredOption("--prompt-id <id>", "Prompt (geo question) ID to generate content for").requiredOption("--content-type-id <id>", "Content type ID that defines the output format (use 'content-types list' to find)").option("--destination <dest>", "Publisher slug to publish to immediately after generation. Omit to save as draft only.").option("--no-wait", "Return the accepted sample job immediately instead of polling for the generated content.").action(async (cmdOpts) => {
1461
1463
  const opts = program2.opts();
1462
1464
  try {
1463
1465
  const body = {
@@ -1474,7 +1476,25 @@ function registerGenerateCommands(program2) {
1474
1476
  apiKey: opts.apiKey,
1475
1477
  baseUrl: opts.baseUrl
1476
1478
  });
1477
- console.log(JSON.stringify(data, null, 2));
1479
+ if (cmdOpts.wait === false) {
1480
+ console.log(JSON.stringify(data, null, 2));
1481
+ return;
1482
+ }
1483
+ const quiet = opts.quiet || opts.output === "json";
1484
+ if (!quiet) {
1485
+ info(`Sample job accepted: ${data.sample_job_id}`);
1486
+ }
1487
+ const job = await waitForSampleJob(data.sample_job_id, {
1488
+ apiKey: opts.apiKey,
1489
+ baseUrl: opts.baseUrl,
1490
+ quiet
1491
+ });
1492
+ if (job.status === "completed") {
1493
+ console.log(JSON.stringify(job.result ?? job, null, 2));
1494
+ return;
1495
+ }
1496
+ const message = job.error?.message || `Sample job ended with status: ${job.status}`;
1497
+ throw new Error(job.error?.code ? `${message} (${job.error.code})` : message);
1478
1498
  } catch (err) {
1479
1499
  error(formatApiError(err));
1480
1500
  process.exit(1);
@@ -1568,6 +1588,29 @@ function registerGenerateCommands(program2) {
1568
1588
  }
1569
1589
  });
1570
1590
  }
1591
+ async function waitForSampleJob(sampleJobId, opts) {
1592
+ const deadline = Date.now() + SAMPLE_JOB_TIMEOUT_MS;
1593
+ let lastStatus = "";
1594
+ while (Date.now() < deadline) {
1595
+ const job = await apiRequest({
1596
+ path: `/org/content-generation/sample-jobs/${sampleJobId}`,
1597
+ apiKey: opts.apiKey,
1598
+ baseUrl: opts.baseUrl
1599
+ });
1600
+ if (!opts.quiet && job.status !== lastStatus) {
1601
+ info(`Sample job status: ${job.status}`);
1602
+ lastStatus = job.status;
1603
+ }
1604
+ if (job.status === "completed" || job.status === "failed" || job.status === "expired") {
1605
+ return job;
1606
+ }
1607
+ await sleep(SAMPLE_JOB_POLL_INTERVAL_MS);
1608
+ }
1609
+ throw new Error(`Timed out waiting for sample job ${sampleJobId}. Poll /org/content-generation/sample-jobs/${sampleJobId} for status.`);
1610
+ }
1611
+ function sleep(ms) {
1612
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
1613
+ }
1571
1614
 
1572
1615
  // src/commands/engine.ts
1573
1616
  function registerEngineCommands(program2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senso-ai/cli",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "Senso CLI — Infrastructure for the Agentic Web. Interact with your Senso knowledge base from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {