@mushi-mushi/cli 0.14.0 → 0.15.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/dist/chunk-UTST6AEP.js +6 -0
- package/dist/index.js +330 -39
- package/dist/init.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4W6VOIQT.js +0 -6
package/dist/index.js
CHANGED
|
@@ -598,7 +598,7 @@ function getFrameworkFromPkg(pkg) {
|
|
|
598
598
|
}
|
|
599
599
|
|
|
600
600
|
// src/version.ts
|
|
601
|
-
var MUSHI_CLI_VERSION = true ? "0.
|
|
601
|
+
var MUSHI_CLI_VERSION = true ? "0.15.0" : "0.0.0-dev";
|
|
602
602
|
|
|
603
603
|
// src/init.ts
|
|
604
604
|
var ENV_FILES = [".env.local", ".env"];
|
|
@@ -1088,6 +1088,49 @@ function runMigrate(opts = {}) {
|
|
|
1088
1088
|
return { matches };
|
|
1089
1089
|
}
|
|
1090
1090
|
|
|
1091
|
+
// src/sanitize-config.ts
|
|
1092
|
+
var PROJECT_ID_RE = /^(?:proj_[A-Za-z0-9_-]{10,}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
|
|
1093
|
+
var API_KEY_RE = /^mushi_[A-Za-z0-9_-]{10,}$/;
|
|
1094
|
+
function sanitizeApiKey(raw) {
|
|
1095
|
+
const key = raw.replace(/[\r\n\0]/g, "");
|
|
1096
|
+
if (!API_KEY_RE.test(key)) {
|
|
1097
|
+
throw new Error(
|
|
1098
|
+
"Invalid API key in config \u2014 run `mushi login --api-key <key>` to refresh credentials."
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
return key;
|
|
1102
|
+
}
|
|
1103
|
+
function sanitizeProjectId(raw) {
|
|
1104
|
+
const id = raw.trim();
|
|
1105
|
+
if (!PROJECT_ID_RE.test(id)) {
|
|
1106
|
+
throw new Error(
|
|
1107
|
+
"Invalid project ID in config \u2014 expected a UUID or proj_* slug from the admin console."
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
return id;
|
|
1111
|
+
}
|
|
1112
|
+
function sanitizeEndpoint(raw) {
|
|
1113
|
+
return assertEndpoint(normalizeEndpoint(raw));
|
|
1114
|
+
}
|
|
1115
|
+
function sanitizeCliCredentials(config) {
|
|
1116
|
+
if (!config.endpoint || !config.apiKey || !config.projectId) {
|
|
1117
|
+
throw new Error("Missing endpoint, apiKey, or projectId");
|
|
1118
|
+
}
|
|
1119
|
+
return {
|
|
1120
|
+
endpoint: sanitizeEndpoint(config.endpoint),
|
|
1121
|
+
apiKey: sanitizeApiKey(config.apiKey),
|
|
1122
|
+
projectId: sanitizeProjectId(config.projectId)
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
function apiKeyHeaders(apiKey, projectId) {
|
|
1126
|
+
const headers = {
|
|
1127
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1128
|
+
"X-Mushi-Api-Key": apiKey
|
|
1129
|
+
};
|
|
1130
|
+
if (projectId) headers["X-Mushi-Project"] = projectId;
|
|
1131
|
+
return headers;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1091
1134
|
// src/sourcemaps.ts
|
|
1092
1135
|
import { createReadStream } from "fs";
|
|
1093
1136
|
import { readFile, readdir } from "fs/promises";
|
|
@@ -1430,13 +1473,11 @@ var IngestSetupHttpError = class extends Error {
|
|
|
1430
1473
|
};
|
|
1431
1474
|
var NON_RETRYABLE_STATUSES = /* @__PURE__ */ new Set([401, 403, 404]);
|
|
1432
1475
|
async function fetchIngestSetup(config, doFetch = globalThis.fetch) {
|
|
1433
|
-
const
|
|
1434
|
-
const
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
...config.projectId ? { "X-Mushi-Project": config.projectId } : {}
|
|
1439
|
-
},
|
|
1476
|
+
const endpoint = sanitizeEndpoint(config.endpoint);
|
|
1477
|
+
const apiKey = sanitizeApiKey(config.apiKey);
|
|
1478
|
+
const projectId = config.projectId ? sanitizeProjectId(config.projectId) : void 0;
|
|
1479
|
+
const res = await doFetch(`${endpoint}/v1/sync/ingest-setup`, {
|
|
1480
|
+
headers: apiKeyHeaders(apiKey, projectId),
|
|
1440
1481
|
signal: AbortSignal.timeout(8e3)
|
|
1441
1482
|
});
|
|
1442
1483
|
if (!res.ok) {
|
|
@@ -1511,13 +1552,14 @@ function checkCliConfig(config) {
|
|
|
1511
1552
|
}
|
|
1512
1553
|
async function checkEndpointReachability(endpoint, doFetch = globalThis.fetch) {
|
|
1513
1554
|
try {
|
|
1514
|
-
const
|
|
1555
|
+
const safeEndpoint = sanitizeEndpoint(endpoint);
|
|
1556
|
+
const res = await doFetch(`${safeEndpoint}/health`, {
|
|
1515
1557
|
signal: AbortSignal.timeout(5e3)
|
|
1516
1558
|
});
|
|
1517
1559
|
return {
|
|
1518
1560
|
name: "Endpoint reachable",
|
|
1519
1561
|
ok: res.status === 200,
|
|
1520
|
-
detail: `GET ${
|
|
1562
|
+
detail: `GET ${safeEndpoint}/health \u2192 ${res.status}`
|
|
1521
1563
|
};
|
|
1522
1564
|
} catch (err) {
|
|
1523
1565
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1559,14 +1601,11 @@ async function checkServerPreflight(config, doFetch = globalThis.fetch) {
|
|
|
1559
1601
|
];
|
|
1560
1602
|
}
|
|
1561
1603
|
try {
|
|
1604
|
+
const { endpoint, apiKey, projectId } = sanitizeCliCredentials(config);
|
|
1562
1605
|
const res = await doFetch(
|
|
1563
|
-
`${
|
|
1606
|
+
`${endpoint}/v1/admin/projects/${projectId}/preflight`,
|
|
1564
1607
|
{
|
|
1565
|
-
headers:
|
|
1566
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
1567
|
-
"X-Mushi-Api-Key": config.apiKey,
|
|
1568
|
-
"X-Mushi-Project": config.projectId
|
|
1569
|
-
},
|
|
1608
|
+
headers: apiKeyHeaders(apiKey, projectId),
|
|
1570
1609
|
signal: AbortSignal.timeout(8e3)
|
|
1571
1610
|
}
|
|
1572
1611
|
);
|
|
@@ -1642,14 +1681,12 @@ async function checkQaStoriesHealth(config, doFetch = globalThis.fetch) {
|
|
|
1642
1681
|
}
|
|
1643
1682
|
const checks = [];
|
|
1644
1683
|
try {
|
|
1684
|
+
const { endpoint, apiKey, projectId } = sanitizeCliCredentials(config);
|
|
1685
|
+
const headers = apiKeyHeaders(apiKey, projectId);
|
|
1645
1686
|
const storiesRes = await doFetch(
|
|
1646
|
-
`${
|
|
1687
|
+
`${endpoint}/v1/admin/projects/${projectId}/qa-coverage`,
|
|
1647
1688
|
{
|
|
1648
|
-
headers
|
|
1649
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
1650
|
-
"X-Mushi-Api-Key": config.apiKey,
|
|
1651
|
-
"X-Mushi-Project": config.projectId
|
|
1652
|
-
},
|
|
1689
|
+
headers,
|
|
1653
1690
|
signal: AbortSignal.timeout(8e3)
|
|
1654
1691
|
}
|
|
1655
1692
|
);
|
|
@@ -1670,14 +1707,10 @@ async function checkQaStoriesHealth(config, doFetch = globalThis.fetch) {
|
|
|
1670
1707
|
detail: `${enabled.length} enabled story/stories configured`
|
|
1671
1708
|
});
|
|
1672
1709
|
const slackRes = await doFetch(
|
|
1673
|
-
`${
|
|
1710
|
+
`${endpoint}/v1/admin/projects/${projectId}/integrations/probe/slack`,
|
|
1674
1711
|
{
|
|
1675
1712
|
method: "POST",
|
|
1676
|
-
headers
|
|
1677
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
1678
|
-
"X-Mushi-Api-Key": config.apiKey,
|
|
1679
|
-
"X-Mushi-Project": config.projectId
|
|
1680
|
-
},
|
|
1713
|
+
headers,
|
|
1681
1714
|
signal: AbortSignal.timeout(6e3)
|
|
1682
1715
|
}
|
|
1683
1716
|
);
|
|
@@ -1689,14 +1722,10 @@ async function checkQaStoriesHealth(config, doFetch = globalThis.fetch) {
|
|
|
1689
1722
|
detail: slackOk ? "Slack connected \u2014 failures will notify your channel" : "Slack not connected \u2014 you won't be notified when stories fail. Visit /integrations \u2192 Add to Slack."
|
|
1690
1723
|
});
|
|
1691
1724
|
const fcRes = await doFetch(
|
|
1692
|
-
`${
|
|
1725
|
+
`${endpoint}/v1/admin/projects/${projectId}/integrations/probe/firecrawl`,
|
|
1693
1726
|
{
|
|
1694
1727
|
method: "POST",
|
|
1695
|
-
headers
|
|
1696
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
1697
|
-
"X-Mushi-Api-Key": config.apiKey,
|
|
1698
|
-
"X-Mushi-Project": config.projectId
|
|
1699
|
-
},
|
|
1728
|
+
headers,
|
|
1700
1729
|
signal: AbortSignal.timeout(6e3)
|
|
1701
1730
|
}
|
|
1702
1731
|
);
|
|
@@ -3760,11 +3789,22 @@ Examples:
|
|
|
3760
3789
|
mushi audit --json
|
|
3761
3790
|
mushi audit --project-id abc123`).action(async (opts) => {
|
|
3762
3791
|
const config = requireConfig();
|
|
3763
|
-
const
|
|
3764
|
-
if (!
|
|
3792
|
+
const rawProjectId = opts.projectId ?? config.projectId;
|
|
3793
|
+
if (!rawProjectId) {
|
|
3765
3794
|
process.stderr.write("error: project ID required. Run `mushi login` or pass --project-id\n");
|
|
3766
3795
|
process.exit(1);
|
|
3767
3796
|
}
|
|
3797
|
+
let endpoint;
|
|
3798
|
+
let projectId;
|
|
3799
|
+
try {
|
|
3800
|
+
endpoint = sanitizeEndpoint(config.endpoint);
|
|
3801
|
+
projectId = sanitizeProjectId(rawProjectId);
|
|
3802
|
+
} catch (err) {
|
|
3803
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3804
|
+
process.stderr.write(`error: ${msg}
|
|
3805
|
+
`);
|
|
3806
|
+
process.exit(2);
|
|
3807
|
+
}
|
|
3768
3808
|
const headers = {
|
|
3769
3809
|
"Content-Type": "application/json",
|
|
3770
3810
|
"X-Mushi-Project-Id": projectId
|
|
@@ -3772,9 +3812,9 @@ Examples:
|
|
|
3772
3812
|
const jwt = config.jwt ?? null;
|
|
3773
3813
|
const apiKey = config.apiKey ?? null;
|
|
3774
3814
|
if (jwt) {
|
|
3775
|
-
headers["Authorization"] = `Bearer ${jwt}`;
|
|
3815
|
+
headers["Authorization"] = `Bearer ${jwt.replace(/[\r\n\0]/g, "")}`;
|
|
3776
3816
|
} else if (apiKey) {
|
|
3777
|
-
headers["X-Mushi-Api-Key"] = apiKey;
|
|
3817
|
+
headers["X-Mushi-Api-Key"] = sanitizeApiKey(apiKey);
|
|
3778
3818
|
} else {
|
|
3779
3819
|
process.stderr.write("error: no credentials found. Run `mushi login` first.\n");
|
|
3780
3820
|
process.exit(1);
|
|
@@ -3784,7 +3824,7 @@ Examples:
|
|
|
3784
3824
|
const controller = new AbortController();
|
|
3785
3825
|
const timer = setTimeout(() => controller.abort(), 3e4);
|
|
3786
3826
|
const res = await fetch(
|
|
3787
|
-
`${
|
|
3827
|
+
`${endpoint}/v1/admin/projects/${projectId}/audit`,
|
|
3788
3828
|
{ method: "POST", headers, body: "{}", signal: controller.signal }
|
|
3789
3829
|
);
|
|
3790
3830
|
clearTimeout(timer);
|
|
@@ -3845,3 +3885,254 @@ program.parseAsync().catch((err) => {
|
|
|
3845
3885
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3846
3886
|
process.exit(1);
|
|
3847
3887
|
});
|
|
3888
|
+
var skills = program.command("skills").description("Manage agent skill catalog");
|
|
3889
|
+
skills.command("list").description("List all skills in the catalog").option("--category <cat>", "Filter by category (workflow, debug, test, audit, \u2026)").option("--search <q>", "Search slug, title, or description").option("--page <n>", "Page number (default 1)", "1").option("--limit <n>", "Max results per page (1\u2013200, default 200)", "200").option("--json", "Machine-readable output").action(async (opts) => {
|
|
3890
|
+
const config = loadConfig();
|
|
3891
|
+
if (!config.apiKey) {
|
|
3892
|
+
console.error("Run `mushi login` first");
|
|
3893
|
+
process.exit(2);
|
|
3894
|
+
}
|
|
3895
|
+
const qs = new URLSearchParams();
|
|
3896
|
+
if (opts.category) qs.set("category", opts.category);
|
|
3897
|
+
if (opts.search) qs.set("q", opts.search);
|
|
3898
|
+
qs.set("page", String(Math.max(1, parseInt(opts.page) || 1)));
|
|
3899
|
+
qs.set("limit", String(Math.min(Math.max(1, parseInt(opts.limit) || 200), 200)));
|
|
3900
|
+
const result = await apiCall(
|
|
3901
|
+
`/v1/admin/skills?${qs}`,
|
|
3902
|
+
config
|
|
3903
|
+
);
|
|
3904
|
+
if (!result.ok) {
|
|
3905
|
+
console.error("Failed:", result.error);
|
|
3906
|
+
process.exit(1);
|
|
3907
|
+
}
|
|
3908
|
+
const rows = result.data ?? [];
|
|
3909
|
+
if (opts.json) {
|
|
3910
|
+
console.log(JSON.stringify({ skills: rows, count: rows.length }, null, 2));
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3913
|
+
if (rows.length === 0) {
|
|
3914
|
+
console.log("No skills in catalog. Add a source with `mushi skills sync`.");
|
|
3915
|
+
return;
|
|
3916
|
+
}
|
|
3917
|
+
console.log(`
|
|
3918
|
+
Skill catalog (${rows.length} skills):
|
|
3919
|
+
`);
|
|
3920
|
+
let lastCat = "";
|
|
3921
|
+
for (const s of rows) {
|
|
3922
|
+
if (s.category !== lastCat) {
|
|
3923
|
+
lastCat = s.category;
|
|
3924
|
+
console.log(`
|
|
3925
|
+
[${s.category}]`);
|
|
3926
|
+
}
|
|
3927
|
+
const chain = s.chain_slugs?.length ? ` \u2192 ${s.chain_slugs.length} steps` : "";
|
|
3928
|
+
console.log(` ${s.slug.padEnd(40)} ${s.title}${chain}`);
|
|
3929
|
+
}
|
|
3930
|
+
console.log();
|
|
3931
|
+
});
|
|
3932
|
+
skills.command("show <slug>").description("Show full details and chain for a skill").action(async (slug) => {
|
|
3933
|
+
const config = loadConfig();
|
|
3934
|
+
if (!config.apiKey) {
|
|
3935
|
+
console.error("Run `mushi login` first");
|
|
3936
|
+
process.exit(2);
|
|
3937
|
+
}
|
|
3938
|
+
const result = await apiCall(`/v1/admin/skills/${slug}`, config);
|
|
3939
|
+
if (!result.ok) {
|
|
3940
|
+
console.error("Skill not found:", slug);
|
|
3941
|
+
process.exit(1);
|
|
3942
|
+
}
|
|
3943
|
+
const s = result.data;
|
|
3944
|
+
console.log(`
|
|
3945
|
+
${s.title} (${s.slug})
|
|
3946
|
+
${"\u2500".repeat(50)}`);
|
|
3947
|
+
console.log(`Category: ${s.category}`);
|
|
3948
|
+
console.log(`Chain: ${s.chain_slugs?.length ? s.chain_slugs.join(" \u2192 ") : "none"}`);
|
|
3949
|
+
console.log(`
|
|
3950
|
+
Description:
|
|
3951
|
+
${s.description}
|
|
3952
|
+
`);
|
|
3953
|
+
});
|
|
3954
|
+
skills.command("sync").description("Trigger skill sync for all configured skill sources").option("--source-id <id>", "Sync only a specific source ID").action(async (opts) => {
|
|
3955
|
+
const config = loadConfig();
|
|
3956
|
+
if (!config.apiKey) {
|
|
3957
|
+
console.error("Run `mushi login` first");
|
|
3958
|
+
process.exit(2);
|
|
3959
|
+
}
|
|
3960
|
+
if (!config.projectId) {
|
|
3961
|
+
console.error("No projectId. Run `mushi config projectId <uuid>`");
|
|
3962
|
+
process.exit(2);
|
|
3963
|
+
}
|
|
3964
|
+
let ids;
|
|
3965
|
+
if (opts.sourceId) {
|
|
3966
|
+
ids = [opts.sourceId];
|
|
3967
|
+
} else {
|
|
3968
|
+
const sourcesResult = await apiCall(
|
|
3969
|
+
`/v1/admin/skills/sources?project_id=${config.projectId}`,
|
|
3970
|
+
config
|
|
3971
|
+
);
|
|
3972
|
+
if (!sourcesResult.ok) {
|
|
3973
|
+
console.error("Failed to list sources:", sourcesResult.error);
|
|
3974
|
+
process.exit(1);
|
|
3975
|
+
}
|
|
3976
|
+
ids = (sourcesResult.data ?? []).map((s) => s.id);
|
|
3977
|
+
}
|
|
3978
|
+
if (ids.length === 0) {
|
|
3979
|
+
console.log("No skill sources configured. Add one in the Skill Pipelines console page.");
|
|
3980
|
+
return;
|
|
3981
|
+
}
|
|
3982
|
+
for (const id of ids) {
|
|
3983
|
+
console.log(`Syncing source ${id.slice(0, 8)}\u2026`);
|
|
3984
|
+
const result = await apiCall(
|
|
3985
|
+
`/v1/admin/skills/sources/${id}/sync`,
|
|
3986
|
+
config,
|
|
3987
|
+
{ method: "POST" }
|
|
3988
|
+
);
|
|
3989
|
+
if (!result.ok) {
|
|
3990
|
+
console.error(" Sync failed:", result.error);
|
|
3991
|
+
} else console.log(` Done: ${result.data?.synced ?? 0} synced, ${result.data?.skipped ?? 0} skipped, ${result.data?.errors ?? 0} errors`);
|
|
3992
|
+
}
|
|
3993
|
+
console.log();
|
|
3994
|
+
});
|
|
3995
|
+
var pipeline = program.command("pipeline").description("Manage skill pipeline runs");
|
|
3996
|
+
pipeline.command("start <reportId>").description("Start a skill pipeline for a report").requiredOption("--skill <slug>", "Root skill slug (e.g. workflow-fix-and-ship)").option("--mode <mode>", "Execution mode: handoff (default) or cloud", "handoff").option("--json", "Machine-readable output").action(async (reportId, opts) => {
|
|
3997
|
+
const config = loadConfig();
|
|
3998
|
+
if (!config.apiKey) {
|
|
3999
|
+
console.error("Run `mushi login` first");
|
|
4000
|
+
process.exit(2);
|
|
4001
|
+
}
|
|
4002
|
+
if (!config.projectId) {
|
|
4003
|
+
console.error("No projectId. Run `mushi config projectId <uuid>`");
|
|
4004
|
+
process.exit(2);
|
|
4005
|
+
}
|
|
4006
|
+
const result = await apiCall(
|
|
4007
|
+
`/v1/admin/skills/pipelines`,
|
|
4008
|
+
config,
|
|
4009
|
+
{
|
|
4010
|
+
method: "POST",
|
|
4011
|
+
body: JSON.stringify({
|
|
4012
|
+
project_id: config.projectId,
|
|
4013
|
+
root_skill_slug: opts.skill,
|
|
4014
|
+
report_id: reportId,
|
|
4015
|
+
mode: opts.mode
|
|
4016
|
+
})
|
|
4017
|
+
}
|
|
4018
|
+
);
|
|
4019
|
+
if (!result.ok) {
|
|
4020
|
+
console.error("Failed:", result.error);
|
|
4021
|
+
process.exit(1);
|
|
4022
|
+
}
|
|
4023
|
+
if (opts.json) {
|
|
4024
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
4025
|
+
return;
|
|
4026
|
+
}
|
|
4027
|
+
const runId = result.data?.id ?? "";
|
|
4028
|
+
const chain = result.data?.chain_slugs ?? [];
|
|
4029
|
+
console.log(`
|
|
4030
|
+
Pipeline started!
|
|
4031
|
+
`);
|
|
4032
|
+
console.log(` Run ID: ${runId.slice(0, 8)}\u2026 (full: ${runId})`);
|
|
4033
|
+
console.log(` Skill: ${opts.skill}`);
|
|
4034
|
+
console.log(` Chain: ${chain.length > 0 ? chain.join(" \u2192 ") : "(root only)"}`);
|
|
4035
|
+
console.log(` Mode: ${opts.mode}`);
|
|
4036
|
+
if (opts.mode === "handoff") {
|
|
4037
|
+
console.log(`
|
|
4038
|
+
Get context packet: mushi pipeline watch ${runId.slice(0, 8)}`);
|
|
4039
|
+
console.log(` Check in step 0: mushi pipeline checkin ${runId.slice(0, 8)} --step 0 --status passed`);
|
|
4040
|
+
}
|
|
4041
|
+
console.log();
|
|
4042
|
+
});
|
|
4043
|
+
pipeline.command("watch <runIdOrPrefix>").description("Watch a pipeline run and print the context packet").option("--json", "Machine-readable output").action(async (runIdOrPrefix, opts) => {
|
|
4044
|
+
const config = loadConfig();
|
|
4045
|
+
if (!config.apiKey) {
|
|
4046
|
+
console.error("Run `mushi login` first");
|
|
4047
|
+
process.exit(2);
|
|
4048
|
+
}
|
|
4049
|
+
let runId = runIdOrPrefix;
|
|
4050
|
+
if (runIdOrPrefix.length < 36) {
|
|
4051
|
+
const list = await apiCall(
|
|
4052
|
+
`/v1/admin/skills/pipelines?project_id=${config.projectId}&limit=50`,
|
|
4053
|
+
config
|
|
4054
|
+
);
|
|
4055
|
+
if (!list.ok) {
|
|
4056
|
+
console.error("Failed:", list.error);
|
|
4057
|
+
process.exit(1);
|
|
4058
|
+
}
|
|
4059
|
+
const match = list.data.find((r) => r.id.startsWith(runIdOrPrefix));
|
|
4060
|
+
if (!match) {
|
|
4061
|
+
console.error("Run not found:", runIdOrPrefix);
|
|
4062
|
+
process.exit(1);
|
|
4063
|
+
}
|
|
4064
|
+
runId = match.id;
|
|
4065
|
+
}
|
|
4066
|
+
const result = await apiCall(
|
|
4067
|
+
`/v1/admin/skills/pipelines/${runId}`,
|
|
4068
|
+
config
|
|
4069
|
+
);
|
|
4070
|
+
if (!result.ok) {
|
|
4071
|
+
console.error("Failed:", result.error);
|
|
4072
|
+
process.exit(1);
|
|
4073
|
+
}
|
|
4074
|
+
if (opts.json) {
|
|
4075
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
4076
|
+
return;
|
|
4077
|
+
}
|
|
4078
|
+
const run = result.data;
|
|
4079
|
+
const statusIcon = run.status === "completed" ? "\u2705" : run.status === "failed" ? "\u274C" : run.status === "running" ? "\u23F3" : "\u26AA";
|
|
4080
|
+
console.log(`
|
|
4081
|
+
${statusIcon} Pipeline ${runId.slice(0, 8)} \xB7 ${run.root_skill_slug} \xB7 ${run.mode}
|
|
4082
|
+
`);
|
|
4083
|
+
const steps = run.steps ?? [];
|
|
4084
|
+
for (const step of steps) {
|
|
4085
|
+
const icon = step.status === "passed" ? "\u2705" : step.status === "failed" ? "\u274C" : step.status === "running" ? "\u23F3" : "\u26AA";
|
|
4086
|
+
const pr = step.pr_url ? ` \u2192 ${step.pr_url}` : "";
|
|
4087
|
+
console.log(` ${icon} Step ${step.step_index + 1}: ${step.skill_slug}${pr}`);
|
|
4088
|
+
if (step.notes) console.log(` ${step.notes}`);
|
|
4089
|
+
}
|
|
4090
|
+
if (run.context_packet) {
|
|
4091
|
+
console.log(`
|
|
4092
|
+
${"\u2500".repeat(60)}`);
|
|
4093
|
+
console.log(`Context Packet (paste into your Cursor agent):
|
|
4094
|
+
`);
|
|
4095
|
+
console.log(run.context_packet.slice(0, 6e3));
|
|
4096
|
+
if (run.context_packet.length > 6e3) console.log("\n\u2026 [truncated \u2014 full packet via --json]");
|
|
4097
|
+
}
|
|
4098
|
+
console.log();
|
|
4099
|
+
});
|
|
4100
|
+
pipeline.command("checkin <runIdOrPrefix>").description("Check in a pipeline step (CLI agent reports status after completing a step)").requiredOption("--step <n>", "Step index (0-based)", parseInt).requiredOption("--status <status>", "Step status: passed | failed | running | skipped").option("--notes <text>", "Optional notes / output summary").option("--pr-url <url>", "PR URL opened during this step").action(async (runIdOrPrefix, opts) => {
|
|
4101
|
+
const config = loadConfig();
|
|
4102
|
+
if (!config.apiKey) {
|
|
4103
|
+
console.error("Run `mushi login` first");
|
|
4104
|
+
process.exit(2);
|
|
4105
|
+
}
|
|
4106
|
+
let runId = runIdOrPrefix;
|
|
4107
|
+
if (runIdOrPrefix.length < 36) {
|
|
4108
|
+
const list = await apiCall(
|
|
4109
|
+
`/v1/admin/skills/pipelines?project_id=${config.projectId}&limit=50`,
|
|
4110
|
+
config
|
|
4111
|
+
);
|
|
4112
|
+
if (!list.ok) {
|
|
4113
|
+
console.error("Failed:", list.error);
|
|
4114
|
+
process.exit(1);
|
|
4115
|
+
}
|
|
4116
|
+
const match = list.data.find((r) => r.id.startsWith(runIdOrPrefix));
|
|
4117
|
+
if (!match) {
|
|
4118
|
+
console.error("Run not found:", runIdOrPrefix);
|
|
4119
|
+
process.exit(1);
|
|
4120
|
+
}
|
|
4121
|
+
runId = match.id;
|
|
4122
|
+
}
|
|
4123
|
+
const result = await apiCall(
|
|
4124
|
+
`/v1/admin/skills/pipelines/${runId}/steps/${opts.step}/checkin`,
|
|
4125
|
+
config,
|
|
4126
|
+
{
|
|
4127
|
+
method: "POST",
|
|
4128
|
+
body: JSON.stringify({ status: opts.status, notes: opts.notes, pr_url: opts.prUrl })
|
|
4129
|
+
}
|
|
4130
|
+
);
|
|
4131
|
+
if (!result.ok) {
|
|
4132
|
+
console.error("Failed:", result.error);
|
|
4133
|
+
process.exit(1);
|
|
4134
|
+
}
|
|
4135
|
+
console.log(` Step ${opts.step} \u2192 ${opts.status}. Console live flow updated.`);
|
|
4136
|
+
console.log(` Next: mushi pipeline watch ${runId.slice(0, 8)}`);
|
|
4137
|
+
console.log();
|
|
4138
|
+
});
|
package/dist/init.js
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED