frontpage-host 0.1.0 → 0.1.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/AGENTS.md +159 -0
- package/README.md +56 -0
- package/dist/bin.js +32 -5
- package/dist/commands/deploy.js +18 -9
- package/dist/commands/diff.js +33 -23
- package/dist/commands/doctor.js +34 -9
- package/dist/commands/help.js +70 -9
- package/dist/commands/history.js +10 -7
- package/dist/commands/ls.js +7 -3
- package/dist/commands/open.js +16 -12
- package/dist/commands/pages.js +10 -5
- package/dist/commands/prompt.js +13 -10
- package/dist/commands/publish.js +21 -9
- package/dist/commands/pull.js +21 -11
- package/dist/commands/push.js +15 -7
- package/dist/commands/revert.js +15 -10
- package/dist/commands/runs.js +52 -24
- package/dist/commands/sites.js +8 -3
- package/dist/commands/status.js +20 -5
- package/dist/commands/whoami.js +12 -6
- package/dist/completions/generate.js +5 -4
- package/dist/flags.d.ts +13 -0
- package/dist/flags.js +31 -0
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js +325 -46
- package/dist/runtime.d.ts +22 -0
- package/dist/runtime.js +73 -0
- package/llms.txt +12 -0
- package/package.json +5 -2
package/dist/commands/open.js
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { resolveSlug } from "../site.js";
|
|
3
|
-
import { EXIT_OK, EXIT_USAGE
|
|
3
|
+
import { EXIT_OK, EXIT_USAGE } from "../http/client.js";
|
|
4
|
+
import { emitErr, emitOk, emitUsage, isJson, isQuiet } from "../runtime.js";
|
|
4
5
|
export async function runOpen(args) {
|
|
5
6
|
try {
|
|
6
7
|
const { slug, rest } = await resolveSlug(args);
|
|
7
8
|
const prod = rest.includes("--prod") || args.includes("--prod");
|
|
8
|
-
const url =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const url = `https://${slug}.frontpage.host/`;
|
|
10
|
+
// --prod is reserved for a future production custom-domain lookup; both
|
|
11
|
+
// modes currently open the site subdomain on *.frontpage.host.
|
|
12
|
+
if (prod && !isJson() && !isQuiet()) {
|
|
13
|
+
console.error("Note: --prod is a no-op stub; opening https://<slug>.frontpage.host/");
|
|
14
|
+
}
|
|
14
15
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
15
16
|
const openerArgs = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
16
17
|
spawn(opener, openerArgs, { detached: true, stdio: "ignore" }).unref();
|
|
17
|
-
|
|
18
|
+
if (isJson()) {
|
|
19
|
+
emitOk("open", { slug, url, prodRequested: prod, prodNoOp: true });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(url);
|
|
23
|
+
}
|
|
18
24
|
return EXIT_OK;
|
|
19
25
|
}
|
|
20
26
|
catch (err) {
|
|
21
27
|
if (err instanceof Error && err.message.includes("Usage")) {
|
|
22
|
-
|
|
23
|
-
return EXIT_USAGE;
|
|
28
|
+
return emitUsage("open", "Usage: frontpage open [--site <slug>] [--prod]", EXIT_USAGE);
|
|
24
29
|
}
|
|
25
|
-
|
|
26
|
-
return exitCodeForError(err);
|
|
30
|
+
return emitErr("open", err);
|
|
27
31
|
}
|
|
28
32
|
}
|
package/dist/commands/pages.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
|
-
import { EXIT_OK,
|
|
2
|
+
import { EXIT_OK, v1Get } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, isJson } from "../runtime.js";
|
|
3
4
|
export async function runPages(args) {
|
|
4
5
|
try {
|
|
5
6
|
const { slug } = await resolveSlug(args);
|
|
6
7
|
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/pages`);
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
if (isJson()) {
|
|
9
|
+
emitOk("pages", { slug, pages: data.pages });
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
for (const p of data.pages) {
|
|
13
|
+
console.log(`${p.path.padEnd(40)} ${p.title}`);
|
|
14
|
+
}
|
|
9
15
|
}
|
|
10
16
|
return EXIT_OK;
|
|
11
17
|
}
|
|
12
18
|
catch (err) {
|
|
13
|
-
|
|
14
|
-
return exitCodeForError(err);
|
|
19
|
+
return emitErr("pages", err);
|
|
15
20
|
}
|
|
16
21
|
}
|
package/dist/commands/prompt.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
|
-
import { EXIT_OK, EXIT_USAGE,
|
|
2
|
+
import { EXIT_OK, EXIT_USAGE, v1Post } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, emitUsage, isJson } from "../runtime.js";
|
|
3
4
|
export async function runPrompt(args) {
|
|
4
5
|
try {
|
|
5
6
|
const { slug, rest } = await resolveSlug(args);
|
|
@@ -19,21 +20,23 @@ export async function runPrompt(args) {
|
|
|
19
20
|
}
|
|
20
21
|
const prompt = promptParts.join(" ").trim();
|
|
21
22
|
if (!prompt) {
|
|
22
|
-
|
|
23
|
-
return EXIT_USAGE;
|
|
23
|
+
return emitUsage("prompt", 'Usage: frontpage prompt "..." [--site <slug>] [--path /page]', EXIT_USAGE);
|
|
24
24
|
}
|
|
25
25
|
if (!currentPath.startsWith("/")) {
|
|
26
|
-
|
|
27
|
-
return EXIT_USAGE;
|
|
26
|
+
return emitUsage("prompt", "currentPath must start with /", EXIT_USAGE);
|
|
28
27
|
}
|
|
29
28
|
const data = await v1Post(`/api/v1/sites/${encodeURIComponent(slug)}/agent-runs`, { prompt, currentPath });
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
if (isJson()) {
|
|
30
|
+
emitOk("prompt", { slug, ...data });
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log(data.runId);
|
|
34
|
+
if (data.coalesced)
|
|
35
|
+
console.error("(coalesced with an identical queued run)");
|
|
36
|
+
}
|
|
33
37
|
return EXIT_OK;
|
|
34
38
|
}
|
|
35
39
|
catch (err) {
|
|
36
|
-
|
|
37
|
-
return exitCodeForError(err);
|
|
40
|
+
return emitErr("prompt", err);
|
|
38
41
|
}
|
|
39
42
|
}
|
package/dist/commands/publish.js
CHANGED
|
@@ -1,28 +1,40 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
|
-
import { EXIT_OK,
|
|
2
|
+
import { EXIT_OK, EXIT_USAGE, v1Delete, v1Post } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, emitUsage, isJson, requireYesOrTty } from "../runtime.js";
|
|
3
4
|
export async function runPublish(args) {
|
|
4
5
|
try {
|
|
5
6
|
const { slug } = await resolveSlug(args);
|
|
6
7
|
const data = await v1Post(`/api/v1/sites/${encodeURIComponent(slug)}/publish`);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if (isJson()) {
|
|
9
|
+
emitOk("publish", { slug, productionUrl: data.productionUrl ?? null });
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.log(`Published ${slug}`);
|
|
13
|
+
if (data.productionUrl)
|
|
14
|
+
console.log(data.productionUrl);
|
|
15
|
+
}
|
|
10
16
|
return EXIT_OK;
|
|
11
17
|
}
|
|
12
18
|
catch (err) {
|
|
13
|
-
|
|
14
|
-
return exitCodeForError(err);
|
|
19
|
+
return emitErr("publish", err);
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
22
|
export async function runUnpublish(args) {
|
|
18
23
|
try {
|
|
24
|
+
const refuse = requireYesOrTty("unpublish");
|
|
25
|
+
if (refuse)
|
|
26
|
+
return emitUsage("unpublish", refuse, EXIT_USAGE);
|
|
19
27
|
const { slug } = await resolveSlug(args);
|
|
20
28
|
await v1Delete(`/api/v1/sites/${encodeURIComponent(slug)}/publish`);
|
|
21
|
-
|
|
29
|
+
if (isJson()) {
|
|
30
|
+
emitOk("unpublish", { slug });
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log(`Unpublished ${slug}`);
|
|
34
|
+
}
|
|
22
35
|
return EXIT_OK;
|
|
23
36
|
}
|
|
24
37
|
catch (err) {
|
|
25
|
-
|
|
26
|
-
return exitCodeForError(err);
|
|
38
|
+
return emitErr("unpublish", err);
|
|
27
39
|
}
|
|
28
40
|
}
|
package/dist/commands/pull.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, resolve, sep } from "node:path";
|
|
3
3
|
import { resolveSlug } from "../site.js";
|
|
4
|
-
import { EXIT_OK, EXIT_UNEXPECTED,
|
|
4
|
+
import { EXIT_OK, EXIT_UNEXPECTED, v1Get } from "../http/client.js";
|
|
5
5
|
import { readState, writeState } from "../state/frontpage-state.js";
|
|
6
|
+
import { emitErr, emitOk, emitUsage, isJson } from "../runtime.js";
|
|
6
7
|
/** Reject absolute / traversal paths before writing into cwd (defense in depth). */
|
|
7
8
|
function assertSafePullPath(repoPath, cwd) {
|
|
8
9
|
if (!repoPath ||
|
|
@@ -31,8 +32,7 @@ export async function runPull(args) {
|
|
|
31
32
|
abs = assertSafePullPath(file.path, cwd);
|
|
32
33
|
}
|
|
33
34
|
catch (err) {
|
|
34
|
-
|
|
35
|
-
return EXIT_UNEXPECTED;
|
|
35
|
+
return emitUsage("pull", err instanceof Error ? err.message : String(err), EXIT_UNEXPECTED);
|
|
36
36
|
}
|
|
37
37
|
await mkdir(dirname(abs), { recursive: true });
|
|
38
38
|
if (file.encoding === "base64") {
|
|
@@ -45,16 +45,26 @@ export async function runPull(args) {
|
|
|
45
45
|
}
|
|
46
46
|
const prev = await readState(cwd);
|
|
47
47
|
await writeState({ ...prev, slug: data.slug, baseCommitSha: data.baseCommitSha ?? undefined }, cwd);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
if (isJson()) {
|
|
49
|
+
emitOk("pull", {
|
|
50
|
+
slug: data.slug,
|
|
51
|
+
baseCommitSha: data.baseCommitSha,
|
|
52
|
+
written,
|
|
53
|
+
fileCount: data.fileCount,
|
|
54
|
+
truncated: data.truncated,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.log(`Pulled ${written} file(s) for ${data.slug}`);
|
|
59
|
+
if (data.baseCommitSha)
|
|
60
|
+
console.log(`baseCommitSha: ${data.baseCommitSha}`);
|
|
61
|
+
if (data.truncated)
|
|
62
|
+
console.log("Warning: pull truncated (file or size cap). Re-run or narrow the tree.");
|
|
63
|
+
console.log("Wrote .frontpage/state.json");
|
|
64
|
+
}
|
|
54
65
|
return EXIT_OK;
|
|
55
66
|
}
|
|
56
67
|
catch (err) {
|
|
57
|
-
|
|
58
|
-
return exitCodeForError(err);
|
|
68
|
+
return emitErr("pull", err);
|
|
59
69
|
}
|
|
60
70
|
}
|
package/dist/commands/push.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
2
|
import { join, relative, sep } from "node:path";
|
|
3
3
|
import { resolveSlug } from "../site.js";
|
|
4
|
-
import { EXIT_OK, EXIT_USAGE,
|
|
4
|
+
import { EXIT_OK, EXIT_USAGE, v1Put } from "../http/client.js";
|
|
5
5
|
import { readState, writeState } from "../state/frontpage-state.js";
|
|
6
|
+
import { emitErr, emitOk, emitUsage, isJson } from "../runtime.js";
|
|
6
7
|
const TEXT_EXTS = new Set([
|
|
7
8
|
".astro",
|
|
8
9
|
".ts",
|
|
@@ -68,13 +69,11 @@ export async function runPush(args) {
|
|
|
68
69
|
const cwd = process.cwd();
|
|
69
70
|
const state = await readState(cwd);
|
|
70
71
|
if (!state.baseCommitSha) {
|
|
71
|
-
|
|
72
|
-
return EXIT_USAGE;
|
|
72
|
+
return emitUsage("push", "No baseCommitSha in .frontpage/state.json. Run: frontpage pull", EXIT_USAGE);
|
|
73
73
|
}
|
|
74
74
|
const paths = await walkAllowlisted(cwd);
|
|
75
75
|
if (paths.length === 0) {
|
|
76
|
-
|
|
77
|
-
return EXIT_USAGE;
|
|
76
|
+
return emitUsage("push", "No allowlisted files (src/, public/, content/) found in this folder.", EXIT_USAGE);
|
|
78
77
|
}
|
|
79
78
|
const files = [];
|
|
80
79
|
for (const path of paths) {
|
|
@@ -100,6 +99,16 @@ export async function runPush(args) {
|
|
|
100
99
|
if (data.commitSha) {
|
|
101
100
|
await writeState({ ...state, slug, baseCommitSha: data.commitSha }, cwd);
|
|
102
101
|
}
|
|
102
|
+
if (isJson()) {
|
|
103
|
+
emitOk("push", {
|
|
104
|
+
slug,
|
|
105
|
+
changed: data.changed,
|
|
106
|
+
commitSha: data.commitSha,
|
|
107
|
+
baseCommitSha: data.baseCommitSha,
|
|
108
|
+
filesChanged: data.filesChanged,
|
|
109
|
+
});
|
|
110
|
+
return EXIT_OK;
|
|
111
|
+
}
|
|
103
112
|
if (!data.changed) {
|
|
104
113
|
console.log("Nothing to commit (remote already matches).");
|
|
105
114
|
return EXIT_OK;
|
|
@@ -111,7 +120,6 @@ export async function runPush(args) {
|
|
|
111
120
|
return EXIT_OK;
|
|
112
121
|
}
|
|
113
122
|
catch (err) {
|
|
114
|
-
|
|
115
|
-
return exitCodeForError(err);
|
|
123
|
+
return emitErr("push", err);
|
|
116
124
|
}
|
|
117
125
|
}
|
package/dist/commands/revert.js
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
|
-
import { EXIT_OK, EXIT_USAGE,
|
|
2
|
+
import { EXIT_OK, EXIT_USAGE, v1Post } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, emitUsage, isJson, requireYesOrTty } from "../runtime.js";
|
|
3
4
|
export async function runRevert(args) {
|
|
4
5
|
try {
|
|
6
|
+
const refuse = requireYesOrTty("revert");
|
|
7
|
+
if (refuse)
|
|
8
|
+
return emitUsage("revert", refuse, EXIT_USAGE);
|
|
5
9
|
const { slug, rest } = await resolveSlug(args);
|
|
6
10
|
const target = rest.find((a) => !a.startsWith("-"));
|
|
7
11
|
if (!target || !/^[0-9a-f]{7,40}$/i.test(target)) {
|
|
8
|
-
|
|
9
|
-
console.error("Pass a full 40-char SHA from `frontpage history`.");
|
|
10
|
-
return EXIT_USAGE;
|
|
12
|
+
return emitUsage("revert", "Usage: frontpage revert <commitSha> [--site <slug>] [--yes]\nPass a full 40-char SHA from `frontpage history`.", EXIT_USAGE);
|
|
11
13
|
}
|
|
12
14
|
if (target.length !== 40) {
|
|
13
|
-
|
|
14
|
-
return EXIT_USAGE;
|
|
15
|
+
return emitUsage("revert", "targetCommitSha must be a full 40-char hex SHA (not a short SHA).", EXIT_USAGE);
|
|
15
16
|
}
|
|
16
17
|
const data = await v1Post(`/api/v1/sites/${encodeURIComponent(slug)}/revert`, {
|
|
17
18
|
targetCommitSha: target.toLowerCase(),
|
|
18
19
|
});
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
if (isJson()) {
|
|
21
|
+
emitOk("revert", { slug, ...data });
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log(`${data.commitHash.slice(0, 7)} ${data.message}`);
|
|
25
|
+
console.log(`restored ${data.targetCommitSha.slice(0, 7)} (was ${data.previousTipSha.slice(0, 7)})`);
|
|
26
|
+
}
|
|
21
27
|
return EXIT_OK;
|
|
22
28
|
}
|
|
23
29
|
catch (err) {
|
|
24
|
-
|
|
25
|
-
return exitCodeForError(err);
|
|
30
|
+
return emitErr("revert", err);
|
|
26
31
|
}
|
|
27
32
|
}
|
package/dist/commands/runs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
|
-
import { EXIT_OK, EXIT_USAGE,
|
|
2
|
+
import { EXIT_OK, EXIT_USAGE, v1Get, v1Post } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, emitUsage, isJson, progress } from "../runtime.js";
|
|
3
4
|
const TERMINAL = new Set(["succeeded", "failed", "canceled"]);
|
|
4
5
|
function printRun(run) {
|
|
5
6
|
const msg = run.statusMessage || run.summary || run.error || "";
|
|
@@ -23,20 +24,21 @@ export async function runRuns(args) {
|
|
|
23
24
|
return await retryRunCmd(args.slice(1));
|
|
24
25
|
if (sub === "get")
|
|
25
26
|
return await getRun(args.slice(1));
|
|
26
|
-
// `frontpage runs <runId>` → get
|
|
27
27
|
if (/^[0-9a-f-]{36}$/i.test(sub))
|
|
28
28
|
return await getRun(args);
|
|
29
|
-
|
|
30
|
-
return EXIT_USAGE;
|
|
29
|
+
return emitUsage("runs", "Usage: frontpage runs [list|current|wait|cancel|retry|get] [runId] [--site <slug>]", EXIT_USAGE);
|
|
31
30
|
}
|
|
32
31
|
catch (err) {
|
|
33
|
-
|
|
34
|
-
return exitCodeForError(err);
|
|
32
|
+
return emitErr("runs", err);
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
async function listRuns(args) {
|
|
38
36
|
const { slug } = await resolveSlug(args);
|
|
39
37
|
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/agent-runs`);
|
|
38
|
+
if (isJson()) {
|
|
39
|
+
emitOk("runs", { slug, ...data });
|
|
40
|
+
return EXIT_OK;
|
|
41
|
+
}
|
|
40
42
|
if (data.run) {
|
|
41
43
|
console.log("latest:");
|
|
42
44
|
printRun(data.run);
|
|
@@ -60,11 +62,15 @@ async function getRun(args) {
|
|
|
60
62
|
const { slug, rest } = await resolveSlug(args);
|
|
61
63
|
const runId = rest[0];
|
|
62
64
|
if (!runId) {
|
|
63
|
-
|
|
64
|
-
return EXIT_USAGE;
|
|
65
|
+
return emitUsage("runs", "Usage: frontpage runs get <runId> [--site <slug>]", EXIT_USAGE);
|
|
65
66
|
}
|
|
66
67
|
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/agent-runs/${encodeURIComponent(runId)}`);
|
|
67
|
-
|
|
68
|
+
if (isJson()) {
|
|
69
|
+
emitOk("runs", { slug, run: data.run });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
printRun(data.run);
|
|
73
|
+
}
|
|
68
74
|
return EXIT_OK;
|
|
69
75
|
}
|
|
70
76
|
async function waitRun(args) {
|
|
@@ -75,10 +81,15 @@ async function waitRun(args) {
|
|
|
75
81
|
while (Date.now() - started < maxMs) {
|
|
76
82
|
if (runId) {
|
|
77
83
|
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/agent-runs/${encodeURIComponent(runId)}`);
|
|
78
|
-
|
|
84
|
+
progress(`\r${data.run.status} ${data.run.statusMessage ?? ""} `);
|
|
79
85
|
if (TERMINAL.has(data.run.status)) {
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
progress("\n");
|
|
87
|
+
if (isJson()) {
|
|
88
|
+
emitOk("runs", { slug, action: "wait", run: data.run });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
printRun(data.run);
|
|
92
|
+
}
|
|
82
93
|
if (data.run.status === "failed")
|
|
83
94
|
return EXIT_USAGE;
|
|
84
95
|
if (data.run.status === "canceled")
|
|
@@ -93,42 +104,59 @@ async function waitRun(args) {
|
|
|
93
104
|
: data.run;
|
|
94
105
|
if (current) {
|
|
95
106
|
runId = current.id;
|
|
96
|
-
|
|
107
|
+
progress(`\r${current.status} ${current.statusMessage ?? ""} `);
|
|
97
108
|
if (TERMINAL.has(current.status) && !data.poll?.active) {
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
progress("\n");
|
|
110
|
+
if (isJson()) {
|
|
111
|
+
emitOk("runs", { slug, action: "wait", run: current });
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
printRun(current);
|
|
115
|
+
}
|
|
100
116
|
return current.status === "succeeded" ? EXIT_OK : EXIT_USAGE;
|
|
101
117
|
}
|
|
102
118
|
}
|
|
103
119
|
else {
|
|
104
|
-
|
|
120
|
+
if (isJson()) {
|
|
121
|
+
emitOk("runs", { slug, action: "wait", run: null });
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log("No active run.");
|
|
125
|
+
}
|
|
105
126
|
return EXIT_OK;
|
|
106
127
|
}
|
|
107
128
|
}
|
|
108
129
|
await new Promise((r) => setTimeout(r, 2000));
|
|
109
130
|
}
|
|
110
|
-
|
|
111
|
-
return EXIT_USAGE;
|
|
131
|
+
return emitUsage("runs", "Timed out waiting for run.", EXIT_USAGE);
|
|
112
132
|
}
|
|
113
133
|
async function cancelRun(args) {
|
|
114
134
|
const { slug, rest } = await resolveSlug(args);
|
|
115
135
|
const runId = rest[0];
|
|
116
136
|
if (!runId) {
|
|
117
|
-
|
|
118
|
-
return EXIT_USAGE;
|
|
137
|
+
return emitUsage("runs", "Usage: frontpage runs cancel <runId> [--site <slug>]", EXIT_USAGE);
|
|
119
138
|
}
|
|
120
139
|
await v1Post(`/api/v1/sites/${encodeURIComponent(slug)}/agent-runs/${encodeURIComponent(runId)}/cancel`);
|
|
121
|
-
|
|
140
|
+
if (isJson()) {
|
|
141
|
+
emitOk("runs", { slug, action: "cancel", runId });
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
console.log(`Canceled ${runId}`);
|
|
145
|
+
}
|
|
122
146
|
return EXIT_OK;
|
|
123
147
|
}
|
|
124
148
|
async function retryRunCmd(args) {
|
|
125
149
|
const { slug, rest } = await resolveSlug(args);
|
|
126
150
|
const runId = rest[0];
|
|
127
151
|
if (!runId) {
|
|
128
|
-
|
|
129
|
-
return EXIT_USAGE;
|
|
152
|
+
return emitUsage("runs", "Usage: frontpage runs retry <runId> [--site <slug>]", EXIT_USAGE);
|
|
130
153
|
}
|
|
131
154
|
const data = await v1Post(`/api/v1/sites/${encodeURIComponent(slug)}/agent-runs/${encodeURIComponent(runId)}/retry`);
|
|
132
|
-
|
|
155
|
+
if (isJson()) {
|
|
156
|
+
emitOk("runs", { slug, action: "retry", runId: data.runId, previousRunId: runId });
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
console.log(data.runId);
|
|
160
|
+
}
|
|
133
161
|
return EXIT_OK;
|
|
134
162
|
}
|
package/dist/commands/sites.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import { EXIT_OK
|
|
1
|
+
import { EXIT_OK } from "../http/client.js";
|
|
2
|
+
import { v1Get } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, isJson } from "../runtime.js";
|
|
2
4
|
export async function runSites() {
|
|
3
5
|
try {
|
|
4
6
|
const data = await v1Get("/api/v1/sites");
|
|
7
|
+
if (isJson()) {
|
|
8
|
+
emitOk("sites", data);
|
|
9
|
+
return EXIT_OK;
|
|
10
|
+
}
|
|
5
11
|
if (data.sites.length === 0) {
|
|
6
12
|
console.log("No sites. Create a site in Frontpage first.");
|
|
7
13
|
return EXIT_OK;
|
|
@@ -14,7 +20,6 @@ export async function runSites() {
|
|
|
14
20
|
return EXIT_OK;
|
|
15
21
|
}
|
|
16
22
|
catch (err) {
|
|
17
|
-
|
|
18
|
-
return exitCodeForError(err);
|
|
23
|
+
return emitErr("sites", err);
|
|
19
24
|
}
|
|
20
25
|
}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
|
-
import { EXIT_OK,
|
|
2
|
+
import { EXIT_OK, v1Get, apiBase } from "../http/client.js";
|
|
3
3
|
import { readState } from "../state/frontpage-state.js";
|
|
4
|
+
import { emitErr, emitOk, isJson } from "../runtime.js";
|
|
4
5
|
export async function runStatus(args) {
|
|
5
6
|
try {
|
|
6
7
|
const { slug } = await resolveSlug(args);
|
|
@@ -11,7 +12,22 @@ export async function runStatus(args) {
|
|
|
11
12
|
active: [],
|
|
12
13
|
})),
|
|
13
14
|
]);
|
|
14
|
-
|
|
15
|
+
const tipDrift = Boolean(state.baseCommitSha && data.baseCommitSha && state.baseCommitSha !== data.baseCommitSha);
|
|
16
|
+
const payload = {
|
|
17
|
+
apiBase: apiBase(),
|
|
18
|
+
site: slug,
|
|
19
|
+
localSlug: state.slug ?? null,
|
|
20
|
+
localBaseCommitSha: state.baseCommitSha ?? null,
|
|
21
|
+
remoteTip: data.baseCommitSha,
|
|
22
|
+
remoteFileCount: data.files.length,
|
|
23
|
+
activeRuns: runs.active ?? [],
|
|
24
|
+
tipDrift,
|
|
25
|
+
};
|
|
26
|
+
if (isJson()) {
|
|
27
|
+
emitOk("status", payload);
|
|
28
|
+
return EXIT_OK;
|
|
29
|
+
}
|
|
30
|
+
console.log(`API base: ${payload.apiBase}`);
|
|
15
31
|
console.log(`Site: ${slug}`);
|
|
16
32
|
console.log(`Local state: ${state.slug ?? "(none)"}${state.baseCommitSha ? ` @ ${state.baseCommitSha.slice(0, 7)}` : ""}`);
|
|
17
33
|
console.log(`Remote tip: ${data.baseCommitSha ?? "(unknown)"}`);
|
|
@@ -23,13 +39,12 @@ export async function runStatus(args) {
|
|
|
23
39
|
else {
|
|
24
40
|
console.log("Active runs: none");
|
|
25
41
|
}
|
|
26
|
-
if (
|
|
42
|
+
if (tipDrift) {
|
|
27
43
|
console.log("Note: remote tip differs from last pull — run frontpage pull");
|
|
28
44
|
}
|
|
29
45
|
return EXIT_OK;
|
|
30
46
|
}
|
|
31
47
|
catch (err) {
|
|
32
|
-
|
|
33
|
-
return exitCodeForError(err);
|
|
48
|
+
return emitErr("status", err);
|
|
34
49
|
}
|
|
35
50
|
}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { EXIT_OK
|
|
1
|
+
import { EXIT_OK } from "../http/client.js";
|
|
2
|
+
import { v1Get } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, isJson } from "../runtime.js";
|
|
2
4
|
export async function runWhoami() {
|
|
3
5
|
try {
|
|
4
6
|
const me = await v1Get("/api/v1/me");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
if (isJson()) {
|
|
8
|
+
emitOk("whoami", me);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
console.log(`email: ${me.email ?? "(none)"}`);
|
|
12
|
+
console.log(`userId: ${me.userId}`);
|
|
13
|
+
console.log(`keyId: ${me.keyId}`);
|
|
14
|
+
}
|
|
8
15
|
return EXIT_OK;
|
|
9
16
|
}
|
|
10
17
|
catch (err) {
|
|
11
|
-
|
|
12
|
-
return exitCodeForError(err);
|
|
18
|
+
return emitErr("whoami", err);
|
|
13
19
|
}
|
|
14
20
|
}
|
|
@@ -14,15 +14,16 @@ _frontpage_completions() {
|
|
|
14
14
|
fi
|
|
15
15
|
local cmd="\${COMP_WORDS[1]}"
|
|
16
16
|
case "\${cmd}" in
|
|
17
|
-
help) COMPREPLY=( $(compgen -W "\${cmds} auth sync agent content history exit-codes" -- "\${cur}") ) ;;
|
|
17
|
+
help) COMPREPLY=( $(compgen -W "\${cmds} quickstart auth sync agent content history isolation exit-codes" -- "\${cur}") ) ;;
|
|
18
18
|
completion) COMPREPLY=( $(compgen -W "bash zsh fish" -- "\${cur}") ) ;;
|
|
19
|
-
runs) COMPREPLY=( $(compgen -W "current wait cancel retry get" -- "\${cur}") ) ;;
|
|
19
|
+
runs) COMPREPLY=( $(compgen -W "list current wait cancel retry get" -- "\${cur}") ) ;;
|
|
20
20
|
deploy) COMPREPLY=( $(compgen -W "wait" -- "\${cur}") ) ;;
|
|
21
21
|
media) COMPREPLY=( $(compgen -W "list upload" -- "\${cur}") ) ;;
|
|
22
22
|
seo|settings) COMPREPLY=( $(compgen -W "get set" -- "\${cur}") ) ;;
|
|
23
23
|
articles) COMPREPLY=( $(compgen -W "list content create-section create-article set-draft" -- "\${cur}") ) ;;
|
|
24
|
-
modules
|
|
25
|
-
|
|
24
|
+
modules) COMPREPLY=( $(compgen -W "list enable disable archive config" -- "\${cur}") ) ;;
|
|
25
|
+
extensions) COMPREPLY=( $(compgen -W "list enable disable config" -- "\${cur}") ) ;;
|
|
26
|
+
*) COMPREPLY=( $(compgen -W "--site --help --json --quiet --yes" -- "\${cur}") ) ;;
|
|
26
27
|
esac
|
|
27
28
|
}
|
|
28
29
|
complete -F _frontpage_completions frontpage
|
package/dist/flags.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip global flags from argv. Safe to call before command dispatch.
|
|
3
|
+
* Recognizes --json, --quiet, --yes, and help aliases anywhere in the list.
|
|
4
|
+
*/
|
|
5
|
+
export type GlobalFlags = {
|
|
6
|
+
json: boolean;
|
|
7
|
+
quiet: boolean;
|
|
8
|
+
yes: boolean;
|
|
9
|
+
/** True when argv asked for help (--help / -h), not the `help` command itself. */
|
|
10
|
+
wantsHelp: boolean;
|
|
11
|
+
args: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare function parseGlobalFlags(argv: string[]): GlobalFlags;
|
package/dist/flags.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip global flags from argv. Safe to call before command dispatch.
|
|
3
|
+
* Recognizes --json, --quiet, --yes, and help aliases anywhere in the list.
|
|
4
|
+
*/
|
|
5
|
+
export function parseGlobalFlags(argv) {
|
|
6
|
+
const args = [];
|
|
7
|
+
let json = false;
|
|
8
|
+
let quiet = false;
|
|
9
|
+
let yes = false;
|
|
10
|
+
let wantsHelp = false;
|
|
11
|
+
for (const a of argv) {
|
|
12
|
+
if (a === "--json") {
|
|
13
|
+
json = true;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (a === "--quiet" || a === "-q") {
|
|
17
|
+
quiet = true;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (a === "--yes" || a === "-y") {
|
|
21
|
+
yes = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (a === "--help" || a === "-h") {
|
|
25
|
+
wantsHelp = true;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
args.push(a);
|
|
29
|
+
}
|
|
30
|
+
return { json, quiet, yes, wantsHelp, args };
|
|
31
|
+
}
|
package/dist/registry.d.ts
CHANGED
|
@@ -8,7 +8,12 @@ export type CommandDef = {
|
|
|
8
8
|
usage?: string;
|
|
9
9
|
/** Topic tags for `help <topic>`. */
|
|
10
10
|
topics?: string[];
|
|
11
|
+
examples?: string[];
|
|
12
|
+
flags?: string[];
|
|
13
|
+
dangers?: string[];
|
|
14
|
+
seeAlso?: string[];
|
|
11
15
|
};
|
|
12
16
|
export declare const COMMANDS: readonly CommandDef[];
|
|
17
|
+
export declare const TOPIC_NAMES: readonly ["quickstart", "auth", "sync", "agent", "content", "history", "isolation", "exit-codes"];
|
|
13
18
|
export declare const TOPICS: Record<string, string>;
|
|
14
19
|
export declare function findCommand(name: string): CommandDef | undefined;
|