@letterstory/cli 0.15.2 → 0.15.3

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
@@ -24,6 +24,8 @@ import {
24
24
  cmdFlows,
25
25
  cmdConnectors,
26
26
  cmdStrategy,
27
+ cmdProbes,
28
+ cmdSuggestions,
27
29
  cmdOnboarding,
28
30
  cmdSeries,
29
31
  cmdInsights,
@@ -41,7 +43,7 @@ import {
41
43
  } from "./commands.mjs";
42
44
 
43
45
  // Keep in sync with cli/package.json.
44
- export const VERSION = "0.15.2";
46
+ export const VERSION = "0.15.3";
45
47
 
46
48
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
47
49
  // can't accidentally swallow the id as --json's value.
@@ -242,6 +244,12 @@ Strategy & onboarding:
242
244
  strategy sitemap --collection <uuid> --url <sitemap_url> [--sub <url> …] [--pattern <glob>]
243
245
  strategy topics list --collection <uuid> List the topic map's clusters/spokes
244
246
  strategy topics set --collection <uuid> (--topic <topic-id> | --suggestion <suggestion-id>)
247
+ suggestions list <collection_id> List pending strategy suggestions + their auto-apply countdown
248
+ suggestions approve | dismiss | snooze <verdict|proposal> <id> [--days <n>]
249
+ probes list [--collection <uuid>] [--active-only] [--kind mention|citation|page]
250
+ probes keep | pause | resume <probe_id> Keep = protect an AI probe from rotation (no pause)
251
+ probes edit <probe_id> <new question text> Fix/sharpen a generated probe
252
+ probes add <question> [--kind mention|citation] [--scope site|company|<blogId>] [--cluster <id>]
245
253
  onboarding status Show the onboarding checklist
246
254
  onboarding step [--current <step>] [--complete <step>] [--skip <step>] [--status <status>]
247
255
  series list The org's content series + coverage state
@@ -459,6 +467,8 @@ const CLIENT_COMMANDS = {
459
467
  flows: cmdFlows,
460
468
  connectors: cmdConnectors,
461
469
  strategy: cmdStrategy,
470
+ probes: cmdProbes,
471
+ suggestions: cmdSuggestions,
462
472
  onboarding: cmdOnboarding,
463
473
  series: cmdSeries,
464
474
  insights: cmdInsights,
@@ -0,0 +1,145 @@
1
+ // `probes` + `suggestions` — surface parity with the Measure → Probes tab and
2
+ // the collection strategy queue. Thin wrappers over the MCP tools (list_probes,
3
+ // control_probe, add_probe; list_strategy_suggestions, decide_strategy_suggestion),
4
+ // which themselves call the same shared lib seams the web + REST use. So an agent
5
+ // or a script can see and act on exactly what a person can.
6
+
7
+ import { CliError } from "../client.mjs";
8
+ import { flagStr, flagNum, flagBool, requirePositional, printResult, compact, ok } from "./shared.mjs";
9
+
10
+ export async function cmdProbes(ctx) {
11
+ const sub = ctx.positionals[0];
12
+ const rest = { ...ctx, positionals: ctx.positionals.slice(1) };
13
+ switch (sub) {
14
+ case "list":
15
+ case "ls":
16
+ return probesList(rest);
17
+ case "keep":
18
+ return probesControl(rest, "keep");
19
+ case "pause":
20
+ return probesControl(rest, "pause");
21
+ case "resume":
22
+ return probesControl(rest, "resume");
23
+ case "edit":
24
+ return probesEdit(rest);
25
+ case "add":
26
+ return probesAdd(rest);
27
+ default:
28
+ throw new CliError("Usage: probes <list|keep|pause|resume|edit|add>");
29
+ }
30
+ }
31
+
32
+ function formatProbeLine(p) {
33
+ const state = p.lifecycle_state ? `[${p.lifecycle_state}]` : p.is_active ? "[active]" : "[paused]";
34
+ return `${p.id} ${state} (${p.probe_kind}/${p.scope}, source=${p.source ?? "?"}) ${p.text}`;
35
+ }
36
+
37
+ async function probesList(ctx) {
38
+ const { client, flags, io } = ctx;
39
+ const result = await client.callTool(
40
+ "list_probes",
41
+ compact({
42
+ collection_id: flagStr(flags.collection),
43
+ active_only: flagBool(flags["active-only"]),
44
+ probe_kind: flagStr(flags.kind),
45
+ })
46
+ );
47
+ printResult(io, flags, result, (r) => {
48
+ const lines = (r.probes ?? []).map(formatProbeLine);
49
+ if (!lines.length) lines.push("No probes match.");
50
+ return lines.join("\n");
51
+ });
52
+ return 0;
53
+ }
54
+
55
+ async function probesControl(ctx, action) {
56
+ const { client, positionals } = ctx;
57
+ const probeId = requirePositional(positionals, 0, "probe_id");
58
+ const result = await client.callTool("control_probe", { probe_id: probeId, action });
59
+ ok(ctx, result.noop ? "Nothing to change (already in that state)." : `Probe ${action}d.`);
60
+ return 0;
61
+ }
62
+
63
+ async function probesEdit(ctx) {
64
+ const { client, positionals } = ctx;
65
+ const probeId = requirePositional(positionals, 0, "probe_id");
66
+ const text = positionals.slice(1).join(" ").trim();
67
+ if (!text) throw new CliError("Usage: probes edit <probe_id> <new question text>");
68
+ await client.callTool("control_probe", { probe_id: probeId, action: "edit", text });
69
+ ok(ctx, "Question updated.");
70
+ return 0;
71
+ }
72
+
73
+ async function probesAdd(ctx) {
74
+ const { client, positionals, flags } = ctx;
75
+ const text = positionals.join(" ").trim();
76
+ if (!text)
77
+ throw new CliError(
78
+ "Usage: probes add <question> [--kind mention|citation] [--scope site|company|<blogId>] [--cluster <id>]"
79
+ );
80
+ const result = await client.callTool(
81
+ "add_probe",
82
+ compact({
83
+ text,
84
+ probe_kind: flagStr(flags.kind) ?? "mention",
85
+ scope: flagStr(flags.scope) ?? "site",
86
+ cluster_id: flagStr(flags.cluster),
87
+ })
88
+ );
89
+ ok(ctx, `Added probe ${result.id}.`);
90
+ return 0;
91
+ }
92
+
93
+ export async function cmdSuggestions(ctx) {
94
+ const sub = ctx.positionals[0];
95
+ const rest = { ...ctx, positionals: ctx.positionals.slice(1) };
96
+ switch (sub) {
97
+ case "list":
98
+ case "ls":
99
+ return suggestionsList(rest);
100
+ case "approve":
101
+ return suggestionsDecide(rest, "approve");
102
+ case "dismiss":
103
+ return suggestionsDecide(rest, "dismiss");
104
+ case "snooze":
105
+ return suggestionsDecide(rest, "snooze");
106
+ default:
107
+ throw new CliError(
108
+ "Usage: suggestions <list <collection_id>|approve|dismiss|snooze <verdict|proposal> <id>>"
109
+ );
110
+ }
111
+ }
112
+
113
+ function formatSuggestionLine(s) {
114
+ const when =
115
+ s.disposition === "auto"
116
+ ? s.snoozed_until
117
+ ? `snoozed→${s.snoozed_until.slice(0, 10)}`
118
+ : `auto→${(s.auto_apply_at ?? "").slice(0, 10)}`
119
+ : "hold";
120
+ return `${s.kind} ${s.id} [${when}] ${s.cluster_name ?? "site"}: ${s.title}`;
121
+ }
122
+
123
+ async function suggestionsList(ctx) {
124
+ const { client, positionals, flags, io } = ctx;
125
+ const collectionId = requirePositional(positionals, 0, "collection_id");
126
+ const result = await client.callTool("list_strategy_suggestions", { collection_id: collectionId });
127
+ printResult(io, flags, result, (r) => {
128
+ const lines = (r.suggestions ?? []).map(formatSuggestionLine);
129
+ if (!lines.length) lines.push("Nothing pending.");
130
+ return lines.join("\n");
131
+ });
132
+ return 0;
133
+ }
134
+
135
+ async function suggestionsDecide(ctx, decision) {
136
+ const { client, positionals, flags } = ctx;
137
+ const kind = requirePositional(positionals, 0, "kind (verdict|proposal)");
138
+ const id = requirePositional(positionals, 1, "id");
139
+ const result = await client.callTool(
140
+ "decide_strategy_suggestion",
141
+ compact({ kind, id, decision, snooze_days: decision === "snooze" ? flagNum(flags.days) : undefined })
142
+ );
143
+ ok(ctx, result.applied ?? `Suggestion ${decision}d.`);
144
+ return 0;
145
+ }
package/lib/commands.mjs CHANGED
@@ -14,6 +14,7 @@ export * from "./commands/authors.mjs";
14
14
  export * from "./commands/flows.mjs";
15
15
  export * from "./commands/connectors.mjs";
16
16
  export * from "./commands/strategy.mjs";
17
+ export * from "./commands/probes.mjs";
17
18
  export * from "./commands/series.mjs";
18
19
  export * from "./commands/insights.mjs";
19
20
  export * from "./commands/covers.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.15.2",
3
+ "version": "0.15.3",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",