@keystrokehq/cli 0.1.5 → 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-C3YClLXV.mjs → dist-H53GUsol.mjs} +775 -73
  6. package/dist/dist-H53GUsol.mjs.map +1 -0
  7. package/dist/{dist-B9XaHV_2.mjs → dist-jchdNGBU.mjs} +57 -20
  8. package/dist/dist-jchdNGBU.mjs.map +1 -0
  9. package/dist/index.mjs +551 -225
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/{maybe-auto-update-DHt-mVf1.mjs → maybe-auto-update-ClXO7U-6.mjs} +2 -2
  12. package/dist/{maybe-auto-update-DHt-mVf1.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-BOm_5ar9.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-B9XaHV_2.mjs.map +0 -1
  37. package/dist/dist-C3YClLXV.mjs.map +0 -1
  38. package/dist/dist-D_-88U7y.mjs +0 -1887
  39. package/dist/dist-D_-88U7y.mjs.map +0 -1
  40. package/dist/dist-iKd6nzBK.mjs +0 -3
  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-BOm_5ar9.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,13 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { $ as ListCredentialsResponseSchema, $t as UpsertGatewayAttachmentBodySchema, A as CreateOrganizationResponseSchema, At as SlugAvailabilityResponseSchema, B as GetCredentialResponseSchema, Bt as TriggerRunListResponseSchema, C as CreateApiKeyResponseSchema, Ct as PromptResponseSchema, D as CreateCustomAppRequestSchema, Dt as RecentResourceListResponseSchema, E as CreateCredentialsResponseSchema, Et as ROUTE_MANIFEST_REL_PATH, F as CredentialInstanceRecordSchema, Ft as StoredRouteManifestSchema, G as HistoryRunListQuerySchema, Gt as UpdateOrganizationMemberResponseSchema, H as HealthResponseSchema, Ht as UpdateCredentialInstanceBodySchema, I as DeclineOrganizationInvitationResponseSchema, It as SubmitTeamRequestRequestSchema, J as InviteOrganizationMembersResponseSchema, Jt as UpdateProjectMemberResponseSchema, K as HistoryRunListResponseSchema, Kt as UpdateOrganizationRequestSchema, L as DownloadActiveProjectArtifactResponseSchema, Lt as TriggerDetailResponseSchema, M as CreateProjectRequestSchema, Mt as StartKeystrokeConnectionResultSchema, N as CreateProjectResponseSchema, Nt as StartOAuthConnectionInputSchema, O as CreateCustomAppResponseSchema, Ot as SkillSummaryDetailResponseSchema, P as CredentialInstanceListResponseSchema, Pt as StartOAuthConnectionResultSchema, Q as ListAppsResponseSchema, Qt as UploadProjectSourceResponseSchema, R as ErrorResponseSchema, Rt as TriggerListResponseSchema, S as CreateApiKeyRequestSchema, St as PromptInputSchema, T as CreateCredentialsRequestSchema, Tt as QueuedRunResponseSchema, U as HistoryRunCancelResponseSchema, Ut as UpdateCredentialRequestSchema, V as GetCustomAppResponseSchema, Vt as UpdateChannelBindingBodySchema, W as HistoryRunDetailResponseSchema, Wt as UpdateOrganizationMemberRequestSchema, X as InviteProjectMembersResponseSchema, Xt as UpdateProjectSettingsRequestSchema, Y as InviteProjectMembersRequestSchema, Yt as UpdateProjectRequestSchema, Z as ListApiKeysResponseSchema, Zt as UploadProjectSourceManifestRequestSchema, _ as ChannelDirectoryListResponseSchema, _t as PresignUserAvatarResponseSchema, a as AgentSessionListResponseSchema, an as WorkflowRunListResponseSchema, at as ListProjectMembersResponseSchema, b as ConnectAuthorizeUrlResponseSchema, bt as ProjectSettingsResponseSchema, c as AppSlugAvailabilityResponseSchema, cn as listenPortFromPublicUrl, ct as OrganizationSidebarBrandingPatchSchema, d as CatalogActionsPageResponseSchema, dn as parseAppSlug, dt as PollRunResponseSchema, en as UserAvatarPatchSchema, et as ListOrganizationInvitationsResponseSchema, f as CatalogAppDetailResponseSchema, fn as parseErrorResponse, ft as PresignOrgLogoRequestSchema, g as ChannelConnectionSchema, gt as PresignUserAvatarRequestSchema, h as ChannelConnectionListResponseSchema, ht as PresignProjectSourceResponseSchema, i as AgentSessionDetailResponseSchema, in as WorkflowRunDetailResponseSchema, it as ListProjectFilesResponseSchema, j as CreateProjectArtifactResponseSchema, jt as StartKeystrokeConnectionInputSchema, k as CreateOrganizationRequestSchema, kt as SkillSummaryListResponseSchema, l as BindChannelBodySchema, lt as OrganizationSidebarBrandingSchema, m as ChannelAccountListResponseSchema, mt as PresignProjectSourceRequestSchema, n as AcceptOrganizationInvitationResponseSchema, nn as UserPreferencesPatchSchema, nt as ListOrganizationsResponseSchema, o as AgentSummaryDetailResponseSchema, on as WorkflowSummaryDetailResponseSchema, ot as ListProjectMetricsResponseSchema, p as CatalogAppsPageResponseSchema, pn as slugifyAppName, pt as PresignOrgLogoResponseSchema, q as InviteOrganizationMembersRequestSchema, qt as UpdateProjectMemberRequestSchema, r as ActiveOrganizationResponseSchema, rn as UserPreferencesSchema, rt as ListProjectDeploymentsResponseSchema, s as AgentSummaryListResponseSchema, sn as WorkflowSummaryListResponseSchema, st as ListProjectsResponseSchema, t as ACTIVE_ORG_HEADER, tn as UserAvatarSchema, tt as ListOrganizationMembersResponseSchema, u as CatalogActionDetailResponseSchema, ut as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, v as ChannelPlatformSchema, vt as ProjectReachabilityResponseSchema, w as CreateCredentialInstanceBodySchema, wt as QueuedAgentPromptResponseSchema, x as ConnectProvidersResponseSchema, xt as ProjectSlugAvailabilityResponseSchema, y as CompleteProjectArtifactResponseSchema, yt as ProjectResponseSchema, z as GatewayAttachmentRecordSchema, zt as TriggerRunDetailResponseSchema } from "./dist-C3YClLXV.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-BOm_5ar9.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";
11
12
  import { access, copyFile, cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
12
13
  import { spawn, spawnSync } from "node:child_process";
13
14
  import { pathToFileURL } from "node:url";
@@ -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 {
@@ -3582,6 +3622,88 @@ function createAgentsResource(http) {
3582
3622
  } catch (error) {
3583
3623
  throw await toPlatformError(error);
3584
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
+ }
3585
3707
  }
3586
3708
  };
3587
3709
  }
