@keystrokehq/cli 0.0.148 → 0.0.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as ProjectSlugAvailabilityResponseSchema, A as InviteOrganizationMembersRequestSchema, At as WorkflowSummaryDetailResponseSchema, B as ListProjectsResponseSchema, C as GatewayAttachmentRecordSchema, Ct as UpsertGatewayAttachmentBodySchema, D as HistoryRunDetailResponseSchema, Dt as UserPreferencesSchema, E as HistoryRunCancelResponseSchema, Et as UserPreferencesPatchSchema, F as ListOrganizationMembersResponseSchema, Ft as parseErrorResponse, G as PresignOrgLogoRequestSchema, H as OrganizationSidebarBrandingSchema, I as ListOrganizationsResponseSchema, J as PresignProjectSourceResponseSchema, K as PresignOrgLogoResponseSchema, L as ListProjectDeploymentsResponseSchema, M as ListAppsResponseSchema, Mt as listenPortFromPublicUrl, N as ListCredentialsResponseSchema, O as HistoryRunListQuerySchema, Ot as WorkflowRunDetailResponseSchema, P as ListOrganizationInvitationsResponseSchema, Pt as originFromPublicUrl, Q as ProjectResponseSchema, R as ListProjectFilesResponseSchema, S as ErrorResponseSchema, St as UploadProjectSourceResponseSchema, T as HealthResponseSchema, Tt as UserAvatarSchema, U as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, V as OrganizationSidebarBrandingPatchSchema, W as PollRunResponseSchema, X as PresignUserAvatarResponseSchema, Y as PresignUserAvatarRequestSchema, Z as ProjectReachabilityResponseSchema, _ as CreateProjectRequestSchema, _t as UpdateOrganizationMemberRequestSchema, a as AgentSessionListResponseSchema, at as RecentResourceListResponseSchema, b as CredentialInstanceRecordSchema, bt as UpdateProjectRequestSchema, c as CompleteProjectArtifactResponseSchema, ct as SlugAvailabilityResponseSchema, d as CreateCredentialInstanceBodySchema, dt as TriggerDetailResponseSchema, et as PromptInputSchema, f as CreateCredentialsRequestSchema, ft as TriggerListResponseSchema, g as CreateProjectArtifactResponseSchema, gt as UpdateCredentialRequestSchema, h as CreateOrganizationResponseSchema, ht as UpdateCredentialInstanceBodySchema, i as AgentSessionDetailResponseSchema, it as ROUTE_MANIFEST_REL_PATH, j as InviteOrganizationMembersResponseSchema, jt as WorkflowSummaryListResponseSchema, k as HistoryRunListResponseSchema, kt as WorkflowRunListResponseSchema, l as ConnectAuthorizeUrlResponseSchema, lt as StartOAuthConnectionInputSchema, m as CreateOrganizationRequestSchema, mt as TriggerRunListResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nt as QueuedAgentPromptResponseSchema, o as AgentSummaryDetailResponseSchema, ot as SkillSummaryDetailResponseSchema, p as CreateCredentialsResponseSchema, pt as TriggerRunDetailResponseSchema, q as PresignProjectSourceRequestSchema, r as ActiveOrganizationResponseSchema, rt as QueuedRunResponseSchema, s as AgentSummaryListResponseSchema, st as SkillSummaryListResponseSchema, t as ACTIVE_ORG_HEADER, tt as PromptResponseSchema, u as ConnectProvidersResponseSchema, ut as StartOAuthConnectionResultSchema, v as CreateProjectResponseSchema, vt as UpdateOrganizationMemberResponseSchema, w as GetCredentialResponseSchema, wt as UserAvatarPatchSchema, x as DeclineOrganizationInvitationResponseSchema, xt as UploadProjectSourceManifestRequestSchema, y as CredentialInstanceListResponseSchema, yt as UpdateOrganizationRequestSchema, z as ListProjectMetricsResponseSchema } from "./dist-B61CtbIr.mjs";
2
+ import { $ as PresignProjectSourceRequestSchema, A as GetCredentialResponseSchema, At as UpsertGatewayAttachmentBodySchema, B as ListOrganizationInvitationsResponseSchema, C as CreateProjectRequestSchema, Ct as UpdateCredentialRequestSchema, D as DeclineOrganizationInvitationResponseSchema, Dt as UpdateProjectRequestSchema, E as CredentialInstanceRecordSchema, Et as UpdateOrganizationRequestSchema, F as HistoryRunListResponseSchema, Ft as WorkflowRunDetailResponseSchema, G as ListProjectMetricsResponseSchema, H as ListOrganizationsResponseSchema, Ht as parseErrorResponse, I as InviteOrganizationMembersRequestSchema, It as WorkflowRunListResponseSchema, J as OrganizationSidebarBrandingSchema, K as ListProjectsResponseSchema, L as InviteOrganizationMembersResponseSchema, Lt as WorkflowSummaryDetailResponseSchema, M as HistoryRunCancelResponseSchema, Mt as UserAvatarSchema, N as HistoryRunDetailResponseSchema, Nt as UserPreferencesPatchSchema, O as ErrorResponseSchema, Ot as UploadProjectSourceManifestRequestSchema, P as HistoryRunListQuerySchema, Pt as UserPreferencesSchema, Q as PresignOrgLogoResponseSchema, R as ListAppsResponseSchema, Rt as WorkflowSummaryListResponseSchema, S as CreateProjectArtifactResponseSchema, St as UpdateCredentialInstanceBodySchema, T as CredentialInstanceListResponseSchema, Tt as UpdateOrganizationMemberResponseSchema, U as ListProjectDeploymentsResponseSchema, V as ListOrganizationMembersResponseSchema, Vt as originFromPublicUrl, W as ListProjectFilesResponseSchema, X as PollRunResponseSchema, Y as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, Z as PresignOrgLogoRequestSchema, _ as CreateCredentialInstanceBodySchema, _t as TriggerDetailResponseSchema, a as AgentSessionListResponseSchema, at as ProjectSlugAvailabilityResponseSchema, b as CreateOrganizationRequestSchema, bt as TriggerRunListResponseSchema, c as BindChannelBodySchema, ct as QueuedAgentPromptResponseSchema, d as ChannelConnectionSchema, dt as RecentResourceListResponseSchema, et as PresignProjectSourceResponseSchema, f as ChannelDirectoryListResponseSchema, ft as SkillSummaryDetailResponseSchema, g as ConnectProvidersResponseSchema, gt as StartOAuthConnectionResultSchema, h as ConnectAuthorizeUrlResponseSchema, ht as StartOAuthConnectionInputSchema, i as AgentSessionDetailResponseSchema, it as ProjectResponseSchema, j as HealthResponseSchema, jt as UserAvatarPatchSchema, k as GatewayAttachmentRecordSchema, kt as UploadProjectSourceResponseSchema, l as ChannelAccountListResponseSchema, lt as QueuedRunResponseSchema, m as CompleteProjectArtifactResponseSchema, mt as SlugAvailabilityResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nt as PresignUserAvatarResponseSchema, o as AgentSummaryDetailResponseSchema, ot as PromptInputSchema, p as ChannelPlatformSchema, pt as SkillSummaryListResponseSchema, q as OrganizationSidebarBrandingPatchSchema, r as ActiveOrganizationResponseSchema, rt as ProjectReachabilityResponseSchema, s as AgentSummaryListResponseSchema, st as PromptResponseSchema, t as ACTIVE_ORG_HEADER, tt as PresignUserAvatarRequestSchema, u as ChannelConnectionListResponseSchema, ut as ROUTE_MANIFEST_REL_PATH, v as CreateCredentialsRequestSchema, vt as TriggerListResponseSchema, w as CreateProjectResponseSchema, wt as UpdateOrganizationMemberRequestSchema, x as CreateOrganizationResponseSchema, xt as UpdateChannelBindingBodySchema, y as CreateCredentialsResponseSchema, yt as TriggerRunDetailResponseSchema, z as ListCredentialsResponseSchema, zt as listenPortFromPublicUrl } from "./dist-BfWdSrRa.mjs";
3
3
  import { t as walkProject } from "./walk-project-171B4cvO-DJy3qZKd.mjs";
4
4
  import { a as installPlaygroundDependencies, i as installDependencies, n as buildPlaygroundWorkspace, o as resolvePackageManager, s as resolveCliRoot, t as readCliVersion } from "./version-DESgLEkE.mjs";
5
5
  import { createRequire } from "node:module";
@@ -3774,8 +3774,8 @@ const DEFAULT_PROJECT_SETTINGS = {
3774
3774
  defaultRole: "editor",
3775
3775
  invitePermission: "admin"
3776
3776
  };
3777
- const MOCK_STORAGE_KEY$1 = "keystroke:mock-project-settings:v1";
3778
- function getBrowserLocalStorage$1() {
3777
+ const MOCK_STORAGE_KEY = "keystroke:mock-project-settings:v1";
3778
+ function getBrowserLocalStorage() {
3779
3779
  if (typeof globalThis !== "object") return null;
3780
3780
  return globalThis.localStorage ?? null;
3781
3781
  }
@@ -3801,10 +3801,10 @@ function mergeProjectSettings(current, patch) {
3801
3801
  });
