@keystrokehq/cli 0.1.4 → 0.1.6

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 (43) hide show
  1. package/README.md +8 -9
  2. package/dist/dist-CWgqwAeq.mjs +19268 -0
  3. package/dist/dist-CWgqwAeq.mjs.map +1 -0
  4. package/dist/dist-DohqaxIM.mjs +3 -0
  5. package/dist/{dist-C47GdlWY.mjs → dist-H53GUsol.mjs} +1019 -183
  6. package/dist/dist-H53GUsol.mjs.map +1 -0
  7. package/dist/{dist-CJL2zYbP.mjs → dist-jchdNGBU.mjs} +62 -5
  8. package/dist/dist-jchdNGBU.mjs.map +1 -0
  9. package/dist/index.mjs +973 -377
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/{maybe-auto-update-B0kal2FM.mjs → maybe-auto-update-ClXO7U-6.mjs} +2 -2
  12. package/dist/{maybe-auto-update-B0kal2FM.mjs.map → maybe-auto-update-ClXO7U-6.mjs.map} +1 -1
  13. package/dist/pack-artifact-DVnIKrsg-CETr40a-.mjs +112 -0
  14. package/dist/pack-artifact-DVnIKrsg-CETr40a-.mjs.map +1 -0
  15. package/dist/skills-bundle/_AGENTS.md +7 -7
  16. package/dist/skills-bundle/skills/keystroke-actions/SKILL.md +39 -7
  17. package/dist/skills-bundle/skills/keystroke-actions/references/catalog-and-imports.md +25 -19
  18. package/dist/skills-bundle/skills/keystroke-agents/SKILL.md +7 -5
  19. package/dist/skills-bundle/skills/keystroke-apps/SKILL.md +133 -0
  20. package/dist/skills-bundle/skills/keystroke-apps/references/cli-and-catalog.md +66 -0
  21. package/dist/skills-bundle/skills/keystroke-cli/SKILL.md +3 -3
  22. package/dist/skills-bundle/skills/keystroke-cli/references/api-targets.md +6 -5
  23. package/dist/skills-bundle/skills/keystroke-deploy/SKILL.md +2 -2
  24. package/dist/skills-bundle/skills/keystroke-files/SKILL.md +6 -5
  25. package/dist/skills-bundle/skills/keystroke-gateways/SKILL.md +2 -2
  26. package/dist/skills-bundle/skills/keystroke-gateways/references/slack-setup.md +1 -1
  27. package/dist/skills-bundle/skills/keystroke-skills/SKILL.md +1 -1
  28. package/dist/skills-bundle/skills/keystroke-workflows/SKILL.md +1 -1
  29. package/dist/skills-bundle/skills/keystroke-workflows/references/authoring.md +2 -2
  30. package/dist/templates/hello-world/.env.example +1 -15
  31. package/dist/templates/hello-world/README.md +1 -1
  32. package/dist/templates/hello-world/package.json +1 -1
  33. package/dist/{version-Dxl3y5p6.mjs → version-CiPDVUdk.mjs} +10 -14
  34. package/dist/version-CiPDVUdk.mjs.map +1 -0
  35. package/package.json +8 -2
  36. package/dist/dist-C47GdlWY.mjs.map +0 -1
  37. package/dist/dist-CJL2zYbP.mjs.map +0 -1
  38. package/dist/dist-Ch53z2P3.mjs +0 -3
  39. package/dist/dist-CwR72_PS.mjs +0 -1887
  40. package/dist/dist-CwR72_PS.mjs.map +0 -1
  41. package/dist/skills-bundle/skills/keystroke-credentials/SKILL.md +0 -108
  42. package/dist/skills-bundle/skills/keystroke-credentials/references/cli-and-oauth.md +0 -51
  43. package/dist/version-Dxl3y5p6.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { $ as ListProjectsResponseSchema, A as DownloadActiveProjectArtifactResponseSchema, At as TriggerRunListResponseSchema, B as InviteOrganizationMembersResponseSchema, Bt as UpdateProjectSettingsRequestSchema, C as CreateOrganizationResponseSchema, Ct as StartOAuthConnectionInputSchema, D as CredentialInstanceListResponseSchema, Dt as TriggerDetailResponseSchema, E as CreateProjectResponseSchema, Et as SubmitTeamRequestRequestSchema, F as HistoryRunCancelResponseSchema, Ft as UpdateOrganizationMemberResponseSchema, G as ListCredentialsResponseSchema, Gt as UserAvatarSchema, H as InviteProjectMembersResponseSchema, Ht as UploadProjectSourceResponseSchema, I as HistoryRunDetailResponseSchema, It as UpdateOrganizationRequestSchema, J as ListOrganizationsResponseSchema, Jt as WorkflowRunDetailResponseSchema, K as ListOrganizationInvitationsResponseSchema, Kt as UserPreferencesPatchSchema, L as HistoryRunListQuerySchema, Lt as UpdateProjectMemberRequestSchema, M as GatewayAttachmentRecordSchema, Mt as UpdateCredentialInstanceBodySchema, N as GetCredentialResponseSchema, Nt as UpdateCredentialRequestSchema, O as CredentialInstanceRecordSchema, Ot as TriggerListResponseSchema, P as HealthResponseSchema, Pt as UpdateOrganizationMemberRequestSchema, Q as ListProjectMetricsResponseSchema, Qt as listenPortFromPublicUrl, R as HistoryRunListResponseSchema, Rt as UpdateProjectMemberResponseSchema, S as CreateOrganizationRequestSchema, St as SlugAvailabilityResponseSchema, T as CreateProjectRequestSchema, Tt as StoredRouteManifestSchema, U as ListApiKeysResponseSchema, Ut as UpsertGatewayAttachmentBodySchema, V as InviteProjectMembersRequestSchema, Vt as UploadProjectSourceManifestRequestSchema, W as ListAppsResponseSchema, Wt as UserAvatarPatchSchema, X as ListProjectFilesResponseSchema, Xt as WorkflowSummaryDetailResponseSchema, Y as ListProjectDeploymentsResponseSchema, Yt as WorkflowRunListResponseSchema, Z as ListProjectMembersResponseSchema, Zt as WorkflowSummaryListResponseSchema, _ as CreateApiKeyRequestSchema, _t as QueuedRunResponseSchema, a as AgentSessionListResponseSchema, at as PresignOrgLogoResponseSchema, b as CreateCredentialsRequestSchema, bt as SkillSummaryDetailResponseSchema, c as BindChannelBodySchema, ct as PresignUserAvatarRequestSchema, d as ChannelConnectionSchema, dt as ProjectResponseSchema, et as OrganizationSidebarBrandingPatchSchema, f as ChannelDirectoryListResponseSchema, ft as ProjectSettingsResponseSchema, g as ConnectProvidersResponseSchema, gt as QueuedAgentPromptResponseSchema, h as ConnectAuthorizeUrlResponseSchema, ht as PromptResponseSchema, i as AgentSessionDetailResponseSchema, it as PresignOrgLogoRequestSchema, j as ErrorResponseSchema, jt as UpdateChannelBindingBodySchema, k as DeclineOrganizationInvitationResponseSchema, kt as TriggerRunDetailResponseSchema, l as ChannelAccountListResponseSchema, lt as PresignUserAvatarResponseSchema, m as CompleteProjectArtifactResponseSchema, mt as PromptInputSchema, n as AcceptOrganizationInvitationResponseSchema, nt as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, o as AgentSummaryDetailResponseSchema, ot as PresignProjectSourceRequestSchema, p as ChannelPlatformSchema, pt as ProjectSlugAvailabilityResponseSchema, q as ListOrganizationMembersResponseSchema, qt as UserPreferencesSchema, r as ActiveOrganizationResponseSchema, rt as PollRunResponseSchema, s as AgentSummaryListResponseSchema, st as PresignProjectSourceResponseSchema, t as ACTIVE_ORG_HEADER, tn as parseErrorResponse, tt as OrganizationSidebarBrandingSchema, u as ChannelConnectionListResponseSchema, ut as ProjectReachabilityResponseSchema, v as CreateApiKeyResponseSchema, vt as ROUTE_MANIFEST_REL_PATH, w as CreateProjectArtifactResponseSchema, wt as StartOAuthConnectionResultSchema, x as CreateCredentialsResponseSchema, xt as SkillSummaryListResponseSchema, y as CreateCredentialInstanceBodySchema, yt as RecentResourceListResponseSchema, z as InviteOrganizationMembersRequestSchema, zt as UpdateProjectRequestSchema } from "./dist-C47GdlWY.mjs";