@@ -3708,6 +3830,74 @@ function createSkillsResource(http) {
3708
3830
  }
3709
3831
  };
3710
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
+ }
3711
3901
  function createTeamRequestsResource(http) {
3712
3902
  return { async submit(input) {
3713
3903
  const body = SubmitTeamRequestRequestSchema.parse(input);
@@ -3718,6 +3908,16 @@ function createTeamRequestsResource(http) {
3718
3908
  }
3719
3909
  } };
3720
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
+ }
3721
3921
  function createRecentsResource(http) {
3722
3922
  return {
3723
3923
  /** Always the viewer's own recents, scoped to their project memberships. */
@@ -3740,6 +3940,8 @@ function buildOAuthAuthorizeSearchParams(input) {
3740
3940
  if (input.createUserProvidedCredential) params.user = "true";
3741
3941
  const label = input.label?.trim();
3742
3942
  if (label) params.label = label;
3943
+ const credentialInstanceId = input.credentialInstanceId?.trim();
3944
+ if (credentialInstanceId) params.credentialInstanceId = credentialInstanceId;
3743
3945
  return params;
3744
3946
  }
3745
3947
  function createCredentialsResource(http) {
@@ -3910,6 +4112,34 @@ function createAppsResource(http) {
3910
4112
  } catch (error) {
3911
4113
  throw await toPlatformError(error);
3912
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
+ }
3913
4143
  }
3914
4144
  };
3915
4145
  }
@@ -4246,6 +4476,7 @@ function projectChannelPlatform(app) {
4246
4476
  resourceNoun: app.gateway.resourceNoun,
4247
4477
  webhookPathHint: app.gateway.webhookPathHint,
4248
4478
  supportsChannelDirectory: app.gateway.supportsChannelDirectory,
4479
+ ...app.gateway.connectAppId ? { connectAppId: app.gateway.connectAppId } : {},
4249
4480
  docsUrl: app.gateway.docsUrl
4250
4481
  });
4251
4482
  }
@@ -4362,6 +4593,7 @@ function createPlatformClient(options) {
4362
4593
  agents: createAgentsResource(http),
4363
4594
  workflows: createWorkflowsResource(http),
4364
4595
  skills: createSkillsResource(http),
4596
+ triggers: createTriggersResource(http),
4365
4597
  apps: createAppsResource(http),
4366
4598
  credentials: createCredentialsResource(http),
4367
4599
  history: createHistoryResource(http),
@@ -4378,6 +4610,7 @@ function createPlatformClient(options) {
4378
4610
  userAvatar: createUserAvatarResource(http),
4379
4611
  organizationSidebarBranding: createOrganizationSidebarBrandingResource(http, { getActiveOrganizationId: () => activeOrganizationId }),
4380
4612
  teamRequests: createTeamRequestsResource(http),
4613
+ marketingContact: createMarketingContactResource(http),
4381
4614
  getActiveOrganizationId: () => activeOrganizationId,
4382
4615
  setActiveOrganizationId
4383
4616
  };
@@ -4500,6 +4733,49 @@ async function ensureActiveOrganization(config) {
4500
4733
  throw new Error("No active organization. Run `keystroke auth login` or `keystroke config use org`.");
4501
4734
  }
4502
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
4503
4779
  //#region src/dev-session.ts
4504
4780
  function getDevSessionPath(configDir = getCliConfigDir()) {
4505
4781
  return join(configDir, "dev-session.json");
@@ -4538,13 +4814,30 @@ function readDevSession(configDir = getCliConfigDir()) {
4538
4814
  }
4539
4815
  //#endregion
4540
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";
4541
4819
  const projectScopedTarget = { projectScoped: true };
4542
- 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
+ };
4543
4832
  return {
4544
- baseUrl: getServerUrl(config),
4833
+ baseUrl: `${base}/api/projects/${DEFAULT_LOCAL_PROJECT_ID}`,
4834
+ projectId: DEFAULT_LOCAL_PROJECT_ID,
4545
4835
  mode: "local"
4546
4836
  };
4547
4837
  }
