@keystrokehq/cli 0.1.5 → 0.1.9

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-BPdyQaUt.mjs +19268 -0
  3. package/dist/dist-BPdyQaUt.mjs.map +1 -0
  4. package/dist/dist-Dz6iW5q5.mjs +3 -0
  5. package/dist/{dist-B9XaHV_2.mjs → dist-IOphuHYN.mjs} +57 -20
  6. package/dist/dist-IOphuHYN.mjs.map +1 -0
  7. package/dist/{dist-C3YClLXV.mjs → dist-YV-kApfg.mjs} +790 -73
  8. package/dist/dist-YV-kApfg.mjs.map +1 -0
  9. package/dist/index.mjs +559 -225
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/{maybe-auto-update-DHt-mVf1.mjs → maybe-auto-update-BiR_kXZX.mjs} +2 -2
  12. package/dist/{maybe-auto-update-DHt-mVf1.mjs.map → maybe-auto-update-BiR_kXZX.mjs.map} +1 -1
  13. package/dist/pack-artifact-DVnIKrsg-BtNTTQcz.mjs +112 -0
  14. package/dist/pack-artifact-DVnIKrsg-BtNTTQcz.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-BGuC7Cpu.mjs} +10 -14
  34. package/dist/version-BGuC7Cpu.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 HistoryRunDetailResponseSchema, $t as TriggerDetailResponseSchema, A as CreateCustomAppRequestSchema, At as PresignUserAvatarRequestSchema, B as CredentialConsumerListQuerySchema, C as ConnectAuthorizeUrlResponseSchema, Cn as WorkflowSummaryListResponseSchema, Ct as OrganizationSidebarBrandingSchema, D as CreateCredentialInstanceBodySchema, Dn as WorkspaceTriggerOverviewSchema, Dt as PresignOrgLogoResponseSchema, E as CreateApiKeyResponseSchema, En as WorkspaceTriggerListResponseSchema, Et as PresignOrgLogoRequestSchema, F as CreateProjectRequestSchema, Fn as parseErrorResponse, Ft as ProjectSlugAvailabilityResponseSchema, G as DownloadActiveProjectArtifactResponseSchema, Gt as StartKeystrokeConnectionInputSchema, H as CredentialInstanceListResponseSchema, Ht as SkillSummaryDetailResponseSchema, I as CreateProjectResponseSchema, It as PromptInputSchema, J as GetCredentialResponseSchema, Jt as StartMcpOAuthConnectionResultSchema, K as ErrorResponseSchema, Kt as StartKeystrokeConnectionResultSchema, L as CredentialAssignmentListQuerySchema, Ln as resolvePublicPlatformOrigin, Lt as PromptResponseSchema, M as CreateOrganizationRequestSchema, Mt as ProjectReachabilityResponseSchema, N as CreateOrganizationResponseSchema, Nt as ProjectResponseSchema, O as CreateCredentialsRequestSchema, On as WorkspaceTriggerRunListResponseSchema, Ot as PresignProjectSourceRequestSchema, P as CreateProjectArtifactResponseSchema, Pn as parseAppSlug, Pt as ProjectSettingsResponseSchema, Q as HistoryRunCancelResponseSchema, Qt as SubmitTeamRequestRequestSchema, R as CredentialAssignmentListResponseSchema, Rn as slugifyAppName, Rt as QueuedAgentPromptResponseSchema, S as CompleteProjectArtifactResponseSchema, Sn as WorkflowSummaryDetailResponseSchema, St as OrganizationSidebarBrandingPatchSchema, T as CreateApiKeyRequestSchema, Tn as WorkspaceTriggerFileSchema, Tt as PollRunResponseSchema, U as CredentialInstanceRecordSchema, Ut as SkillSummaryListResponseSchema, V as CredentialConsumerListResponseSchema, Vt as RecentResourceListResponseSchema, W as DeclineOrganizationInvitationResponseSchema, Wt as SlugAvailabilityResponseSchema, X as GraphqlDiscoverResponseSchema, Xt as StartOAuthConnectionResultSchema, Y as GetCustomAppResponseSchema, Yt as StartOAuthConnectionInputSchema, Z as HealthResponseSchema, Zt as SubmitMarketingContactRequestSchema, _ as ChannelAccountListResponseSchema, _n as UserAvatarSchema, _t as ListProjectMembersResponseSchema, a as AgentSessionDetailResponseSchema, an as UpdateCredentialRequestSchema, at as InviteProjectMembersResponseSchema, b as ChannelDirectoryListResponseSchema, bn as WorkflowRunDetailResponseSchema, bt as McpDiscoverResponseSchema, c as AgentSummaryListResponseSchema, cn as UpdateOrganizationRequestSchema, ct as ListAgentWorkspaceFilesResponseSchema, d as AssignCredentialBodySchema, dn as UpdateProjectRequestSchema, dt as ListCredentialsResponseSchema, en as TriggerListResponseSchema, et as HistoryRunListQuerySchema, f as BindChannelBodySchema, fn as UpdateProjectSettingsRequestSchema, ft as ListOrganizationInvitationsResponseSchema, g as CatalogAppsPageResponseSchema, gn as UserAvatarPatchSchema, gt as ListProjectFilesResponseSchema, h as CatalogAppDetailResponseSchema, hn as UpsertGatewayAttachmentBodySchema, ht as ListProjectDeploymentsResponseSchema, i as AgentSessionChatStateResponseSchema, in as UpdateCredentialInstanceBodySchema, it as InviteProjectMembersRequestSchema, j as CreateCustomAppResponseSchema, jn as listenPortFromPublicUrl, jt as PresignUserAvatarResponseSchema, k as CreateCredentialsResponseSchema, kn as buildConnectDeeplink, kt as PresignProjectSourceResponseSchema, l as AgentTriggerSummaryListResponseSchema, ln as UpdateProjectMemberRequestSchema, lt as ListApiKeysResponseSchema, m as CatalogActionsPageResponseSchema, mn as UploadProjectSourceResponseSchema, mt as ListOrganizationsResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nn as TriggerRunListResponseSchema, nt as InviteOrganizationMembersRequestSchema, o as AgentSessionListResponseSchema, on as UpdateOrganizationMemberRequestSchema, p as CatalogActionDetailResponseSchema, pn as UploadProjectSourceManifestRequestSchema, pt as ListOrganizationMembersResponseSchema, q as GatewayAttachmentRecordSchema, qt as StartMcpOAuthConnectionInputSchema, r as ActiveOrganizationResponseSchema, rn as UpdateChannelBindingBodySchema, rt as InviteOrganizationMembersResponseSchema, s as AgentSummaryDetailResponseSchema, sn as UpdateOrganizationMemberResponseSchema, st as ListAgentMemoryFilesResponseSchema, t as ACTIVE_ORG_HEADER, tn as TriggerRunDetailResponseSchema, tt as HistoryRunListResponseSchema, u as AppSlugAvailabilityResponseSchema, un as UpdateProjectMemberResponseSchema, ut as ListAppsResponseSchema, v as ChannelConnectionListResponseSchema, vn as UserPreferencesPatchSchema, vt as ListProjectMetricsResponseSchema, w as ConnectProvidersResponseSchema, wn as WorkspaceTriggerDetailSchema, wt as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, x as ChannelPlatformSchema, xn as WorkflowRunListResponseSchema, xt as OpenApiDiscoverResponseSchema, y as ChannelConnectionSchema, yn as UserPreferencesSchema, yt as ListProjectsResponseSchema, z as CredentialAssignmentRecordSchema, zt as QueuedRunResponseSchema } from "./dist-YV-kApfg.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-BGuC7Cpu.mjs";
