@mostra/cli 0.0.0-stage → 0.2.0
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/LICENSE +202 -0
- package/README.md +18 -2
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +79 -0
- package/dist/bin.js.map +1 -0
- package/dist/bootstrap-DfEe_yPr.js +113 -0
- package/dist/bootstrap-DfEe_yPr.js.map +1 -0
- package/dist/exit-CBIf8nAU.js +79 -0
- package/dist/exit-CBIf8nAU.js.map +1 -0
- package/dist/flush-BCuWs0Zh.js +718 -0
- package/dist/flush-BCuWs0Zh.js.map +1 -0
- package/dist/index.d.ts +230 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/reference/cli.md +977 -0
- package/dist/reference/diagnostics.json +1264 -0
- package/dist/reference/errors/MOSTRA_A11Y_MINOR.md +23 -0
- package/dist/reference/errors/MOSTRA_A11Y_SERIOUS.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_CANCELLED.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_EVENT_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_EXPORT_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_INTERRUPTED.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_RUN_NOT_FOUND.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_THREW.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_TOO_LARGE.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_UNKNOWN_FUNCTION.md +23 -0
- package/dist/reference/errors/MOSTRA_ACTION_UNSERIALIZABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_DIR_NOT_EMPTY.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_ENTRY_AMBIGUOUS.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_NOT_FOUND.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_NO_ENTRY.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_NO_PAGE.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_SOURCE_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_SOURCE_UNREADABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_TEMPLATE_UNKNOWN.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_VERSION_COLLECTED.md +23 -0
- package/dist/reference/errors/MOSTRA_ARTIFACT_VERSION_NOT_FOUND.md +23 -0
- package/dist/reference/errors/MOSTRA_BUILD_CRASHED.md +23 -0
- package/dist/reference/errors/MOSTRA_BUILD_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_BUILD_TIMEOUT.md +23 -0
- package/dist/reference/errors/MOSTRA_BUILD_UNRESOLVED.md +23 -0
- package/dist/reference/errors/MOSTRA_CLI_CONFIG_UNWRITABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_CLI_UNKNOWN_COMMAND.md +23 -0
- package/dist/reference/errors/MOSTRA_CLI_USAGE.md +23 -0
- package/dist/reference/errors/MOSTRA_CONSOLE_ERROR.md +23 -0
- package/dist/reference/errors/MOSTRA_CONSOLE_WARNING.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_INSTALL_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_NOT_FOUND.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_OFFLINE.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_SPEC_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_TIMEOUT.md +23 -0
- package/dist/reference/errors/MOSTRA_DEP_WARM_CONFLICT.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_BIND_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_BROWSER_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_BUNDLE_DOWNLOAD_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_BUNDLE_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_BUNDLE_UNAVAILABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_NODE_UNSUPPORTED.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_PORT_TAKEN.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_RUNTIME_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_SERVICE_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_SHELL_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_ENV_WARM_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_CONFLICT.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_DUPLICATE_ID.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_ID_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_ID_UNSTABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_MUTATION_ID_REUSED.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_SHARED.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_TOO_LARGE.md +23 -0
- package/dist/reference/errors/MOSTRA_FIELD_UNBOUND.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_DISK_FULL.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_GC_INCOMPLETE.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_GONE.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_INTEGRITY.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_LEDGER_UNREADABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_LOCKED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_MISMATCH.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_NOT_ALWAYS_ON.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_NOT_OWNED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_SOCKET_TOO_LONG.md +23 -0
- package/dist/reference/errors/MOSTRA_HOME_TOO_NEW.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_CONNECTION_CLOSED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_CURSOR_COMPACTED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_IDENTITY_UNAVAILABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_INITIALIZE_ORDER.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_INTERNAL_ERROR.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_INVALID_PARAMS.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_MALFORMED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_MESSAGE_TOO_LARGE.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_METHOD_UNKNOWN.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_NOTIFICATION_UNSUPPORTED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_PORT_UNSUPPORTED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_REQUEST_ID_REUSED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_REVISION_UNSUPPORTED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_SHUTDOWN_REFUSED.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_SUBSCRIPTION_UNKNOWN.md +23 -0
- package/dist/reference/errors/MOSTRA_HOST_TIMEOUT.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_CONTENT_TYPE.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_CSRF_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_HEADERS_TOO_LARGE.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_HOST_REFUSED.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_NOT_SERVED.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_ORIGIN_REFUSED.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_RATE_LIMITED.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_REQUEST_MALFORMED.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_SCOPE_DENIED.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_SESSION_CONFLICT.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_SESSION_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_TOKEN_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_HYGIENE_TOKEN_REVOKED.md +23 -0
- package/dist/reference/errors/MOSTRA_LIVE_SOURCE_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_LIVE_TOO_LARGE.md +23 -0
- package/dist/reference/errors/MOSTRA_MANIFEST_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_MANIFEST_NOT_LITERAL.md +23 -0
- package/dist/reference/errors/MOSTRA_MANIFEST_UNKNOWN_KEY.md +23 -0
- package/dist/reference/errors/MOSTRA_NETWORK_EXTERNAL_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_NETWORK_REQUEST_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_PLATFORM_UNSUPPORTED.md +23 -0
- package/dist/reference/errors/MOSTRA_PUBLISH_ID_CONFLICT.md +23 -0
- package/dist/reference/errors/MOSTRA_PUBLISH_SOURCE_CHANGED.md +23 -0
- package/dist/reference/errors/MOSTRA_PUBLISH_VERIFY_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_REGRESSION_ACTION_REMOVED.md +23 -0
- package/dist/reference/errors/MOSTRA_REGRESSION_ARIA.md +23 -0
- package/dist/reference/errors/MOSTRA_REGRESSION_FIELD_REMOVED.md +23 -0
- package/dist/reference/errors/MOSTRA_REGRESSION_LIVE_REMOVED.md +23 -0
- package/dist/reference/errors/MOSTRA_REGRESSION_PAGE_REMOVED.md +23 -0
- package/dist/reference/errors/MOSTRA_REGRESSION_PIXELS.md +23 -0
- package/dist/reference/errors/MOSTRA_RUNTIME_BLANK.md +23 -0
- package/dist/reference/errors/MOSTRA_RUNTIME_NOT_READY.md +23 -0
- package/dist/reference/errors/MOSTRA_RUNTIME_PAGE_ERROR.md +23 -0
- package/dist/reference/errors/MOSTRA_RUNTIME_WORKER_CRASHED.md +23 -0
- package/dist/reference/errors/MOSTRA_RUNTIME_WORKER_PARKED.md +23 -0
- package/dist/reference/errors/MOSTRA_SECRET_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_SMOKE_BUDGET.md +23 -0
- package/dist/reference/errors/MOSTRA_SMOKE_NO_EFFECT.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_ALREADY.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_BLOCKED.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_CHANNEL_DENIED.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_NOT_FOUND.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_POLICY_NONE.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_REVISION_MOVED.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_SIGNAL_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_SUBMIT_VIEW_INVALID.md +23 -0
- package/dist/reference/errors/MOSTRA_TARGET_UNAVAILABLE.md +23 -0
- package/dist/reference/errors/MOSTRA_TYPE_ERROR.md +23 -0
- package/dist/reference/errors/MOSTRA_TYPE_UNTYPED_PACKAGE.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_ACTION_SKIPPED.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_BASELINE_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_CRASHED.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_LIVE_FAILED.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_NO_BASELINE.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_SECRET_MISSING.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_SKIP_CONSEQUENCE.md +23 -0
- package/dist/reference/errors/MOSTRA_VERIFY_TIMEOUT.md +23 -0
- package/dist/reference/telemetry.md +82 -0
- package/dist/run-BJaRnz-Q.js +3824 -0
- package/dist/run-BJaRnz-Q.js.map +1 -0
- package/dist/run-CMyjOm0Q.js +2 -0
- package/dist/telemetry/flush-main.d.ts +1 -0
- package/dist/telemetry/flush-main.js +14 -0
- package/dist/telemetry/flush-main.js.map +1 -0
- package/package.json +62 -3
- package/src/bin.ts +70 -0
- package/src/bootstrap.ts +156 -0
- package/src/browser.ts +186 -0
- package/src/client.ts +313 -0
- package/src/command.ts +147 -0
- package/src/commands/admin.ts +791 -0
- package/src/commands/authoring.ts +244 -0
- package/src/commands/dev.ts +106 -0
- package/src/commands/index.ts +71 -0
- package/src/commands/interaction.ts +288 -0
- package/src/commands/shared.ts +71 -0
- package/src/commands/viewing.ts +153 -0
- package/src/docs.ts +111 -0
- package/src/exit.ts +89 -0
- package/src/help.ts +170 -0
- package/src/home.ts +111 -0
- package/src/index.ts +23 -0
- package/src/node-gate.ts +15 -0
- package/src/parse.ts +246 -0
- package/src/run.ts +387 -0
- package/src/telemetry/decision.ts +101 -0
- package/src/telemetry/events.ts +147 -0
- package/src/telemetry/flush-main.ts +13 -0
- package/src/telemetry/flush.ts +143 -0
- package/src/telemetry/harness.ts +39 -0
- package/src/telemetry/index.ts +318 -0
- package/src/telemetry/store.ts +379 -0
- package/src/telemetry/timezone.ts +72 -0
- package/src/telemetry/words.ts +87 -0
- package/src/telemetry/zone-sets.ts +182 -0
- package/src/telemetry/zones.generated.ts +720 -0
- package/src/version.ts +43 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authoring: `new`, `verify`, `publish` and `add`, thin clients of `artifact/create`,
|
|
3
|
+
* `artifact/verify`, `artifact/publish` and `deps/add` (INTERFACES §6).
|
|
4
|
+
*/
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
import {
|
|
8
|
+
ARTIFACT_PROGRESS,
|
|
9
|
+
artifactCreateMethod,
|
|
10
|
+
artifactPublishMethod,
|
|
11
|
+
artifactVerifyMethod,
|
|
12
|
+
depsAddMethod,
|
|
13
|
+
type SubmissionPolicy,
|
|
14
|
+
type VerifyVerdict,
|
|
15
|
+
} from "@mostra/protocol";
|
|
16
|
+
import { type CommandDef, defineCommand } from "../command.ts";
|
|
17
|
+
import { EXIT } from "../exit.ts";
|
|
18
|
+
import { usage } from "../parse.ts";
|
|
19
|
+
import { arg, flag, sourceRef } from "./shared.ts";
|
|
20
|
+
|
|
21
|
+
/** `mostra new <dir>`. */
|
|
22
|
+
export const newCommand: CommandDef = defineCommand({
|
|
23
|
+
path: ["new"],
|
|
24
|
+
summary: "Create an artifact in an empty directory, with a generated ID.",
|
|
25
|
+
args: [{ name: "dir", summary: "The directory to create it in; it must be empty or not exist." }],
|
|
26
|
+
flags: [
|
|
27
|
+
{
|
|
28
|
+
name: "title",
|
|
29
|
+
kind: "string",
|
|
30
|
+
value: "<text>",
|
|
31
|
+
summary: "The artifact's title. Default: the directory's name.",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "template",
|
|
35
|
+
kind: "string",
|
|
36
|
+
value: "<family>",
|
|
37
|
+
summary: "Start from a template (templates arrive in a later release).",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "request-id",
|
|
41
|
+
kind: "string",
|
|
42
|
+
value: "<id>",
|
|
43
|
+
summary: "Make a retry return the first attempt's result.",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
output: { type: "ArtifactCreateResult", topic: "cli" },
|
|
47
|
+
exits: [EXIT.failure],
|
|
48
|
+
example: "new ./sidebar-review --title 'Sidebar review'",
|
|
49
|
+
async run(context) {
|
|
50
|
+
const title = flag(context, "title");
|
|
51
|
+
const template = flag(context, "template");
|
|
52
|
+
const requestId = flag(context, "request-id");
|
|
53
|
+
const result = await context.call(artifactCreateMethod, {
|
|
54
|
+
dir: resolve(context.cwd, arg(context, "dir")),
|
|
55
|
+
...(title !== undefined ? { title } : {}),
|
|
56
|
+
...(template !== undefined ? { template } : {}),
|
|
57
|
+
...(requestId !== undefined ? { requestId } : {}),
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
result,
|
|
61
|
+
human: `Created ${result.artifactId} in ${result.dir}\n${result.files.map((file) => ` ${file}\n`).join("")}`,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/** The verdict for people: the status, each diagnostic, the screenshots worth looking at. */
|
|
67
|
+
function verdictText(verdict: VerifyVerdict): string {
|
|
68
|
+
const lines = [`verify: ${verdict.status}`];
|
|
69
|
+
for (const diagnostic of verdict.diagnostics) {
|
|
70
|
+
const where =
|
|
71
|
+
diagnostic.location && "file" in diagnostic.location
|
|
72
|
+
? ` ${diagnostic.location.file}:${diagnostic.location.line}:${diagnostic.location.column}`
|
|
73
|
+
: "";
|
|
74
|
+
const count =
|
|
75
|
+
diagnostic.count !== undefined && diagnostic.count > 1 ? ` (×${diagnostic.count})` : "";
|
|
76
|
+
lines.push(
|
|
77
|
+
` ${diagnostic.severity} ${diagnostic.code}${where}${count}: ${diagnostic.message}`,
|
|
78
|
+
);
|
|
79
|
+
if (diagnostic.hint) lines.push(` ${diagnostic.hint}`);
|
|
80
|
+
}
|
|
81
|
+
for (const shot of verdict.screenshots.filter((screenshot) => screenshot.returned)) {
|
|
82
|
+
lines.push(` screenshot ${shot.viewport}: ${shot.path}`);
|
|
83
|
+
}
|
|
84
|
+
return `${lines.join("\n")}\n`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** `mostra verify <path>`. */
|
|
88
|
+
export const verifyCommand: CommandDef = defineCommand({
|
|
89
|
+
path: ["verify"],
|
|
90
|
+
summary: "Build, render and check an artifact's source; one verdict, nothing published.",
|
|
91
|
+
args: [{ name: "path", summary: "The artifact's source: a file, a directory, or its ID." }],
|
|
92
|
+
flags: [
|
|
93
|
+
{
|
|
94
|
+
name: "screenshots",
|
|
95
|
+
kind: "string",
|
|
96
|
+
value: "<when>",
|
|
97
|
+
choices: ["on-failure", "always", "never"],
|
|
98
|
+
default: "on-failure",
|
|
99
|
+
summary: "Which screenshots the verdict marks as worth looking at.",
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
output: { type: "VerifyVerdict", topic: "cli" },
|
|
103
|
+
exits: [EXIT.failure],
|
|
104
|
+
example: "verify ./sidebar-review",
|
|
105
|
+
async run(context) {
|
|
106
|
+
const connection = await context.connection();
|
|
107
|
+
const progressToken = randomUUID();
|
|
108
|
+
connection?.onNotification(ARTIFACT_PROGRESS, (params) => {
|
|
109
|
+
const { progressToken: token, stage } = (params ?? {}) as {
|
|
110
|
+
progressToken?: string;
|
|
111
|
+
stage?: string;
|
|
112
|
+
};
|
|
113
|
+
if (token === progressToken && typeof stage === "string") context.log(`verify: ${stage}`);
|
|
114
|
+
});
|
|
115
|
+
const screenshots = flag(context, "screenshots") as
|
|
116
|
+
| "on-failure"
|
|
117
|
+
| "always"
|
|
118
|
+
| "never"
|
|
119
|
+
| undefined;
|
|
120
|
+
const verdict = await context.call(artifactVerifyMethod, {
|
|
121
|
+
source: sourceRef(arg(context, "path"), context.cwd),
|
|
122
|
+
progressToken,
|
|
123
|
+
...(screenshots !== undefined ? { screenshots } : {}),
|
|
124
|
+
});
|
|
125
|
+
context.record({
|
|
126
|
+
event: "verify.result",
|
|
127
|
+
fields: {
|
|
128
|
+
status: verdict.status,
|
|
129
|
+
codes: verdict.diagnostics.map((diagnostic) => diagnostic.code),
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
result: verdict,
|
|
134
|
+
human: verdictText(verdict),
|
|
135
|
+
...(verdict.status === "fail" ? { exit: EXIT.failure } : {}),
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const POLICIES: Readonly<Record<string, SubmissionPolicy>> = {
|
|
141
|
+
once: { policy: "once", scope: "per-artifact" },
|
|
142
|
+
"once-per-viewer": { policy: "once", scope: "per-viewer" },
|
|
143
|
+
epochs: { policy: "epochs" },
|
|
144
|
+
none: { policy: "none" },
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/** `mostra publish <path>`. */
|
|
148
|
+
export const publishCommand: CommandDef = defineCommand({
|
|
149
|
+
path: ["publish"],
|
|
150
|
+
summary:
|
|
151
|
+
"Publish an artifact's source as a new immutable version, gated by verify, and print its link.",
|
|
152
|
+
args: [{ name: "path", summary: "The artifact's source: a file, a directory, or its ID." }],
|
|
153
|
+
flags: [
|
|
154
|
+
{
|
|
155
|
+
name: "force",
|
|
156
|
+
kind: "boolean",
|
|
157
|
+
summary: "Publish despite verify's errors and record their codes; never what didn't build.",
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "policy",
|
|
161
|
+
kind: "string",
|
|
162
|
+
value: "<policy>",
|
|
163
|
+
choices: Object.keys(POLICIES),
|
|
164
|
+
summary: "The submission policy to use, instead of the manifest's.",
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "request-id",
|
|
168
|
+
kind: "string",
|
|
169
|
+
value: "<id>",
|
|
170
|
+
summary: "Make a retry return the first attempt's receipt.",
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
output: { type: "PublishReceipt", topic: "cli" },
|
|
174
|
+
exits: [EXIT.failure, EXIT.conflict],
|
|
175
|
+
example: "publish ./sidebar-review",
|
|
176
|
+
async run(context) {
|
|
177
|
+
const policyName = flag(context, "policy");
|
|
178
|
+
const requestId = flag(context, "request-id");
|
|
179
|
+
const force = context.flags["force"] === true;
|
|
180
|
+
const receipt = await context.call(artifactPublishMethod, {
|
|
181
|
+
source: sourceRef(arg(context, "path"), context.cwd),
|
|
182
|
+
...(force ? { force: true } : {}),
|
|
183
|
+
...(policyName !== undefined ? { policy: POLICIES[policyName] as SubmissionPolicy } : {}),
|
|
184
|
+
...(requestId !== undefined ? { requestId } : {}),
|
|
185
|
+
});
|
|
186
|
+
context.record({ event: "publish.done", fields: { reused: receipt.reused, forced: force } });
|
|
187
|
+
const forced =
|
|
188
|
+
receipt.forcedDiagnostics !== undefined && receipt.forcedDiagnostics.length > 0
|
|
189
|
+
? `Forced past: ${receipt.forcedDiagnostics.join(", ")}\n`
|
|
190
|
+
: "";
|
|
191
|
+
return {
|
|
192
|
+
result: receipt,
|
|
193
|
+
human: `${receipt.reused ? "Already published" : "Published"} version ${receipt.version} (${receipt.versionId}) of ${receipt.artifactId}\n${forced}${receipt.url ?? ""}\n`,
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
/** `mostra add <package…>`. */
|
|
199
|
+
export const addCommand: CommandDef = defineCommand({
|
|
200
|
+
path: ["add"],
|
|
201
|
+
summary:
|
|
202
|
+
"Add npm packages to an artifact's lockfile at exact versions, installing them into the home's store.",
|
|
203
|
+
args: [
|
|
204
|
+
{
|
|
205
|
+
name: "package",
|
|
206
|
+
summary: "npm specs: name, name@version, name@range or name@tag.",
|
|
207
|
+
variadic: true,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
flags: [
|
|
211
|
+
{
|
|
212
|
+
name: "artifact",
|
|
213
|
+
kind: "string",
|
|
214
|
+
value: "<path|id>",
|
|
215
|
+
summary: "The artifact. Default: the one in the current directory.",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: "request-id",
|
|
219
|
+
kind: "string",
|
|
220
|
+
value: "<id>",
|
|
221
|
+
summary: "Make a retry return the first attempt's result.",
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
output: { type: "DepsAddResult", topic: "cli" },
|
|
225
|
+
exits: [EXIT.failure],
|
|
226
|
+
example: "add recharts@3 --artifact ./dashboard",
|
|
227
|
+
async run(context) {
|
|
228
|
+
const packages = context.args["package"];
|
|
229
|
+
if (!Array.isArray(packages) || packages.length === 0)
|
|
230
|
+
throw usage('"mostra add" needs <package…>.');
|
|
231
|
+
const requestId = flag(context, "request-id");
|
|
232
|
+
const result = await context.call(depsAddMethod, {
|
|
233
|
+
artifact: sourceRef(flag(context, "artifact") ?? ".", context.cwd),
|
|
234
|
+
packages: packages as string[],
|
|
235
|
+
...(requestId !== undefined ? { requestId } : {}),
|
|
236
|
+
});
|
|
237
|
+
return {
|
|
238
|
+
result,
|
|
239
|
+
human: result.packages
|
|
240
|
+
.map((added) => `${added.name}@${added.version}${added.warm ? " (warm set)" : ""}\n`)
|
|
241
|
+
.join(""),
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mostra dev` (VR-08, D140 item 12): a development preview of unpublished source with hot
|
|
3
|
+
* reload, until Ctrl-C. It prints the preview's link and then what happens in the session (built,
|
|
4
|
+
* reloaded, server restarted, submissions with their Results, diagnostics) as a stream: NDJSON
|
|
5
|
+
* envelopes with `--json`, lines otherwise. Viewers never reach a preview; it isn't a version.
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
createDiagnostic,
|
|
9
|
+
DEV_NOTIFY,
|
|
10
|
+
type DevNotifyParams,
|
|
11
|
+
type Diagnostic,
|
|
12
|
+
devStartMethod,
|
|
13
|
+
devStopMethod,
|
|
14
|
+
RpcError,
|
|
15
|
+
} from "@mostra/protocol";
|
|
16
|
+
import { type CommandDef, defineCommand } from "../command.ts";
|
|
17
|
+
import { EXIT } from "../exit.ts";
|
|
18
|
+
import { arg, sourceRef } from "./shared.ts";
|
|
19
|
+
|
|
20
|
+
/** One event's line without `--json`. */
|
|
21
|
+
function line(event: DevNotifyParams): string {
|
|
22
|
+
const files = event.files && event.files.length > 0 ? `: ${event.files.join(", ")}` : "";
|
|
23
|
+
switch (event.kind) {
|
|
24
|
+
case "built":
|
|
25
|
+
return `Updated${files}\n`;
|
|
26
|
+
case "reloaded":
|
|
27
|
+
return `Reloaded${files}\n`;
|
|
28
|
+
case "server-restarted":
|
|
29
|
+
return `Server code restarted${files}\n`;
|
|
30
|
+
case "submission":
|
|
31
|
+
return `Submission recorded (not delivered):\n${JSON.stringify(event.results, null, 2)}\n`;
|
|
32
|
+
case "diagnostics":
|
|
33
|
+
return `${(event.diagnostics ?? [])
|
|
34
|
+
.map((diagnostic: Diagnostic) => `${diagnostic.code}: ${diagnostic.message}`)
|
|
35
|
+
.join("\n")}\n`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const devCommand: CommandDef = defineCommand({
|
|
40
|
+
path: ["dev"],
|
|
41
|
+
summary:
|
|
42
|
+
"Preview an artifact's unpublished source with hot reload, until Ctrl-C; viewers never see it.",
|
|
43
|
+
args: [{ name: "path", summary: "The artifact's source: a file, a directory, or its ID." }],
|
|
44
|
+
flags: [
|
|
45
|
+
{
|
|
46
|
+
name: "port",
|
|
47
|
+
kind: "number",
|
|
48
|
+
value: "<port>",
|
|
49
|
+
summary: "The preview's port on 127.0.0.1; default one the system picks.",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
output: { type: "DevStartResult", topic: "cli" },
|
|
53
|
+
exits: [EXIT.failure, EXIT.environment],
|
|
54
|
+
example: "dev ./sidebar-review",
|
|
55
|
+
streams: true,
|
|
56
|
+
async run(context) {
|
|
57
|
+
const connection = await context.connection();
|
|
58
|
+
let sessionId: string | undefined;
|
|
59
|
+
const early: DevNotifyParams[] = [];
|
|
60
|
+
const show = (event: DevNotifyParams): void => {
|
|
61
|
+
if (event.kind === "diagnostics") {
|
|
62
|
+
for (const diagnostic of event.diagnostics ?? []) context.warn(diagnostic);
|
|
63
|
+
}
|
|
64
|
+
context.emit(event, line(event));
|
|
65
|
+
};
|
|
66
|
+
connection?.onNotification(DEV_NOTIFY, (params) => {
|
|
67
|
+
const event = params as DevNotifyParams;
|
|
68
|
+
if (sessionId === undefined) early.push(event);
|
|
69
|
+
else if (event.sessionId === sessionId) show(event);
|
|
70
|
+
});
|
|
71
|
+
const portFlag = context.flags["port"];
|
|
72
|
+
const started = await context.call(devStartMethod, {
|
|
73
|
+
source: sourceRef(arg(context, "path"), context.cwd),
|
|
74
|
+
...(typeof portFlag === "number" ? { port: portFlag } : {}),
|
|
75
|
+
});
|
|
76
|
+
sessionId = started.sessionId;
|
|
77
|
+
context.emit(
|
|
78
|
+
{ kind: "started", ...started },
|
|
79
|
+
`Development preview, not published: ${started.url}\nPress Ctrl-C to stop.\n`,
|
|
80
|
+
);
|
|
81
|
+
for (const event of early.splice(0)) if (event.sessionId === sessionId) show(event);
|
|
82
|
+
// The session lasts until Ctrl-C (or SIGTERM), or until the instance ends it.
|
|
83
|
+
let stop: () => void = () => {};
|
|
84
|
+
const ended = await new Promise<"signal" | "closed">((done) => {
|
|
85
|
+
stop = (): void => done("signal");
|
|
86
|
+
process.once("SIGINT", stop);
|
|
87
|
+
process.once("SIGTERM", stop);
|
|
88
|
+
void connection?.closed.then(() => done("closed"));
|
|
89
|
+
});
|
|
90
|
+
process.off("SIGINT", stop);
|
|
91
|
+
process.off("SIGTERM", stop);
|
|
92
|
+
if (ended === "closed") {
|
|
93
|
+
throw new RpcError(
|
|
94
|
+
createDiagnostic("MOSTRA_HOST_CONNECTION_CLOSED", {
|
|
95
|
+
message: "The instance ended the development preview (it stopped or restarted).",
|
|
96
|
+
hint: "Run mostra dev again.",
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
await context.call(devStopMethod, { sessionId }).catch(() => undefined);
|
|
101
|
+
return {
|
|
102
|
+
result: { sessionId, stopped: "signal" },
|
|
103
|
+
human: "Stopped.\n",
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every command of `mostra` (D60, D140 item 13), in the order help lists them. Commands later
|
|
3
|
+
* packages own (`share`, `review export`, `export`, `mcp`, `plugin`, `term`, `run`) join this
|
|
4
|
+
* list with their packages, never as placeholders.
|
|
5
|
+
*/
|
|
6
|
+
import type { CommandDef } from "../command.ts";
|
|
7
|
+
import {
|
|
8
|
+
daemonInstallCommand,
|
|
9
|
+
daemonRestartCommand,
|
|
10
|
+
daemonStartCommand,
|
|
11
|
+
daemonStatusCommand,
|
|
12
|
+
daemonStopCommand,
|
|
13
|
+
daemonUninstallCommand,
|
|
14
|
+
docsCommand,
|
|
15
|
+
doctorCommand,
|
|
16
|
+
gcCommand,
|
|
17
|
+
hostCommand,
|
|
18
|
+
listCommand,
|
|
19
|
+
secretListCommand,
|
|
20
|
+
secretRmCommand,
|
|
21
|
+
secretSetCommand,
|
|
22
|
+
statusCommand,
|
|
23
|
+
telemetryOffCommand,
|
|
24
|
+
telemetryOnCommand,
|
|
25
|
+
telemetryStatusCommand,
|
|
26
|
+
} from "./admin.ts";
|
|
27
|
+
import { addCommand, newCommand, publishCommand, verifyCommand } from "./authoring.ts";
|
|
28
|
+
import { devCommand } from "./dev.ts";
|
|
29
|
+
import {
|
|
30
|
+
pushCommand,
|
|
31
|
+
resultsCommand,
|
|
32
|
+
stateGetCommand,
|
|
33
|
+
statePatchCommand,
|
|
34
|
+
stateSetCommand,
|
|
35
|
+
waitCommand,
|
|
36
|
+
} from "./interaction.ts";
|
|
37
|
+
import { openCommand } from "./viewing.ts";
|
|
38
|
+
|
|
39
|
+
/** The commands, in help's order: the authoring loop first. */
|
|
40
|
+
export const COMMANDS: readonly CommandDef[] = [
|
|
41
|
+
newCommand,
|
|
42
|
+
devCommand,
|
|
43
|
+
verifyCommand,
|
|
44
|
+
publishCommand,
|
|
45
|
+
openCommand,
|
|
46
|
+
waitCommand,
|
|
47
|
+
resultsCommand,
|
|
48
|
+
stateGetCommand,
|
|
49
|
+
stateSetCommand,
|
|
50
|
+
statePatchCommand,
|
|
51
|
+
pushCommand,
|
|
52
|
+
addCommand,
|
|
53
|
+
secretSetCommand,
|
|
54
|
+
secretListCommand,
|
|
55
|
+
secretRmCommand,
|
|
56
|
+
listCommand,
|
|
57
|
+
statusCommand,
|
|
58
|
+
daemonStartCommand,
|
|
59
|
+
daemonStopCommand,
|
|
60
|
+
daemonRestartCommand,
|
|
61
|
+
daemonStatusCommand,
|
|
62
|
+
daemonInstallCommand,
|
|
63
|
+
daemonUninstallCommand,
|
|
64
|
+
hostCommand,
|
|
65
|
+
docsCommand,
|
|
66
|
+
doctorCommand,
|
|
67
|
+
gcCommand,
|
|
68
|
+
telemetryStatusCommand,
|
|
69
|
+
telemetryOnCommand,
|
|
70
|
+
telemetryOffCommand,
|
|
71
|
+
];
|