@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,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { E as WorkflowResolutionError, d as getApiErrorCode, f as getHttpStatus, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { t as assertWorkflowProjectRoot } from "./project-config-D1qsQlO7.mjs";
|
|
5
|
+
import { a as readManifestsFromOutDir } from "./dist-BkJUoBiG.mjs";
|
|
6
|
+
import { t as requireWorkflowsDir } from "./resolve-project-DDJ29sCF.mjs";
|
|
7
|
+
import { t as createSpinnerProgress } from "./spinner-progress-DMVwgqO9.mjs";
|
|
8
|
+
import { a as runWorkflowBuild, n as renderBuildFailure } from "./workflow-build-DBQaBfnn.mjs";
|
|
9
|
+
//#region src/commands/workflows/_shared/current-deployment-workflow.ts
|
|
10
|
+
/**
|
|
11
|
+
* Lightweight resolution: gets projectId from keystroke.config.ts and authoredWorkflowId
|
|
12
|
+
* from cached manifests without triggering a build. Falls back to a full build
|
|
13
|
+
* only if the cached manifest is unavailable and the ref isn't already an authored ID.
|
|
14
|
+
*/
|
|
15
|
+
async function resolveProjectContext(workflowRef, explicitPath, options) {
|
|
16
|
+
const workflowsDir = await requireWorkflowsDir(explicitPath);
|
|
17
|
+
const projectConfig = await assertWorkflowProjectRoot(workflowsDir);
|
|
18
|
+
const cachedId = (await readManifestsFromOutDir(workflowsDir, workflowRef))[0]?.manifest.id;
|
|
19
|
+
if (typeof cachedId === "string" && cachedId.length > 0) return {
|
|
20
|
+
workflowsDir,
|
|
21
|
+
organizationId: projectConfig.organizationId,
|
|
22
|
+
projectId: projectConfig.projectId,
|
|
23
|
+
authoredWorkflowId: cachedId
|
|
24
|
+
};
|
|
25
|
+
if (workflowRef.startsWith("wf_")) return {
|
|
26
|
+
workflowsDir,
|
|
27
|
+
organizationId: projectConfig.organizationId,
|
|
28
|
+
projectId: projectConfig.projectId,
|
|
29
|
+
authoredWorkflowId: workflowRef
|
|
30
|
+
};
|
|
31
|
+
const resolved = await resolveLocalWorkflowManifest(workflowRef, explicitPath, options);
|
|
32
|
+
return {
|
|
33
|
+
workflowsDir: resolved.workflowsDir,
|
|
34
|
+
organizationId: resolved.organizationId,
|
|
35
|
+
projectId: resolved.projectId,
|
|
36
|
+
authoredWorkflowId: resolved.authoredWorkflowId
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function resolveLocalWorkflowManifest(workflowRef, explicitPath, options) {
|
|
40
|
+
const workflowsDir = await requireWorkflowsDir(explicitPath);
|
|
41
|
+
let results = await readManifestsFromOutDir(workflowsDir, workflowRef);
|
|
42
|
+
if (results.length === 0) {
|
|
43
|
+
const spinner = !options?.jsonMode ? createSpinnerProgress("[resolve]") : void 0;
|
|
44
|
+
spinner?.start(`Building "${workflowRef}" to resolve manifest...`);
|
|
45
|
+
try {
|
|
46
|
+
await runWorkflowBuild({
|
|
47
|
+
workflowsDir,
|
|
48
|
+
workflowRef,
|
|
49
|
+
verbose: false,
|
|
50
|
+
force: false
|
|
51
|
+
});
|
|
52
|
+
spinner?.stop();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
spinner?.stop();
|
|
55
|
+
renderBuildFailure(error);
|
|
56
|
+
throw new WorkflowResolutionError(`Build failed for "${workflowRef}"`);
|
|
57
|
+
}
|
|
58
|
+
results = await readManifestsFromOutDir(workflowsDir, workflowRef);
|
|
59
|
+
}
|
|
60
|
+
const found = results[0];
|
|
61
|
+
if (!found) {
|
|
62
|
+
ui.error(`Workflow "${workflowRef}" not found.`);
|
|
63
|
+
throw new WorkflowResolutionError(`Workflow "${workflowRef}" not found.`);
|
|
64
|
+
}
|
|
65
|
+
const authoredWorkflowId = typeof found.manifest.id === "string" && found.manifest.id.length > 0 ? found.manifest.id : null;
|
|
66
|
+
if (!authoredWorkflowId) {
|
|
67
|
+
ui.error(`Workflow "${workflowRef}" is missing an authored workflow ID.`);
|
|
68
|
+
throw new WorkflowResolutionError(`Workflow "${workflowRef}" is missing an authored workflow ID.`);
|
|
69
|
+
}
|
|
70
|
+
const projectConfig = await assertWorkflowProjectRoot(workflowsDir);
|
|
71
|
+
return {
|
|
72
|
+
workflowsDir,
|
|
73
|
+
organizationId: projectConfig.organizationId,
|
|
74
|
+
projectId: projectConfig.projectId,
|
|
75
|
+
authoredWorkflowId,
|
|
76
|
+
manifest: found.manifest
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async function lookupCurrentDeploymentWorkflow(client, params) {
|
|
80
|
+
try {
|
|
81
|
+
return {
|
|
82
|
+
status: "found",
|
|
83
|
+
workflow: (await client.projects.getCurrentDeploymentWorkflow(params.projectId, params.authoredWorkflowId)).workflow
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (getHttpStatus(error) !== 404) throw error;
|
|
87
|
+
const errorCode = await getApiErrorCode(error);
|
|
88
|
+
if (errorCode === "no_current_deployment") return { status: "missingCurrentDeployment" };
|
|
89
|
+
if (errorCode === "workflow_not_in_deployment") return { status: "missingWorkflow" };
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { resolveLocalWorkflowManifest as n, resolveProjectContext as r, lookupCurrentDeploymentWorkflow as t };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { i as requireClient } from "./context-T7HZuB97.mjs";
|
|
5
|
+
//#region src/commands/org/current.handler.ts
|
|
6
|
+
async function handleOrgCurrent(_options, ctx) {
|
|
7
|
+
if (!ctx.organizationId) {
|
|
8
|
+
ui.warn("No organization set. Use `keystroke org switch` or `--org` to select one.");
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const { user } = await requireClient(ctx).users.getMe();
|
|
12
|
+
const currentOrg = user.organizations?.find((o) => o.id === ctx.organizationId);
|
|
13
|
+
if (currentOrg) {
|
|
14
|
+
ui.text(`Current organization: ${currentOrg.name}`);
|
|
15
|
+
if (ctx.orgSource) ui.hint(`Source: ${ctx.orgSource}`);
|
|
16
|
+
} else ui.text(`Current organization ID: ${ctx.organizationId}`);
|
|
17
|
+
const storedOrgCount = ctx.storedCredentials?.orgs.length ?? 0;
|
|
18
|
+
if (storedOrgCount > 1) ui.hint(`${storedOrgCount} organizations with stored credentials. Use \`keystroke org switch\` to change.`);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { handleOrgCurrent };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { D as throwReportedCliExit, h as toErrorMessage, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { i as requireClient } from "./context-T7HZuB97.mjs";
|
|
5
|
+
//#region src/commands/api-keys/delete.handler.ts
|
|
6
|
+
async function handleApiKeysDelete(options, ctx) {
|
|
7
|
+
const client = requireClient(ctx);
|
|
8
|
+
try {
|
|
9
|
+
await client.apiKeys.remove(options.apiKeyId);
|
|
10
|
+
ui.success("API key deleted.");
|
|
11
|
+
} catch (error) {
|
|
12
|
+
ui.error(`Failed to delete API key: ${toErrorMessage(error)}`);
|
|
13
|
+
throwReportedCliExit(`Failed to delete API key: ${toErrorMessage(error)}`, { cause: error });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { handleApiKeysDelete };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { a as createKyInstance, n as auth, r as bundles, s as getClientEnv, t as projects } from "./projects-CHkRE9rS.mjs";
|
|
4
|
+
//#region ../../packages/workflow-sdk/src/deploy.ts
|
|
5
|
+
function createDeployClient(config = {}) {
|
|
6
|
+
const env = getClientEnv();
|
|
7
|
+
const baseUrl = config.baseUrl ?? env.SERVER_URL;
|
|
8
|
+
const apiKey = config.apiKey ?? env.KEYSTROKE_API_KEY;
|
|
9
|
+
const organizationId = config.organizationId ?? env.KEYSTROKE_ORG_ID;
|
|
10
|
+
if (!baseUrl) throw new Error("baseUrl is required (pass in config or set SERVER_URL)");
|
|
11
|
+
if (!apiKey) throw new Error("Keystroke API Key is required (pass apiKey or set KEYSTROKE_API_KEY)");
|
|
12
|
+
const v1 = createKyInstance({
|
|
13
|
+
prefixUrl: baseUrl,
|
|
14
|
+
apiKey,
|
|
15
|
+
organizationId
|
|
16
|
+
}).extend((options) => ({ prefixUrl: `${options.prefixUrl}/api/v1` }));
|
|
17
|
+
return {
|
|
18
|
+
public: {
|
|
19
|
+
auth: { validate: auth(v1).validate },
|
|
20
|
+
projects: projects(v1)
|
|
21
|
+
},
|
|
22
|
+
bundles: { getHashes: bundles(v1).getHashes }
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { createDeployClient };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { t as createTypedCommand } from "./commander-DfTVqQ-3.mjs";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/commands/deploy/deploy.command.ts
|
|
6
|
+
/**
|
|
7
|
+
* Deploy command options schema
|
|
8
|
+
*/
|
|
9
|
+
const DeployOptionsSchema = z.object({
|
|
10
|
+
path: z.string().optional().describe("Path to the workflow directory"),
|
|
11
|
+
dryRun: z.boolean().default(false).describe("Run without making changes"),
|
|
12
|
+
diff: z.boolean().default(false).describe("Show current deployment diff before deploying"),
|
|
13
|
+
verbose: z.boolean().default(false).describe("Show detailed output"),
|
|
14
|
+
force: z.boolean().default(false).describe("Deploy even if bundle unchanged"),
|
|
15
|
+
target: z.array(z.string()).default([]).describe("Deploy deployable exports from a target source file; repeat for multiple files"),
|
|
16
|
+
incrementalBuild: z.boolean().default(false).describe("Use workflow build cache when combined with --force (still forces upload/registration; omit for a full clean rebuild)"),
|
|
17
|
+
disableSourcemaps: z.boolean().default(false).describe("Disable sourcemap generation")
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Commander option configuration for deploy command
|
|
21
|
+
*/
|
|
22
|
+
const DEPLOY_OPTIONS_CONFIG = {
|
|
23
|
+
path: {
|
|
24
|
+
flag: "--path <path>",
|
|
25
|
+
description: "Path to project root (directory containing keystroke.config.ts); auto-discovered from CWD if omitted"
|
|
26
|
+
},
|
|
27
|
+
dryRun: {
|
|
28
|
+
flag: "--dry-run",
|
|
29
|
+
description: "Build and validate only, do not upload"
|
|
30
|
+
},
|
|
31
|
+
diff: {
|
|
32
|
+
flag: "--diff",
|
|
33
|
+
description: "Show current deployment diff before deploying"
|
|
34
|
+
},
|
|
35
|
+
verbose: {
|
|
36
|
+
flag: "--verbose",
|
|
37
|
+
description: "Show detailed deployment logs"
|
|
38
|
+
},
|
|
39
|
+
force: {
|
|
40
|
+
flag: "--force",
|
|
41
|
+
description: "Deploy even if bundle unchanged (will not bump version)"
|
|
42
|
+
},
|
|
43
|
+
target: {
|
|
44
|
+
flag: "--target <file>",
|
|
45
|
+
description: "Deploy deployable exports from a target source file; repeat for multiple files",
|
|
46
|
+
collect: true
|
|
47
|
+
},
|
|
48
|
+
incrementalBuild: {
|
|
49
|
+
flag: "--incremental-build",
|
|
50
|
+
description: "With --force, skip busting the local workflow build cache (still forces deploy/upload)"
|
|
51
|
+
},
|
|
52
|
+
disableSourcemaps: {
|
|
53
|
+
flag: "--disable-sourcemaps",
|
|
54
|
+
description: "Disable sourcemap generation for deployment bundles"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Creates the deploy command
|
|
59
|
+
*/
|
|
60
|
+
function createDeployCommand() {
|
|
61
|
+
const cmd = createTypedCommand({
|
|
62
|
+
name: "deploy",
|
|
63
|
+
description: "Deploy the current project snapshot to Keystroke",
|
|
64
|
+
schema: DeployOptionsSchema,
|
|
65
|
+
optionsConfig: DEPLOY_OPTIONS_CONFIG,
|
|
66
|
+
contextMode: "auth",
|
|
67
|
+
loadHandler: async () => (await import("./deploy.handler-BAzgiNhd.mjs")).handleDeploy
|
|
68
|
+
});
|
|
69
|
+
cmd.enablePositionalOptions();
|
|
70
|
+
cmd.passThroughOptions();
|
|
71
|
+
return cmd;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { createDeployCommand };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { t as createSpinnerProgress } from "./spinner-progress-DMVwgqO9.mjs";
|
|
5
|
+
//#region src/lib/deploy-progress.ts
|
|
6
|
+
function renderItemFailure(event, kind, spinner) {
|
|
7
|
+
if (event.result === "failure") spinner.fail(`${kind} failed (${event.name})`, void 0, event.error);
|
|
8
|
+
}
|
|
9
|
+
function createDeployProgress() {
|
|
10
|
+
const spinner = createSpinnerProgress("[deploy]");
|
|
11
|
+
let completedSuccessfully = false;
|
|
12
|
+
function handleEvent(event) {
|
|
13
|
+
if (event.phase === "prepare") {
|
|
14
|
+
if (event.status === "warning") {
|
|
15
|
+
ui.warn(event.warning);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (event.phase === "filter") return;
|
|
21
|
+
if (event.phase === "upload-workflows" || event.phase === "upload-agents" || event.phase === "upload-tasks") {
|
|
22
|
+
if (event.status === "item") {
|
|
23
|
+
renderItemFailure(event, event.phase === "upload-workflows" ? "Workflow upload" : event.phase === "upload-agents" ? "Agent upload" : "Task upload", spinner);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (event.status === "complete" && event.failed > 0) {
|
|
27
|
+
const kind = event.phase === "upload-workflows" ? "workflow" : event.phase === "upload-agents" ? "agent" : "task";
|
|
28
|
+
spinner.fail(`Upload failed (${event.succeeded} ${kind}(s) succeeded, ${event.failed} failed)`, event.elapsedMs);
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (event.phase === "register-workflows" || event.phase === "register-agents" || event.phase === "register-tasks") {
|
|
33
|
+
if (event.status === "item") {
|
|
34
|
+
renderItemFailure(event, event.phase === "register-workflows" ? "Workflow registration" : event.phase === "register-agents" ? "Agent registration" : "Task registration", spinner);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (event.status === "complete" && event.failed > 0) {
|
|
38
|
+
const kind = event.phase === "register-workflows" ? "workflow" : event.phase === "register-agents" ? "agent" : "task";
|
|
39
|
+
spinner.fail(`Registration failed (${event.succeeded} ${kind}(s) succeeded, ${event.failed} failed)`, event.elapsedMs);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (event.phase === "hash-check") return;
|
|
44
|
+
if (event.phase === "sync-file-metadata") return;
|
|
45
|
+
if (event.phase === "complete") {
|
|
46
|
+
if (event.success) {
|
|
47
|
+
const parts = [];
|
|
48
|
+
if (event.workflowsTotal > 0) parts.push(`${event.workflowsTotal} workflow(s)`);
|
|
49
|
+
if (event.agentsTotal > 0) parts.push(`${event.agentsTotal} agent(s)`);
|
|
50
|
+
if (event.tasksTotal > 0) parts.push(`${event.tasksTotal} task(s)`);
|
|
51
|
+
spinner.complete(`Deployed ${parts.join(" and ")}`, event.elapsedMs);
|
|
52
|
+
completedSuccessfully = true;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
spinner.fail("Deployment completed with failures", event.elapsedMs);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`Unhandled deploy progress event: ${JSON.stringify(event)}`);
|
|
59
|
+
}
|
|
60
|
+
function stop() {
|
|
61
|
+
if (!completedSuccessfully) spinner.stop();
|
|
62
|
+
}
|
|
63
|
+
spinner.start("Deploying...");
|
|
64
|
+
return {
|
|
65
|
+
handleEvent,
|
|
66
|
+
stop
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { createDeployProgress as t };
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { C as CliExitError, i as logger, o as ANSI, s as style, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { d as trackProject } from "./dist-CUK7yBM0.mjs";
|
|
5
|
+
import { t as assertWorkflowProjectRoot } from "./project-config-D1qsQlO7.mjs";
|
|
6
|
+
import { i as readAgentManifestsFromOutDir, o as readWorkflowsFromDisk } from "./dist-BkJUoBiG.mjs";
|
|
7
|
+
import { t as requireWorkflowsDir } from "./resolve-project-DDJ29sCF.mjs";
|
|
8
|
+
import { n as renderBuildFailure, r as renderBuildHeader } from "./workflow-build-DBQaBfnn.mjs";
|
|
9
|
+
import { r as isLocalMode } from "./env-91KwMKov.mjs";
|
|
10
|
+
import { r as requireAuthOptions, t as assertProjectConfigMatchesAuthenticatedOrg } from "./context-T7HZuB97.mjs";
|
|
11
|
+
import { t as createBuildProgress } from "./build-progress-DgYKb4hB.mjs";
|
|
12
|
+
import { t as createDeployProgress } from "./deploy-progress-BmGUNFKg.mjs";
|
|
13
|
+
import { t as withErrorBoundary } from "./error-boundary-VL-JLfIa.mjs";
|
|
14
|
+
import { t as lookupCurrentDeploymentWorkflow } from "./current-deployment-workflow-poHt27i3.mjs";
|
|
15
|
+
import { t as computeWorkflowDiff } from "./diff-utils-NEfcjqxt.mjs";
|
|
16
|
+
import { access } from "node:fs/promises";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
//#region src/commands/deploy/deploy-diff.ts
|
|
19
|
+
const deployDiffDependencies = {
|
|
20
|
+
readWorkflowsFromDisk,
|
|
21
|
+
readAgentManifestsFromOutDir
|
|
22
|
+
};
|
|
23
|
+
async function computeDeployDiff(params) {
|
|
24
|
+
const workflows = await deployDiffDependencies.readWorkflowsFromDisk(params.outDir);
|
|
25
|
+
const workflowDiffs = [];
|
|
26
|
+
let missingCurrentDeployment = false;
|
|
27
|
+
for (const workflow of workflows) {
|
|
28
|
+
let deployed = null;
|
|
29
|
+
if (!missingCurrentDeployment) {
|
|
30
|
+
const lookup = await lookupCurrentDeploymentWorkflow(params.client, {
|
|
31
|
+
projectId: params.projectId,
|
|
32
|
+
authoredWorkflowId: workflow.manifestData.id
|
|
33
|
+
});
|
|
34
|
+
if (lookup.status === "found") deployed = lookup.workflow.manifest;
|
|
35
|
+
else if (lookup.status === "missingCurrentDeployment") missingCurrentDeployment = true;
|
|
36
|
+
}
|
|
37
|
+
workflowDiffs.push(computeWorkflowDiff(workflow.manifestData, deployed, {
|
|
38
|
+
workflowName: workflow.name,
|
|
39
|
+
deployedVersion: null
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
workflows: workflowDiffs,
|
|
44
|
+
agents: (await deployDiffDependencies.readAgentManifestsFromOutDir(params.workflowsDir)).map(({ manifest }) => ({
|
|
45
|
+
authoredAgentId: manifest.authoredAgentId,
|
|
46
|
+
agentName: manifest.agentName,
|
|
47
|
+
workflowTools: (manifest.tools ?? []).filter((tool) => tool.sourceKind === "workflow")
|
|
48
|
+
})),
|
|
49
|
+
hasChanges: workflowDiffs.some((diff) => diff.hasChanges)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function renderDeployDiff(diff) {
|
|
53
|
+
ui.header("Deploy diff");
|
|
54
|
+
ui.br();
|
|
55
|
+
ui.text(style("Workflows", ANSI.bold));
|
|
56
|
+
if (diff.workflows.length === 0) ui.text(style(" (none)", ANSI.dim));
|
|
57
|
+
else for (const workflow of diff.workflows) {
|
|
58
|
+
const marker = workflow.notYetDeployed ? "+" : workflow.hasChanges ? "~" : " ";
|
|
59
|
+
const color = workflow.notYetDeployed ? ANSI.green : workflow.hasChanges ? ANSI.yellow : ANSI.dim;
|
|
60
|
+
ui.text(style(` ${marker} ${workflow.workflowName}`, color));
|
|
61
|
+
}
|
|
62
|
+
ui.br();
|
|
63
|
+
ui.text(style("Agent Workflow Tools", ANSI.bold));
|
|
64
|
+
if (diff.agents.length === 0) ui.text(style(" (none)", ANSI.dim));
|
|
65
|
+
else for (const agent of diff.agents) {
|
|
66
|
+
ui.text(` ${agent.authoredAgentId} (${agent.agentName})`);
|
|
67
|
+
if (agent.workflowTools.length === 0) {
|
|
68
|
+
ui.text(style(" (no workflow tools)", ANSI.dim));
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
for (const tool of agent.workflowTools) {
|
|
72
|
+
const deployment = tool.deploymentId ? ` deployment=${tool.deploymentId}` : "";
|
|
73
|
+
const invocation = tool.invocation ? ` invocation=${tool.invocation}` : "";
|
|
74
|
+
ui.text(` ${tool.toolName}: workflow=${tool.authoredWorkflowId ?? "unknown"}${deployment}${invocation}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
ui.br();
|
|
78
|
+
if (diff.hasChanges) ui.warn("Workflow changes detected against the current deployment.");
|
|
79
|
+
else ui.success("No workflow changes detected.");
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/commands/deploy/deploy-targets.ts
|
|
83
|
+
var DeployTargetError = class extends Error {
|
|
84
|
+
constructor(message) {
|
|
85
|
+
super(message);
|
|
86
|
+
this.name = "DeployTargetError";
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function getDeployMode(targets) {
|
|
90
|
+
return targets.some((target) => target.trim().length > 0) ? "targets" : "project";
|
|
91
|
+
}
|
|
92
|
+
function classifyDeployTargetFile(filePath) {
|
|
93
|
+
if (filePath.endsWith(".workflow.ts")) return "workflow";
|
|
94
|
+
if (filePath.endsWith(".agent.ts")) return "agent";
|
|
95
|
+
if (filePath.endsWith(".task.ts")) return "task";
|
|
96
|
+
return "unknown";
|
|
97
|
+
}
|
|
98
|
+
async function resolveDeployTargetFiles(projectRoot, targets) {
|
|
99
|
+
const resolvedTargets = [];
|
|
100
|
+
for (const inputPath of targets) {
|
|
101
|
+
const trimmedInput = inputPath.trim();
|
|
102
|
+
if (trimmedInput.length === 0) continue;
|
|
103
|
+
const absolutePath = path.normalize(path.isAbsolute(trimmedInput) ? trimmedInput : path.resolve(projectRoot, trimmedInput));
|
|
104
|
+
const projectRelativePath = path.relative(projectRoot, absolutePath);
|
|
105
|
+
if (projectRelativePath.startsWith("..") || path.isAbsolute(projectRelativePath)) throw new DeployTargetError(`Target file "${inputPath}" must be inside project root ${projectRoot}.`);
|
|
106
|
+
await access(absolutePath).catch(() => {
|
|
107
|
+
throw new DeployTargetError(`Target file "${inputPath}" was not found.`);
|
|
108
|
+
});
|
|
109
|
+
const kind = classifyDeployTargetFile(absolutePath);
|
|
110
|
+
if (kind === "unknown") throw new DeployTargetError(`Target file "${inputPath}" is not deployable. Expected a .workflow.ts, .agent.ts, or .task.ts file.`);
|
|
111
|
+
resolvedTargets.push({
|
|
112
|
+
kind,
|
|
113
|
+
inputPath,
|
|
114
|
+
absolutePath,
|
|
115
|
+
projectRelativePath
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return resolvedTargets;
|
|
119
|
+
}
|
|
120
|
+
function groupDeployTargetsByKind(targets) {
|
|
121
|
+
const grouped = {
|
|
122
|
+
workflows: [],
|
|
123
|
+
agents: [],
|
|
124
|
+
tasks: []
|
|
125
|
+
};
|
|
126
|
+
for (const target of targets) switch (target.kind) {
|
|
127
|
+
case "workflow":
|
|
128
|
+
grouped.workflows.push(target);
|
|
129
|
+
break;
|
|
130
|
+
case "agent":
|
|
131
|
+
grouped.agents.push(target);
|
|
132
|
+
break;
|
|
133
|
+
case "task":
|
|
134
|
+
grouped.tasks.push(target);
|
|
135
|
+
break;
|
|
136
|
+
default: {
|
|
137
|
+
const exhaustive = target.kind;
|
|
138
|
+
throw new DeployTargetError(`Unsupported target kind: ${exhaustive}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return grouped;
|
|
142
|
+
}
|
|
143
|
+
function buildDeployArtifactFilter(result, deployMode) {
|
|
144
|
+
if (deployMode === "project") return;
|
|
145
|
+
return {
|
|
146
|
+
workflows: result.artifacts.map((artifact) => artifact.manifest.name),
|
|
147
|
+
agents: result.agentArtifacts.map((artifact) => artifact.agent.agentId),
|
|
148
|
+
tasks: result.taskArtifacts.map((artifact) => artifact.task.taskId)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/commands/deploy/deploy.handler.ts
|
|
153
|
+
const deployHandlerDependencies = {
|
|
154
|
+
deployFromDir: void 0,
|
|
155
|
+
buildTaskTargets: void 0,
|
|
156
|
+
createDeployClient: void 0,
|
|
157
|
+
deployTaskTargets: void 0
|
|
158
|
+
};
|
|
159
|
+
async function handleDeploy(options, ctx) {
|
|
160
|
+
return withErrorBoundary("Deployment", async () => {
|
|
161
|
+
const workflowsDir = await requireWorkflowsDir(options.path);
|
|
162
|
+
const projectConfig = await assertWorkflowProjectRoot(workflowsDir);
|
|
163
|
+
const deployMode = getDeployMode(options.target);
|
|
164
|
+
const groupedTargets = groupDeployTargetsByKind(deployMode === "targets" ? await resolveDeployTargetFiles(workflowsDir, options.target) : []);
|
|
165
|
+
const artifactKinds = deployMode === "targets" ? [
|
|
166
|
+
...groupedTargets.workflows.length > 0 ? ["workflow"] : [],
|
|
167
|
+
...groupedTargets.agents.length > 0 ? ["agent"] : [],
|
|
168
|
+
...groupedTargets.tasks.length > 0 ? ["task"] : []
|
|
169
|
+
] : [
|
|
170
|
+
"workflow",
|
|
171
|
+
"agent",
|
|
172
|
+
"task"
|
|
173
|
+
];
|
|
174
|
+
trackProject(workflowsDir);
|
|
175
|
+
const forceBuild = options.force && !options.incrementalBuild;
|
|
176
|
+
logger.info("Starting deployment", {
|
|
177
|
+
workflowsDir,
|
|
178
|
+
dryRun: options.dryRun,
|
|
179
|
+
forceBuild,
|
|
180
|
+
targets: options.target
|
|
181
|
+
});
|
|
182
|
+
if (deployMode === "targets" && groupedTargets.tasks.length > 0 && groupedTargets.workflows.length === 0 && groupedTargets.agents.length === 0) {
|
|
183
|
+
await handleTaskTargetDeploy({
|
|
184
|
+
workflowsDir,
|
|
185
|
+
projectConfig,
|
|
186
|
+
options,
|
|
187
|
+
ctx,
|
|
188
|
+
targetFiles: options.target
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
let client;
|
|
193
|
+
if (!options.dryRun || options.diff) {
|
|
194
|
+
client = await createFullDeployClient(ctx);
|
|
195
|
+
await assertProjectConfigMatchesAuthenticatedOrg(client, projectConfig);
|
|
196
|
+
}
|
|
197
|
+
renderBuildHeader(void 0);
|
|
198
|
+
const buildProgress = createBuildProgress("project");
|
|
199
|
+
let outDir;
|
|
200
|
+
let artifactFilter;
|
|
201
|
+
try {
|
|
202
|
+
const { runWorkflowBuild } = await import("./workflow-build-DBQaBfnn.mjs").then((n) => n.o);
|
|
203
|
+
const buildOutcome = await runWorkflowBuild({
|
|
204
|
+
workflowsDir,
|
|
205
|
+
verbose: options.verbose,
|
|
206
|
+
force: forceBuild,
|
|
207
|
+
targetFiles: options.target,
|
|
208
|
+
releaseBundleMemory: true,
|
|
209
|
+
...options.disableSourcemaps ? { sourceMaps: false } : {},
|
|
210
|
+
onProgressEvent: (event) => buildProgress.handleEvent(event)
|
|
211
|
+
});
|
|
212
|
+
outDir = buildOutcome.outDir;
|
|
213
|
+
artifactFilter = buildDeployArtifactFilter(buildOutcome.result, deployMode);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
renderBuildFailure(error);
|
|
216
|
+
throw new CliExitError("Build failed");
|
|
217
|
+
} finally {
|
|
218
|
+
buildProgress.stop();
|
|
219
|
+
}
|
|
220
|
+
if (options.diff) {
|
|
221
|
+
if (!client) throw new CliExitError("Deployment client was not initialized.");
|
|
222
|
+
renderDeployDiff(await computeDeployDiff({
|
|
223
|
+
outDir,
|
|
224
|
+
workflowsDir,
|
|
225
|
+
projectId: projectConfig.projectId,
|
|
226
|
+
client
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
if (options.dryRun) {
|
|
230
|
+
ui.success("Dry run complete. Deployment skipped.");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (!client) throw new CliExitError("Deployment client was not initialized.");
|
|
234
|
+
const progress = createDeployProgress();
|
|
235
|
+
let result;
|
|
236
|
+
try {
|
|
237
|
+
result = await (deployHandlerDependencies.deployFromDir ?? (await import("./dist-BkJUoBiG.mjs").then((n) => n.r)).deployFromDir)({
|
|
238
|
+
outDir,
|
|
239
|
+
workflowsDir,
|
|
240
|
+
client,
|
|
241
|
+
isLocalMode: isLocalMode(),
|
|
242
|
+
force: options.force,
|
|
243
|
+
deploymentScope: deployMode === "targets" ? "targets" : "project",
|
|
244
|
+
...deployMode === "targets" ? {
|
|
245
|
+
artifactFilter,
|
|
246
|
+
artifactKinds
|
|
247
|
+
} : {},
|
|
248
|
+
onDeployProgressEvent: (event) => progress.handleEvent(event)
|
|
249
|
+
});
|
|
250
|
+
} finally {
|
|
251
|
+
progress.stop();
|
|
252
|
+
}
|
|
253
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
254
|
+
if (result.success) {
|
|
255
|
+
renderSuccessSummary(result);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
renderFailureSummary(result);
|
|
259
|
+
throw new CliExitError("Deployment failed");
|
|
260
|
+
}, { json: ctx.jsonMode });
|
|
261
|
+
}
|
|
262
|
+
async function handleTaskTargetDeploy(options) {
|
|
263
|
+
renderBuildHeader(void 0);
|
|
264
|
+
const buildResult = await (deployHandlerDependencies.buildTaskTargets ?? (await import("./task-target-build-CBeCKbu2.mjs")).buildTaskTargets)({
|
|
265
|
+
projectRoot: options.workflowsDir,
|
|
266
|
+
targetFiles: options.targetFiles,
|
|
267
|
+
disableSourcemaps: options.options.disableSourcemaps
|
|
268
|
+
});
|
|
269
|
+
if (buildResult.failures.length > 0) {
|
|
270
|
+
for (const failure of buildResult.failures) ui.error(failure.error);
|
|
271
|
+
throw new CliExitError("Build failed");
|
|
272
|
+
}
|
|
273
|
+
if (options.options.dryRun) {
|
|
274
|
+
ui.success("Dry run complete. Deployment skipped.");
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const client = await createTaskDeployClient(options.ctx);
|
|
278
|
+
await assertProjectConfigMatchesAuthenticatedOrg(client, options.projectConfig);
|
|
279
|
+
const progress = createDeployProgress();
|
|
280
|
+
let result;
|
|
281
|
+
try {
|
|
282
|
+
result = await (deployHandlerDependencies.deployTaskTargets ?? (await import("./task-target-deploy-C5X-USeR.mjs")).deployTaskTargets)({
|
|
283
|
+
preparedTasks: buildResult.preparedTasks,
|
|
284
|
+
client,
|
|
285
|
+
organizationId: options.projectConfig.organizationId,
|
|
286
|
+
projectId: options.projectConfig.projectId,
|
|
287
|
+
projectRoot: options.workflowsDir,
|
|
288
|
+
force: options.options.force,
|
|
289
|
+
onDeployProgressEvent: (event) => progress.handleEvent(event)
|
|
290
|
+
});
|
|
291
|
+
} finally {
|
|
292
|
+
progress.stop();
|
|
293
|
+
}
|
|
294
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
295
|
+
if (result.success) {
|
|
296
|
+
renderSuccessSummary(result);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
renderFailureSummary(result);
|
|
300
|
+
throw new CliExitError("Deployment failed");
|
|
301
|
+
}
|
|
302
|
+
async function createFullDeployClient(ctx) {
|
|
303
|
+
const authOptions = requireAuthOptions(ctx);
|
|
304
|
+
const { createClient } = await import("./src-eHwu-Gfw.mjs");
|
|
305
|
+
return createClient({
|
|
306
|
+
...authOptions,
|
|
307
|
+
onRequest: (info) => logger.debug(`-> ${info.method} ${info.url}`, {
|
|
308
|
+
headers: info.headers,
|
|
309
|
+
body: info.body
|
|
310
|
+
}),
|
|
311
|
+
onResponse: (info) => logger.debug(`<- ${info.status} ${info.method} ${info.url} (${info.durationMs}ms)`, {
|
|
312
|
+
headers: info.headers,
|
|
313
|
+
body: info.body
|
|
314
|
+
})
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
async function createTaskDeployClient(ctx) {
|
|
318
|
+
const authOptions = requireAuthOptions(ctx);
|
|
319
|
+
return (deployHandlerDependencies.createDeployClient ?? (await import("./deploy-7Jjls436.mjs")).createDeployClient)(authOptions);
|
|
320
|
+
}
|
|
321
|
+
function renderSuccessSummary(result) {
|
|
322
|
+
const tasks = result.tasks || [];
|
|
323
|
+
if (result.workflows.length === 0 && result.agents.length === 0 && tasks.length === 0) {
|
|
324
|
+
ui.hint("Nothing to deploy.");
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const deployedWorkflows = result.workflows.filter((w) => w.status === "deployed");
|
|
328
|
+
const deployedAgents = result.agents.filter((a) => a.status === "deployed");
|
|
329
|
+
const deployedTasks = tasks.filter((t) => t.status === "deployed");
|
|
330
|
+
const skippedWorkflows = result.workflows.filter((w) => w.status === "skipped");
|
|
331
|
+
const skippedAgents = result.agents.filter((a) => a.status === "skipped");
|
|
332
|
+
const skippedTasks = tasks.filter((t) => t.status === "skipped");
|
|
333
|
+
if (deployedWorkflows.length === 0 && deployedAgents.length === 0 && deployedTasks.length === 0) {
|
|
334
|
+
if (skippedWorkflows.length > 0 || skippedAgents.length > 0 || skippedTasks.length > 0) ui.success("All workflows, agents, and tasks are up to date.");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function renderFailureSummary(result) {
|
|
339
|
+
const tasks = result.tasks || [];
|
|
340
|
+
const failedWorkflows = result.workflows.filter((wf) => wf.status === "failed");
|
|
341
|
+
const failedAgents = result.agents.filter((agent) => agent.status === "failed");
|
|
342
|
+
const failedTasks = tasks.filter((task) => task.status === "failed");
|
|
343
|
+
ui.error("Deployment failed for some artifacts:");
|
|
344
|
+
const allErrors = [
|
|
345
|
+
...failedWorkflows.map((wf) => ({
|
|
346
|
+
name: wf.name,
|
|
347
|
+
kind: "workflow",
|
|
348
|
+
error: wf.error
|
|
349
|
+
})),
|
|
350
|
+
...failedAgents.map((a) => ({
|
|
351
|
+
name: a.name,
|
|
352
|
+
kind: "agent",
|
|
353
|
+
error: a.error
|
|
354
|
+
})),
|
|
355
|
+
...failedTasks.map((t) => ({
|
|
356
|
+
name: t.name,
|
|
357
|
+
kind: "task",
|
|
358
|
+
error: t.error
|
|
359
|
+
}))
|
|
360
|
+
];
|
|
361
|
+
const uniqueErrors = [...new Set(allErrors.map((e) => e.error))];
|
|
362
|
+
if (uniqueErrors.length === 1 && allErrors.length > 1 && allErrors.length > 3) ui.hint(`- ${failedWorkflows.length} workflow(s), ${failedAgents.length} agent(s), ${failedTasks.length} task(s): ${uniqueErrors[0]}`);
|
|
363
|
+
else {
|
|
364
|
+
for (const wf of failedWorkflows) ui.hint(`- workflow ${wf.name}: ${wf.error}`);
|
|
365
|
+
for (const agent of failedAgents) ui.hint(`- agent ${agent.name}: ${agent.error}`);
|
|
366
|
+
for (const task of failedTasks) ui.hint(`- task ${task.name}: ${task.error}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
export { handleDeploy };
|