4
+ import { n as packProjectArtifact, t as mergeFilteredArtifact } from "./pack-artifact-DVnIKrsg-BtNTTQcz.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,42 @@ 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 discoverGraphql(input) {
4133
+ try {
4134
+ const data = await http.post("/api/apps/discover-graphql", { json: input }).json();
4135
+ return GraphqlDiscoverResponseSchema.parse(data);
4136
+ } catch (error) {
4137
+ throw await toPlatformError(error);
4138
+ }
4139
+ },
4140
+ async startMcpOAuthConnection(slug, input) {
4141
+ try {
4142
+ const body = StartMcpOAuthConnectionInputSchema.parse({
4143
+ ...input,
4144
+ appSlug: slug
4145
+ });
4146
+ const data = await http.post(`/api/apps/${encodeURIComponent(slug)}/mcp/oauth/connections`, { json: body }).json();
4147
+ return StartMcpOAuthConnectionResultSchema.parse(data);
4148
+ } catch (error) {
4149
+ throw await toPlatformError(error);
4150
+ }
3913
4151
  }
3914
4152
  };
3915
4153
  }
@@ -4246,6 +4484,7 @@ function projectChannelPlatform(app) {
4246
4484
  resourceNoun: app.gateway.resourceNoun,
4247
4485
  webhookPathHint: app.gateway.webhookPathHint,
4248
4486
  supportsChannelDirectory: app.gateway.supportsChannelDirectory,
4487
+ ...app.gateway.connectAppId ? { connectAppId: app.gateway.connectAppId } : {},
4249
4488
  docsUrl: app.gateway.docsUrl
4250
4489
  });
4251
4490
  }
