@keystrokehq/cli 0.1.38 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{dist-DkLbeW8l.mjs → dist-BOhrc_Nv.mjs} +198 -561
- package/dist/dist-BOhrc_Nv.mjs.map +1 -0
- package/dist/{dist-B6z1wti6.mjs → dist-D-cLLjHv.mjs} +87 -2017
- package/dist/dist-D-cLLjHv.mjs.map +1 -0
- package/dist/{dist-GSI9JDuz.mjs → dist-DGKF3FGu.mjs} +31 -265
- package/dist/dist-DGKF3FGu.mjs.map +1 -0
- package/dist/dist-DMuIdus5.mjs +3 -0
- package/dist/{dist-gAvgHBlr.mjs → dist-Re6HHSqz.mjs} +2 -2
- package/dist/{dist-gAvgHBlr.mjs.map → dist-Re6HHSqz.mjs.map} +1 -1
- package/dist/index.mjs +177 -463
- package/dist/index.mjs.map +1 -1
- package/dist/{maybe-auto-update-Dv4MJvWb.mjs → maybe-auto-update-q5MthdI8.mjs} +2 -2
- package/dist/{maybe-auto-update-Dv4MJvWb.mjs.map → maybe-auto-update-q5MthdI8.mjs.map} +1 -1
- package/dist/skills-bundle/_AGENTS.mcp.md +5 -9
- package/dist/skills-bundle/_AGENTS.md +112 -243
- package/dist/skills-bundle/skills/keystroke-actions/SKILL.md +160 -0
- package/dist/skills-bundle/skills/keystroke-actions/references/catalog-and-imports.md +71 -0
- package/dist/skills-bundle/skills/keystroke-agents/SKILL.md +115 -0
- package/dist/skills-bundle/skills/keystroke-agents/references/models.md +23 -0
- package/dist/skills-bundle/skills/keystroke-agents/references/tools-mcp-codemode.md +73 -0
- package/dist/skills-bundle/skills/keystroke-agents/references/workflows-and-testing.md +26 -0
- package/dist/skills-bundle/skills/keystroke-apps/SKILL.md +151 -0
- package/dist/skills-bundle/skills/keystroke-apps/references/cli-and-catalog.md +104 -0
- package/dist/skills-bundle/skills/keystroke-channels/SKILL.md +66 -0
- package/dist/skills-bundle/skills/keystroke-channels/references/slack-setup.md +41 -0
- package/dist/skills-bundle/skills/keystroke-cli/SKILL.md +93 -0
- package/dist/skills-bundle/skills/keystroke-deploy/SKILL.md +93 -0
- package/dist/skills-bundle/skills/keystroke-deploy/references/build-and-full-deploy.md +30 -0
- package/dist/skills-bundle/skills/keystroke-deploy/references/filtered-deploy.md +50 -0
- package/dist/skills-bundle/skills/keystroke-deploy/references/wip-ignore.md +35 -0
- package/dist/skills-bundle/skills/keystroke-files/SKILL.md +43 -0
- package/dist/skills-bundle/skills/keystroke-skills/SKILL.md +42 -0
- package/dist/skills-bundle/skills/keystroke-triggers/SKILL.md +143 -0
- package/dist/skills-bundle/skills/keystroke-workflows/SKILL.md +78 -0
- package/dist/skills-bundle/skills/keystroke-workflows/references/authoring.md +168 -0
- package/dist/skills-bundle/skills/keystroke-workflows/references/testing.md +138 -0
- package/dist/templates/hello-world/.env.example +4 -0
- package/dist/templates/hello-world/README.md +3 -4
- package/dist/templates/hello-world/package.json +0 -1
- package/dist/templates/hello-world/src/actions/greet.ts +0 -1
- package/dist/templates/hello-world/src/agents/hello.ts +0 -2
- package/dist/templates/hello-world/src/workflows/greeting.ts +0 -1
- package/dist/{version-CiFlKPyE.mjs → version-DcR3O1UD.mjs} +3 -2
- package/dist/version-DcR3O1UD.mjs.map +1 -0
- package/package.json +5 -5
- package/dist/dist-B6z1wti6.mjs.map +0 -1
- package/dist/dist-CjWXZCN7.mjs +0 -3
- package/dist/dist-DkLbeW8l.mjs.map +0 -1
- package/dist/dist-GSI9JDuz.mjs.map +0 -1
- package/dist/version-CiFlKPyE.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
3
|
-
import { i as packProjectArtifact, n as withMcpReadClient, r as mergeFilteredArtifact, t as mapInParallelBatches } from "./dist-
|
|
4
|
-
import { a as installPlaygroundDependencies, c as createCliConfig, d as getEffectiveApiTarget, f as getPlatformUrl, g as resolvePlatformUrlForWebUrl, i as installDependencies$1, l as getCliConfigDir, m as DEFAULT_PLATFORM_URL, n as buildPlaygroundWorkspace, o as resolvePackageManager, p as getWebUrl, s as resolveCliRoot, t as readCliVersion, u as getConfigDir } from "./version-
|
|
2
|
+
import { $ as GetCustomAppResponseSchema, $n as slugifyAppName, $t as SlugAvailabilityResponseSchema, A as CreateCustomAppRequestSchema, An as WorkflowRunHooksResponseSchema, At as PollRunResponseSchema, B as CredentialConsumerListQuerySchema, Bt as ProjectReachabilityResponseSchema, C as ConnectAuthorizeUrlResponseSchema, Cn as UploadProjectSourceResponseSchema, Ct as ListProjectsResponseSchema, D as CreateCredentialInstanceBodySchema, Dn as UserPreferencesPatchSchema, Dt as OrganizationSidebarBrandingSchema, E as CreateApiKeyResponseSchema, En as UserAvatarSchema, Et as OrganizationSidebarBrandingPatchSchema, F as CreateProjectRequestSchema, Fn as WorkspaceTriggerFileSchema, Ft as PresignProjectSourceRequestSchema, G as DOCS_QUERY_TOOL, Gt as PromptResponseSchema, H as CredentialInstanceListResponseSchema, Hn as detectProjectPackageManagerFromSnapshot, Ht as ProjectSettingsResponseSchema, I as CreateProjectResponseSchema, In as WorkspaceTriggerListResponseSchema, It as PresignProjectSourceResponseSchema, J as DownloadActiveProjectArtifactResponseSchema, Jn as parseErrorResponse, Jt as QueuedRunResponseSchema, K as DOCS_SEARCH_TOOL, L as CredentialAssignmentListQuerySchema, Ln as WorkspaceTriggerOverviewSchema, Lt as PresignUserAvatarRequestSchema, M as CreateOrganizationRequestSchema, Mn as WorkflowSummaryDetailResponseSchema, Mt as PresignChatAttachmentResponseSchema, N as CreateOrganizationResponseSchema, Nn as WorkflowSummaryListResponseSchema, Nt as PresignOrgLogoRequestSchema, O as CreateCredentialsRequestSchema, On as UserPreferencesSchema, Ot as PROJECT_PULL_STATE_RELATIVE_PATH, P as CreateProjectArtifactResponseSchema, Pn as WorkspaceTriggerDetailSchema, Pt as PresignOrgLogoResponseSchema, Q as GetCredentialResponseSchema, Qn as resolvePublicPlatformOrigin, Qt as SkillSummaryListResponseSchema, R as CredentialAssignmentListResponseSchema, Rn as WorkspaceTriggerRunListResponseSchema, Rt as PresignUserAvatarResponseSchema, S as CompleteProjectArtifactResponseSchema, Sn as UploadProjectSourceManifestRequestSchema, St as ListProjectMetricsResponseSchema, T as CreateApiKeyRequestSchema, Tn as UserAvatarPatchSchema, Tt as OpenApiDiscoverResponseSchema, U as CredentialInstanceRecordSchema, Un as isAcceptableInstallExit, Ut as ProjectSlugAvailabilityResponseSchema, V as CredentialConsumerListResponseSchema, Vn as deriveCustomAppDisplay, Vt as ProjectResponseSchema, Wn as listenPortFromPublicUrl, Wt as PromptInputSchema, X as ErrorResponseSchema, Xn as resolveConnectAppSlug, Xt as RecentResourceListResponseSchema, Y as DownloadActiveProjectSourceResponseSchema, Z as GatewayAttachmentRecordSchema, Zn as resolveDocsMcpUrl, Zt as SkillSummaryDetailResponseSchema, _ as ChannelAccountListResponseSchema, _n as UpdateOrganizationRequestSchema, _t as ListOrganizationMembersResponseSchema, a as AgentSessionDetailResponseSchema, an as StartOAuthConnectionResultSchema, at as HistoryRunListResponseSchema, b as ChannelDirectoryListResponseSchema, bn as UpdateProjectRequestSchema, bt as ListProjectFilesResponseSchema, c as AgentSummaryListResponseSchema, cn as TriggerDetailResponseSchema, ct as InviteProjectMembersRequestSchema, d as AssignCredentialBodySchema, dn as TriggerRunListResponseSchema, dt as ListAgentMemoryFilesResponseSchema, en as StartKeystrokeConnectionInputSchema, et as GraphqlDiscoverResponseSchema, f as BindChannelBodySchema, fn as UpdateChannelBindingBodySchema, ft as ListAgentWorkspaceFilesResponseSchema, g as CatalogAppsPageResponseSchema, gn as UpdateOrganizationMemberResponseSchema, gt as ListOrganizationInvitationsResponseSchema, h as CatalogAppDetailResponseSchema, hn as UpdateOrganizationMemberRequestSchema, ht as ListCredentialsResponseSchema, i as AgentSessionChatStateResponseSchema, in as StartOAuthConnectionInputSchema, it as HistoryRunListQuerySchema, j as CreateCustomAppResponseSchema, jn as WorkflowRunListResponseSchema, jt as PresignChatAttachmentRequestSchema, k as CreateCredentialsResponseSchema, kn as WorkflowRunDetailResponseSchema, kt as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, l as AgentTriggerSummaryListResponseSchema, ln as TriggerListResponseSchema, lt as InviteProjectMembersResponseSchema, m as CatalogActionsPageResponseSchema, mn as UpdateCredentialRequestSchema, mt as ListAppsResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nn as StartMcpOAuthConnectionInputSchema, nt as HistoryRunCancelResponseSchema, o as AgentSessionListResponseSchema, on as SubmitMarketingContactRequestSchema, ot as InviteOrganizationMembersRequestSchema, p as CatalogActionDetailResponseSchema, pn as UpdateCredentialInstanceBodySchema, pt as ListApiKeysResponseSchema, q as DeclineOrganizationInvitationResponseSchema, qn as parseAppSlug, qt as QueuedAgentPromptResponseSchema, r as ActiveOrganizationResponseSchema, rn as StartMcpOAuthConnectionResultSchema, rt as HistoryRunDetailResponseSchema, s as AgentSummaryDetailResponseSchema, sn as SubmitTeamRequestRequestSchema, st as InviteOrganizationMembersResponseSchema, t as ACTIVE_ORG_HEADER, tn as StartKeystrokeConnectionResultSchema, tt as HealthResponseSchema, u as AppSlugAvailabilityResponseSchema, un as TriggerRunDetailResponseSchema, v as ChannelConnectionListResponseSchema, vn as UpdateProjectMemberRequestSchema, vt as ListOrganizationsResponseSchema, w as ConnectProvidersResponseSchema, wn as UpsertGatewayAttachmentBodySchema, wt as McpDiscoverResponseSchema, x as ChannelPlatformSchema, xn as UpdateProjectSettingsRequestSchema, xt as ListProjectMembersResponseSchema, y as ChannelConnectionSchema, yn as UpdateProjectMemberResponseSchema, yt as ListProjectDeploymentsResponseSchema, z as CredentialAssignmentRecordSchema, zn as buildConnectDeeplink, zt as ProjectPullStateSchema } from "./dist-BOhrc_Nv.mjs";
|
|
3
|
+
import { i as packProjectArtifact, n as withMcpReadClient, r as mergeFilteredArtifact, t as mapInParallelBatches } from "./dist-Re6HHSqz.mjs";
|
|
4
|
+
import { a as installPlaygroundDependencies, c as createCliConfig, d as getEffectiveApiTarget, f as getPlatformUrl, g as resolvePlatformUrlForWebUrl, i as installDependencies$1, l as getCliConfigDir, m as DEFAULT_PLATFORM_URL, n as buildPlaygroundWorkspace, o as resolvePackageManager, p as getWebUrl, s as resolveCliRoot, t as readCliVersion, u as getConfigDir } from "./version-DcR3O1UD.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { Command } from "commander";
|
|
7
|
+
import { platform } from "node:os";
|
|
7
8
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
8
9
|
import { Entry } from "@napi-rs/keyring";
|
|
9
10
|
import { confirm, input, select } from "@inquirer/prompts";
|
|
10
11
|
import { existsSync, lstatSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
11
|
-
import { access, lstat, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
12
|
+
import { access, copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
12
13
|
import { spawn, spawnSync } from "node:child_process";
|
|
13
14
|
import { pathToFileURL } from "node:url";
|
|
14
15
|
//#region ../../node_modules/.pnpm/ky@2.0.2/node_modules/ky/distribution/errors/KyError.js
|
|
@@ -3805,18 +3806,11 @@ function createProjectMetricsResource(http) {
|
|
|
3805
3806
|
}
|
|
3806
3807
|
} };
|
|
3807
3808
|
}
|
|
3808
|
-
/**
|
|
3809
|
-
* `platform.workflows` resource.
|
|
3810
|
-
*
|
|
3811
|
-
* Every method calls a real platform route: list/detail, file, run history,
|
|
3812
|
-
* run-inputs, canvas, overview, the canvas run overlay (`getCanvasRun`), the
|
|
3813
|
-
* credential overlay (`getCanvasCredentialBindings`), and manual `run`.
|
|
3814
|
-
*/
|
|
3815
3809
|
function createWorkflowsResource(http) {
|
|
3816
3810
|
return {
|
|
3817
3811
|
async list(options) {
|
|
3818
3812
|
try {
|
|
3819
|
-
const data = await http.get("api/workflows", { searchParams: listSearchParams(options) }).json();
|
|
3813
|
+
const data = await http.get("/api/workflows", { searchParams: listSearchParams(options) }).json();
|
|
3820
3814
|
return WorkflowSummaryListResponseSchema.parse(data);
|
|
3821
3815
|
} catch (error) {
|
|
3822
3816
|
throw await toPlatformError(error);
|
|
@@ -3824,120 +3818,12 @@ function createWorkflowsResource(http) {
|
|
|
3824
3818
|
},
|
|
3825
3819
|
async get(workflowId) {
|
|
3826
3820
|
try {
|
|
3827
|
-
const data = await http.get(
|
|
3821
|
+
const data = await http.get(`/api/workflows/${encodeURIComponent(workflowId)}`).json();
|
|
3828
3822
|
return WorkflowSummaryDetailResponseSchema.parse(data);
|
|
3829
3823
|
} catch (error) {
|
|
3830
3824
|
throw await toPlatformError(error);
|
|
3831
3825
|
}
|
|
3832
3826
|
},
|
|
3833
|
-
/**
|
|
3834
|
-
* LLM-generated overview (summary + guided-tour phases), content-hash cached
|
|
3835
|
-
* and served stale-while-revalidating; poll while `status` is "generating".
|
|
3836
|
-
*/
|
|
3837
|
-
async getOverview(workflowId) {
|
|
3838
|
-
try {
|
|
3839
|
-
const data = await http.get(`api/workflows/${encodeURIComponent(workflowId)}/overview`).json();
|
|
3840
|
-
return WorkspaceWorkflowOverviewSchema.parse(data);
|
|
3841
|
-
} catch (error) {
|
|
3842
|
-
throw await toPlatformError(error);
|
|
3843
|
-
}
|
|
3844
|
-
},
|
|
3845
|
-
/**
|
|
3846
|
-
* The workflow source file from the active deploy source snapshot. Takes the
|
|
3847
|
-
* workflow's `projectId`/`slug`/`sourcePath` (already on `WorkflowSummary`) so
|
|
3848
|
-
* it resolves the file in two calls (project files + content) instead of
|
|
3849
|
-
* re-fetching the workflow detail the caller already holds.
|
|
3850
|
-
*/
|
|
3851
|
-
async getFile(input) {
|
|
3852
|
-
try {
|
|
3853
|
-
const filesData = await http.get(`api/projects/${encodeURIComponent(input.projectId)}/files`).json();
|
|
3854
|
-
const files = ListProjectFilesResponseSchema.parse(filesData);
|
|
3855
|
-
if (!files.artifactId) return null;
|
|
3856
|
-
const path = files.resources.workflows.find((entry) => entry.slug === input.slug)?.path ?? input.sourcePath;
|
|
3857
|
-
if (!path) return null;
|
|
3858
|
-
return {
|
|
3859
|
-
path,
|
|
3860
|
-
contents: await http.get(`api/projects/${encodeURIComponent(input.projectId)}/artifacts/${encodeURIComponent(files.artifactId)}/files/content`, { searchParams: { path } }).text()
|
|
3861
|
-
};
|
|
3862
|
-
} catch (error) {
|
|
3863
|
-
throw await toPlatformError(error);
|
|
3864
|
-
}
|
|
3865
|
-
},
|
|
3866
|
-
/**
|
|
3867
|
-
* Read-only canvas graph (deterministic AST skeleton + manifest trigger
|
|
3868
|
-
* nodes) plus the gated code-block annotation layer. Returns null when the
|
|
3869
|
-
* active deploy has no flow graph for the workflow (404).
|
|
3870
|
-
*/
|
|
3871
|
-
async getCanvas(workflowId) {
|
|
3872
|
-
try {
|
|
3873
|
-
const response = await http.get(`api/workflows/${encodeURIComponent(workflowId)}/canvas`);
|
|
3874
|
-
if (response.status === 404) return null;
|
|
3875
|
-
return WorkflowCanvasSchema.parse(await response.json());
|
|
3876
|
-
} catch (error) {
|
|
3877
|
-
throw await toPlatformError(error);
|
|
3878
|
-
}
|
|
3879
|
-
},
|
|
3880
|
-
/**
|
|
3881
|
-
* Live credential overlay: canvas node id → how each of its step's credential
|
|
3882
|
-
* requirements currently resolves (bound instance + policy). Resolved per view
|
|
3883
|
-
* (not cached) since credential state changes without a redeploy.
|
|
3884
|
-
*/
|
|
3885
|
-
async getCanvasCredentialBindings(workflowId) {
|
|
3886
|
-
try {
|
|
3887
|
-
const data = await http.get(`api/workflows/${encodeURIComponent(workflowId)}/canvas/credentials`).json();
|
|
3888
|
-
return WorkflowCanvasCredentialBindingsSchema.parse(data);
|
|
3889
|
-
} catch (error) {
|
|
3890
|
-
throw await toPlatformError(error);
|
|
3891
|
-
}
|
|
3892
|
-
},
|
|
3893
|
-
/** Per-node run state for a finished/live run, projected onto the canvas skeleton. */
|
|
3894
|
-
async getCanvasRun(workflowId, runId) {
|
|
3895
|
-
try {
|
|
3896
|
-
const response = await http.get(`api/workflows/${encodeURIComponent(workflowId)}/canvas/runs/${encodeURIComponent(runId)}`);
|
|
3897
|
-
if (response.status === 404) return null;
|
|
3898
|
-
return WorkflowCanvasRunSchema.parse(await response.json());
|
|
3899
|
-
} catch (error) {
|
|
3900
|
-
throw await toPlatformError(error);
|
|
3901
|
-
}
|
|
3902
|
-
},
|
|
3903
|
-
async listCanvasRuns(workflowId) {
|
|
3904
|
-
try {
|
|
3905
|
-
const data = await http.get(`api/workflows/${encodeURIComponent(workflowId)}/runs`).json();
|
|
3906
|
-
return HistoryRunListResponseSchema.parse(data);
|
|
3907
|
-
} catch (error) {
|
|
3908
|
-
throw await toPlatformError(error);
|
|
3909
|
-
}
|
|
3910
|
-
},
|
|
3911
|
-
async getRunInputs(workflowId) {
|
|
3912
|
-
try {
|
|
3913
|
-
const data = await http.get(`api/workflows/${encodeURIComponent(workflowId)}/run-inputs`).json();
|
|
3914
|
-
return WorkflowRunInputsSchema.parse(data);
|
|
3915
|
-
} catch (error) {
|
|
3916
|
-
throw await toPlatformError(error);
|
|
3917
|
-
}
|
|
3918
|
-
},
|
|
3919
|
-
async saveRunInputs(workflowId, values) {
|
|
3920
|
-
try {
|
|
3921
|
-
const body = WorkflowRunInputsPutBodySchema.parse(values);
|
|
3922
|
-
const data = await http.put(`api/workflows/${encodeURIComponent(workflowId)}/run-inputs`, { json: body }).json();
|
|
3923
|
-
return WorkflowRunInputsSchema.parse(data);
|
|
3924
|
-
} catch (error) {
|
|
3925
|
-
throw await toPlatformError(error);
|
|
3926
|
-
}
|
|
3927
|
-
},
|
|
3928
|
-
/**
|
|
3929
|
-
* Manually start a workflow run from the dashboard. Validates the input
|
|
3930
|
-
* against the active deploy's request schema, enqueues the run, and returns
|
|
3931
|
-
* its id (surface the new run by refetching {@link listCanvasRuns}).
|
|
3932
|
-
*/
|
|
3933
|
-
async run(workflowId, input = {}) {
|
|
3934
|
-
try {
|
|
3935
|
-
const data = await http.post(`api/workflows/${encodeURIComponent(workflowId)}/run`, { json: input }).json();
|
|
3936
|
-
return WorkflowRunResponseSchema.parse(data);
|
|
3937
|
-
} catch (error) {
|
|
3938
|
-
throw await toPlatformError(error);
|
|
3939
|
-
}
|
|
3940
|
-
},
|
|
3941
3827
|
async cancelRun(runId) {
|
|
3942
3828
|
try {
|
|
3943
3829
|
const response = await http.post(`api/workflows/runs/${encodeURIComponent(runId)}/cancel`);
|
|
@@ -4227,16 +4113,6 @@ function createAppsResource(http) {
|
|
|
4227
4113
|
throw await toPlatformError(error);
|
|
4228
4114
|
}
|
|
4229
4115
|
},
|
|
4230
|
-
async executeTool(request) {
|
|
4231
|
-
try {
|
|
4232
|
-
const body = ExecuteKeystrokeToolRequestSchema.parse(request);
|
|
4233
|
-
const data = await http.post("/mcp/execute", { json: body }).json();
|
|
4234
|
-
if (typeof data !== "object" || data === null || !("ok" in data) || data.ok !== true || !("result" in data)) throw new PlatformError("Invalid MCP execute response", 502, data);
|
|
4235
|
-
return data;
|
|
4236
|
-
} catch (error) {
|
|
4237
|
-
throw await toPlatformError(error);
|
|
4238
|
-
}
|
|
4239
|
-
},
|
|
4240
4116
|
async checkSlug(slug) {
|
|
4241
4117
|
try {
|
|
4242
4118
|
const searchParams = new URLSearchParams({ slug });
|
|
@@ -4809,7 +4685,7 @@ async function resolveProjectRef(platform, ref) {
|
|
|
4809
4685
|
if (looksLikeUuid(ref)) try {
|
|
4810
4686
|
return await platform.projects.get(ref);
|
|
4811
4687
|
} catch (error) {
|
|
4812
|
-
if (error instanceof PlatformError && error.status === 404) throw new Error(`Project ${ref} not found in the active organization. Run \`keystroke project list\`, then \`keystroke
|
|
4688
|
+
if (error instanceof PlatformError && error.status === 404) throw new Error(`Project ${ref} not found in the active organization. Run \`keystroke project list\`, then \`keystroke config use project <slug>\`.`);
|
|
4813
4689
|
throw error;
|
|
4814
4690
|
}
|
|
4815
4691
|
const match = (await platform.projects.list()).find((project) => project.slug === ref);
|
|
@@ -4971,78 +4847,6 @@ function readDevSession(configDir = getCliConfigDir()) {
|
|
|
4971
4847
|
}
|
|
4972
4848
|
}
|
|
4973
4849
|
//#endregion
|
|
4974
|
-
//#region src/project/resolve-keystroke-config-root.ts
|
|
4975
|
-
const KEYSTROKE_CONFIG$2 = "keystroke.config.ts";
|
|
4976
|
-
/** Walk up from `fromDir` and return the directory containing `keystroke.config.ts`, if any. */
|
|
4977
|
-
function resolveKeystrokeConfigRoot(fromDir = process.cwd()) {
|
|
4978
|
-
let dir = resolve(fromDir);
|
|
4979
|
-
while (dir !== dirname(dir)) {
|
|
4980
|
-
if (existsSync(join(dir, KEYSTROKE_CONFIG$2))) return dir;
|
|
4981
|
-
dir = dirname(dir);
|
|
4982
|
-
}
|
|
4983
|
-
if (existsSync(join(dir, KEYSTROKE_CONFIG$2))) return dir;
|
|
4984
|
-
return null;
|
|
4985
|
-
}
|
|
4986
|
-
//#endregion
|
|
4987
|
-
//#region src/project/read-project-config.ts
|
|
4988
|
-
const KEYSTROKE_CONFIG$1 = "keystroke.config.ts";
|
|
4989
|
-
/** Remove line and block comments before scanning config literals. */
|
|
4990
|
-
function stripConfigComments(source) {
|
|
4991
|
-
return source.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
4992
|
-
}
|
|
4993
|
-
/** Mask comments while preserving string length so match indices stay aligned. */
|
|
4994
|
-
function stripConfigCommentsPreservingLength(source) {
|
|
4995
|
-
return source.replace(/\/\/[^\n]*/g, (match) => " ".repeat(match.length)).replace(/\/\*[\s\S]*?\*\//g, (match) => " ".repeat(match.length));
|
|
4996
|
-
}
|
|
4997
|
-
function readStringLiteral(source, key) {
|
|
4998
|
-
const stripped = stripConfigComments(source);
|
|
4999
|
-
const pattern = new RegExp(`\\b${key}\\s*:\\s*(['"])([^'"]*)\\1`);
|
|
5000
|
-
return stripped.match(pattern)?.[2]?.trim() || void 0;
|
|
5001
|
-
}
|
|
5002
|
-
function parseLinkedProjectConfig(source) {
|
|
5003
|
-
const project = readStringLiteral(source, "project");
|
|
5004
|
-
const organization = readStringLiteral(source, "organization");
|
|
5005
|
-
return {
|
|
5006
|
-
...project ? { project } : {},
|
|
5007
|
-
...organization ? { organization } : {}
|
|
5008
|
-
};
|
|
5009
|
-
}
|
|
5010
|
-
/** Read optional project/organization slugs from keystroke.config.ts without executing it. */
|
|
5011
|
-
function readLinkedProjectConfig(fromDir = process.cwd()) {
|
|
5012
|
-
const root = resolveKeystrokeConfigRoot(fromDir);
|
|
5013
|
-
if (!root) return {};
|
|
5014
|
-
return parseLinkedProjectConfig(readFileSync(join(root, KEYSTROKE_CONFIG$1), "utf8"));
|
|
5015
|
-
}
|
|
5016
|
-
//#endregion
|
|
5017
|
-
//#region src/target-options.ts
|
|
5018
|
-
let targetOptions = {};
|
|
5019
|
-
function setCliTargetOptions(options) {
|
|
5020
|
-
targetOptions = options;
|
|
5021
|
-
}
|
|
5022
|
-
function getCliTargetOptions() {
|
|
5023
|
-
return targetOptions;
|
|
5024
|
-
}
|
|
5025
|
-
//#endregion
|
|
5026
|
-
//#region src/resolve-project-target.ts
|
|
5027
|
-
function resolveLinkedProjectRef(fromDir = process.cwd()) {
|
|
5028
|
-
return readLinkedProjectConfig(fromDir).project;
|
|
5029
|
-
}
|
|
5030
|
-
/** Activate the organization slug from keystroke.config.ts when present. */
|
|
5031
|
-
async function ensureLinkedOrganization(config, fromDir = process.cwd()) {
|
|
5032
|
-
const linked = readLinkedProjectConfig(fromDir);
|
|
5033
|
-
if (!linked.organization) return;
|
|
5034
|
-
await activateOrganization(config, resolveOrganizationRef(await listOrganizations(config), linked.organization).organization.id);
|
|
5035
|
-
}
|
|
5036
|
-
async function resolveActiveProject(config, platform, fromDir = process.cwd()) {
|
|
5037
|
-
const ref = getCliTargetOptions().projectId ?? readLinkedProjectConfig(fromDir).project;
|
|
5038
|
-
if (!ref) return;
|
|
5039
|
-
await ensureLinkedOrganization(config, fromDir);
|
|
5040
|
-
return resolveProjectRef(platform ?? createCliPlatformClient(config), ref);
|
|
5041
|
-
}
|
|
5042
|
-
async function resolveActiveProjectId(config, fromDir = process.cwd()) {
|
|
5043
|
-
return (await resolveActiveProject(config, void 0, fromDir))?.id;
|
|
5044
|
-
}
|
|
5045
|
-
//#endregion
|
|
5046
4850
|
//#region src/resolve-api-target.ts
|
|
5047
4851
|
/** Standalone local server default project id — keep in sync with @keystrokehq/database. */
|
|
5048
4852
|
const DEFAULT_LOCAL_PROJECT_ID = "default";
|
|
@@ -5075,7 +4879,6 @@ function resolveOrgPlatformTarget(config) {
|
|
|
5075
4879
|
};
|
|
5076
4880
|
}
|
|
5077
4881
|
async function resolvePlatformTarget(config, projectRef) {
|
|
5078
|
-
await ensureLinkedOrganization(config);
|
|
5079
4882
|
const platform = createCliPlatformClient(config);
|
|
5080
4883
|
let project;
|
|
5081
4884
|
try {
|
|
@@ -5103,11 +4906,20 @@ async function resolveApiTarget(config, options = {}) {
|
|
|
5103
4906
|
if (options.projectId) return resolvePlatformTarget(config, options.projectId);
|
|
5104
4907
|
if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
|
|
5105
4908
|
if (!options.projectScoped) return resolveOrgPlatformTarget(config);
|
|
5106
|
-
const projectRef = options.projectId ??
|
|
5107
|
-
if (!projectRef) throw new Error("No project selected. Pass `--project <slug>` or run `keystroke
|
|
4909
|
+
const projectRef = options.projectId ?? config.get("activeProjectId");
|
|
4910
|
+
if (!projectRef) throw new Error("No project selected. Pass `--project <slug>` or run `keystroke config use project <slug>`.");
|
|
5108
4911
|
return resolvePlatformTarget(config, projectRef);
|
|
5109
4912
|
}
|
|
5110
4913
|
//#endregion
|
|
4914
|
+
//#region src/target-options.ts
|
|
4915
|
+
let targetOptions = {};
|
|
4916
|
+
function setCliTargetOptions(options) {
|
|
4917
|
+
targetOptions = options;
|
|
4918
|
+
}
|
|
4919
|
+
function getCliTargetOptions() {
|
|
4920
|
+
return targetOptions;
|
|
4921
|
+
}
|
|
4922
|
+
//#endregion
|
|
5111
4923
|
//#region src/errors/example-input.ts
|
|
5112
4924
|
function exampleValueFromValidationMessage(message) {
|
|
5113
4925
|
if (/expected number/i.test(message)) return 0;
|
|
@@ -5277,6 +5089,18 @@ async function requireAdminRole(config) {
|
|
|
5277
5089
|
if (!active || active.role !== "owner" && active.role !== "admin") throw new Error("--admin requires org owner or admin");
|
|
5278
5090
|
}
|
|
5279
5091
|
//#endregion
|
|
5092
|
+
//#region src/resolve-project-target.ts
|
|
5093
|
+
async function resolveActiveProject(config, platform) {
|
|
5094
|
+
const ref = getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
5095
|
+
if (!ref) return;
|
|
5096
|
+
const client = platform ?? createCliPlatformClient(config);
|
|
5097
|
+
if (!getCliTargetOptions().projectId && looksLikeUuid(ref)) return resolveProjectRef(client, ref);
|
|
5098
|
+
return resolveProjectRef(client, ref);
|
|
5099
|
+
}
|
|
5100
|
+
async function resolveActiveProjectId(config) {
|
|
5101
|
+
return (await resolveActiveProject(config))?.id;
|
|
5102
|
+
}
|
|
5103
|
+
//#endregion
|
|
5280
5104
|
//#region src/commands/agent/list.ts
|
|
5281
5105
|
function registerAgentListCommand(agent) {
|
|
5282
5106
|
agent.command("list").description("List agents in the active organization").option("--admin", "List all org resources (org owner or admin only)").action((options) => runCliCommand("List agents failed", async () => {
|
|
@@ -5305,8 +5129,7 @@ function registerAgentPromptCommand(agent) {
|
|
|
5305
5129
|
}
|
|
5306
5130
|
//#endregion
|
|
5307
5131
|
//#region src/commands/project/run-project.ts
|
|
5308
|
-
async function withActivePlatformClient(config, fn
|
|
5309
|
-
if (applyLinkedOrganization) await ensureLinkedOrganization(config, fromDir);
|
|
5132
|
+
async function withActivePlatformClient(config, fn) {
|
|
5310
5133
|
const platform = createCliPlatformClient(config);
|
|
5311
5134
|
let active = await platform.organizations.getActive();
|
|
5312
5135
|
if (!active) active = await selectActiveOrganization(config);
|
|
@@ -5317,7 +5140,7 @@ function writeInactiveDeployHints(projects) {
|
|
|
5317
5140
|
const bin = cliBinaryName();
|
|
5318
5141
|
for (const project of projects) {
|
|
5319
5142
|
if (project.status !== "inactive") continue;
|
|
5320
|
-
process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin}
|
|
5143
|
+
process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin} deploy --project ${formatProjectLabel(project)}\n`);
|
|
5321
5144
|
}
|
|
5322
5145
|
}
|
|
5323
5146
|
async function runProjectList(config, options = {}) {
|
|
@@ -5476,33 +5299,6 @@ function registerApiKeyCommand(program) {
|
|
|
5476
5299
|
});
|
|
5477
5300
|
}
|
|
5478
5301
|
//#endregion
|
|
5479
|
-
//#region src/commands/app/action-hints.ts
|
|
5480
|
-
function toCamelCase(value) {
|
|
5481
|
-
const pascal = value.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
5482
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
5483
|
-
}
|
|
5484
|
-
/** `github`, `GITHUB_CREATE_ISSUE` → `githubCreateIssue` (matches the generated action export). */
|
|
5485
|
-
function actionExportName(app, tool) {
|
|
5486
|
-
const toolkit = app.toLowerCase();
|
|
5487
|
-
const upperTool = tool.toUpperCase();
|
|
5488
|
-
const prefix = `${toolkit.toUpperCase()}_`;
|
|
5489
|
-
return toCamelCase(`${toolkit}-${upperTool.startsWith(prefix) ? upperTool.slice(prefix.length) : upperTool}`);
|
|
5490
|
-
}
|
|
5491
|
-
/** Best-effort code-import line for a catalog action. */
|
|
5492
|
-
function actionImportHint(app, tool) {
|
|
5493
|
-
return `import { ${actionExportName(app, tool)} } from "@keystrokehq/${app.toLowerCase()}/actions"`;
|
|
5494
|
-
}
|
|
5495
|
-
/** Next-step hint printed after listing an app's actions. */
|
|
5496
|
-
function listActionsHint(app) {
|
|
5497
|
-
const bin = cliBinaryName();
|
|
5498
|
-
return `\nNext steps:\n Inspect a tool: ${bin} app action ${app} <TOOL_SLUG>\n Run a tool: ${bin} app execute ${app} <TOOL_SLUG> --input '{...}'\n`;
|
|
5499
|
-
}
|
|
5500
|
-
/** Next-step hint printed after showing one action's schema. */
|
|
5501
|
-
function showActionHint(app, tool) {
|
|
5502
|
-
const bin = cliBinaryName();
|
|
5503
|
-
return `\nNext steps:\n Run ad-hoc: ${bin} app execute ${app} ${tool} --input '{...}'\n Use in code: ${actionImportHint(app, tool)}\n Not connected? ${bin} connect ${app}\n`;
|
|
5504
|
-
}
|
|
5505
|
-
//#endregion
|
|
5506
5302
|
//#region src/commands/app/run-app-catalog.ts
|
|
5507
5303
|
async function runAppSearch(client, query, options) {
|
|
5508
5304
|
const trimmed = query.trim();
|
|
@@ -5535,26 +5331,25 @@ async function runAppActions(client, options) {
|
|
|
5535
5331
|
});
|
|
5536
5332
|
}
|
|
5537
5333
|
async function runAppAction(client, toolSlug) {
|
|
5538
|
-
const trimmed = toolSlug.trim()
|
|
5334
|
+
const trimmed = toolSlug.trim();
|
|
5539
5335
|
if (!trimmed) throw new Error("Tool slug is required");
|
|
5540
5336
|
return client.apps.getCatalogAction(trimmed);
|
|
5541
5337
|
}
|
|
5542
5338
|
//#endregion
|
|
5543
5339
|
//#region src/commands/app/action.ts
|
|
5544
5340
|
function registerAppActionCommand(app) {
|
|
5545
|
-
app.command("action").description("Show a
|
|
5341
|
+
app.command("action").description("Show a Composio action schema from the live catalog").argument("<tool-slug>", "Composio tool slug (e.g. GITHUB_CREATE_ISSUE)").action((toolSlug) => runCliCommand("App action failed", async () => {
|
|
5546
5342
|
const config = createCliConfig();
|
|
5547
5343
|
const client = createCliPlatformClient(config);
|
|
5548
5344
|
await ensureActiveOrganization(config);
|
|
5549
5345
|
const result = await runAppAction(client, toolSlug);
|
|
5550
5346
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
5551
|
-
process.stderr.write(showActionHint(appSlug.trim().toLowerCase(), toolSlug.trim().toUpperCase()));
|
|
5552
5347
|
}, void 0, { orgScoped: true }));
|
|
5553
5348
|
}
|
|
5554
5349
|
//#endregion
|
|
5555
5350
|
//#region src/commands/app/actions.ts
|
|
5556
5351
|
function registerAppActionsCommand(app) {
|
|
5557
|
-
app.command("actions [slug]").description("List or search
|
|
5352
|
+
app.command("actions [slug]").description("List or search Composio actions (per app or globally with --search)").option("--search <query>", "Search actions within the app or across all apps").option("--limit <n>", "Page size", (value) => Number.parseInt(value, 10)).option("--cursor <cursor>", "Pagination cursor").action((slug, options) => runCliCommand("App actions failed", async () => {
|
|
5558
5353
|
const config = createCliConfig();
|
|
5559
5354
|
const client = createCliPlatformClient(config);
|
|
5560
5355
|
await ensureActiveOrganization(config);
|
|
@@ -5563,7 +5358,6 @@ function registerAppActionsCommand(app) {
|
|
|
5563
5358
|
...options
|
|
5564
5359
|
});
|
|
5565
5360
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
5566
|
-
if (slug?.trim()) process.stderr.write(listActionsHint(slug.trim().toLowerCase()));
|
|
5567
5361
|
}, void 0, { orgScoped: true }));
|
|
5568
5362
|
}
|
|
5569
5363
|
//#endregion
|
|
@@ -5712,68 +5506,6 @@ function registerAppCreateCommand(app) {
|
|
|
5712
5506
|
}, void 0, { orgScoped: true }));
|
|
5713
5507
|
}
|
|
5714
5508
|
//#endregion
|
|
5715
|
-
//#region src/commands/app/run-app-execute.ts
|
|
5716
|
-
function isNotConnectedError(error) {
|
|
5717
|
-
if (!(error instanceof PlatformError) || error.status !== 404) return false;
|
|
5718
|
-
const body = error.body;
|
|
5719
|
-
if (typeof body !== "object" || body === null || !("error" in body)) return false;
|
|
5720
|
-
return body.error === "not_found";
|
|
5721
|
-
}
|
|
5722
|
-
async function runAppExecute(client, appSlug, toolSlug, options) {
|
|
5723
|
-
const app = appSlug.trim().toLowerCase();
|
|
5724
|
-
const tool = toolSlug.trim().toUpperCase();
|
|
5725
|
-
if (!app || !tool) throw new Error("App and tool slugs are required (e.g. github github_get_the_authenticated_user)");
|
|
5726
|
-
const credentialSlug = options.credentialSlug?.trim() || void 0;
|
|
5727
|
-
const projectSlug = options.projectSlug?.trim() || void 0;
|
|
5728
|
-
const version = options.version?.trim() || (await client.apps.getCatalogAction(tool)).version?.trim() || void 0;
|
|
5729
|
-
if (!version) throw new Error(`Catalog action "${tool}" has no pinned version. Pass --version explicitly.`);
|
|
5730
|
-
try {
|
|
5731
|
-
const { result } = await client.apps.executeTool({
|
|
5732
|
-
app,
|
|
5733
|
-
tool,
|
|
5734
|
-
version,
|
|
5735
|
-
arguments: typeof options.input === "object" && options.input !== null && !Array.isArray(options.input) ? options.input : {},
|
|
5736
|
-
...credentialSlug ? { credentialSlug } : {},
|
|
5737
|
-
...projectSlug ? { projectSlug } : {}
|
|
5738
|
-
});
|
|
5739
|
-
return result;
|
|
5740
|
-
} catch (error) {
|
|
5741
|
-
if (isNotConnectedError(error) && !credentialSlug) throw new Error(`Not connected to ${app}. Run: ${cliBinaryName()} connect ${app}`);
|
|
5742
|
-
throw error;
|
|
5743
|
-
}
|
|
5744
|
-
}
|
|
5745
|
-
//#endregion
|
|
5746
|
-
//#region src/commands/app/execute.ts
|
|
5747
|
-
function registerAppExecuteCommand(app) {
|
|
5748
|
-
app.command("execute").description("Run a connected catalog action against the cloud (no local server)").argument("<app>", "App slug (e.g. github)").argument("<tool>", "Tool slug (e.g. github_get_the_authenticated_user)").option("--input <json>", "JSON arguments (defaults to {})", "{}").option("--version <version>", "Pinned toolkit version (defaults to the catalog value)").option("--credential <slug>", `Pin a specific credential by slug (see '${cliBinaryName()} credentials list'); overrides the default and is the only way to use a user credential`).addHelpText("after", `
|
|
5749
|
-
Credential resolution matches the runtime: project default → org default. User credentials are
|
|
5750
|
-
never a default — reach one with --credential <slug>. Target a project with the global
|
|
5751
|
-
--project <slug> flag; without it, only org credentials resolve.
|
|
5752
|
-
|
|
5753
|
-
Examples:
|
|
5754
|
-
${cliBinaryName()} app execute github github_get_the_authenticated_user
|
|
5755
|
-
${cliBinaryName()} app execute github github_get_the_authenticated_user --project my-app
|
|
5756
|
-
${cliBinaryName()} app execute github github_get_the_authenticated_user --credential work-github
|
|
5757
|
-
${cliBinaryName()} app execute acculynx acculynx_add_job_appointment --input '{"jobId":"123","startDate":"2026-01-01T09:00:00Z","endDate":"2026-01-01T10:00:00Z"}'
|
|
5758
|
-
`).action((appSlug, toolSlug, options) => runCliCommand("App execute failed", async () => {
|
|
5759
|
-
const config = createCliConfig();
|
|
5760
|
-
const client = createCliPlatformClient(config);
|
|
5761
|
-
await ensureActiveOrganization(config);
|
|
5762
|
-
const input = parseJsonOption(options.input, "--input");
|
|
5763
|
-
const project = await resolveActiveProject(config, client);
|
|
5764
|
-
const result = await runAppExecute(client, appSlug, toolSlug, {
|
|
5765
|
-
input,
|
|
5766
|
-
version: options.version,
|
|
5767
|
-
credentialSlug: options.credential,
|
|
5768
|
-
projectSlug: project?.slug
|
|
5769
|
-
});
|
|
5770
|
-
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
5771
|
-
}, { usage: {
|
|
5772
|
-
command: `${cliBinaryName()} app execute ${appSlug} ${toolSlug}`,
|
|
5773
|
-
flag: "--input"
|
|
5774
|
-
} }, { orgScoped: true }));
|
|
5775
|
-
}
|
|
5776
|
-
//#endregion
|
|
5777
5509
|
//#region src/commands/app/run-app-list.ts
|
|
5778
5510
|
async function runAppList(client) {
|
|
5779
5511
|
return client.apps.listCatalog();
|
|
@@ -5812,6 +5544,19 @@ function registerAppShowCommand(app) {
|
|
|
5812
5544
|
}, void 0, { orgScoped: true }));
|
|
5813
5545
|
}
|
|
5814
5546
|
//#endregion
|
|
5547
|
+
//#region src/project/resolve-keystroke-config-root.ts
|
|
5548
|
+
const KEYSTROKE_CONFIG = "keystroke.config.ts";
|
|
5549
|
+
/** Walk up from `fromDir` and return the directory containing `keystroke.config.ts`, if any. */
|
|
5550
|
+
function resolveKeystrokeConfigRoot(fromDir = process.cwd()) {
|
|
5551
|
+
let dir = resolve(fromDir);
|
|
5552
|
+
while (dir !== dirname(dir)) {
|
|
5553
|
+
if (existsSync(join(dir, KEYSTROKE_CONFIG))) return dir;
|
|
5554
|
+
dir = dirname(dir);
|
|
5555
|
+
}
|
|
5556
|
+
if (existsSync(join(dir, KEYSTROKE_CONFIG))) return dir;
|
|
5557
|
+
return null;
|
|
5558
|
+
}
|
|
5559
|
+
//#endregion
|
|
5815
5560
|
//#region src/commands/app/generate-app-stub.ts
|
|
5816
5561
|
function slugPartToExportName(part) {
|
|
5817
5562
|
return part.split(/[-_]+/).filter(Boolean).map((segment, index) => index === 0 ? segment.charAt(0).toLowerCase() + segment.slice(1) : segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
|
|
@@ -5874,13 +5619,12 @@ function registerAppSyncCommand(app) {
|
|
|
5874
5619
|
//#endregion
|
|
5875
5620
|
//#region src/commands/app/index.ts
|
|
5876
5621
|
function registerAppCommand(program) {
|
|
5877
|
-
const app = program.command("app").description("
|
|
5622
|
+
const app = program.command("app").description("Browse connectable integrations");
|
|
5878
5623
|
registerAppListCommand(app);
|
|
5879
5624
|
registerAppSearchCommand(app);
|
|
5880
5625
|
registerAppShowCommand(app);
|
|
5881
5626
|
registerAppActionsCommand(app);
|
|
5882
5627
|
registerAppActionCommand(app);
|
|
5883
|
-
registerAppExecuteCommand(app);
|
|
5884
5628
|
registerAppCreateCommand(app);
|
|
5885
5629
|
registerAppSyncCommand(app);
|
|
5886
5630
|
}
|
|
@@ -6479,11 +6223,12 @@ function registerBuildCommand(program) {
|
|
|
6479
6223
|
program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
|
|
6480
6224
|
try {
|
|
6481
6225
|
const root = resolveProjectRoot(options.dir);
|
|
6482
|
-
const { buildApp } = await import("./dist-
|
|
6226
|
+
const { buildApp } = await import("./dist-DGKF3FGu.mjs");
|
|
6483
6227
|
await buildApp({ root });
|
|
6484
6228
|
process.stdout.write(`Built ${root}\n`);
|
|
6485
6229
|
} catch (error) {
|
|
6486
|
-
|
|
6230
|
+
const message = error instanceof Error ? error.message : "Build failed";
|
|
6231
|
+
process.stderr.write(`${message}\n`);
|
|
6487
6232
|
process.exitCode = 1;
|
|
6488
6233
|
}
|
|
6489
6234
|
});
|
|
@@ -6532,7 +6277,7 @@ async function sleep(ms) {
|
|
|
6532
6277
|
}
|
|
6533
6278
|
async function buildDeployArchive(client, root, projectId, filter) {
|
|
6534
6279
|
if (filter?.length) {
|
|
6535
|
-
const { buildFilteredApp } = await import("./dist-
|
|
6280
|
+
const { buildFilteredApp } = await import("./dist-DGKF3FGu.mjs");
|
|
6536
6281
|
const filtered = await buildFilteredApp({
|
|
6537
6282
|
root,
|
|
6538
6283
|
filter,
|
|
@@ -6554,7 +6299,7 @@ async function buildDeployArchive(client, root, projectId, filter) {
|
|
|
6554
6299
|
sourceFiles: filtered.sourceFiles
|
|
6555
6300
|
};
|
|
6556
6301
|
}
|
|
6557
|
-
const { buildApp } = await import("./dist-
|
|
6302
|
+
const { buildApp } = await import("./dist-DGKF3FGu.mjs");
|
|
6558
6303
|
const { sourceFiles } = await buildApp({
|
|
6559
6304
|
root,
|
|
6560
6305
|
collectSources: true,
|
|
@@ -6570,7 +6315,6 @@ async function runDeploy(options) {
|
|
|
6570
6315
|
const root = resolveProjectRoot(options.dir);
|
|
6571
6316
|
const config = createCliConfig();
|
|
6572
6317
|
const client = createCliPlatformClient(config);
|
|
6573
|
-
await ensureLinkedOrganization(config, root);
|
|
6574
6318
|
let active = await client.organizations.getActive();
|
|
6575
6319
|
if (!active) active = await selectActiveOrganization(config);
|
|
6576
6320
|
client.setActiveOrganizationId(active.organization.id);
|
|
@@ -6595,6 +6339,7 @@ async function runDeploy(options) {
|
|
|
6595
6339
|
while (Date.now() < deadline) {
|
|
6596
6340
|
const current = await client.projects.get(project.id);
|
|
6597
6341
|
if (current.status === "active") {
|
|
6342
|
+
config.set("activeProjectId", project.id);
|
|
6598
6343
|
config.set("apiTarget", "platform");
|
|
6599
6344
|
process.stdout.write(`Project active${current.baseUrl ? `: ${current.baseUrl}` : ""}\n`);
|
|
6600
6345
|
return;
|
|
@@ -6606,20 +6351,17 @@ async function runDeploy(options) {
|
|
|
6606
6351
|
}
|
|
6607
6352
|
function registerDeployCommand(program) {
|
|
6608
6353
|
program.command("deploy").description("Build, upload, and deploy the project to the platform").option("--dir <path>", "Project directory", process.cwd()).option("--filter <entry>", "Build and deploy only matching module entry keys (repeatable)", (value, previous) => [...previous, value], []).action(async (options) => {
|
|
6609
|
-
let config;
|
|
6610
6354
|
try {
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
const projectId = await resolveActiveProjectId(config, root);
|
|
6614
|
-
if (!projectId) throw new Error("Usage: keystroke deploy --project <slug> (or run `keystroke project link --project <slug>`)");
|
|
6355
|
+
const projectId = await resolveActiveProjectId(createCliConfig());
|
|
6356
|
+
if (!projectId) throw new Error("Usage: keystroke deploy --project <slug>");
|
|
6615
6357
|
await runDeploy({
|
|
6616
6358
|
dir: options.dir,
|
|
6617
6359
|
projectId,
|
|
6618
6360
|
filter: options.filter.length > 0 ? options.filter : void 0
|
|
6619
6361
|
});
|
|
6620
6362
|
} catch (error) {
|
|
6621
|
-
const message =
|
|
6622
|
-
process.stderr.write(
|
|
6363
|
+
const message = error instanceof Error ? error.message : "Deploy failed";
|
|
6364
|
+
process.stderr.write(`${message}\n`);
|
|
6623
6365
|
process.exitCode = 1;
|
|
6624
6366
|
}
|
|
6625
6367
|
});
|
|
@@ -6676,7 +6418,7 @@ function runtimeChildEnv(parentEnv, overrides) {
|
|
|
6676
6418
|
//#region src/project/bootstrap-run.ts
|
|
6677
6419
|
/** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
|
|
6678
6420
|
async function resolveBootstrapRun(options) {
|
|
6679
|
-
const { resolveRuntimeBuildArtifact } = await import("./dist-
|
|
6421
|
+
const { resolveRuntimeBuildArtifact } = await import("./dist-DGKF3FGu.mjs");
|
|
6680
6422
|
const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
|
|
6681
6423
|
const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/standalone-bootstrap.mjs");
|
|
6682
6424
|
const args = [`--import=${loader}`];
|
|
@@ -6825,7 +6567,7 @@ async function runDev(options) {
|
|
|
6825
6567
|
process.on("SIGINT", shutdown);
|
|
6826
6568
|
process.on("SIGTERM", shutdown);
|
|
6827
6569
|
try {
|
|
6828
|
-
const { watchApp } = await import("./dist-
|
|
6570
|
+
const { watchApp } = await import("./dist-DGKF3FGu.mjs");
|
|
6829
6571
|
await watchApp({
|
|
6830
6572
|
root,
|
|
6831
6573
|
clean: false,
|
|
@@ -7032,7 +6774,7 @@ const INIT_CATALOG_VERSIONS = {
|
|
|
7032
6774
|
vitest: "^4.1.7",
|
|
7033
6775
|
"@types/node": "^25.9.1"
|
|
7034
6776
|
};
|
|
7035
|
-
const INIT_KEYSTROKE_VERSION = "^0.1.
|
|
6777
|
+
const INIT_KEYSTROKE_VERSION = "^0.1.20";
|
|
7036
6778
|
//#endregion
|
|
7037
6779
|
//#region src/init/copy-template.ts
|
|
7038
6780
|
function renderTemplate(content, variables) {
|
|
@@ -7122,31 +6864,6 @@ async function applyPlaygroundManifest(targetDir, projectName, monorepoRoot) {
|
|
|
7122
6864
|
await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
|
|
7123
6865
|
}
|
|
7124
6866
|
//#endregion
|
|
7125
|
-
//#region src/skills/agents-guide-version.ts
|
|
7126
|
-
const VERSION_MARKER_RE = /<!-- keystroke-agents-guide: (.+?) -->/;
|
|
7127
|
-
function agentsGuideDir(projectRoot) {
|
|
7128
|
-
return join(projectRoot, ".agents");
|
|
7129
|
-
}
|
|
7130
|
-
function agentsMdPath(projectRoot) {
|
|
7131
|
-
return join(projectRoot, "AGENTS.md");
|
|
7132
|
-
}
|
|
7133
|
-
/**
|
|
7134
|
-
* Append the CLI version as a trailing HTML comment so auto-sync can detect
|
|
7135
|
-
* staleness without writing a sidecar `.agents/` directory. The marker is
|
|
7136
|
-
* invisible in rendered markdown and re-stamped (not stacked) on each write.
|
|
7137
|
-
*/
|
|
7138
|
-
function stampAgentsGuideVersion(content, version = readCliVersion()) {
|
|
7139
|
-
const stripped = content.replace(/\n*<!-- keystroke-agents-guide: .+? -->\n*$/, "\n");
|
|
7140
|
-
return `${stripped.endsWith("\n") ? stripped : `${stripped}\n`}\n<!-- keystroke-agents-guide: ${version} -->\n`;
|
|
7141
|
-
}
|
|
7142
|
-
async function readBundleVersion(projectRoot) {
|
|
7143
|
-
try {
|
|
7144
|
-
return (await readFile(agentsMdPath(projectRoot), "utf8")).match(VERSION_MARKER_RE)?.[1]?.trim() ?? null;
|
|
7145
|
-
} catch {
|
|
7146
|
-
return null;
|
|
7147
|
-
}
|
|
7148
|
-
}
|
|
7149
|
-
//#endregion
|
|
7150
6867
|
//#region src/skills/resolve-skills-bundle-dir.ts
|
|
7151
6868
|
const SKILLS_BUNDLE = "skills-bundle";
|
|
7152
6869
|
function resolveSkillsBundleDir(fromModuleUrl = import.meta.url) {
|
|
@@ -7158,58 +6875,53 @@ function resolveSkillsBundleDir(fromModuleUrl = import.meta.url) {
|
|
|
7158
6875
|
join(cliRoot, SKILLS_BUNDLE)
|
|
7159
6876
|
];
|
|
7160
6877
|
for (const candidate of candidates) if (existsSync(join(candidate, "_AGENTS.md"))) return candidate;
|
|
7161
|
-
throw new Error("Bundled
|
|
6878
|
+
throw new Error("Bundled keystroke skills not found — run `pnpm --filter @keystrokehq/cli build`");
|
|
7162
6879
|
}
|
|
7163
6880
|
//#endregion
|
|
7164
|
-
//#region src/skills/
|
|
7165
|
-
|
|
6881
|
+
//#region src/skills/sync-bundled-skills.ts
|
|
6882
|
+
const BUNDLE_VERSION_FILENAME = ".bundle-version";
|
|
6883
|
+
function agentsSkillsDir(projectRoot) {
|
|
6884
|
+
return join(projectRoot, ".agents", "skills");
|
|
6885
|
+
}
|
|
6886
|
+
function bundleVersionPath(projectRoot) {
|
|
6887
|
+
return join(agentsSkillsDir(projectRoot), BUNDLE_VERSION_FILENAME);
|
|
6888
|
+
}
|
|
6889
|
+
async function readBundleVersion(projectRoot) {
|
|
6890
|
+
try {
|
|
6891
|
+
return (await readFile(bundleVersionPath(projectRoot), "utf8")).trim();
|
|
6892
|
+
} catch {
|
|
6893
|
+
return null;
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
async function ensureSymlink(target, linkPath, kind) {
|
|
7166
6897
|
await mkdir(dirname(linkPath), { recursive: true });
|
|
7167
6898
|
await rm(linkPath, {
|
|
7168
6899
|
recursive: true,
|
|
7169
6900
|
force: true
|
|
7170
6901
|
});
|
|
7171
|
-
await symlink(target, linkPath, "
|
|
6902
|
+
await symlink(target, linkPath, platform() === "win32" && kind === "dir" ? "junction" : kind);
|
|
7172
6903
|
}
|
|
7173
|
-
/**
|
|
7174
|
-
async function
|
|
6904
|
+
/** Overwrites `.agents/skills/`, AGENTS.md, and recreates `.claude` symlinks from the CLI bundle. */
|
|
6905
|
+
async function syncBundledSkills(projectRoot, fromModuleUrl = import.meta.url) {
|
|
7175
6906
|
const bundleDir = resolveSkillsBundleDir(fromModuleUrl);
|
|
7176
|
-
const
|
|
7177
|
-
|
|
7178
|
-
await
|
|
7179
|
-
await
|
|
7180
|
-
}
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
if (
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
}
|
|
7195
|
-
if (value === void 0) return source;
|
|
7196
|
-
const defineConfigPattern = /defineConfig\(\{\s*\n?/;
|
|
7197
|
-
if (defineConfigPattern.test(source)) return source.replace(defineConfigPattern, `defineConfig({\n${entry}`);
|
|
7198
|
-
throw new Error(`Could not find defineConfig({ ... }) in ${KEYSTROKE_CONFIG}`);
|
|
7199
|
-
}
|
|
7200
|
-
function upsertLinkedProjectConfig(source, input) {
|
|
7201
|
-
let next = source;
|
|
7202
|
-
if (input.project !== void 0) next = upsertStringLiteral(next, "project", input.project);
|
|
7203
|
-
if (input.organization !== void 0) next = upsertStringLiteral(next, "organization", input.organization);
|
|
7204
|
-
return next;
|
|
7205
|
-
}
|
|
7206
|
-
/** Write project/organization slugs into keystroke.config.ts. */
|
|
7207
|
-
function writeLinkedProjectConfig(input, fromDir = process.cwd()) {
|
|
7208
|
-
const root = resolveKeystrokeConfigRoot(fromDir);
|
|
7209
|
-
if (!root) throw new Error(`No ${KEYSTROKE_CONFIG} found — run from a keystroke project directory`);
|
|
7210
|
-
const configPath = join(root, KEYSTROKE_CONFIG);
|
|
7211
|
-
writeFileSync(configPath, upsertLinkedProjectConfig(readFileSync(configPath, "utf8"), input));
|
|
7212
|
-
return configPath;
|
|
6907
|
+
const skillsDir = agentsSkillsDir(projectRoot);
|
|
6908
|
+
const agentsMdPath = join(projectRoot, "AGENTS.md");
|
|
6909
|
+
await mkdir(join(projectRoot, ".agents"), { recursive: true });
|
|
6910
|
+
if ((await lstat(skillsDir).catch(() => null))?.isSymbolicLink()) {
|
|
6911
|
+
await rm(skillsDir, { force: true });
|
|
6912
|
+
await cp(join(bundleDir, "skills"), skillsDir, { recursive: true });
|
|
6913
|
+
} else {
|
|
6914
|
+
await mkdir(skillsDir, { recursive: true });
|
|
6915
|
+
await cp(join(bundleDir, "skills"), skillsDir, {
|
|
6916
|
+
recursive: true,
|
|
6917
|
+
force: true
|
|
6918
|
+
});
|
|
6919
|
+
}
|
|
6920
|
+
if ((await lstat(agentsMdPath).catch(() => null))?.isSymbolicLink()) await rm(agentsMdPath, { force: true });
|
|
6921
|
+
await writeFile(agentsMdPath, await readFile(join(bundleDir, "_AGENTS.md"), "utf8"));
|
|
6922
|
+
await ensureSymlink(relative(dirname(join(projectRoot, ".claude", "skills")), skillsDir), join(projectRoot, ".claude", "skills"), "dir");
|
|
6923
|
+
await ensureSymlink(relative(dirname(join(projectRoot, "CLAUDE.md")), agentsMdPath), join(projectRoot, "CLAUDE.md"), "file");
|
|
6924
|
+
await writeFile(bundleVersionPath(projectRoot), `${readCliVersion()}\n`);
|
|
7213
6925
|
}
|
|
7214
6926
|
//#endregion
|
|
7215
6927
|
//#region src/init/scaffold-empty-src-dirs.ts
|
|
@@ -7310,11 +7022,8 @@ async function runInit(options) {
|
|
|
7310
7022
|
}
|
|
7311
7023
|
if (playgroundRoot) await applyPlaygroundManifest(targetDir, projectName, playgroundRoot);
|
|
7312
7024
|
else await scaffoldProjectDotfiles(targetDir);
|
|
7313
|
-
await
|
|
7314
|
-
|
|
7315
|
-
...options.project ? { project: options.project } : {},
|
|
7316
|
-
...options.organization ? { organization: options.organization } : {}
|
|
7317
|
-
}, targetDir);
|
|
7025
|
+
await syncBundledSkills(targetDir);
|
|
7026
|
+
await copyFile(join(targetDir, ".env.example"), join(targetDir, ".env"));
|
|
7318
7027
|
if (!options.skipInstall) if (playgroundRoot) {
|
|
7319
7028
|
installPlaygroundDependencies(targetDir);
|
|
7320
7029
|
buildPlaygroundWorkspace(playgroundRoot);
|
|
@@ -7327,7 +7036,7 @@ async function runInit(options) {
|
|
|
7327
7036
|
//#endregion
|
|
7328
7037
|
//#region src/commands/init.ts
|
|
7329
7038
|
function registerInitCommand(program) {
|
|
7330
|
-
program.command("init").description("Create a new keystroke project from a template").argument("[directory]", "Directory to create the project in").option("--name <name>", "Project name (kebab-case)").option("--template <name>", "Template to use", "hello-world").option("-y, --yes", "Skip prompts (headless mode for scripts and AI agents)").option("--skip-install", "Skip dependency installation").option("--pm <manager>", "Package manager: npm, pnpm, yarn, or bun").option("--no-example", "Scaffold without the example action, agent, and workflow").
|
|
7039
|
+
program.command("init").description("Create a new keystroke project from a template").argument("[directory]", "Directory to create the project in").option("--name <name>", "Project name (kebab-case)").option("--template <name>", "Template to use", "hello-world").option("-y, --yes", "Skip prompts (headless mode for scripts and AI agents)").option("--skip-install", "Skip dependency installation").option("--pm <manager>", "Package manager: npm, pnpm, yarn, or bun").option("--no-example", "Scaffold without the example action, agent, and workflow").action(async (directory, options) => {
|
|
7331
7040
|
try {
|
|
7332
7041
|
const result = await runInit({
|
|
7333
7042
|
directory,
|
|
@@ -7337,16 +7046,14 @@ function registerInitCommand(program) {
|
|
|
7337
7046
|
skipInstall: options.skipInstall,
|
|
7338
7047
|
packageManager: options.pm,
|
|
7339
7048
|
noExample: options.example === false,
|
|
7340
|
-
project: options.project,
|
|
7341
|
-
organization: options.organization,
|
|
7342
7049
|
version: readCliVersion()
|
|
7343
7050
|
});
|
|
7344
7051
|
process.stdout.write(`Created keystroke project "${result.projectName}" at ${result.targetDir}\n`);
|
|
7345
7052
|
process.stdout.write("\nNext steps:\n");
|
|
7346
7053
|
process.stdout.write(` cd ${result.targetDir}\n`);
|
|
7347
7054
|
process.stdout.write(" keystroke auth login # once\n");
|
|
7348
|
-
|
|
7349
|
-
process.stdout.write(" keystroke deploy
|
|
7055
|
+
process.stdout.write(" keystroke project list # pick a project (or: project create)\n");
|
|
7056
|
+
process.stdout.write(" keystroke deploy --project <id> # build + ship src/ to the platform\n");
|
|
7350
7057
|
} catch (error) {
|
|
7351
7058
|
const message = error instanceof Error ? error.message : "Init failed";
|
|
7352
7059
|
process.stderr.write(`${message}\n`);
|
|
@@ -7355,6 +7062,15 @@ function registerInitCommand(program) {
|
|
|
7355
7062
|
});
|
|
7356
7063
|
}
|
|
7357
7064
|
//#endregion
|
|
7065
|
+
//#region src/active-project.ts
|
|
7066
|
+
function clearActiveProjectIfMatches(config, project) {
|
|
7067
|
+
const activeProjectId = config.get("activeProjectId");
|
|
7068
|
+
if (activeProjectId === project.id || activeProjectId === project.slug) config.delete("activeProjectId");
|
|
7069
|
+
}
|
|
7070
|
+
function clearActiveProject(config) {
|
|
7071
|
+
if (config.get("activeProjectId") !== void 0) config.delete("activeProjectId");
|
|
7072
|
+
}
|
|
7073
|
+
//#endregion
|
|
7358
7074
|
//#region src/commands/organization/run-organization.ts
|
|
7359
7075
|
async function runOrganizationUpdate(config, input) {
|
|
7360
7076
|
await withActivePlatformClient(config, async (platform) => {
|
|
@@ -7396,6 +7112,7 @@ async function runOrganizationLeave(config) {
|
|
|
7396
7112
|
await platform.members.removeOrganizationMember(user.id);
|
|
7397
7113
|
platform.setActiveOrganizationId(null);
|
|
7398
7114
|
config.delete("activeOrganizationId");
|
|
7115
|
+
clearActiveProject(config);
|
|
7399
7116
|
process.stdout.write(`${JSON.stringify({ left: user.id }, null, 2)}\n`);
|
|
7400
7117
|
});
|
|
7401
7118
|
}
|
|
@@ -7468,23 +7185,9 @@ function registerOrganizationCommand(program) {
|
|
|
7468
7185
|
});
|
|
7469
7186
|
}
|
|
7470
7187
|
//#endregion
|
|
7471
|
-
//#region src/commands/project/run-project-link.ts
|
|
7472
|
-
async function runProjectLink(config, projectRef, fromDir = process.cwd()) {
|
|
7473
|
-
await withActivePlatformClient(config, async (platform) => {
|
|
7474
|
-
const project = await resolveProjectRef(platform, projectRef);
|
|
7475
|
-
const membership = (await listOrganizations(config)).find((entry) => entry.organization.id === project.organizationId);
|
|
7476
|
-
if (!membership) throw new Error(`Organization for project ${formatProjectLabel(project)} was not found or you do not have access`);
|
|
7477
|
-
const configPath = writeLinkedProjectConfig({
|
|
7478
|
-
project: project.slug,
|
|
7479
|
-
organization: membership.organization.slug
|
|
7480
|
-
}, fromDir);
|
|
7481
|
-
process.stdout.write(`Linked ${configPath} to ${membership.organization.slug}/${formatProjectLabel(project)}\nDeploy with: ${cliBinaryName()} deploy\n`);
|
|
7482
|
-
}, fromDir, false);
|
|
7483
|
-
}
|
|
7484
|
-
//#endregion
|
|
7485
7188
|
//#region src/commands/project/run-project-members.ts
|
|
7486
7189
|
async function resolveMembersProject(platform, config, projectRef) {
|
|
7487
|
-
const ref = projectRef ?? getCliTargetOptions().projectId ??
|
|
7190
|
+
const ref = projectRef ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
7488
7191
|
if (!ref) throw new Error("Usage: keystroke --project <slug> project members <command>");
|
|
7489
7192
|
return resolveProjectRef(platform, ref);
|
|
7490
7193
|
}
|
|
@@ -7524,6 +7227,7 @@ async function runProjectMembersLeave(config, options) {
|
|
|
7524
7227
|
await withActivePlatformClient(config, async (platform) => {
|
|
7525
7228
|
const project = await resolveMembersProject(platform, config, options.projectRef);
|
|
7526
7229
|
await platform.members.leaveProject(project.id);
|
|
7230
|
+
clearActiveProjectIfMatches(config, project);
|
|
7527
7231
|
process.stdout.write(`${JSON.stringify({ left: project.id }, null, 2)}\n`);
|
|
7528
7232
|
});
|
|
7529
7233
|
}
|
|
@@ -7537,7 +7241,7 @@ function parseProjectRole$1(role) {
|
|
|
7537
7241
|
throw new Error("Role must be admin or builder");
|
|
7538
7242
|
}
|
|
7539
7243
|
function resolveProjectRefOption$1(config, optionsProject) {
|
|
7540
|
-
return optionsProject ?? getCliTargetOptions().projectId ??
|
|
7244
|
+
return optionsProject ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
7541
7245
|
}
|
|
7542
7246
|
function projectRefInput$1(config, optionsProject) {
|
|
7543
7247
|
const projectRef = resolveProjectRefOption$1(config, optionsProject);
|
|
@@ -7603,7 +7307,7 @@ function registerProjectMembersCommand(project) {
|
|
|
7603
7307
|
//#endregion
|
|
7604
7308
|
//#region src/commands/project/run-project-settings.ts
|
|
7605
7309
|
async function resolveSettingsProject(platform, config, projectRef) {
|
|
7606
|
-
const ref = projectRef ?? getCliTargetOptions().projectId ??
|
|
7310
|
+
const ref = projectRef ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
7607
7311
|
if (!ref) throw new Error("Usage: keystroke --project <slug> project settings <command>");
|
|
7608
7312
|
return resolveProjectRef(platform, ref);
|
|
7609
7313
|
}
|
|
@@ -7625,7 +7329,7 @@ async function runProjectSettingsUpdate(config, input) {
|
|
|
7625
7329
|
//#endregion
|
|
7626
7330
|
//#region src/commands/project/settings.ts
|
|
7627
7331
|
function resolveProjectRefOption(config, optionsProject) {
|
|
7628
|
-
return optionsProject ?? getCliTargetOptions().projectId ??
|
|
7332
|
+
return optionsProject ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
7629
7333
|
}
|
|
7630
7334
|
function projectRefInput(config, optionsProject) {
|
|
7631
7335
|
const projectRef = resolveProjectRefOption(config, optionsProject);
|
|
@@ -7688,12 +7392,11 @@ function registerProjectCommand(program) {
|
|
|
7688
7392
|
process.exitCode = 1;
|
|
7689
7393
|
}
|
|
7690
7394
|
});
|
|
7691
|
-
project.command("metrics").description("List rollup metrics for projects in the active organization").option("--admin", "List all org resources (org owner or admin only)").action(async (options) => {
|
|
7395
|
+
project.command("metrics").description("List rollup metrics for projects in the active organization").option("--project <slug>", "Return metrics for a single project").option("--admin", "List all org resources (org owner or admin only)").action(async (options) => {
|
|
7692
7396
|
const config = createCliConfig();
|
|
7693
7397
|
try {
|
|
7694
|
-
const projectRef = getCliTargetOptions().projectId;
|
|
7695
7398
|
await runProjectMetrics(config, {
|
|
7696
|
-
...
|
|
7399
|
+
...options.project ? { projectRef: options.project } : {},
|
|
7697
7400
|
...options.admin ? { admin: true } : {}
|
|
7698
7401
|
});
|
|
7699
7402
|
} catch (error) {
|
|
@@ -7707,8 +7410,8 @@ function registerProjectCommand(program) {
|
|
|
7707
7410
|
project.command("deployments").description("View deployment history for platform projects").command("list").description("List deployment history for a project").option("--project <slug>", "Project slug").action(async (options) => {
|
|
7708
7411
|
const config = createCliConfig();
|
|
7709
7412
|
try {
|
|
7710
|
-
const projectRef = options.project ?? getCliTargetOptions().projectId ??
|
|
7711
|
-
if (!projectRef) throw new Error("Usage: keystroke project deployments list --project <slug>
|
|
7413
|
+
const projectRef = options.project ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
7414
|
+
if (!projectRef) throw new Error("Usage: keystroke project deployments list --project <slug>");
|
|
7712
7415
|
await runProjectDeploymentsList(config, { projectRef });
|
|
7713
7416
|
} catch (error) {
|
|
7714
7417
|
process.stderr.write(`${formatCliError(error, "List deployments failed", {
|
|
@@ -7718,18 +7421,6 @@ function registerProjectCommand(program) {
|
|
|
7718
7421
|
process.exitCode = 1;
|
|
7719
7422
|
}
|
|
7720
7423
|
});
|
|
7721
|
-
project.command("link").description("Link this directory to a platform project in keystroke.config.ts").requiredOption("--project <slug>", "Platform project slug").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
|
|
7722
|
-
const config = createCliConfig();
|
|
7723
|
-
try {
|
|
7724
|
-
await runProjectLink(config, options.project, options.dir);
|
|
7725
|
-
} catch (error) {
|
|
7726
|
-
process.stderr.write(`${formatCliError(error, "Link project failed", {
|
|
7727
|
-
serverUrl: getPlatformUrl(config),
|
|
7728
|
-
webUrl: getWebUrl(config)
|
|
7729
|
-
})}\n`);
|
|
7730
|
-
process.exitCode = 1;
|
|
7731
|
-
}
|
|
7732
|
-
});
|
|
7733
7424
|
project.command("create").description("Create a platform project in the active organization").requiredOption("--name <name>", "Project name").option("--description <description>", "Project description").action(async (options) => {
|
|
7734
7425
|
const config = createCliConfig();
|
|
7735
7426
|
try {
|
|
@@ -7832,7 +7523,7 @@ async function runPull(options) {
|
|
|
7832
7523
|
}
|
|
7833
7524
|
await writeSourceTree(targetDir, source.files);
|
|
7834
7525
|
installDependencies(targetDir, detectProjectPackageManagerFromSnapshot(source.files));
|
|
7835
|
-
await
|
|
7526
|
+
await syncBundledSkills(targetDir);
|
|
7836
7527
|
await writePullState({
|
|
7837
7528
|
targetDir,
|
|
7838
7529
|
projectId: options.projectId,
|
|
@@ -7845,7 +7536,7 @@ async function runPull(options) {
|
|
|
7845
7536
|
function registerPullCommand(program) {
|
|
7846
7537
|
program.command("pull").description("Download the active deploy source snapshot into a local directory").option("--dir <path>", "Target directory", process.cwd()).option("--force", "Overwrite an existing local project tree").action(async (options) => runCliCommand("Pull failed", async () => {
|
|
7847
7538
|
const config = createCliConfig();
|
|
7848
|
-
const projectId = await resolveActiveProjectId(config
|
|
7539
|
+
const projectId = await resolveActiveProjectId(config);
|
|
7849
7540
|
if (!projectId) throw new Error("Usage: keystroke pull --project <slug>");
|
|
7850
7541
|
await runPull({
|
|
7851
7542
|
client: createCliPlatformClient(config),
|
|
@@ -7868,7 +7559,7 @@ async function runStart(options) {
|
|
|
7868
7559
|
const apiPort = Number(new URL(serverUrl).port || 80);
|
|
7869
7560
|
const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
|
|
7870
7561
|
ensureNativeDeps(runtimeNodeModules);
|
|
7871
|
-
const { buildApp } = await import("./dist-
|
|
7562
|
+
const { buildApp } = await import("./dist-DGKF3FGu.mjs");
|
|
7872
7563
|
await buildApp({
|
|
7873
7564
|
root,
|
|
7874
7565
|
clean: false
|
|
@@ -8137,10 +7828,9 @@ function registerChannelPlatformsCommand(channel) {
|
|
|
8137
7828
|
//#region src/commands/channel/resolve-channel-project.ts
|
|
8138
7829
|
async function resolveChannelProjectId(config, projectRef) {
|
|
8139
7830
|
const platform = createCliPlatformClient(config);
|
|
8140
|
-
await ensureLinkedOrganization(config);
|
|
8141
7831
|
await ensureActiveOrganization(config);
|
|
8142
|
-
const ref = projectRef?.trim() || getCliTargetOptions().projectId?.trim() ||
|
|
8143
|
-
if (!ref) throw new Error("Project is required. Pass --project <slug> or
|
|
7832
|
+
const ref = projectRef?.trim() || getCliTargetOptions().projectId?.trim() || config.get("activeProjectId")?.trim();
|
|
7833
|
+
if (!ref) throw new Error("Project is required. Pass --project <slug> or set an active project.");
|
|
8144
7834
|
return (await resolveProjectRef(platform, ref)).id;
|
|
8145
7835
|
}
|
|
8146
7836
|
//#endregion
|
|
@@ -8238,6 +7928,27 @@ function registerChannelCommand(program) {
|
|
|
8238
7928
|
registerChannelUpdateBindingCommand(channel);
|
|
8239
7929
|
}
|
|
8240
7930
|
//#endregion
|
|
7931
|
+
//#region src/commands/config/use-project.ts
|
|
7932
|
+
async function fetchProjectInOrg(config, projectRef) {
|
|
7933
|
+
return resolveProjectRef(createCliPlatformClient(config), projectRef);
|
|
7934
|
+
}
|
|
7935
|
+
function assertProjectReadyForConfig(project) {
|
|
7936
|
+
const label = formatProjectLabel(project);
|
|
7937
|
+
if (project.status === "failed") throw new Error(project.lastError ? `Project ${label} deploy failed: ${project.lastError}` : `Project ${label} deploy failed`);
|
|
7938
|
+
if (project.status === "starting") throw new Error(`Project ${label} is still starting. Wait for deploy to finish, then run \`keystroke config use project ${label}\`.`);
|
|
7939
|
+
}
|
|
7940
|
+
async function runConfigUseProject(config, projectRef) {
|
|
7941
|
+
const project = await fetchProjectInOrg(config, projectRef);
|
|
7942
|
+
assertProjectReadyForConfig(project);
|
|
7943
|
+
config.set("activeProjectId", project.id);
|
|
7944
|
+
config.set("apiTarget", "platform");
|
|
7945
|
+
const label = formatProjectLabel(project);
|
|
7946
|
+
return {
|
|
7947
|
+
stdout: project.status === "active" ? `Using platform project ${label}\n` : `Using platform project ${label} (${project.status})\n`,
|
|
7948
|
+
stderr: project.status === "inactive" ? `Project is not active yet. Deploy with: ${cliBinaryName()} deploy --project ${label}\n` : void 0
|
|
7949
|
+
};
|
|
7950
|
+
}
|
|
7951
|
+
//#endregion
|
|
8241
7952
|
//#region src/commands/config/preferences-patch.ts
|
|
8242
7953
|
function parsePreferenceValue(rawValue) {
|
|
8243
7954
|
try {
|
|
@@ -8291,23 +8002,22 @@ function registerConfigCommand(program) {
|
|
|
8291
8002
|
config.command("show").description("Show CLI configuration").action(() => {
|
|
8292
8003
|
const cliConfig = createCliConfig();
|
|
8293
8004
|
const configDir = getConfigDir(cliConfig);
|
|
8294
|
-
const linked = readLinkedProjectConfig();
|
|
8295
8005
|
process.stdout.write(`${JSON.stringify({
|
|
8296
8006
|
webUrl: cliConfig.get("webUrl"),
|
|
8297
8007
|
platformUrl: getPlatformUrl(cliConfig),
|
|
8298
8008
|
localApiUrl: resolveLocalApiOrigin(process.cwd()),
|
|
8299
8009
|
activeOrganizationId: cliConfig.get("activeOrganizationId"),
|
|
8300
|
-
|
|
8301
|
-
linkedOrganization: linked.organization ?? null,
|
|
8010
|
+
activeProjectId: cliConfig.get("activeProjectId"),
|
|
8302
8011
|
apiTarget: getEffectiveApiTarget(cliConfig),
|
|
8303
8012
|
devSession: readDevSession(configDir) ?? null
|
|
8304
8013
|
}, null, 2)}\n`);
|
|
8305
8014
|
});
|
|
8306
|
-
config.command("use").description("Switch API target (local/cloud) or active organization").argument("[mode]", "local, cloud, or org").argument("[id]", "
|
|
8015
|
+
config.command("use").description("Switch API target (local/cloud/project) or active organization").argument("[mode]", "local, cloud, project, or org").argument("[id]", "Project or organization id when switching cloud target or org").action(async (mode, id) => {
|
|
8307
8016
|
const cliConfig = createCliConfig();
|
|
8308
8017
|
if (!mode || mode === "local") {
|
|
8309
8018
|
cliConfig.set("apiTarget", "local");
|
|
8310
|
-
|
|
8019
|
+
const activeProjectId = cliConfig.get("activeProjectId");
|
|
8020
|
+
process.stdout.write(activeProjectId ? `Using local keystroke server (cloud project ${activeProjectId} unchanged)\n` : "Using local keystroke server\n");
|
|
8311
8021
|
return;
|
|
8312
8022
|
}
|
|
8313
8023
|
if (mode === "org") {
|
|
@@ -8317,10 +8027,16 @@ function registerConfigCommand(program) {
|
|
|
8317
8027
|
}
|
|
8318
8028
|
if (mode === "cloud") {
|
|
8319
8029
|
cliConfig.set("apiTarget", "platform");
|
|
8320
|
-
|
|
8030
|
+
const activeProjectId = cliConfig.get("activeProjectId");
|
|
8031
|
+
process.stdout.write(activeProjectId ? `Using platform API (default project ${activeProjectId} for project-scoped commands)\n` : "Using platform API\n");
|
|
8321
8032
|
return;
|
|
8322
8033
|
}
|
|
8323
|
-
throw new Error("Usage: keystroke config use [local|cloud|org [slug]]");
|
|
8034
|
+
if (mode !== "project") throw new Error("Usage: keystroke config use [local|cloud|project [slug]|org [slug]]");
|
|
8035
|
+
const targetProjectId = id ?? cliConfig.get("activeProjectId");
|
|
8036
|
+
if (!targetProjectId) throw new Error("Usage: keystroke config use project <slug>");
|
|
8037
|
+
const result = await runConfigUseProject(cliConfig, targetProjectId);
|
|
8038
|
+
process.stdout.write(result.stdout);
|
|
8039
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
8324
8040
|
});
|
|
8325
8041
|
config.command("org").description("List organizations you belong to").action(async () => {
|
|
8326
8042
|
const organizations = await listOrganizations(createCliConfig());
|
|
@@ -8346,20 +8062,20 @@ function registerSkillCommand(program) {
|
|
|
8346
8062
|
//#endregion
|
|
8347
8063
|
//#region src/commands/skills.ts
|
|
8348
8064
|
function registerSkillsCommand(program) {
|
|
8349
|
-
program.command("skills").description("Manage
|
|
8065
|
+
program.command("skills").description("Manage bundled agent skills").command("sync").description("Overwrite bundled skills and AGENTS.md with the CLI version").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
|
|
8350
8066
|
try {
|
|
8351
8067
|
const root = resolveProjectRoot(options.dir);
|
|
8352
|
-
await
|
|
8353
|
-
process.stdout.write(`Synced
|
|
8068
|
+
await syncBundledSkills(root);
|
|
8069
|
+
process.stdout.write(`Synced bundled skills at ${root}\n`);
|
|
8354
8070
|
} catch (error) {
|
|
8355
|
-
const message = error instanceof Error ? error.message : "
|
|
8071
|
+
const message = error instanceof Error ? error.message : "Skills sync failed";
|
|
8356
8072
|
process.stderr.write(`${message}\n`);
|
|
8357
8073
|
process.exitCode = 1;
|
|
8358
8074
|
}
|
|
8359
8075
|
});
|
|
8360
8076
|
}
|
|
8361
8077
|
//#endregion
|
|
8362
|
-
//#region src/skills/sync-
|
|
8078
|
+
//#region src/skills/sync-skills.ts
|
|
8363
8079
|
function commandPath(command) {
|
|
8364
8080
|
const names = [];
|
|
8365
8081
|
for (let current = command; current; current = current.parent) {
|
|
@@ -8378,20 +8094,18 @@ function shouldSkipAutoSync(command) {
|
|
|
8378
8094
|
function resolveAutoSyncRoot(command) {
|
|
8379
8095
|
return resolveKeystrokeConfigRoot(command.opts().dir ?? process.cwd());
|
|
8380
8096
|
}
|
|
8381
|
-
/** Sync
|
|
8382
|
-
async function
|
|
8097
|
+
/** Sync bundled skills when stale; no-op when not in a project or already up to date. */
|
|
8098
|
+
async function syncSkills(command) {
|
|
8383
8099
|
if (shouldSkipAutoSync(command)) return;
|
|
8384
8100
|
const projectRoot = resolveAutoSyncRoot(command);
|
|
8385
8101
|
if (!projectRoot) return;
|
|
8386
|
-
const
|
|
8387
|
-
if (!existsSync(
|
|
8388
|
-
if (lstatSync(
|
|
8389
|
-
const legacySkillsDir = join(agentsGuideDir(projectRoot), "skills");
|
|
8390
|
-
if (existsSync(legacySkillsDir) && lstatSync(legacySkillsDir).isSymbolicLink()) return;
|
|
8102
|
+
const skillsDir = agentsSkillsDir(projectRoot);
|
|
8103
|
+
if (!existsSync(skillsDir)) return;
|
|
8104
|
+
if (lstatSync(skillsDir).isSymbolicLink()) return;
|
|
8391
8105
|
const currentVersion = readCliVersion();
|
|
8392
8106
|
if (await readBundleVersion(projectRoot) === currentVersion) return;
|
|
8393
|
-
await
|
|
8394
|
-
process.stderr.write(`Synced
|
|
8107
|
+
await syncBundledSkills(projectRoot);
|
|
8108
|
+
process.stderr.write(`Synced bundled skills to ${currentVersion}\n`);
|
|
8395
8109
|
}
|
|
8396
8110
|
//#endregion
|
|
8397
8111
|
//#region src/program.ts
|
|
@@ -8402,7 +8116,7 @@ function createProgram() {
|
|
|
8402
8116
|
projectId: opts.project,
|
|
8403
8117
|
local: opts.local
|
|
8404
8118
|
});
|
|
8405
|
-
await
|
|
8119
|
+
await syncSkills(actionCommand);
|
|
8406
8120
|
});
|
|
8407
8121
|
registerAuthCommand(program);
|
|
8408
8122
|
registerConnectCommand(program);
|
|
@@ -8430,7 +8144,7 @@ function createProgram() {
|
|
|
8430
8144
|
return program;
|
|
8431
8145
|
}
|
|
8432
8146
|
async function runCli(argv) {
|
|
8433
|
-
const { maybeAutoUpdate } = await import("./maybe-auto-update-
|
|
8147
|
+
const { maybeAutoUpdate } = await import("./maybe-auto-update-q5MthdI8.mjs");
|
|
8434
8148
|
await maybeAutoUpdate(argv);
|
|
8435
8149
|
createProgram().parse(argv);
|
|
8436
8150
|
}
|