@letterstory/cli 0.139.0 → 0.140.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.
package/lib/cli.mjs CHANGED
@@ -64,7 +64,7 @@ import {
64
64
  } from "./commands.mjs";
65
65
 
66
66
  // Keep in sync with cli/package.json.
67
- export const VERSION = "0.139.0";
67
+ export const VERSION = "0.140.0";
68
68
 
69
69
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
70
70
  // can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
@@ -634,6 +634,7 @@ Ranking targets (what the org wants to be THE answer for — company-wide or on
634
634
  targets subqueries [<target-id>] [--retired] The phrasings asked under each target (who retired one, and why)
635
635
  targets subquery add <target-id> <phrasing> Another way your buyers ask a target's question
636
636
  targets subquery update <subquery-id> [--text <t>] [--retire | --restore]
637
+ targets posts [<target-id>] Each target's posts (written for it first), cited and won (28 days)
637
638
 
638
639
  Arenas (adversarial clusters of research agents -> a sourced, fact-checked outline):
639
640
  arena run --topic <text> [--source <url> …] [--must-include <text> …] [--depth barebones|fleshed_out]
@@ -1420,7 +1421,8 @@ Repo changes (Claude Code edits your repo in a sandbox; the Letterstory GitHub A
1420
1421
  repo delete-secret --repo <owner/name> --secret <KEY>
1421
1422
  Delete one
1422
1423
  repo status <run-id> Phase, spend, PR link and Claude's summary
1423
- repo activity <run-id> [--follow] What the sandbox is doing, line by line (--follow: until it stops)
1424
+ repo activity <run-id> [--follow] [--since <iso>] What the sandbox is doing, line by line (--follow: until it stops)
1425
+ repo say <run-id> <message…> Tell a running build something; it carries on with it
1424
1426
  repo list [--status running|succeeded|no_changes|failed|cancelled] [--limit n] [--audit <id>]
1425
1427
  [--source site_audit_issue|site_quick_check|letterprove_install|visitors_install]
1426
1428
  repo publish <run-id> Make PR on a preview in review
@@ -5,6 +5,7 @@
5
5
  // repo list → list_repo_changes repo cancel → cancel_repo_change
6
6
  // repo publish → publish_repo_change (Make PR on a preview)
7
7
  // repo revise → revise_repo_change (ask for more on a preview, before the PR)
8
+ // repo say → send_repo_change_message (steer a build while its agent works)
8
9
  // repo repos → list_github_app_repos repo branches → list_repo_branches
9
10
  // repo prs → list_open_pull_requests (every open PR, whoever opened it)
10
11
  // repo install-letterprove → letterprove_open_install_pr
@@ -182,7 +183,16 @@ const ARGS = {
182
183
  auto_merge_after_hours: { value: (flags) => autoMergeHours(flags["auto-merge"]) },
183
184
  },
184
185
  get_repo_change: { run_id: { positional: 0, required: true, label: "run-id" } },
185
- get_repo_change_activity: { run_id: { positional: 0, required: true, label: "run-id" } },
186
+ get_repo_change_activity: {
187
+ run_id: { positional: 0, required: true, label: "run-id" },
188
+ since: "since",
189
+ },
190
+ send_repo_change_message: {
191
+ run_id: { positional: 0, required: true, label: "run-id" },
192
+ message: {
193
+ value: (flags, positionals) => flagStr(flags.message) ?? (positionals.slice(1).join(" ") || undefined),
194
+ },
195
+ },
186
196
  cancel_repo_change: { run_id: { positional: 0, required: true, label: "run-id" } },
187
197
  publish_repo_change: { run_id: { positional: 0, required: true, label: "run-id" } },
188
198
  revise_repo_change: {
@@ -283,6 +293,8 @@ export async function cmdRepo(ctx) {
283
293
  return repoPublish(rest);
284
294
  case "revise":
285
295
  return repoRevise(rest);
296
+ case "say":
297
+ return repoSay(rest);
286
298
  case "repos":
287
299
  return repoRepos(rest);
288
300
  case "branches":
@@ -299,7 +311,7 @@ export async function cmdRepo(ctx) {
299
311
  return repoSlackTest(rest);
300
312
  default:
301
313
  throw new CliError(
302
- `Unknown repo subcommand: ${sub ?? "(none)"}. Try: start, fix-audit, install-letterprove, install-visitors, sites, set-site, reset-site, secrets, set-secret, delete-secret, status, list, publish, cancel, repos, branches, prs, settings, suggestions, slack-targets, slack-test`
314
+ `Unknown repo subcommand: ${sub ?? "(none)"}. Try: start, fix-audit, install-letterprove, install-visitors, sites, set-site, reset-site, secrets, set-secret, delete-secret, status, list, publish, revise, say, cancel, repos, branches, prs, settings, suggestions, slack-targets, slack-test`
303
315
  );
304
316
  }
305
317
  }
@@ -555,12 +567,12 @@ async function repoStatus(ctx) {
555
567
  return 0;
556
568
  }
557
569
 
558
- const ACTIVITY_MARK = { progress: "·", stage: "▸", say: "»", tool: "$", error: "!" };
570
+ const ACTIVITY_MARK = { progress: "·", stage: "▸", say: "»", think: "◇", tool: "$", user: ">", error: "!" };
559
571
 
560
- /** `repo activity <run-id> [--follow]`: the build's feed; --follow prints new lines until it stops. */
572
+ /** `repo activity <run-id> [--follow] [--since <iso>]`: the build's feed; --follow prints new lines until it stops. */
561
573
  async function repoActivity(ctx) {
562
574
  const { client, flags, io } = ctx;
563
- refuseUnknownFlags(ctx, {}, ["follow"]);
575
+ refuseUnknownFlags(ctx, {}, ["follow", "since"]);
564
576
  const args = argsFromFlags(ARGS.get_repo_change_activity, flags, ctx.positionals);
565
577
  const line = (l) => `${l.at.slice(11, 19)} ${ACTIVITY_MARK[l.kind] ?? " "} ${l.text}`;
566
578
  let { activity } = await client.callTool("get_repo_change_activity", args);
@@ -623,6 +635,18 @@ async function repoPublish(ctx) {
623
635
  return 0;
624
636
  }
625
637
 
638
+ /** `repo say <run-id> <message…>` (or --message): steer a build while its agent works. */
639
+ async function repoSay(ctx) {
640
+ const { client, flags, io } = ctx;
641
+ refuseUnknownFlags(ctx, {}, ["message"]);
642
+ const args = argsFromFlags(ARGS.send_repo_change_message, flags, ctx.positionals);
643
+ if (!args.message) throw new CliError("Say what to tell the build: repo say <run-id> <message…> (or --message)");
644
+ const result = await client.callTool("send_repo_change_message", args);
645
+ ok(ctx, result.message);
646
+ printResult(io, flags, result.sent, (s) => `${s.delivered ? "Sent" : "Waiting for the sandbox"}: ${s.message}`);
647
+ return 0;
648
+ }
649
+
626
650
  /** `repo revise <run-id> --instructions <text>`: a follow-up on a preview, built on top of it. */
627
651
  async function repoRevise(ctx) {
628
652
  const { client, flags, io } = ctx;
@@ -44,6 +44,7 @@ const priority = { value: readPriority };
44
44
  // `scripts/parity-check.ts` compares these keys against each tool's published input schema.
45
45
  export const ARGS = {
46
46
  list_ranking_targets: { offering_id: offering },
47
+ list_ranking_target_posts: { target_id: { positional: 0, label: "target-id" } },
47
48
  add_ranking_target: {
48
49
  // The phrase is every positional, so `targets add best payroll software` needs no quotes.
49
50
  phrase: {
@@ -138,7 +139,8 @@ const USAGE = `Usage: targets <list|add|update|activate|deactivate|cap|suggest|s
138
139
  targets suggest [--offering <offering-id|company>]
139
140
  targets subqueries [<target-id>] [--retired] the phrasings asked under each target
140
141
  targets subquery add <target-id> <phrasing>
141
- targets subquery update <subquery-id> [--text <t>] [--retire | --restore]`;
142
+ targets subquery update <subquery-id> [--text <t>] [--retire | --restore]
143
+ targets posts [<target-id>]`;
142
144
 
143
145
  export async function cmdTargets(ctx) {
144
146
  const sub = ctx.positionals[0];
@@ -163,6 +165,8 @@ export async function cmdTargets(ctx) {
163
165
  return subqueriesList(rest);
164
166
  case "subquery":
165
167
  return subqueryWrite(rest);
168
+ case "posts":
169
+ return targetsPosts(rest);
166
170
  default:
167
171
  throw new CliError(USAGE);
168
172
  }
@@ -277,6 +281,31 @@ async function targetsCap(ctx) {
277
281
  return 0;
278
282
  }
279
283
 
284
+ function formatTargetPosts(r) {
285
+ if (!r.targets?.length) return "No active ranking targets.";
286
+ const lines = [];
287
+ for (const t of r.targets) {
288
+ lines.push(`${t.phrase}${t.queued ? ` (${t.queued} queued)` : ""}`);
289
+ if (!t.posts.length) lines.push(" No published posts yet.");
290
+ for (const p of t.posts) {
291
+ const why = p.writtenForTarget ? (p.subquery ? `for "${p.subquery}"` : "written for it") : "on its pillar";
292
+ lines.push(` ${p.title} [${why}] cited for ${p.citedQueries} · won ${p.breakthroughQueries}`);
293
+ }
294
+ }
295
+ lines.push(`Cited and won: distinct queries, the last ${r.windowDays} days.`);
296
+ return lines.join("\n");
297
+ }
298
+
299
+ async function targetsPosts(ctx) {
300
+ const { client, flags, io } = ctx;
301
+ const result = await client.callTool(
302
+ "list_ranking_target_posts",
303
+ argsFromFlags(ARGS.list_ranking_target_posts, flags, ctx.positionals)
304
+ );
305
+ printResult(io, flags, result, formatTargetPosts);
306
+ return 0;
307
+ }
308
+
280
309
  async function targetsSuggest(ctx) {
281
310
  const { client, flags, io } = ctx;
282
311
  const result = await client.callTool("suggest_ranking_targets", argsFromFlags(ARGS.suggest_ranking_targets, flags));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.139.0",
3
+ "version": "0.140.0",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",