@keystrokehq/cli 0.1.37 → 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.
Files changed (50) hide show
  1. package/dist/{dist-DkLbeW8l.mjs → dist-BOhrc_Nv.mjs} +198 -561
  2. package/dist/dist-BOhrc_Nv.mjs.map +1 -0
  3. package/dist/{dist-B6z1wti6.mjs → dist-D-cLLjHv.mjs} +87 -2017
  4. package/dist/dist-D-cLLjHv.mjs.map +1 -0
  5. package/dist/{dist-GSI9JDuz.mjs → dist-DGKF3FGu.mjs} +31 -265
  6. package/dist/dist-DGKF3FGu.mjs.map +1 -0
  7. package/dist/dist-DMuIdus5.mjs +3 -0
  8. package/dist/{dist-gAvgHBlr.mjs → dist-Re6HHSqz.mjs} +2 -2
  9. package/dist/{dist-gAvgHBlr.mjs.map → dist-Re6HHSqz.mjs.map} +1 -1
  10. package/dist/index.mjs +177 -463
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/{maybe-auto-update-Dv4MJvWb.mjs → maybe-auto-update-q5MthdI8.mjs} +2 -2
  13. package/dist/{maybe-auto-update-Dv4MJvWb.mjs.map → maybe-auto-update-q5MthdI8.mjs.map} +1 -1
  14. package/dist/skills-bundle/_AGENTS.mcp.md +5 -9
  15. package/dist/skills-bundle/_AGENTS.md +112 -243
  16. package/dist/skills-bundle/skills/keystroke-actions/SKILL.md +160 -0
  17. package/dist/skills-bundle/skills/keystroke-actions/references/catalog-and-imports.md +71 -0
  18. package/dist/skills-bundle/skills/keystroke-agents/SKILL.md +115 -0
  19. package/dist/skills-bundle/skills/keystroke-agents/references/models.md +23 -0
  20. package/dist/skills-bundle/skills/keystroke-agents/references/tools-mcp-codemode.md +73 -0
  21. package/dist/skills-bundle/skills/keystroke-agents/references/workflows-and-testing.md +26 -0
  22. package/dist/skills-bundle/skills/keystroke-apps/SKILL.md +151 -0
  23. package/dist/skills-bundle/skills/keystroke-apps/references/cli-and-catalog.md +104 -0
  24. package/dist/skills-bundle/skills/keystroke-channels/SKILL.md +66 -0
  25. package/dist/skills-bundle/skills/keystroke-channels/references/slack-setup.md +41 -0
  26. package/dist/skills-bundle/skills/keystroke-cli/SKILL.md +93 -0
  27. package/dist/skills-bundle/skills/keystroke-deploy/SKILL.md +93 -0
  28. package/dist/skills-bundle/skills/keystroke-deploy/references/build-and-full-deploy.md +30 -0
  29. package/dist/skills-bundle/skills/keystroke-deploy/references/filtered-deploy.md +50 -0
  30. package/dist/skills-bundle/skills/keystroke-deploy/references/wip-ignore.md +35 -0
  31. package/dist/skills-bundle/skills/keystroke-files/SKILL.md +43 -0
  32. package/dist/skills-bundle/skills/keystroke-skills/SKILL.md +42 -0
  33. package/dist/skills-bundle/skills/keystroke-triggers/SKILL.md +143 -0
  34. package/dist/skills-bundle/skills/keystroke-workflows/SKILL.md +78 -0
  35. package/dist/skills-bundle/skills/keystroke-workflows/references/authoring.md +168 -0
  36. package/dist/skills-bundle/skills/keystroke-workflows/references/testing.md +138 -0
  37. package/dist/templates/hello-world/.env.example +4 -0
  38. package/dist/templates/hello-world/README.md +3 -4
  39. package/dist/templates/hello-world/package.json +0 -1
  40. package/dist/templates/hello-world/src/actions/greet.ts +0 -1
  41. package/dist/templates/hello-world/src/agents/hello.ts +0 -2
  42. package/dist/templates/hello-world/src/workflows/greeting.ts +0 -1
  43. package/dist/{version-CiFlKPyE.mjs → version-DcR3O1UD.mjs} +3 -2
  44. package/dist/version-DcR3O1UD.mjs.map +1 -0
  45. package/package.json +6 -6
  46. package/dist/dist-B6z1wti6.mjs.map +0 -1
  47. package/dist/dist-CjWXZCN7.mjs +0 -3
  48. package/dist/dist-DkLbeW8l.mjs.map +0 -1
  49. package/dist/dist-GSI9JDuz.mjs.map +0 -1
  50. 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 GetCredentialResponseSchema, $t as SkillSummaryListResponseSchema, A as CreateCustomAppRequestSchema, An as WorkflowCanvasCredentialBindingsSchema, At as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, B as CredentialConsumerListQuerySchema, Bn as WorkflowSummaryListResponseSchema, Bt as ProjectPullStateSchema, C as ConnectAuthorizeUrlResponseSchema, Cn as UploadProjectSourceManifestRequestSchema, Ct as ListProjectMetricsResponseSchema, D as CreateCredentialInstanceBodySchema, Dn as UserAvatarSchema, Dt as OrganizationSidebarBrandingPatchSchema, E as CreateApiKeyResponseSchema, En as UserAvatarPatchSchema, Et as OpenApiDiscoverResponseSchema, F as CreateProjectRequestSchema, Fn as WorkflowRunInputsPutBodySchema, Ft as PresignOrgLogoResponseSchema, G as DOCS_QUERY_TOOL, Gn as WorkspaceTriggerRunListResponseSchema, Gt as PromptInputSchema, H as CredentialInstanceListResponseSchema, Hn as WorkspaceTriggerFileSchema, Ht as ProjectResponseSchema, I as CreateProjectResponseSchema, In as WorkflowRunInputsSchema, It as PresignProjectSourceRequestSchema, J as DownloadActiveProjectArtifactResponseSchema, Jt as QueuedAgentPromptResponseSchema, K as DOCS_SEARCH_TOOL, Kn as WorkspaceWorkflowOverviewSchema, Kt as PromptResponseSchema, L as CredentialAssignmentListQuerySchema, Ln as WorkflowRunListResponseSchema, Lt as PresignProjectSourceResponseSchema, M as CreateOrganizationRequestSchema, Mn as WorkflowCanvasSchema, Mt as PresignChatAttachmentRequestSchema, N as CreateOrganizationResponseSchema, Nn as WorkflowRunDetailResponseSchema, Nt as PresignChatAttachmentResponseSchema, O as CreateCredentialsRequestSchema, On as UserPreferencesPatchSchema, Ot as OrganizationSidebarBrandingSchema, P as CreateProjectArtifactResponseSchema, Pn as WorkflowRunHooksResponseSchema, Pt as PresignOrgLogoRequestSchema, Q as GatewayAttachmentRecordSchema, Qn as listenPortFromPublicUrl, Qt as SkillSummaryDetailResponseSchema, R as CredentialAssignmentListResponseSchema, Rn as WorkflowRunResponseSchema, Rt as PresignUserAvatarRequestSchema, S as CompleteProjectArtifactResponseSchema, Sn as UpdateProjectSettingsRequestSchema, St as ListProjectMembersResponseSchema, T as CreateApiKeyRequestSchema, Tn as UpsertGatewayAttachmentBodySchema, Tt as McpDiscoverResponseSchema, U as CredentialInstanceRecordSchema, Un as WorkspaceTriggerListResponseSchema, Ut as ProjectSettingsResponseSchema, V as CredentialConsumerListResponseSchema, Vn as WorkspaceTriggerDetailSchema, Vt as ProjectReachabilityResponseSchema, Wn as WorkspaceTriggerOverviewSchema, Wt as ProjectSlugAvailabilityResponseSchema, X as ErrorResponseSchema, Xn as detectProjectPackageManagerFromSnapshot, Y as DownloadActiveProjectSourceResponseSchema, Yn as deriveCustomAppDisplay, Yt as QueuedRunResponseSchema, Z as ExecuteKeystrokeToolRequestSchema, Zn as isAcceptableInstallExit, Zt as RecentResourceListResponseSchema, _ as ChannelAccountListResponseSchema, _n as UpdateOrganizationMemberResponseSchema, _t as ListOrganizationInvitationsResponseSchema, a as AgentSessionDetailResponseSchema, an as StartOAuthConnectionInputSchema, ar as resolveConnectAppSlug, at as HistoryRunListQuerySchema, b as ChannelDirectoryListResponseSchema, bn as UpdateProjectMemberResponseSchema, bt as ListProjectDeploymentsResponseSchema, c as AgentSummaryListResponseSchema, cn as SubmitTeamRequestRequestSchema, cr as slugifyAppName, ct as InviteOrganizationMembersResponseSchema, d as AssignCredentialBodySchema, dn as TriggerRunDetailResponseSchema, en as SlugAvailabilityResponseSchema, et as GetCustomAppResponseSchema, f as BindChannelBodySchema, fn as TriggerRunListResponseSchema, ft as ListAgentMemoryFilesResponseSchema, g as CatalogAppsPageResponseSchema, gn as UpdateOrganizationMemberRequestSchema, gt as ListCredentialsResponseSchema, h as CatalogAppDetailResponseSchema, hn as UpdateCredentialRequestSchema, ht as ListAppsResponseSchema, i as AgentSessionChatStateResponseSchema, in as StartMcpOAuthConnectionResultSchema, it as HistoryRunDetailResponseSchema, j as CreateCustomAppResponseSchema, jn as WorkflowCanvasRunSchema, jt as PollRunResponseSchema, k as CreateCredentialsResponseSchema, kn as UserPreferencesSchema, kt as PROJECT_PULL_STATE_RELATIVE_PATH, l as AgentTriggerSummaryListResponseSchema, ln as TriggerDetailResponseSchema, lt as InviteProjectMembersRequestSchema, m as CatalogActionsPageResponseSchema, mn as UpdateCredentialInstanceBodySchema, mt as ListApiKeysResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nn as StartKeystrokeConnectionResultSchema, nr as parseErrorResponse, nt as HealthResponseSchema, o as AgentSessionListResponseSchema, on as StartOAuthConnectionResultSchema, or as resolveDocsMcpUrl, ot as HistoryRunListResponseSchema, p as CatalogActionDetailResponseSchema, pn as UpdateChannelBindingBodySchema, pt as ListAgentWorkspaceFilesResponseSchema, q as DeclineOrganizationInvitationResponseSchema, qn as buildConnectDeeplink, r as ActiveOrganizationResponseSchema, rn as StartMcpOAuthConnectionInputSchema, rt as HistoryRunCancelResponseSchema, s as AgentSummaryDetailResponseSchema, sn as SubmitMarketingContactRequestSchema, sr as resolvePublicPlatformOrigin, st as InviteOrganizationMembersRequestSchema, t as ACTIVE_ORG_HEADER, tn as StartKeystrokeConnectionInputSchema, tr as parseAppSlug, tt as GraphqlDiscoverResponseSchema, u as AppSlugAvailabilityResponseSchema, un as TriggerListResponseSchema, ut as InviteProjectMembersResponseSchema, v as ChannelConnectionListResponseSchema, vn as UpdateOrganizationRequestSchema, vt as ListOrganizationMembersResponseSchema, w as ConnectProvidersResponseSchema, wn as UploadProjectSourceResponseSchema, wt as ListProjectsResponseSchema, x as ChannelPlatformSchema, xn as UpdateProjectRequestSchema, xt as ListProjectFilesResponseSchema, y as ChannelConnectionSchema, yn as UpdateProjectMemberRequestSchema, yt as ListOrganizationsResponseSchema, z as CredentialAssignmentRecordSchema, zn as WorkflowSummaryDetailResponseSchema, zt as PresignUserAvatarResponseSchema } from "./dist-DkLbeW8l.mjs";
