@letterstory/cli 0.15.1 → 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 +12 -2
- package/lib/commands/admin.mjs +2 -1
- package/lib/commands/onboard.mjs +1 -0
- package/lib/commands/probes.mjs +145 -0
- package/lib/commands.mjs +1 -0
- package/package.json +1 -1
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.
|
|
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
|
|
@@ -325,7 +333,7 @@ Domain onboarding (ONE SHOT: a bare domain in, a fully-configured organization o
|
|
|
325
333
|
[--name "<main collection name>"] [--posts N] [--no-phantom] [--phantom-name X]
|
|
326
334
|
[--site-domain host] [--domain-mode subdomain|buy_now|connect_later]
|
|
327
335
|
[--seers suggest|skip] [--no-visuals] [--no-enhance] [--test]
|
|
328
|
-
[--readiness-minutes N] [--watch]
|
|
336
|
+
[--readiness-minutes N] [--client-email jo@acme.com] [--watch]
|
|
329
337
|
On the org behind the key (its registered
|
|
330
338
|
domain): onboard the main blog (the
|
|
331
339
|
collection recipe), infer org visuals from
|
|
@@ -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,
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// admin create-org --domain acme.com [--name "Acme"] [--test] [--no-key] [--key-name N]
|
|
7
7
|
// [--capabilities a,b] [--onboard] [--about "…"] [--sitemap <url>]
|
|
8
8
|
// [--cms <provider>] [--posts N] [--seers suggest|skip] [--no-visuals]
|
|
9
|
-
// [--no-enhance] [--readiness-minutes N] [--watch]
|
|
9
|
+
// [--no-enhance] [--readiness-minutes N] [--client-email jo@acme.com] [--watch]
|
|
10
10
|
//
|
|
11
11
|
// The KEY EXCHANGE: create the client org from its domain (one org per domain; an existing
|
|
12
12
|
// owner is adopted), mint an ORG-scoped API key for it and print the plaintext ONCE. With
|
|
@@ -79,6 +79,7 @@ function onboardOptionsFromFlags(flags) {
|
|
|
79
79
|
visuals: flagBool(flags["no-visuals"]) ? false : undefined,
|
|
80
80
|
enhance: flagBool(flags["no-enhance"]) ? false : undefined,
|
|
81
81
|
readiness_minutes: flagNum(flags["readiness-minutes"]),
|
|
82
|
+
client_email: flagStr(flags["client-email"]),
|
|
82
83
|
});
|
|
83
84
|
return compact({
|
|
84
85
|
direction: flagStr(flags.about) ?? flagStr(flags.direction),
|
package/lib/commands/onboard.mjs
CHANGED
|
@@ -342,6 +342,7 @@ async function cmdOnboardDomain(ctx) {
|
|
|
342
342
|
enhance: flagBool(flags["no-enhance"]) ? false : undefined,
|
|
343
343
|
is_test: flagBool(flags.test) ? true : undefined,
|
|
344
344
|
readiness_minutes: flagNum(flags["readiness-minutes"]),
|
|
345
|
+
client_email: flagStr(flags["client-email"]),
|
|
345
346
|
});
|
|
346
347
|
|
|
347
348
|
ok(ctx, "Starting domain onboarding…");
|
|
@@ -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";
|