@letterstory/cli 0.125.0 → 0.126.1
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 +23 -2
- package/lib/commands/admin.mjs +42 -2
- package/lib/commands/enclosures.mjs +210 -0
- package/lib/commands/repo.mjs +3 -0
- package/lib/commands/site.mjs +2 -0
- package/lib/commands.mjs +1 -0
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -56,12 +56,13 @@ import {
|
|
|
56
56
|
cmdSite,
|
|
57
57
|
cmdEvals,
|
|
58
58
|
cmdOfferings,
|
|
59
|
+
cmdEnclosures,
|
|
59
60
|
cmdTargets,
|
|
60
61
|
cmdVisits,
|
|
61
62
|
} from "./commands.mjs";
|
|
62
63
|
|
|
63
64
|
// Keep in sync with cli/package.json.
|
|
64
|
-
export const VERSION = "0.
|
|
65
|
+
export const VERSION = "0.126.1";
|
|
65
66
|
|
|
66
67
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
67
68
|
// can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
|
|
@@ -72,6 +73,13 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
72
73
|
"starred",
|
|
73
74
|
// shredder file / arena file: save the version as a candidate beside live.
|
|
74
75
|
"candidate",
|
|
76
|
+
// enclosures create/update: what it needs, and the AI-edited label.
|
|
77
|
+
"browser",
|
|
78
|
+
"image-model",
|
|
79
|
+
"record",
|
|
80
|
+
"stealth",
|
|
81
|
+
"disclosure",
|
|
82
|
+
"no-disclosure",
|
|
75
83
|
// site tree: include children a fold-by-default family would hide; items over the whole subtree.
|
|
76
84
|
"unfold",
|
|
77
85
|
"subtree",
|
|
@@ -96,6 +104,7 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
96
104
|
"own-beat",
|
|
97
105
|
"refresh",
|
|
98
106
|
"preview",
|
|
107
|
+
"with-preview",
|
|
99
108
|
"accept",
|
|
100
109
|
"help",
|
|
101
110
|
"version",
|
|
@@ -523,6 +532,14 @@ Strategy & onboarding:
|
|
|
523
532
|
directives apply <directive_id> --effect <id>... Commit the levers you kept (or --reason to decline them all)
|
|
524
533
|
directives off <directive_id> --reason <why> Stop a live instruction; the reason is read back by the next proposal
|
|
525
534
|
|
|
535
|
+
Enclosures (pictures, clips and sentences made for each prospect; each output is a Prospects column):
|
|
536
|
+
enclosures list The org's enclosures with print counts
|
|
537
|
+
enclosures show <enclosure-id> One enclosure + its versions
|
|
538
|
+
enclosures create --name <n> --output key:shape:Label… [--instructions <text>] [--input website…] [--browser]
|
|
539
|
+
[--login <app-connection-id>] [--tool run_site_audit…] [--skip-when <sentence>]
|
|
540
|
+
enclosures update <enclosure-id> [same flags] Outputs are fixed once a version is in use
|
|
541
|
+
enclosures prints <enclosure-id> [--status <s>] Its current prints, newest first
|
|
542
|
+
|
|
526
543
|
Offerings (context layered org → offering → collection; a layer sets only what it overrides):
|
|
527
544
|
offerings list The org's offerings (things you'd name when recommending them)
|
|
528
545
|
offerings show <offering-id> One offering + its competitor overrides
|
|
@@ -885,6 +902,8 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
885
902
|
| renewals [--days 90]
|
|
886
903
|
| reach-outs [--day YYYY-MM-DD] [--fresh] the day's reach-outs, N of 5 (#crm-reminders' count)
|
|
887
904
|
| track-record [--since YYYY-MM-DD] | at-risk | expansion-signals
|
|
905
|
+
| collections [--org-ids a,b | --account-stages won,active]
|
|
906
|
+
| delivery-flags [--org-ids a,b | --account-stages won,active] [--include collections]
|
|
888
907
|
| case <account-id> [--outcome <outcome-id>]
|
|
889
908
|
| onboard <account-id> --domain acme.com [--name "Acme"] [--site "<direction>"]… [--sites N]
|
|
890
909
|
[--slack a@acme.com,b@acme.com] [--invite a@acme.com[:admin]]… [--no-checklist]
|
|
@@ -1312,8 +1331,9 @@ Repo changes (Claude Code edits your repo in a sandbox; the Letterstory GitHub A
|
|
|
1312
1331
|
repo slack-test Post a test into the Send to Slack channel
|
|
1313
1332
|
repo start --repo <owner/name> --instructions <text>|--instructions-file <path|->
|
|
1314
1333
|
[--branch <base>] [--attach <path>]... [--attach-url <name>=<https url>]...
|
|
1315
|
-
[--action build|build_pr|build_merge|slack|linear] [--wait]
|
|
1334
|
+
[--action build|build_pr|build_merge|slack|linear] [--with-preview] [--wait]
|
|
1316
1335
|
Start a change (attached files go to the sandbox);
|
|
1336
|
+
--with-preview keeps a preview up next to the PR;
|
|
1317
1337
|
--wait follows it to the PR
|
|
1318
1338
|
repo fix-audit --issue <issue-type>... [--audit <id>] [--branch <base>] [--action build|build_pr|build_merge|slack|linear] [--wait]
|
|
1319
1339
|
One PR fixing site-audit issues (repeat --issue to bundle) on every affected page,
|
|
@@ -1417,6 +1437,7 @@ const CLIENT_COMMANDS = {
|
|
|
1417
1437
|
strategy: cmdStrategy,
|
|
1418
1438
|
directives: cmdDirectives,
|
|
1419
1439
|
offerings: cmdOfferings,
|
|
1440
|
+
enclosures: cmdEnclosures,
|
|
1420
1441
|
targets: cmdTargets,
|
|
1421
1442
|
probes: cmdProbes,
|
|
1422
1443
|
suggestions: cmdSuggestions,
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// The old names — evals, eval-add, eval-set, proposals, propose-eval, capture-eval, reject-eval — still work.)
|
|
15
15
|
// admin evals scoreboard|cases|runs|run|triage|guard|retire … (fleet:read / tuning:experiment)
|
|
16
16
|
// admin fleet-experiments list|articles|clients|mark|unmark|new|assign|assign-eligible|assign-orgs|spin-up|apply|start|stop|decide … (fleet:read / fleet:experiment)
|
|
17
|
-
// admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|reach-outs|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (crm:read / crm:write)
|
|
17
|
+
// admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|reach-outs|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|collections|delivery-flags|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (crm:read / crm:write)
|
|
18
18
|
// admin spend summary|reconcile|pnl|entries|add|import|usage|remove|reference|stripe-sync|services|service … (spend:read / spend:write)
|
|
19
19
|
// admin brand-detection <org-id> (fleet:read)
|
|
20
20
|
// admin brand-detection <org-id> [--term t]... [--exact t]... [--exclude p]... [--note "…"] | --clear [--note "…"] (fleet:instrument)
|
|
@@ -3572,6 +3572,46 @@ async function cmdAdminCrm(ctx) {
|
|
|
3572
3572
|
: "(no next-product verdicts)"
|
|
3573
3573
|
);
|
|
3574
3574
|
}
|
|
3575
|
+
case "collections": {
|
|
3576
|
+
// admin crm collections [--org-ids a,b | --account-stages won,active] — what we publish for each client.
|
|
3577
|
+
const params = new URLSearchParams(
|
|
3578
|
+
compact({ org_ids: flagStr(flags["org-ids"]), account_stages: flagStr(flags["account-stages"]) })
|
|
3579
|
+
);
|
|
3580
|
+
return out(await staffRequest(ctx, "GET", `${CRM}/collections?${params}`), (r) =>
|
|
3581
|
+
r.orgs.length
|
|
3582
|
+
? r.orgs
|
|
3583
|
+
.map(
|
|
3584
|
+
(o) =>
|
|
3585
|
+
`${o.orgName} ${o.phantomCount} phantom · ${o.mainBlogCount} blog · ${o.postsLast30d} posts in 30d${o.internal.value ? ` (${o.internal.label ?? o.internal.source})` : ""}${o.issues.length ? ` ${o.issues.map((i) => i.message).join("; ")}` : ""} ${o.orgId}`
|
|
3586
|
+
)
|
|
3587
|
+
.join("\n")
|
|
3588
|
+
: "(no org with a collection in that scope)"
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
case "delivery-flags": {
|
|
3592
|
+
// admin crm delivery-flags [--org-ids a,b | --account-stages won,active] [--include collections]
|
|
3593
|
+
// — does what we spend on a client match what they pay? Findings per org, worst first.
|
|
3594
|
+
const params = new URLSearchParams(
|
|
3595
|
+
compact({
|
|
3596
|
+
org_ids: flagStr(flags["org-ids"]),
|
|
3597
|
+
account_stages: flagStr(flags["account-stages"]),
|
|
3598
|
+
include: flagStr(flags.include),
|
|
3599
|
+
})
|
|
3600
|
+
);
|
|
3601
|
+
return out(await staffRequest(ctx, "GET", `${CRM}/delivery-flags?${params}`), (r) => {
|
|
3602
|
+
if (!r.accounts)
|
|
3603
|
+
return "Billing cannot say who pays yet, so there are no flags (collections are in --json).";
|
|
3604
|
+
const flagged = r.accounts.filter((a) => a.findings.length);
|
|
3605
|
+
return flagged.length
|
|
3606
|
+
? flagged
|
|
3607
|
+
.map(
|
|
3608
|
+
(a) =>
|
|
3609
|
+
`${a.owedDelivery ? "owed " : a.notPaying ? "unpaid" : " "} ${a.orgName} ${a.findings.map((f) => f.message).join("; ")} ${a.orgId}`
|
|
3610
|
+
)
|
|
3611
|
+
.join("\n")
|
|
3612
|
+
: `(${r.accounts.length} org${r.accounts.length === 1 ? "" : "s"}, nothing flagged)`;
|
|
3613
|
+
});
|
|
3614
|
+
}
|
|
3575
3615
|
case "case": {
|
|
3576
3616
|
// admin crm case <account-id> [--outcome <id>] — the 90 days before an outcome, or before today.
|
|
3577
3617
|
if (!id) throw new CliError("Usage: admin crm case <account-id> [--outcome <outcome-id>]");
|
|
@@ -3650,7 +3690,7 @@ async function cmdAdminCrm(ctx) {
|
|
|
3650
3690
|
}
|
|
3651
3691
|
default:
|
|
3652
3692
|
throw new CliError(
|
|
3653
|
-
"Usage: admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|reach-outs|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (see --help)"
|
|
3693
|
+
"Usage: admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|reach-outs|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|collections|delivery-flags|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (see --help)"
|
|
3654
3694
|
);
|
|
3655
3695
|
}
|
|
3656
3696
|
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// `enclosures` — pictures, clips and sentences made for each prospect (generated
|
|
2
|
+
// prospect columns). Each output IS a Prospects column that sequence emails read as
|
|
3
|
+
// {{custom:<key>}}. Thin wrappers over the MCP tools, which call the same store functions
|
|
4
|
+
// the app's /api/generators routes do.
|
|
5
|
+
|
|
6
|
+
import { CliError } from "../client.mjs";
|
|
7
|
+
import {
|
|
8
|
+
flagStr,
|
|
9
|
+
flagNum,
|
|
10
|
+
flagList,
|
|
11
|
+
requirePositional,
|
|
12
|
+
printResult,
|
|
13
|
+
argsFromFlags,
|
|
14
|
+
refuseUnknownFlags,
|
|
15
|
+
readTextInput,
|
|
16
|
+
ok,
|
|
17
|
+
} from "./shared.mjs";
|
|
18
|
+
|
|
19
|
+
const SHAPES = ["text", "image", "animation", "video"];
|
|
20
|
+
|
|
21
|
+
// `--output key:shape:Label` (repeatable), e.g. --output audit_shot:image:"Site audit".
|
|
22
|
+
function readOutputs(flags) {
|
|
23
|
+
const raw = flagList(flags.output);
|
|
24
|
+
if (!raw.length) return undefined;
|
|
25
|
+
return raw.map((entry) => {
|
|
26
|
+
const [key, shape, ...label] = entry.split(":");
|
|
27
|
+
if (!key || !SHAPES.includes(shape) || !label.length) {
|
|
28
|
+
throw new CliError(
|
|
29
|
+
`--output takes key:shape:Label with shape one of ${SHAPES.join(", ")} (got "${entry}")`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return { key, shape, label: label.join(":") };
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// --browser, --login <app-connection-id>, --stealth, --record, --region, --image-model, --tool <op>…
|
|
37
|
+
function readNeeds(flags) {
|
|
38
|
+
const browser = {};
|
|
39
|
+
if (flagStr(flags.login)) browser.login = flagStr(flags.login);
|
|
40
|
+
if (flags.stealth === true) browser.stealth = true;
|
|
41
|
+
if (flags.record === true) browser.record = true;
|
|
42
|
+
if (flagStr(flags.region)) browser.region = flagStr(flags.region);
|
|
43
|
+
const needs = {};
|
|
44
|
+
if (flags.browser === true || Object.keys(browser).length) needs.browser = browser;
|
|
45
|
+
if (flags["image-model"] === true) needs.image_model = true;
|
|
46
|
+
const tools = flagList(flags.tool);
|
|
47
|
+
if (tools.length) needs.tools = tools;
|
|
48
|
+
return Object.keys(needs).length ? needs : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const inputs = (flags) => {
|
|
52
|
+
const v = flagList(flags.input);
|
|
53
|
+
return v.length ? v : undefined;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const fields = {
|
|
57
|
+
name: "name",
|
|
58
|
+
instructions: { value: (flags) => readTextInput(flags, "instructions", "instructions-file") },
|
|
59
|
+
inputs: { value: inputs },
|
|
60
|
+
outputs: { value: readOutputs },
|
|
61
|
+
needs: { value: readNeeds },
|
|
62
|
+
cache_scope: { flag: "share", enum: ["prospect", "company_domain"] },
|
|
63
|
+
freshness_days: { flag: "fresh-days", type: "num" },
|
|
64
|
+
budget_per_person_usd: { flag: "budget", type: "num" },
|
|
65
|
+
no_fit_rule: "skip-when",
|
|
66
|
+
disclosure: { flag: "disclosure", type: "bool", negate: "no-disclosure" },
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Flags the computed sources above read (refuseUnknownFlags can't see inside `value`).
|
|
70
|
+
const FIELD_FLAGS = [
|
|
71
|
+
"instructions",
|
|
72
|
+
"instructions-file",
|
|
73
|
+
"input",
|
|
74
|
+
"output",
|
|
75
|
+
"browser",
|
|
76
|
+
"login",
|
|
77
|
+
"stealth",
|
|
78
|
+
"record",
|
|
79
|
+
"region",
|
|
80
|
+
"image-model",
|
|
81
|
+
"tool",
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
// How every tool this module calls gets its arguments — see `argsFromFlags` in shared.mjs.
|
|
85
|
+
// `scripts/parity-check.ts` compares these keys against each tool's published input schema.
|
|
86
|
+
export const ARGS = {
|
|
87
|
+
list_generators: {},
|
|
88
|
+
get_generator: {
|
|
89
|
+
generator_id: { positional: 0, label: "enclosure-id", required: true },
|
|
90
|
+
},
|
|
91
|
+
create_generator: {
|
|
92
|
+
key: "key",
|
|
93
|
+
...fields,
|
|
94
|
+
name: { flag: "name", required: true },
|
|
95
|
+
},
|
|
96
|
+
update_generator: {
|
|
97
|
+
generator_id: { positional: 0, label: "enclosure-id", required: true },
|
|
98
|
+
...fields,
|
|
99
|
+
},
|
|
100
|
+
list_generations: {
|
|
101
|
+
generator_id: { positional: 0, label: "enclosure-id", required: true },
|
|
102
|
+
status: { flag: "status", enum: ["queued", "running", "done", "no_fit", "failed", "skipped"] },
|
|
103
|
+
limit: { flag: "limit", type: "num" },
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const USAGE = `Usage: enclosures <list|show|create|update|prints>
|
|
108
|
+
enclosures list
|
|
109
|
+
enclosures show <enclosure-id>
|
|
110
|
+
enclosures create --name <n> --output key:shape:Label… [--key <k>] [--instructions <text>|--instructions-file <path>]
|
|
111
|
+
[--input website…] [--browser] [--login <app-connection-id>] [--stealth] [--record] [--region us-east|eu-west]
|
|
112
|
+
[--image-model] [--tool run_site_audit…] [--share prospect|company_domain] [--fresh-days <n>]
|
|
113
|
+
[--budget <usd>] [--skip-when <sentence>] [--no-disclosure]
|
|
114
|
+
enclosures update <enclosure-id> [same flags]
|
|
115
|
+
enclosures prints <enclosure-id> [--status done|failed|no_fit|…] [--limit <n>]`;
|
|
116
|
+
|
|
117
|
+
export async function cmdEnclosures(ctx) {
|
|
118
|
+
const sub = ctx.positionals[0];
|
|
119
|
+
const rest = { ...ctx, positionals: ctx.positionals.slice(1) };
|
|
120
|
+
switch (sub) {
|
|
121
|
+
case "list":
|
|
122
|
+
case "ls":
|
|
123
|
+
return enclosuresList(rest);
|
|
124
|
+
case "show":
|
|
125
|
+
case "get":
|
|
126
|
+
return enclosuresShow(rest);
|
|
127
|
+
case "create":
|
|
128
|
+
return enclosuresCreate(rest);
|
|
129
|
+
case "update":
|
|
130
|
+
return enclosuresUpdate(rest);
|
|
131
|
+
case "prints":
|
|
132
|
+
return enclosuresPrints(rest);
|
|
133
|
+
default:
|
|
134
|
+
throw new CliError(USAGE);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function formatEnclosure(g) {
|
|
139
|
+
const c = g.counts ?? {};
|
|
140
|
+
const lines = [
|
|
141
|
+
`${g.id} ${g.key} ${g.name} [${g.status}${g.current_version ? `, version ${g.current_version}` : ""}]`,
|
|
142
|
+
];
|
|
143
|
+
lines.push(` columns: ${(g.outputs ?? []).map((o) => `${o.label} {{custom:${o.key}}} (${o.shape})`).join(", ")}`);
|
|
144
|
+
if (g.inputs?.length) lines.push(` reads: ${g.inputs.join(", ")}`);
|
|
145
|
+
lines.push(
|
|
146
|
+
` prints: ${c.done ?? 0} ready, ${(c.queued ?? 0) + (c.running ?? 0)} making, ${c.no_fit ?? 0} no fit, ${c.failed ?? 0} failed`
|
|
147
|
+
);
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function enclosuresList(ctx) {
|
|
152
|
+
const { client, flags, io } = ctx;
|
|
153
|
+
const result = await client.callTool("list_generators", argsFromFlags(ARGS.list_generators, flags));
|
|
154
|
+
printResult(io, flags, result, (r) => {
|
|
155
|
+
const all = r.generators ?? [];
|
|
156
|
+
if (!all.length) return "No enclosures yet.";
|
|
157
|
+
return all.map(formatEnclosure).join("\n\n");
|
|
158
|
+
});
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function enclosuresShow(ctx) {
|
|
163
|
+
const { client, flags, positionals, io } = ctx;
|
|
164
|
+
const result = await client.callTool("get_generator", argsFromFlags(ARGS.get_generator, flags, positionals));
|
|
165
|
+
printResult(io, flags, result, (r) => {
|
|
166
|
+
const lines = [formatEnclosure(r.generator)];
|
|
167
|
+
for (const v of r.generator.versions ?? []) {
|
|
168
|
+
lines.push(
|
|
169
|
+
` version ${v.version} (${v.author}): ${v.steps} steps${v.change_summary ? `, ${v.change_summary}` : ""}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
});
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function enclosuresCreate(ctx) {
|
|
178
|
+
const { client, flags, positionals, io } = ctx;
|
|
179
|
+
refuseUnknownFlags(ctx, ARGS.create_generator, FIELD_FLAGS);
|
|
180
|
+
const result = await client.callTool("create_generator", argsFromFlags(ARGS.create_generator, flags, positionals));
|
|
181
|
+
ok(ctx, `Created ${result.generator?.name} (${result.generator?.id}).`);
|
|
182
|
+
printResult(io, flags, result, (r) => formatEnclosure(r.generator));
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function enclosuresUpdate(ctx) {
|
|
187
|
+
const { client, flags, positionals, io } = ctx;
|
|
188
|
+
refuseUnknownFlags(ctx, ARGS.update_generator, FIELD_FLAGS);
|
|
189
|
+
const args = argsFromFlags(ARGS.update_generator, flags, positionals);
|
|
190
|
+
if (Object.keys(args).length === 1) throw new CliError("Nothing to update. Pass a field flag.");
|
|
191
|
+
const result = await client.callTool("update_generator", args);
|
|
192
|
+
ok(ctx, `Updated ${result.generator?.name}.`);
|
|
193
|
+
printResult(io, flags, result, (r) => formatEnclosure(r.generator));
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function enclosuresPrints(ctx) {
|
|
198
|
+
const { client, flags, positionals, io } = ctx;
|
|
199
|
+
requirePositional(positionals, 0, "enclosure-id");
|
|
200
|
+
if (flags.limit !== undefined) flagNum(flags.limit);
|
|
201
|
+
const result = await client.callTool("list_generations", argsFromFlags(ARGS.list_generations, flags, positionals));
|
|
202
|
+
printResult(io, flags, result, (r) => {
|
|
203
|
+
const all = r.generations ?? [];
|
|
204
|
+
if (!all.length) return "No prints yet.";
|
|
205
|
+
return all
|
|
206
|
+
.map((g) => `${g.status.padEnd(8)} ${g.prospect?.email ?? g.prospect_id}${g.error ? ` ${g.error}` : ""}`)
|
|
207
|
+
.join("\n");
|
|
208
|
+
});
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
package/lib/commands/repo.mjs
CHANGED
|
@@ -63,6 +63,8 @@ const ARGS = {
|
|
|
63
63
|
files: { value: (_flags, _positionals, extra) => (extra.files?.length ? extra.files : undefined) },
|
|
64
64
|
action: { flag: "action", enum: ["build", "build_pr", "build_merge", "slack", "linear"] },
|
|
65
65
|
preview: { flag: "preview", type: "bool" },
|
|
66
|
+
// --with-preview: the PR opens straight away and a preview of the change stays up next to it.
|
|
67
|
+
with_preview: { flag: "with-preview", type: "bool" },
|
|
66
68
|
},
|
|
67
69
|
create_repo_change_upload: { file_names: { internal: "the basenames of the --attach files" } },
|
|
68
70
|
list_repo_sites: {},
|
|
@@ -320,6 +322,7 @@ async function repoStart(ctx) {
|
|
|
320
322
|
"attach-url",
|
|
321
323
|
"action",
|
|
322
324
|
"preview",
|
|
325
|
+
"with-preview",
|
|
323
326
|
"wait",
|
|
324
327
|
]);
|
|
325
328
|
const files = [
|
package/lib/commands/site.mjs
CHANGED
|
@@ -178,6 +178,8 @@ const ARGS = {
|
|
|
178
178
|
base_branch: { flag: "base-branch" },
|
|
179
179
|
preview: { flag: "preview", type: "bool" },
|
|
180
180
|
action: { flag: "action", enum: ["build", "build_pr", "build_merge", "slack", "linear"] },
|
|
181
|
+
// --with-preview: the PR opens straight away and a preview of the fix stays up next to it.
|
|
182
|
+
with_preview: { flag: "with-preview", type: "bool" },
|
|
181
183
|
},
|
|
182
184
|
};
|
|
183
185
|
|
package/lib/commands.mjs
CHANGED
|
@@ -38,6 +38,7 @@ export * from "./commands/enhance.mjs";
|
|
|
38
38
|
export * from "./commands/landings.mjs";
|
|
39
39
|
export * from "./commands/outbound.mjs";
|
|
40
40
|
export * from "./commands/offerings.mjs";
|
|
41
|
+
export * from "./commands/enclosures.mjs";
|
|
41
42
|
export * from "./commands/targets.mjs";
|
|
42
43
|
export * from "./commands/admin.mjs";
|
|
43
44
|
export * from "./commands/feedback.mjs";
|