4838
+ function resolveLocalTarget(options = {}) {
4839
+ return resolveLocalTargetFromOrigin(resolvePublicPlatformOrigin(process.env), options);
4840
+ }
4548
4841
  function resolveOrgPlatformTarget(config) {
4549
4842
  return {
4550
4843
  baseUrl: `${getPlatformUrl(config).replace(/\/+$/, "")}/api`,
@@ -4568,18 +4861,16 @@ async function resolvePlatformTarget(config, projectRef) {
4568
4861
  };
4569
4862
  }
4570
4863
  async function resolveApiTarget(config, options = {}) {
4571
- if (options.local) return resolveLocalTarget(config);
4864
+ loadProjectEnv(process.cwd());
4865
+ if (options.local) return resolveLocalTarget(options);
4572
4866
  const devSession = readDevSession(getConfigDir(config));
4573
- if (devSession && getEffectiveApiTarget(config) !== "platform") return {
4574
- baseUrl: devSession.serverUrl,
4575
- mode: "local"
4576
- };
4867
+ if (devSession && getEffectiveApiTarget(config) !== "platform") return resolveLocalTargetFromOrigin(devSession.serverUrl, options);
4577
4868
  if (options.orgScoped || options.projectScoped === false) {
4578
- if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(config);
4869
+ if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
4579
4870
  return resolveOrgPlatformTarget(config);
4580
4871
  }
4581
4872
  if (options.projectId) return resolvePlatformTarget(config, options.projectId);
4582
- if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(config);
4873
+ if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
4583
4874
  if (!options.projectScoped) return resolveOrgPlatformTarget(config);
4584
4875
  const projectRef = options.projectId ?? config.get("activeProjectId");
4585
4876
  if (!projectRef) throw new Error("No project selected. Pass `--project <slug>` or run `keystroke config use project <slug>`.");
@@ -4666,6 +4957,9 @@ function formatHttpClientError(error, context) {
4666
4957
  if (origin && !getAccessToken(origin)) return "Not logged in. Run `keystroke auth login` first.";
4667
4958
  return "Authentication failed. Run `keystroke auth login` again.";
4668
4959
  }
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
+ }
4669
4963
  if (error.status === 0) {
4670
4964
  if (error.message && !isUnreachableServerError(error)) return error.message;
4671
4965
  return unreachableServerMessage(unreachableTarget(context));
@@ -5062,6 +5356,7 @@ function registerAppCreateCommand(app) {
5062
5356
  name: options.name.trim(),
5063
5357
  slug,
5064
5358
  description: options.description,
5359
+ source: "custom",
5065
5360
  fields: parseCustomAppFields(options.field)
5066
5361
  });
5067
5362
  process.stdout.write(`${JSON.stringify(created, null, 2)}\n`);
@@ -5135,7 +5430,7 @@ function resolveSyncedAppDirName(slug) {
5135
5430
  }
5136
5431
  function generateAppStub(app) {
5137
5432
  const exportName = resolveSyncedAppExportName(app.slug);
5138
- const credentialLines = Object.entries(app.credentialFields).map(([key, field]) => {
5433
+ const credentialLines = Object.entries(app.credentialFields ?? {}).map(([key, field]) => {
5139
5434
  return ` ${key}: ${field.optional ? "z.string().optional()" : "z.string()"},`;
5140
5435
  }).join("\n");
5141
5436
  return `import { defineApp } from "@keystrokehq/keystroke/app";
@@ -5216,11 +5511,6 @@ function resolveConnectAppSlug(slug, apps) {
5216
5511
  }
5217
5512
  return match;
5218
5513
  }
5219
- function buildConnectDeeplink(options) {
5220
- const base = options.webUrl.replace(/\/+$/, "");
5221
- const params = new URLSearchParams({ connect: options.appSlug });
5222
- return `${base}/${options.orgSlug}/apps?${params.toString()}`;
5223
- }
5224
5514
  async function runConnect(options) {
5225
5515
  const apps = await options.platform.apps.listCatalog();
5226
5516
  const app = resolveConnectAppSlug(options.slug, apps);
@@ -5256,6 +5546,90 @@ function registerConnectCommand(program) {
5256
5546
  }, void 0, { orgScoped: true }));
5257
5547
  }
5258
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
5623
+ });
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"));
5631
+ }
5632
+ //#endregion
5259
5633
  //#region src/commands/credentials/target-options.ts
5260
5634
  function resolveCredentialsTargetOptions(options = {}) {
5261
5635
  if (options.scopeType === "project") return {
@@ -5332,13 +5706,13 @@ function buildPlatformUpdatePatch(args) {
5332
5706
  //#endregion
5333
5707
  //#region src/commands/credentials/delete.ts
5334
5708
  function registerCredentialsDeleteCommand(credentials) {
5335
- 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 }) => {
5336
5710
  if (local) {
5337
5711
  const { client } = await createLocalCredentialsClient();
5338
- await client.credentials.deleteInstance(id);
5712
+ await client.credentials.deleteInstance(ref);
5339
5713
  return;
5340
5714
  }
5341
- await platform.credentials.delete(id);
5715
+ await platform.credentials.delete(ref);
5342
5716
  }));
5343
5717
  }
5344
5718
  //#endregion
@@ -5380,49 +5754,6 @@ function envRefName(raw) {
5380
5754
  return raw.slice(5);
5381
5755
  }
5382
5756
  //#endregion
5383
- //#region src/project/resolve-project-root.ts
5384
- function hasProjectLayout(dir) {
5385
- return existsSync(join(dir, "package.json")) && existsSync(join(dir, "src", "agents"));
5386
- }
5387
- function resolveProjectRoot(fromDir = process.cwd()) {
5388
- let dir = resolve(fromDir);
5389
- while (dir !== dirname(dir)) {
5390
- if (hasProjectLayout(dir)) return dir;
5391
- dir = dirname(dir);
5392
- }
5393
- if (hasProjectLayout(dir)) return dir;
5394
- throw new Error("Could not find keystroke project root (expected package.json and src/agents/)");
5395
- }
5396
- //#endregion
5397
- //#region src/project/load-project-env.ts
5398
- let loaded = false;
5399
- function parseEnvFile(contents) {
5400
- const values = {};
5401
- for (const line of contents.split("\n")) {
5402
- const trimmed = line.trim();
5403
- if (!trimmed || trimmed.startsWith("#")) continue;
5404
- const eq = trimmed.indexOf("=");
5405
- if (eq === -1) continue;
5406
- const key = trimmed.slice(0, eq).trim();
5407
- let value = trimmed.slice(eq + 1).trim();
5408
- if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
5409
- values[key] = value;
5410
- }
5411
- return values;
5412
- }
5413
- function loadProjectEnv(fromDir = process.cwd()) {
5414
- if (loaded) return;
5415
- loaded = true;
5416
- let envPath;
5417
- try {
5418
- envPath = join(resolveProjectRoot(fromDir), ".env");
5419
- } catch {
5420
- return;
5421
- }
5422
- if (!existsSync(envPath)) return;
5423
- for (const [key, value] of Object.entries(parseEnvFile(readFileSync(envPath, "utf8")))) if (process.env[key] === void 0) process.env[key] = value;
5424
- }
5425
- //#endregion
5426
5757
  //#region src/commands/credentials/parse-value.ts
5427
5758
  function parseCredentialValueFields(fields) {
5428
5759
  const value = {};
@@ -5468,8 +5799,7 @@ function collectSetValues$2(value, previous) {
5468
5799
  //#region src/commands/credentials/format-set-conflict-error.ts
5469
5800
  function describeInstance(instance) {
5470
5801
  const defaultStatus = instance.isDefault ? "default" : "not default";
5471
- const labelStatus = instance.label ? `label: ${instance.label}` : "no label";
5472
- return `id: ${instance.id}, ${defaultStatus}, ${labelStatus}`;
5802
+ return `${instance.name ? `name: ${instance.name}` : `slug: ${instance.slug}`}, ${defaultStatus}`;
5473
5803
  }
5474
5804
  function formatSetFields(setFields) {
5475
5805
  return setFields.map((field) => `--set ${field}`).join(" ");
@@ -5478,10 +5808,10 @@ function formatSetConflictError(args) {
5478
5808
  const binary = cliBinaryName();
5479
5809
  const setArgs = formatSetFields(args.setFields);
5480
5810
  const listCmd = `${binary} credentials list --key ${args.key}`;
5481
- 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}`;
5482
5812
  if (args.matching.length === 1) {
5483
5813
  const instance = args.matching[0];
5484
- const updateCmd = `${binary} credentials update ${instance.id} ${setArgs}`;
5814
+ const updateCmd = `${binary} credentials update ${instance.slug} ${setArgs}`;
5485
5815
  return [
5486
5816
  `An ${args.key} credential already exists in ${args.scope} scope (${describeInstance(instance)}).`,
5487
5817
  "credentials set creates a new instance — it does not update an existing one.",
@@ -5494,7 +5824,7 @@ function formatSetConflictError(args) {
5494
5824
  }
5495
5825
  const instanceLines = args.matching.map((instance) => ` • ${describeInstance(instance)}`);
5496
5826
  return [
5497
- `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:`,
5498
5828
  ...instanceLines,
5499
5829
  "To add another credential in the same scope:",
5500
5830
  ` ${addSecondCmd}`,
@@ -5502,7 +5832,7 @@ function formatSetConflictError(args) {
5502
5832
  ].join("\n");
5503
5833
  }
5504
5834
  async function assertNoSetConflict(client, args) {
5505
- if (args.label) return;
5835
+ if (args.slug) return;
5506
5836
  const { instances } = await client.credentials.listInstances({ key: args.key });
5507
5837
  const matching = instances.filter((instance) => instance.scopeType === args.scopeType && (args.scopeType !== "project" || instance.scopeId === args.projectId));
5508
5838
  if (matching.length === 0) return;
@@ -5538,7 +5868,7 @@ function parseCredentialSetScopes(scopes, projectSlugs) {
5538
5868
  //#endregion
5539
5869
  //#region src/commands/credentials/set.ts
5540
5870
  function registerCredentialsSetCommand(credentials) {
5541
- 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 }) => {
5542
5872
  const value = parseCredentialValueFields(options.set);
5543
5873
  const parsedScopes = parseCredentialSetScopes(options.scope, options.projectSlug);
5544
5874
  if (local) {
@@ -5546,19 +5876,21 @@ function registerCredentialsSetCommand(credentials) {
5546
5876
  const targets = expandLocalCredentialTargets(parsedScopes);
5547
5877
  const instances = [];
5548
5878
  for (const target of targets) {
5879
+ const displayName = options.name ?? options.label;
5549
5880
  await assertNoSetConflict(client, {
5550
5881
  key,
5551
5882
  scope: target.scope,
5552
5883
  scopeType: target.scopeType,
5553
5884
  projectId: target.projectSlug,
5554
- label: options.label,
5885
+ slug: options.slug,
5555
5886
  setFields: options.set
5556
5887
  });
5557
5888
  instances.push(await client.credentials.createInstance({
5558
5889
  key,
5559
5890
  scopeType: target.scopeType,
5560
5891
  scopeId: target.projectSlug,
5561
- label: options.label,
5892
+ ...options.slug !== void 0 ? { slug: options.slug } : {},
5893
+ ...displayName !== void 0 ? { name: displayName } : {},
5562
5894
  isDefault: options.default,
5563
5895
  value
5564
5896
  }));
@@ -5614,12 +5946,14 @@ function expandLocalCredentialTargets(targets) {
5614
5946
  //#endregion
5615
5947
  //#region src/commands/credentials/update.ts
5616
5948
  function registerCredentialsUpdateCommand(credentials) {
5617
- 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 }) => {
5618
5950
  const value = options.set.length > 0 ? parseCredentialValueFields(options.set) : void 0;
5951
+ const displayName = options.name ?? options.label;
5619
5952
  if (local) {
5620
5953
  const { client } = await createLocalCredentialsClient();
5621
- const result = await client.credentials.updateInstance(id, {
5622
- ...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 } : {},
5623
5957
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5624
5958
  ...value ? { value } : {}
5625
5959
  });
@@ -5627,11 +5961,11 @@ function registerCredentialsUpdateCommand(credentials) {
5627
5961
  return;
5628
5962
  }
5629
5963
  const patch = buildPlatformUpdatePatch({
5630
- ...options.label !== void 0 ? { label: options.label } : {},
5964
+ ...displayName !== void 0 ? { label: displayName } : {},
5631
5965
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5632
5966
  ...value ? { value } : {}
5633
5967
  });
5634
- const credential = await platform.credentials.update(id, patch);
5968
+ const credential = await platform.credentials.update(ref, patch);
5635
5969
  process.stdout.write(`${JSON.stringify({ credential }, null, 2)}\n`);
5636
5970
  }));
5637
5971
  }
@@ -5648,11 +5982,13 @@ function registerCredentialsCommand(program) {
5648
5982
  registerCredentialsUpdateCommand(credentials);
5649
5983
  registerCredentialsRotateKeyCommand(credentials);
5650
5984
  registerCredentialsDeleteCommand(credentials);
5985
+ registerCredentialsAssignmentsCommands(credentials);
5986
+ registerCredentialsConsumersCommands(credentials);
5651
5987
  }
5652
5988
  //#endregion
5653
5989
  //#region src/auth/resolve-login-targets.ts
5654
5990
  function resolveAuthLoginTargets(options, config) {
5655
- const webUrl = options.webUrl ?? "https://app.keystroke.ai";
5991
+ const webUrl = options.webUrl ?? "https://keystroke.ai";
5656
5992
  return {
5657
5993
  webUrl,
5658
5994
  platformUrl: resolvePlatformUrlForWebUrl(webUrl, {
@@ -5759,7 +6095,7 @@ function registerBuildCommand(program) {
5759
6095
  program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
5760
6096
  try {
5761
6097
  const root = resolveProjectRoot(options.dir);
5762
- const { buildApp } = await import("./dist-B9XaHV_2.mjs");
6098
+ const { buildApp } = await import("./dist-jchdNGBU.mjs");
5763
6099
  await buildApp({ root });
5764
6100
  process.stdout.write(`Built ${root}\n`);
5765
6101
  } catch (error) {
@@ -5770,109 +6106,6 @@ function registerBuildCommand(program) {
5770
6106
  });
5771
6107
  }
5772
6108
  //#endregion
5773
- //#region ../../packages/storage/dist/pack-artifact-NGxvGcXq.mjs
5774
- /**
5775
- * Pack a directory tree that contains a `dist/` folder into a gzip tarball
5776
- * suitable for project-server extraction.
5777
- */
5778
- function packDistTree(rootContainingDist) {
5779
- const tempDir = mkdtempSync(join(tmpdir(), "keystroke-artifact-pack-"));
5780
- const archivePath = join(tempDir, "artifact.tgz");
5781
- try {
5782
- const result = spawnSync("tar", [
5783
- "-czf",
5784
- archivePath,
5785
- "--exclude=._*",
5786
- "--exclude=.DS_Store",
5787
- "-C",
5788
- rootContainingDist,
5789
- "dist"
5790
- ], {
5791
- encoding: "utf8",
5792
- env: {
5793
- ...process.env,
5794
- COPYFILE_DISABLE: "1"
5795
- }
5796
- });
5797
- if (result.status !== 0) throw new Error(result.stderr?.trim() || "Failed to pack project artifact");
5798
- return readFileSync(archivePath);
5799
- } finally {
5800
- rmSync(tempDir, {
5801
- recursive: true,
5802
- force: true
5803
- });
5804
- }
5805
- }
5806
- /** Extract a packed project artifact tarball into `destDir` (creates `destDir/dist/`). */
5807
- function extractProjectArtifact(archive, destDir) {
5808
- const tempDir = mkdtempSync(join(tmpdir(), "keystroke-artifact-extract-"));
5809
- const archivePath = join(tempDir, "artifact.tgz");
5810
- try {
5811
- writeFileSync(archivePath, archive);
5812
- const result = spawnSync("tar", [
5813
- "-xzf",
5814
- archivePath,
5815
- "-C",
5816
- destDir
5817
- ], {
5818
- encoding: "utf8",
5819
- env: {
5820
- ...process.env,
5821
- COPYFILE_DISABLE: "1"
5822
- }
5823
- });
5824
- if (result.status !== 0) throw new Error(result.stderr?.trim() || "Failed to extract project artifact");
5825
- } finally {
5826
- rmSync(tempDir, {
5827
- recursive: true,
5828
- force: true
5829
- });
5830
- }
5831
- }
5832
- function moduleFileOf(entry) {
5833
- return "moduleFile" in entry && typeof entry.moduleFile === "string" ? entry.moduleFile : void 0;
5834
- }
5835
- /** Replace manifest rows for rebuilt modules while keeping untouched routes and metadata. */
5836
- function mergeStoredRouteManifest(base, rebuiltEntries) {
5837
- const rebuiltModuleFiles = new Set(rebuiltEntries.map(moduleFileOf).filter((value) => Boolean(value)));
5838
- const keptEntries = base.entries.filter((entry) => {
5839
- const moduleFile = moduleFileOf(entry);
5840
- if (!moduleFile) return true;
5841
- return !rebuiltModuleFiles.has(moduleFile);
5842
- });
5843
- const filteredRebuilt = rebuiltEntries.filter((entry) => entry.kind !== "health");
5844
- return {
5845
- ...base,
5846
- entries: [...keptEntries, ...filteredRebuilt]
5847
- };
5848
- }
5849
- async function mergeFilteredArtifact(input) {
5850
- const mergeRoot = mkdtempSync(join(tmpdir(), "keystroke-artifact-merge-"));
5851
- try {
5852
- extractProjectArtifact(input.baseArchive, mergeRoot);
5853
- const manifestPath = join(mergeRoot, ROUTE_MANIFEST_REL_PATH);
5854
- const mergedManifest = mergeStoredRouteManifest(StoredRouteManifestSchema.parse(JSON.parse(readFileSync(manifestPath, "utf8"))), input.filtered.manifestEntries);
5855
- writeFileSync(manifestPath, `${JSON.stringify(mergedManifest, null, 2)}\n`);
5856
- for (const file of input.filtered.files) {
5857
- const destination = join(mergeRoot, "dist", file.relativePath);
5858
- mkdirSync(dirname(destination), { recursive: true });
5859
- writeFileSync(destination, file.contents);
5860
- if (file.sourceMap) writeFileSync(`${destination}.map`, file.sourceMap);
5861
- }
5862
- return packDistTree(mergeRoot);
5863
- } finally {
5864
- rmSync(mergeRoot, {
5865
- recursive: true,
5866
- force: true
5867
- });
5868
- }
5869
- }
5870
- /** Pack `dist/` into a gzip tarball suitable for `/app` extraction in the project server image. */
5871
- function packProjectArtifact(projectRoot) {
5872
- if (!existsSync(join(projectRoot, "dist"))) throw new Error("dist/ not found — run keystroke build first");
5873
- return packDistTree(projectRoot);
5874
- }
5875
- //#endregion
5876
6109
  //#region src/commands/deploy.ts
5877
6110
  const POLL_INTERVAL_MS = 2e3;
5878
6111
  const DEPLOY_TIMEOUT_MS = 12e4;
@@ -5916,7 +6149,7 @@ async function sleep(ms) {
5916
6149
  }
5917
6150
  async function buildDeployArchive(client, root, projectId, filter) {
5918
6151
  if (filter?.length) {
5919
- const { buildFilteredApp } = await import("./dist-B9XaHV_2.mjs");
6152
+ const { buildFilteredApp } = await import("./dist-jchdNGBU.mjs");
5920
6153
  const filtered = await buildFilteredApp({
5921
6154
  root,
5922
6155
  filter,
@@ -5938,7 +6171,7 @@ async function buildDeployArchive(client, root, projectId, filter) {
5938
6171
  sourceFiles: filtered.sourceFiles
5939
6172
  };
5940
6173
  }
5941
- const { buildApp } = await import("./dist-B9XaHV_2.mjs");
6174
+ const { buildApp } = await import("./dist-jchdNGBU.mjs");
5942
6175
  const { sourceFiles } = await buildApp({
5943
6176
  root,
5944
6177
  collectSources: true,
@@ -6006,6 +6239,13 @@ function registerDeployCommand(program) {
6006
6239
  });
6007
6240
  }
6008
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
6009
6249
  //#region src/project/runtime-child-env.ts
6010
6250
  /** Strip dev-only Node flags so the API child loads built `dist/`, not package `src/`. */
6011
6251
  function runtimeChildNodeOptions(nodeOptions) {
@@ -6044,14 +6284,13 @@ function runtimeChildEnv(parentEnv, overrides) {
6044
6284
  env.DATABASE_URL = "file:./data/public.db";
6045
6285
  }
6046
6286
  env.KEYSTROKE_APP_MODE ??= "standalone";
6047
- env.PROJECT_ID ??= "default";
6048
6287
  return env;
6049
6288
  }
6050
6289
  //#endregion
6051
6290
  //#region src/project/bootstrap-run.ts
6052
6291
  /** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
6053
6292
  async function resolveBootstrapRun(options) {
6054
- const { resolveRuntimeBuildArtifact } = await import("./dist-B9XaHV_2.mjs");
6293
+ const { resolveRuntimeBuildArtifact } = await import("./dist-jchdNGBU.mjs");
6055
6294
  const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
6056
6295
  const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/standalone-bootstrap.mjs");
6057
6296
  const args = [`--import=${loader}`];
@@ -6061,10 +6300,9 @@ async function resolveBootstrapRun(options) {
6061
6300
  const childEnv = runtimeChildEnv(process.env, {
6062
6301
  KEYSTROKE_ROOT: options.root,
6063
6302
  KEYSTROKE_RUNTIME_NODE_MODULES: options.runtimeNodeModules,
6064
- KEYSTROKE_APP_MODE: "standalone",
6065
- PROJECT_ID: process.env.PROJECT_ID ?? "default"
6303
+ KEYSTROKE_APP_MODE: "standalone"
6066
6304
  });
6067
- childEnv.PORT = String(listenPortFromPublicUrl(childEnv.PUBLIC_SERVER_URL, options.apiPort));
6305
+ childEnv.PORT = String(listenPortFromPublicUrl(childEnv.PUBLIC_PLATFORM_URL, options.apiPort));
6068
6306
  return {
6069
6307
  cwd: options.root,
6070
6308
  args,
@@ -6156,8 +6394,8 @@ const DEV_BANNER = "keystroke dev: watch rebuilds dist/ and restarts the API —
6156
6394
  function stopChild(child) {
6157
6395
  if (child && !child.killed && child.pid !== void 0) child.kill("SIGTERM");
6158
6396
  }
6159
- function resolveDevServerUrl(config, portOverride) {
6160
- const url = new URL(getServerUrl(config));
6397
+ function resolveDevServerUrl(root, portOverride) {
6398
+ const url = new URL(resolveLocalApiOrigin(root));
6161
6399
  if (portOverride !== void 0) url.port = String(portOverride);
6162
6400
  return url.origin;
6163
6401
  }
@@ -6165,10 +6403,9 @@ async function runDev(options) {
6165
6403
  const root = resolveProjectRoot(options.dir);
6166
6404
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
6167
6405
  ensureNativeDeps(runtimeNodeModules);
6168
- const cliConfig = createCliConfig();
6169
- const configDir = getConfigDir(cliConfig);
6406
+ const configDir = getConfigDir(createCliConfig());
6170
6407
  process.stdout.write(DEV_BANNER);
6171
- const serverUrl = resolveDevServerUrl(cliConfig, options.port);
6408
+ const serverUrl = resolveDevServerUrl(root, options.port);
6172
6409
  const apiPort = Number(new URL(serverUrl).port || 80);
6173
6410
  writeDevSession({
6174
6411
  pid: process.pid,
@@ -6202,7 +6439,7 @@ async function runDev(options) {
6202
6439
  process.on("SIGINT", shutdown);
6203
6440
  process.on("SIGTERM", shutdown);
6204
6441
  try {
6205
- const { watchApp } = await import("./dist-B9XaHV_2.mjs");
6442
+ const { watchApp } = await import("./dist-jchdNGBU.mjs");
6206
6443
  await watchApp({
6207
6444
  root,
6208
6445
  clean: false,
@@ -6352,10 +6589,11 @@ const INIT_CATALOG_VERSIONS = {
6352
6589
  vitest: "^4.1.7",
6353
6590
  "@types/node": "^25.9.1"
6354
6591
  };
6592
+ const INIT_KEYSTROKE_VERSION = "^0.1.5";
6355
6593
  //#endregion
6356
6594
  //#region src/init/copy-template.ts
6357
6595
  function renderTemplate(content, variables) {
6358
- 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);
6359
6597
  for (const [dep, version] of Object.entries(INIT_CATALOG_VERSIONS)) rendered = rendered.replaceAll(`{{catalog:${dep}}}`, version);
6360
6598
  return rendered;
6361
6599
  }
@@ -6531,6 +6769,33 @@ function resolvePlaygroundRoot(targetDir) {
6531
6769
  const rel = relative(join(root, "playground"), resolve(targetDir));
6532
6770
  return rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel) ? root : null;
6533
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
+ }
6534
6799
  async function directoryExists(path) {
6535
6800
  try {
6536
6801
  await access(path);
@@ -6564,6 +6829,10 @@ async function runInit(options) {
6564
6829
  version: options.version
6565
6830
  });
6566
6831
  await scaffoldEmptySrcDirs(targetDir);
6832
+ if (options.noExample) {
6833
+ await removeExampleFiles(targetDir);
6834
+ await stripExampleReadme(targetDir);
6835
+ }
6567
6836
  if (playgroundRoot) await applyPlaygroundManifest(targetDir, projectName, playgroundRoot);
6568
6837
  else await scaffoldProjectDotfiles(targetDir);
6569
6838
  await syncBundledSkills(targetDir);
@@ -6580,7 +6849,7 @@ async function runInit(options) {
6580
6849
  //#endregion
6581
6850
  //#region src/commands/init.ts
6582
6851
  function registerInitCommand(program) {
6583
- 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) => {
6584
6853
  try {
6585
6854
  const result = await runInit({
6586
6855
  directory,
@@ -6589,6 +6858,7 @@ function registerInitCommand(program) {
6589
6858
  yes: options.yes,
6590
6859
  skipInstall: options.skipInstall,
6591
6860
  packageManager: options.pm,
6861
+ noExample: options.example === false,
6592
6862
  version: readCliVersion()
6593
6863
  });
6594
6864
  process.stdout.write(`Created keystroke project "${result.projectName}" at ${result.targetDir}\n`);
@@ -7017,18 +7287,18 @@ function registerProjectCommand(program) {
7017
7287
  }
7018
7288
  //#endregion
7019
7289
  //#region src/commands/start.ts
7020
- function resolveStartServerUrl(portOverride) {
7021
- const url = new URL(getServerUrl(createCliConfig()));
7290
+ function resolveStartServerUrl(root, portOverride) {
7291
+ const url = new URL(resolveLocalApiOrigin(root));
7022
7292
  if (portOverride !== void 0) url.port = String(portOverride);
7023
7293
  return url.origin;
7024
7294
  }
7025
7295
  async function runStart(options) {
7026
7296
  const root = resolveProjectRoot(options.dir);
7027
- const serverUrl = resolveStartServerUrl(options.port);
7297
+ const serverUrl = resolveStartServerUrl(root, options.port);
7028
7298
  const apiPort = Number(new URL(serverUrl).port || 80);
7029
7299
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
7030
7300
  ensureNativeDeps(runtimeNodeModules);
7031
- const { buildApp } = await import("./dist-B9XaHV_2.mjs");
7301
+ const { buildApp } = await import("./dist-jchdNGBU.mjs");
7032
7302
  await buildApp({
7033
7303
  root,
7034
7304
  clean: false
@@ -7111,6 +7381,61 @@ function registerTriggerRunsCommand(trigger) {
7111
7381
  }));
7112
7382
  }
7113
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
7114
7439
  //#region src/commands/trigger/index.ts
7115
7440
  function registerTriggerCommand(program) {
7116
7441
  const trigger = program.command("trigger").description("Invoke and inspect triggers");
@@ -7119,6 +7444,7 @@ function registerTriggerCommand(program) {
7119
7444
  registerTriggerUrlCommand(trigger);
7120
7445
  registerTriggerPollCommand(trigger);
7121
7446
  registerTriggerRunsCommand(trigger);
7447
+ registerTriggerAttachmentCommand(trigger);
7122
7448
  }
7123
7449
  //#endregion
7124
7450
  //#region src/commands/workflow/list.ts
@@ -7412,9 +7738,9 @@ function registerConfigCommand(program) {
7412
7738
  const cliConfig = createCliConfig();
7413
7739
  const configDir = getConfigDir(cliConfig);
7414
7740
  process.stdout.write(`${JSON.stringify({
7415
- serverUrl: cliConfig.get("serverUrl"),
7416
7741
  webUrl: cliConfig.get("webUrl"),
7417
7742
  platformUrl: getPlatformUrl(cliConfig),
7743
+ localApiUrl: resolveLocalApiOrigin(process.cwd()),
7418
7744
  activeOrganizationId: cliConfig.get("activeOrganizationId"),
7419
7745
  activeProjectId: cliConfig.get("activeProjectId"),
7420
7746
  apiTarget: getEffectiveApiTarget(cliConfig),
@@ -7551,7 +7877,7 @@ function createProgram() {
7551
7877
  return program;
7552
7878
  }
7553
7879
  async function runCli(argv) {
7554
- const { maybeAutoUpdate } = await import("./maybe-auto-update-DHt-mVf1.mjs");
7880
+ const { maybeAutoUpdate } = await import("./maybe-auto-update-ClXO7U-6.mjs");
7555
7881
  await maybeAutoUpdate(argv);
7556
7882
  createProgram().parse(argv);
7557
7883
  }