3802
3802
  }
3803
3803
  function readSettingsStore() {
3804
- const localStorage = getBrowserLocalStorage$1();
3804
+ const localStorage = getBrowserLocalStorage();
3805
3805
  if (!localStorage) return {};
3806
3806
  try {
3807
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$1);
3807
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY);
3808
3808
  if (!raw) return {};
3809
3809
  const parsed = JSON.parse(raw);
3810
3810
  if (!parsed || typeof parsed !== "object") return {};
@@ -3814,10 +3814,10 @@ function readSettingsStore() {
3814
3814
  }
3815
3815
  }
3816
3816
  function writeSettingsStore(store) {
3817
- const localStorage = getBrowserLocalStorage$1();
3817
+ const localStorage = getBrowserLocalStorage();
3818
3818
  if (!localStorage) return;
3819
3819
  try {
3820
- localStorage.setItem(MOCK_STORAGE_KEY$1, JSON.stringify(store));
3820
+ localStorage.setItem(MOCK_STORAGE_KEY, JSON.stringify(store));
3821
3821
  } catch {}
3822
3822
  }
3823
3823
  function requireProjectId(projectId) {
@@ -3883,8 +3883,8 @@ function buildOAuthAuthorizeSearchParams(input) {
3883
3883
  const params = {};
3884
3884
  const scopes = input.scopes ?? [];
3885
3885
  if (scopes.length > 0) params.scopes = scopes.join(",");
3886
- const projectIds = input.projectIds ?? [];
3887
- if (projectIds.length > 0) params.projectIds = projectIds.join(",");
3886
+ const projectIds = input.projects ?? [];
3887
+ if (projectIds.length > 0) params.projects = projectIds.join(",");
3888
3888
  if (input.createOrganizationCredential) params.org = "true";
3889
3889
  if (input.createUserProvidedCredential) params.user = "true";
3890
3890
  return params;
@@ -4331,556 +4331,92 @@ function createUserAvatarResource(http) {
4331
4331
  }
4332
4332
  };
4333
4333
  }