3
- import { _ as resolvePlatformUrlForWebUrl, a as installPlaygroundDependencies, c as createCliConfig, d as getEffectiveApiTarget, f as getPlatformUrl, h as DEFAULT_PLATFORM_URL, i as installDependencies, l as getCliConfigDir, m as getWebUrl, n as buildPlaygroundWorkspace, o as resolvePackageManager, p as getServerUrl, s as resolveCliRoot, t as readCliVersion, u as getConfigDir } from "./version-Dxl3y5p6.mjs";
2
+ import { $ as HistoryRunListQuerySchema, $t as TriggerListResponseSchema, A as CreateCustomAppRequestSchema, An as listenPortFromPublicUrl, At as PresignUserAvatarResponseSchema, B as CredentialConsumerListQuerySchema, Bt as RecentResourceListResponseSchema, C as ConnectAuthorizeUrlResponseSchema, Cn as WorkspaceTriggerDetailSchema, Ct as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, D as CreateCredentialInstanceBodySchema, Dn as WorkspaceTriggerRunListResponseSchema, Dt as PresignProjectSourceRequestSchema, E as CreateApiKeyResponseSchema, En as WorkspaceTriggerOverviewSchema, Et as PresignOrgLogoResponseSchema, F as CreateProjectRequestSchema, Ft as PromptInputSchema, G as DownloadActiveProjectArtifactResponseSchema, Gt as StartKeystrokeConnectionResultSchema, H as CredentialInstanceListResponseSchema, Ht as SkillSummaryListResponseSchema, I as CreateProjectResponseSchema, In as resolvePublicPlatformOrigin, It as PromptResponseSchema, J as GetCredentialResponseSchema, Jt as StartOAuthConnectionInputSchema, K as ErrorResponseSchema, Kt as StartMcpOAuthConnectionInputSchema, L as CredentialAssignmentListQuerySchema, Ln as slugifyAppName, Lt as QueuedAgentPromptResponseSchema, M as CreateOrganizationRequestSchema, Mt as ProjectResponseSchema, N as CreateOrganizationResponseSchema, Nn as parseAppSlug, Nt as ProjectSettingsResponseSchema, O as CreateCredentialsRequestSchema, On as buildConnectDeeplink, Ot as PresignProjectSourceResponseSchema, P as CreateProjectArtifactResponseSchema, Pn as parseErrorResponse, Pt as ProjectSlugAvailabilityResponseSchema, Q as HistoryRunDetailResponseSchema, Qt as TriggerDetailResponseSchema, R as CredentialAssignmentListResponseSchema, Rt as QueuedRunResponseSchema, S as CompleteProjectArtifactResponseSchema, Sn as WorkflowSummaryListResponseSchema, St as OrganizationSidebarBrandingSchema, T as CreateApiKeyRequestSchema, Tn as WorkspaceTriggerListResponseSchema, Tt as PresignOrgLogoRequestSchema, U as CredentialInstanceRecordSchema, Ut as SlugAvailabilityResponseSchema, V as CredentialConsumerListResponseSchema, Vt as SkillSummaryDetailResponseSchema, W as DeclineOrganizationInvitationResponseSchema, Wt as StartKeystrokeConnectionInputSchema, X as HealthResponseSchema, Xt as SubmitMarketingContactRequestSchema, Y as GetCustomAppResponseSchema, Yt as StartOAuthConnectionResultSchema, Z as HistoryRunCancelResponseSchema, Zt as SubmitTeamRequestRequestSchema, _ as ChannelAccountListResponseSchema, _n as UserPreferencesPatchSchema, _t as ListProjectMetricsResponseSchema, a as AgentSessionDetailResponseSchema, an as UpdateOrganizationMemberRequestSchema, b as ChannelDirectoryListResponseSchema, bn as WorkflowRunListResponseSchema, bt as OpenApiDiscoverResponseSchema, c as AgentSummaryListResponseSchema, cn as UpdateProjectMemberRequestSchema, ct as ListApiKeysResponseSchema, d as AssignCredentialBodySchema, dn as UpdateProjectSettingsRequestSchema, dt as ListOrganizationInvitationsResponseSchema, en as TriggerRunDetailResponseSchema, et as HistoryRunListResponseSchema, f as BindChannelBodySchema, fn as UploadProjectSourceManifestRequestSchema, ft as ListOrganizationMembersResponseSchema, g as CatalogAppsPageResponseSchema, gn as UserAvatarSchema, gt as ListProjectMembersResponseSchema, h as CatalogAppDetailResponseSchema, hn as UserAvatarPatchSchema, ht as ListProjectFilesResponseSchema, i as AgentSessionChatStateResponseSchema, in as UpdateCredentialRequestSchema, it as InviteProjectMembersResponseSchema, j as CreateCustomAppResponseSchema, jt as ProjectReachabilityResponseSchema, k as CreateCredentialsResponseSchema, kt as PresignUserAvatarRequestSchema, l as AgentTriggerSummaryListResponseSchema, ln as UpdateProjectMemberResponseSchema, lt as ListAppsResponseSchema, m as CatalogActionsPageResponseSchema, mn as UpsertGatewayAttachmentBodySchema, mt as ListProjectDeploymentsResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nn as UpdateChannelBindingBodySchema, nt as InviteOrganizationMembersResponseSchema, o as AgentSessionListResponseSchema, on as UpdateOrganizationMemberResponseSchema, ot as ListAgentMemoryFilesResponseSchema, p as CatalogActionDetailResponseSchema, pn as UploadProjectSourceResponseSchema, pt as ListOrganizationsResponseSchema, q as GatewayAttachmentRecordSchema, qt as StartMcpOAuthConnectionResultSchema, r as ActiveOrganizationResponseSchema, rn as UpdateCredentialInstanceBodySchema, rt as InviteProjectMembersRequestSchema, s as AgentSummaryDetailResponseSchema, sn as UpdateOrganizationRequestSchema, st as ListAgentWorkspaceFilesResponseSchema, t as ACTIVE_ORG_HEADER, tn as TriggerRunListResponseSchema, tt as InviteOrganizationMembersRequestSchema, u as AppSlugAvailabilityResponseSchema, un as UpdateProjectRequestSchema, ut as ListCredentialsResponseSchema, v as ChannelConnectionListResponseSchema, vn as UserPreferencesSchema, vt as ListProjectsResponseSchema, w as ConnectProvidersResponseSchema, wn as WorkspaceTriggerFileSchema, wt as PollRunResponseSchema, x as ChannelPlatformSchema, xn as WorkflowSummaryDetailResponseSchema, xt as OrganizationSidebarBrandingPatchSchema, y as ChannelConnectionSchema, yn as WorkflowRunDetailResponseSchema, yt as McpDiscoverResponseSchema, z as CredentialAssignmentRecordSchema } from "./dist-H53GUsol.mjs";
3
+ import { a as installPlaygroundDependencies, c as createCliConfig, d as getEffectiveApiTarget, f as getPlatformUrl, g as resolvePlatformUrlForWebUrl, i as installDependencies, 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-CiPDVUdk.mjs";
4
+ import { n as packProjectArtifact, t as mergeFilteredArtifact } from "./pack-artifact-DVnIKrsg-CETr40a-.mjs";
4
5
  import { createRequire } from "node:module";
5
6
  import { Command } from "commander";
6
- import { platform, tmpdir } from "node:os";
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
- import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
11
+ import { existsSync, lstatSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
12
+ import { access, copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
11
13
  import { spawn, spawnSync } from "node:child_process";
12
14
  import { pathToFileURL } from "node:url";
13
- import { access, copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
14
15
  //#region ../../node_modules/.pnpm/ky@2.0.2/node_modules/ky/distribution/errors/KyError.js
15
16
  /**
16
17
  Base class for all Ky-specific errors. `HTTPError`, `NetworkError`, `TimeoutError`, and `ForceRetryError` extend this class.
@@ -1433,6 +1434,40 @@ function createCredentialsResource$1(http) {
1433
1434
  } catch (error) {
1434
1435
  throw await toKeystrokeError(error);
1435
1436
  }
1437
+ },
1438
+ async listAssignments(query) {
1439
+ try {
1440
+ const params = CredentialAssignmentListQuerySchema.parse(query);
1441
+ const data = await http.get("credentials/assignments", { searchParams: params }).json();
1442
+ return CredentialAssignmentListResponseSchema.parse(data);
1443
+ } catch (error) {
1444
+ throw await toKeystrokeError(error);
1445
+ }
1446
+ },
1447
+ async assignCredential(body) {
1448
+ try {
1449
+ const payload = AssignCredentialBodySchema.parse(body);
1450
+ const data = await http.put("credentials/assignments", { json: payload }).json();
1451
+ return CredentialAssignmentRecordSchema.parse(data);
1452
+ } catch (error) {
1453
+ throw await toKeystrokeError(error);
1454
+ }
1455
+ },
1456
+ async unassignCredential(id) {
1457
+ try {
1458
+ await http.delete(`credentials/assignments/${id}`);
1459
+ } catch (error) {
1460
+ throw await toKeystrokeError(error);
1461
+ }
1462
+ },
1463
+ async listConsumers(query) {
1464
+ try {
1465
+ const params = CredentialConsumerListQuerySchema.parse(query);
1466
+ const data = await http.get("credentials/consumers", { searchParams: params }).json();
1467
+ return CredentialConsumerListResponseSchema.parse(data);
1468
+ } catch (error) {
1469
+ throw await toKeystrokeError(error);
1470
+ }
1436
1471
  }
1437
1472
  };
1438
1473
  }
@@ -1474,7 +1509,7 @@ function detailSearchParams$1(query) {
1474
1509
  if (!query?.include) return {};
1475
1510
  return { include: query.include };
1476
1511
  }
1477
- function createTriggersResource(http) {
1512
+ function createTriggersResource$1(http) {
1478
1513
  return {
1479
1514
  async list(query) {
1480
1515
  try {
@@ -1552,7 +1587,7 @@ function createTriggersResource(http) {
1552
1587
  function isQueuedRunResponse(value) {
1553
1588
  return QueuedRunResponseSchema.safeParse(value).success;
1554
1589
  }
1555
- function listRunsSearchParams(query) {
1590
+ function listRunsSearchParams$2(query) {
1556
1591
  if (!query) return {};
1557
1592
  const params = {};
1558
1593
  if (query.limit !== void 0) params.limit = String(query.limit);
@@ -1579,7 +1614,7 @@ function createWorkflowsResource$1(http) {
1579
1614
  },
1580
1615
  async listRuns(workflowId, query) {
1581
1616
  try {
1582
- const data = await http.get(`workflows/${workflowId}/runs`, { searchParams: listRunsSearchParams(query) }).json();
1617
+ const data = await http.get(`workflows/${workflowId}/runs`, { searchParams: listRunsSearchParams$2(query) }).json();
1583
1618
  return WorkflowRunListResponseSchema.parse(data);
1584
1619
  } catch (error) {
1585
1620
  throw await toKeystrokeError(error);
@@ -1616,7 +1651,7 @@ function createKeystrokeClient(options) {
1616
1651
  openapi: createOpenApiResource(http),
1617
1652
  agents: createAgentsResource$1(http),
1618
1653
  workflows: createWorkflowsResource$1(http),
1619
- triggers: createTriggersResource(http)
1654
+ triggers: createTriggersResource$1(http)
1620
1655
  };
1621
1656
  }
1622
1657
  //#endregion
@@ -1700,7 +1735,7 @@ function createJwtTokenCache(mint) {
1700
1735
  };
1701
1736
  }
1702
1737
  //#endregion
1703
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/version.mjs
1738
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/version.mjs
1704
1739
  const PACKAGE_VERSION = "1.6.11";
1705
1740
  //#endregion
1706
1741
  //#region ../../node_modules/.pnpm/better-call@1.3.5_zod@4.4.3/node_modules/better-call/dist/error.mjs
@@ -1825,7 +1860,7 @@ var BetterAuthError = class extends Error {
1825
1860
  }
1826
1861
  };
1827
1862
  //#endregion
1828
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/plugins/device-authorization/client.mjs
1863
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/plugins/device-authorization/client.mjs
1829
1864
  const deviceAuthorizationClient = () => {
1830
1865
  return {
1831
1866
  id: "device-authorization",
@@ -1970,7 +2005,7 @@ let onMount = ($store, initialize) => {
1970
2005
  });
1971
2006
  };
1972
2007
  //#endregion
1973
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/query.mjs
2008
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/query.mjs
1974
2009
  const isServer = () => typeof window === "undefined";
1975
2010
  const useAuthQuery = (initializedAtom, path, $fetch, options) => {
1976
2011
  const value = /* @__PURE__ */ atom({
@@ -2064,7 +2099,7 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
2064
2099
  return value;
2065
2100
  };
2066
2101
  //#endregion
2067
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/broadcast-channel.mjs
2102
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/broadcast-channel.mjs
2068
2103
  const kBroadcastChannel = Symbol.for("better-auth:broadcast-channel");
2069
2104
  const now$1 = () => Math.floor(Date.now() / 1e3);
2070
2105
  var WindowBroadcastChannel = class {
@@ -2107,7 +2142,7 @@ function getGlobalBroadcastChannel(name = "better-auth.message") {
2107
2142
  return globalThis[kBroadcastChannel];
2108
2143
  }
2109
2144
  //#endregion
2110
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/focus-manager.mjs
2145
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/focus-manager.mjs
2111
2146
  const kFocusManager = Symbol.for("better-auth:focus-manager");
2112
2147
  var WindowFocusManager = class {
2113
2148
  listeners = /* @__PURE__ */ new Set();
@@ -2136,7 +2171,7 @@ function getGlobalFocusManager() {
2136
2171
  return globalThis[kFocusManager];
2137
2172
  }
2138
2173
  //#endregion
2139
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/online-manager.mjs
2174
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/online-manager.mjs
2140
2175
  const kOnlineManager = Symbol.for("better-auth:online-manager");
2141
2176
  var WindowOnlineManager = class {
2142
2177
  listeners = /* @__PURE__ */ new Set();
@@ -2168,7 +2203,7 @@ function getGlobalOnlineManager() {
2168
2203
  return globalThis[kOnlineManager];
2169
2204
  }
2170
2205
  //#endregion
2171
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/parser.mjs
2206
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/parser.mjs
2172
2207
  const PROTO_POLLUTION_PATTERNS = {
2173
2208
  proto: /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,
2174
2209
  constructor: /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,
@@ -2238,7 +2273,7 @@ function parseJSON(value, options = { strict: true }) {
2238
2273
  return betterJSONParse(value, options);
2239
2274
  }
2240
2275
  //#endregion
2241
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/session-refresh.mjs
2276
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/session-refresh.mjs
2242
2277
  const now = () => Math.floor(Date.now() / 1e3);
2243
2278
  /**
2244
2279
  * Normalize $fetch response: `throw: true` returns data directly, otherwise `{ data, error }`.
@@ -2436,7 +2471,7 @@ Object.freeze({
2436
2471
  }
2437
2472
  });
2438
2473
  //#endregion
2439
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/utils/url.mjs
2474
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/utils/url.mjs
2440
2475
  function checkHasPath(url) {
2441
2476
  try {
2442
2477
  return (new URL(url).pathname.replace(/\/+$/, "") || "/") !== "/";
@@ -2508,7 +2543,7 @@ function getOrigin(url) {
2508
2543
  }
2509
2544
  }
2510
2545
  //#endregion
2511
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/fetch-plugins.mjs
2546
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/fetch-plugins.mjs
2512
2547
  const redirectPlugin = {
2513
2548
  id: "redirect",
2514
2549
  name: "Redirect",
@@ -2523,7 +2558,7 @@ const redirectPlugin = {
2523
2558
  } }
2524
2559
  };
2525
2560
  //#endregion
2526
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/session-atom.mjs
2561
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/session-atom.mjs
2527
2562
  function getSessionAtom($fetch, options) {
2528
2563
  const $signal = /* @__PURE__ */ atom(false);
2529
2564
  const session = useAuthQuery($signal, "/get-session", $fetch, { method: "GET" });
@@ -3010,7 +3045,7 @@ var betterFetch = async (url, options) => {
3010
3045
  };
3011
3046
  };
3012
3047
  //#endregion
3013
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/config.mjs
3048
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/config.mjs
3014
3049
  const resolvePublicAuthUrl = (basePath) => {
3015
3050
  if (typeof process === "undefined") return void 0;
3016
3051
  const path = basePath ?? "/api/auth";
@@ -3108,12 +3143,12 @@ const getClientConfig = (options, loadEnv) => {
3108
3143
  };
3109
3144
  };
3110
3145
  //#endregion
3111
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/utils/is-atom.mjs
3146
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/utils/is-atom.mjs
3112
3147
  function isAtom(value) {
3113
3148
  return typeof value === "object" && value !== null && "get" in value && typeof value.get === "function" && "lc" in value && typeof value.lc === "number";
3114
3149
  }
3115
3150
  //#endregion
3116
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/proxy.mjs
3151
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/proxy.mjs
3117
3152
  function getMethod(path, knownPathMethods, args) {
3118
3153
  const method = knownPathMethods[path];
3119
3154
  const { fetchOptions, query: _query, ...body } = args || {};
@@ -3193,7 +3228,7 @@ function capitalizeFirstLetter(str) {
3193
3228
  return str.charAt(0).toUpperCase() + str.slice(1);
3194
3229
  }
3195
3230
  //#endregion
3196
- //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._648f7a3b727ed48c95c8caf5024eaef9/node_modules/better-auth/dist/client/vanilla.mjs
3231
+ //#region ../../node_modules/.pnpm/better-auth@1.6.11_@opentelemetry+api@1.9.1_@tanstack+react-start@1.168.26_crossws@0.4._775c78039924a67af81d79c1d7be3379/node_modules/better-auth/dist/client/vanilla.mjs
3197
3232
  function createAuthClient(options) {
3198
3233
  const { pluginPathMethods, pluginsActions, pluginsAtoms, $fetch, atomListeners, $store } = getClientConfig(options);
3199
3234
  const resolvedHooks = {};
@@ -3303,8 +3338,13 @@ async function getCliJwt(platformUrl, force = false) {
3303
3338
  }
3304
3339
  //#endregion
3305
3340
  //#region src/auth/resolve-cli-auth.ts
3306
- /** Returns JWT bearer auth when a session refresh token is stored; otherwise none. */
3341
+ /** Returns API key, JWT bearer, or none auth for platform requests. */
3307
3342
  function resolveCliAuth(config) {
3343
+ const apiKey = process.env.KEYSTROKE_API_KEY?.trim();
3344
+ if (apiKey) return {
3345
+ type: "apiKey",
3346
+ getKey: () => apiKey
3347
+ };
3308
3348
  const platformUrl = getPlatformUrl(config);
3309
3349
  if (!getAccessToken(platformUrl)) return { type: "none" };
3310
3350
  return {
@@ -3351,6 +3391,7 @@ var PlatformError = class extends Error {
3351
3391
  }
3352
3392
  };
3353
3393
  async function toPlatformError(error) {
3394
+ if (error instanceof PlatformError) return error;
3354
3395
  if (!isHTTPError(error)) return new PlatformError(error instanceof Error ? error.message : "Request failed", 0, null);
3355
3396
  const status = error.response.status;
3356
3397
  const body = error.data ?? null;
@@ -3421,7 +3462,7 @@ function createDeploymentsResource(http) {
3421
3462
  return { async listForProject(projectId) {
3422
3463
  try {
3423
3464
  const data = await http.get(`/api/projects/${encodeURIComponent(projectId)}/deployments`).json();
3424
- return ListProjectDeploymentsResponseSchema.parse(data).deployments;
3465
+ return ListProjectDeploymentsResponseSchema.parse(data);
3425
3466
  } catch (error) {
3426
3467
  throw await toPlatformError(error);
3427
3468
  }
@@ -3474,7 +3515,7 @@ function createOrganizationsResource(http, options = {}) {
3474
3515
  async function get(organizationId) {
3475
3516
  try {
3476
3517
  const data = await http.get(`/api/organizations/${organizationId}`).json();
3477
- const organization = ActiveOrganizationResponseSchema.parse(data).organization;
3518
+ const organization = ActiveOrganizationResponseSchema.parse(data);
3478
3519
  if (!organization) throw new Error("Organization was not returned");
3479
3520
  return organization;
3480
3521
  } catch (error) {
@@ -3487,7 +3528,7 @@ function createOrganizationsResource(http, options = {}) {
3487
3528
  if (!organizationId) throw new Error("No active organization");
3488
3529
  try {
3489
3530
  const data = await http.patch(`/api/organizations/${organizationId}`, { json: body }).json();
3490
- const organization = ActiveOrganizationResponseSchema.parse(data).organization;
3531
+ const organization = ActiveOrganizationResponseSchema.parse(data);
3491
3532
  if (!organization) throw new Error("Active organization was not returned");
3492
3533
  return organization;
3493
3534
  } catch (error) {
@@ -3498,7 +3539,7 @@ function createOrganizationsResource(http, options = {}) {
3498
3539
  async list() {
3499
3540
  try {
3500
3541
  const data = await http.get("/api/organizations").json();
3501
- return ListOrganizationsResponseSchema.parse(data).organizations;
3542
+ return ListOrganizationsResponseSchema.parse(data);
3502
3543
  } catch (error) {
3503
3544
  throw await toPlatformError(error);
3504
3545
  }
@@ -3530,7 +3571,7 @@ function createOrganizationsResource(http, options = {}) {
3530
3571
  const body = CreateOrganizationRequestSchema.parse(input);
3531
3572
  try {
3532
3573
  const data = await http.post("/api/organizations", { json: body }).json();
3533
- return CreateOrganizationResponseSchema.parse(data).organization;
3574
+ return CreateOrganizationResponseSchema.parse(data);
3534
3575
  } catch (error) {
3535
3576
  throw await toPlatformError(error);
3536
3577
  }
@@ -3581,6 +3622,88 @@ function createAgentsResource(http) {
3581
3622
  } catch (error) {
3582
3623
  throw await toPlatformError(error);
3583
3624
  }
3625
+ },
3626
+ /**
3627
+ * Prompting goes through the project-scoped runtime route
3628
+ * (`POST /api/projects/:projectId/agents/:slug`) so it reuses the runtime's
3629
+ * `requireProject` + `requireProjectMembership` auth — a user must belong to
3630
+ * the project to prompt its agents.
3631
+ */
3632
+ async prompt(projectId, agentSlug, input) {
3633
+ try {
3634
+ const payload = PromptInputSchema.parse(input);
3635
+ const data = await (await http.post(`api/projects/${encodeURIComponent(projectId)}/agents/${encodeURIComponent(agentSlug)}`, { json: payload })).json();
3636
+ return QueuedAgentPromptResponseSchema.parse(data);
3637
+ } catch (error) {
3638
+ throw await toPlatformError(error);
3639
+ }
3640
+ },
3641
+ async getSessionState(projectId, sessionId, options) {
3642
+ try {
3643
+ const sinceSeq = options?.sinceSeq;
3644
+ const searchParams = sinceSeq != null && sinceSeq > 0 ? { sinceSeq: String(sinceSeq) } : void 0;
3645
+ const data = await http.get(`api/projects/${encodeURIComponent(projectId)}/sessions/${encodeURIComponent(sessionId)}/state`, { searchParams }).json();
3646
+ if (data == null) return null;
3647
+ return AgentSessionChatStateResponseSchema.parse(data);
3648
+ } catch (error) {
3649
+ throw await toPlatformError(error);
3650
+ }
3651
+ },
3652
+ async listSessions(projectId, agentSlug) {
3653
+ try {
3654
+ const data = await http.get(`api/projects/${encodeURIComponent(projectId)}/agents/${encodeURIComponent(agentSlug)}/sessions`).json();
3655
+ return AgentSessionListResponseSchema.parse(data).items;
3656
+ } catch (error) {
3657
+ throw await toPlatformError(error);
3658
+ }
3659
+ },
3660
+ async listTriggers(projectId, agentSlug) {
3661
+ try {
3662
+ const data = await http.get(`api/projects/${encodeURIComponent(projectId)}/agents/${encodeURIComponent(agentSlug)}/triggers`).json();
3663
+ return AgentTriggerSummaryListResponseSchema.parse(data);
3664
+ } catch (error) {
3665
+ throw await toPlatformError(error);
3666
+ }
3667
+ },
3668
+ /** Deletes an agent-owned ephemeral trigger; throws if it is not deletable (404). */
3669
+ async deleteTrigger(projectId, agentSlug, triggerId) {
3670
+ try {
3671
+ await http.delete(`api/projects/${encodeURIComponent(projectId)}/agents/${encodeURIComponent(agentSlug)}/triggers/${encodeURIComponent(triggerId)}`);
3672
+ } catch (error) {
3673
+ throw await toPlatformError(error);
3674
+ }
3675
+ },
3676
+ async listMemoryFiles(agentId) {
3677
+ try {
3678
+ const data = await http.get(`api/agents/${encodeURIComponent(agentId)}/memory/files`).json();
3679
+ return ListAgentMemoryFilesResponseSchema.parse(data);
3680
+ } catch (error) {
3681
+ throw await toPlatformError(error);
3682
+ }
3683
+ },
3684
+ async getMemoryFileContent(agentId, path) {
3685
+ try {
3686
+ return await http.get(`api/agents/${encodeURIComponent(agentId)}/memory/files/content`, { searchParams: { path } }).text();
3687
+ } catch (error) {
3688
+ throw await toPlatformError(error);
3689
+ }
3690
+ },
3691
+ /** Persistent agent workspace files under `/workspace/agent`. */
3692
+ async listWorkspaceFiles(agentId) {
3693
+ try {
3694
+ const data = await http.get(`api/agents/${encodeURIComponent(agentId)}/workspace/files`).json();
3695
+ return ListAgentWorkspaceFilesResponseSchema.parse(data);
3696
+ } catch (error) {
3697
+ throw await toPlatformError(error);
3698
+ }
3699
+ },
3700
+ /** Content for a path from {@link listWorkspaceFiles}. */
3701
+ async getWorkspaceFileContent(agentId, path) {
3702
+ try {
3703
+ return await http.get(`api/agents/${encodeURIComponent(agentId)}/workspace/files/content`, { searchParams: { path } }).text();
3704
+ } catch (error) {
3705
+ throw await toPlatformError(error);
3706
+ }
3584
3707
  }
3585
3708
  };
3586
3709
  }
@@ -3589,7 +3712,7 @@ function createProjectsResource(http) {
3589
3712
  async list(options) {
3590
3713
  try {
3591
3714
  const data = await http.get("/api/projects", { searchParams: listSearchParams(options) }).json();
3592
- return ListProjectsResponseSchema.parse(data).projects;
3715
+ return ListProjectsResponseSchema.parse(data);
3593
3716
  } catch (error) {
3594
3717
  throw await toPlatformError(error);
3595
3718
  }
@@ -3598,7 +3721,7 @@ function createProjectsResource(http) {
3598
3721
  const body = CreateProjectRequestSchema.parse(input);
3599
3722
  try {
3600
3723
  const data = await http.post("/api/projects", { json: body }).json();
3601
- return CreateProjectResponseSchema.parse(data).project;
3724
+ return CreateProjectResponseSchema.parse(data);
3602
3725
  } catch (error) {
3603
3726
  throw await toPlatformError(error);
3604
3727
  }
@@ -3606,7 +3729,7 @@ function createProjectsResource(http) {
3606
3729
  async get(projectId) {
3607
3730
  try {
3608
3731
  const data = await http.get(`/api/projects/${encodeURIComponent(projectId)}`).json();
3609
- return ProjectResponseSchema.parse(data).project;
3732
+ return ProjectResponseSchema.parse(data);
3610
3733
  } catch (error) {
3611
3734
  throw await toPlatformError(error);
3612
3735
  }
@@ -3615,7 +3738,7 @@ function createProjectsResource(http) {
3615
3738
  const body = UpdateProjectRequestSchema.parse(patch);
3616
3739
  try {
3617
3740
  const data = await http.patch(`/api/projects/${encodeURIComponent(projectId)}`, { json: body }).json();
3618
- return ProjectResponseSchema.parse(data).project;
3741
+ return ProjectResponseSchema.parse(data);
3619
3742
  } catch (error) {
3620
3743
  throw await toPlatformError(error);
3621
3744
  }
@@ -3651,7 +3774,7 @@ function createProjectMetricsResource(http) {
3651
3774
  return { async list(options) {
3652
3775
  try {
3653
3776
  const data = await http.get("/api/projects/metrics", { searchParams: listSearchParams(options) }).json();
3654
- return ListProjectMetricsResponseSchema.parse(data).metrics;
3777
+ return ListProjectMetricsResponseSchema.parse(data);
3655
3778
  } catch (error) {
3656
3779
  throw await toPlatformError(error);
3657
3780
  }
@@ -3707,6 +3830,74 @@ function createSkillsResource(http) {
3707
3830
  }
3708
3831
  };
3709
3832
  }
3833
+ function listRunsSearchParams(query) {
3834
+ if (!query) return {};
3835
+ const params = {};
3836
+ if (query.limit !== void 0) params.limit = String(query.limit);
3837
+ if (query.cursor) params.cursor = query.cursor;
3838
+ if (query.triggerType) params.triggerType = query.triggerType;
3839
+ return params;
3840
+ }
3841
+ function createTriggersResource(http) {
3842
+ return {
3843
+ /** Triggers across the projects the caller can access in the active org. */
3844
+ async list() {
3845
+ try {
3846
+ const data = await http.get("api/triggers").json();
3847
+ return WorkspaceTriggerListResponseSchema.parse(data);
3848
+ } catch (error) {
3849
+ throw await toPlatformError(error);
3850
+ }
3851
+ },
3852
+ async get(triggerId) {
3853
+ try {
3854
+ const data = await http.get(`api/triggers/${encodeURIComponent(triggerId)}`).json();
3855
+ return WorkspaceTriggerDetailSchema.parse(data);
3856
+ } catch (error) {
3857
+ const platformError = await toPlatformError(error);
3858
+ if (platformError.status === 404) return null;
3859
+ throw platformError;
3860
+ }
3861
+ },
3862
+ /** LLM-generated markdown overview of the trigger (generated lazily on the worker). */
3863
+ async getOverview(triggerId) {
3864
+ try {
3865
+ const data = await http.get(`api/triggers/${encodeURIComponent(triggerId)}/overview`).json();
3866
+ return WorkspaceTriggerOverviewSchema.parse(data);
3867
+ } catch (error) {
3868
+ throw await toPlatformError(error);
3869
+ }
3870
+ },
3871
+ /** The trigger source file. */
3872
+ async getFile(triggerId) {
3873
+ try {
3874
+ const data = await http.get(`api/triggers/${encodeURIComponent(triggerId)}/file`).json();
3875
+ return WorkspaceTriggerFileSchema.parse(data);
3876
+ } catch (error) {
3877
+ const platformError = await toPlatformError(error);
3878
+ if (platformError.status === 404) return null;
3879
+ throw platformError;
3880
+ }
3881
+ },
3882
+ /** Every fire of the trigger (poll/webhook/cron), dispatched or not. */
3883
+ async listRuns(triggerId, query) {
3884
+ try {
3885
+ const data = await http.get(`api/triggers/${encodeURIComponent(triggerId)}/runs`, { searchParams: listRunsSearchParams(query) }).json();
3886
+ return WorkspaceTriggerRunListResponseSchema.parse(data);
3887
+ } catch (error) {
3888
+ throw await toPlatformError(error);
3889
+ }
3890
+ },
3891
+ async updateAttachment(triggerId, attachmentId, body) {
3892
+ try {
3893
+ const data = await http.patch(`api/triggers/${encodeURIComponent(triggerId)}/attachments/${encodeURIComponent(attachmentId)}`, { json: body }).json();
3894
+ return WorkspaceTriggerDetailSchema.parse(data);
3895
+ } catch (error) {
3896
+ throw await toPlatformError(error);
3897
+ }
3898
+ }
3899
+ };
3900
+ }
3710
3901
  function createTeamRequestsResource(http) {
3711
3902
  return { async submit(input) {
3712
3903
  const body = SubmitTeamRequestRequestSchema.parse(input);
@@ -3717,6 +3908,16 @@ function createTeamRequestsResource(http) {
3717
3908
  }
3718
3909
  } };
3719
3910
  }
3911
+ function createMarketingContactResource(http) {
3912
+ return { async submit(input) {
3913
+ const body = SubmitMarketingContactRequestSchema.parse(input);
3914
+ try {
3915
+ await http.post("/api/public/contact", { json: body }).json();
3916
+ } catch (error) {
3917
+ throw await toPlatformError(error);
3918
+ }
3919
+ } };
3920
+ }
3720
3921
  function createRecentsResource(http) {
3721
3922
  return {
3722
3923
  /** Always the viewer's own recents, scoped to their project memberships. */
@@ -3737,6 +3938,10 @@ function buildOAuthAuthorizeSearchParams(input) {
3737
3938
  if (projectIds.length > 0) params.projects = projectIds.join(",");
3738
3939
  if (input.createOrganizationCredential) params.org = "true";
3739
3940
  if (input.createUserProvidedCredential) params.user = "true";
3941
+ const label = input.label?.trim();
3942
+ if (label) params.label = label;
3943
+ const credentialInstanceId = input.credentialInstanceId?.trim();
3944
+ if (credentialInstanceId) params.credentialInstanceId = credentialInstanceId;
3740
3945
  return params;
3741
3946
  }
3742
3947
  function createCredentialsResource(http) {
@@ -3744,7 +3949,7 @@ function createCredentialsResource(http) {
3744
3949
  async list() {
3745
3950
  try {
3746
3951
  const data = await http.get("/api/credentials").json();
3747
- return ListCredentialsResponseSchema.parse(data).credentials;
3952
+ return ListCredentialsResponseSchema.parse(data);
3748
3953
  } catch (error) {
3749
3954
  throw await toPlatformError(error);
3750
3955
  }
@@ -3752,7 +3957,7 @@ function createCredentialsResource(http) {
3752
3957
  async get(credentialId) {
3753
3958
  try {
3754
3959
  const data = await http.get(`/api/credentials/${encodeURIComponent(credentialId)}`).json();
3755
- return GetCredentialResponseSchema.parse(data).credential;
3960
+ return GetCredentialResponseSchema.parse(data);
3756
3961
  } catch (error) {
3757
3962
  throw await toPlatformError(error);
3758
3963
  }
@@ -3761,7 +3966,7 @@ function createCredentialsResource(http) {
3761
3966
  const body = CreateCredentialsRequestSchema.parse(input);
3762
3967
  try {
3763
3968
  const data = await http.post("/api/credentials", { json: body }).json();
3764
- return CreateCredentialsResponseSchema.parse(data).credentials;
3969
+ return CreateCredentialsResponseSchema.parse(data);
3765
3970
  } catch (error) {
3766
3971
  throw await toPlatformError(error);
3767
3972
  }
@@ -3770,7 +3975,7 @@ function createCredentialsResource(http) {
3770
3975
  const body = UpdateCredentialRequestSchema.parse(patch);
3771
3976
  try {
3772
3977
  const data = await http.patch(`/api/credentials/${encodeURIComponent(credentialId)}`, { json: body }).json();
3773
- return GetCredentialResponseSchema.parse(data).credential;
3978
+ return GetCredentialResponseSchema.parse(data);
3774
3979
  } catch (error) {
3775
3980
  throw await toPlatformError(error);
3776
3981
  }
@@ -3794,25 +3999,156 @@ function createCredentialsResource(http) {
3794
3999
  } catch (error) {
3795
4000
  throw await toPlatformError(error);
3796
4001
  }
4002
+ },
4003
+ async startKeystrokeConnection(input) {
4004
+ const body = StartKeystrokeConnectionInputSchema.parse(input);
4005
+ try {
4006
+ const data = await http.post("/mcp/connections", { json: body }).json();
4007
+ return StartKeystrokeConnectionResultSchema.parse(data);
4008
+ } catch (error) {
4009
+ throw await toPlatformError(error);
4010
+ }
3797
4011
  }
3798
4012
  };
3799
4013
  }
4014
+ function parseCatalogData(schema, data) {
4015
+ const parsed = schema.safeParse(data);
4016
+ if (parsed.success) return parsed.data;
4017
+ throw new PlatformError(`Invalid catalog response: ${parsed.error.message}`, 502, data);
4018
+ }
4019
+ function catalogSearchParams(params) {
4020
+ const searchParams = new URLSearchParams();
4021
+ for (const [key, value] of Object.entries(params)) {
4022
+ if (value === void 0 || value === "") continue;
4023
+ searchParams.set(key, String(value));
4024
+ }
4025
+ return searchParams;
4026
+ }
3800
4027
  function createAppsResource(http) {
3801
- return { async listCatalog() {
3802
- try {
3803
- const data = await http.get("/api/apps").json();
3804
- return ListAppsResponseSchema.parse(data).apps;
3805
- } catch (error) {
3806
- throw await toPlatformError(error);
4028
+ return {
4029
+ async listCatalog() {
4030
+ try {
4031
+ const data = await http.get("/api/apps").json();
4032
+ return ListAppsResponseSchema.parse(data);
4033
+ } catch (error) {
4034
+ throw await toPlatformError(error);
4035
+ }
4036
+ },
4037
+ async searchCatalog(options) {
4038
+ try {
4039
+ const searchParams = catalogSearchParams({
4040
+ search: options.search,
4041
+ category: options.category,
4042
+ sort_by: options.sortBy,
4043
+ limit: options.limit,
4044
+ cursor: options.cursor
4045
+ });
4046
+ return parseCatalogData(CatalogAppsPageResponseSchema, await http.get(`/mcp/catalog/apps?${searchParams}`).json());
4047
+ } catch (error) {
4048
+ throw await toPlatformError(error);
4049
+ }
4050
+ },
4051
+ async getCatalogApp(slug) {
4052
+ try {
4053
+ return parseCatalogData(CatalogAppDetailResponseSchema, await http.get(`/mcp/catalog/apps/${encodeURIComponent(slug)}`).json());
4054
+ } catch (error) {
4055
+ throw await toPlatformError(error);
4056
+ }
4057
+ },
4058
+ async listCatalogActions(slug, options) {
4059
+ try {
4060
+ const searchParams = catalogSearchParams({
4061
+ search: options?.search,
4062
+ limit: options?.limit,
4063
+ cursor: options?.cursor
4064
+ });
4065
+ const query = searchParams.size > 0 ? `?${searchParams}` : "";
4066
+ return parseCatalogData(CatalogActionsPageResponseSchema, await http.get(`/mcp/catalog/apps/${encodeURIComponent(slug)}/actions${query}`).json());
4067
+ } catch (error) {
4068
+ throw await toPlatformError(error);
4069
+ }
4070
+ },
4071
+ async searchCatalogActions(options) {
4072
+ try {
4073
+ const searchParams = catalogSearchParams({
4074
+ search: options.search,
4075
+ limit: options.limit,
4076
+ cursor: options.cursor
4077
+ });
4078
+ return parseCatalogData(CatalogActionsPageResponseSchema, await http.get(`/mcp/catalog/actions?${searchParams}`).json());
4079
+ } catch (error) {
4080
+ throw await toPlatformError(error);
4081
+ }
4082
+ },
4083
+ async getCatalogAction(toolSlug) {
4084
+ try {
4085
+ return parseCatalogData(CatalogActionDetailResponseSchema, await http.get(`/mcp/catalog/actions/${encodeURIComponent(toolSlug)}`).json());
4086
+ } catch (error) {
4087
+ throw await toPlatformError(error);
4088
+ }
4089
+ },
4090
+ async checkSlug(slug) {
4091
+ try {
4092
+ const searchParams = new URLSearchParams({ slug });
4093
+ const data = await http.get(`/api/apps/slug-available?${searchParams}`).json();
4094
+ return AppSlugAvailabilityResponseSchema.parse(data);
4095
+ } catch (error) {
4096
+ throw await toPlatformError(error);
4097
+ }
4098
+ },
4099
+ async create(input) {
4100
+ try {
4101
+ const body = CreateCustomAppRequestSchema.parse(input);
4102
+ const data = await http.post("/api/apps", { json: body }).json();
4103
+ return CreateCustomAppResponseSchema.parse(data);
4104
+ } catch (error) {
4105
+ throw await toPlatformError(error);
4106
+ }
4107
+ },
4108
+ async get(slug) {
4109
+ try {
4110
+ const data = await http.get(`/api/apps/${encodeURIComponent(slug)}`).json();
4111
+ return GetCustomAppResponseSchema.parse(data);
4112
+ } catch (error) {
4113
+ throw await toPlatformError(error);
4114
+ }
4115
+ },
4116
+ async discoverMcp(input) {
4117
+ try {
4118
+ const data = await http.post("/api/apps/discover", { json: input }).json();
4119
+ return McpDiscoverResponseSchema.parse(data);
4120
+ } catch (error) {
4121
+ throw await toPlatformError(error);
4122
+ }
4123
+ },
4124
+ async discoverOpenApi(input) {
4125
+ try {
4126
+ const data = await http.post("/api/apps/discover-openapi", { json: input }).json();
4127
+ return OpenApiDiscoverResponseSchema.parse(data);
4128
+ } catch (error) {
4129
+ throw await toPlatformError(error);
4130
+ }
4131
+ },
4132
+ async startMcpOAuthConnection(slug, input) {
4133
+ try {
4134
+ const body = StartMcpOAuthConnectionInputSchema.parse({
4135
+ ...input,
4136
+ appSlug: slug
4137
+ });
4138
+ const data = await http.post(`/api/apps/${encodeURIComponent(slug)}/mcp/oauth/connections`, { json: body }).json();
4139
+ return StartMcpOAuthConnectionResultSchema.parse(data);
4140
+ } catch (error) {
4141
+ throw await toPlatformError(error);
4142
+ }
3807
4143
  }
3808
- } };
4144
+ };
3809
4145
  }
3810
4146
  function createMembersResource(http) {
3811
4147
  return {
3812
4148
  async listOrganizationMembers() {
3813
4149
  try {
3814
4150
  const data = await http.get("/api/members").json();
3815
- return ListOrganizationMembersResponseSchema.parse(data).members;
4151
+ return ListOrganizationMembersResponseSchema.parse(data);
3816
4152
  } catch (error) {
3817
4153
  throw await toPlatformError(error);
3818
4154
  }
@@ -3830,7 +4166,7 @@ function createMembersResource(http) {
3830
4166
  const body = UpdateOrganizationMemberRequestSchema.parse(input);
3831
4167
  try {
3832
4168
  const data = await http.patch(`/api/members/${encodeURIComponent(userId)}`, { json: body }).json();
3833
- return UpdateOrganizationMemberResponseSchema.parse(data).member;
4169
+ return UpdateOrganizationMemberResponseSchema.parse(data);
3834
4170
  } catch (error) {
3835
4171
  throw await toPlatformError(error);
3836
4172
  }
@@ -3845,7 +4181,7 @@ function createMembersResource(http) {
3845
4181
  async listForProject(projectId) {
3846
4182
  try {
3847
4183
  const data = await http.get(`/api/projects/${encodeURIComponent(projectId)}/members`).json();
3848
- return ListProjectMembersResponseSchema.parse(data).members;
4184
+ return ListProjectMembersResponseSchema.parse(data);
3849
4185
  } catch (error) {
3850
4186
  throw await toPlatformError(error);
3851
4187
  }
@@ -3866,7 +4202,7 @@ function createMembersResource(http) {
3866
4202
  const body = UpdateProjectMemberRequestSchema.parse(input);
3867
4203
  try {
3868
4204
  const data = await http.patch(`/api/projects/${encodeURIComponent(projectId)}/members/${encodeURIComponent(userId)}`, { json: body }).json();
3869
- return UpdateProjectMemberResponseSchema.parse(data).member;
4205
+ return UpdateProjectMemberResponseSchema.parse(data);
3870
4206
  } catch (error) {
3871
4207
  throw await toPlatformError(error);
3872
4208
  }
@@ -3892,7 +4228,7 @@ function createProjectSettingsResource(http) {
3892
4228
  async get(projectId) {
3893
4229
  try {
3894
4230
  const data = await http.get(`/api/projects/${encodeURIComponent(projectId)}/settings`).json();
3895
- return ProjectSettingsResponseSchema.parse(data).settings;
4231
+ return ProjectSettingsResponseSchema.parse(data);
3896
4232
  } catch (error) {
3897
4233
  throw await toPlatformError(error);
3898
4234
  }
@@ -3901,7 +4237,7 @@ function createProjectSettingsResource(http) {
3901
4237
  const body = UpdateProjectSettingsRequestSchema.parse(patch);
3902
4238
  try {
3903
4239
  const data = await http.patch(`/api/projects/${encodeURIComponent(projectId)}/settings`, { json: body }).json();
3904
- return ProjectSettingsResponseSchema.parse(data).settings;
4240
+ return ProjectSettingsResponseSchema.parse(data);
3905
4241
  } catch (error) {
3906
4242
  throw await toPlatformError(error);
3907
4243
  }
@@ -3913,7 +4249,7 @@ function createInvitationsResource(http) {
3913
4249
  async list() {
3914
4250
  try {
3915
4251
  const data = await http.get("/api/invitations").json();
3916
- return ListOrganizationInvitationsResponseSchema.parse(data).invitations;
4252
+ return ListOrganizationInvitationsResponseSchema.parse(data);
3917
4253
  } catch (error) {
3918
4254
  throw await toPlatformError(error);
3919
4255
  }
@@ -3921,7 +4257,7 @@ function createInvitationsResource(http) {
3921
4257
  async accept(invitationId) {
3922
4258
  try {
3923
4259
  const data = await http.post(`/api/invitations/${encodeURIComponent(invitationId)}/accept`).json();
3924
- return AcceptOrganizationInvitationResponseSchema.parse(data).organization;
4260
+ return AcceptOrganizationInvitationResponseSchema.parse(data);
3925
4261
  } catch (error) {
3926
4262
  throw await toPlatformError(error);
3927
4263
  }
@@ -3941,7 +4277,7 @@ function createApiKeysResource(http) {
3941
4277
  async list() {
3942
4278
  try {
3943
4279
  const data = await http.get("/api/api-keys").json();
3944
- return ListApiKeysResponseSchema.parse(data).apiKeys;
4280
+ return ListApiKeysResponseSchema.parse(data);
3945
4281
  } catch (error) {
3946
4282
  throw await toPlatformError(error);
3947
4283
  }
@@ -4140,6 +4476,7 @@ function projectChannelPlatform(app) {
4140
4476
  resourceNoun: app.gateway.resourceNoun,
4141
4477
  webhookPathHint: app.gateway.webhookPathHint,
4142
4478
  supportsChannelDirectory: app.gateway.supportsChannelDirectory,
4479
+ ...app.gateway.connectAppId ? { connectAppId: app.gateway.connectAppId } : {},
4143
4480
  docsUrl: app.gateway.docsUrl
4144
4481
  });
4145
4482
  }
@@ -4148,7 +4485,7 @@ function createChannelsResource(http) {
4148
4485
  async function listGatewayPlatforms() {
4149
4486
  try {
4150
4487
  const data = await http.get("/api/apps").json();
4151
- return ListAppsResponseSchema.parse(data).apps.filter((app) => app.gateway).map((app) => projectChannelPlatform(app));
4488
+ return ListAppsResponseSchema.parse(data).filter((app) => app.gateway).map((app) => projectChannelPlatform(app));
4152
4489
  } catch (error) {
4153
4490
  throw await toPlatformError(error);
4154
4491
  }
@@ -4160,7 +4497,7 @@ function createChannelsResource(http) {
4160
4497
  async listAccounts(projectId, platform) {
4161
4498
  try {
4162
4499
  const data = await http.get(`${projectPrefix(projectId)}/channels/${encodeURIComponent(platform)}/accounts`).json();
4163
- return ChannelAccountListResponseSchema.parse(data).accounts;
4500
+ return ChannelAccountListResponseSchema.parse(data);
4164
4501
  } catch (error) {
4165
4502
  throw await toPlatformError(error);
4166
4503
  }
@@ -4168,7 +4505,7 @@ function createChannelsResource(http) {
4168
4505
  async listForAgent(projectId, agentId) {
4169
4506
  try {
4170
4507
  const data = await http.get(`${projectPrefix(projectId)}/agents/${encodeURIComponent(agentId)}/channels`).json();
4171
- return ChannelConnectionListResponseSchema.parse(data).connections;
4508
+ return ChannelConnectionListResponseSchema.parse(data);
4172
4509
  } catch (error) {
4173
4510
  throw await toPlatformError(error);
4174
4511
  }
@@ -4176,7 +4513,7 @@ function createChannelsResource(http) {
4176
4513
  async listChannels(projectId, platform, accountId) {
4177
4514
  try {
4178
4515
  const data = await http.get(`${projectPrefix(projectId)}/channels/${encodeURIComponent(platform)}/directory`, { searchParams: { accountId } }).json();
4179
- return ChannelDirectoryListResponseSchema.parse(data).channels;
4516
+ return ChannelDirectoryListResponseSchema.parse(data);
4180
4517
  } catch (error) {
4181
4518
  throw await toPlatformError(error);
4182
4519
  }
@@ -4256,6 +4593,7 @@ function createPlatformClient(options) {
4256
4593
  agents: createAgentsResource(http),
4257
4594
  workflows: createWorkflowsResource(http),
4258
4595
  skills: createSkillsResource(http),
4596
+ triggers: createTriggersResource(http),
4259
4597
  apps: createAppsResource(http),
4260
4598
  credentials: createCredentialsResource(http),
4261
4599
  history: createHistoryResource(http),
@@ -4272,6 +4610,7 @@ function createPlatformClient(options) {
4272
4610
  userAvatar: createUserAvatarResource(http),
4273
4611
  organizationSidebarBranding: createOrganizationSidebarBrandingResource(http, { getActiveOrganizationId: () => activeOrganizationId }),
4274
4612
  teamRequests: createTeamRequestsResource(http),
4613
+ marketingContact: createMarketingContactResource(http),
4275
4614
  getActiveOrganizationId: () => activeOrganizationId,
4276
4615
  setActiveOrganizationId
4277
4616
  };
@@ -4394,6 +4733,49 @@ async function ensureActiveOrganization(config) {
4394
4733
  throw new Error("No active organization. Run `keystroke auth login` or `keystroke config use org`.");
4395
4734
  }
4396
4735
  //#endregion
4736
+ //#region src/project/resolve-project-root.ts
4737
+ function hasProjectLayout(dir) {
4738
+ return existsSync(join(dir, "package.json")) && existsSync(join(dir, "src", "agents"));
4739
+ }
4740
+ function resolveProjectRoot(fromDir = process.cwd()) {
4741
+ let dir = resolve(fromDir);
4742
+ while (dir !== dirname(dir)) {
4743
+ if (hasProjectLayout(dir)) return dir;
4744
+ dir = dirname(dir);
4745
+ }
4746
+ if (hasProjectLayout(dir)) return dir;
4747
+ throw new Error("Could not find keystroke project root (expected package.json and src/agents/)");
4748
+ }
4749
+ //#endregion
4750
+ //#region src/project/load-project-env.ts
4751
+ let loaded = false;
4752
+ function parseEnvFile(contents) {
4753
+ const values = {};
4754
+ for (const line of contents.split("\n")) {
4755
+ const trimmed = line.trim();
4756
+ if (!trimmed || trimmed.startsWith("#")) continue;
4757
+ const eq = trimmed.indexOf("=");
4758
+ if (eq === -1) continue;
4759
+ const key = trimmed.slice(0, eq).trim();
4760
+ let value = trimmed.slice(eq + 1).trim();
4761
+ if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
4762
+ values[key] = value;
4763
+ }
4764
+ return values;
4765
+ }
4766
+ function loadProjectEnv(fromDir = process.cwd()) {
4767
+ if (loaded) return;
4768
+ loaded = true;
4769
+ let envPath;
4770
+ try {
4771
+ envPath = join(resolveProjectRoot(fromDir), ".env");
4772
+ } catch {
4773
+ return;
4774
+ }
4775
+ if (!existsSync(envPath)) return;
4776
+ for (const [key, value] of Object.entries(parseEnvFile(readFileSync(envPath, "utf8")))) if (process.env[key] === void 0) process.env[key] = value;
4777
+ }
4778
+ //#endregion
4397
4779
  //#region src/dev-session.ts
4398
4780
  function getDevSessionPath(configDir = getCliConfigDir()) {
4399
4781
  return join(configDir, "dev-session.json");
@@ -4432,13 +4814,30 @@ function readDevSession(configDir = getCliConfigDir()) {
4432
4814
  }
4433
4815
  //#endregion
4434
4816
  //#region src/resolve-api-target.ts
4817
+ /** Standalone local server default project id — keep in sync with @keystrokehq/database. */
4818
+ const DEFAULT_LOCAL_PROJECT_ID = "default";
4435
4819
  const projectScopedTarget = { projectScoped: true };
4436
- function resolveLocalTarget(config) {
4820
+ function resolveLocalTargetFromOrigin(origin, options = {}) {
4821
+ const base = origin.replace(/\/+$/, "");
4822
+ if (!options.projectScoped) return {
4823
+ baseUrl: base,
4824
+ mode: "local"
4825
+ };
4826
+ const projectPathMatch = base.match(/^(.*\/api\/projects\/([^/]+))$/);
4827
+ if (projectPathMatch) return {
4828
+ baseUrl: projectPathMatch[1],
4829
+ projectId: projectPathMatch[2],
4830
+ mode: "local"
4831
+ };
4437
4832
  return {
4438
- baseUrl: getServerUrl(config),
4833
+ baseUrl: `${base}/api/projects/${DEFAULT_LOCAL_PROJECT_ID}`,
4834
+ projectId: DEFAULT_LOCAL_PROJECT_ID,
4439
4835
  mode: "local"
4440
4836
  };
4441
4837
  }
4838
+ function resolveLocalTarget(options = {}) {
4839
+ return resolveLocalTargetFromOrigin(resolvePublicPlatformOrigin(process.env), options);
4840
+ }
4442
4841
  function resolveOrgPlatformTarget(config) {
4443
4842
  return {
4444
4843
  baseUrl: `${getPlatformUrl(config).replace(/\/+$/, "")}/api`,
@@ -4462,18 +4861,16 @@ async function resolvePlatformTarget(config, projectRef) {
4462
4861
  };
4463
4862
  }
4464
4863
  async function resolveApiTarget(config, options = {}) {
4465
- if (options.local) return resolveLocalTarget(config);
4864
+ loadProjectEnv(process.cwd());
4865
+ if (options.local) return resolveLocalTarget(options);
4466
4866
  const devSession = readDevSession(getConfigDir(config));
4467
- if (devSession && getEffectiveApiTarget(config) !== "platform") return {
4468
- baseUrl: devSession.serverUrl,
4469
- mode: "local"
4470
- };
4867
+ if (devSession && getEffectiveApiTarget(config) !== "platform") return resolveLocalTargetFromOrigin(devSession.serverUrl, options);
4471
4868
  if (options.orgScoped || options.projectScoped === false) {
4472
- if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(config);
4869
+ if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
4473
4870
  return resolveOrgPlatformTarget(config);
4474
4871
  }
4475
4872
  if (options.projectId) return resolvePlatformTarget(config, options.projectId);
4476
- if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(config);
4873
+ if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
4477
4874
  if (!options.projectScoped) return resolveOrgPlatformTarget(config);
4478
4875
  const projectRef = options.projectId ?? config.get("activeProjectId");
4479
4876
  if (!projectRef) throw new Error("No project selected. Pass `--project <slug>` or run `keystroke config use project <slug>`.");
@@ -4560,7 +4957,13 @@ function formatHttpClientError(error, context) {
4560
4957
  if (origin && !getAccessToken(origin)) return "Not logged in. Run `keystroke auth login` first.";
4561
4958
  return "Authentication failed. Run `keystroke auth login` again.";
4562
4959
  }
4563
- if (error.status === 0) return unreachableServerMessage(unreachableTarget(context));
4960
+ if (error.status === 403) {
4961
+ if (parseErrorResponse(error.body)?.code === "org_unverified") return "This organization is pending verification. Request access in the Keystroke dashboard.";
4962
+ }
4963
+ if (error.status === 0) {
4964
+ if (error.message && !isUnreachableServerError(error)) return error.message;
4965
+ return unreachableServerMessage(unreachableTarget(context));
4966
+ }
4564
4967
  const parsed = parseErrorResponse(error.body);
4565
4968
  if (parsed) return formatApiErrorMessage(parsed, error.message, context);
4566
4969
  return error.message;
@@ -4845,13 +5248,128 @@ function registerApiKeyCommand(program) {
4845
5248
  });
4846
5249
  }
4847
5250
  //#endregion
4848
- //#region src/commands/app/run-app-list.ts
4849
- async function runAppList(client) {
4850
- return client.apps.listCatalog();
5251
+ //#region src/commands/app/run-app-catalog.ts
5252
+ async function runAppSearch(client, query, options) {
5253
+ const trimmed = query.trim();
5254
+ if (!trimmed) throw new Error("Search query is required");
5255
+ return client.apps.searchCatalog({
5256
+ search: trimmed,
5257
+ category: options?.category,
5258
+ limit: options?.limit,
5259
+ cursor: options?.cursor
5260
+ });
4851
5261
  }
4852
- //#endregion
4853
- //#region src/commands/app/list.ts
4854
- function registerAppListCommand(app) {
5262
+ async function runAppShow(client, slug) {
5263
+ const trimmed = slug.trim();
5264
+ if (!trimmed) throw new Error("App slug is required");
5265
+ return client.apps.getCatalogApp(trimmed);
5266
+ }
5267
+ async function runAppActions(client, options) {
5268
+ const slug = options.slug?.trim();
5269
+ const search = options.search?.trim();
5270
+ if (slug) return client.apps.listCatalogActions(slug, {
5271
+ search,
5272
+ limit: options.limit,
5273
+ cursor: options.cursor
5274
+ });
5275
+ if (!search) throw new Error("App slug or --search is required");
5276
+ return client.apps.searchCatalogActions({
5277
+ search,
5278
+ limit: options.limit,
5279
+ cursor: options.cursor
5280
+ });
5281
+ }
5282
+ async function runAppAction(client, toolSlug) {
5283
+ const trimmed = toolSlug.trim();
5284
+ if (!trimmed) throw new Error("Tool slug is required");
5285
+ return client.apps.getCatalogAction(trimmed);
5286
+ }
5287
+ //#endregion
5288
+ //#region src/commands/app/action.ts
5289
+ function registerAppActionCommand(app) {
5290
+ 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 () => {
5291
+ const config = createCliConfig();
5292
+ const client = createCliPlatformClient(config);
5293
+ await ensureActiveOrganization(config);
5294
+ const result = await runAppAction(client, toolSlug);
5295
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5296
+ }, void 0, { orgScoped: true }));
5297
+ }
5298
+ //#endregion
5299
+ //#region src/commands/app/actions.ts
5300
+ function registerAppActionsCommand(app) {
5301
+ 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 () => {
5302
+ const config = createCliConfig();
5303
+ const client = createCliPlatformClient(config);
5304
+ await ensureActiveOrganization(config);
5305
+ const result = await runAppActions(client, {
5306
+ slug,
5307
+ ...options
5308
+ });
5309
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5310
+ }, void 0, { orgScoped: true }));
5311
+ }
5312
+ //#endregion
5313
+ //#region src/commands/app/parse-custom-app-fields.ts
5314
+ function parseCustomAppFieldFlag(value) {
5315
+ const parts = value.split(":").map((part) => part.trim()).filter(Boolean);
5316
+ const key = parts[0];
5317
+ if (!key || !/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)) throw new Error(`Invalid field key in --field ${JSON.stringify(value)}`);
5318
+ const optional = parts.includes("optional");
5319
+ return {
5320
+ key,
5321
+ secret: parts.includes("public") ? false : parts.includes("secret") || !optional,
5322
+ optional
5323
+ };
5324
+ }
5325
+ function parseCustomAppFields(flags) {
5326
+ const fields = {};
5327
+ for (const flag of flags) {
5328
+ const parsed = parseCustomAppFieldFlag(flag);
5329
+ fields[parsed.key] = {
5330
+ ...parsed.secret ? { secret: true } : {},
5331
+ ...parsed.optional ? { optional: true } : {}
5332
+ };
5333
+ }
5334
+ if (Object.keys(fields).length === 0) throw new Error("At least one --field is required");
5335
+ if (!Object.values(fields).some((field) => field.optional !== true)) return fields;
5336
+ if (!Object.values(fields).some((field) => field.optional !== true)) throw new Error("At least one --field must be required (omit :optional)");
5337
+ return fields;
5338
+ }
5339
+ function collectValues$1(value, previous) {
5340
+ return [...previous, value];
5341
+ }
5342
+ //#endregion
5343
+ //#region src/commands/app/run-app-create.ts
5344
+ async function runAppCreate(client, input) {
5345
+ return client.apps.create(input);
5346
+ }
5347
+ //#endregion
5348
+ //#region src/commands/app/create.ts
5349
+ function registerAppCreateCommand(app) {
5350
+ app.command("create").description("Create a custom org api_key app").requiredOption("--name <name>", "App display name").option("--slug <slug>", "App slug segment (defaults from name)").requiredOption("--description <description>", "App description").option("--field <field>", "Credential field as key, key:secret, key:optional, or key:secret:optional (repeatable)", collectValues$1, []).action((options) => runCliCommand("Create app failed", async () => {
5351
+ const config = createCliConfig();
5352
+ const client = createCliPlatformClient(config);
5353
+ await ensureActiveOrganization(config);
5354
+ const slug = options.slug?.trim() || slugifyAppName(options.name);
5355
+ const created = await runAppCreate(client, {
5356
+ name: options.name.trim(),
5357
+ slug,
5358
+ description: options.description,
5359
+ source: "custom",
5360
+ fields: parseCustomAppFields(options.field)
5361
+ });
5362
+ process.stdout.write(`${JSON.stringify(created, null, 2)}\n`);
5363
+ }, void 0, { orgScoped: true }));
5364
+ }
5365
+ //#endregion
5366
+ //#region src/commands/app/run-app-list.ts
5367
+ async function runAppList(client) {
5368
+ return client.apps.listCatalog();
5369
+ }
5370
+ //#endregion
5371
+ //#region src/commands/app/list.ts
5372
+ function registerAppListCommand(app) {
4855
5373
  app.command("list").description("List connectable apps in the active organization").action(() => runCliCommand("List apps failed", async () => {
4856
5374
  const config = createCliConfig();
4857
5375
  const client = createCliPlatformClient(config);
@@ -4861,26 +5379,111 @@ function registerAppListCommand(app) {
4861
5379
  }, void 0, { orgScoped: true }));
4862
5380
  }
4863
5381
  //#endregion
4864
- //#region src/commands/app/index.ts
4865
- function registerAppCommand(program) {
4866
- registerAppListCommand(program.command("app").description("Browse connectable integrations"));
5382
+ //#region src/commands/app/search.ts
5383
+ function registerAppSearchCommand(app) {
5384
+ app.command("search").description("Search the Composio app catalog (live)").argument("<query>", "Search query").option("--category <category>", "Filter by category").option("--limit <n>", "Page size", (value) => Number.parseInt(value, 10)).option("--cursor <cursor>", "Pagination cursor").action((query, options) => runCliCommand("App search failed", async () => {
5385
+ const config = createCliConfig();
5386
+ const client = createCliPlatformClient(config);
5387
+ await ensureActiveOrganization(config);
5388
+ const result = await runAppSearch(client, query, options);
5389
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5390
+ }, void 0, { orgScoped: true }));
4867
5391
  }
4868
5392
  //#endregion
4869
- //#region src/commands/connect/parse-connect-scopes.ts
4870
- function parseConnectScopes(scopes, projectSlugs) {
4871
- const normalized = scopes.length > 0 ? scopes : ["org"];
4872
- for (const scope of normalized) if (scope !== "org" && scope !== "user" && scope !== "project") throw new Error(`Unknown scope "${scope}". Expected org, user, or project.`);
4873
- const createOrganizationCredential = normalized.includes("org");
4874
- const createUserProvidedCredential = normalized.includes("user");
4875
- const includesProject = normalized.includes("project");
4876
- const selectedProjects = includesProject ? projectSlugs : [];
4877
- if (includesProject && selectedProjects.length === 0) throw new Error("--project-slug is required when scope includes project");
4878
- if (!createOrganizationCredential && !createUserProvidedCredential && selectedProjects.length === 0) throw new Error("At least one scope is required via --scope and/or --project-slug");
4879
- return {
4880
- createOrganizationCredential,
4881
- createUserProvidedCredential,
4882
- projects: selectedProjects
4883
- };
5393
+ //#region src/commands/app/show.ts
5394
+ function registerAppShowCommand(app) {
5395
+ app.command("show").description("Show a Composio app from the live catalog").argument("<slug>", "App slug").action((slug) => runCliCommand("App show failed", async () => {
5396
+ const config = createCliConfig();
5397
+ const client = createCliPlatformClient(config);
5398
+ await ensureActiveOrganization(config);
5399
+ const result = await runAppShow(client, slug);
5400
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5401
+ }, void 0, { orgScoped: true }));
5402
+ }
5403
+ //#endregion
5404
+ //#region src/project/resolve-keystroke-config-root.ts
5405
+ const KEYSTROKE_CONFIG = "keystroke.config.ts";
5406
+ /** Walk up from `fromDir` and return the directory containing `keystroke.config.ts`, if any. */
5407
+ function resolveKeystrokeConfigRoot(fromDir = process.cwd()) {
5408
+ let dir = resolve(fromDir);
5409
+ while (dir !== dirname(dir)) {
5410
+ if (existsSync(join(dir, KEYSTROKE_CONFIG))) return dir;
5411
+ dir = dirname(dir);
5412
+ }
5413
+ if (existsSync(join(dir, KEYSTROKE_CONFIG))) return dir;
5414
+ return null;
5415
+ }
5416
+ //#endregion
5417
+ //#region src/commands/app/generate-app-stub.ts
5418
+ function slugPartToExportName(part) {
5419
+ 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("");
5420
+ }
5421
+ function resolveSyncedAppExportName(slug) {
5422
+ const parsed = parseAppSlug(slug);
5423
+ const exportName = slugPartToExportName(parsed.kind === "org" ? parsed.name : parsed.slug);
5424
+ if (!exportName) throw new Error(`Cannot derive export name from app slug: ${slug}`);
5425
+ return exportName;
5426
+ }
5427
+ function resolveSyncedAppDirName(slug) {
5428
+ const parsed = parseAppSlug(slug);
5429
+ return parsed.kind === "org" ? parsed.name : parsed.slug;
5430
+ }
5431
+ function generateAppStub(app) {
5432
+ const exportName = resolveSyncedAppExportName(app.slug);
5433
+ const credentialLines = Object.entries(app.credentialFields ?? {}).map(([key, field]) => {
5434
+ return ` ${key}: ${field.optional ? "z.string().optional()" : "z.string()"},`;
5435
+ }).join("\n");
5436
+ return `import { defineApp } from "@keystrokehq/keystroke/app";
5437
+ import { z } from "zod";
5438
+
5439
+ /** Synced from platform app \`${app.slug}\`. Re-run \`keystroke app sync ${app.slug}\` after template changes. */
5440
+ export const ${exportName} = defineApp({
5441
+ slug: ${JSON.stringify(app.slug)},
5442
+ auth: "api_key",
5443
+ credential: {
5444
+ ${credentialLines}
5445
+ },
5446
+ });
5447
+ `;
5448
+ }
5449
+ //#endregion
5450
+ //#region src/commands/app/run-app-sync.ts
5451
+ async function runAppSync(options) {
5452
+ const projectRoot = resolveKeystrokeConfigRoot(options.dir ?? process.cwd());
5453
+ if (!projectRoot) throw new Error("Not in a keystroke project (keystroke.config.ts not found)");
5454
+ const app = await options.client.apps.get(options.slug);
5455
+ const appDir = join(projectRoot, "src", "apps", resolveSyncedAppDirName(app.slug));
5456
+ const outputPath = join(appDir, "app.ts");
5457
+ await mkdir(appDir, { recursive: true });
5458
+ await writeFile(outputPath, generateAppStub(app), "utf8");
5459
+ return { outputPath };
5460
+ }
5461
+ //#endregion
5462
+ //#region src/commands/app/sync.ts
5463
+ function registerAppSyncCommand(app) {
5464
+ app.command("sync").description("Sync a custom app credential template into src/apps/<name>/app.ts").argument("<slug>", "App slug, e.g. acme/internal-api").option("--dir <dir>", "Project root (defaults to cwd)").action((slug, options) => runCliCommand("Sync app failed", async () => {
5465
+ const config = createCliConfig();
5466
+ const client = createCliPlatformClient(config);
5467
+ await ensureActiveOrganization(config);
5468
+ const result = await runAppSync({
5469
+ client,
5470
+ slug,
5471
+ ...options.dir !== void 0 ? { dir: options.dir } : {}
5472
+ });
5473
+ process.stdout.write(`Wrote ${result.outputPath}\n`);
5474
+ }, void 0, { orgScoped: true }));
5475
+ }
5476
+ //#endregion
5477
+ //#region src/commands/app/index.ts
5478
+ function registerAppCommand(program) {
5479
+ const app = program.command("app").description("Browse connectable integrations");
5480
+ registerAppListCommand(app);
5481
+ registerAppSearchCommand(app);
5482
+ registerAppShowCommand(app);
5483
+ registerAppActionsCommand(app);
5484
+ registerAppActionCommand(app);
5485
+ registerAppCreateCommand(app);
5486
+ registerAppSyncCommand(app);
4884
5487
  }
4885
5488
  //#endregion
4886
5489
  //#region src/auth/open-url.ts
@@ -4893,101 +5496,138 @@ function openUrl(url) {
4893
5496
  }
4894
5497
  //#endregion
4895
5498
  //#region src/commands/connect/run-connect.ts
4896
- function providerLabel(key) {
4897
- return key.charAt(0).toUpperCase() + key.slice(1);
4898
- }
4899
- async function runConnect(options) {
4900
- const { client, platform, provider, serverUrl, printUrl, oauthScopes = [], credentialScopes } = options;
4901
- const label = providerLabel(provider.key);
4902
- if (provider.mode === "browser-redirect") {
4903
- const url = `${serverUrl}${provider.path}`;
4904
- if (printUrl) {
4905
- process.stdout.write(`${url}\n`);
4906
- return;
4907
- }
4908
- openUrl(url);
4909
- process.stdout.write(`Complete ${label} sign-in in your browser.\n`);
4910
- return;
4911
- }
4912
- if (platform) {
4913
- const scopes = credentialScopes ?? parseConnectScopes([], []);
4914
- const result = await platform.credentials.startOAuthConnection({
4915
- appId: provider.key,
4916
- scopes: oauthScopes,
4917
- permissionMode: "default",
4918
- projects: scopes.projects,
4919
- createOrganizationCredential: scopes.createOrganizationCredential,
4920
- createUserProvidedCredential: scopes.createUserProvidedCredential
4921
- });
4922
- if (!result.authorizeUrl) throw new Error("OAuth provider did not return an authorize URL");
4923
- if (oauthScopes.length > 0) {
4924
- process.stdout.write("Requested OAuth scopes:\n");
4925
- for (const scope of oauthScopes) process.stdout.write(` - ${scope}\n`);
4926
- process.stdout.write("\n");
4927
- }
4928
- if (printUrl) {
4929
- process.stdout.write(`${result.authorizeUrl}\n`);
4930
- return;
4931
- }
4932
- openUrl(result.authorizeUrl);
4933
- process.stdout.write(`Complete ${label} sign-in in your browser.\n`);
4934
- return;
5499
+ function resolveConnectAppSlug(slug, apps) {
5500
+ const trimmed = slug.trim();
5501
+ if (!trimmed) throw new Error("App slug is required");
5502
+ try {
5503
+ parseAppSlug(trimmed);
5504
+ } catch {
5505
+ throw new Error(`Invalid app slug: ${slug}`);
4935
5506
  }
4936
- const payload = await client.connect.getAuthorizeUrl(provider.path);
4937
- const scopes = new URL(payload.url).searchParams.get("scope")?.split(" ").filter(Boolean) ?? [];
4938
- if (scopes.length > 0) {
4939
- process.stdout.write("Requested scopes:\n");
4940
- for (const scope of scopes) process.stdout.write(` - ${scope}\n`);
4941
- process.stdout.write("\n");
5507
+ const match = apps.find((app) => app.id === trimmed);
5508
+ if (!match) {
5509
+ const available = apps.map((app) => app.id).join(", ") || "(none)";
5510
+ throw new Error(`Unknown app "${trimmed}". Available: ${available}`);
4942
5511
  }
4943
- if (printUrl) {
4944
- process.stdout.write(`${payload.url}\n`);
5512
+ return match;
5513
+ }
5514
+ async function runConnect(options) {
5515
+ const apps = await options.platform.apps.listCatalog();
5516
+ const app = resolveConnectAppSlug(options.slug, apps);
5517
+ const url = buildConnectDeeplink({
5518
+ webUrl: options.webUrl,
5519
+ orgSlug: options.orgSlug,
5520
+ appSlug: app.id
5521
+ });
5522
+ if (options.printUrl) {
5523
+ process.stdout.write(`${url}\n`);
4945
5524
  return;
4946
5525
  }
4947
- openUrl(payload.url);
4948
- process.stdout.write(`Complete ${label} sign-in in your browser.\n`);
5526
+ openUrl(url);
5527
+ process.stdout.write(`Opening ${app.name} connect flow in your browser.\n`);
4949
5528
  }
4950
5529
  //#endregion
4951
5530
  //#region src/commands/connect/index.ts
4952
- function resolveConnectTargetOptions() {
4953
- const { local } = getCliTargetOptions();
4954
- if (local) return { local: true };
4955
- return { orgScoped: true };
4956
- }
4957
- function collectValues$1(value, previous) {
4958
- return previous.concat([value]);
4959
- }
4960
5531
  function registerConnectCommand(program) {
4961
- program.command("connect [provider]").description("Connect third-party accounts (uses apiTarget; --local for local server)").option("--oauth-scope <scope>", "OAuth permission scope to request (repeatable)", collectValues$1, []).option("--scope <scope>", "Credential scope: org, user, or project (repeatable)", collectValues$1, []).option("--project-slug <slug>", "Project slug when scope includes project (repeatable)", collectValues$1, []).option("--print-url", "Print the authorize URL and exit without opening the browser").action((provider, options) => runCliCommand("Could not fetch connect providers", async (ctx) => {
4962
- const providers = await ctx.client.connect.listProviders();
4963
- if (!provider) {
4964
- if (providers.length === 0) {
4965
- process.stdout.write("No connect providers available on this server.\n");
4966
- return;
4967
- }
4968
- process.stdout.write("Available providers:\n");
4969
- for (const entry of providers) process.stdout.write(` ${entry.key}\n`);
4970
- return;
4971
- }
4972
- const match = providers.find((entry) => entry.key === provider);
4973
- if (!match) {
4974
- const available = providers.map((entry) => entry.key).join(", ") || "(none)";
4975
- throw new Error(`Unknown provider "${provider}". Available: ${available}`);
4976
- }
4977
- const hasScopeFlags = options.scope.length > 0 || options.projectSlug.length > 0;
4978
- if (ctx.apiTarget.mode === "local" && hasScopeFlags) throw new Error("--scope and --project-slug are only supported against the platform API (omit --local)");
4979
- const credentialScopes = ctx.apiTarget.mode === "platform" ? parseConnectScopes(options.scope, options.projectSlug) : void 0;
4980
- const platform = ctx.apiTarget.mode === "platform" ? createCliPlatformClient(createCliConfig()) : void 0;
5532
+ program.command("connect <slug>").description("Open the web app to connect an integration by catalog slug").option("--print-url", "Print the connect URL and exit without opening the browser").action((slug, options) => runCliCommand("Connect failed", async () => {
5533
+ const config = createCliConfig();
5534
+ await ensureActiveOrganization(config);
5535
+ const organizations = await listOrganizations(config);
5536
+ const activeOrganizationId = config.get("activeOrganizationId");
5537
+ const activeOrg = organizations.find((entry) => entry.organization.id === activeOrganizationId);
5538
+ if (!activeOrg) throw new Error("No active organization. Run `keystroke auth login` or `keystroke config use org`.");
4981
5539
  await runConnect({
4982
- client: ctx.client,
4983
- platform,
4984
- provider: match,
4985
- serverUrl: ctx.serverUrl,
4986
- printUrl: options.printUrl,
4987
- oauthScopes: options.oauthScope,
4988
- credentialScopes
5540
+ platform: createCliPlatformClient(config),
5541
+ webUrl: getWebUrl(config),
5542
+ orgSlug: activeOrg.organization.slug,
5543
+ slug,
5544
+ printUrl: options.printUrl
5545
+ });
5546
+ }, void 0, { orgScoped: true }));
5547
+ }
5548
+ //#endregion
5549
+ //#region src/commands/credentials/parse-assignment-target.ts
5550
+ function parseAssignmentTarget(options) {
5551
+ const agent = options.agent?.trim();
5552
+ const workflow = options.workflow?.trim();
5553
+ if (agent && workflow) throw new Error("Exactly one of --agent or --workflow is required");
5554
+ if (agent) return {
5555
+ targetType: "agent",
5556
+ targetKey: agent
5557
+ };
5558
+ if (workflow) return {
5559
+ targetType: "workflow",
5560
+ targetKey: workflow
5561
+ };
5562
+ throw new Error("Exactly one of --agent or --workflow is required");
5563
+ }
5564
+ //#endregion
5565
+ //#region src/commands/credentials/assignments/assign.ts
5566
+ function registerCredentialsAssignmentsAssignCommand(assignments) {
5567
+ assignments.command("assign").description("Assign a credential instance to a workflow step or agent tool").option("--agent <key>", "Agent slug").option("--workflow <key>", "Workflow slug").requiredOption("--credential <slug>", "Credential instance slug (e.g. work, org/work, linear/work)").option("--consumer <id>", "Consumer id (step correlation id or tool slug); omit for wildcard (*)").addHelpText("after", `
5568
+ Examples:
5569
+ ${cliBinaryName()} credentials assignments assign --workflow sync --credential work
5570
+ ${cliBinaryName()} credentials assignments assign --workflow sync --credential org/work --consumer step:fetch-gmail#0
5571
+ ${cliBinaryName()} credentials assignments assign --agent support --credential vault-prod --consumer vault-lookup
5572
+ ${cliBinaryName()} credentials assignments assign --agent pm --credential linear/work
5573
+ `).action((options) => runProjectCliCommand("Assign credential failed", async ({ client }) => {
5574
+ const target = parseAssignmentTarget(options);
5575
+ const assignment = await client.credentials.assignCredential({
5576
+ targetType: target.targetType,
5577
+ targetKey: target.targetKey,
5578
+ credential: options.credential,
5579
+ ...options.consumer ? { consumerId: options.consumer } : {}
5580
+ });
5581
+ process.stdout.write(`${JSON.stringify(assignment, null, 2)}\n`);
5582
+ }));
5583
+ }
5584
+ //#endregion
5585
+ //#region src/commands/credentials/assignments/list.ts
5586
+ function registerCredentialsAssignmentsListCommand(assignments) {
5587
+ assignments.command("list").description("List credential assignments for a workflow or agent").option("--agent <key>", "Agent slug").option("--workflow <key>", "Workflow slug").action((options) => runProjectCliCommand("List credential assignments failed", async ({ client }) => {
5588
+ const target = parseAssignmentTarget(options);
5589
+ const result = await client.credentials.listAssignments({
5590
+ targetType: target.targetType,
5591
+ targetKey: target.targetKey
5592
+ });
5593
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5594
+ }));
5595
+ }
5596
+ //#endregion
5597
+ //#region src/commands/credentials/assignments/unassign.ts
5598
+ function registerCredentialsAssignmentsUnassignCommand(assignments) {
5599
+ assignments.command("unassign").description("Remove a credential assignment by id").argument("<id>", "Credential assignment id").action((id) => runProjectCliCommand("Unassign credential failed", async ({ client }) => {
5600
+ await client.credentials.unassignCredential(id);
5601
+ }));
5602
+ }
5603
+ //#endregion
5604
+ //#region src/commands/credentials/assignments/index.ts
5605
+ function registerCredentialsAssignmentsCommands(credentials) {
5606
+ const assignments = credentials.command("assignments").description("Assign credential instances to workflow steps or agent tools");
5607
+ registerCredentialsAssignmentsListCommand(assignments);
5608
+ registerCredentialsAssignmentsAssignCommand(assignments);
5609
+ registerCredentialsAssignmentsUnassignCommand(assignments);
5610
+ }
5611
+ //#endregion
5612
+ //#region src/commands/credentials/consumers/list.ts
5613
+ function registerCredentialsConsumersListCommand(consumers) {
5614
+ consumers.command("list").description("List bindable consumers for a workflow or agent").option("--agent <key>", "Agent slug").option("--workflow <key>", "Workflow slug").addHelpText("after", `
5615
+ Workflow consumers come from recent step_completed events (e.g. step:fetch-gmail#0).
5616
+ Agent consumers include known tool slugs when available, plus any from existing assignments.
5617
+ Use consumer id "*" (wildcard) or omit --consumer on assignments assign to bind all consumers.
5618
+ `).action((options) => runProjectCliCommand("List credential consumers failed", async ({ client }) => {
5619
+ const target = parseAssignmentTarget(options);
5620
+ const result = await client.credentials.listConsumers({
5621
+ targetType: target.targetType,
5622
+ targetKey: target.targetKey
4989
5623
  });
4990
- }, void 0, resolveConnectTargetOptions()));
5624
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5625
+ }));
5626
+ }
5627
+ //#endregion
5628
+ //#region src/commands/credentials/consumers/index.ts
5629
+ function registerCredentialsConsumersCommands(credentials) {
5630
+ registerCredentialsConsumersListCommand(credentials.command("consumers").description("Discover workflow step and agent tool consumer ids for assignment"));
4991
5631
  }
4992
5632
  //#endregion
4993
5633
  //#region src/commands/credentials/target-options.ts
@@ -5066,13 +5706,13 @@ function buildPlatformUpdatePatch(args) {
5066
5706
  //#endregion
5067
5707
  //#region src/commands/credentials/delete.ts
5068
5708
  function registerCredentialsDeleteCommand(credentials) {
5069
- credentials.command("delete").description("Delete a credential instance").argument("<id>", "Credential instance id").action((id) => runCredentialsCommand("Delete credential failed", async ({ platform, local }) => {
5709
+ credentials.command("delete").description("Delete a credential instance").argument("<ref>", "Credential slug or id").action((ref) => runCredentialsCommand("Delete credential failed", async ({ platform, local }) => {
5070
5710
  if (local) {
5071
5711
  const { client } = await createLocalCredentialsClient();
5072
- await client.credentials.deleteInstance(id);
5712
+ await client.credentials.deleteInstance(ref);
5073
5713
  return;
5074
5714
  }
5075
- await platform.credentials.delete(id);
5715
+ await platform.credentials.delete(ref);
5076
5716
  }));
5077
5717
  }
5078
5718
  //#endregion
@@ -5114,49 +5754,6 @@ function envRefName(raw) {
5114
5754
  return raw.slice(5);
5115
5755
  }
5116
5756
  //#endregion
5117
- //#region src/project/resolve-project-root.ts
5118
- function hasProjectLayout(dir) {
5119
- return existsSync(join(dir, "package.json")) && existsSync(join(dir, "src", "agents"));
5120
- }
5121
- function resolveProjectRoot(fromDir = process.cwd()) {
5122
- let dir = resolve(fromDir);
5123
- while (dir !== dirname(dir)) {
5124
- if (hasProjectLayout(dir)) return dir;
5125
- dir = dirname(dir);
5126
- }
5127
- if (hasProjectLayout(dir)) return dir;
5128
- throw new Error("Could not find keystroke project root (expected package.json and src/agents/)");
5129
- }
5130
- //#endregion
5131
- //#region src/project/load-project-env.ts
5132
- let loaded = false;
5133
- function parseEnvFile(contents) {
5134
- const values = {};
5135
- for (const line of contents.split("\n")) {
5136
- const trimmed = line.trim();
5137
- if (!trimmed || trimmed.startsWith("#")) continue;
5138
- const eq = trimmed.indexOf("=");
5139
- if (eq === -1) continue;
5140
- const key = trimmed.slice(0, eq).trim();
5141
- let value = trimmed.slice(eq + 1).trim();
5142
- if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
5143
- values[key] = value;
5144
- }
5145
- return values;
5146
- }
5147
- function loadProjectEnv(fromDir = process.cwd()) {
5148
- if (loaded) return;
5149
- loaded = true;
5150
- let envPath;
5151
- try {
5152
- envPath = join(resolveProjectRoot(fromDir), ".env");
5153
- } catch {
5154
- return;
5155
- }
5156
- if (!existsSync(envPath)) return;
5157
- for (const [key, value] of Object.entries(parseEnvFile(readFileSync(envPath, "utf8")))) if (process.env[key] === void 0) process.env[key] = value;
5158
- }
5159
- //#endregion
5160
5757
  //#region src/commands/credentials/parse-value.ts
5161
5758
  function parseCredentialValueFields(fields) {
5162
5759
  const value = {};
@@ -5202,8 +5799,7 @@ function collectSetValues$2(value, previous) {
5202
5799
  //#region src/commands/credentials/format-set-conflict-error.ts
5203
5800
  function describeInstance(instance) {
5204
5801
  const defaultStatus = instance.isDefault ? "default" : "not default";
5205
- const labelStatus = instance.label ? `label: ${instance.label}` : "no label";
5206
- return `id: ${instance.id}, ${defaultStatus}, ${labelStatus}`;
5802
+ return `${instance.name ? `name: ${instance.name}` : `slug: ${instance.slug}`}, ${defaultStatus}`;
5207
5803
  }
5208
5804
  function formatSetFields(setFields) {
5209
5805
  return setFields.map((field) => `--set ${field}`).join(" ");
@@ -5212,10 +5808,10 @@ function formatSetConflictError(args) {
5212
5808
  const binary = cliBinaryName();
5213
5809
  const setArgs = formatSetFields(args.setFields);
5214
5810
  const listCmd = `${binary} credentials list --key ${args.key}`;
5215
- const addSecondCmd = `${binary} credentials set ${args.key} --scope ${args.scope} --label <name> ${setArgs}`;
5811
+ const addSecondCmd = `${binary} credentials set ${args.key} --scope ${args.scope} --slug <slug> ${setArgs}`;
5216
5812
  if (args.matching.length === 1) {
5217
5813
  const instance = args.matching[0];
5218
- const updateCmd = `${binary} credentials update ${instance.id} ${setArgs}`;
5814
+ const updateCmd = `${binary} credentials update ${instance.slug} ${setArgs}`;
5219
5815
  return [
5220
5816
  `An ${args.key} credential already exists in ${args.scope} scope (${describeInstance(instance)}).`,
5221
5817
  "credentials set creates a new instance — it does not update an existing one.",
@@ -5228,7 +5824,7 @@ function formatSetConflictError(args) {
5228
5824
  }
5229
5825
  const instanceLines = args.matching.map((instance) => ` • ${describeInstance(instance)}`);
5230
5826
  return [
5231
- `Multiple ${args.key} credentials already exist in ${args.scope} scope. --label is required to add another:`,
5827
+ `Multiple ${args.key} credentials already exist in ${args.scope} scope. Pass --slug to add another:`,
5232
5828
  ...instanceLines,
5233
5829
  "To add another credential in the same scope:",
5234
5830
  ` ${addSecondCmd}`,
@@ -5236,7 +5832,7 @@ function formatSetConflictError(args) {
5236
5832
  ].join("\n");
5237
5833
  }
5238
5834
  async function assertNoSetConflict(client, args) {
5239
- if (args.label) return;
5835
+ if (args.slug) return;
5240
5836
  const { instances } = await client.credentials.listInstances({ key: args.key });
5241
5837
  const matching = instances.filter((instance) => instance.scopeType === args.scopeType && (args.scopeType !== "project" || instance.scopeId === args.projectId));
5242
5838
  if (matching.length === 0) return;
@@ -5248,6 +5844,23 @@ async function assertNoSetConflict(client, args) {
5248
5844
  }));
5249
5845
  }
5250
5846
  //#endregion
5847
+ //#region src/commands/connect/parse-connect-scopes.ts
5848
+ function parseConnectScopes(scopes, projectSlugs) {
5849
+ const normalized = scopes.length > 0 ? scopes : ["org"];
5850
+ for (const scope of normalized) if (scope !== "org" && scope !== "user" && scope !== "project") throw new Error(`Unknown scope "${scope}". Expected org, user, or project.`);
5851
+ const createOrganizationCredential = normalized.includes("org");
5852
+ const createUserProvidedCredential = normalized.includes("user");
5853
+ const includesProject = normalized.includes("project");
5854
+ const selectedProjects = includesProject ? projectSlugs : [];
5855
+ if (includesProject && selectedProjects.length === 0) throw new Error("--project-slug is required when scope includes project");
5856
+ if (!createOrganizationCredential && !createUserProvidedCredential && selectedProjects.length === 0) throw new Error("At least one scope is required via --scope and/or --project-slug");
5857
+ return {
5858
+ createOrganizationCredential,
5859
+ createUserProvidedCredential,
5860
+ projects: selectedProjects
5861
+ };
5862
+ }
5863
+ //#endregion
5251
5864
  //#region src/commands/credentials/parse-set-scopes.ts
5252
5865
  function parseCredentialSetScopes(scopes, projectSlugs) {
5253
5866
  return parseConnectScopes(scopes, projectSlugs);
@@ -5255,7 +5868,7 @@ function parseCredentialSetScopes(scopes, projectSlugs) {
5255
5868
  //#endregion
5256
5869
  //#region src/commands/credentials/set.ts
5257
5870
  function registerCredentialsSetCommand(credentials) {
5258
- credentials.command("set").description("Create a new api_key credential instance").argument("<key>", "Credential key or app id, e.g. exa").option("--scope <scope>", "org, user, or project (repeatable)", collectValues, []).option("--project-slug <slug>", "Project slug when scope includes project (repeatable)", collectValues, []).option("--label <label>", "Human-readable label within the scope").option("--default", "Mark as default for this scope").option("--set <field>", "Credential field as key=value or key=@env:VAR (falls back to project .env when unset in shell)", collectSetValues$1, []).action((key, options) => runCredentialsCommand("Set credential failed", async ({ platform, local }) => {
5871
+ credentials.command("set").description("Create a new api_key credential instance").argument("<key>", "Credential key or app id, e.g. exa").option("--scope <scope>", "org, user, or project (repeatable)", collectValues, []).option("--project-slug <slug>", "Project slug when scope includes project (repeatable)", collectValues, []).option("--slug <slug>", "Friendly credential slug within the scope").option("--name <name>", "Display name (used to derive slug when --slug is omitted)").option("--label <label>", "Alias for --name").option("--default", "Mark as default for this scope").option("--set <field>", "Credential field as key=value or key=@env:VAR (falls back to project .env when unset in shell)", collectSetValues$1, []).action((key, options) => runCredentialsCommand("Set credential failed", async ({ platform, local }) => {
5259
5872
  const value = parseCredentialValueFields(options.set);
5260
5873
  const parsedScopes = parseCredentialSetScopes(options.scope, options.projectSlug);
5261
5874
  if (local) {
@@ -5263,19 +5876,21 @@ function registerCredentialsSetCommand(credentials) {
5263
5876
  const targets = expandLocalCredentialTargets(parsedScopes);
5264
5877
  const instances = [];
5265
5878
  for (const target of targets) {
5879
+ const displayName = options.name ?? options.label;
5266
5880
  await assertNoSetConflict(client, {
5267
5881
  key,
5268
5882
  scope: target.scope,
5269
5883
  scopeType: target.scopeType,
5270
5884
  projectId: target.projectSlug,
5271
- label: options.label,
5885
+ slug: options.slug,
5272
5886
  setFields: options.set
5273
5887
  });
5274
5888
  instances.push(await client.credentials.createInstance({
5275
5889
  key,
5276
5890
  scopeType: target.scopeType,
5277
5891
  scopeId: target.projectSlug,
5278
- label: options.label,
5892
+ ...options.slug !== void 0 ? { slug: options.slug } : {},
5893
+ ...displayName !== void 0 ? { name: displayName } : {},
5279
5894
  isDefault: options.default,
5280
5895
  value
5281
5896
  }));
@@ -5331,12 +5946,14 @@ function expandLocalCredentialTargets(targets) {
5331
5946
  //#endregion
5332
5947
  //#region src/commands/credentials/update.ts
5333
5948
  function registerCredentialsUpdateCommand(credentials) {
5334
- credentials.command("update").description("Update a credential instance").argument("<id>", "Credential instance id").option("--label <label>", "Human-readable label within the scope").option("--default", "Mark as default for this scope").option("--set <field>", "Credential field as key=value or key=@env:VAR", collectSetValues, []).action((id, options) => runCredentialsCommand("Update credential failed", async ({ platform, local }) => {
5949
+ credentials.command("update").description("Update a credential instance").argument("<ref>", "Credential slug or id").option("--slug <slug>", "Update friendly slug").option("--name <name>", "Update display name").option("--label <label>", "Alias for --name").option("--default", "Mark as default for this scope").option("--set <field>", "Credential field as key=value or key=@env:VAR", collectSetValues, []).action((ref, options) => runCredentialsCommand("Update credential failed", async ({ platform, local }) => {
5335
5950
  const value = options.set.length > 0 ? parseCredentialValueFields(options.set) : void 0;
5951
+ const displayName = options.name ?? options.label;
5336
5952
  if (local) {
5337
5953
  const { client } = await createLocalCredentialsClient();
5338
- const result = await client.credentials.updateInstance(id, {
5339
- ...options.label !== void 0 ? { label: options.label } : {},
5954
+ const result = await client.credentials.updateInstance(ref, {
5955
+ ...options.slug !== void 0 ? { slug: options.slug } : {},
5956
+ ...displayName !== void 0 ? { name: displayName } : {},
5340
5957
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5341
5958
  ...value ? { value } : {}
5342
5959
  });
@@ -5344,11 +5961,11 @@ function registerCredentialsUpdateCommand(credentials) {
5344
5961
  return;
5345
5962
  }
5346
5963
  const patch = buildPlatformUpdatePatch({
5347
- ...options.label !== void 0 ? { label: options.label } : {},
5964
+ ...displayName !== void 0 ? { label: displayName } : {},
5348
5965
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5349
5966
  ...value ? { value } : {}
5350
5967
  });
5351
- const credential = await platform.credentials.update(id, patch);
5968
+ const credential = await platform.credentials.update(ref, patch);
5352
5969
  process.stdout.write(`${JSON.stringify({ credential }, null, 2)}\n`);
5353
5970
  }));
5354
5971
  }
@@ -5365,11 +5982,13 @@ function registerCredentialsCommand(program) {
5365
5982
  registerCredentialsUpdateCommand(credentials);
5366
5983
  registerCredentialsRotateKeyCommand(credentials);
5367
5984
  registerCredentialsDeleteCommand(credentials);
5985
+ registerCredentialsAssignmentsCommands(credentials);
5986
+ registerCredentialsConsumersCommands(credentials);
5368
5987
  }
5369
5988
  //#endregion
5370
5989
  //#region src/auth/resolve-login-targets.ts
5371
5990
  function resolveAuthLoginTargets(options, config) {
5372
- const webUrl = options.webUrl ?? "https://app.keystroke.ai";
5991
+ const webUrl = options.webUrl ?? "https://keystroke.ai";
5373
5992
  return {
5374
5993
  webUrl,
5375
5994
  platformUrl: resolvePlatformUrlForWebUrl(webUrl, {
@@ -5476,7 +6095,7 @@ function registerBuildCommand(program) {
5476
6095
  program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
5477
6096
  try {
5478
6097
  const root = resolveProjectRoot(options.dir);
5479
- const { buildApp } = await import("./dist-CJL2zYbP.mjs");
6098
+ const { buildApp } = await import("./dist-jchdNGBU.mjs");
5480
6099
  await buildApp({ root });
5481
6100
  process.stdout.write(`Built ${root}\n`);
5482
6101
  } catch (error) {
@@ -5487,109 +6106,6 @@ function registerBuildCommand(program) {
5487
6106
  });
5488
6107
  }
5489
6108
  //#endregion
5490
- //#region ../../packages/storage/dist/pack-artifact-NGxvGcXq.mjs
5491
- /**
5492
- * Pack a directory tree that contains a `dist/` folder into a gzip tarball
5493
- * suitable for project-server extraction.
5494
- */
5495
- function packDistTree(rootContainingDist) {
5496
- const tempDir = mkdtempSync(join(tmpdir(), "keystroke-artifact-pack-"));
5497
- const archivePath = join(tempDir, "artifact.tgz");
5498
- try {
5499
- const result = spawnSync("tar", [
5500
- "-czf",
5501
- archivePath,
5502
- "--exclude=._*",
5503
- "--exclude=.DS_Store",
5504
- "-C",
5505
- rootContainingDist,
5506
- "dist"
5507
- ], {
5508
- encoding: "utf8",
5509
- env: {
5510
- ...process.env,
5511
- COPYFILE_DISABLE: "1"
5512
- }
5513
- });
5514
- if (result.status !== 0) throw new Error(result.stderr?.trim() || "Failed to pack project artifact");
5515
- return readFileSync(archivePath);
5516
- } finally {
5517
- rmSync(tempDir, {
5518
- recursive: true,
5519
- force: true
5520
- });
5521
- }
5522
- }
5523
- /** Extract a packed project artifact tarball into `destDir` (creates `destDir/dist/`). */
5524
- function extractProjectArtifact(archive, destDir) {
5525
- const tempDir = mkdtempSync(join(tmpdir(), "keystroke-artifact-extract-"));
5526
- const archivePath = join(tempDir, "artifact.tgz");
5527
- try {
5528
- writeFileSync(archivePath, archive);
5529
- const result = spawnSync("tar", [
5530
- "-xzf",
5531
- archivePath,
5532
- "-C",
5533
- destDir
5534
- ], {
5535
- encoding: "utf8",
5536
- env: {
5537
- ...process.env,
5538
- COPYFILE_DISABLE: "1"
5539
- }
5540
- });
5541
- if (result.status !== 0) throw new Error(result.stderr?.trim() || "Failed to extract project artifact");
5542
- } finally {
5543
- rmSync(tempDir, {
5544
- recursive: true,
5545
- force: true
5546
- });
5547
- }
5548
- }
5549
- function moduleFileOf(entry) {
5550
- return "moduleFile" in entry && typeof entry.moduleFile === "string" ? entry.moduleFile : void 0;
5551
- }
5552
- /** Replace manifest rows for rebuilt modules while keeping untouched routes and metadata. */
5553
- function mergeStoredRouteManifest(base, rebuiltEntries) {
5554
- const rebuiltModuleFiles = new Set(rebuiltEntries.map(moduleFileOf).filter((value) => Boolean(value)));
5555
- const keptEntries = base.entries.filter((entry) => {
5556
- const moduleFile = moduleFileOf(entry);
5557
- if (!moduleFile) return true;
5558
- return !rebuiltModuleFiles.has(moduleFile);
5559
- });
5560
- const filteredRebuilt = rebuiltEntries.filter((entry) => entry.kind !== "health");
5561
- return {
5562
- ...base,
5563
- entries: [...keptEntries, ...filteredRebuilt]
5564
- };
5565
- }
5566
- async function mergeFilteredArtifact(input) {
5567
- const mergeRoot = mkdtempSync(join(tmpdir(), "keystroke-artifact-merge-"));
5568
- try {
5569
- extractProjectArtifact(input.baseArchive, mergeRoot);
5570
- const manifestPath = join(mergeRoot, ROUTE_MANIFEST_REL_PATH);
5571
- const mergedManifest = mergeStoredRouteManifest(StoredRouteManifestSchema.parse(JSON.parse(readFileSync(manifestPath, "utf8"))), input.filtered.manifestEntries);
5572
- writeFileSync(manifestPath, `${JSON.stringify(mergedManifest, null, 2)}\n`);
5573
- for (const file of input.filtered.files) {
5574
- const destination = join(mergeRoot, "dist", file.relativePath);
5575
- mkdirSync(dirname(destination), { recursive: true });
5576
- writeFileSync(destination, file.contents);
5577
- if (file.sourceMap) writeFileSync(`${destination}.map`, file.sourceMap);
5578
- }
5579
- return packDistTree(mergeRoot);
5580
- } finally {
5581
- rmSync(mergeRoot, {
5582
- recursive: true,
5583
- force: true
5584
- });
5585
- }
5586
- }
5587
- /** Pack `dist/` into a gzip tarball suitable for `/app` extraction in the project server image. */
5588
- function packProjectArtifact(projectRoot) {
5589
- if (!existsSync(join(projectRoot, "dist"))) throw new Error("dist/ not found — run keystroke build first");
5590
- return packDistTree(projectRoot);
5591
- }
5592
- //#endregion
5593
6109
  //#region src/commands/deploy.ts
5594
6110
  const POLL_INTERVAL_MS = 2e3;
5595
6111
  const DEPLOY_TIMEOUT_MS = 12e4;
@@ -5633,7 +6149,7 @@ async function sleep(ms) {
5633
6149
  }
5634
6150
  async function buildDeployArchive(client, root, projectId, filter) {
5635
6151
  if (filter?.length) {
5636
- const { buildFilteredApp } = await import("./dist-CJL2zYbP.mjs");
6152
+ const { buildFilteredApp } = await import("./dist-jchdNGBU.mjs");
5637
6153
  const filtered = await buildFilteredApp({
5638
6154
  root,
5639
6155
  filter,
@@ -5655,7 +6171,7 @@ async function buildDeployArchive(client, root, projectId, filter) {
5655
6171
  sourceFiles: filtered.sourceFiles
5656
6172
  };
5657
6173
  }
5658
- const { buildApp } = await import("./dist-CJL2zYbP.mjs");
6174
+ const { buildApp } = await import("./dist-jchdNGBU.mjs");
5659
6175
  const { sourceFiles } = await buildApp({
5660
6176
  root,
5661
6177
  collectSources: true,
@@ -5723,6 +6239,13 @@ function registerDeployCommand(program) {
5723
6239
  });
5724
6240
  }
5725
6241
  //#endregion
6242
+ //#region src/resolve-local-api-origin.ts
6243
+ /** Local platform API origin from the project `.env` (`PUBLIC_PLATFORM_URL`). */
6244
+ function resolveLocalApiOrigin(fromDir = process.cwd()) {
6245
+ loadProjectEnv(fromDir);
6246
+ return resolvePublicPlatformOrigin(process.env);
6247
+ }
6248
+ //#endregion
5726
6249
  //#region src/project/runtime-child-env.ts
5727
6250
  /** Strip dev-only Node flags so the API child loads built `dist/`, not package `src/`. */
5728
6251
  function runtimeChildNodeOptions(nodeOptions) {
@@ -5761,14 +6284,13 @@ function runtimeChildEnv(parentEnv, overrides) {
5761
6284
  env.DATABASE_URL = "file:./data/public.db";
5762
6285
  }
5763
6286
  env.KEYSTROKE_APP_MODE ??= "standalone";
5764
- env.PROJECT_ID ??= "default";
5765
6287
  return env;
5766
6288
  }
5767
6289
  //#endregion
5768
6290
  //#region src/project/bootstrap-run.ts
5769
6291
  /** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
5770
6292
  async function resolveBootstrapRun(options) {
5771
- const { resolveRuntimeBuildArtifact } = await import("./dist-CJL2zYbP.mjs");
6293
+ const { resolveRuntimeBuildArtifact } = await import("./dist-jchdNGBU.mjs");
5772
6294
  const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
5773
6295
  const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/standalone-bootstrap.mjs");
5774
6296
  const args = [`--import=${loader}`];
@@ -5778,10 +6300,9 @@ async function resolveBootstrapRun(options) {
5778
6300
  const childEnv = runtimeChildEnv(process.env, {
5779
6301
  KEYSTROKE_ROOT: options.root,
5780
6302
  KEYSTROKE_RUNTIME_NODE_MODULES: options.runtimeNodeModules,
5781
- KEYSTROKE_APP_MODE: "standalone",
5782
- PROJECT_ID: process.env.PROJECT_ID ?? "default"
6303
+ KEYSTROKE_APP_MODE: "standalone"
5783
6304
  });
5784
- childEnv.PORT = String(listenPortFromPublicUrl(childEnv.PUBLIC_SERVER_URL, options.apiPort));
6305
+ childEnv.PORT = String(listenPortFromPublicUrl(childEnv.PUBLIC_PLATFORM_URL, options.apiPort));
5785
6306
  return {
5786
6307
  cwd: options.root,
5787
6308
  args,
@@ -5873,8 +6394,8 @@ const DEV_BANNER = "keystroke dev: watch rebuilds dist/ and restarts the API —
5873
6394
  function stopChild(child) {
5874
6395
  if (child && !child.killed && child.pid !== void 0) child.kill("SIGTERM");
5875
6396
  }
5876
- function resolveDevServerUrl(config, portOverride) {
5877
- const url = new URL(getServerUrl(config));
6397
+ function resolveDevServerUrl(root, portOverride) {
6398
+ const url = new URL(resolveLocalApiOrigin(root));
5878
6399
  if (portOverride !== void 0) url.port = String(portOverride);
5879
6400
  return url.origin;
5880
6401
  }
@@ -5882,10 +6403,9 @@ async function runDev(options) {
5882
6403
  const root = resolveProjectRoot(options.dir);
5883
6404
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
5884
6405
  ensureNativeDeps(runtimeNodeModules);
5885
- const cliConfig = createCliConfig();
5886
- const configDir = getConfigDir(cliConfig);
6406
+ const configDir = getConfigDir(createCliConfig());
5887
6407
  process.stdout.write(DEV_BANNER);
5888
- const serverUrl = resolveDevServerUrl(cliConfig, options.port);
6408
+ const serverUrl = resolveDevServerUrl(root, options.port);
5889
6409
  const apiPort = Number(new URL(serverUrl).port || 80);
5890
6410
  writeDevSession({
5891
6411
  pid: process.pid,
@@ -5919,7 +6439,7 @@ async function runDev(options) {
5919
6439
  process.on("SIGINT", shutdown);
5920
6440
  process.on("SIGTERM", shutdown);
5921
6441
  try {
5922
- const { watchApp } = await import("./dist-CJL2zYbP.mjs");
6442
+ const { watchApp } = await import("./dist-jchdNGBU.mjs");
5923
6443
  await watchApp({
5924
6444
  root,
5925
6445
  clean: false,
@@ -6069,10 +6589,11 @@ const INIT_CATALOG_VERSIONS = {
6069
6589
  vitest: "^4.1.7",
6070
6590
  "@types/node": "^25.9.1"
6071
6591
  };
6592
+ const INIT_KEYSTROKE_VERSION = "^0.1.5";
6072
6593
  //#endregion
6073
6594
  //#region src/init/copy-template.ts
6074
6595
  function renderTemplate(content, variables) {
6075
- let rendered = content.replaceAll("{{projectName}}", variables.projectName).replaceAll("{{version}}", variables.version);
6596
+ let rendered = content.replaceAll("{{projectName}}", variables.projectName).replaceAll("{{keystrokeVersion}}", INIT_KEYSTROKE_VERSION).replaceAll("{{version}}", variables.version);
6076
6597
  for (const [dep, version] of Object.entries(INIT_CATALOG_VERSIONS)) rendered = rendered.replaceAll(`{{catalog:${dep}}}`, version);
6077
6598
  return rendered;
6078
6599
  }
@@ -6248,6 +6769,33 @@ function resolvePlaygroundRoot(targetDir) {
6248
6769
  const rel = relative(join(root, "playground"), resolve(targetDir));
6249
6770
  return rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel) ? root : null;
6250
6771
  }
6772
+ /** Example primitives the hello-world template ships; removed when --no-example is set. */
6773
+ const EXAMPLE_FILES = [
6774
+ "src/actions/greet.ts",
6775
+ "src/agents/hello.ts",
6776
+ "src/agents/hello.int.test.ts",
6777
+ "src/workflows/greeting.ts",
6778
+ "src/workflows/greeting.test.ts"
6779
+ ];
6780
+ async function removeExampleFiles(targetDir) {
6781
+ await Promise.all(EXAMPLE_FILES.map((rel) => rm(join(targetDir, rel), { force: true })));
6782
+ }
6783
+ /**
6784
+ * Drop the README sections that walk through the example hello agent / greeting
6785
+ * workflow — those primitives don't exist in a --no-example scaffold (e.g. MCP
6786
+ * sprite bootstrap), so shipping their usage docs is misleading.
6787
+ */
6788
+ async function stripExampleReadme(targetDir) {
6789
+ const readmePath = join(targetDir, "README.md");
6790
+ let content;
6791
+ try {
6792
+ content = await readFile(readmePath, "utf8");
6793
+ } catch {
6794
+ return;
6795
+ }
6796
+ const next = content.replace(/Prompt the hello agent:\n+```bash\n[\s\S]*?\n```\n+/, "").replace(/Run the greeting workflow:\n+```bash\n[\s\S]*?\n```\n+/, "").replace(/\nExample: `src\/workflows\/greeting\.test\.ts`[^\n]*\n/, "\n");
6797
+ if (next !== content) await writeFile(readmePath, next);
6798
+ }
6251
6799
  async function directoryExists(path) {
6252
6800
  try {
6253
6801
  await access(path);
@@ -6281,6 +6829,10 @@ async function runInit(options) {
6281
6829
  version: options.version
6282
6830
  });
6283
6831
  await scaffoldEmptySrcDirs(targetDir);
6832
+ if (options.noExample) {
6833
+ await removeExampleFiles(targetDir);
6834
+ await stripExampleReadme(targetDir);
6835
+ }
6284
6836
  if (playgroundRoot) await applyPlaygroundManifest(targetDir, projectName, playgroundRoot);
6285
6837
  else await scaffoldProjectDotfiles(targetDir);
6286
6838
  await syncBundledSkills(targetDir);
@@ -6297,7 +6849,7 @@ async function runInit(options) {
6297
6849
  //#endregion
6298
6850
  //#region src/commands/init.ts
6299
6851
  function registerInitCommand(program) {
6300
- 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").action(async (directory, options) => {
6852
+ 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) => {
6301
6853
  try {
6302
6854
  const result = await runInit({
6303
6855
  directory,
@@ -6306,6 +6858,7 @@ function registerInitCommand(program) {
6306
6858
  yes: options.yes,
6307
6859
  skipInstall: options.skipInstall,
6308
6860
  packageManager: options.pm,
6861
+ noExample: options.example === false,
6309
6862
  version: readCliVersion()
6310
6863
  });
6311
6864
  process.stdout.write(`Created keystroke project "${result.projectName}" at ${result.targetDir}\n`);
@@ -6734,18 +7287,18 @@ function registerProjectCommand(program) {
6734
7287
  }
6735
7288
  //#endregion
6736
7289
  //#region src/commands/start.ts
6737
- function resolveStartServerUrl(portOverride) {
6738
- const url = new URL(getServerUrl(createCliConfig()));
7290
+ function resolveStartServerUrl(root, portOverride) {
7291
+ const url = new URL(resolveLocalApiOrigin(root));
6739
7292
  if (portOverride !== void 0) url.port = String(portOverride);
6740
7293
  return url.origin;
6741
7294
  }
6742
7295
  async function runStart(options) {
6743
7296
  const root = resolveProjectRoot(options.dir);
6744
- const serverUrl = resolveStartServerUrl(options.port);
7297
+ const serverUrl = resolveStartServerUrl(root, options.port);
6745
7298
  const apiPort = Number(new URL(serverUrl).port || 80);
6746
7299
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
6747
7300
  ensureNativeDeps(runtimeNodeModules);
6748
- const { buildApp } = await import("./dist-CJL2zYbP.mjs");
7301
+ const { buildApp } = await import("./dist-jchdNGBU.mjs");
6749
7302
  await buildApp({
6750
7303
  root,
6751
7304
  clean: false
@@ -6828,6 +7381,61 @@ function registerTriggerRunsCommand(trigger) {
6828
7381
  }));
6829
7382
  }
6830
7383
  //#endregion
7384
+ //#region src/commands/trigger/resolve-trigger-attachment.ts
7385
+ function findAssignment(assignments, attachmentRef) {
7386
+ return assignments.find((entry) => entry.attachmentId === attachmentRef || entry.attachmentSlug === attachmentRef);
7387
+ }
7388
+ async function resolveTriggerAttachment(platform, triggerRef, attachmentRef) {
7389
+ let trigger = await platform.triggers.get(triggerRef);
7390
+ if (!trigger) {
7391
+ const summary = (await platform.triggers.list()).find((entry) => entry.id === triggerRef || entry.slug === triggerRef) ?? null;
7392
+ if (summary) trigger = await platform.triggers.get(summary.id);
7393
+ }
7394
+ if (!trigger) throw new Error(`Trigger not found: ${triggerRef}`);
7395
+ const assignment = findAssignment(trigger.assignments, attachmentRef);
7396
+ if (!assignment) throw new Error(`Attachment not found on trigger ${trigger.slug}: ${attachmentRef}`);
7397
+ return {
7398
+ triggerId: trigger.id,
7399
+ attachmentId: assignment.attachmentId,
7400
+ trigger,
7401
+ assignment
7402
+ };
7403
+ }
7404
+ //#endregion
7405
+ //#region src/commands/trigger/run-attachment-enabled.ts
7406
+ async function runTriggerAttachmentEnabled(config, options) {
7407
+ await withActivePlatformClient(config, async (platform) => {
7408
+ const resolved = await resolveTriggerAttachment(platform, options.triggerRef, options.attachmentRef);
7409
+ const trigger = await platform.triggers.updateAttachment(resolved.triggerId, resolved.attachmentId, { enabled: options.enabled });
7410
+ process.stdout.write(`${JSON.stringify(trigger, null, 2)}\n`);
7411
+ });
7412
+ }
7413
+ //#endregion
7414
+ //#region src/commands/trigger/attachment.ts
7415
+ function registerAttachmentToggleCommand(attachment, command, enabled) {
7416
+ attachment.command(command).description(`${command === "enable" ? "Enable" : "Disable"} a trigger attachment`).argument("<triggerRef>", "Trigger id or slug").argument("<attachmentRef>", "Attachment id or slug (for example signup:signup-pipeline)").action(async (triggerRef, attachmentRef) => {
7417
+ const config = createCliConfig();
7418
+ try {
7419
+ await runTriggerAttachmentEnabled(config, {
7420
+ triggerRef,
7421
+ attachmentRef,
7422
+ enabled
7423
+ });
7424
+ } catch (error) {
7425
+ process.stderr.write(`${formatCliError(error, `${command} trigger attachment failed`, {
7426
+ serverUrl: getPlatformUrl(config),
7427
+ webUrl: getWebUrl(config)
7428
+ })}\n`);
7429
+ process.exitCode = 1;
7430
+ }
7431
+ });
7432
+ }
7433
+ function registerTriggerAttachmentCommand(trigger) {
7434
+ const attachment = trigger.command("attachment").description("Enable or disable individual trigger attachments");
7435
+ registerAttachmentToggleCommand(attachment, "disable", false);
7436
+ registerAttachmentToggleCommand(attachment, "enable", true);
7437
+ }
7438
+ //#endregion
6831
7439
  //#region src/commands/trigger/index.ts
6832
7440
  function registerTriggerCommand(program) {
6833
7441
  const trigger = program.command("trigger").description("Invoke and inspect triggers");
@@ -6836,6 +7444,7 @@ function registerTriggerCommand(program) {
6836
7444
  registerTriggerUrlCommand(trigger);
6837
7445
  registerTriggerPollCommand(trigger);
6838
7446
  registerTriggerRunsCommand(trigger);
7447
+ registerTriggerAttachmentCommand(trigger);
6839
7448
  }
6840
7449
  //#endregion
6841
7450
  //#region src/commands/workflow/list.ts
@@ -7129,9 +7738,9 @@ function registerConfigCommand(program) {
7129
7738
  const cliConfig = createCliConfig();
7130
7739
  const configDir = getConfigDir(cliConfig);
7131
7740
  process.stdout.write(`${JSON.stringify({
7132
- serverUrl: cliConfig.get("serverUrl"),
7133
7741
  webUrl: cliConfig.get("webUrl"),
7134
7742
  platformUrl: getPlatformUrl(cliConfig),
7743
+ localApiUrl: resolveLocalApiOrigin(process.cwd()),
7135
7744
  activeOrganizationId: cliConfig.get("activeOrganizationId"),
7136
7745
  activeProjectId: cliConfig.get("activeProjectId"),
7137
7746
  apiTarget: getEffectiveApiTarget(cliConfig),
@@ -7201,19 +7810,6 @@ function registerSkillsCommand(program) {
7201
7810
  });
7202
7811
  }
7203
7812
  //#endregion
7204
- //#region src/project/resolve-keystroke-config-root.ts
7205
- const KEYSTROKE_CONFIG = "keystroke.config.ts";
7206
- /** Walk up from `fromDir` and return the directory containing `keystroke.config.ts`, if any. */
7207
- function resolveKeystrokeConfigRoot(fromDir = process.cwd()) {
7208
- let dir = resolve(fromDir);
7209
- while (dir !== dirname(dir)) {
7210
- if (existsSync(join(dir, KEYSTROKE_CONFIG))) return dir;
7211
- dir = dirname(dir);
7212
- }
7213
- if (existsSync(join(dir, KEYSTROKE_CONFIG))) return dir;
7214
- return null;
7215
- }
7216
- //#endregion
7217
7813
  //#region src/skills/sync-skills.ts
7218
7814
  function commandPath(command) {
7219
7815
  const names = [];
@@ -7281,7 +7877,7 @@ function createProgram() {
7281
7877
  return program;
7282
7878
  }
7283
7879
  async function runCli(argv) {
7284
- const { maybeAutoUpdate } = await import("./maybe-auto-update-B0kal2FM.mjs");
7880
+ const { maybeAutoUpdate } = await import("./maybe-auto-update-ClXO7U-6.mjs");
7285
7881
  await maybeAutoUpdate(argv);
7286
7882
  createProgram().parse(argv);
7287
7883
  }