@shipd-ai/cli 0.1.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/README.md +133 -0
- package/dist/auth.d.ts +26 -0
- package/dist/auth.js +75 -0
- package/dist/client.d.ts +51 -0
- package/dist/client.js +70 -0
- package/dist/commands/auth.d.ts +22 -0
- package/dist/commands/auth.js +109 -0
- package/dist/commands/checks.d.ts +12 -0
- package/dist/commands/checks.js +669 -0
- package/dist/contract.d.ts +129 -0
- package/dist/contract.js +24 -0
- package/dist/errors.d.ts +20 -0
- package/dist/errors.js +49 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.js +93 -0
- package/dist/harbor.d.ts +25 -0
- package/dist/harbor.js +137 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +95 -0
- package/dist/plan.d.ts +65 -0
- package/dist/plan.js +367 -0
- package/dist/quests.d.ts +24 -0
- package/dist/quests.js +181 -0
- package/dist/report.d.ts +62 -0
- package/dist/report.js +107 -0
- package/package.json +43 -0
package/dist/report.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { EXIT_CANCELLED, EXIT_CHECK_FAILED, EXIT_OK } from "./errors.js";
|
|
4
|
+
import { formatDuration, formatTable, statusBadge, truncate } from "./format.js";
|
|
5
|
+
export function modeLabel(mode) {
|
|
6
|
+
return mode === "harbor" ? "stateless, nothing written" : "live: writes to production";
|
|
7
|
+
}
|
|
8
|
+
/** The precheck stage status, as the product spells it, mapped to a verdict. */
|
|
9
|
+
export function precheckVerdict(status) {
|
|
10
|
+
const lower = status.toLowerCase();
|
|
11
|
+
if (lower === "missing_fields")
|
|
12
|
+
return "skipped";
|
|
13
|
+
return lower;
|
|
14
|
+
}
|
|
15
|
+
/** A one-line human detail for a check row. */
|
|
16
|
+
export function checkDetail(check) {
|
|
17
|
+
if (check.error)
|
|
18
|
+
return check.error;
|
|
19
|
+
if (check.reason)
|
|
20
|
+
return check.reason;
|
|
21
|
+
const output = check.output;
|
|
22
|
+
if (output && typeof output === "object") {
|
|
23
|
+
const o = output;
|
|
24
|
+
if (check.kind === "precheck" && Array.isArray(o.checks)) {
|
|
25
|
+
const checks = o.checks;
|
|
26
|
+
const passed = checks.filter((c) => String(c.status).toLowerCase() === "pass").length;
|
|
27
|
+
return `${passed}/${checks.length} checks pass`;
|
|
28
|
+
}
|
|
29
|
+
for (const key of ["summary", "message", "reasoning"]) {
|
|
30
|
+
if (typeof o[key] === "string" && o[key].trim())
|
|
31
|
+
return o[key];
|
|
32
|
+
}
|
|
33
|
+
const evaluation = o.evaluation;
|
|
34
|
+
if (evaluation && typeof evaluation === "object") {
|
|
35
|
+
const summary = evaluation.summary;
|
|
36
|
+
if (typeof summary === "string")
|
|
37
|
+
return summary;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return "";
|
|
41
|
+
}
|
|
42
|
+
export function renderTable(report, opts = {}) {
|
|
43
|
+
const color = opts.color ?? false;
|
|
44
|
+
const checks = Object.values(report.checks);
|
|
45
|
+
const rows = checks.map((check) => ({
|
|
46
|
+
check: check.key,
|
|
47
|
+
kind: check.kind,
|
|
48
|
+
status: statusBadge(check.status, color),
|
|
49
|
+
verdict: check.verdict ? statusBadge(String(check.verdict), color) : "",
|
|
50
|
+
time: formatDuration(check.durationMs),
|
|
51
|
+
detail: truncate(checkDetail(check), 70),
|
|
52
|
+
}));
|
|
53
|
+
const lines = [
|
|
54
|
+
` Quest: ${report.quest} (${modeLabel(report.mode)})`,
|
|
55
|
+
...sourceLines(report.source),
|
|
56
|
+
"",
|
|
57
|
+
...formatTable(rows, [
|
|
58
|
+
{ key: "check", label: "Check" },
|
|
59
|
+
{ key: "kind", label: "Kind" },
|
|
60
|
+
{ key: "status", label: "Status" },
|
|
61
|
+
{ key: "verdict", label: "Verdict" },
|
|
62
|
+
{ key: "time", label: "Time" },
|
|
63
|
+
{ key: "detail", label: "Detail" },
|
|
64
|
+
]),
|
|
65
|
+
];
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}
|
|
68
|
+
function sourceLines(source) {
|
|
69
|
+
const lines = [];
|
|
70
|
+
if (source.dir)
|
|
71
|
+
lines.push(` Bundle: ${source.dir}`);
|
|
72
|
+
if (source.inputHash)
|
|
73
|
+
lines.push(` Input: ${source.inputHash}`);
|
|
74
|
+
if (source.problemId) {
|
|
75
|
+
const title = source.title ? ` "${source.title}"` : "";
|
|
76
|
+
lines.push(` Task: ${source.problemId}${title} (version ${source.versionId})`);
|
|
77
|
+
}
|
|
78
|
+
if (source.url)
|
|
79
|
+
lines.push(` URL: ${source.url}`);
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
const BAD_VERDICTS = new Set(["fail", "error"]);
|
|
83
|
+
/**
|
|
84
|
+
* 0 when every run check passed or warned; 1 when any failed or errored (or
|
|
85
|
+
* an explicitly requested check was skipped); 3 when any check was cancelled.
|
|
86
|
+
*/
|
|
87
|
+
export function exitCodeFor(report) {
|
|
88
|
+
const checks = Object.values(report.checks);
|
|
89
|
+
if (checks.some((c) => c.status === "cancelled"))
|
|
90
|
+
return EXIT_CANCELLED;
|
|
91
|
+
for (const check of checks) {
|
|
92
|
+
if (check.status === "failed" || check.status === "error")
|
|
93
|
+
return EXIT_CHECK_FAILED;
|
|
94
|
+
if (check.status === "skipped" && report.selection === "explicit")
|
|
95
|
+
return EXIT_CHECK_FAILED;
|
|
96
|
+
if (check.status === "completed" && check.verdict && BAD_VERDICTS.has(String(check.verdict))) {
|
|
97
|
+
return EXIT_CHECK_FAILED;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return EXIT_OK;
|
|
101
|
+
}
|
|
102
|
+
export async function writeReport(report, path) {
|
|
103
|
+
const target = resolve(path);
|
|
104
|
+
await mkdir(dirname(target), { recursive: true });
|
|
105
|
+
await writeFile(target, `${JSON.stringify(report, null, 2)}\n`);
|
|
106
|
+
return target;
|
|
107
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shipd-ai/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shipd admin CLI — run quest checks on Harbor tasks or existing tasks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://shipd.ai",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"shipd",
|
|
9
|
+
"harbor",
|
|
10
|
+
"cli",
|
|
11
|
+
"convex"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"shipd": "dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
21
|
+
"cli": "tsx src/index.ts",
|
|
22
|
+
"prepack": "pnpm build",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"typecheck": "tsc --noEmit"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"citty": "^0.2.1",
|
|
34
|
+
"convex": "1.39.1",
|
|
35
|
+
"smol-toml": "^1.3.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"tsx": "^4.21.0",
|
|
40
|
+
"typescript": "~5.7.0",
|
|
41
|
+
"vitest": "^3.0.5"
|
|
42
|
+
}
|
|
43
|
+
}
|