@@ -4362,6 +4601,7 @@ function createPlatformClient(options) {
4362
4601
  agents: createAgentsResource(http),
4363
4602
  workflows: createWorkflowsResource(http),
4364
4603
  skills: createSkillsResource(http),
4604
+ triggers: createTriggersResource(http),
4365
4605
  apps: createAppsResource(http),
4366
4606
  credentials: createCredentialsResource(http),
4367
4607
  history: createHistoryResource(http),
@@ -4378,6 +4618,7 @@ function createPlatformClient(options) {
4378
4618
  userAvatar: createUserAvatarResource(http),
4379
4619
  organizationSidebarBranding: createOrganizationSidebarBrandingResource(http, { getActiveOrganizationId: () => activeOrganizationId }),
4380
4620
  teamRequests: createTeamRequestsResource(http),
4621
+ marketingContact: createMarketingContactResource(http),
4381
4622
  getActiveOrganizationId: () => activeOrganizationId,
4382
4623
  setActiveOrganizationId
4383
4624
  };
@@ -4500,6 +4741,49 @@ async function ensureActiveOrganization(config) {
4500
4741
  throw new Error("No active organization. Run `keystroke auth login` or `keystroke config use org`.");
4501
4742
  }
4502
4743
  //#endregion
4744
+ //#region src/project/resolve-project-root.ts
4745
+ function hasProjectLayout(dir) {
4746
+ return existsSync(join(dir, "package.json")) && existsSync(join(dir, "src", "agents"));
4747
+ }
4748
+ function resolveProjectRoot(fromDir = process.cwd()) {
4749
+ let dir = resolve(fromDir);
4750
+ while (dir !== dirname(dir)) {
4751
+ if (hasProjectLayout(dir)) return dir;
4752
+ dir = dirname(dir);
4753
+ }
4754
+ if (hasProjectLayout(dir)) return dir;
4755
+ throw new Error("Could not find keystroke project root (expected package.json and src/agents/)");
4756
+ }
4757
+ //#endregion
4758
+ //#region src/project/load-project-env.ts
4759
+ let loaded = false;
4760
+ function parseEnvFile(contents) {
4761
+ const values = {};
4762
+ for (const line of contents.split("\n")) {
4763
+ const trimmed = line.trim();
4764
+ if (!trimmed || trimmed.startsWith("#")) continue;
4765
+ const eq = trimmed.indexOf("=");
4766
+ if (eq === -1) continue;
4767
+ const key = trimmed.slice(0, eq).trim();
4768
+ let value = trimmed.slice(eq + 1).trim();
4769
+ if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
4770
+ values[key] = value;
4771
+ }
4772
+ return values;
4773
+ }
4774
+ function loadProjectEnv(fromDir = process.cwd()) {
4775
+ if (loaded) return;
4776
+ loaded = true;
4777
+ let envPath;
4778
+ try {
4779
+ envPath = join(resolveProjectRoot(fromDir), ".env");
4780
+ } catch {
4781
+ return;
4782
+ }
4783
+ if (!existsSync(envPath)) return;
4784
+ for (const [key, value] of Object.entries(parseEnvFile(readFileSync(envPath, "utf8")))) if (process.env[key] === void 0) process.env[key] = value;
4785
+ }
4786
+ //#endregion
4503
4787
  //#region src/dev-session.ts
4504
4788
  function getDevSessionPath(configDir = getCliConfigDir()) {
4505
4789
  return join(configDir, "dev-session.json");
@@ -4538,13 +4822,30 @@ function readDevSession(configDir = getCliConfigDir()) {
4538
4822
  }
4539
4823
  //#endregion
4540
4824
  //#region src/resolve-api-target.ts
4825
+ /** Standalone local server default project id — keep in sync with @keystrokehq/database. */
4826
+ const DEFAULT_LOCAL_PROJECT_ID = "default";
4541
4827
  const projectScopedTarget = { projectScoped: true };
4542
- function resolveLocalTarget(config) {
4828
+ function resolveLocalTargetFromOrigin(origin, options = {}) {
4829
+ const base = origin.replace(/\/+$/, "");
4830
+ if (!options.projectScoped) return {
4831
+ baseUrl: base,
4832
+ mode: "local"
4833
+ };
4834
+ const projectPathMatch = base.match(/^(.*\/api\/projects\/([^/]+))$/);
4835
+ if (projectPathMatch) return {
4836
+ baseUrl: projectPathMatch[1],
4837
+ projectId: projectPathMatch[2],
4838
+ mode: "local"
4839
+ };
4543
4840
  return {
4544
- baseUrl: getServerUrl(config),
4841
+ baseUrl: `${base}/api/projects/${DEFAULT_LOCAL_PROJECT_ID}`,
4842
+ projectId: DEFAULT_LOCAL_PROJECT_ID,
4545
4843
  mode: "local"
4546
4844
  };
4547
4845
  }
4846
+ function resolveLocalTarget(options = {}) {
4847
+ return resolveLocalTargetFromOrigin(resolvePublicPlatformOrigin(process.env), options);
4848
+ }
4548
4849
  function resolveOrgPlatformTarget(config) {
4549
4850
  return {
4550
4851
  baseUrl: `${getPlatformUrl(config).replace(/\/+$/, "")}/api`,
@@ -4568,18 +4869,16 @@ async function resolvePlatformTarget(config, projectRef) {
4568
4869
  };
4569
4870
  }
4570
4871
  async function resolveApiTarget(config, options = {}) {
4571
- if (options.local) return resolveLocalTarget(config);
4872
+ loadProjectEnv(process.cwd());
4873
+ if (options.local) return resolveLocalTarget(options);
4572
4874
  const devSession = readDevSession(getConfigDir(config));
4573
- if (devSession && getEffectiveApiTarget(config) !== "platform") return {
4574
- baseUrl: devSession.serverUrl,
4575
- mode: "local"
4576
- };
4875
+ if (devSession && getEffectiveApiTarget(config) !== "platform") return resolveLocalTargetFromOrigin(devSession.serverUrl, options);
4577
4876
  if (options.orgScoped || options.projectScoped === false) {
4578
- if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(config);
4877
+ if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
4579
4878
  return resolveOrgPlatformTarget(config);
4580
4879
  }
4581
4880
  if (options.projectId) return resolvePlatformTarget(config, options.projectId);
4582
- if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(config);
4881
+ if (getEffectiveApiTarget(config) === "local") return resolveLocalTarget(options);
4583
4882
  if (!options.projectScoped) return resolveOrgPlatformTarget(config);
4584
4883
  const projectRef = options.projectId ?? config.get("activeProjectId");
4585
4884
  if (!projectRef) throw new Error("No project selected. Pass `--project <slug>` or run `keystroke config use project <slug>`.");
@@ -4666,6 +4965,9 @@ function formatHttpClientError(error, context) {
4666
4965
  if (origin && !getAccessToken(origin)) return "Not logged in. Run `keystroke auth login` first.";
4667
4966
  return "Authentication failed. Run `keystroke auth login` again.";
4668
4967
  }
4968
+ if (error.status === 403) {
4969
+ if (parseErrorResponse(error.body)?.code === "org_unverified") return "This organization is pending verification. Request access in the Keystroke dashboard.";
4970
+ }
4669
4971
  if (error.status === 0) {
4670
4972
  if (error.message && !isUnreachableServerError(error)) return error.message;
4671
4973
  return unreachableServerMessage(unreachableTarget(context));
@@ -5062,6 +5364,7 @@ function registerAppCreateCommand(app) {
5062
5364
  name: options.name.trim(),
5063
5365
  slug,
5064
5366
  description: options.description,
5367
+ source: "custom",
5065
5368
  fields: parseCustomAppFields(options.field)
5066
5369
  });
5067
5370
  process.stdout.write(`${JSON.stringify(created, null, 2)}\n`);
@@ -5135,7 +5438,7 @@ function resolveSyncedAppDirName(slug) {
5135
5438
  }
5136
5439
  function generateAppStub(app) {
5137
5440
  const exportName = resolveSyncedAppExportName(app.slug);
5138
- const credentialLines = Object.entries(app.credentialFields).map(([key, field]) => {
5441
+ const credentialLines = Object.entries(app.credentialFields ?? {}).map(([key, field]) => {
5139
5442
  return ` ${key}: ${field.optional ? "z.string().optional()" : "z.string()"},`;
5140
5443
  }).join("\n");
5141
5444
  return `import { defineApp } from "@keystrokehq/keystroke/app";
@@ -5216,11 +5519,6 @@ function resolveConnectAppSlug(slug, apps) {
5216
5519
  }
5217
5520
  return match;
5218
5521
  }
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
5522
  async function runConnect(options) {
5225
5523
  const apps = await options.platform.apps.listCatalog();
5226
5524
  const app = resolveConnectAppSlug(options.slug, apps);
@@ -5256,6 +5554,90 @@ function registerConnectCommand(program) {
5256
5554
  }, void 0, { orgScoped: true }));
5257
5555
  }
5258
5556
  //#endregion
5557
+ //#region src/commands/credentials/parse-assignment-target.ts
5558
+ function parseAssignmentTarget(options) {
5559
+ const agent = options.agent?.trim();
5560
+ const workflow = options.workflow?.trim();
5561
+ if (agent && workflow) throw new Error("Exactly one of --agent or --workflow is required");
5562
+ if (agent) return {
5563
+ targetType: "agent",
5564
+ targetKey: agent
5565
+ };
5566
+ if (workflow) return {
5567
+ targetType: "workflow",
5568
+ targetKey: workflow
5569
+ };
5570
+ throw new Error("Exactly one of --agent or --workflow is required");
5571
+ }
5572
+ //#endregion
5573
+ //#region src/commands/credentials/assignments/assign.ts
5574
+ function registerCredentialsAssignmentsAssignCommand(assignments) {
5575
+ 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", `
5576
+ Examples:
5577
+ ${cliBinaryName()} credentials assignments assign --workflow sync --credential work
5578
+ ${cliBinaryName()} credentials assignments assign --workflow sync --credential org/work --consumer step:fetch-gmail#0
5579
+ ${cliBinaryName()} credentials assignments assign --agent support --credential vault-prod --consumer vault-lookup
5580
+ ${cliBinaryName()} credentials assignments assign --agent pm --credential linear/work
5581
+ `).action((options) => runProjectCliCommand("Assign credential failed", async ({ client }) => {
5582
+ const target = parseAssignmentTarget(options);
5583
+ const assignment = await client.credentials.assignCredential({
5584
+ targetType: target.targetType,
5585
+ targetKey: target.targetKey,
5586
+ credential: options.credential,
5587
+ ...options.consumer ? { consumerId: options.consumer } : {}
5588
+ });
5589
+ process.stdout.write(`${JSON.stringify(assignment, null, 2)}\n`);
5590
+ }));
5591
+ }
5592
+ //#endregion
5593
+ //#region src/commands/credentials/assignments/list.ts
5594
+ function registerCredentialsAssignmentsListCommand(assignments) {
5595
+ 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 }) => {
5596
+ const target = parseAssignmentTarget(options);
5597
+ const result = await client.credentials.listAssignments({
5598
+ targetType: target.targetType,
5599
+ targetKey: target.targetKey
5600
+ });
5601
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5602
+ }));
5603
+ }
5604
+ //#endregion
5605
+ //#region src/commands/credentials/assignments/unassign.ts
5606
+ function registerCredentialsAssignmentsUnassignCommand(assignments) {
5607
+ assignments.command("unassign").description("Remove a credential assignment by id").argument("<id>", "Credential assignment id").action((id) => runProjectCliCommand("Unassign credential failed", async ({ client }) => {
5608
+ await client.credentials.unassignCredential(id);
5609
+ }));
5610
+ }
5611
+ //#endregion
5612
+ //#region src/commands/credentials/assignments/index.ts
5613
+ function registerCredentialsAssignmentsCommands(credentials) {
5614
+ const assignments = credentials.command("assignments").description("Assign credential instances to workflow steps or agent tools");
5615
+ registerCredentialsAssignmentsListCommand(assignments);
5616
+ registerCredentialsAssignmentsAssignCommand(assignments);
5617
+ registerCredentialsAssignmentsUnassignCommand(assignments);
5618
+ }
5619
+ //#endregion
5620
+ //#region src/commands/credentials/consumers/list.ts
5621
+ function registerCredentialsConsumersListCommand(consumers) {
5622
+ consumers.command("list").description("List bindable consumers for a workflow or agent").option("--agent <key>", "Agent slug").option("--workflow <key>", "Workflow slug").addHelpText("after", `
5623
+ Workflow consumers come from recent step_completed events (e.g. step:fetch-gmail#0).
5624
+ Agent consumers include known tool slugs when available, plus any from existing assignments.
5625
+ Use consumer id "*" (wildcard) or omit --consumer on assignments assign to bind all consumers.
5626
+ `).action((options) => runProjectCliCommand("List credential consumers failed", async ({ client }) => {
5627
+ const target = parseAssignmentTarget(options);
5628
+ const result = await client.credentials.listConsumers({
5629
+ targetType: target.targetType,
5630
+ targetKey: target.targetKey
5631
+ });
5632
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5633
+ }));
5634
+ }
5635
+ //#endregion
5636
+ //#region src/commands/credentials/consumers/index.ts
5637
+ function registerCredentialsConsumersCommands(credentials) {
5638
+ registerCredentialsConsumersListCommand(credentials.command("consumers").description("Discover workflow step and agent tool consumer ids for assignment"));
5639
+ }
5640
+ //#endregion
5259
5641
  //#region src/commands/credentials/target-options.ts
5260
5642
  function resolveCredentialsTargetOptions(options = {}) {
5261
5643
  if (options.scopeType === "project") return {
@@ -5332,13 +5714,13 @@ function buildPlatformUpdatePatch(args) {
5332
5714
  //#endregion
5333
5715
  //#region src/commands/credentials/delete.ts
5334
5716
  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 }) => {
5717
+ credentials.command("delete").description("Delete a credential instance").argument("<ref>", "Credential slug or id").action((ref) => runCredentialsCommand("Delete credential failed", async ({ platform, local }) => {
5336
5718
  if (local) {
5337
5719
  const { client } = await createLocalCredentialsClient();
5338
- await client.credentials.deleteInstance(id);
5720
+ await client.credentials.deleteInstance(ref);
5339
5721
  return;
5340
5722
  }
5341
- await platform.credentials.delete(id);
5723
+ await platform.credentials.delete(ref);
5342
5724
  }));
5343
5725
  }
5344
5726
  //#endregion
@@ -5380,49 +5762,6 @@ function envRefName(raw) {
5380
5762
  return raw.slice(5);
5381
5763
  }
5382
5764
  //#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
5765
  //#region src/commands/credentials/parse-value.ts
5427
5766
  function parseCredentialValueFields(fields) {
5428
5767
  const value = {};
@@ -5468,8 +5807,7 @@ function collectSetValues$2(value, previous) {
5468
5807
  //#region src/commands/credentials/format-set-conflict-error.ts
5469
5808
  function describeInstance(instance) {
5470
5809
  const defaultStatus = instance.isDefault ? "default" : "not default";
5471
- const labelStatus = instance.label ? `label: ${instance.label}` : "no label";
5472
- return `id: ${instance.id}, ${defaultStatus}, ${labelStatus}`;
5810
+ return `${instance.name ? `name: ${instance.name}` : `slug: ${instance.slug}`}, ${defaultStatus}`;
5473
5811
  }
5474
5812
  function formatSetFields(setFields) {
5475
5813
  return setFields.map((field) => `--set ${field}`).join(" ");
@@ -5478,10 +5816,10 @@ function formatSetConflictError(args) {
5478
5816
  const binary = cliBinaryName();
5479
5817
  const setArgs = formatSetFields(args.setFields);
5480
5818
  const listCmd = `${binary} credentials list --key ${args.key}`;
5481
- const addSecondCmd = `${binary} credentials set ${args.key} --scope ${args.scope} --label <name> ${setArgs}`;
5819
+ const addSecondCmd = `${binary} credentials set ${args.key} --scope ${args.scope} --slug <slug> ${setArgs}`;
5482
5820
  if (args.matching.length === 1) {
5483
5821
  const instance = args.matching[0];
5484
- const updateCmd = `${binary} credentials update ${instance.id} ${setArgs}`;
5822
+ const updateCmd = `${binary} credentials update ${instance.slug} ${setArgs}`;
5485
5823
  return [
5486
5824
  `An ${args.key} credential already exists in ${args.scope} scope (${describeInstance(instance)}).`,
5487
5825
  "credentials set creates a new instance — it does not update an existing one.",
@@ -5494,7 +5832,7 @@ function formatSetConflictError(args) {
5494
5832
  }
5495
5833
  const instanceLines = args.matching.map((instance) => ` • ${describeInstance(instance)}`);
5496
5834
  return [
5497
- `Multiple ${args.key} credentials already exist in ${args.scope} scope. --label is required to add another:`,
5835
+ `Multiple ${args.key} credentials already exist in ${args.scope} scope. Pass --slug to add another:`,
5498
5836
  ...instanceLines,
5499
5837
  "To add another credential in the same scope:",
5500
5838
  ` ${addSecondCmd}`,
@@ -5502,7 +5840,7 @@ function formatSetConflictError(args) {
5502
5840
  ].join("\n");
5503
5841
  }
5504
5842
  async function assertNoSetConflict(client, args) {
5505
- if (args.label) return;
5843
+ if (args.slug) return;
5506
5844
  const { instances } = await client.credentials.listInstances({ key: args.key });
5507
5845
  const matching = instances.filter((instance) => instance.scopeType === args.scopeType && (args.scopeType !== "project" || instance.scopeId === args.projectId));
5508
5846
  if (matching.length === 0) return;
@@ -5538,7 +5876,7 @@ function parseCredentialSetScopes(scopes, projectSlugs) {
5538
5876
  //#endregion
5539
5877
  //#region src/commands/credentials/set.ts
5540
5878
  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 }) => {
5879
+ 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
5880
  const value = parseCredentialValueFields(options.set);
5543
5881
  const parsedScopes = parseCredentialSetScopes(options.scope, options.projectSlug);
5544
5882
  if (local) {
@@ -5546,19 +5884,21 @@ function registerCredentialsSetCommand(credentials) {
5546
5884
  const targets = expandLocalCredentialTargets(parsedScopes);
5547
5885
  const instances = [];
5548
5886
  for (const target of targets) {
5887
+ const displayName = options.name ?? options.label;
5549
5888
  await assertNoSetConflict(client, {
5550
5889
  key,
5551
5890
  scope: target.scope,
5552
5891
  scopeType: target.scopeType,
5553
5892
  projectId: target.projectSlug,
5554
- label: options.label,
5893
+ slug: options.slug,
5555
5894
  setFields: options.set
5556
5895
  });
5557
5896
  instances.push(await client.credentials.createInstance({
5558
5897
  key,
5559
5898
  scopeType: target.scopeType,
5560
5899
  scopeId: target.projectSlug,
5561
- label: options.label,
5900
+ ...options.slug !== void 0 ? { slug: options.slug } : {},
5901
+ ...displayName !== void 0 ? { name: displayName } : {},
5562
5902
  isDefault: options.default,
5563
5903
  value
5564
5904
  }));
@@ -5614,12 +5954,14 @@ function expandLocalCredentialTargets(targets) {
5614
5954
  //#endregion
5615
5955
  //#region src/commands/credentials/update.ts
5616
5956
  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 }) => {
5957
+ 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
5958
  const value = options.set.length > 0 ? parseCredentialValueFields(options.set) : void 0;
5959
+ const displayName = options.name ?? options.label;
5619
5960
  if (local) {
5620
5961
  const { client } = await createLocalCredentialsClient();
5621
- const result = await client.credentials.updateInstance(id, {
5622
- ...options.label !== void 0 ? { label: options.label } : {},
5962
+ const result = await client.credentials.updateInstance(ref, {
5963
+ ...options.slug !== void 0 ? { slug: options.slug } : {},
5964
+ ...displayName !== void 0 ? { name: displayName } : {},
5623
5965
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5624
5966
  ...value ? { value } : {}
5625
5967
  });
@@ -5627,11 +5969,11 @@ function registerCredentialsUpdateCommand(credentials) {
5627
5969
  return;
5628
5970
  }
5629
5971
  const patch = buildPlatformUpdatePatch({
5630
- ...options.label !== void 0 ? { label: options.label } : {},
5972
+ ...displayName !== void 0 ? { label: displayName } : {},
5631
5973
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5632
5974
  ...value ? { value } : {}
5633
5975
  });
5634
- const credential = await platform.credentials.update(id, patch);
5976
+ const credential = await platform.credentials.update(ref, patch);
5635
5977
  process.stdout.write(`${JSON.stringify({ credential }, null, 2)}\n`);
5636
5978
  }));
5637
5979
  }
@@ -5648,11 +5990,13 @@ function registerCredentialsCommand(program) {
5648
5990
  registerCredentialsUpdateCommand(credentials);
5649
5991
  registerCredentialsRotateKeyCommand(credentials);
5650
5992
  registerCredentialsDeleteCommand(credentials);
5993
+ registerCredentialsAssignmentsCommands(credentials);
5994
+ registerCredentialsConsumersCommands(credentials);
5651
5995
  }
5652
5996
  //#endregion
5653
5997
  //#region src/auth/resolve-login-targets.ts
5654
5998
  function resolveAuthLoginTargets(options, config) {
5655
- const webUrl = options.webUrl ?? "https://app.keystroke.ai";
5999
+ const webUrl = options.webUrl ?? "https://keystroke.ai";
5656
6000
  return {
5657
6001
  webUrl,
5658
6002
  platformUrl: resolvePlatformUrlForWebUrl(webUrl, {
@@ -5759,7 +6103,7 @@ function registerBuildCommand(program) {
5759
6103
  program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
5760
6104
  try {
5761
6105
  const root = resolveProjectRoot(options.dir);
5762
- const { buildApp } = await import("./dist-B9XaHV_2.mjs");
6106
+ const { buildApp } = await import("./dist-IOphuHYN.mjs");
5763
6107
  await buildApp({ root });
5764
6108
  process.stdout.write(`Built ${root}\n`);
5765
6109
  } catch (error) {
@@ -5770,109 +6114,6 @@ function registerBuildCommand(program) {
5770
6114
  });
5771
6115
  }
5772
6116
  //#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
6117
  //#region src/commands/deploy.ts
5877
6118
  const POLL_INTERVAL_MS = 2e3;
5878
6119
  const DEPLOY_TIMEOUT_MS = 12e4;
@@ -5916,7 +6157,7 @@ async function sleep(ms) {
5916
6157
  }
5917
6158
  async function buildDeployArchive(client, root, projectId, filter) {
5918
6159
  if (filter?.length) {
5919
- const { buildFilteredApp } = await import("./dist-B9XaHV_2.mjs");
6160
+ const { buildFilteredApp } = await import("./dist-IOphuHYN.mjs");
5920
6161
  const filtered = await buildFilteredApp({
5921
6162
  root,
5922
6163
  filter,
@@ -5938,7 +6179,7 @@ async function buildDeployArchive(client, root, projectId, filter) {
5938
6179
  sourceFiles: filtered.sourceFiles
5939
6180
  };
5940
6181
  }
5941
- const { buildApp } = await import("./dist-B9XaHV_2.mjs");
6182
+ const { buildApp } = await import("./dist-IOphuHYN.mjs");
5942
6183
  const { sourceFiles } = await buildApp({
5943
6184
  root,
5944
6185
  collectSources: true,
@@ -6006,6 +6247,13 @@ function registerDeployCommand(program) {
6006
6247
  });
6007
6248
  }
6008
6249
  //#endregion
6250
+ //#region src/resolve-local-api-origin.ts
6251
+ /** Local platform API origin from the project `.env` (`PUBLIC_PLATFORM_URL`). */
6252
+ function resolveLocalApiOrigin(fromDir = process.cwd()) {
6253
+ loadProjectEnv(fromDir);
6254
+ return resolvePublicPlatformOrigin(process.env);
6255
+ }
6256
+ //#endregion
6009
6257
  //#region src/project/runtime-child-env.ts
6010
6258
  /** Strip dev-only Node flags so the API child loads built `dist/`, not package `src/`. */
6011
6259
  function runtimeChildNodeOptions(nodeOptions) {
@@ -6044,14 +6292,13 @@ function runtimeChildEnv(parentEnv, overrides) {
6044
6292
  env.DATABASE_URL = "file:./data/public.db";
6045
6293
  }
6046
6294
  env.KEYSTROKE_APP_MODE ??= "standalone";
6047
- env.PROJECT_ID ??= "default";
6048
6295
  return env;
6049
6296
  }
6050
6297
  //#endregion
6051
6298
  //#region src/project/bootstrap-run.ts
6052
6299
  /** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
6053
6300
  async function resolveBootstrapRun(options) {
6054
- const { resolveRuntimeBuildArtifact } = await import("./dist-B9XaHV_2.mjs");
6301
+ const { resolveRuntimeBuildArtifact } = await import("./dist-IOphuHYN.mjs");
6055
6302
  const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
6056
6303
  const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/standalone-bootstrap.mjs");
6057
6304
  const args = [`--import=${loader}`];
@@ -6061,10 +6308,9 @@ async function resolveBootstrapRun(options) {
6061
6308
  const childEnv = runtimeChildEnv(process.env, {
6062
6309
  KEYSTROKE_ROOT: options.root,
6063
6310
  KEYSTROKE_RUNTIME_NODE_MODULES: options.runtimeNodeModules,
6064
- KEYSTROKE_APP_MODE: "standalone",
6065
- PROJECT_ID: process.env.PROJECT_ID ?? "default"
6311
+ KEYSTROKE_APP_MODE: "standalone"
6066
6312
  });
6067
- childEnv.PORT = String(listenPortFromPublicUrl(childEnv.PUBLIC_SERVER_URL, options.apiPort));
6313
+ childEnv.PORT = String(listenPortFromPublicUrl(childEnv.PUBLIC_PLATFORM_URL, options.apiPort));
6068
6314
  return {
6069
6315
  cwd: options.root,
6070
6316
  args,
@@ -6156,8 +6402,8 @@ const DEV_BANNER = "keystroke dev: watch rebuilds dist/ and restarts the API —
6156
6402
  function stopChild(child) {
6157
6403
  if (child && !child.killed && child.pid !== void 0) child.kill("SIGTERM");
6158
6404
  }
6159
- function resolveDevServerUrl(config, portOverride) {
6160
- const url = new URL(getServerUrl(config));
6405
+ function resolveDevServerUrl(root, portOverride) {
6406
+ const url = new URL(resolveLocalApiOrigin(root));
6161
6407
  if (portOverride !== void 0) url.port = String(portOverride);
6162
6408
  return url.origin;
6163
6409
  }
@@ -6165,10 +6411,9 @@ async function runDev(options) {
6165
6411
  const root = resolveProjectRoot(options.dir);
6166
6412
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
6167
6413
  ensureNativeDeps(runtimeNodeModules);
6168
- const cliConfig = createCliConfig();
6169
- const configDir = getConfigDir(cliConfig);
6414
+ const configDir = getConfigDir(createCliConfig());
6170
6415
  process.stdout.write(DEV_BANNER);
6171
- const serverUrl = resolveDevServerUrl(cliConfig, options.port);
6416
+ const serverUrl = resolveDevServerUrl(root, options.port);
6172
6417
  const apiPort = Number(new URL(serverUrl).port || 80);
6173
6418
  writeDevSession({
6174
6419
  pid: process.pid,
@@ -6202,7 +6447,7 @@ async function runDev(options) {
6202
6447
  process.on("SIGINT", shutdown);
6203
6448
  process.on("SIGTERM", shutdown);
6204
6449
  try {
6205
- const { watchApp } = await import("./dist-B9XaHV_2.mjs");
6450
+ const { watchApp } = await import("./dist-IOphuHYN.mjs");
6206
6451
  await watchApp({
6207
6452
  root,
6208
6453
  clean: false,
@@ -6352,10 +6597,11 @@ const INIT_CATALOG_VERSIONS = {
6352
6597
  vitest: "^4.1.7",
6353
6598
  "@types/node": "^25.9.1"
6354
6599
  };
6600
+ const INIT_KEYSTROKE_VERSION = "^0.1.8";
6355
6601
  //#endregion
6356
6602
  //#region src/init/copy-template.ts
6357
6603
  function renderTemplate(content, variables) {
6358
- let rendered = content.replaceAll("{{projectName}}", variables.projectName).replaceAll("{{version}}", variables.version);
6604
+ let rendered = content.replaceAll("{{projectName}}", variables.projectName).replaceAll("{{keystrokeVersion}}", INIT_KEYSTROKE_VERSION).replaceAll("{{version}}", variables.version);
6359
6605
  for (const [dep, version] of Object.entries(INIT_CATALOG_VERSIONS)) rendered = rendered.replaceAll(`{{catalog:${dep}}}`, version);
6360
6606
  return rendered;
6361
6607
  }
@@ -6531,6 +6777,33 @@ function resolvePlaygroundRoot(targetDir) {
6531
6777
  const rel = relative(join(root, "playground"), resolve(targetDir));
6532
6778
  return rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel) ? root : null;
6533
6779
  }
6780
+ /** Example primitives the hello-world template ships; removed when --no-example is set. */
6781
+ const EXAMPLE_FILES = [
6782
+ "src/actions/greet.ts",
6783
+ "src/agents/hello.ts",
6784
+ "src/agents/hello.int.test.ts",
6785
+ "src/workflows/greeting.ts",
6786
+ "src/workflows/greeting.test.ts"
6787
+ ];
6788
+ async function removeExampleFiles(targetDir) {
6789
+ await Promise.all(EXAMPLE_FILES.map((rel) => rm(join(targetDir, rel), { force: true })));
6790
+ }
6791
+ /**
6792
+ * Drop the README sections that walk through the example hello agent / greeting
6793
+ * workflow — those primitives don't exist in a --no-example scaffold (e.g. MCP
6794
+ * sprite bootstrap), so shipping their usage docs is misleading.
6795
+ */
6796
+ async function stripExampleReadme(targetDir) {
6797
+ const readmePath = join(targetDir, "README.md");
6798
+ let content;
6799
+ try {
6800
+ content = await readFile(readmePath, "utf8");
6801
+ } catch {
6802
+ return;
6803
+ }
6804
+ 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");
6805
+ if (next !== content) await writeFile(readmePath, next);
6806
+ }
6534
6807
  async function directoryExists(path) {
6535
6808
  try {
6536
6809
  await access(path);
@@ -6564,6 +6837,10 @@ async function runInit(options) {
6564
6837
  version: options.version
6565
6838
  });
6566
6839
  await scaffoldEmptySrcDirs(targetDir);
6840
+ if (options.noExample) {
6841
+ await removeExampleFiles(targetDir);
6842
+ await stripExampleReadme(targetDir);
6843
+ }
6567
6844
  if (playgroundRoot) await applyPlaygroundManifest(targetDir, projectName, playgroundRoot);
6568
6845
  else await scaffoldProjectDotfiles(targetDir);
6569
6846
  await syncBundledSkills(targetDir);
@@ -6580,7 +6857,7 @@ async function runInit(options) {
6580
6857
  //#endregion
6581
6858
  //#region src/commands/init.ts
6582
6859
  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) => {
6860
+ 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
6861
  try {
6585
6862
  const result = await runInit({
6586
6863
  directory,
@@ -6589,6 +6866,7 @@ function registerInitCommand(program) {
6589
6866
  yes: options.yes,
6590
6867
  skipInstall: options.skipInstall,
6591
6868
  packageManager: options.pm,
6869
+ noExample: options.example === false,
6592
6870
  version: readCliVersion()
6593
6871
  });
6594
6872
  process.stdout.write(`Created keystroke project "${result.projectName}" at ${result.targetDir}\n`);
@@ -7017,18 +7295,18 @@ function registerProjectCommand(program) {
7017
7295
  }
7018
7296
  //#endregion
7019
7297
  //#region src/commands/start.ts
7020
- function resolveStartServerUrl(portOverride) {
7021
- const url = new URL(getServerUrl(createCliConfig()));
7298
+ function resolveStartServerUrl(root, portOverride) {
7299
+ const url = new URL(resolveLocalApiOrigin(root));
7022
7300
  if (portOverride !== void 0) url.port = String(portOverride);
7023
7301
  return url.origin;
7024
7302
  }
7025
7303
  async function runStart(options) {
7026
7304
  const root = resolveProjectRoot(options.dir);
7027
- const serverUrl = resolveStartServerUrl(options.port);
7305
+ const serverUrl = resolveStartServerUrl(root, options.port);
7028
7306
  const apiPort = Number(new URL(serverUrl).port || 80);
7029
7307
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
7030
7308
  ensureNativeDeps(runtimeNodeModules);
7031
- const { buildApp } = await import("./dist-B9XaHV_2.mjs");
7309
+ const { buildApp } = await import("./dist-IOphuHYN.mjs");
7032
7310
  await buildApp({
7033
7311
  root,
7034
7312
  clean: false
@@ -7111,6 +7389,61 @@ function registerTriggerRunsCommand(trigger) {
7111
7389
  }));
7112
7390
  }
7113
7391
  //#endregion
7392
+ //#region src/commands/trigger/resolve-trigger-attachment.ts
7393
+ function findAssignment(assignments, attachmentRef) {
7394
+ return assignments.find((entry) => entry.attachmentId === attachmentRef || entry.attachmentSlug === attachmentRef);
7395
+ }
7396
+ async function resolveTriggerAttachment(platform, triggerRef, attachmentRef) {
7397
+ let trigger = await platform.triggers.get(triggerRef);
7398
+ if (!trigger) {
7399
+ const summary = (await platform.triggers.list()).find((entry) => entry.id === triggerRef || entry.slug === triggerRef) ?? null;
7400
+ if (summary) trigger = await platform.triggers.get(summary.id);
7401
+ }
7402
+ if (!trigger) throw new Error(`Trigger not found: ${triggerRef}`);
7403
+ const assignment = findAssignment(trigger.assignments, attachmentRef);
7404
+ if (!assignment) throw new Error(`Attachment not found on trigger ${trigger.slug}: ${attachmentRef}`);
7405
+ return {
7406
+ triggerId: trigger.id,
7407
+ attachmentId: assignment.attachmentId,
7408
+ trigger,
7409
+ assignment
7410
+ };
7411
+ }
7412
+ //#endregion
7413
+ //#region src/commands/trigger/run-attachment-enabled.ts
7414
+ async function runTriggerAttachmentEnabled(config, options) {
7415
+ await withActivePlatformClient(config, async (platform) => {
7416
+ const resolved = await resolveTriggerAttachment(platform, options.triggerRef, options.attachmentRef);
7417
+ const trigger = await platform.triggers.updateAttachment(resolved.triggerId, resolved.attachmentId, { enabled: options.enabled });
7418
+ process.stdout.write(`${JSON.stringify(trigger, null, 2)}\n`);
7419
+ });
7420
+ }
7421
+ //#endregion
7422
+ //#region src/commands/trigger/attachment.ts
7423
+ function registerAttachmentToggleCommand(attachment, command, enabled) {
7424
+ 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) => {
7425
+ const config = createCliConfig();
7426
+ try {
7427
+ await runTriggerAttachmentEnabled(config, {
7428
+ triggerRef,
7429
+ attachmentRef,
7430
+ enabled
7431
+ });
7432
+ } catch (error) {
7433
+ process.stderr.write(`${formatCliError(error, `${command} trigger attachment failed`, {
7434
+ serverUrl: getPlatformUrl(config),
7435
+ webUrl: getWebUrl(config)
7436
+ })}\n`);
7437
+ process.exitCode = 1;
7438
+ }
7439
+ });
7440
+ }
7441
+ function registerTriggerAttachmentCommand(trigger) {
7442
+ const attachment = trigger.command("attachment").description("Enable or disable individual trigger attachments");
7443
+ registerAttachmentToggleCommand(attachment, "disable", false);
7444
+ registerAttachmentToggleCommand(attachment, "enable", true);
7445
+ }
7446
+ //#endregion
7114
7447
  //#region src/commands/trigger/index.ts
7115
7448
  function registerTriggerCommand(program) {
7116
7449
  const trigger = program.command("trigger").description("Invoke and inspect triggers");
@@ -7119,6 +7452,7 @@ function registerTriggerCommand(program) {
7119
7452
  registerTriggerUrlCommand(trigger);
7120
7453
  registerTriggerPollCommand(trigger);
7121
7454
  registerTriggerRunsCommand(trigger);
7455
+ registerTriggerAttachmentCommand(trigger);
7122
7456
  }
7123
7457
  //#endregion
7124
7458
  //#region src/commands/workflow/list.ts
@@ -7412,9 +7746,9 @@ function registerConfigCommand(program) {
7412
7746
  const cliConfig = createCliConfig();
7413
7747
  const configDir = getConfigDir(cliConfig);
7414
7748
  process.stdout.write(`${JSON.stringify({
7415
- serverUrl: cliConfig.get("serverUrl"),
7416
7749
  webUrl: cliConfig.get("webUrl"),
7417
7750
  platformUrl: getPlatformUrl(cliConfig),
7751
+ localApiUrl: resolveLocalApiOrigin(process.cwd()),
7418
7752
  activeOrganizationId: cliConfig.get("activeOrganizationId"),
7419
7753
  activeProjectId: cliConfig.get("activeProjectId"),
7420
7754
  apiTarget: getEffectiveApiTarget(cliConfig),
@@ -7551,7 +7885,7 @@ function createProgram() {
7551
7885
  return program;
7552
7886
  }
7553
7887
  async function runCli(argv) {
7554
- const { maybeAutoUpdate } = await import("./maybe-auto-update-DHt-mVf1.mjs");
7888
+ const { maybeAutoUpdate } = await import("./maybe-auto-update-BiR_kXZX.mjs");
7555
7889
  await maybeAutoUpdate(argv);
7556
7890
  createProgram().parse(argv);
7557
7891
  }