@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,369 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { a as createKyInstance, i as buildSearchParams, n as auth, r as bundles, s as getClientEnv, t as projects$1 } from "./projects-CHkRE9rS.mjs";
|
|
4
|
+
//#region ../../packages/workflow-sdk/src/v1/agents.ts
|
|
5
|
+
const agents = (api) => ({ list: (params) => api.get("agents", { searchParams: params }).json() });
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region ../../packages/workflow-sdk/src/v1/api-keys.ts
|
|
8
|
+
const apiKeys = (api) => ({
|
|
9
|
+
/** List API keys for the current organization. */
|
|
10
|
+
list: () => api.get("api-keys").json(),
|
|
11
|
+
/** Create a new API key. The key value is only returned once. */
|
|
12
|
+
create: (params) => api.post("api-keys", { json: params ?? {} }).json(),
|
|
13
|
+
/** Delete an API key. */
|
|
14
|
+
remove: (id) => api.delete(`api-keys/${id}`).json()
|
|
15
|
+
});
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region ../../packages/workflow-sdk/src/v1/connections.ts
|
|
18
|
+
const connections = (api) => ({
|
|
19
|
+
/**
|
|
20
|
+
* Returns the caller's configured connections.
|
|
21
|
+
*
|
|
22
|
+
* @param params Optional filters. See `ListConnectionsQuerySchema` in
|
|
23
|
+
* `@keystroke/shared-types/connections` for the authoritative schema.
|
|
24
|
+
*/
|
|
25
|
+
list: (params) => {
|
|
26
|
+
const searchParams = buildSearchParams(params);
|
|
27
|
+
return api.get("connections", searchParams ? { searchParams } : {}).json();
|
|
28
|
+
} });
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region ../../packages/workflow-sdk/src/v1/credentials.ts
|
|
31
|
+
const credentials = (api) => ({
|
|
32
|
+
/** List credential sets, optionally filtered. */
|
|
33
|
+
list: (params) => {
|
|
34
|
+
const searchParams = buildSearchParams(params);
|
|
35
|
+
return api.get("credentials", searchParams ? { searchParams } : {}).json();
|
|
36
|
+
},
|
|
37
|
+
/** Create a new credential set. */
|
|
38
|
+
create: (params) => api.post("credentials", { json: params }).json(),
|
|
39
|
+
/** Get a credential set by ID. */
|
|
40
|
+
getById: (id) => api.get(`credentials/${id}`).json(),
|
|
41
|
+
/** Update a credential set (metadata only). */
|
|
42
|
+
update: (id, params) => api.patch(`credentials/${id}`, { json: params }).json(),
|
|
43
|
+
/** Delete a credential set. */
|
|
44
|
+
remove: (id) => api.delete(`credentials/${id}`).json(),
|
|
45
|
+
/** Update credential values (secrets) for a credential set. */
|
|
46
|
+
updateValues: (id, params) => api.put(`credentials/${id}/values`, { json: params }).json(),
|
|
47
|
+
/** Resolve decrypted credential values for an integration. */
|
|
48
|
+
resolve: (params) => api.post("credentials/resolve", { json: params }).json(),
|
|
49
|
+
/**
|
|
50
|
+
* Exchange user-submitted `input` for a stored credential payload via
|
|
51
|
+
* an authored `credentials-exchange` connection.
|
|
52
|
+
*
|
|
53
|
+
* Returns `{ status: 'exchanged', ... }` on success or
|
|
54
|
+
* `{ status: 'needs-reinput', message? }` when the exchange hook
|
|
55
|
+
* rejects the input. The CLI and web UI render the `message` and
|
|
56
|
+
* return the user to the connect form on `needs-reinput`.
|
|
57
|
+
*
|
|
58
|
+
* @see packages/credential-connection/src/exchange.ts executeCredentialsExchange
|
|
59
|
+
*/
|
|
60
|
+
exchange: (params) => api.post("credentials/exchange", { json: params }).json()
|
|
61
|
+
});
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region ../../packages/workflow-sdk/src/v1/hooks.ts
|
|
64
|
+
const hooks = (api) => ({
|
|
65
|
+
/** Resume a wait hook with optional payload. Continues workflow execution. */
|
|
66
|
+
resume: (token, payload) => api.post(`hooks/${token}/resume`, { json: payload ?? {} }).json(),
|
|
67
|
+
/** Cancel a wait hook. Optionally provide a reason. */
|
|
68
|
+
cancel: (token, body) => api.post(`hooks/${token}/cancel`, { json: body ?? {} }).json()
|
|
69
|
+
});
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region ../../packages/workflow-sdk/src/v1/integrations.ts
|
|
72
|
+
const integrations = (api) => ({
|
|
73
|
+
/**
|
|
74
|
+
* Returns the Keystroke integration catalog.
|
|
75
|
+
*
|
|
76
|
+
* Catalog data is effectively static for a given server deploy. Consumers
|
|
77
|
+
* should cache the response for the lifetime of a UI session / CLI process
|
|
78
|
+
* rather than refetching per command.
|
|
79
|
+
*
|
|
80
|
+
* @param params Optional query filters. See `ListIntegrationsQuerySchema`
|
|
81
|
+
* in `@keystroke/shared-types/connections` for the authoritative schema.
|
|
82
|
+
*/
|
|
83
|
+
list: (params) => {
|
|
84
|
+
const searchParams = buildSearchParams(params);
|
|
85
|
+
return api.get("integrations", searchParams ? { searchParams } : {}).json();
|
|
86
|
+
} });
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region ../../packages/workflow-sdk/src/v1/organizations.ts
|
|
89
|
+
const organizations = (api) => ({
|
|
90
|
+
/** List organizations (paginated). */
|
|
91
|
+
list: (params) => api.get("organizations", { searchParams: params }).json(),
|
|
92
|
+
/** Create a new organization. */
|
|
93
|
+
create: (params) => api.post("organizations", { json: params }).json(),
|
|
94
|
+
/** Get an organization by ID. */
|
|
95
|
+
getById: (id) => api.get(`organizations/${id}`).json(),
|
|
96
|
+
/** Update an organization. */
|
|
97
|
+
update: (id, params) => api.patch(`organizations/${id}`, { json: params }).json(),
|
|
98
|
+
/** Delete an organization. */
|
|
99
|
+
remove: (id) => api.delete(`organizations/${id}`).json()
|
|
100
|
+
});
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region ../../packages/workflow-sdk/src/v1/projects.ts
|
|
103
|
+
const projects = (api) => ({
|
|
104
|
+
/** List projects, optionally filtered by organization. */
|
|
105
|
+
list: (params) => api.get("projects", { searchParams: params }).json(),
|
|
106
|
+
/** Create a new project. */
|
|
107
|
+
create: (params) => api.post("projects", { json: params }).json(),
|
|
108
|
+
/** Get a project by ID. */
|
|
109
|
+
getById: (id) => api.get(`projects/${id}`).json(),
|
|
110
|
+
/** Update a project. */
|
|
111
|
+
update: (id, params) => api.patch(`projects/${id}`, { json: params }).json(),
|
|
112
|
+
/** Get a short-lived proxy token for the sandbox agent LLM proxy. */
|
|
113
|
+
getAgentToken: (id) => api.post(`projects/${id}/daytona-sandbox/agent-token`).json(),
|
|
114
|
+
/** Get git clone credentials for sandbox git operations. */
|
|
115
|
+
getGitToken: (id) => api.post(`projects/${id}/daytona-sandbox/git-token`).json(),
|
|
116
|
+
/** Delete a project. */
|
|
117
|
+
remove: (id) => api.delete(`projects/${id}`).then(() => void 0),
|
|
118
|
+
/** Roll back a project to a previous deployment snapshot. */
|
|
119
|
+
listDeployments: (projectId) => api.get(`projects/${projectId}/deployments`).json(),
|
|
120
|
+
/** Get a workflow snapshot from the current deployment for a project. */
|
|
121
|
+
getCurrentDeploymentWorkflow: (projectId, authoredWorkflowId) => api.get(`projects/${projectId}/deployments/current/workflows/${authoredWorkflowId}`).json(),
|
|
122
|
+
/** Roll back a project to a previous deployment snapshot. */
|
|
123
|
+
rollbackDeployment: (projectId, deploymentId) => api.post(`projects/${projectId}/deployments/${deploymentId}/rollback`).json(),
|
|
124
|
+
/** Get current user's subscription for a workflow in a project. */
|
|
125
|
+
getWorkflowSubscription: (projectId, workflowId) => api.get(`projects/${projectId}/workflows/${workflowId}/subscription`).json(),
|
|
126
|
+
/** Create or update current user's subscription for a workflow in a project. */
|
|
127
|
+
upsertWorkflowSubscription: (projectId, workflowId, params) => api.put(`projects/${projectId}/workflows/${workflowId}/subscription`, { json: params }).json(),
|
|
128
|
+
/** Remove current user's subscription for a workflow in a project. */
|
|
129
|
+
removeWorkflowSubscription: (projectId, workflowId) => api.delete(`projects/${projectId}/workflows/${workflowId}/subscription`).then(() => void 0)
|
|
130
|
+
});
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region ../../packages/workflow-sdk/src/v1/public/index.ts
|
|
133
|
+
const publicApi = (api) => ({
|
|
134
|
+
auth: auth(api),
|
|
135
|
+
projects: projects$1(api)
|
|
136
|
+
});
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region ../../packages/workflow-sdk/src/v1/runs.ts
|
|
139
|
+
const runs = (api) => ({
|
|
140
|
+
/** List recent workflow runs, optionally filtered by authored workflow id, workflow name, and status. */
|
|
141
|
+
listRuns: (params) => {
|
|
142
|
+
const searchParams = buildSearchParams(params);
|
|
143
|
+
return api.get("runs", searchParams ? { searchParams } : {}).json();
|
|
144
|
+
},
|
|
145
|
+
/** List workflow runs currently paused on an active wait or hook. */
|
|
146
|
+
listPausedRuns: (params) => {
|
|
147
|
+
const searchParams = buildSearchParams(params);
|
|
148
|
+
return api.get("runs/paused", searchParams ? { searchParams } : {}).json();
|
|
149
|
+
},
|
|
150
|
+
/** Get the current status, input, and output of a workflow run. */
|
|
151
|
+
getRun: (runId) => api.get(`runs/${runId}`).json(),
|
|
152
|
+
/** Inspect an agent run with its events, yielded child workflows, and latest replay snapshot. */
|
|
153
|
+
getAgentRun: (agentRunId) => api.get(`agent-runs/${agentRunId}`).json(),
|
|
154
|
+
/** List workflow events for a run. */
|
|
155
|
+
listEvents: (runId) => api.get(`runs/${runId}/events`).json(),
|
|
156
|
+
/** List workflow logs for a run. */
|
|
157
|
+
listLogs: (runId, params) => {
|
|
158
|
+
const searchParams = buildSearchParams(params);
|
|
159
|
+
return api.get(`runs/${runId}/logs`, searchParams ? { searchParams } : {}).json();
|
|
160
|
+
},
|
|
161
|
+
/** Delete a test run and all dependent records. */
|
|
162
|
+
deleteTestRun: (runId) => api.delete(`runs/${runId}`).json(),
|
|
163
|
+
/** Request cancellation of a sandbox agent within a run. */
|
|
164
|
+
cancelAgent: (runId, correlationId, body) => api.post(`runs/${runId}/agents/${correlationId}/cancel`, { json: body ?? {} }).json()
|
|
165
|
+
});
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region ../../packages/workflow-sdk/src/v1/steps.ts
|
|
168
|
+
const steps = (api) => ({
|
|
169
|
+
/** List steps, optionally filtered by project. */
|
|
170
|
+
list: (params) => api.get("steps", { searchParams: params }).json(),
|
|
171
|
+
/** Create a new step definition. */
|
|
172
|
+
create: (params) => api.post("steps", { json: params }).json(),
|
|
173
|
+
/** Get a step by ID. */
|
|
174
|
+
getById: (id) => api.get(`steps/${id}`).json(),
|
|
175
|
+
/** Update a step definition. */
|
|
176
|
+
update: (id, params) => api.patch(`steps/${id}`, { json: params }).json(),
|
|
177
|
+
/** Delete a step definition. */
|
|
178
|
+
remove: (id) => api.delete(`steps/${id}`).then(() => void 0),
|
|
179
|
+
/** List versions of a step. */
|
|
180
|
+
listVersions: (id, params) => api.get(`steps/${id}/versions`, { searchParams: params }).json(),
|
|
181
|
+
/** Create a new version of a step. */
|
|
182
|
+
createVersion: (id, params) => api.post(`steps/${id}/versions`, { json: params }).json(),
|
|
183
|
+
/** Get a specific step version. */
|
|
184
|
+
getVersion: (id, version) => api.get(`steps/${id}/versions/${version}`).json()
|
|
185
|
+
});
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region ../../packages/workflow-sdk/src/v1/user-groups.ts
|
|
188
|
+
const userGroups = (api) => ({
|
|
189
|
+
/** List user groups, optionally filtered by organization. */
|
|
190
|
+
list: (params) => api.get("user-groups", { searchParams: params }).json(),
|
|
191
|
+
/** Create a new user group. */
|
|
192
|
+
create: (params) => api.post("user-groups", { json: params }).json(),
|
|
193
|
+
/** Get a user group by ID. */
|
|
194
|
+
getById: (id) => api.get(`user-groups/${id}`).json(),
|
|
195
|
+
/** Update a user group. */
|
|
196
|
+
update: (id, params) => api.patch(`user-groups/${id}`, { json: params }).json(),
|
|
197
|
+
/** Delete a user group. */
|
|
198
|
+
remove: (id) => api.delete(`user-groups/${id}`).then(() => void 0),
|
|
199
|
+
/** List members of a user group. */
|
|
200
|
+
listMembers: (id) => api.get(`user-groups/${id}/members`).json(),
|
|
201
|
+
/** Add a member to a user group. */
|
|
202
|
+
addMember: (id, params) => api.post(`user-groups/${id}/members`, { json: params }).json(),
|
|
203
|
+
/** Remove a member from a user group. */
|
|
204
|
+
removeMember: (id, userId) => api.delete(`user-groups/${id}/members/${userId}`).json()
|
|
205
|
+
});
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region ../../packages/workflow-sdk/src/v1/users.ts
|
|
208
|
+
const users = (api) => ({
|
|
209
|
+
/** Create a new user. */
|
|
210
|
+
create: (params) => api.post("users", { json: params }).json(),
|
|
211
|
+
/** Get the currently authenticated user. */
|
|
212
|
+
getMe: () => api.get("users/me").json(),
|
|
213
|
+
/** List current user's workflow subscriptions across projects. */
|
|
214
|
+
listSubscriptions: () => api.get("users/me/subscriptions").json(),
|
|
215
|
+
/** Get a user by ID. */
|
|
216
|
+
getById: (id) => api.get(`users/${id}`).json(),
|
|
217
|
+
/** Invite users to the current organization by email. */
|
|
218
|
+
invite: (params) => api.post("users/invite", { json: params }).json()
|
|
219
|
+
});
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region ../../packages/workflow-sdk/src/v1/webhooks.ts
|
|
222
|
+
function buildWebhookEndpoint(organizationId, webhookPath) {
|
|
223
|
+
const normalizedPath = webhookPath.replace(/^\/+/, "");
|
|
224
|
+
if (!normalizedPath) throw new Error("webhookPath is required");
|
|
225
|
+
return `webhooks/${encodeURIComponent(organizationId)}/${encodeURIComponent(normalizedPath)}`;
|
|
226
|
+
}
|
|
227
|
+
function isBodyInit(body) {
|
|
228
|
+
if (typeof body === "string") return true;
|
|
229
|
+
if (typeof FormData !== "undefined" && body instanceof FormData) return true;
|
|
230
|
+
if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) return true;
|
|
231
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) return true;
|
|
232
|
+
if (typeof ArrayBuffer !== "undefined" && body instanceof ArrayBuffer) return true;
|
|
233
|
+
if (typeof ReadableStream !== "undefined" && body instanceof ReadableStream) return true;
|
|
234
|
+
if (ArrayBuffer.isView(body)) return true;
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
function serializeWebhookRequestBody(body, headers) {
|
|
238
|
+
if (body === void 0) return void 0;
|
|
239
|
+
if (isBodyInit(body)) return body;
|
|
240
|
+
if (!headers.has("Content-Type")) headers.set("Content-Type", "application/json");
|
|
241
|
+
return JSON.stringify(body);
|
|
242
|
+
}
|
|
243
|
+
const webhooks = (api) => ({
|
|
244
|
+
/**
|
|
245
|
+
* Send a request directly to a custom webhook endpoint.
|
|
246
|
+
*
|
|
247
|
+
* Use this for public webhook ingress where the caller supplies the webhook
|
|
248
|
+
* path, HTTP method, provider auth/signature headers, query params, and body.
|
|
249
|
+
*/
|
|
250
|
+
send: (request) => {
|
|
251
|
+
const headers = new Headers(request.headers);
|
|
252
|
+
const body = serializeWebhookRequestBody(request.body, headers);
|
|
253
|
+
return api(buildWebhookEndpoint(request.organizationId, request.webhookPath), {
|
|
254
|
+
method: request.method ?? "POST",
|
|
255
|
+
headers,
|
|
256
|
+
body,
|
|
257
|
+
searchParams: request.searchParams
|
|
258
|
+
}).json();
|
|
259
|
+
},
|
|
260
|
+
/**
|
|
261
|
+
* Send a request to a webhook endpoint (simulates inbound webhook).
|
|
262
|
+
* Use for testing or forwarding webhook payloads.
|
|
263
|
+
*/
|
|
264
|
+
handle: (orgId, webhookId, options) => webhooks(api).send({
|
|
265
|
+
organizationId: orgId,
|
|
266
|
+
webhookPath: webhookId,
|
|
267
|
+
method: options?.method,
|
|
268
|
+
headers: options?.headers,
|
|
269
|
+
body: options?.body
|
|
270
|
+
}),
|
|
271
|
+
/** Replay a previously captured webhook request by ID. */
|
|
272
|
+
replay: (orgId, webhookId, requestId) => api.post(`webhooks/${orgId}/${webhookId}/replay/${requestId}`).json()
|
|
273
|
+
});
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region ../../packages/workflow-sdk/src/v1/workflows.ts
|
|
276
|
+
const workflows = (api) => ({
|
|
277
|
+
/** List workflows, optionally filtered by project. */
|
|
278
|
+
list: (params) => {
|
|
279
|
+
const searchParams = buildSearchParams(params);
|
|
280
|
+
return api.get("workflows", searchParams ? { searchParams } : {}).json();
|
|
281
|
+
},
|
|
282
|
+
/** Create a new workflow definition. */
|
|
283
|
+
create: (params) => api.post("workflows", { json: params }).json(),
|
|
284
|
+
/** Get a workflow by project-scoped authored ID. */
|
|
285
|
+
getById: (projectId, workflowId) => api.get(`projects/${projectId}/workflows/${workflowId}`).json(),
|
|
286
|
+
/** Update a workflow definition. */
|
|
287
|
+
update: (projectId, workflowId, params) => api.patch(`projects/${projectId}/workflows/${workflowId}`, { json: params }).json(),
|
|
288
|
+
/** Delete a workflow definition. */
|
|
289
|
+
remove: (projectId, workflowId) => api.delete(`projects/${projectId}/workflows/${workflowId}`).then(() => void 0),
|
|
290
|
+
/** Start a new run of a workflow. Returns immediately with a run ID. */
|
|
291
|
+
execute: (params) => api.post("workflows/execute", { json: params }).json(),
|
|
292
|
+
/** Test a workflow. Server upserts workflow, runs with source 'cli-test'. */
|
|
293
|
+
testById: (params) => api.post("workflows/test", { json: params }).json(),
|
|
294
|
+
/** Delete a test bundle from S3 storage. */
|
|
295
|
+
deleteTestBundle: (params) => api.delete("workflows/test", { json: params }).then(() => void 0),
|
|
296
|
+
/** Get the ReactFlow graph for the latest deployed version of a workflow. */
|
|
297
|
+
getGraph: (projectId, workflowId) => api.get(`projects/${projectId}/workflows/${workflowId}/graph`).json(),
|
|
298
|
+
/** Apply visual mutations (e.g. node position changes) to a workflow's graph state. */
|
|
299
|
+
applyMutations: (projectId, workflowId, params) => api.post(`projects/${projectId}/workflows/${workflowId}/graph`, { json: params }).json()
|
|
300
|
+
});
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region ../../packages/workflow-sdk/src/client.ts
|
|
303
|
+
/**
|
|
304
|
+
* Creates a Keystroke API client.
|
|
305
|
+
*
|
|
306
|
+
* Authentication is resolved in order: `getApiKey` > `apiKey` > `KEYSTROKE_API_KEY` env.
|
|
307
|
+
* Base URL falls back to the `SERVER_URL` env variable when not provided.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```ts
|
|
311
|
+
* // Static API key
|
|
312
|
+
* const client = createClient({ apiKey: 'wz_live_...' });
|
|
313
|
+
*
|
|
314
|
+
* // Dynamic token (e.g. from auth provider)
|
|
315
|
+
* const client = createClient({
|
|
316
|
+
* baseUrl: 'https://api.keystroke.dev',
|
|
317
|
+
* getApiKey: () => getSession().then((s) => s.accessToken),
|
|
318
|
+
* });
|
|
319
|
+
*
|
|
320
|
+
* // Execute a workflow
|
|
321
|
+
* const { runId } = await client.workflows.execute({
|
|
322
|
+
* projectId: '00000000-0000-4000-8000-000000000001',
|
|
323
|
+
* authoredWorkflowId: 'onboard-user',
|
|
324
|
+
* args: [{ email: 'user@example.com' }],
|
|
325
|
+
* });
|
|
326
|
+
*
|
|
327
|
+
* // Check run status
|
|
328
|
+
* const { run } = await client.runs.getRun(runId);
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
function createClient(config = {}) {
|
|
332
|
+
const env = getClientEnv();
|
|
333
|
+
const baseUrl = config.baseUrl ?? env.SERVER_URL;
|
|
334
|
+
const apiKey = config.apiKey ?? env.KEYSTROKE_API_KEY;
|
|
335
|
+
const getApiKey = config.getApiKey;
|
|
336
|
+
const organizationId = config.organizationId ?? env.KEYSTROKE_ORG_ID;
|
|
337
|
+
const getOrganizationId = config.getOrganizationId;
|
|
338
|
+
if (!baseUrl) throw new Error("baseUrl is required (pass in config or set SERVER_URL)");
|
|
339
|
+
if (!(apiKey ?? getApiKey)) throw new Error("Keystroke API Key is required (pass apiKey, getApiKey, or set KEYSTROKE_API_KEY)");
|
|
340
|
+
const v1 = createKyInstance({
|
|
341
|
+
prefixUrl: baseUrl,
|
|
342
|
+
apiKey,
|
|
343
|
+
getApiKey,
|
|
344
|
+
organizationId,
|
|
345
|
+
getOrganizationId,
|
|
346
|
+
onRequest: config.onRequest,
|
|
347
|
+
onResponse: config.onResponse
|
|
348
|
+
}).extend((options) => ({ prefixUrl: `${options.prefixUrl}/api/v1` }));
|
|
349
|
+
return {
|
|
350
|
+
agents: agents(v1),
|
|
351
|
+
apiKeys: apiKeys(v1),
|
|
352
|
+
public: publicApi(v1),
|
|
353
|
+
bundles: bundles(v1),
|
|
354
|
+
connections: connections(v1),
|
|
355
|
+
credentials: credentials(v1),
|
|
356
|
+
hooks: hooks(v1),
|
|
357
|
+
integrations: integrations(v1),
|
|
358
|
+
organizations: organizations(v1),
|
|
359
|
+
projects: projects(v1),
|
|
360
|
+
runs: runs(v1),
|
|
361
|
+
steps: steps(v1),
|
|
362
|
+
userGroups: userGroups(v1),
|
|
363
|
+
users: users(v1),
|
|
364
|
+
webhooks: webhooks(v1),
|
|
365
|
+
workflows: workflows(v1)
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
export { createClient };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { h as toErrorMessage, l as AUTH_HINT, m as isNetworkError, p as isAuthError, t as ui, u as REAUTH_HINT } from "./keystroke.mjs";
|
|
4
|
+
//#region src/commands/auth/status.handler.ts
|
|
5
|
+
async function getValidationStatus(ctx) {
|
|
6
|
+
if (!ctx.client) return { kind: "not_authenticated" };
|
|
7
|
+
try {
|
|
8
|
+
const result = await ctx.client.public.auth.validate();
|
|
9
|
+
return {
|
|
10
|
+
kind: "valid",
|
|
11
|
+
apiKeyId: result.apiKeyId,
|
|
12
|
+
organizationId: result.organizationId
|
|
13
|
+
};
|
|
14
|
+
} catch (error) {
|
|
15
|
+
const message = toErrorMessage(error);
|
|
16
|
+
if (isAuthError(error)) return {
|
|
17
|
+
kind: "invalid",
|
|
18
|
+
message
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
kind: "unavailable",
|
|
22
|
+
message,
|
|
23
|
+
reason: isNetworkError(error) ? "network" : "other"
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function getLiveUser(ctx, validation) {
|
|
28
|
+
if (!ctx.client || validation.kind !== "valid") return;
|
|
29
|
+
try {
|
|
30
|
+
const { user } = await ctx.client.users.getMe();
|
|
31
|
+
return user;
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function getLocalOrganization(ctx) {
|
|
37
|
+
if (!ctx.organizationId) return;
|
|
38
|
+
const org = ctx.storedCredentials?.orgs.find((entry) => entry.organizationId === ctx.organizationId);
|
|
39
|
+
if (!org) return { id: ctx.organizationId };
|
|
40
|
+
return {
|
|
41
|
+
id: org.organizationId,
|
|
42
|
+
name: org.organizationName
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function getLiveOrganization(liveUser, organizationId) {
|
|
46
|
+
if (!liveUser || !organizationId) return;
|
|
47
|
+
const org = liveUser.organizations?.find((entry) => entry.id === organizationId);
|
|
48
|
+
if (!org) return;
|
|
49
|
+
return {
|
|
50
|
+
id: org.id,
|
|
51
|
+
name: org.name
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function printOrganization(org) {
|
|
55
|
+
if (!org) {
|
|
56
|
+
ui.warn("No organization set. Use `keystroke org switch` or `--org` to select one.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (org.name) {
|
|
60
|
+
ui.text(`Current organization: ${org.name}`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
ui.text(`Current organization: ${org.id}`);
|
|
64
|
+
}
|
|
65
|
+
function printValidationStatus(validation) {
|
|
66
|
+
switch (validation.kind) {
|
|
67
|
+
case "valid":
|
|
68
|
+
ui.success("API key is valid.");
|
|
69
|
+
ui.hint(`Key ID: ${validation.apiKeyId}`);
|
|
70
|
+
return;
|
|
71
|
+
case "invalid":
|
|
72
|
+
ui.warn("Saved API key is invalid or expired.");
|
|
73
|
+
ui.hint(REAUTH_HINT);
|
|
74
|
+
ui.hint(`Validation error: ${validation.message}`);
|
|
75
|
+
return;
|
|
76
|
+
case "unavailable":
|
|
77
|
+
ui.warn(validation.reason === "network" ? "Could not reach the API to verify the saved API key." : "Could not verify the saved API key right now.");
|
|
78
|
+
ui.hint(`Validation error: ${validation.message}`);
|
|
79
|
+
return;
|
|
80
|
+
case "not_authenticated":
|
|
81
|
+
ui.warn(`Not authenticated. ${AUTH_HINT}`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function handleAuthStatus(_options, ctx) {
|
|
86
|
+
const validation = await getValidationStatus(ctx);
|
|
87
|
+
const liveUser = await getLiveUser(ctx, validation);
|
|
88
|
+
const organization = getLiveOrganization(liveUser, ctx.organizationId ?? (validation.kind === "valid" ? validation.organizationId : void 0)) ?? getLocalOrganization(ctx);
|
|
89
|
+
const userEmail = liveUser?.email ?? ctx.storedCredentials?.user?.email;
|
|
90
|
+
ui.header("Keystroke CLI auth status");
|
|
91
|
+
if (userEmail) ui.text(`Signed in as: ${userEmail}`);
|
|
92
|
+
else if (validation.kind === "not_authenticated") ui.hint("No saved user identity found.");
|
|
93
|
+
else ui.warn("Signed-in user could not be determined from saved credentials.");
|
|
94
|
+
printOrganization(organization);
|
|
95
|
+
if (ctx.orgSource) ui.hint(`Source: ${ctx.orgSource}`);
|
|
96
|
+
printValidationStatus(validation);
|
|
97
|
+
if (ctx.baseUrl) ui.hint(`API URL: ${ctx.baseUrl}`);
|
|
98
|
+
ui.hint(`Credentials: ${ctx.credentialsPath}`);
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { handleAuthStatus };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { D as throwReportedCliExit, t as ui } from "./keystroke.mjs";
|
|
4
|
+
import { u as setActiveOrg } from "./dist-CUK7yBM0.mjs";
|
|
5
|
+
import { i as requireClient } from "./context-T7HZuB97.mjs";
|
|
6
|
+
import { select } from "@clack/prompts";
|
|
7
|
+
//#region src/commands/org/switch.handler.ts
|
|
8
|
+
async function handleOrgSwitch(_options, ctx) {
|
|
9
|
+
const { user } = await requireClient(ctx).users.getMe();
|
|
10
|
+
const orgs = user.organizations ?? [];
|
|
11
|
+
const storedOrgIds = new Set(ctx.storedCredentials?.orgs.map((o) => o.organizationId) ?? []);
|
|
12
|
+
if (orgs.length === 0) {
|
|
13
|
+
ui.warn("You do not belong to any organization.");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (orgs.length === 1) {
|
|
17
|
+
const name = orgs[0]?.name ?? "unknown";
|
|
18
|
+
ui.hint(`You only belong to one organization: ${name}`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const selected = await select({
|
|
22
|
+
message: "Switch to organization:",
|
|
23
|
+
options: orgs.map((org) => {
|
|
24
|
+
const isCurrent = org.id === ctx.organizationId;
|
|
25
|
+
const hasKey = storedOrgIds.has(org.id);
|
|
26
|
+
const hint = isCurrent ? "(current)" : hasKey ? void 0 : "No stored key, run `keystroke auth`";
|
|
27
|
+
return {
|
|
28
|
+
value: org.id,
|
|
29
|
+
label: org.name,
|
|
30
|
+
hint
|
|
31
|
+
};
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
if (typeof selected !== "string") {
|
|
35
|
+
ui.hint("Cancelled.");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const selectedOrg = orgs.find((o) => o.id === selected);
|
|
39
|
+
if (!selectedOrg) {
|
|
40
|
+
ui.error("Selected organization not found.");
|
|
41
|
+
throwReportedCliExit("Selected organization not found.");
|
|
42
|
+
}
|
|
43
|
+
if (!storedOrgIds.has(selected)) {
|
|
44
|
+
ui.warn(`No stored API key for ${selectedOrg.name}. Run \`keystroke auth\` and select this org to add credentials.`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
await setActiveOrg(selected);
|
|
48
|
+
ui.success(`Switched to ${selectedOrg.name}`);
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { handleOrgSwitch };
|
|
@@ -0,0 +1,39 @@
|
|
|
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/sync/sync.command.ts
|
|
6
|
+
/**
|
|
7
|
+
* Sync command options schema
|
|
8
|
+
*/
|
|
9
|
+
const SyncOptionsSchema = z.object({
|
|
10
|
+
watch: z.boolean().default(false).describe("Watch for changes and sync automatically"),
|
|
11
|
+
force: z.boolean().default(false).describe("Force sync even if no changes detected")
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Commander option configuration for sync command
|
|
15
|
+
*/
|
|
16
|
+
const SYNC_OPTIONS_CONFIG = {
|
|
17
|
+
watch: {
|
|
18
|
+
flag: "--watch",
|
|
19
|
+
description: "Watch for changes and sync automatically"
|
|
20
|
+
},
|
|
21
|
+
force: {
|
|
22
|
+
flag: "--force",
|
|
23
|
+
description: "Force sync even if no changes detected"
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Creates the sync command
|
|
28
|
+
*/
|
|
29
|
+
function createSyncCommand() {
|
|
30
|
+
return createTypedCommand({
|
|
31
|
+
name: "sync",
|
|
32
|
+
description: "Sync local workflows with Keystroke",
|
|
33
|
+
schema: SyncOptionsSchema,
|
|
34
|
+
optionsConfig: SYNC_OPTIONS_CONFIG,
|
|
35
|
+
loadHandler: async () => (await import("./sync.handler-BUFPdzWz.mjs")).handleSync
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { createSyncCommand };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { access, cp, mkdir, readdir } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
//#region src/lib/sync-keystroke-agent-skills.ts
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the installed `@keystroke/skills` package root for a consumer project.
|
|
8
|
+
*
|
|
9
|
+
* Only checks `projectDir/node_modules/@keystroke/skills` (pnpm symlinks that path; npm/yarn lay out
|
|
10
|
+
* the same). We intentionally do not walk ancestor directories — that avoids resolving a
|
|
11
|
+
* unrelated workspace copy when TMPDIR or the project lives inside another repo.
|
|
12
|
+
*/
|
|
13
|
+
async function resolveKeystrokeSkillsPackageRoot(projectDir) {
|
|
14
|
+
const root = path.resolve(projectDir);
|
|
15
|
+
const marker = path.join(root, "node_modules", "@keystroke", "skills", "package.json");
|
|
16
|
+
try {
|
|
17
|
+
await access(marker);
|
|
18
|
+
return path.dirname(marker);
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function listKeystrokeSkillDirectoryNames(skillsPackageRoot) {
|
|
24
|
+
const entries = await readdir(skillsPackageRoot, { withFileTypes: true });
|
|
25
|
+
const names = [];
|
|
26
|
+
for (const e of entries) {
|
|
27
|
+
if (!e.isDirectory()) continue;
|
|
28
|
+
if (e.name.startsWith(".")) continue;
|
|
29
|
+
try {
|
|
30
|
+
await access(path.join(skillsPackageRoot, e.name, "SKILL.md"));
|
|
31
|
+
names.push(e.name);
|
|
32
|
+
} catch {}
|
|
33
|
+
}
|
|
34
|
+
return names.sort();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Copy each skill directory from `node_modules/@keystroke/skills/*` into
|
|
38
|
+
* `.cursor/skills` and `.claude/skills` under `projectDir`.
|
|
39
|
+
*/
|
|
40
|
+
async function syncKeystrokeAgentSkills(projectDir) {
|
|
41
|
+
const packageRoot = await resolveKeystrokeSkillsPackageRoot(projectDir);
|
|
42
|
+
if (!packageRoot) return {
|
|
43
|
+
ok: false,
|
|
44
|
+
reason: "not_installed"
|
|
45
|
+
};
|
|
46
|
+
const names = await listKeystrokeSkillDirectoryNames(packageRoot);
|
|
47
|
+
if (names.length === 0) return {
|
|
48
|
+
ok: false,
|
|
49
|
+
reason: "no_skills_found",
|
|
50
|
+
packageRoot
|
|
51
|
+
};
|
|
52
|
+
const root = path.resolve(projectDir);
|
|
53
|
+
for (const name of names) {
|
|
54
|
+
const src = path.join(packageRoot, name);
|
|
55
|
+
for (const rel of [".cursor/skills", ".claude/skills"]) {
|
|
56
|
+
const dest = path.join(root, rel, name);
|
|
57
|
+
await mkdir(path.dirname(dest), { recursive: true });
|
|
58
|
+
await cp(src, dest, {
|
|
59
|
+
recursive: true,
|
|
60
|
+
force: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
copied: names
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { syncKeystrokeAgentSkills as t };
|