@letterstory/cli 0.176.67 → 0.176.69
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 +13 -5
- package/lib/commands/automate.mjs +4 -1
- package/lib/commands/replicate.mjs +23 -2
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -85,7 +85,7 @@ import {
|
|
|
85
85
|
import { fetchParkedSections, withoutParked } from "./parked.mjs";
|
|
86
86
|
|
|
87
87
|
// Matches cli/package.json; publish-cli.yml rewrites both to the published version.
|
|
88
|
-
export const VERSION = "0.176.
|
|
88
|
+
export const VERSION = "0.176.69";
|
|
89
89
|
|
|
90
90
|
/** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
|
|
91
91
|
export const EXIT_PAYMENT_REQUIRED = 3;
|
|
@@ -1970,11 +1970,13 @@ Bench (Benches: open-source benchmarks on their own domains, kept running; @lett
|
|
|
1970
1970
|
Replicate (the Replicator: a website rebuilt as a native Next.js repo, page for page; @letterstory.com only):
|
|
1971
1971
|
replicate <https://site> [--max-pages <n>] [--refine-budget <usd>] [--repo-name <r>] [--repo-owner <o>]
|
|
1972
1972
|
Capture every page, rebuild it, compare it pixel by pixel
|
|
1973
|
-
replicate [list] Your replications: stage, how closely each matches
|
|
1973
|
+
replicate [list] Your replications: stage, how closely each matches, preview link
|
|
1974
1974
|
replicate show <id> [--failing] Pages with their routes and pixel match; collections; events
|
|
1975
1975
|
replicate attach <id> <repo-name> [--repo-owner <o>] The repo to commit it into (yours; Letter never creates it)
|
|
1976
|
-
replicate advance <id> [--retry] [--again]
|
|
1977
|
-
|
|
1976
|
+
replicate advance <id> [--retry] [--again] [--preview]
|
|
1977
|
+
Move it on now; --retry once blocked_on is done; --again replicates from the start;
|
|
1978
|
+
--preview deploys its staging link again
|
|
1979
|
+
replicate archive <id> Stop it and take its preview down; the project stays in storage and in the repo
|
|
1978
1980
|
|
|
1979
1981
|
Evals (how the pipeline is doing on your posts, and the regression cases captured from them):
|
|
1980
1982
|
evals scoreboard [--collection <id>] [--days N] Every measure by stage: posts, failing, rate
|
|
@@ -2146,7 +2148,13 @@ export async function run(argv, io = defaultIo()) {
|
|
|
2146
2148
|
}
|
|
2147
2149
|
|
|
2148
2150
|
try {
|
|
2149
|
-
|
|
2151
|
+
// A subcommand that declares its own `--key`/`--url` (`automate send --key <event id> --url <page>`) keeps them;
|
|
2152
|
+
// they never become the API key or the API's URL (2026-11-08 E2E: a 401 and a "path not found").
|
|
2153
|
+
const owns = handler.ownFlags?.(positionals[1]) ?? [];
|
|
2154
|
+
const config = resolveConfig({
|
|
2155
|
+
url: owns.includes("url") ? undefined : str(flags.url),
|
|
2156
|
+
key: owns.includes("key") ? undefined : str(flags.key),
|
|
2157
|
+
});
|
|
2150
2158
|
// A silent refresh mid-command should persist the new tokens so the next
|
|
2151
2159
|
// invocation doesn't have to refresh again — but only when the config we
|
|
2152
2160
|
// resolved actually came from a saved OAuth session (a --key/env override
|
|
@@ -31,7 +31,7 @@ const TEMPLATES = [
|
|
|
31
31
|
"monthly_page_refresh",
|
|
32
32
|
];
|
|
33
33
|
const UNITS = ["hours", "days", "weeks", "months"];
|
|
34
|
-
const STATUSES = ["pending", "proposed", "acting", "acted", "skipped", "failed", "rejected"];
|
|
34
|
+
const STATUSES = ["pending", "proposed", "acting", "acted", "answered", "skipped", "failed", "rejected"];
|
|
35
35
|
|
|
36
36
|
const triggerParams = {
|
|
37
37
|
object: {
|
|
@@ -211,6 +211,9 @@ export async function cmdAutomate(ctx) {
|
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/** The global flags a subcommand reads as its own arguments, so the CLI never takes them as its key or URL. */
|
|
215
|
+
cmdAutomate.ownFlags = (sub) => (sub === "send" ? ["key", "url"] : []);
|
|
216
|
+
|
|
214
217
|
async function run(ctx, tool, said, extra = {}) {
|
|
215
218
|
const { client, flags, io } = ctx;
|
|
216
219
|
const result = await client.callTool(tool, { ...argsFromFlags(ARGS[tool], flags, ctx.positionals), ...extra });
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// letterstory replicate list
|
|
10
10
|
// letterstory replicate show <id> [--failing]
|
|
11
11
|
// letterstory replicate attach <id> <repo-name> [--repo-owner <account>]
|
|
12
|
-
// letterstory replicate advance <id> [--retry] [--again]
|
|
12
|
+
// letterstory replicate advance <id> [--retry] [--again] [--preview]
|
|
13
13
|
// letterstory replicate archive <id>
|
|
14
14
|
|
|
15
15
|
import { CliError } from "../client.mjs";
|
|
@@ -39,6 +39,7 @@ export const ARGS = {
|
|
|
39
39
|
replication_id: replicationId,
|
|
40
40
|
retry: { flag: "retry", type: "bool" },
|
|
41
41
|
again: { flag: "again", type: "bool" },
|
|
42
|
+
preview: { flag: "preview", type: "bool" },
|
|
42
43
|
},
|
|
43
44
|
archive_replication: { replication_id: replicationId },
|
|
44
45
|
};
|
|
@@ -88,7 +89,7 @@ async function replicationList(ctx) {
|
|
|
88
89
|
x.summary
|
|
89
90
|
? `${x.summary.passing}/${x.summary.replicated} pages match, mean ${pct(x.summary.meanPixel)}`
|
|
90
91
|
: ""
|
|
91
|
-
}`
|
|
92
|
+
}${x.staging_url ? ` ${x.staging_url}` : ""}`
|
|
92
93
|
)
|
|
93
94
|
.join("\n");
|
|
94
95
|
});
|
|
@@ -100,6 +101,7 @@ function headline(x) {
|
|
|
100
101
|
`${x.host} — ${x.status}, stage ${x.stage}`,
|
|
101
102
|
...(x.blocked_on ? [` Blocked: ${x.blocked_on}`, ` Then: replicate advance ${x.id} --retry`] : []),
|
|
102
103
|
...(x.stage_note && !x.blocked_on ? [` ${x.stage_note}`] : []),
|
|
104
|
+
...previewLines(x),
|
|
103
105
|
...(x.summary
|
|
104
106
|
? [
|
|
105
107
|
` ${x.summary.replicated} of ${x.summary.pages} pages replicated; ${x.summary.passing} match the original at every width (mean ${pct(x.summary.meanPixel)})`,
|
|
@@ -129,6 +131,25 @@ function headline(x) {
|
|
|
129
131
|
];
|
|
130
132
|
}
|
|
131
133
|
|
|
134
|
+
// The staging link: the replica live on a Letter domain, to share before (or without) a repo.
|
|
135
|
+
function previewLines(x) {
|
|
136
|
+
if (x.staging_url)
|
|
137
|
+
return [
|
|
138
|
+
` Preview ${x.staging_url}${x.staging_state === "deploying" || x.staging_state === "pending" ? " (redeploying)" : ""}`,
|
|
139
|
+
...(x.staging_state === "failed" && x.staging_error
|
|
140
|
+
? [` Preview redeploy failed: ${x.staging_error}`]
|
|
141
|
+
: []),
|
|
142
|
+
];
|
|
143
|
+
if (x.staging_state === "pending" || x.staging_state === "deploying") return [" Preview deploying…"];
|
|
144
|
+
if (x.staging_state === "failed")
|
|
145
|
+
return [
|
|
146
|
+
` Preview failed: ${x.staging_error ?? "no reason given"}`,
|
|
147
|
+
` Then: replicate advance ${x.id} --preview`,
|
|
148
|
+
];
|
|
149
|
+
if (x.can_deploy_staging && !x.staging_state) return [` No preview yet: replicate advance ${x.id} --preview`];
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
|
|
132
153
|
function replicationShow(ctx, result) {
|
|
133
154
|
printResult(ctx.io, ctx.flags, result, (r) => headline(r.replication).join("\n"));
|
|
134
155
|
return 0;
|