4334
- const CHANNEL_PLATFORMS = [
4335
- {
4336
- key: "slack",
4337
- name: "Slack",
4338
- appLogoId: "slack",
4339
- fallbackDomain: "slack.com",
4340
- description: "Connect a Slack workspace so this agent can respond in channels, threads, and DMs.",
4341
- tagline: "Respond in channels, threads, and DMs.",
4342
- authKind: "oauth",
4334
+ const PLATFORM_FALLBACK_DOMAINS = { slack: "slack.com" };
4335
+ function projectChannelPlatform(app) {
4336
+ if (!app.gateway) throw new Error(`App ${app.id} does not support gateway bindings`);
4337
+ return ChannelPlatformSchema.parse({
4338
+ key: app.id,
4339
+ name: app.name,
4340
+ appLogoId: app.id,
4341
+ fallbackDomain: PLATFORM_FALLBACK_DOMAINS[app.id] ?? `${app.id}.com`,
4342
+ description: app.integrationDescription,
4343
+ tagline: app.gateway.tagline ?? app.description,
4344
+ authKind: app.authKind,
4343
4345
  credentialFields: [],
4344
- capabilities: {
4345
- mentions: true,
4346
- reactions: "full",
4347
- cards: "full",
4348
- modals: true,
4349
- streaming: "native",
4350
- dms: true
4351
- },
4352
- supportedModes: [
4353
- "mention",
4354
- "all",
4355
- "dm"
4356
- ],
4357
- resourceNoun: {
4358
- singular: "channel",
4359
- plural: "channels"
4346
+ capabilities: app.gateway.capabilities,
4347
+ supportedModes: app.gateway.supportedModes,
4348
+ resourceNoun: app.gateway.resourceNoun,
4349
+ webhookPathHint: app.gateway.webhookPathHint,
4350
+ supportsChannelDirectory: app.gateway.supportsChannelDirectory,
4351
+ docsUrl: app.gateway.docsUrl
4352
+ });
4353
+ }
4354
+ function createChannelsResource(http) {
4355
+ const projectPrefix = (projectId) => `/api/projects/${encodeURIComponent(projectId)}`;
4356
+ async function listGatewayPlatforms() {
4357
+ try {
4358
+ const data = await http.get("/api/apps").json();
4359
+ return ListAppsResponseSchema.parse(data).apps.filter((app) => app.gateway).map((app) => projectChannelPlatform(app));
4360
+ } catch (error) {
4361
+ throw await toPlatformError(error);
4362
+ }
4363
+ }
4364
+ return {
4365
+ async listPlatforms() {
4366
+ return listGatewayPlatforms();
4360
4367
  },
4361
- webhookPathHint: "/gateways/slack",
4362
- supportsChannelDirectory: true,
4363
- docsUrl: "https://chat-sdk.dev/adapters/official/slack"
4364
- },
4365
- {
4366
- key: "discord",
4367
- name: "Discord",
4368
- appLogoId: "discord",
4369
- fallbackDomain: "discord.com",
4370
- description: "Connect a Discord application so this agent can respond in servers and channels.",
4371
- tagline: "Respond in servers and channels.",
4372
- authKind: "credentials",
4373
- credentialFields: [
4374
- {
4375
- key: "botToken",
4376
- label: "Bot token",
4377
- placeholder: "Bot token from the Discord developer portal",
4378
- helpText: "Bot → Reset Token. Shown only once.",
4379
- type: "password",
4380
- required: true
4381
- },
4382
- {
4383
- key: "applicationId",
4384
- label: "Application ID",
4385
- placeholder: "Application ID",
4386
- type: "text",
4387
- required: true
4388
- },
4389
- {
4390
- key: "publicKey",
4391
- label: "Public key",
4392
- placeholder: "Public key",
4393
- helpText: "General Information → Public Key, used to verify interactions.",
4394
- type: "text",
4395
- required: true
4368
+ async listAccounts(projectId, platform) {
4369
+ try {
4370
+ const data = await http.get(`${projectPrefix(projectId)}/channels/${encodeURIComponent(platform)}/accounts`).json();
4371
+ return ChannelAccountListResponseSchema.parse(data).accounts;
4372
+ } catch (error) {
4373
+ throw await toPlatformError(error);
4396
4374
  }
4397
- ],
4398
- capabilities: {
4399
- mentions: true,
4400
- reactions: "full",
4401
- cards: "full",
4402
- modals: false,
4403
- streaming: "post-edit",
4404
- dms: true
4405
4375
  },
4406
- supportedModes: [
4407
- "mention",
4408
- "all",
4409
- "dm"
4410
- ],
4411
- resourceNoun: {
4412
- singular: "channel",
4413
- plural: "channels"
4414
- },
4415
- webhookPathHint: "/gateways/discord",
4416
- supportsChannelDirectory: true,
4417
- docsUrl: "https://chat-sdk.dev/adapters/official/discord"
4418
- },
4419
- {
4420
- key: "telegram",
4421
- name: "Telegram",
4422
- appLogoId: "telegram",
4423
- fallbackDomain: "telegram.org",
4424
- description: "Connect a Telegram bot so this agent can respond in chats and groups.",
4425
- tagline: "Respond in chats and groups.",
4426
- authKind: "bot-token",
4427
- credentialFields: [{
4428
- key: "botToken",
4429
- label: "Bot token",
4430
- placeholder: "123456:ABC-DEF…",
4431
- helpText: "Create a bot with @BotFather and paste its token.",
4432
- type: "password",
4433
- required: true
4434
- }, {
4435
- key: "botUsername",
4436
- label: "Bot username",
4437
- placeholder: "my_agent_bot",
4438
- type: "text",
4439
- required: false,
4440
- prefix: "@"
4441
- }],
4442
- capabilities: {
4443
- mentions: true,
4444
- reactions: "full",
4445
- cards: "partial",
4446
- modals: false,
4447
- streaming: "drafts",
4448
- dms: true
4449
- },
4450
- supportedModes: [
4451
- "mention",
4452
- "all",
4453
- "dm"
4454
- ],
4455
- resourceNoun: {
4456
- singular: "chat",
4457
- plural: "chats"
4458
- },
4459
- webhookPathHint: "/gateways/telegram",
4460
- supportsChannelDirectory: false,
4461
- docsUrl: "https://chat-sdk.dev/adapters/official/telegram"
4462
- },
4463
- {
4464
- key: "microsoft-teams",
4465
- name: "Microsoft Teams",
4466
- appLogoId: "microsoft-teams",
4467
- fallbackDomain: "teams.microsoft.com",
4468
- description: "Connect a Microsoft Teams app so this agent can respond in channels and chats.",
4469
- tagline: "Respond in channels and chats.",
4470
- authKind: "credentials",
4471
- credentialFields: [
4472
- {
4473
- key: "appId",
4474
- label: "App ID",
4475
- placeholder: "Azure AD application (client) ID",
4476
- type: "text",
4477
- required: true
4478
- },
4479
- {
4480
- key: "appPassword",
4481
- label: "App password",
4482
- placeholder: "Client secret",
4483
- type: "password",
4484
- required: true
4485
- },
4486
- {
4487
- key: "tenantId",
4488
- label: "Tenant ID",
4489
- placeholder: "Azure AD tenant ID",
4490
- type: "text",
4491
- required: true
4376
+ async listForAgent(projectId, agentId) {
4377
+ try {
4378
+ const data = await http.get(`${projectPrefix(projectId)}/agents/${encodeURIComponent(agentId)}/channels`).json();
4379
+ return ChannelConnectionListResponseSchema.parse(data).connections;
4380
+ } catch (error) {
4381
+ throw await toPlatformError(error);
4492
4382
  }
4493
- ],
4494
- capabilities: {
4495
- mentions: true,
4496
- reactions: "read-only",
4497
- cards: "full",
4498
- modals: true,
4499
- streaming: "buffered",
4500
- dms: true
4501
- },
4502
- supportedModes: [
4503
- "mention",
4504
- "all",
4505
- "dm"
4506
- ],
4507
- resourceNoun: {
4508
- singular: "channel",
4509
- plural: "channels"
4510
- },
4511
- webhookPathHint: "/gateways/teams",
4512
- supportsChannelDirectory: true,
4513
- docsUrl: "https://chat-sdk.dev/adapters/official/teams"
4514
- },
4515
- {
4516
- key: "google-chat",
4517
- name: "Google Chat",
4518
- appLogoId: "google-chat",
4519
- fallbackDomain: "chat.google.com",
4520
- description: "Connect a Google Chat app so this agent can respond in spaces and direct messages.",
4521
- tagline: "Respond in spaces and DMs.",
4522
- authKind: "credentials",
4523
- credentialFields: [{
4524
- key: "serviceAccountJson",
4525
- label: "Service account JSON",
4526
- placeholder: "Paste the service account key JSON",
4527
- helpText: "IAM → Service Accounts → Keys → Add key → JSON.",
4528
- type: "textarea",
4529
- required: true
4530
- }, {
4531
- key: "projectNumber",
4532
- label: "GCP project number",
4533
- placeholder: "Project number used to verify webhooks",
4534
- type: "text",
4535
- required: true
4536
- }],
4537
- capabilities: {
4538
- mentions: true,
4539
- reactions: "full",
4540
- cards: "full",
4541
- modals: false,
4542
- streaming: "post-edit",
4543
- dms: true
4544
- },
4545
- supportedModes: [
4546
- "mention",
4547
- "all",
4548
- "dm"
4549
- ],
4550
- resourceNoun: {
4551
- singular: "space",
4552
- plural: "spaces"
4553
- },
4554
- webhookPathHint: "/gateways/gchat",
4555
- supportsChannelDirectory: true,
4556
- docsUrl: "https://chat-sdk.dev/adapters/official/google-chat"
4557
- }
4558
- ];
4559
- function getChannelPlatform(key) {
4560
- return CHANNEL_PLATFORMS.find((platform) => platform.key === key);
4561
- }
4562
- const CHANNEL_DIRECTORY = {
4563
- slack: [
4564
- {
4565
- id: "C0SUPPORT",
4566
- name: "support",
4567
- kind: "public",
4568
- memberCount: 48
4569
- },
4570
- {
4571
- id: "C0GENERAL",
4572
- name: "general",
4573
- kind: "public",
4574
- memberCount: 132
4575
- },
4576
- {
4577
- id: "C0ENG",
4578
- name: "engineering",
4579
- kind: "public",
4580
- memberCount: 27
4581
- },
4582
- {
4583
- id: "C0INCIDENTS",
4584
- name: "incidents",
4585
- kind: "private",
4586
- memberCount: 12
4587
4383
  },
4588
- {
4589
- id: "C0RANDOM",
4590
- name: "random",
4591
- kind: "public",
4592
- memberCount: 118
4593
- },
4594
- {
4595
- id: "C0ARCHIVE",
4596
- name: "launch-2025",
4597
- kind: "public",
4598
- memberCount: 9,
4599
- isArchived: true
4600
- }
4601
- ],
4602
- discord: [
4603
- {
4604
- id: "d-general",
4605
- name: "general",
4606
- kind: "public",
4607
- memberCount: 540
4608
- },
4609
- {
4610
- id: "d-help",
4611
- name: "help",
4612
- kind: "public",
4613
- memberCount: 312
4614
- },
4615
- {
4616
- id: "d-dev",
4617
- name: "dev",
4618
- kind: "public",
4619
- memberCount: 76
4620
- },
4621
- {
4622
- id: "d-staff",
4623
- name: "staff",
4624
- kind: "private",
4625
- memberCount: 8
4626
- }
4627
- ],
4628
- telegram: [],
4629
- "microsoft-teams": [
4630
- {
4631
- id: "t-general",
4632
- name: "General",
4633
- kind: "public",
4634
- memberCount: 64
4635
- },
4636
- {
4637
- id: "t-support",
4638
- name: "Customer Support",
4639
- kind: "public",
4640
- memberCount: 22
4384
+ async listChannels(projectId, platform, accountId) {
4385
+ try {
4386
+ const data = await http.get(`${projectPrefix(projectId)}/channels/${encodeURIComponent(platform)}/directory`, { searchParams: { accountId } }).json();
4387
+ return ChannelDirectoryListResponseSchema.parse(data).channels;
4388
+ } catch (error) {
4389
+ throw await toPlatformError(error);
4390
+ }
4641
4391
  },
4642
- {
4643
- id: "t-leads",
4644
- name: "Leadership",
4645
- kind: "private",
4646
- memberCount: 6
4647
- }
4648
- ],
4649
- "google-chat": [
4650
- {
4651
- id: "spaces/AAA-support",
4652
- name: "Support",
4653
- kind: "space",
4654
- memberCount: 31
4392
+ async bind(projectId, input) {
4393
+ const body = BindChannelBodySchema.parse(input);
4394
+ try {
4395
+ const data = await http.post(`${projectPrefix(projectId)}/agents/${encodeURIComponent(input.agentId)}/channels/bindings`, { json: body }).json();
4396
+ return ChannelConnectionSchema.parse(data);
4397
+ } catch (error) {
4398
+ throw await toPlatformError(error);
4399
+ }
4655
4400
  },
4656
- {
4657
- id: "spaces/AAA-eng",
4658
- name: "Engineering",
4659
- kind: "space",
4660
- memberCount: 44
4401
+ async updateBinding(projectId, input) {
4402
+ const body = UpdateChannelBindingBodySchema.parse({ patch: input.patch });
4403
+ try {
4404
+ const data = await http.put(`${projectPrefix(projectId)}/agents/${encodeURIComponent(input.agentId)}/channels/bindings/${encodeURIComponent(input.bindingId)}`, { json: body }).json();
4405
+ return ChannelConnectionSchema.parse(data);
4406
+ } catch (error) {
4407
+ throw await toPlatformError(error);
4408
+ }
4661
4409
  },
4662
- {
4663
- id: "spaces/AAA-ops",
4664
- name: "Ops On-call",
4665
- kind: "space",
4666
- memberCount: 10
4667
- }
4668
- ]
4669
- };
4670
- const MOCK_STORAGE_KEY = "keystroke:mock-channels:v1";
4671
- function getBrowserLocalStorage() {
4672
- if (typeof globalThis !== "object") return null;
4673
- return globalThis.localStorage ?? null;
4674
- }
4675
- /** A connected Slack workspace with two bindings, so the panel is reviewable. */
4676
- function seedStore() {
4677
- return { "agent-support": [{
4678
- id: "chan-conn-slack-support",
4679
- platform: "slack",
4680
- agentId: "agent-support",
4681
- accountLabel: "Keystroke HQ",
4682
- accountId: "T0KEYSTROKE",
4683
- connectedAt: "2026-05-28T15:30:00Z",
4684
- bindings: [{
4685
- id: "chan-bind-support",
4686
- channelId: "C0SUPPORT",
4687
- channelName: "support",
4688
- channelKind: "public",
4689
- mode: "all",
4690
- subscribeOnMention: true,
4691
- createdAt: "2026-05-28T15:31:00Z",
4692
- updatedAt: "2026-05-28T15:31:00Z"
4693
- }, {
4694
- id: "chan-bind-incidents",
4695
- channelId: "C0INCIDENTS",
4696
- channelName: "incidents",
4697
- channelKind: "private",
4698
- mode: "mention",
4699
- subscribeOnMention: true,
4700
- createdAt: "2026-05-29T09:05:00Z",
4701
- updatedAt: "2026-05-29T09:05:00Z"
4702
- }]
4703
- }] };
4704
- }
4705
- function readStore() {
4706
- const localStorage = getBrowserLocalStorage();
4707
- if (!localStorage) return seedStore();
4708
- try {
4709
- const raw = localStorage.getItem(MOCK_STORAGE_KEY);
4710
- if (!raw) {
4711
- const seeded = seedStore();
4712
- localStorage.setItem(MOCK_STORAGE_KEY, JSON.stringify(seeded));
4713
- return seeded;
4410
+ async removeBinding(projectId, input) {
4411
+ try {
4412
+ const response = await http.delete(`${projectPrefix(projectId)}/agents/${encodeURIComponent(input.agentId)}/channels/bindings/${encodeURIComponent(input.bindingId)}`);
4413
+ if (response.status === 204) return null;
4414
+ const data = await response.json();
4415
+ return ChannelConnectionSchema.parse(data);
4416
+ } catch (error) {
4417
+ throw await toPlatformError(error);
4418
+ }
4714
4419
  }
4715
- const parsed = JSON.parse(raw);
4716
- if (!parsed || typeof parsed !== "object") return {};
4717
- return parsed;
4718
- } catch {
4719
- return {};
4720
- }
4721
- }
4722
- function writeStore(store) {
4723
- const localStorage = getBrowserLocalStorage();
4724
- if (!localStorage) return;
4725
- try {
4726
- localStorage.setItem(MOCK_STORAGE_KEY, JSON.stringify(store));
4727
- } catch {}
4728
- }
4729
- function newId(prefix) {
4730
- const cryptoRef = globalThis.crypto;
4731
- if (cryptoRef?.randomUUID) return `${prefix}-${cryptoRef.randomUUID()}`;
4732
- return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
4733
- }
4734
- function requireAgentId(agentId) {
4735
- const trimmed = agentId.trim();
4736
- if (!trimmed) throw new Error("Channels require an agent id");
4737
- return trimmed;
4738
- }
4739
- function clone(value) {
4740
- return JSON.parse(JSON.stringify(value));
4741
- }
4742
- function defaultAccountLabel(platform) {
4743
- const meta = getChannelPlatform(platform);
4744
- return meta ? `${meta.name} workspace` : platform;
4745
- }
4746
- function findConnection(connections, connectionId) {
4747
- const connection = connections.find((entry) => entry.id === connectionId);
4748
- if (!connection) throw new Error(`Channel connection not found: ${connectionId}`);
4749
- return connection;
4750
- }
4751
- function toBinding(input, now) {
4752
- return {
4753
- id: newId("chan-bind"),
4754
- channelId: input.channelId,
4755
- channelName: input.channelName,
4756
- channelKind: input.channelKind ?? "public",
4757
- mode: input.mode ?? "mention",
4758
- subscribeOnMention: input.subscribeOnMention ?? true,
4759
- createdAt: now,
4760
- updatedAt: now
4761
- };
4762
- }
4763
- function createChannelsResource() {
4764
- return {
4765
- /** The supported-platform catalog (static; backend may derive from the adapter registry). */
4766
- listPlatforms: mock({
4767
- domain: "channels",
4768
- method: "listPlatforms",
4769
- plannedEndpoint: "GET /api/channels/platforms"
4770
- }, async () => clone(CHANNEL_PLATFORMS)),
4771
- /** Connections (with their channel bindings) for one agent. */
4772
- listForAgent: mock({
4773
- domain: "channels",
4774
- method: "listForAgent",
4775
- plannedEndpoint: "GET /api/agents/:agentId/channels"
4776
- }, async (agentId) => {
4777
- const id = requireAgentId(agentId);
4778
- return clone(readStore()[id] ?? []);
4779
- }),
4780
- /**
4781
- * Channel directory for a platform — the picker source. NET-NEW vs. the
4782
- * current backend (no channel-list endpoint exists). The runtime team needs
4783
- * to expose this (e.g. Slack `conversations.list`) for a real picker.
4784
- */
4785
- listChannels: mock({
4786
- domain: "channels",
4787
- method: "listChannels",
4788
- plannedEndpoint: "GET /api/channels/:platform/directory"
4789
- }, async (platform) => clone(CHANNEL_DIRECTORY[platform] ?? [])),
4790
- /** Connect a platform for an agent (OAuth install or credential entry), optionally with a first binding. */
4791
- connect: mock({
4792
- domain: "channels",
4793
- method: "connect",
4794
- plannedEndpoint: "POST /api/agents/:agentId/channels"
4795
- }, async (input) => {
4796
- const agentId = requireAgentId(input.agentId);
4797
- const store = readStore();
4798
- const now = (/* @__PURE__ */ new Date()).toISOString();
4799
- const connection = {
4800
- id: newId("chan-conn"),
4801
- platform: input.platform,
4802
- agentId,
4803
- accountLabel: input.accountLabel ?? defaultAccountLabel(input.platform),
4804
- accountId: newId("acct").toUpperCase(),
4805
- connectedAt: now,
4806
- bindings: input.initialBinding ? [toBinding(input.initialBinding, now)] : []
4807
- };
4808
- writeStore({
4809
- ...store,
4810
- [agentId]: [...store[agentId] ?? [], connection]
4811
- });
4812
- return clone(connection);
4813
- }),
4814
- /** Add a channel binding to an existing connection. */
4815
- addBinding: mock({
4816
- domain: "channels",
4817
- method: "addBinding",
4818
- plannedEndpoint: "PUT /gateways/:platform/attachments/:channelId"
4819
- }, async (input) => {
4820
- const agentId = requireAgentId(input.agentId);
4821
- const store = readStore();
4822
- const connections = store[agentId] ?? [];
4823
- const connection = findConnection(connections, input.connectionId);
4824
- const now = (/* @__PURE__ */ new Date()).toISOString();
4825
- connection.bindings = [...connection.bindings, toBinding(input.binding, now)];
4826
- writeStore({
4827
- ...store,
4828
- [agentId]: connections
4829
- });
4830
- return clone(connection);
4831
- }),
4832
- /** Update a binding's listen mode / subscribe flag. */
4833
- updateBinding: mock({
4834
- domain: "channels",
4835
- method: "updateBinding",
4836
- plannedEndpoint: "PUT /gateways/:platform/attachments/:channelId"
4837
- }, async (input) => {
4838
- const agentId = requireAgentId(input.agentId);
4839
- const store = readStore();
4840
- const connections = store[agentId] ?? [];
4841
- const connection = findConnection(connections, input.connectionId);
4842
- const binding = connection.bindings.find((entry) => entry.id === input.bindingId);
4843
- if (!binding) throw new Error(`Channel binding not found: ${input.bindingId}`);
4844
- if (input.patch.mode !== void 0) binding.mode = input.patch.mode;
4845
- if (input.patch.subscribeOnMention !== void 0) binding.subscribeOnMention = input.patch.subscribeOnMention;
4846
- binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4847
- writeStore({
4848
- ...store,
4849
- [agentId]: connections
4850
- });
4851
- return clone(connection);
4852
- }),
4853
- /** Remove a channel binding. */
4854
- removeBinding: mock({
4855
- domain: "channels",
4856
- method: "removeBinding",
4857
- plannedEndpoint: "DELETE /gateways/:platform/attachments/:channelId"
4858
- }, async (input) => {
4859
- const agentId = requireAgentId(input.agentId);
4860
- const store = readStore();
4861
- const connections = store[agentId] ?? [];
4862
- const connection = findConnection(connections, input.connectionId);
4863
- connection.bindings = connection.bindings.filter((entry) => entry.id !== input.bindingId);
4864
- writeStore({
4865
- ...store,
4866
- [agentId]: connections
4867
- });
4868
- return clone(connection);
4869
- }),
4870
- /** Disconnect the agent from a platform (removes the connection + its bindings). */
4871
- disconnect: mock({
4872
- domain: "channels",
4873
- method: "disconnect",
4874
- plannedEndpoint: "DELETE /api/agents/:agentId/channels/:connectionId"
4875
- }, async (input) => {
4876
- const agentId = requireAgentId(input.agentId);
4877
- const store = readStore();
4878
- const next = (store[agentId] ?? []).filter((entry) => entry.id !== input.connectionId);
4879
- writeStore({
4880
- ...store,
4881
- [agentId]: next
4882
- });
4883
- })
4884
4420
  };
4885
4421
  }
4886
4422
  const JWT_RETRY_HEADER = "x-keystroke-jwt-retry";
@@ -4935,7 +4471,7 @@ function createPlatformClient(options) {
4935
4471
  gatewayAttachments: createGatewayAttachmentsResource(http),
4936
4472
  projectMetrics: createProjectMetricsResource(http),
4937
4473
  projectFiles: createProjectFilesResource(http),
4938
- channels: createChannelsResource(),
4474
+ channels: createChannelsResource(http),
4939
4475
  members: createMembersResource(http),
4940
4476
  invitations: createInvitationsResource(http),
4941
4477
  apiKeys: createApiKeysResource(),
@@ -5382,19 +4918,19 @@ function registerAppCommand(program) {
5382
4918
  }
5383
4919
  //#endregion
5384
4920
  //#region src/commands/connect/parse-connect-scopes.ts
5385
- function parseConnectScopes(scopes, projectIds) {
4921
+ function parseConnectScopes(scopes, projectSlugs) {
5386
4922
  const normalized = scopes.length > 0 ? scopes : ["org"];
5387
4923
  for (const scope of normalized) if (scope !== "org" && scope !== "user" && scope !== "project") throw new Error(`Unknown scope "${scope}". Expected org, user, or project.`);
5388
4924
  const createOrganizationCredential = normalized.includes("org");
5389
4925
  const createUserProvidedCredential = normalized.includes("user");
5390
4926
  const includesProject = normalized.includes("project");
5391
- const selectedProjectIds = includesProject ? projectIds : [];
5392
- if (includesProject && selectedProjectIds.length === 0) throw new Error("--project-id is required when scope includes project");
5393
- if (!createOrganizationCredential && !createUserProvidedCredential && selectedProjectIds.length === 0) throw new Error("At least one scope is required via --scope and/or --project-id");
4927
+ const selectedProjects = includesProject ? projectSlugs : [];
4928
+ if (includesProject && selectedProjects.length === 0) throw new Error("--project-slug is required when scope includes project");
4929
+ if (!createOrganizationCredential && !createUserProvidedCredential && selectedProjects.length === 0) throw new Error("At least one scope is required via --scope and/or --project-slug");
5394
4930
  return {
5395
4931
  createOrganizationCredential,
5396
4932
  createUserProvidedCredential,
5397
- projectIds: selectedProjectIds
4933
+ projects: selectedProjects
5398
4934
  };
5399
4935
  }
5400
4936
  //#endregion
@@ -5430,7 +4966,7 @@ async function runConnect(options) {
5430
4966
  appId: provider.key,
5431
4967
  scopes: oauthScopes,
5432
4968
  permissionMode: "default",
5433
- projectIds: scopes.projectIds,
4969
+ projects: scopes.projects,
5434
4970
  createOrganizationCredential: scopes.createOrganizationCredential,
5435
4971
  createUserProvidedCredential: scopes.createUserProvidedCredential
5436
4972
  });
@@ -5469,11 +5005,11 @@ function resolveConnectTargetOptions() {
5469
5005
  if (local) return { local: true };
5470
5006
  return { orgScoped: true };
5471
5007
  }
5472
- function collectValues(value, previous) {
5008
+ function collectValues$1(value, previous) {
5473
5009
  return previous.concat([value]);
5474
5010
  }
5475
5011
  function registerConnectCommand(program) {
5476
- program.command("connect [provider]").description("Connect third-party accounts (uses apiTarget; --local for local server)").option("--oauth-scope <scope>", "OAuth permission scope to request (repeatable)", collectValues, []).option("--scope <scope>", "Credential scope: org, user, or project (repeatable)", collectValues, []).option("--project-id <id>", "Project id when scope includes project (repeatable)", collectValues, []).option("--print-url", "Print the authorize URL and exit without opening the browser").action((provider, options) => runCliCommand("Could not fetch connect providers", async (ctx) => {
5012
+ program.command("connect [provider]").description("Connect third-party accounts (uses apiTarget; --local for local server)").option("--oauth-scope <scope>", "OAuth permission scope to request (repeatable)", collectValues$1, []).option("--scope <scope>", "Credential scope: org, user, or project (repeatable)", collectValues$1, []).option("--project-slug <slug>", "Project slug when scope includes project (repeatable)", collectValues$1, []).option("--print-url", "Print the authorize URL and exit without opening the browser").action((provider, options) => runCliCommand("Could not fetch connect providers", async (ctx) => {
5477
5013
  const providers = await ctx.client.connect.listProviders();
5478
5014
  if (!provider) {
5479
5015
  if (providers.length === 0) {
@@ -5489,9 +5025,9 @@ function registerConnectCommand(program) {
5489
5025
  const available = providers.map((entry) => entry.key).join(", ") || "(none)";
5490
5026
  throw new Error(`Unknown provider "${provider}". Available: ${available}`);
5491
5027
  }
5492
- const hasScopeFlags = options.scope.length > 0 || options.projectId.length > 0;
5493
- if (ctx.apiTarget.mode === "local" && hasScopeFlags) throw new Error("--scope and --project-id are only supported against the platform API (omit --local)");
5494
- const credentialScopes = ctx.apiTarget.mode === "platform" ? parseConnectScopes(options.scope, options.projectId) : void 0;
5028
+ const hasScopeFlags = options.scope.length > 0 || options.projectSlug.length > 0;
5029
+ if (ctx.apiTarget.mode === "local" && hasScopeFlags) throw new Error("--scope and --project-slug are only supported against the platform API (omit --local)");
5030
+ const credentialScopes = ctx.apiTarget.mode === "platform" ? parseConnectScopes(options.scope, options.projectSlug) : void 0;
5495
5031
  const platform = ctx.apiTarget.mode === "platform" ? createCliPlatformClient(createCliConfig()) : void 0;
5496
5032
  await runConnect({
5497
5033
  client: ctx.client,
@@ -5505,6 +5041,73 @@ function registerConnectCommand(program) {
5505
5041
  }, void 0, resolveConnectTargetOptions()));
5506
5042
  }
5507
5043
  //#endregion
5044
+ //#region src/commands/project/run-project.ts
5045
+ async function withActivePlatformClient(config, fn) {
5046
+ const platform = createCliPlatformClient(config);
5047
+ let active = await platform.organizations.getActive();
5048
+ if (!active) active = await selectActiveOrganization(config);
5049
+ platform.setActiveOrganizationId(active.organization.id);
5050
+ await fn(platform);
5051
+ }
5052
+ function writeInactiveDeployHints(projects) {
5053
+ const bin = cliBinaryName();
5054
+ for (const project of projects) {
5055
+ if (project.status !== "inactive") continue;
5056
+ process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin} deploy --project ${formatProjectLabel(project)}\n`);
5057
+ }
5058
+ }
5059
+ async function runProjectList(config) {
5060
+ await withActivePlatformClient(config, async (platform) => {
5061
+ const projects = await platform.projects.list();
5062
+ process.stdout.write(`${JSON.stringify({ projects }, null, 2)}\n`);
5063
+ if (projects.length === 0) {
5064
+ const bin = cliBinaryName();
5065
+ process.stderr.write(`No projects yet. Create one with: ${bin} project create --name "My project"\n`);
5066
+ return;
5067
+ }
5068
+ writeInactiveDeployHints(projects);
5069
+ });
5070
+ }
5071
+ async function runProjectMetrics(config, options) {
5072
+ await withActivePlatformClient(config, async (platform) => {
5073
+ const metrics = await platform.projectMetrics.list();
5074
+ if (options.projectRef === void 0) {
5075
+ process.stdout.write(`${JSON.stringify(metrics, null, 2)}\n`);
5076
+ return;
5077
+ }
5078
+ const project = await resolveProjectRef(platform, options.projectRef);
5079
+ const output = Object.fromEntries(Object.entries(metrics).filter(([projectId]) => projectId === project.id));
5080
+ process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
5081
+ });
5082
+ }
5083
+ async function runProjectDeploymentsList(config, options) {
5084
+ await withActivePlatformClient(config, async (platform) => {
5085
+ const project = await resolveProjectRef(platform, options.projectRef);
5086
+ const deployments = await platform.deployments.listForProject(project.id);
5087
+ process.stdout.write(`${JSON.stringify({ deployments }, null, 2)}\n`);
5088
+ });
5089
+ }
5090
+ async function runProjectCreate(config, input) {
5091
+ await withActivePlatformClient(config, async (platform) => {
5092
+ const project = await platform.projects.create(input);
5093
+ process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
5094
+ writeInactiveDeployHints([project]);
5095
+ });
5096
+ }
5097
+ async function runProjectUpdate(config, input) {
5098
+ await withActivePlatformClient(config, async (platform) => {
5099
+ const { projectId, ...patch } = input;
5100
+ const project = await platform.projects.update(projectId, patch);
5101
+ process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
5102
+ });
5103
+ }
5104
+ async function runProjectDelete(config, projectId) {
5105
+ await withActivePlatformClient(config, async (platform) => {
5106
+ await platform.projects.delete(projectId);
5107
+ process.stdout.write(`${JSON.stringify({ deleted: projectId }, null, 2)}\n`);
5108
+ });
5109
+ }
5110
+ //#endregion
5508
5111
  //#region src/commands/credentials/target-options.ts
5509
5112
  function resolveCredentialsTargetOptions(options = {}) {
5510
5113
  if (options.scopeType === "project") return {
@@ -5515,10 +5118,21 @@ function resolveCredentialsTargetOptions(options = {}) {
5515
5118
  }
5516
5119
  //#endregion
5517
5120
  //#region src/commands/credentials/run-credentials.ts
5518
- async function withActivePlatformClient$1(config, fn) {
5519
- const platform = createCliPlatformClient(config);
5520
- await ensureActiveOrganization(config);
5521
- await fn(platform);
5121
+ async function createLocalCredentialsClient(targetOptions) {
5122
+ const config = createCliConfig();
5123
+ const target = await resolveApiTarget(config, {
5124
+ ...getCliTargetOptions(),
5125
+ ...resolveCredentialsTargetOptions(),
5126
+ ...targetOptions
5127
+ });
5128
+ return {
5129
+ config,
5130
+ client: createCliClient(config, {
5131
+ baseUrl: target.baseUrl,
5132
+ platform: target.mode === "platform"
5133
+ }),
5134
+ target
5135
+ };
5522
5136
  }
5523
5137
  function isLocalCredentialsTarget() {
5524
5138
  return Boolean(getCliTargetOptions().local);
@@ -5534,7 +5148,7 @@ async function runCredentialsCommand(fallback, fn) {
5534
5148
  });
5535
5149
  return;
5536
5150
  }
5537
- await withActivePlatformClient$1(config, async (platform) => {
5151
+ await withActivePlatformClient(config, async (platform) => {
5538
5152
  await fn({
5539
5153
  config,
5540
5154
  platform,
@@ -5550,15 +5164,14 @@ async function runCredentialsCommand(fallback, fn) {
5550
5164
  }
5551
5165
  }
5552
5166
  function buildPlatformCreateRequest(args) {
5553
- const apiKey = Object.values(args.value)[0];
5554
- if (!apiKey) throw new Error("At least one --set field is required");
5167
+ if (Object.keys(args.value).length === 0) throw new Error("At least one --set field is required");
5555
5168
  return {
5556
5169
  appId: args.appId,
5557
5170
  connectionKind: "manual",
5558
- apiKey,
5559
- projectIds: args.scope === "project" && args.projectId ? [args.projectId] : [],
5560
- createOrganizationCredential: args.scope === "org",
5561
- createUserProvidedCredential: args.scope === "user"
5171
+ value: args.value,
5172
+ projects: args.targets.projects,
5173
+ createOrganizationCredential: args.targets.createOrganizationCredential,
5174
+ createUserProvidedCredential: args.targets.createUserProvidedCredential
5562
5175
  };
5563
5176
  }
5564
5177
  function buildPlatformUpdatePatch(args) {
@@ -5573,15 +5186,8 @@ function buildPlatformUpdatePatch(args) {
5573
5186
  function registerCredentialsDeleteCommand(credentials) {
5574
5187
  credentials.command("delete").description("Delete a credential instance").argument("<id>", "Credential instance id").action((id) => runCredentialsCommand("Delete credential failed", async ({ platform, local }) => {
5575
5188
  if (local) {
5576
- const config = createCliConfig();
5577
- const target = await resolveApiTarget(config, {
5578
- ...getCliTargetOptions(),
5579
- ...resolveCredentialsTargetOptions()
5580
- });
5581
- await createCliClient(config, {
5582
- baseUrl: target.baseUrl,
5583
- platform: target.mode === "platform"
5584
- }).credentials.deleteInstance(id);
5189
+ const { client } = await createLocalCredentialsClient();
5190
+ await client.credentials.deleteInstance(id);
5585
5191
  return;
5586
5192
  }
5587
5193
  await platform.credentials.delete(id);
@@ -5592,15 +5198,8 @@ function registerCredentialsDeleteCommand(credentials) {
5592
5198
  function registerCredentialsGetCommand(credentials) {
5593
5199
  credentials.command("get").description("Get a credential instance by id").argument("<id>", "Credential instance id").action((id) => runCredentialsCommand("Get credential failed", async ({ platform, local }) => {
5594
5200
  if (local) {
5595
- const config = createCliConfig();
5596
- const target = await resolveApiTarget(config, {
5597
- ...getCliTargetOptions(),
5598
- ...resolveCredentialsTargetOptions()
5599
- });
5600
- const match = (await createCliClient(config, {
5601
- baseUrl: target.baseUrl,
5602
- platform: target.mode === "platform"
5603
- }).credentials.listInstances()).instances.find((instance) => instance.id === id);
5201
+ const { client } = await createLocalCredentialsClient();
5202
+ const match = (await client.credentials.listInstances()).instances.find((instance) => instance.id === id);
5604
5203
  if (!match) throw new Error(`Credential ${id} not found`);
5605
5204
  process.stdout.write(`${JSON.stringify(match, null, 2)}\n`);
5606
5205
  return;
@@ -5614,15 +5213,8 @@ function registerCredentialsGetCommand(credentials) {
5614
5213
  function registerCredentialsListCommand(credentials) {
5615
5214
  credentials.command("list").description("List stored credential instances").option("--key <key>", "Filter by credential key (local server only)").action((options) => runCredentialsCommand("List credential instances failed", async ({ platform, local }) => {
5616
5215
  if (local) {
5617
- const config = createCliConfig();
5618
- const target = await resolveApiTarget(config, {
5619
- ...getCliTargetOptions(),
5620
- ...resolveCredentialsTargetOptions()
5621
- });
5622
- const result = await createCliClient(config, {
5623
- baseUrl: target.baseUrl,
5624
- platform: target.mode === "platform"
5625
- }).credentials.listInstances(options.key ? { key: options.key } : void 0);
5216
+ const { client } = await createLocalCredentialsClient();
5217
+ const result = await client.credentials.listInstances(options.key ? { key: options.key } : void 0);
5626
5218
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5627
5219
  return;
5628
5220
  }
@@ -5775,83 +5367,119 @@ async function assertNoSetConflict(client, args) {
5775
5367
  }));
5776
5368
  }
5777
5369
  //#endregion
5370
+ //#region src/commands/credentials/parse-set-scopes.ts
5371
+ function parseCredentialSetScopes(scopes, projectSlugs) {
5372
+ if (scopes.includes("global")) {
5373
+ if (scopes.length > 1) throw new Error("global scope cannot be combined with org, user, or project");
5374
+ if (projectSlugs.length > 0) throw new Error("global scope cannot be combined with --project-slug");
5375
+ return { global: true };
5376
+ }
5377
+ return parseConnectScopes(scopes, projectSlugs);
5378
+ }
5379
+ //#endregion
5778
5380
  //#region src/commands/credentials/set.ts
5779
5381
  function registerCredentialsSetCommand(credentials) {
5780
- credentials.command("set").description("Create a new api_key credential instance").argument("<key>", "Credential key or app id, e.g. exa").requiredOption("--scope <scope>", "org, user, project, or global").option("--project-id <id>", "Project id when scope is project").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 }) => {
5382
+ 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, project, or global (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 }) => {
5781
5383
  const value = parseCredentialValueFields(options.set);
5782
- const scopeType = scopeTypeFromCli(options.scope);
5783
- if (scopeType === "project" && !options.projectId) throw new Error("--project-id is required when scope is project");
5384
+ const parsedScopes = parseCredentialSetScopes(options.scope, options.projectSlug);
5784
5385
  if (local) {
5785
- const config = createCliConfig();
5786
- const target = await resolveApiTarget(config, {
5787
- ...getCliTargetOptions(),
5788
- ...resolveCredentialsTargetOptions({
5386
+ const { client } = await createLocalCredentialsClient();
5387
+ if ("global" in parsedScopes) {
5388
+ const scopeType = scopeTypeFromCli("global");
5389
+ await assertNoSetConflict(client, {
5390
+ key,
5391
+ scope: "global",
5789
5392
  scopeType,
5790
- projectId: options.projectId
5791
- })
5792
- });
5793
- const client = createCliClient(config, {
5794
- baseUrl: target.baseUrl,
5795
- platform: target.mode === "platform"
5796
- });
5797
- await assertNoSetConflict(client, {
5798
- key,
5799
- scope: options.scope,
5800
- scopeType,
5801
- projectId: options.projectId,
5802
- label: options.label,
5803
- setFields: options.set
5804
- });
5805
- const result = await client.credentials.createInstance({
5806
- key,
5807
- scopeType,
5808
- scopeId: scopeType === "project" ? options.projectId : void 0,
5809
- label: options.label,
5810
- isDefault: options.default,
5811
- value
5812
- });
5813
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5393
+ label: options.label,
5394
+ setFields: options.set
5395
+ });
5396
+ const result = await client.credentials.createInstance({
5397
+ key,
5398
+ scopeType,
5399
+ label: options.label,
5400
+ isDefault: options.default,
5401
+ value
5402
+ });
5403
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
5404
+ return;
5405
+ }
5406
+ const targets = expandLocalCredentialTargets(parsedScopes);
5407
+ const instances = [];
5408
+ for (const target of targets) {
5409
+ await assertNoSetConflict(client, {
5410
+ key,
5411
+ scope: target.scope,
5412
+ scopeType: target.scopeType,
5413
+ projectId: target.projectSlug,
5414
+ label: options.label,
5415
+ setFields: options.set
5416
+ });
5417
+ instances.push(await client.credentials.createInstance({
5418
+ key,
5419
+ scopeType: target.scopeType,
5420
+ scopeId: target.projectSlug,
5421
+ label: options.label,
5422
+ isDefault: options.default,
5423
+ value
5424
+ }));
5425
+ }
5426
+ if (instances.length === 1) {
5427
+ process.stdout.write(`${JSON.stringify(instances[0], null, 2)}\n`);
5428
+ return;
5429
+ }
5430
+ process.stdout.write(`${JSON.stringify({ instances }, null, 2)}\n`);
5814
5431
  return;
5815
5432
  }
5816
- if (options.scope === "global") throw new Error("global scope is only supported against a local keystroke server");
5433
+ if (options.scope.includes("global") || "global" in parsedScopes) throw new Error("global scope is only supported against a local keystroke server");
5817
5434
  const created = await platform.credentials.create(buildPlatformCreateRequest({
5818
5435
  appId: key,
5819
5436
  value,
5820
- scope: options.scope,
5821
- projectId: options.projectId
5437
+ targets: parsedScopes
5822
5438
  }));
5823
5439
  if (options.label !== void 0 || options.default !== void 0) {
5824
5440
  const patch = buildPlatformUpdatePatch({
5825
5441
  ...options.label !== void 0 ? { label: options.label } : {},
5826
5442
  ...options.default !== void 0 ? { isDefault: options.default } : {}
5827
5443
  });
5828
- for (const credential of created) {
5829
- const updated = await platform.credentials.update(credential.id, patch);
5830
- process.stdout.write(`${JSON.stringify({ credential: updated }, null, 2)}\n`);
5831
- }
5444
+ const credentials = [];
5445
+ for (const credential of created) credentials.push(await platform.credentials.update(credential.id, patch));
5446
+ process.stdout.write(`${JSON.stringify({ credentials }, null, 2)}\n`);
5832
5447
  return;
5833
5448
  }
5834
5449
  process.stdout.write(`${JSON.stringify({ credentials: created }, null, 2)}\n`);
5835
5450
  }));
5836
5451
  }
5452
+ function collectValues(value, previous) {
5453
+ return previous.concat([value]);
5454
+ }
5837
5455
  function collectSetValues$1(value, previous) {
5838
5456
  return previous.concat([value]);
5839
5457
  }
5458
+ function expandLocalCredentialTargets(targets) {
5459
+ const expanded = [];
5460
+ if (targets.createOrganizationCredential) expanded.push({
5461
+ scope: "org",
5462
+ scopeType: scopeTypeFromCli("org")
5463
+ });
5464
+ if (targets.createUserProvidedCredential) expanded.push({
5465
+ scope: "user",
5466
+ scopeType: scopeTypeFromCli("user")
5467
+ });
5468
+ for (const projectSlug of targets.projects) expanded.push({
5469
+ scope: "project",
5470
+ scopeType: scopeTypeFromCli("project"),
5471
+ projectSlug
5472
+ });
5473
+ return expanded;
5474
+ }
5840
5475
  //#endregion
5841
5476
  //#region src/commands/credentials/update.ts
5842
5477
  function registerCredentialsUpdateCommand(credentials) {
5843
5478
  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 }) => {
5844
5479
  const value = options.set.length > 0 ? parseCredentialValueFields(options.set) : void 0;
5845
5480
  if (local) {
5846
- const config = createCliConfig();
5847
- const target = await resolveApiTarget(config, {
5848
- ...getCliTargetOptions(),
5849
- ...resolveCredentialsTargetOptions()
5850
- });
5851
- const result = await createCliClient(config, {
5852
- baseUrl: target.baseUrl,
5853
- platform: target.mode === "platform"
5854
- }).credentials.updateInstance(id, {
5481
+ const { client } = await createLocalCredentialsClient();
5482
+ const result = await client.credentials.updateInstance(id, {
5855
5483
  ...options.label !== void 0 ? { label: options.label } : {},
5856
5484
  ...options.default !== void 0 ? { isDefault: options.default } : {},
5857
5485
  ...value ? { value } : {}
@@ -5992,7 +5620,7 @@ function registerBuildCommand(program) {
5992
5620
  program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
5993
5621
  try {
5994
5622
  const root = resolveProjectRoot(options.dir);
5995
- const { buildApp } = await import("./dist-CcJj87Po.mjs");
5623
+ const { buildApp } = await import("./dist-DkDkM0NH.mjs");
5996
5624
  await buildApp({ root });
5997
5625
  process.stdout.write(`Built ${root}\n`);
5998
5626
  } catch (error) {
@@ -6089,7 +5717,7 @@ async function runDeploy(options) {
6089
5717
  const client = createCliPlatformClient(config);
6090
5718
  let source;
6091
5719
  if (!options.skipBuild) {
6092
- const { buildApp } = await import("./dist-CcJj87Po.mjs");
5720
+ const { buildApp } = await import("./dist-DkDkM0NH.mjs");
6093
5721
  source = { files: (await buildApp({
6094
5722
  root,
6095
5723
  collectSources: true,
@@ -6189,7 +5817,7 @@ function runtimeChildEnv(parentEnv, overrides) {
6189
5817
  //#region src/project/bootstrap-run.ts
6190
5818
  /** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
6191
5819
  async function resolveBootstrapRun(options) {
6192
- const { resolveRuntimeBuildArtifact } = await import("./dist-CcJj87Po.mjs");
5820
+ const { resolveRuntimeBuildArtifact } = await import("./dist-DkDkM0NH.mjs");
6193
5821
  const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
6194
5822
  const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/bootstrap.mjs");
6195
5823
  const args = [`--import=${loader}`];
@@ -6339,7 +5967,7 @@ async function runDev(options) {
6339
5967
  process.on("SIGINT", shutdown);
6340
5968
  process.on("SIGTERM", shutdown);
6341
5969
  try {
6342
- const { watchApp } = await import("./dist-CcJj87Po.mjs");
5970
+ const { watchApp } = await import("./dist-DkDkM0NH.mjs");
6343
5971
  await watchApp({
6344
5972
  root,
6345
5973
  clean: false,
@@ -6367,73 +5995,6 @@ function registerDevCommand(program) {
6367
5995
  });
6368
5996
  }
6369
5997
  //#endregion
6370
- //#region src/commands/project/run-project.ts
6371
- async function withActivePlatformClient(config, fn) {
6372
- const platform = createCliPlatformClient(config);
6373
- let active = await platform.organizations.getActive();
6374
- if (!active) active = await selectActiveOrganization(config);
6375
- platform.setActiveOrganizationId(active.organization.id);
6376
- await fn(platform);
6377
- }
6378
- function writeInactiveDeployHints(projects) {
6379
- const bin = cliBinaryName();
6380
- for (const project of projects) {
6381
- if (project.status !== "inactive") continue;
6382
- process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin} deploy --project ${formatProjectLabel(project)}\n`);
6383
- }
6384
- }
6385
- async function runProjectList(config) {
6386
- await withActivePlatformClient(config, async (platform) => {
6387
- const projects = await platform.projects.list();
6388
- process.stdout.write(`${JSON.stringify({ projects }, null, 2)}\n`);
6389
- if (projects.length === 0) {
6390
- const bin = cliBinaryName();
6391
- process.stderr.write(`No projects yet. Create one with: ${bin} project create --name "My project"\n`);
6392
- return;
6393
- }
6394
- writeInactiveDeployHints(projects);
6395
- });
6396
- }
6397
- async function runProjectMetrics(config, options) {
6398
- await withActivePlatformClient(config, async (platform) => {
6399
- const metrics = await platform.projectMetrics.list();
6400
- if (options.projectRef === void 0) {
6401
- process.stdout.write(`${JSON.stringify(metrics, null, 2)}\n`);
6402
- return;
6403
- }
6404
- const project = await resolveProjectRef(platform, options.projectRef);
6405
- const output = Object.fromEntries(Object.entries(metrics).filter(([projectId]) => projectId === project.id));
6406
- process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
6407
- });
6408
- }
6409
- async function runProjectDeploymentsList(config, options) {
6410
- await withActivePlatformClient(config, async (platform) => {
6411
- const project = await resolveProjectRef(platform, options.projectRef);
6412
- const deployments = await platform.deployments.listForProject(project.id);
6413
- process.stdout.write(`${JSON.stringify({ deployments }, null, 2)}\n`);
6414
- });
6415
- }
6416
- async function runProjectCreate(config, input) {
6417
- await withActivePlatformClient(config, async (platform) => {
6418
- const project = await platform.projects.create(input);
6419
- process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
6420
- writeInactiveDeployHints([project]);
6421
- });
6422
- }
6423
- async function runProjectUpdate(config, input) {
6424
- await withActivePlatformClient(config, async (platform) => {
6425
- const { projectId, ...patch } = input;
6426
- const project = await platform.projects.update(projectId, patch);
6427
- process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
6428
- });
6429
- }
6430
- async function runProjectDelete(config, projectId) {
6431
- await withActivePlatformClient(config, async (platform) => {
6432
- await platform.projects.delete(projectId);
6433
- process.stdout.write(`${JSON.stringify({ deleted: projectId }, null, 2)}\n`);
6434
- });
6435
- }
6436
- //#endregion
6437
5998
  //#region src/commands/history/run-history.ts
6438
5999
  async function runHistoryList(config, filters) {
6439
6000
  await withActivePlatformClient(config, async (platform) => {
@@ -6954,7 +6515,7 @@ async function runStart(options) {
6954
6515
  const apiPort = Number(new URL(serverUrl).port || 80);
6955
6516
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
6956
6517
  ensureNativeDeps(runtimeNodeModules);
6957
- const { buildApp } = await import("./dist-CcJj87Po.mjs");
6518
+ const { buildApp } = await import("./dist-DkDkM0NH.mjs");
6958
6519
  await buildApp({
6959
6520
  root,
6960
6521
  clean: false
@@ -7102,6 +6663,143 @@ function registerWorkflowCommand(program) {
7102
6663
  registerWorkflowRunsCommand(workflow);
7103
6664
  }
7104
6665
  //#endregion
6666
+ //#region src/commands/channel/run-channel.ts
6667
+ async function runChannelPlatformsList(client) {
6668
+ return client.channels.listPlatforms();
6669
+ }
6670
+ async function runChannelAccounts(client, projectId, platform) {
6671
+ return client.channels.listAccounts(projectId, platform);
6672
+ }
6673
+ async function runChannelList(client, projectId, agentId) {
6674
+ return client.channels.listForAgent(projectId, agentId);
6675
+ }
6676
+ async function runChannelDirectory(client, projectId, platform, accountId) {
6677
+ return client.channels.listChannels(projectId, platform, accountId);
6678
+ }
6679
+ async function runChannelBind(client, projectId, input) {
6680
+ return client.channels.bind(projectId, input);
6681
+ }
6682
+ async function runChannelUpdateBinding(client, projectId, input) {
6683
+ return client.channels.updateBinding(projectId, input);
6684
+ }
6685
+ async function runChannelUnbind(client, projectId, input) {
6686
+ return client.channels.removeBinding(projectId, input);
6687
+ }
6688
+ //#endregion
6689
+ //#region src/commands/channel/platforms.ts
6690
+ function registerChannelPlatformsCommand(channel) {
6691
+ channel.command("platforms").description("Browse gateway-enabled apps").command("list").description("List apps that support agent external channels").action(() => runCliCommand("List channel platforms failed", async () => {
6692
+ const config = createCliConfig();
6693
+ const client = createCliPlatformClient(config);
6694
+ await ensureActiveOrganization(config);
6695
+ const platforms = await runChannelPlatformsList(client);
6696
+ process.stdout.write(`${JSON.stringify({ platforms }, null, 2)}\n`);
6697
+ }, void 0, { orgScoped: true }));
6698
+ }
6699
+ //#endregion
6700
+ //#region src/commands/channel/resolve-channel-project.ts
6701
+ async function resolveChannelProjectId(config, projectRef) {
6702
+ const platform = createCliPlatformClient(config);
6703
+ await ensureActiveOrganization(config);
6704
+ const ref = projectRef?.trim() || getCliTargetOptions().projectId?.trim() || config.get("activeProjectId")?.trim();
6705
+ if (!ref) throw new Error("Project is required. Pass --project <slug> or set an active project.");
6706
+ return (await resolveProjectRef(platform, ref)).id;
6707
+ }
6708
+ //#endregion
6709
+ //#region src/commands/channel/list.ts
6710
+ function registerChannelAccountsCommand(channel) {
6711
+ channel.command("accounts").description("List available workspace accounts for a platform").requiredOption("--platform <key>", "Platform key (slack)").option("--project <slug>", "Project slug").action(async (options) => runCliCommand("List channel accounts failed", async () => {
6712
+ const config = createCliConfig();
6713
+ const projectId = await resolveChannelProjectId(config, options.project);
6714
+ const client = createCliPlatformClient(config);
6715
+ await ensureActiveOrganization(config);
6716
+ const accounts = await runChannelAccounts(client, projectId, options.platform);
6717
+ process.stdout.write(`${JSON.stringify({ accounts }, null, 2)}\n`);
6718
+ }));
6719
+ }
6720
+ function registerChannelListCommand(channel) {
6721
+ channel.command("list").description("List channel bindings for an agent").requiredOption("--agent <id>", "Agent id").option("--project <slug>", "Project slug").action(async (options) => runCliCommand("List agent channels failed", async () => {
6722
+ const config = createCliConfig();
6723
+ const projectId = await resolveChannelProjectId(config, options.project);
6724
+ const client = createCliPlatformClient(config);
6725
+ await ensureActiveOrganization(config);
6726
+ const connections = await runChannelList(client, projectId, options.agent);
6727
+ process.stdout.write(`${JSON.stringify({ connections }, null, 2)}\n`);
6728
+ }));
6729
+ }
6730
+ function registerChannelDirectoryCommand(channel) {
6731
+ channel.command("directory").description("List channels available to bind from a platform directory").requiredOption("--platform <key>", "Platform key (slack)").requiredOption("--account <id>", "Workspace account id (team id)").option("--project <slug>", "Project slug").action(async (options) => runCliCommand("List channel directory failed", async () => {
6732
+ const config = createCliConfig();
6733
+ const projectId = await resolveChannelProjectId(config, options.project);
6734
+ const client = createCliPlatformClient(config);
6735
+ await ensureActiveOrganization(config);
6736
+ const channels = await runChannelDirectory(client, projectId, options.platform, options.account);
6737
+ process.stdout.write(`${JSON.stringify({ channels }, null, 2)}\n`);
6738
+ }));
6739
+ }
6740
+ function registerChannelBindCommand(channel) {
6741
+ channel.command("bind").description("Bind an agent to a channel").requiredOption("--agent <id>", "Agent id").requiredOption("--platform <key>", "Platform key (slack)").requiredOption("--account <id>", "Workspace account id (team id)").requiredOption("--channel <id>", "Provider channel id").option("--channel-name <name>", "Provider channel name").option("--mode <mode>", "Listen mode (mention, all, dm)", "mention").option("--project <slug>", "Project slug").action(async (options) => runCliCommand("Bind channel failed", async () => {
6742
+ const config = createCliConfig();
6743
+ const projectId = await resolveChannelProjectId(config, options.project);
6744
+ const client = createCliPlatformClient(config);
6745
+ await ensureActiveOrganization(config);
6746
+ const connection = await runChannelBind(client, projectId, {
6747
+ agentId: options.agent,
6748
+ platform: options.platform,
6749
+ accountId: options.account,
6750
+ binding: {
6751
+ channelId: options.channel,
6752
+ channelName: options.channelName ?? options.channel,
6753
+ mode: options.mode,
6754
+ subscribeOnMention: true
6755
+ }
6756
+ });
6757
+ process.stdout.write(`${JSON.stringify({ connection }, null, 2)}\n`);
6758
+ }));
6759
+ }
6760
+ function registerChannelUnbindCommand(channel) {
6761
+ channel.command("unbind").description("Remove a channel binding from an agent").requiredOption("--agent <id>", "Agent id").requiredOption("--binding <id>", "Binding id").option("--project <slug>", "Project slug").action(async (options) => runCliCommand("Unbind channel failed", async () => {
6762
+ const config = createCliConfig();
6763
+ const projectId = await resolveChannelProjectId(config, options.project);
6764
+ const client = createCliPlatformClient(config);
6765
+ await ensureActiveOrganization(config);
6766
+ const connection = await runChannelUnbind(client, projectId, {
6767
+ agentId: options.agent,
6768
+ bindingId: options.binding
6769
+ });
6770
+ process.stdout.write(`${JSON.stringify({ connection }, null, 2)}\n`);
6771
+ }));
6772
+ }
6773
+ function registerChannelUpdateBindingCommand(channel) {
6774
+ channel.command("update-binding").description("Update a channel binding listen mode or thread setting").requiredOption("--agent <id>", "Agent id").requiredOption("--binding <id>", "Binding id").option("--mode <mode>", "Listen mode (mention, all, dm)").option("--threads", "Enable thread follow-up (subscribe on mention)").option("--no-threads", "Disable thread follow-up").option("--project <slug>", "Project slug").action(async (options) => runCliCommand("Update channel binding failed", async () => {
6775
+ const config = createCliConfig();
6776
+ const projectId = await resolveChannelProjectId(config, options.project);
6777
+ const client = createCliPlatformClient(config);
6778
+ await ensureActiveOrganization(config);
6779
+ const patch = {};
6780
+ if (options.mode) patch.mode = options.mode;
6781
+ if (options.threads !== void 0) patch.subscribeOnMention = options.threads;
6782
+ const connection = await runChannelUpdateBinding(client, projectId, {
6783
+ agentId: options.agent,
6784
+ bindingId: options.binding,
6785
+ patch
6786
+ });
6787
+ process.stdout.write(`${JSON.stringify({ connection }, null, 2)}\n`);
6788
+ }));
6789
+ }
6790
+ //#endregion
6791
+ //#region src/commands/channel/index.ts
6792
+ function registerChannelCommand(program) {
6793
+ const channel = program.command("channel").description("Manage agent external channel bindings");
6794
+ registerChannelPlatformsCommand(channel);
6795
+ registerChannelAccountsCommand(channel);
6796
+ registerChannelListCommand(channel);
6797
+ registerChannelDirectoryCommand(channel);
6798
+ registerChannelBindCommand(channel);
6799
+ registerChannelUnbindCommand(channel);
6800
+ registerChannelUpdateBindingCommand(channel);
6801
+ }
6802
+ //#endregion
7105
6803
  //#region src/commands/config/use-project.ts
7106
6804
  async function fetchProjectInOrg(config, projectRef) {
7107
6805
  return resolveProjectRef(createCliPlatformClient(config), projectRef);
@@ -7317,6 +7015,7 @@ function createProgram() {
7317
7015
  registerDevCommand(program);
7318
7016
  registerStartCommand(program);
7319
7017
  registerAgentCommand(program);
7018
+ registerChannelCommand(program);
7320
7019
  registerAppCommand(program);
7321
7020
  registerWorkflowCommand(program);
7322
7021
  registerTriggerCommand(program);