3
- import { i as packProjectArtifact, n as withMcpReadClient, r as mergeFilteredArtifact, t as mapInParallelBatches } from "./dist-gAvgHBlr.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-CiFlKPyE.mjs";
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(`api/workflows/${encodeURIComponent(workflowId)}`).json();
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 project link --project <slug>\`.`);
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 ?? readLinkedProjectConfig().project;
5107
- if (!projectRef) throw new Error("No project selected. Pass `--project <slug>` or run `keystroke project link --project <slug>`.");
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, fromDir = process.cwd(), applyLinkedOrganization = true) {
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} project link --project ${formatProjectLabel(project)}, then ${bin} deploy\n`);
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().toUpperCase();
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 catalog action schema, plus how to run and import it").argument("<app>", "App slug (e.g. github)").argument("<tool>", "Tool slug (e.g. github_create_an_issue)").action((appSlug, toolSlug) => runCliCommand("App action failed", async () => {
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 a catalog app's 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 () => {
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("Discover and run connectable integrations");
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-GSI9JDuz.mjs");
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
- process.stderr.write(`Build failed: ${formatCliError(error, "unknown error")}\n`);
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-GSI9JDuz.mjs");
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-GSI9JDuz.mjs");
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
- config = createCliConfig();
6612
- const root = resolveProjectRoot(options.dir);
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 = formatCliError(error, "unknown error", { webUrl: config ? getWebUrl(config) : void 0 });
6622
- process.stderr.write(`Deploy failed: ${message}\n`);
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-GSI9JDuz.mjs");
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-GSI9JDuz.mjs");
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.28";
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 AGENTS guide not found — run `pnpm --filter @keystrokehq/cli build`");
6878
+ throw new Error("Bundled keystroke skills not found — run `pnpm --filter @keystrokehq/cli build`");
7162
6879
  }
7163
6880
  //#endregion
7164
- //#region src/skills/scaffold-agents-guide.ts
7165
- async function ensureSymlink(target, linkPath) {
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, "file");
6902
+ await symlink(target, linkPath, platform() === "win32" && kind === "dir" ? "junction" : kind);
7172
6903
  }
7173
- /** Writes AGENTS.md from the CLI bundle and recreates the CLAUDE.md symlink. */
7174
- async function scaffoldAgentsGuide(projectRoot, fromModuleUrl = import.meta.url) {
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 guidePath = agentsMdPath(projectRoot);
7177
- if ((await lstat(guidePath).catch(() => null))?.isSymbolicLink()) await rm(guidePath, { force: true });
7178
- await writeFile(guidePath, stampAgentsGuideVersion(await readFile(join(bundleDir, "_AGENTS.md"), "utf8")));
7179
- await ensureSymlink(relative(dirname(join(projectRoot, "CLAUDE.md")), guidePath), join(projectRoot, "CLAUDE.md"));
7180
- }
7181
- //#endregion
7182
- //#region src/project/write-project-config.ts
7183
- const KEYSTROKE_CONFIG = "keystroke.config.ts";
7184
- function upsertStringLiteral(source, key, value) {
7185
- const stripped = stripConfigCommentsPreservingLength(source);
7186
- const entryPattern = new RegExp(`\\b${key}\\s*:\\s*(['"])[^'"]*\\1,?\\s*\\n?`);
7187
- const entry = value === void 0 ? void 0 : ` ${key}: "${value}",\n`;
7188
- const match = stripped.match(entryPattern);
7189
- if (match?.index !== void 0) {
7190
- const start = match.index;
7191
- const end = start + match[0].length;
7192
- if (value === void 0) return source.slice(0, start) + source.slice(end);
7193
- return source.slice(0, start) + entry + source.slice(end);
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 scaffoldAgentsGuide(targetDir);
7314
- if (options.project || options.organization) writeLinkedProjectConfig({
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").option("--project <slug>", "Platform project slug to write into keystroke.config.ts").option("--organization <slug>", "Platform organization slug to write into keystroke.config.ts").action(async (directory, options) => {
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
- if (!options.project) process.stdout.write(" keystroke project link --project <slug> # link this directory to a platform project\n");
7349
- process.stdout.write(" keystroke deploy # build + ship src/ to the platform\n");
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 ?? readLinkedProjectConfig().project;
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 ?? readLinkedProjectConfig().project;
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 ?? readLinkedProjectConfig().project;
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 ?? readLinkedProjectConfig().project;
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
- ...projectRef ? { projectRef } : {},
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 ?? resolveLinkedProjectRef();
7711
- if (!projectRef) throw new Error("Usage: keystroke project deployments list --project <slug> (or run `keystroke project link`)");
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 scaffoldAgentsGuide(targetDir);
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, resolveProjectRoot(options.dir));
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-GSI9JDuz.mjs");
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() || readLinkedProjectConfig().project?.trim();
8143
- if (!ref) throw new Error("Project is required. Pass --project <slug> or run `keystroke project link --project <slug>`.");
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
- linkedProject: linked.project ?? null,
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]", "Organization slug when switching org").action(async (mode, 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
- process.stdout.write("Using local keystroke server\n");
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
- process.stdout.write("Using platform API\n");
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 the scaffolded AGENTS guide").command("sync").description("Overwrite AGENTS.md with the CLI version").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
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 scaffoldAgentsGuide(root);
8353
- process.stdout.write(`Synced AGENTS.md at ${root}\n`);
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 : "AGENTS guide sync failed";
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-agents-guide.ts
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 AGENTS.md when stale; no-op when not in a project or already up to date. */
8382
- async function syncAgentsGuide(command) {
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 agentsMdPath = join(projectRoot, "AGENTS.md");
8387
- if (!existsSync(agentsMdPath)) return;
8388
- if (lstatSync(agentsMdPath).isSymbolicLink()) return;
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 scaffoldAgentsGuide(projectRoot);
8394
- process.stderr.write(`Synced AGENTS.md to ${currentVersion}\n`);
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 syncAgentsGuide(actionCommand);
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-Dv4MJvWb.mjs");
8147
+ const { maybeAutoUpdate } = await import("./maybe-auto-update-q5MthdI8.mjs");
8434
8148
  await maybeAutoUpdate(argv);
8435
8149
  createProgram().parse(argv);
8436
8150
  }