@keystrokehq/cli 0.0.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-blurb.md +123 -0
- package/LICENSE +42 -0
- package/README.md +177 -0
- package/THIRD_PARTY_NOTICES.md +16 -0
- package/bin/keystroke.mjs +107 -0
- package/dist/_manifest-JSRE3H8k.mjs +385 -0
- package/dist/agent-bundle-package-DWV6B_5q-BtV7Xycc.mjs +2344 -0
- package/dist/agent-manifest-CDnbkR2f.mjs +245 -0
- package/dist/agents-CZJGxVqV.mjs +228 -0
- package/dist/api-keys-D2lgguuY.mjs +40 -0
- package/dist/auth-DN2VusyU.mjs +59 -0
- package/dist/auth.handler-CT1BQUvu.mjs +340 -0
- package/dist/browser-qwFrUH82.mjs +24 -0
- package/dist/build-agents-BmM_AsSd-BGi9wtzt.mjs +514 -0
- package/dist/build-metadata-BWS7uhd_-DR8gJjTX.mjs +1422 -0
- package/dist/build-progress-DgYKb4hB.mjs +183 -0
- package/dist/build-tasks-CdihpudT-D5r5HUHe.mjs +91 -0
- package/dist/build-workflows-CfxBnIWh-CdYPv8w2.mjs +370 -0
- package/dist/build.handler-4799CjWH.mjs +36 -0
- package/dist/chunk-CH6r78ws.mjs +37 -0
- package/dist/clear-cache.handler-B9tqSoSM.mjs +11 -0
- package/dist/clear.handler-BTIXXPTJ.mjs +42 -0
- package/dist/clear.handler-BydlX-zE.mjs +11 -0
- package/dist/commander-DfTVqQ-3.mjs +133 -0
- package/dist/concurrency-gXn9Rw8x-DNl2YtrS.mjs +20 -0
- package/dist/connect-BUXkeH0F.mjs +43 -0
- package/dist/connect.handler-CYel9cy6.mjs +430 -0
- package/dist/constants-CPpPdSNg.mjs +8 -0
- package/dist/context-T7HZuB97.mjs +138 -0
- package/dist/credential-env-map-CI8yWHVy.mjs +28 -0
- package/dist/credential-schema-mismatch-BKo5PjcQ.mjs +76 -0
- package/dist/credentials-CvmjU0lK.mjs +171 -0
- package/dist/credentials-OfVHOtG3.mjs +151216 -0
- package/dist/current-deployment-workflow-poHt27i3.mjs +94 -0
- package/dist/current.handler-B8zKzfPp.mjs +21 -0
- package/dist/delete.handler-bAu1iXVQ.mjs +17 -0
- package/dist/deploy-7Jjls436.mjs +26 -0
- package/dist/deploy-BOPIpRWm.mjs +74 -0
- package/dist/deploy-progress-BmGUNFKg.mjs +70 -0
- package/dist/deploy.handler-BAzgiNhd.mjs +370 -0
- package/dist/detect-env-access-CwkOYeYM-D_BCZqV6.mjs +209 -0
- package/dist/diff-utils-NEfcjqxt.mjs +185 -0
- package/dist/diff.handler-Du7SY8K4.mjs +47 -0
- package/dist/dist-BkJUoBiG.mjs +1116 -0
- package/dist/dist-CUK7yBM0.mjs +308 -0
- package/dist/env-91KwMKov.mjs +140 -0
- package/dist/env.handler-BAzBuMzQ.mjs +277 -0
- package/dist/error-boundary-VL-JLfIa.mjs +34 -0
- package/dist/file-metadata-D1vm-XY2.mjs +191 -0
- package/dist/get-intrinsic-zLxwtrLK.mjs +658 -0
- package/dist/import-module-CV84H5fZ-B_CBCmb4.mjs +1747 -0
- package/dist/init-DpMCotSK.mjs +45 -0
- package/dist/init.handler-CPRnif52.mjs +585 -0
- package/dist/inspect.handler-DT_cD036.mjs +146 -0
- package/dist/integration-catalog-Bt-L3GjF.mjs +104 -0
- package/dist/integrations-DlatPK4W.mjs +79 -0
- package/dist/keystroke.d.mts +3 -0
- package/dist/keystroke.mjs +707 -0
- package/dist/layout-CbMtQ2tm.mjs +67 -0
- package/dist/list-enrichment-y-cwizLr.mjs +189 -0
- package/dist/list.handler-BTWvCyjA.mjs +52 -0
- package/dist/list.handler-CWF_Dj15.mjs +24 -0
- package/dist/list.handler-CZ6G2x_G.mjs +75 -0
- package/dist/list.handler-DWaQkJaR.mjs +51 -0
- package/dist/list.handler-DqbFcBW7.mjs +180 -0
- package/dist/list.handler-lq3ZGAn4.mjs +104 -0
- package/dist/logs-BEg9L5l8.mjs +28 -0
- package/dist/logs.handler-6hoMBzqw.mjs +35 -0
- package/dist/logs.handler-BD_dXiL1.mjs +231 -0
- package/dist/metadata-layout-GUYIUo0i-_aG2zjue.mjs +5877 -0
- package/dist/normalize-path-CojS-CgQ-DLCOvnD1.mjs +20 -0
- package/dist/options-CeaTcFxP.mjs +43 -0
- package/dist/org-xLzBtt2_.mjs +41 -0
- package/dist/output-DM4b7KgY.mjs +72 -0
- package/dist/oxc-B3KI3rf_-n9d1hKNq.mjs +119 -0
- package/dist/paused.handler-BMFm9Cff.mjs +94 -0
- package/dist/project-config-D1qsQlO7.mjs +107 -0
- package/dist/projects-CHkRE9rS.mjs +1574 -0
- package/dist/projects-Cjb7sovS.mjs +30 -0
- package/dist/read-credential-keys-77a91T8M-KA0Iw0Z1.mjs +9 -0
- package/dist/register.handler-BPCdor1_.mjs +86 -0
- package/dist/requirements.handler-DPXdSks3.mjs +201 -0
- package/dist/resolve-project-DDJ29sCF.mjs +35 -0
- package/dist/rolldown-runtime-twds-ZHy-BWWzu8VG.mjs +15 -0
- package/dist/run-polling-CAgFRdK3.mjs +20 -0
- package/dist/runs-D9hNLb9A.mjs +259 -0
- package/dist/schedule-BXx3uXwr.mjs +1142 -0
- package/dist/schema-17qMfNyI.mjs +18 -0
- package/dist/schema-display-CgmeKigW.mjs +130 -0
- package/dist/schemas-CDib1RhE.mjs +125 -0
- package/dist/skills-sync.handler-DIy8GR16.mjs +34 -0
- package/dist/skills.command-CrjI2dN9.mjs +35 -0
- package/dist/skills.handler-Bz8bJKql.mjs +9 -0
- package/dist/source-analysis-Cj-ADyu--BJQcFPCG.mjs +144 -0
- package/dist/spinner-progress-DMVwgqO9.mjs +173 -0
- package/dist/src-C0X6u_Mw.mjs +1340 -0
- package/dist/src-eHwu-Gfw.mjs +369 -0
- package/dist/status.handler-BO4nwvWn.mjs +101 -0
- package/dist/switch.handler-D_9213Vf.mjs +51 -0
- package/dist/sync-BL_Mo5st.mjs +39 -0
- package/dist/sync-keystroke-agent-skills-Kx_H7UTd.mjs +70 -0
- package/dist/sync.handler-BUFPdzWz.mjs +82 -0
- package/dist/task-B2sZMaZu.mjs +8 -0
- package/dist/task-target-build-CBeCKbu2.mjs +432 -0
- package/dist/task-target-deploy-C5X-USeR.mjs +4 -0
- package/dist/task-target-deploy-CA6elFpF-BEr4gkol.mjs +271 -0
- package/dist/task-target-deploy-runner.d.mts +3 -0
- package/dist/task-target-deploy-runner.mjs +202 -0
- package/dist/test-BHTgR3UA.mjs +698 -0
- package/dist/test.handler-BcPQ8b74.mjs +13 -0
- package/dist/trigger-artifacts-DQPbQNqC-B4yeeFBY.mjs +239 -0
- package/dist/trigger-manifest-CY7brZeg.mjs +30 -0
- package/dist/try-deploy.handler-DqybNhXx.mjs +490 -0
- package/dist/upload-CkU--iDC.mjs +207 -0
- package/dist/upload.handler-DCtiznQp.mjs +441 -0
- package/dist/utils-CywxCDM7.mjs +14 -0
- package/dist/validate.handler-DOcTaJL0.mjs +280 -0
- package/dist/workflow-build-DBQaBfnn.mjs +1819 -0
- package/dist/workflow-bundler-BPiqVscj-X1PFFAuP.mjs +167 -0
- package/dist/workflows-g9z87AJJ.mjs +799 -0
- package/dist/writer-BG8poUm3-BbXlU2kI.mjs +426 -0
- package/package.json +87 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { n as JsonOptionSchema, t as JSON_OPTION_CONFIG } from "./output-DM4b7KgY.mjs";
|
|
4
|
+
import { t as createTypedCommand } from "./commander-DfTVqQ-3.mjs";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/commands/projects/projects.command.ts
|
|
7
|
+
function createProjectsCommand() {
|
|
8
|
+
return createTypedCommand({
|
|
9
|
+
name: "projects",
|
|
10
|
+
description: "List tracked Keystroke projects",
|
|
11
|
+
schema: JsonOptionSchema,
|
|
12
|
+
optionsConfig: { ...JSON_OPTION_CONFIG },
|
|
13
|
+
loadHandler: async () => (await import("./list.handler-CZ6G2x_G.mjs")).handleProjectsList,
|
|
14
|
+
subcommands: [createTypedCommand({
|
|
15
|
+
name: "list",
|
|
16
|
+
description: "List all tracked Keystroke projects",
|
|
17
|
+
schema: JsonOptionSchema,
|
|
18
|
+
optionsConfig: { ...JSON_OPTION_CONFIG },
|
|
19
|
+
loadHandler: async () => (await import("./list.handler-CZ6G2x_G.mjs")).handleProjectsList
|
|
20
|
+
}), createTypedCommand({
|
|
21
|
+
name: "clear-cache",
|
|
22
|
+
description: "Clear the stored projects cache (projects.json)",
|
|
23
|
+
schema: z.object({}),
|
|
24
|
+
optionsConfig: {},
|
|
25
|
+
loadHandler: async () => (await import("./clear-cache.handler-B9tqSoSM.mjs")).handleProjectsClearCache
|
|
26
|
+
})]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createProjectsCommand };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
//#region ../../packages/workflow-builder/dist/read-credential-keys-77a91T8M.mjs
|
|
4
|
+
function readCredentialKeysFromSchemaObject(schema) {
|
|
5
|
+
const properties = schema.properties;
|
|
6
|
+
return typeof properties === "object" && properties !== null && !Array.isArray(properties) ? Object.keys(properties).sort() : [];
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { readCredentialKeysFromSchemaObject as t };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { D as throwReportedCliExit, h as toErrorMessage, l as AUTH_HINT, m as isNetworkError, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { i as writeJson } from "./output-DM4b7KgY.mjs";
|
|
5
|
+
//#region src/commands/integrations/register.handler.ts
|
|
6
|
+
function exitWithError(ctx, message, opts) {
|
|
7
|
+
if (ctx.jsonMode) {
|
|
8
|
+
writeJson({
|
|
9
|
+
error: message,
|
|
10
|
+
...opts?.code ? { code: opts.code } : {},
|
|
11
|
+
...opts?.hint ? { hint: opts.hint } : {}
|
|
12
|
+
});
|
|
13
|
+
throwReportedCliExit(message);
|
|
14
|
+
}
|
|
15
|
+
ui.error(message);
|
|
16
|
+
if (opts?.hint) ui.hint(opts.hint);
|
|
17
|
+
throwReportedCliExit(message);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Handle `keystroke integrations register <integrationId>`.
|
|
21
|
+
*
|
|
22
|
+
* Upserts a `workspace_provider_apps` row by calling
|
|
23
|
+
* `POST /api/v1/admin/workspace-provider-apps` on the server.
|
|
24
|
+
*/
|
|
25
|
+
async function handleIntegrationsRegister(options, ctx) {
|
|
26
|
+
const integrationId = options.integrationId?.trim();
|
|
27
|
+
const { baseUrl, apiKey } = ctx;
|
|
28
|
+
if (!baseUrl || !apiKey) exitWithError(ctx, "Not authenticated.", {
|
|
29
|
+
code: "AUTH_ERROR",
|
|
30
|
+
hint: AUTH_HINT
|
|
31
|
+
});
|
|
32
|
+
if (!integrationId) exitWithError(ctx, "Usage: keystroke integrations register <integrationId>", {
|
|
33
|
+
code: "USAGE_ERROR",
|
|
34
|
+
hint: "Example: keystroke integrations register acmeCrm"
|
|
35
|
+
});
|
|
36
|
+
if (!options.clientAppCredentialSetId) exitWithError(ctx, "Missing --client-app <credentialSetId>. This is the internal credential set that holds clientId + clientSecret.", {
|
|
37
|
+
code: "USAGE_ERROR",
|
|
38
|
+
hint: `Example: keystroke integrations register ${integrationId} --client-app acmeClientApp`
|
|
39
|
+
});
|
|
40
|
+
const displayName = options.displayName ?? integrationId;
|
|
41
|
+
if (!ctx.jsonMode) ui.text(`Registering workspace provider app "${integrationId}"...`);
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch(`${baseUrl}/api/v1/admin/workspace-provider-apps`, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: `Bearer ${apiKey}`,
|
|
47
|
+
"Content-Type": "application/json"
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
credentialSetId: integrationId,
|
|
51
|
+
clientAppCredentialSetId: options.clientAppCredentialSetId,
|
|
52
|
+
displayName
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
if (response.status === 401) exitWithError(ctx, "Not authenticated.", {
|
|
57
|
+
code: "AUTH_ERROR",
|
|
58
|
+
hint: AUTH_HINT
|
|
59
|
+
});
|
|
60
|
+
exitWithError(ctx, `Failed to register workspace integration: ${(await response.json().catch(() => ({}))).error ?? `Server returned HTTP ${response.status}`}`, { code: "REGISTER_FAILED" });
|
|
61
|
+
}
|
|
62
|
+
const data = await response.json();
|
|
63
|
+
if (ctx.jsonMode) {
|
|
64
|
+
writeJson({
|
|
65
|
+
status: data.created ? "created" : "updated",
|
|
66
|
+
workspaceProviderApp: data.workspaceProviderApp
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (data.created) ui.success(`Registered workspace provider app for "${integrationId}".`);
|
|
71
|
+
else ui.success(`Updated workspace provider app for "${integrationId}".`);
|
|
72
|
+
ui.hint("Workspace-authored OAuth connect flows are not available yet. This registration stores the client app metadata for future support.");
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof Error && error.name === "CliExitError") throw error;
|
|
75
|
+
if (isNetworkError(error)) exitWithError(ctx, `Could not reach the Keystroke server to register "${integrationId}".`, {
|
|
76
|
+
code: "NETWORK_ERROR",
|
|
77
|
+
hint: `Check that your local services are running and that the CLI is pointed at ${baseUrl}.`
|
|
78
|
+
});
|
|
79
|
+
exitWithError(ctx, `Failed to register workspace integration "${integrationId}".`, {
|
|
80
|
+
code: "REGISTER_FAILED",
|
|
81
|
+
hint: toErrorMessage(error)
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { handleIntegrationsRegister };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { o as ANSI, s as style, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { i as writeJson } from "./output-DM4b7KgY.mjs";
|
|
5
|
+
import { a as readManifestsFromOutDir } from "./dist-BkJUoBiG.mjs";
|
|
6
|
+
import { t as requireWorkflowsDir } from "./resolve-project-DDJ29sCF.mjs";
|
|
7
|
+
import { n as getProcessEnv } from "./env-91KwMKov.mjs";
|
|
8
|
+
import { t as readCredentialEnvMap } from "./credential-env-map-CI8yWHVy.mjs";
|
|
9
|
+
import { a as loadProjectDotenvFile, c as getTerminalContentWidth, o as manifestGroupKey, s as normalizeManifestScopeToServer, t as buildCredentialWorkflowConsumersByGroup, u as truncateWithEllipsis } from "./list-enrichment-y-cwizLr.mjs";
|
|
10
|
+
import { t as groupCredentialRequirements } from "./credentials-OfVHOtG3.mjs";
|
|
11
|
+
//#region src/commands/credentials/requirements/requirements-display.ts
|
|
12
|
+
function dimLabel(label, width = 10) {
|
|
13
|
+
return style(label.padEnd(width), ANSI.dim);
|
|
14
|
+
}
|
|
15
|
+
function presenceIcon(p) {
|
|
16
|
+
switch (p) {
|
|
17
|
+
case "set": return style("✓", ANSI.green);
|
|
18
|
+
case "missing": return style("✗", ANSI.red);
|
|
19
|
+
default: return style("?", ANSI.dim);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function renderRequirementsBlocks(rows, serverChecked) {
|
|
23
|
+
const w = getTerminalContentWidth();
|
|
24
|
+
const indent = " ";
|
|
25
|
+
let first = true;
|
|
26
|
+
let totalKeys = 0;
|
|
27
|
+
let serverMissing = 0;
|
|
28
|
+
let localSet = 0;
|
|
29
|
+
for (const r of rows) {
|
|
30
|
+
if (!first) ui.br();
|
|
31
|
+
first = false;
|
|
32
|
+
ui.text(style(r.credentialSetId, ANSI.bold));
|
|
33
|
+
ui.text(`${indent}${dimLabel("Scope")}${r.scope}`);
|
|
34
|
+
const wfDisplay = truncateWithEllipsis(r.workflows.length === 0 ? "—" : r.workflows.join(", "), Math.max(12, w - 14));
|
|
35
|
+
ui.text(`${indent}${dimLabel("Workflows")}${wfDisplay}`);
|
|
36
|
+
ui.text(`${indent}${dimLabel("Keys")}`);
|
|
37
|
+
for (const k of r.keys) {
|
|
38
|
+
totalKeys++;
|
|
39
|
+
if (k.server === "missing") serverMissing++;
|
|
40
|
+
if (k.local === "set") localSet++;
|
|
41
|
+
const envLabel = k.envVar === `KEYSTROKE_${k.key}` ? k.envVar : `${k.envVar} (${k.key})`;
|
|
42
|
+
if (serverChecked) ui.text(`${indent} ${presenceIcon(k.server)} server ${presenceIcon(k.local)} local ${envLabel}`);
|
|
43
|
+
else ui.text(`${indent} ${presenceIcon(k.local)} ${envLabel}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (totalKeys > 0) {
|
|
47
|
+
ui.br();
|
|
48
|
+
if (serverChecked) if (serverMissing > 0) ui.warn(`Server: ${serverMissing} of ${totalKeys} key(s) missing.`);
|
|
49
|
+
else ui.success(`Server: all ${totalKeys} key(s) configured.`);
|
|
50
|
+
const localMissing = totalKeys - localSet;
|
|
51
|
+
if (localMissing > 0) ui.warn(`Local: ${localMissing} of ${totalKeys} env var(s) missing.`);
|
|
52
|
+
else ui.success(`Local: all ${totalKeys} env var(s) set.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/commands/credentials/requirements/resolve-server-keys.ts
|
|
57
|
+
/**
|
|
58
|
+
* Returns true for HTTP responses that mean "credential set not configured"
|
|
59
|
+
* (404 = not found, 422 = missing keys). Other errors (network, 500) should propagate.
|
|
60
|
+
*/
|
|
61
|
+
function isNotConfiguredError(error) {
|
|
62
|
+
if (typeof error === "object" && error !== null && "response" in error && typeof error.response?.status === "number") {
|
|
63
|
+
const status = error.response.status;
|
|
64
|
+
return status === 404 || status === 422;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Tries `credentials.resolve` for each group. Returns per-key server status.
|
|
70
|
+
* On network/auth errors returns null (server unreachable — caller should degrade gracefully).
|
|
71
|
+
*/
|
|
72
|
+
async function resolveServerKeyStatuses(client, groups) {
|
|
73
|
+
const results = [];
|
|
74
|
+
for (const group of groups) {
|
|
75
|
+
const scope = group.scope === "organization" || group.scope === "project" ? group.scope : void 0;
|
|
76
|
+
try {
|
|
77
|
+
const response = await client.credentials.resolve({
|
|
78
|
+
credentialSetId: group.credentialSetId,
|
|
79
|
+
keys: group.keys,
|
|
80
|
+
...scope && { scope }
|
|
81
|
+
});
|
|
82
|
+
const configuredKeys = new Set(Object.keys(response.credentials ?? {}));
|
|
83
|
+
const keys = /* @__PURE__ */ new Map();
|
|
84
|
+
for (const k of group.keys) keys.set(k, configuredKeys.has(k) ? "set" : "missing");
|
|
85
|
+
results.push({
|
|
86
|
+
credentialSetId: group.credentialSetId,
|
|
87
|
+
scope: group.scope,
|
|
88
|
+
keys
|
|
89
|
+
});
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (isNotConfiguredError(err)) {
|
|
92
|
+
const keys = /* @__PURE__ */ new Map();
|
|
93
|
+
for (const k of group.keys) keys.set(k, "missing");
|
|
94
|
+
results.push({
|
|
95
|
+
credentialSetId: group.credentialSetId,
|
|
96
|
+
scope: group.scope,
|
|
97
|
+
keys
|
|
98
|
+
});
|
|
99
|
+
} else return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return results;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/commands/credentials/requirements/requirements.handler.ts
|
|
106
|
+
function resolveEnvVarName(credentialSetId, key, envMap) {
|
|
107
|
+
return envMap?.[credentialSetId]?.[key] ?? `KEYSTROKE_${key}`;
|
|
108
|
+
}
|
|
109
|
+
function serverPresenceForKey(credentialSetId, scope, key, serverResults) {
|
|
110
|
+
if (!serverResults) return "unknown";
|
|
111
|
+
return serverResults.find((r) => r.credentialSetId === credentialSetId && r.scope === scope)?.keys.get(key) ?? "unknown";
|
|
112
|
+
}
|
|
113
|
+
async function handleCredentialsRequirements(options, ctx) {
|
|
114
|
+
const workflowsDir = await requireWorkflowsDir(options.path);
|
|
115
|
+
const manifests = await readManifestsFromOutDir(workflowsDir);
|
|
116
|
+
if (manifests.length === 0) {
|
|
117
|
+
ui.warn("No built manifests found. Run `keystroke workflows build` first.");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const seen = /* @__PURE__ */ new Set();
|
|
121
|
+
const requirements = [];
|
|
122
|
+
for (const { manifest } of manifests) {
|
|
123
|
+
const groups = groupCredentialRequirements(manifest);
|
|
124
|
+
for (const group of groups) {
|
|
125
|
+
const key = `${group.credentialSetId}:${group.scope ?? "__default__"}`;
|
|
126
|
+
if (!seen.has(key)) {
|
|
127
|
+
seen.add(key);
|
|
128
|
+
requirements.push({
|
|
129
|
+
credentialSetId: group.credentialSetId,
|
|
130
|
+
scope: group.scope,
|
|
131
|
+
keys: group.keys
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (requirements.length === 0) {
|
|
137
|
+
ui.text("No credential requirements in workflow manifests.");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
requirements.sort((a, b) => {
|
|
141
|
+
const id = a.credentialSetId.localeCompare(b.credentialSetId);
|
|
142
|
+
if (id !== 0) return id;
|
|
143
|
+
return (a.scope ?? "").localeCompare(b.scope ?? "");
|
|
144
|
+
});
|
|
145
|
+
const credentialEnvMap = await readCredentialEnvMap(workflowsDir);
|
|
146
|
+
const projectDotenv = await loadProjectDotenvFile(workflowsDir);
|
|
147
|
+
const mergedEnv = {
|
|
148
|
+
...getProcessEnv(),
|
|
149
|
+
...projectDotenv
|
|
150
|
+
};
|
|
151
|
+
let serverResults = null;
|
|
152
|
+
if (ctx.client) {
|
|
153
|
+
serverResults = await resolveServerKeyStatuses(ctx.client, requirements);
|
|
154
|
+
if (!serverResults) ui.warn("Could not reach the server — showing local status only.");
|
|
155
|
+
}
|
|
156
|
+
const workflowConsumersByGroup = buildCredentialWorkflowConsumersByGroup(manifests);
|
|
157
|
+
function resolveKeyStatuses(credentialSetId, scope, keys) {
|
|
158
|
+
return keys.map((k) => {
|
|
159
|
+
const envVar = resolveEnvVarName(credentialSetId, k, credentialEnvMap);
|
|
160
|
+
const value = mergedEnv[envVar];
|
|
161
|
+
return {
|
|
162
|
+
key: k,
|
|
163
|
+
envVar,
|
|
164
|
+
local: value && value.trim().length > 0 ? "set" : "missing",
|
|
165
|
+
server: serverPresenceForKey(credentialSetId, scope, k, serverResults)
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function workflowsForGroup(r) {
|
|
170
|
+
return workflowConsumersByGroup.get(manifestGroupKey({
|
|
171
|
+
credentialSetId: r.credentialSetId,
|
|
172
|
+
scope: r.scope,
|
|
173
|
+
keys: r.keys
|
|
174
|
+
})) ?? [];
|
|
175
|
+
}
|
|
176
|
+
if (ctx.jsonMode) {
|
|
177
|
+
writeJson(requirements.map((r) => ({
|
|
178
|
+
credentialSetId: r.credentialSetId,
|
|
179
|
+
scope: r.scope,
|
|
180
|
+
keys: resolveKeyStatuses(r.credentialSetId, r.scope, r.keys).map((ks) => ({
|
|
181
|
+
key: ks.key,
|
|
182
|
+
envVar: ks.envVar,
|
|
183
|
+
local: ks.local,
|
|
184
|
+
server: ks.server
|
|
185
|
+
})),
|
|
186
|
+
workflows: workflowsForGroup(r)
|
|
187
|
+
})));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
renderRequirementsBlocks(requirements.map((r) => ({
|
|
191
|
+
credentialSetId: r.credentialSetId,
|
|
192
|
+
scope: normalizeManifestScopeToServer(r.scope),
|
|
193
|
+
keys: resolveKeyStatuses(r.credentialSetId, r.scope, r.keys),
|
|
194
|
+
workflows: workflowsForGroup(r)
|
|
195
|
+
})), serverResults !== null);
|
|
196
|
+
ui.br();
|
|
197
|
+
if (!ctx.client) ui.hint("Not authenticated — run `keystroke auth` to also check server status.");
|
|
198
|
+
ui.hint("Set missing env vars, then run: keystroke credentials upload");
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
export { handleCredentialsRequirements };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { T as ProjectNotFoundError, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { s as readStoredProjects } from "./dist-CUK7yBM0.mjs";
|
|
5
|
+
import { n as findProjectRoot } from "./project-config-D1qsQlO7.mjs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
//#region src/lib/resolve-project.ts
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the project root from an explicit `--path` flag or by
|
|
10
|
+
* walking up from CWD looking for `keystroke.config.ts`.
|
|
11
|
+
*
|
|
12
|
+
* Returns `null` when no project is found.
|
|
13
|
+
*/
|
|
14
|
+
async function resolveWorkflowsDir(explicitPath) {
|
|
15
|
+
if (explicitPath) return path.resolve(explicitPath);
|
|
16
|
+
return findProjectRoot(process.cwd());
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Like `resolveWorkflowsDir` but throws a `ProjectNotFoundError`
|
|
20
|
+
* when no project is found.
|
|
21
|
+
*/
|
|
22
|
+
async function requireWorkflowsDir(explicitPath) {
|
|
23
|
+
const dir = await resolveWorkflowsDir(explicitPath);
|
|
24
|
+
if (dir) return dir;
|
|
25
|
+
ui.warn("No keystroke.config.ts found in this directory or any parent directory.");
|
|
26
|
+
const stored = await readStoredProjects();
|
|
27
|
+
if (stored?.lastProject) {
|
|
28
|
+
ui.hint(`Last used project: ${stored.lastProject}`);
|
|
29
|
+
ui.hint(` cd ${stored.lastProject}`);
|
|
30
|
+
}
|
|
31
|
+
ui.hint("Run `keystroke init` to initialize a project, or use --path.");
|
|
32
|
+
throw new ProjectNotFoundError("No keystroke.config.ts found");
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { resolveWorkflowsDir as n, requireWorkflowsDir as t };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
//#region ../../packages/workflow-builder/dist/rolldown-runtime-twds-ZHy.mjs
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __exportAll = (all, no_symbols) => {
|
|
6
|
+
let target = {};
|
|
7
|
+
for (var name in all) __defProp(target, name, {
|
|
8
|
+
get: all[name],
|
|
9
|
+
enumerable: true
|
|
10
|
+
});
|
|
11
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
12
|
+
return target;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { __exportAll as t };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
//#region src/lib/run-polling.ts
|
|
4
|
+
/**
|
|
5
|
+
* run-polling.ts
|
|
6
|
+
*
|
|
7
|
+
* Shared utilities for polling workflow run completion status.
|
|
8
|
+
* Used by `workflows try-deploy` polling and `workflows logs --follow`.
|
|
9
|
+
*/
|
|
10
|
+
const TERMINAL_STATUSES = new Set([
|
|
11
|
+
"completed",
|
|
12
|
+
"failed",
|
|
13
|
+
"cancelled",
|
|
14
|
+
"expired"
|
|
15
|
+
]);
|
|
16
|
+
function sleep(durationMs) {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { sleep as n, TERMINAL_STATUSES as t };
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { D as throwReportedCliExit, h as toErrorMessage, o as ANSI, s as style, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { i as writeJson, n as JsonOptionSchema, t as JSON_OPTION_CONFIG } from "./output-DM4b7KgY.mjs";
|
|
5
|
+
import { t as createTypedCommand } from "./commander-DfTVqQ-3.mjs";
|
|
6
|
+
import { i as requireClient } from "./context-T7HZuB97.mjs";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
//#region src/commands/runs/inspect-display.ts
|
|
9
|
+
function renderRunInspect(input) {
|
|
10
|
+
const { run, events, logs } = input;
|
|
11
|
+
ui.text(style(` Run: ${run.id}`, `${ANSI.bold}${ANSI.cyan}`));
|
|
12
|
+
ui.text(` Workflow: ${run.workflowName} (${run.authoredWorkflowId})`);
|
|
13
|
+
ui.text(` Status: ${run.status}`);
|
|
14
|
+
ui.text(` Deployment: ${run.deploymentId}`);
|
|
15
|
+
ui.text(` Created: ${formatDate(run.createdAt)}`);
|
|
16
|
+
if (run.startedAt) ui.text(` Started: ${formatDate(run.startedAt)}`);
|
|
17
|
+
if (run.completedAt) ui.text(` Completed: ${formatDate(run.completedAt)}`);
|
|
18
|
+
ui.br();
|
|
19
|
+
ui.text(style(" Events", ANSI.bold));
|
|
20
|
+
const eventSummary = formatEventSummary(events);
|
|
21
|
+
ui.text(eventSummary || style(" (none)", ANSI.dim));
|
|
22
|
+
ui.br();
|
|
23
|
+
const pendingYields = formatPendingYields(events);
|
|
24
|
+
if (pendingYields) {
|
|
25
|
+
ui.text(style(" Pending Yields", ANSI.bold));
|
|
26
|
+
ui.text(pendingYields);
|
|
27
|
+
ui.br();
|
|
28
|
+
}
|
|
29
|
+
if (run.error) {
|
|
30
|
+
ui.text(style(" Error", ANSI.bold));
|
|
31
|
+
ui.text(` ${formatUnknown(run.error)}`);
|
|
32
|
+
ui.br();
|
|
33
|
+
}
|
|
34
|
+
ui.text(style(" Recent Logs", ANSI.bold));
|
|
35
|
+
const logSummary = formatLogs(logs);
|
|
36
|
+
ui.text(logSummary || style(" (none)", ANSI.dim));
|
|
37
|
+
}
|
|
38
|
+
function renderAgentRunInspect(input) {
|
|
39
|
+
const { agentRun, events, childWorkflowRuns, latestSnapshot } = input;
|
|
40
|
+
ui.text(style(` Agent Run: ${agentRun.id}`, `${ANSI.bold}${ANSI.cyan}`));
|
|
41
|
+
ui.text(` Agent: ${agentRun.agentName}${agentRun.agentId ? ` (${agentRun.agentId})` : ""}`);
|
|
42
|
+
ui.text(` Status: ${agentRun.status}`);
|
|
43
|
+
ui.text(` Source: ${agentRun.source}`);
|
|
44
|
+
ui.text(` Runtime: ${agentRun.runtime}`);
|
|
45
|
+
if (agentRun.workflowRunId) ui.text(` Parent Workflow Run: ${agentRun.workflowRunId}`);
|
|
46
|
+
if (agentRun.correlationId) ui.text(` Parent Correlation: ${agentRun.correlationId}`);
|
|
47
|
+
ui.text(` Created: ${formatDate(agentRun.createdAt)}`);
|
|
48
|
+
if (agentRun.startedAt) ui.text(` Started: ${formatDate(agentRun.startedAt)}`);
|
|
49
|
+
if (agentRun.completedAt) ui.text(` Completed: ${formatDate(agentRun.completedAt)}`);
|
|
50
|
+
ui.br();
|
|
51
|
+
ui.text(style(" Pending Yields", ANSI.bold));
|
|
52
|
+
ui.text(formatAgentPendingYields(agentRun.yieldState) || style(" (none)", ANSI.dim));
|
|
53
|
+
ui.br();
|
|
54
|
+
ui.text(style(" Child Workflow Runs", ANSI.bold));
|
|
55
|
+
ui.text(formatChildWorkflowRuns(childWorkflowRuns) || style(" (none)", ANSI.dim));
|
|
56
|
+
ui.br();
|
|
57
|
+
ui.text(style(" Latest Snapshot", ANSI.bold));
|
|
58
|
+
ui.text(formatSnapshot(latestSnapshot) || style(" (none)", ANSI.dim));
|
|
59
|
+
ui.br();
|
|
60
|
+
ui.text(style(" Agent Events", ANSI.bold));
|
|
61
|
+
ui.text(formatAgentEvents(events) || style(" (none)", ANSI.dim));
|
|
62
|
+
if (agentRun.error) {
|
|
63
|
+
ui.br();
|
|
64
|
+
ui.text(style(" Error", ANSI.bold));
|
|
65
|
+
ui.text(` ${formatUnknown(agentRun.error)}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function formatEventSummary(events) {
|
|
69
|
+
if (events.length === 0) return "";
|
|
70
|
+
const counts = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const event of events) counts.set(event.eventType, (counts.get(event.eventType) ?? 0) + 1);
|
|
72
|
+
const summary = [...counts.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([type, count]) => ` ${type}: ${count}`).join("\n");
|
|
73
|
+
const latest = events[events.length - 1];
|
|
74
|
+
if (!latest) return summary;
|
|
75
|
+
return `${summary}\n\n latest: ${latest.eventType} at ${formatDate(latest.createdAt)} (${latest.correlationId})`;
|
|
76
|
+
}
|
|
77
|
+
function formatPendingYields(events) {
|
|
78
|
+
const terminalChildCorrelations = new Set(events.filter((event) => event.eventType === "child_workflow_completed" || event.eventType === "child_workflow_failed").map((event) => event.correlationId));
|
|
79
|
+
const pending = events.filter((event) => isPendingYieldEvent(event, terminalChildCorrelations));
|
|
80
|
+
if (pending.length === 0) return "";
|
|
81
|
+
return pending.map((event) => {
|
|
82
|
+
const data = asRecord(event.eventData);
|
|
83
|
+
const kind = stringField(data, "kind") ?? stringField(data, "yieldKind") ?? "unknown";
|
|
84
|
+
const toolCallId = stringField(data, "toolCallId") ?? stringField(data, "tool_call_id");
|
|
85
|
+
const childRunId = stringField(data, "childRunId") ?? stringField(data, "child_run_id");
|
|
86
|
+
const parts = [` - ${event.correlationId}`, `kind: ${kind}`];
|
|
87
|
+
if (toolCallId) parts.push(`tool_call: ${toolCallId}`);
|
|
88
|
+
if (childRunId) parts.push(`child_run: ${childRunId}`);
|
|
89
|
+
parts.push(`at: ${formatDate(event.createdAt)}`);
|
|
90
|
+
return parts.join(" | ");
|
|
91
|
+
}).join("\n");
|
|
92
|
+
}
|
|
93
|
+
function formatLogs(logs) {
|
|
94
|
+
if (logs.length === 0) return "";
|
|
95
|
+
return logs.map((log) => {
|
|
96
|
+
const correlation = log.correlationId ? ` <${log.correlationId}>` : "";
|
|
97
|
+
return ` ${formatDate(log.timestamp)} [${log.level}]${correlation} ${log.message}`;
|
|
98
|
+
}).join("\n");
|
|
99
|
+
}
|
|
100
|
+
function formatAgentPendingYields(yieldState) {
|
|
101
|
+
const pendingYield = asRecord(asRecord(yieldState).pendingYield);
|
|
102
|
+
if (Object.keys(pendingYield).length === 0) return "";
|
|
103
|
+
const kind = stringField(pendingYield, "kind") ?? "unknown";
|
|
104
|
+
const toolCallId = stringField(pendingYield, "toolCallId");
|
|
105
|
+
const childRunId = stringField(pendingYield, "childRunId");
|
|
106
|
+
const snapshotId = stringField(pendingYield, "snapshotId");
|
|
107
|
+
const hookToken = stringField(pendingYield, "hookToken");
|
|
108
|
+
const credSetId = stringField(pendingYield, "credSetId");
|
|
109
|
+
const yieldedAt = stringField(pendingYield, "yieldedAt");
|
|
110
|
+
const parts = [` - kind: ${kind}`];
|
|
111
|
+
if (toolCallId) parts.push(`tool_call: ${toolCallId}`);
|
|
112
|
+
if (childRunId) parts.push(`child_run: ${childRunId}`);
|
|
113
|
+
if (snapshotId) parts.push(`snapshot: ${snapshotId}`);
|
|
114
|
+
if (hookToken) parts.push(`hook_token: ${hookToken}`);
|
|
115
|
+
if (credSetId) parts.push(`credential: ${credSetId}`);
|
|
116
|
+
if (yieldedAt) parts.push(`yielded_at: ${formatDate(yieldedAt)}`);
|
|
117
|
+
return parts.join(" | ");
|
|
118
|
+
}
|
|
119
|
+
function formatChildWorkflowRuns(childWorkflowRuns) {
|
|
120
|
+
if (childWorkflowRuns.length === 0) return "";
|
|
121
|
+
return childWorkflowRuns.map((run) => {
|
|
122
|
+
const parts = [
|
|
123
|
+
` - ${run.id}`,
|
|
124
|
+
`${run.workflowName} (${run.authoredWorkflowId})`,
|
|
125
|
+
`status: ${run.status}`
|
|
126
|
+
];
|
|
127
|
+
if (run.parentToolCallId) parts.push(`tool_call: ${run.parentToolCallId}`);
|
|
128
|
+
if (run.parentIdempotencyKey) parts.push(`idempotency: ${run.parentIdempotencyKey}`);
|
|
129
|
+
return parts.join(" | ");
|
|
130
|
+
}).join("\n");
|
|
131
|
+
}
|
|
132
|
+
function formatSnapshot(snapshot) {
|
|
133
|
+
if (!snapshot) return "";
|
|
134
|
+
return `${[
|
|
135
|
+
` ${snapshot.id}`,
|
|
136
|
+
`kind: ${snapshot.piSessionStateKind}`,
|
|
137
|
+
`reason: ${snapshot.triggerReason}`,
|
|
138
|
+
`version: ${snapshot.snapshotVersion}`,
|
|
139
|
+
`bytes: ${snapshot.byteSize}`,
|
|
140
|
+
`expires: ${formatDate(snapshot.expiresAt)}`
|
|
141
|
+
].join(" | ")}\n replay: Path B conversation-log replay; native Pi restore is not active.`;
|
|
142
|
+
}
|
|
143
|
+
function formatAgentEvents(events) {
|
|
144
|
+
if (events.length === 0) return "";
|
|
145
|
+
return events.slice(-10).map((event) => {
|
|
146
|
+
const step = event.stepNumber === null ? "" : ` step:${event.stepNumber}`;
|
|
147
|
+
return ` ${formatDate(event.timestamp)}${step} ${event.eventType} (${event.id})`;
|
|
148
|
+
}).join("\n");
|
|
149
|
+
}
|
|
150
|
+
function isPendingYieldEvent(event, terminalChildCorrelations) {
|
|
151
|
+
if (event.eventType === "child_workflow_created") return !terminalChildCorrelations.has(event.correlationId);
|
|
152
|
+
const data = asRecord(event.eventData);
|
|
153
|
+
const status = stringField(data, "status");
|
|
154
|
+
const kind = stringField(data, "kind") ?? stringField(data, "yieldKind");
|
|
155
|
+
return status === "pending" && kind !== void 0;
|
|
156
|
+
}
|
|
157
|
+
function asRecord(value) {
|
|
158
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
159
|
+
}
|
|
160
|
+
function stringField(record, key) {
|
|
161
|
+
const value = record[key];
|
|
162
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
163
|
+
}
|
|
164
|
+
function formatUnknown(value) {
|
|
165
|
+
if (typeof value === "string") return value;
|
|
166
|
+
return JSON.stringify(value);
|
|
167
|
+
}
|
|
168
|
+
function formatDate(value) {
|
|
169
|
+
const date = new Date(value);
|
|
170
|
+
return Number.isNaN(date.getTime()) ? value : date.toISOString();
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/commands/runs/inspect.handler.ts
|
|
174
|
+
async function handleRunsInspect(options, ctx) {
|
|
175
|
+
const client = requireClient(ctx);
|
|
176
|
+
try {
|
|
177
|
+
if (isAgentRunId(options.runId)) {
|
|
178
|
+
const inspect = await client.runs.getAgentRun(options.runId);
|
|
179
|
+
if (ctx.jsonMode) {
|
|
180
|
+
writeJson(inspect);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
renderAgentRunInspect(inspect);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const [{ run }, { events }, logsResponse] = await Promise.all([
|
|
187
|
+
client.runs.getRun(options.runId),
|
|
188
|
+
client.runs.listEvents(options.runId),
|
|
189
|
+
options.logs > 0 ? client.runs.listLogs(options.runId, {
|
|
190
|
+
limit: options.logs,
|
|
191
|
+
offset: 0
|
|
192
|
+
}) : Promise.resolve({ logs: [] })
|
|
193
|
+
]);
|
|
194
|
+
if (ctx.jsonMode) {
|
|
195
|
+
writeJson({
|
|
196
|
+
run,
|
|
197
|
+
events,
|
|
198
|
+
logs: logsResponse.logs
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
renderRunInspect({
|
|
203
|
+
run,
|
|
204
|
+
events,
|
|
205
|
+
logs: logsResponse.logs
|
|
206
|
+
});
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const message = toErrorMessage(error);
|
|
209
|
+
throwReportedCliExit(`Failed to inspect run "${options.runId}": ${message}`, { cause: error });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function isAgentRunId(runId) {
|
|
213
|
+
return runId.startsWith("arun_");
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/commands/runs/runs.command.ts
|
|
217
|
+
const RunsOptionsSchema = JsonOptionSchema;
|
|
218
|
+
const RunsInspectOptionsSchema = JsonOptionSchema.extend({
|
|
219
|
+
runId: z.string().min(1),
|
|
220
|
+
logs: z.coerce.number().int().min(0).max(100).default(10)
|
|
221
|
+
});
|
|
222
|
+
const RUNS_OPTIONS_CONFIG = { ...JSON_OPTION_CONFIG };
|
|
223
|
+
const RUNS_INSPECT_OPTIONS_CONFIG = {
|
|
224
|
+
...JSON_OPTION_CONFIG,
|
|
225
|
+
logs: {
|
|
226
|
+
flag: "--logs <n>",
|
|
227
|
+
description: "Number of recent logs to include (default: 10, use 0 to omit logs)"
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
function handleRunsHelp() {
|
|
231
|
+
ui.hint("Use `keystroke runs inspect <wrun_...>` to inspect a workflow run.");
|
|
232
|
+
ui.hint("Use `keystroke runs inspect <arun_...>` to inspect an agent run.");
|
|
233
|
+
}
|
|
234
|
+
function createRunsCommand() {
|
|
235
|
+
const cmd = createTypedCommand({
|
|
236
|
+
name: "runs",
|
|
237
|
+
description: "Inspect workflow and agent-tool runs",
|
|
238
|
+
schema: RunsOptionsSchema,
|
|
239
|
+
optionsConfig: RUNS_OPTIONS_CONFIG,
|
|
240
|
+
handler: handleRunsHelp,
|
|
241
|
+
subcommands: [createTypedCommand({
|
|
242
|
+
name: "inspect",
|
|
243
|
+
description: "Show status, events, and debugging links for a workflow or agent run",
|
|
244
|
+
schema: RunsInspectOptionsSchema,
|
|
245
|
+
optionsConfig: RUNS_INSPECT_OPTIONS_CONFIG,
|
|
246
|
+
argument: {
|
|
247
|
+
name: "runId",
|
|
248
|
+
description: "Workflow run id (wrun_...) or agent run id (arun_...)",
|
|
249
|
+
key: "runId"
|
|
250
|
+
},
|
|
251
|
+
handler: handleRunsInspect
|
|
252
|
+
})]
|
|
253
|
+
});
|
|
254
|
+
cmd.enablePositionalOptions();
|
|
255
|
+
cmd.passThroughOptions();
|
|
256
|
+
return cmd;
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
259
|
+
export { createRunsCommand };
|