@keystrokehq/cli 0.0.65 → 0.0.68

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 (33) hide show
  1. package/dist/{cat-TSFMZVYS-Qzyhqpeq.mjs → cat-TSFMZVYS-Bp6ZgHzP.mjs} +2 -2
  2. package/dist/{cat-TSFMZVYS-Qzyhqpeq.mjs.map → cat-TSFMZVYS-Bp6ZgHzP.mjs.map} +1 -1
  3. package/dist/{cut-OKARJCCV-UOo5blGN.mjs → cut-OKARJCCV-DLzvnQ0X.mjs} +2 -2
  4. package/dist/{cut-OKARJCCV-UOo5blGN.mjs.map → cut-OKARJCCV-DLzvnQ0X.mjs.map} +1 -1
  5. package/dist/{dist-D2apKUWN-BDQ3166v.mjs → dist-BNJUEQuz-C9tkfUCE.mjs} +203 -9
  6. package/dist/dist-BNJUEQuz-C9tkfUCE.mjs.map +1 -0
  7. package/dist/{dist-CMxQJtOA.mjs → dist-nRx_8hnk.mjs} +6 -8
  8. package/dist/dist-nRx_8hnk.mjs.map +1 -0
  9. package/dist/{du-572XNP42-4gdN6HgU.mjs → du-572XNP42-DCcv0kSr.mjs} +2 -2
  10. package/dist/{du-572XNP42-4gdN6HgU.mjs.map → du-572XNP42-DCcv0kSr.mjs.map} +1 -1
  11. package/dist/{emit-route-manifest-DRcNXHCP-BHonsCIQ.mjs → emit-route-manifest-DRcNXHCP-BkSmGkhV.mjs} +32 -13
  12. package/dist/{emit-route-manifest-DRcNXHCP-BHonsCIQ.mjs.map → emit-route-manifest-DRcNXHCP-BkSmGkhV.mjs.map} +1 -1
  13. package/dist/index.mjs +1044 -117
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/{jq-4XLYLOS5-D_rIiq4w.mjs → jq-4XLYLOS5-CgTVHGto.mjs} +2 -2
  16. package/dist/{jq-4XLYLOS5-D_rIiq4w.mjs.map → jq-4XLYLOS5-CgTVHGto.mjs.map} +1 -1
  17. package/dist/{ls-ZJGQER7M-B-eSANU2.mjs → ls-ZJGQER7M-DbHjJAJ5.mjs} +2 -2
  18. package/dist/{ls-ZJGQER7M-B-eSANU2.mjs.map → ls-ZJGQER7M-DbHjJAJ5.mjs.map} +1 -1
  19. package/dist/{mistral-CCsOaxvh-FZsMk4KR.mjs → mistral-D7a1LQ-6-CFFRHspK.mjs} +3 -3
  20. package/dist/{mistral-CCsOaxvh-FZsMk4KR.mjs.map → mistral-D7a1LQ-6-CFFRHspK.mjs.map} +1 -1
  21. package/dist/{sort-SW2YEO5B-BaN_eY3l.mjs → sort-SW2YEO5B-DM3UAdjd.mjs} +2 -2
  22. package/dist/{sort-SW2YEO5B-BaN_eY3l.mjs.map → sort-SW2YEO5B-DM3UAdjd.mjs.map} +1 -1
  23. package/dist/{tree-YLD52CNT-BZJomf0H.mjs → tree-YLD52CNT-Bv1j-DWN.mjs} +2 -2
  24. package/dist/{tree-YLD52CNT-BZJomf0H.mjs.map → tree-YLD52CNT-Bv1j-DWN.mjs.map} +1 -1
  25. package/dist/{uniq-XSIZR6PB-Ajuixkb6.mjs → uniq-XSIZR6PB-d6Kx_H64.mjs} +2 -2
  26. package/dist/{uniq-XSIZR6PB-Ajuixkb6.mjs.map → uniq-XSIZR6PB-d6Kx_H64.mjs.map} +1 -1
  27. package/dist/{wc-LF7NU4LA-DiSdKP_u.mjs → wc-LF7NU4LA-B6PXzeyp.mjs} +2 -2
  28. package/dist/{wc-LF7NU4LA-DiSdKP_u.mjs.map → wc-LF7NU4LA-B6PXzeyp.mjs.map} +1 -1
  29. package/dist/{xan-Y6WF3IRG-COQGCVSz.mjs → xan-Y6WF3IRG-CnmH45qB.mjs} +2 -2
  30. package/dist/{xan-Y6WF3IRG-COQGCVSz.mjs.map → xan-Y6WF3IRG-CnmH45qB.mjs.map} +1 -1
  31. package/package.json +21 -21
  32. package/dist/dist-CMxQJtOA.mjs.map +0 -1
  33. package/dist/dist-D2apKUWN-BDQ3166v.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1460,7 +1460,7 @@ const propertyKeyTypes = /* @__PURE__ */ new Set([
1460
1460
  function escapeRegex(str) {
1461
1461
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1462
1462
  }
1463
- function clone(inst, def, params) {
1463
+ function clone$1(inst, def, params) {
1464
1464
  const cl = new inst._zod.constr(def ?? inst._zod.def);
1465
1465
  if (!def || params?.parent) cl._zod.parent = inst;
1466
1466
  return cl;
@@ -1496,7 +1496,7 @@ function pick(schema, mask) {
1496
1496
  const currDef = schema._zod.def;
1497
1497
  const checks = currDef.checks;
1498
1498
  if (checks && checks.length > 0) throw new Error(".pick() cannot be used on object schemas containing refinements");
1499
- return clone(schema, mergeDefs(schema._zod.def, {
1499
+ return clone$1(schema, mergeDefs(schema._zod.def, {
1500
1500
  get shape() {
1501
1501
  const newShape = {};
1502
1502
  for (const key in mask) {
@@ -1514,7 +1514,7 @@ function omit(schema, mask) {
1514
1514
  const currDef = schema._zod.def;
1515
1515
  const checks = currDef.checks;
1516
1516
  if (checks && checks.length > 0) throw new Error(".omit() cannot be used on object schemas containing refinements");
1517
- return clone(schema, mergeDefs(schema._zod.def, {
1517
+ return clone$1(schema, mergeDefs(schema._zod.def, {
1518
1518
  get shape() {
1519
1519
  const newShape = { ...schema._zod.def.shape };
1520
1520
  for (const key in mask) {
@@ -1535,7 +1535,7 @@ function extend(schema, shape) {
1535
1535
  const existingShape = schema._zod.def.shape;
1536
1536
  for (const key in shape) if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.");
1537
1537
  }
1538
- return clone(schema, mergeDefs(schema._zod.def, { get shape() {
1538
+ return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
1539
1539
  const _shape = {
1540
1540
  ...schema._zod.def.shape,
1541
1541
  ...shape
@@ -1546,7 +1546,7 @@ function extend(schema, shape) {
1546
1546
  }
1547
1547
  function safeExtend(schema, shape) {
1548
1548
  if (!isPlainObject$1(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
1549
- return clone(schema, mergeDefs(schema._zod.def, { get shape() {
1549
+ return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
1550
1550
  const _shape = {
1551
1551
  ...schema._zod.def.shape,
1552
1552
  ...shape
@@ -1557,7 +1557,7 @@ function safeExtend(schema, shape) {
1557
1557
  }
1558
1558
  function merge(a, b) {
1559
1559
  if (a._zod.def.checks?.length) throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");
1560
- return clone(a, mergeDefs(a._zod.def, {
1560
+ return clone$1(a, mergeDefs(a._zod.def, {
1561
1561
  get shape() {
1562
1562
  const _shape = {
1563
1563
  ...a._zod.def.shape,
@@ -1575,7 +1575,7 @@ function merge(a, b) {
1575
1575
  function partial(Class, schema, mask) {
1576
1576
  const checks = schema._zod.def.checks;
1577
1577
  if (checks && checks.length > 0) throw new Error(".partial() cannot be used on object schemas containing refinements");
1578
- return clone(schema, mergeDefs(schema._zod.def, {
1578
+ return clone$1(schema, mergeDefs(schema._zod.def, {
1579
1579
  get shape() {
1580
1580
  const oldShape = schema._zod.def.shape;
1581
1581
  const shape = { ...oldShape };
@@ -1598,7 +1598,7 @@ function partial(Class, schema, mask) {
1598
1598
  }));
1599
1599
  }
1600
1600
  function required(Class, schema, mask) {
1601
- return clone(schema, mergeDefs(schema._zod.def, { get shape() {
1601
+ return clone$1(schema, mergeDefs(schema._zod.def, { get shape() {
1602
1602
  const oldShape = schema._zod.def.shape;
1603
1603
  const shape = { ...oldShape };
1604
1604
  if (mask) for (const key in mask) {
@@ -5354,7 +5354,7 @@ const ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
5354
5354
  return this.check(...chks);
5355
5355
  },
5356
5356
  clone(def, params) {
5357
- return clone(this, def, params);
5357
+ return clone$1(this, def, params);
5358
5358
  },
5359
5359
  brand() {
5360
5360
  return this;
@@ -6795,6 +6795,126 @@ function listenPortFromPublicUrl(value, fallback) {
6795
6795
  return fallback;
6796
6796
  }
6797
6797
  }
6798
+ const serializedRouteManifestEntrySchema = discriminatedUnion("kind", [
6799
+ object({
6800
+ kind: literal("health"),
6801
+ method: literal("GET"),
6802
+ path: literal("/health")
6803
+ }),
6804
+ object({
6805
+ kind: literal("agent"),
6806
+ method: literal("POST"),
6807
+ path: string(),
6808
+ moduleFile: string(),
6809
+ requestSchema: record(string(), unknown()),
6810
+ responseSchema: record(string(), unknown())
6811
+ }),
6812
+ object({
6813
+ kind: literal("agent-sessions-list"),
6814
+ method: literal("GET"),
6815
+ path: string(),
6816
+ agentId: string(),
6817
+ moduleFile: string()
6818
+ }),
6819
+ object({
6820
+ kind: literal("agent-session-detail"),
6821
+ method: literal("GET"),
6822
+ path: string(),
6823
+ agentId: string(),
6824
+ moduleFile: string()
6825
+ }),
6826
+ object({
6827
+ kind: literal("workflow"),
6828
+ method: literal("POST"),
6829
+ path: string(),
6830
+ workflowId: string(),
6831
+ workflowName: string().optional(),
6832
+ moduleFile: string(),
6833
+ requestSchema: record(string(), unknown()),
6834
+ responseSchema: record(string(), unknown())
6835
+ }),
6836
+ object({
6837
+ kind: literal("workflow-runs-list"),
6838
+ method: literal("GET"),
6839
+ path: string(),
6840
+ workflowId: string(),
6841
+ workflowName: string().optional(),
6842
+ moduleFile: string()
6843
+ }),
6844
+ object({
6845
+ kind: literal("workflow-run-detail"),
6846
+ method: literal("GET"),
6847
+ path: string(),
6848
+ workflowId: string(),
6849
+ workflowName: string().optional(),
6850
+ moduleFile: string()
6851
+ }),
6852
+ object({
6853
+ kind: literal("trigger-webhook"),
6854
+ method: literal("POST"),
6855
+ path: string(),
6856
+ attachmentIds: array(string()),
6857
+ moduleFile: string(),
6858
+ requestSchema: record(string(), unknown()),
6859
+ responseSchema: record(string(), unknown())
6860
+ }),
6861
+ object({
6862
+ kind: literal("trigger-poll"),
6863
+ method: literal("POST"),
6864
+ path: string(),
6865
+ attachmentId: string(),
6866
+ moduleFile: string(),
6867
+ schedule: string(),
6868
+ responseSchema: record(string(), unknown())
6869
+ }),
6870
+ object({
6871
+ kind: literal("trigger-poll-group"),
6872
+ method: literal("POST"),
6873
+ path: string(),
6874
+ pollId: string(),
6875
+ attachmentIds: array(string()),
6876
+ moduleFile: string(),
6877
+ schedule: string(),
6878
+ responseSchema: record(string(), unknown())
6879
+ }),
6880
+ object({
6881
+ kind: literal("trigger-runs-list"),
6882
+ method: literal("GET"),
6883
+ path: string(),
6884
+ attachmentId: string(),
6885
+ moduleFile: string()
6886
+ }),
6887
+ object({
6888
+ kind: literal("trigger-run-detail"),
6889
+ method: literal("GET"),
6890
+ path: string(),
6891
+ attachmentId: string(),
6892
+ moduleFile: string()
6893
+ }),
6894
+ object({
6895
+ kind: literal("cron-schedule"),
6896
+ attachmentId: string(),
6897
+ moduleFile: string(),
6898
+ schedule: string()
6899
+ }),
6900
+ object({
6901
+ kind: literal("plugin"),
6902
+ method: _enum([
6903
+ "GET",
6904
+ "POST",
6905
+ "PUT",
6906
+ "PATCH",
6907
+ "DELETE"
6908
+ ]),
6909
+ path: string(),
6910
+ plugin: string()
6911
+ })
6912
+ ]);
6913
+ object({
6914
+ version: literal(1),
6915
+ entries: array(serializedRouteManifestEntrySchema),
6916
+ integrations: array(string()).optional()
6917
+ });
6798
6918
  /** How a credential instance is stored (`credential_instances.auth_kind`). */
6799
6919
  const CredentialAuthKindSchema = _enum(["api_key", "oauth_managed"]);
6800
6920
  /** Where a credential instance is stored (`credential_instances.scope_type`). */
@@ -6872,14 +6992,18 @@ const ProjectStatusSchema = _enum([
6872
6992
  "active",
6873
6993
  "failed"
6874
6994
  ]);
6875
- const OrganizationUserRoleSchema = _enum(["admin"]);
6876
- const isoDateTime$1 = string().datetime();
6995
+ const OrganizationUserRoleSchema = _enum([
6996
+ "owner",
6997
+ "admin",
6998
+ "builder"
6999
+ ]);
7000
+ const isoDateTime$2 = string().datetime();
6877
7001
  const OrganizationSchema = object({
6878
7002
  id: string(),
6879
7003
  name: string(),
6880
7004
  slug: OrganizationSlugSchema,
6881
- createdAt: isoDateTime$1,
6882
- updatedAt: isoDateTime$1
7005
+ createdAt: isoDateTime$2,
7006
+ updatedAt: isoDateTime$2
6883
7007
  });
6884
7008
  const ProjectSchema = object({
6885
7009
  id: string(),
@@ -6889,8 +7013,8 @@ const ProjectSchema = object({
6889
7013
  baseUrl: string().nullable(),
6890
7014
  runtimeId: string().nullable(),
6891
7015
  lastError: string().nullable(),
6892
- createdAt: isoDateTime$1,
6893
- updatedAt: isoDateTime$1
7016
+ createdAt: isoDateTime$2,
7017
+ updatedAt: isoDateTime$2
6894
7018
  });
6895
7019
  const UserOrganizationSchema = object({
6896
7020
  organization: OrganizationSchema,
@@ -7354,6 +7478,57 @@ const TriggerListItemSchema = object({
7354
7478
  const TriggerListResponseSchema = object({ triggers: array(TriggerListItemSchema) });
7355
7479
  object({ endpoint: string().min(1).optional() });
7356
7480
  const TriggerDetailResponseSchema = TriggerListItemSchema;
7481
+ const OrganizationMemberRoleSchema = _enum([
7482
+ "owner",
7483
+ "admin",
7484
+ "builder"
7485
+ ]);
7486
+ const OrganizationMemberStatusSchema = _enum([
7487
+ "invited",
7488
+ "active",
7489
+ "rejected",
7490
+ "suspended"
7491
+ ]);
7492
+ const InvitableOrganizationMemberRoleSchema = _enum(["admin", "builder"]);
7493
+ const isoDateTime$1 = string().datetime();
7494
+ const OrganizationMemberSchema = object({
7495
+ id: string(),
7496
+ name: string(),
7497
+ email: string().email(),
7498
+ role: OrganizationMemberRoleSchema,
7499
+ status: OrganizationMemberStatusSchema,
7500
+ avatarUrl: string().optional(),
7501
+ joinedAt: isoDateTime$1.optional(),
7502
+ lastActiveAt: isoDateTime$1.nullable().optional()
7503
+ });
7504
+ const ListOrganizationMembersResponseSchema = object({ members: array(OrganizationMemberSchema) });
7505
+ const InviteOrganizationMembersRequestSchema = object({
7506
+ emails: array(string().trim().email()).min(1),
7507
+ role: InvitableOrganizationMemberRoleSchema
7508
+ });
7509
+ const InviteOrganizationMemberResultStatusSchema = _enum([
7510
+ "sent",
7511
+ "already_member",
7512
+ "pending",
7513
+ "invalid"
7514
+ ]);
7515
+ const InviteOrganizationMembersResponseSchema = object({ results: array(object({
7516
+ email: string(),
7517
+ status: InviteOrganizationMemberResultStatusSchema,
7518
+ invitationId: string().optional()
7519
+ })) });
7520
+ const UpdateOrganizationMemberRequestSchema = object({ role: InvitableOrganizationMemberRoleSchema });
7521
+ const UpdateOrganizationMemberResponseSchema = object({ member: OrganizationMemberSchema });
7522
+ const ListOrganizationInvitationsResponseSchema = object({ invitations: array(object({
7523
+ id: string(),
7524
+ organizationName: string(),
7525
+ organizationSlug: OrganizationSlugSchema,
7526
+ invitedByName: string().optional(),
7527
+ invitedByEmail: string().email().optional(),
7528
+ role: OrganizationMemberRoleSchema
7529
+ })) });
7530
+ const AcceptOrganizationInvitationResponseSchema = object({ organization: UserOrganizationSchema });
7531
+ const DeclineOrganizationInvitationResponseSchema = object({ success: literal(true) });
7357
7532
  const ProjectArtifactStatusSchema = _enum(["pending", "ready"]);
7358
7533
  const isoDateTime = string().datetime();
7359
7534
  const ProjectArtifactSchema = object({
@@ -8008,8 +8183,8 @@ const DEFAULT_PROJECT_SETTINGS = {
8008
8183
  defaultRole: "editor",
8009
8184
  invitePermission: "admin"
8010
8185
  };
8011
- const MOCK_STORAGE_KEY$3 = "keystroke:mock-project-settings:v1";
8012
- function getBrowserLocalStorage$3() {
8186
+ const MOCK_STORAGE_KEY$4 = "keystroke:mock-project-settings:v1";
8187
+ function getBrowserLocalStorage$4() {
8013
8188
  if (typeof globalThis !== "object") return null;
8014
8189
  return globalThis.localStorage ?? null;
8015
8190
  }
@@ -8035,10 +8210,10 @@ function mergeProjectSettings(current, patch) {
8035
8210
  });
8036
8211
  }
8037
8212
  function readSettingsStore() {
8038
- const localStorage = getBrowserLocalStorage$3();
8213
+ const localStorage = getBrowserLocalStorage$4();
8039
8214
  if (!localStorage) return {};
8040
8215
  try {
8041
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$3);
8216
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY$4);
8042
8217
  if (!raw) return {};
8043
8218
  const parsed = JSON.parse(raw);
8044
8219
  if (!parsed || typeof parsed !== "object") return {};
@@ -8048,10 +8223,10 @@ function readSettingsStore() {
8048
8223
  }
8049
8224
  }
8050
8225
  function writeSettingsStore(store) {
8051
- const localStorage = getBrowserLocalStorage$3();
8226
+ const localStorage = getBrowserLocalStorage$4();
8052
8227
  if (!localStorage) return;
8053
8228
  try {
8054
- localStorage.setItem(MOCK_STORAGE_KEY$3, JSON.stringify(store));
8229
+ localStorage.setItem(MOCK_STORAGE_KEY$4, JSON.stringify(store));
8055
8230
  } catch {}
8056
8231
  }
8057
8232
  function requireProjectId(projectId) {
@@ -8085,6 +8260,71 @@ function createProjectSettingsResource() {
8085
8260
  })
8086
8261
  };
8087
8262
  }
8263
+ function createInvitationsResource(http) {
8264
+ return {
8265
+ async list() {
8266
+ try {
8267
+ const data = await http.get("/api/invitations").json();
8268
+ return ListOrganizationInvitationsResponseSchema.parse(data).invitations;
8269
+ } catch (error) {
8270
+ throw await toPlatformError(error);
8271
+ }
8272
+ },
8273
+ async accept(invitationId) {
8274
+ try {
8275
+ const data = await http.post(`/api/invitations/${encodeURIComponent(invitationId)}/accept`).json();
8276
+ return AcceptOrganizationInvitationResponseSchema.parse(data).organization;
8277
+ } catch (error) {
8278
+ throw await toPlatformError(error);
8279
+ }
8280
+ },
8281
+ async decline(invitationId) {
8282
+ try {
8283
+ const data = await http.post(`/api/invitations/${encodeURIComponent(invitationId)}/decline`).json();
8284
+ DeclineOrganizationInvitationResponseSchema.parse(data);
8285
+ } catch (error) {
8286
+ throw await toPlatformError(error);
8287
+ }
8288
+ }
8289
+ };
8290
+ }
8291
+ function createMembersResource$1(http) {
8292
+ return {
8293
+ async listOrganizationMembers() {
8294
+ try {
8295
+ const data = await http.get("/api/members").json();
8296
+ return ListOrganizationMembersResponseSchema.parse(data).members;
8297
+ } catch (error) {
8298
+ throw await toPlatformError(error);
8299
+ }
8300
+ },
8301
+ async inviteOrganizationMembers(input) {
8302
+ const body = InviteOrganizationMembersRequestSchema.parse(input);
8303
+ try {
8304
+ const data = await http.post("/api/members/invitations", { json: body }).json();
8305
+ return InviteOrganizationMembersResponseSchema.parse(data);
8306
+ } catch (error) {
8307
+ throw await toPlatformError(error);
8308
+ }
8309
+ },
8310
+ async updateOrganizationMember(userId, input) {
8311
+ const body = UpdateOrganizationMemberRequestSchema.parse(input);
8312
+ try {
8313
+ const data = await http.patch(`/api/members/${encodeURIComponent(userId)}`, { json: body }).json();
8314
+ return UpdateOrganizationMemberResponseSchema.parse(data).member;
8315
+ } catch (error) {
8316
+ throw await toPlatformError(error);
8317
+ }
8318
+ },
8319
+ async removeOrganizationMember(userId) {
8320
+ try {
8321
+ await http.delete(`/api/members/${encodeURIComponent(userId)}`);
8322
+ } catch (error) {
8323
+ throw await toPlatformError(error);
8324
+ }
8325
+ }
8326
+ };
8327
+ }
8088
8328
  /**
8089
8329
  * The supported-app catalog shown in the "Connect an app" picker. Mirrors the
8090
8330
  * curated integration list from keystroke-mockups. No connected/available flag:
@@ -9090,7 +9330,6 @@ const agentSeed = [{
9090
9330
  updatedAt: "2026-06-02T14:20:00Z",
9091
9331
  description: "Triage support requests and draft helpful replies.",
9092
9332
  sourcePath: "src/agents/support-agent.ts",
9093
- mode: "sandbox",
9094
9333
  model: "claude-4-sonnet",
9095
9334
  toolCount: 4,
9096
9335
  credentialCount: 2,
@@ -9102,7 +9341,6 @@ const agentSeed = [{
9102
9341
  updatedAt: "2026-06-01T09:15:00Z",
9103
9342
  description: "Summarize docs and pull answers from connected sources.",
9104
9343
  sourcePath: "src/agents/research-agent.ts",
9105
- mode: "worker",
9106
9344
  model: "claude-4-sonnet",
9107
9345
  toolCount: 6,
9108
9346
  credentialCount: 3,
@@ -9115,11 +9353,8 @@ const workflowSeed = [{
9115
9353
  updatedAt: "2026-06-02T11:05:00Z",
9116
9354
  description: "Collect project updates and send a daily summary.",
9117
9355
  sourcePath: "src/workflows/daily-digest.ts",
9118
- trigger: "schedule.daily",
9119
9356
  stepCount: 2,
9120
- integrationCount: 1,
9121
- lastRunAt: "2026-06-02T11:05:00Z",
9122
- runState: "Succeeded"
9357
+ lastRunAt: "2026-06-02T11:05:00Z"
9123
9358
  }, {
9124
9359
  id: "workflow-email-triage",
9125
9360
  name: "Email Triage",
@@ -9127,11 +9362,8 @@ const workflowSeed = [{
9127
9362
  updatedAt: "2026-05-31T16:40:00Z",
9128
9363
  description: "Label, prioritize, and draft replies for inbound email.",
9129
9364
  sourcePath: "src/workflows/email-triage.ts",
9130
- trigger: "gmail.new_message",
9131
9365
  stepCount: 4,
9132
- integrationCount: 2,
9133
- lastRunAt: "2026-05-31T16:40:00Z",
9134
- runState: "Running"
9366
+ lastRunAt: "2026-05-31T16:40:00Z"
9135
9367
  }];
9136
9368
  const skillSeed = [{
9137
9369
  id: "skill-attio-sync",
@@ -9139,20 +9371,14 @@ const skillSeed = [{
9139
9371
  projectId: "project_personal_repo",
9140
9372
  updatedAt: "2026-06-01T18:05:00Z",
9141
9373
  description: "Enrich company and contact records from Attio.",
9142
- sourcePath: ".agents/skills/attio-sync/SKILL.md",
9143
- category: "CRM",
9144
- availability: "Private",
9145
- lastUsedAt: "2026-06-02T08:30:00Z"
9374
+ sourcePath: ".agents/skills/attio-sync/SKILL.md"
9146
9375
  }, {
9147
9376
  id: "skill-doc-coauthor",
9148
9377
  name: "Doc Co-author",
9149
9378
  projectId: "project_personal_repo",
9150
9379
  updatedAt: "2026-05-30T10:24:00Z",
9151
9380
  description: "Collaborative writing, editing, and version tracking for docs.",
9152
- sourcePath: ".agents/skills/doc-coauthor/SKILL.md",
9153
- category: "Writing",
9154
- availability: "Private",
9155
- lastUsedAt: "2026-05-29T14:12:00Z"
9381
+ sourcePath: ".agents/skills/doc-coauthor/SKILL.md"
9156
9382
  }];
9157
9383
  const deploymentSeed = [{
9158
9384
  id: "deployment-v002",
@@ -9163,11 +9389,7 @@ const deploymentSeed = [{
9163
9389
  deployedBy: "Dallin Bentley",
9164
9390
  deployedByEmail: "dallin@keystroke.ai",
9165
9391
  createdAt: "2026-04-20T15:44:00Z",
9166
- active: true,
9167
- summary: "Added support-agent and daily digest workflow.",
9168
- changedFiles: 4,
9169
- lineAdditions: 182,
9170
- lineDeletions: 24
9392
+ active: true
9171
9393
  }, {
9172
9394
  id: "deployment-v001",
9173
9395
  projectId: "project_personal_repo",
@@ -9177,11 +9399,7 @@ const deploymentSeed = [{
9177
9399
  deployedBy: "Dallin Bentley",
9178
9400
  deployedByEmail: "dallin@keystroke.ai",
9179
9401
  createdAt: "2026-04-18T15:44:00Z",
9180
- active: false,
9181
- summary: "Initial deployed project snapshot.",
9182
- changedFiles: 2,
9183
- lineAdditions: 96,
9184
- lineDeletions: 0
9402
+ active: false
9185
9403
  }];
9186
9404
  const projectFileSeed = [
9187
9405
  {
@@ -9258,12 +9476,13 @@ export const sendSlackMessage = defineAction({
9258
9476
  `
9259
9477
  }
9260
9478
  ];
9261
- const organizationMemberSeed = [
9479
+ /** Review personas for mocked project members and API key authors (not org membership). */
9480
+ const mockPersonaSeed = [
9262
9481
  {
9263
9482
  id: "user_blake_rouse",
9264
9483
  name: "Blake Rouse",
9265
9484
  email: "blake@keystroke.ai",
9266
- role: "owner",
9485
+ avatarUrl: "/icons/avatars/blake-rouse.png",
9267
9486
  joinedAt: "2026-01-12T18:00:00Z",
9268
9487
  lastActiveAt: "2026-05-31T18:00:00Z"
9269
9488
  },
@@ -9271,7 +9490,7 @@ const organizationMemberSeed = [
9271
9490
  id: "org-member-nate",
9272
9491
  name: "Nate Wells",
9273
9492
  email: "nate@keystroke.ai",
9274
- role: "admin",
9493
+ avatarUrl: "/icons/avatars/nate-kelley.png",
9275
9494
  joinedAt: "2026-02-03T18:00:00Z",
9276
9495
  lastActiveAt: "2026-05-31T16:00:00Z"
9277
9496
  },
@@ -9279,7 +9498,7 @@ const organizationMemberSeed = [
9279
9498
  id: "org-member-dallin",
9280
9499
  name: "Dallin Bentley",
9281
9500
  email: "dallin@keystroke.ai",
9282
- role: "builder",
9501
+ avatarUrl: "/icons/avatars/dallin-bentley.png",
9283
9502
  joinedAt: "2026-03-18T18:00:00Z",
9284
9503
  lastActiveAt: "2026-05-30T16:00:00Z"
9285
9504
  },
@@ -9287,12 +9506,12 @@ const organizationMemberSeed = [
9287
9506
  id: "org-member-wells",
9288
9507
  name: "Wells Riley",
9289
9508
  email: "wells@keystroke.ai",
9290
- role: "builder",
9509
+ avatarUrl: "/icons/avatars/wells-bunker.png",
9291
9510
  joinedAt: "2026-04-09T18:00:00Z",
9292
9511
  lastActiveAt: "2026-05-20T16:00:00Z"
9293
9512
  }
9294
9513
  ];
9295
- const projectMemberSeed = organizationMemberSeed.map((member, index) => ({
9514
+ const projectMemberSeed = mockPersonaSeed.map((member, index) => ({
9296
9515
  id: `project-member-${member.id}`,
9297
9516
  projectId: "project_personal_repo",
9298
9517
  name: member.name,
@@ -9309,7 +9528,7 @@ const apiKeySeed = [
9309
9528
  name: "LOCAL_DEV_BLAKE",
9310
9529
  keyPreview: "******J7Pt",
9311
9530
  createdAt: "2026-04-20T15:44:00Z",
9312
- createdBy: organizationMemberSeed[0],
9531
+ createdBy: mockPersonaSeed[0],
9313
9532
  isCreatedByCurrentUser: true
9314
9533
  },
9315
9534
  {
@@ -9317,7 +9536,7 @@ const apiKeySeed = [
9317
9536
  name: "CI deploy",
9318
9537
  keyPreview: "******TJb7",
9319
9538
  createdAt: "2026-03-08T15:44:00Z",
9320
- createdBy: organizationMemberSeed[1],
9539
+ createdBy: mockPersonaSeed[1],
9321
9540
  isCreatedByCurrentUser: false
9322
9541
  },
9323
9542
  {
@@ -9325,7 +9544,7 @@ const apiKeySeed = [
9325
9544
  name: "partner_webhooks",
9326
9545
  keyPreview: "******9Qzc",
9327
9546
  createdAt: "2026-02-18T15:44:00Z",
9328
- createdBy: organizationMemberSeed[2],
9547
+ createdBy: mockPersonaSeed[2],
9329
9548
  isCreatedByCurrentUser: false
9330
9549
  }
9331
9550
  ];
@@ -9374,7 +9593,7 @@ function buildRecentResourceSeed() {
9374
9593
  });
9375
9594
  const skillRecents = skillSeed.map((skill, index) => {
9376
9595
  const lastModifiedAt = skill.updatedAt;
9377
- const lastOpenedAt = skill.lastUsedAt ?? hoursBefore(lastModifiedAt, index * 3 + 1);
9596
+ const lastOpenedAt = hoursBefore(lastModifiedAt, index * 3 + 1);
9378
9597
  return {
9379
9598
  id: `recent-skill-${skill.id}`,
9380
9599
  resourceKind: "skill",
@@ -9554,13 +9773,9 @@ function createProjectFilesResource() {
9554
9773
  projectId
9555
9774
  }))) };
9556
9775
  }
9557
- function createMembersResource() {
9776
+ function createMembersResource(http) {
9558
9777
  return {
9559
- listOrganizationMembers: mock({
9560
- domain: "members",
9561
- method: "listOrganizationMembers",
9562
- plannedEndpoint: "GET /api/members"
9563
- }, async () => organizationMemberSeed),
9778
+ ...createMembersResource$1(http),
9564
9779
  listForProject: mock({
9565
9780
  domain: "members",
9566
9781
  method: "listForProject",
@@ -9590,7 +9805,7 @@ function createApiKeysResource() {
9590
9805
  name: input.name,
9591
9806
  keyPreview,
9592
9807
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
9593
- createdBy: organizationMemberSeed[0],
9808
+ createdBy: mockPersonaSeed[0],
9594
9809
  isCreatedByCurrentUser: true
9595
9810
  };
9596
9811
  apiKeyRecords = [created, ...apiKeyRecords];
@@ -9616,6 +9831,57 @@ function createRecentsResource() {
9616
9831
  }, async () => buildRecentResourceSeed()) };
9617
9832
  }
9618
9833
  const historyProjectNameById = { project_personal_repo: "Blake's Project" };
9834
+ const MOCK_ACTOR = {
9835
+ userId: "user_blake",
9836
+ name: "Blake Rouse",
9837
+ avatarUrl: null
9838
+ };
9839
+ function buildCompletedUsage(durationMs) {
9840
+ return {
9841
+ runDurationMs: durationMs,
9842
+ lineItems: [
9843
+ {
9844
+ id: "claude-opus",
9845
+ label: "Claude Opus 4.8",
9846
+ amountUsd: .413
9847
+ },
9848
+ {
9849
+ id: "gemini-flash",
9850
+ label: "Gemini Flash 3.5",
9851
+ amountUsd: .001
9852
+ },
9853
+ {
9854
+ id: "daytona",
9855
+ label: "Daytona Sandbox",
9856
+ amountUsd: .188
9857
+ }
9858
+ ],
9859
+ totalExcludingDurationUsd: .603
9860
+ };
9861
+ }
9862
+ function buildRunningUsage() {
9863
+ return {
9864
+ runDurationMs: null,
9865
+ lineItems: [],
9866
+ totalExcludingDurationUsd: null
9867
+ };
9868
+ }
9869
+ function buildFailedUsage(durationMs) {
9870
+ if (durationMs == null) return {
9871
+ runDurationMs: null,
9872
+ lineItems: [],
9873
+ totalExcludingDurationUsd: null
9874
+ };
9875
+ return {
9876
+ runDurationMs: durationMs,
9877
+ lineItems: [{
9878
+ id: "claude-opus",
9879
+ label: "Claude Opus 4.8",
9880
+ amountUsd: .021
9881
+ }],
9882
+ totalExcludingDurationUsd: .021
9883
+ };
9884
+ }
9619
9885
  function workflowKeyFromId(workflowId) {
9620
9886
  const row = workflowSeed.find((workflow) => workflow.id === workflowId);
9621
9887
  if (!row?.sourcePath) return workflowId;
@@ -9637,11 +9903,17 @@ const historyRunSeed = [
9637
9903
  resourceId: "agent-support",
9638
9904
  resourceName: "Support Agent",
9639
9905
  status: "completed",
9906
+ triggeredAt: "2026-04-20T15:44:00Z",
9907
+ timeInQueueMs: 85,
9640
9908
  startedAt: "2026-04-20T15:44:00Z",
9641
9909
  finishedAt: "2026-04-20T15:44:42Z",
9642
9910
  durationMs: 42e3,
9643
9911
  triggerLabel: "Gateway",
9644
9912
  triggerRaw: "gateway",
9913
+ ranAs: MOCK_ACTOR,
9914
+ modelsUsed: ["Claude Opus 4.8", "Gemini Flash 3.5"],
9915
+ otherServicesUsed: ["Slack", "Daytona Sandbox"],
9916
+ totalCostUsd: .603,
9645
9917
  messageCount: 8
9646
9918
  },
9647
9919
  {
@@ -9654,11 +9926,17 @@ const historyRunSeed = [
9654
9926
  resourceId: "workflow-daily-digest",
9655
9927
  resourceName: "Daily Digest",
9656
9928
  status: "running",
9929
+ triggeredAt: "2026-04-20T15:12:00Z",
9930
+ timeInQueueMs: null,
9657
9931
  startedAt: "2026-04-20T15:12:00Z",
9658
9932
  finishedAt: null,
9659
9933
  durationMs: null,
9660
9934
  triggerLabel: "Cron",
9661
9935
  triggerRaw: "cron",
9936
+ ranAs: MOCK_ACTOR,
9937
+ modelsUsed: [],
9938
+ otherServicesUsed: [],
9939
+ totalCostUsd: null,
9662
9940
  stepCount: 1
9663
9941
  },
9664
9942
  {
@@ -9671,11 +9949,17 @@ const historyRunSeed = [
9671
9949
  resourceId: "agent-support",
9672
9950
  resourceName: "Support Agent",
9673
9951
  status: "failed",
9952
+ triggeredAt: "2026-04-19T18:22:00Z",
9953
+ timeInQueueMs: 45,
9674
9954
  startedAt: "2026-04-19T18:22:00Z",
9675
9955
  finishedAt: "2026-04-19T18:22:12Z",
9676
9956
  durationMs: 12e3,
9677
9957
  triggerLabel: "Gateway",
9678
9958
  triggerRaw: "gateway",
9959
+ ranAs: MOCK_ACTOR,
9960
+ modelsUsed: ["Claude Opus 4.8"],
9961
+ otherServicesUsed: ["Slack"],
9962
+ totalCostUsd: .021,
9679
9963
  messageCount: 2
9680
9964
  },
9681
9965
  {
@@ -9688,11 +9972,17 @@ const historyRunSeed = [
9688
9972
  resourceId: "workflow-email-triage",
9689
9973
  resourceName: "Email Triage",
9690
9974
  status: "failed",
9975
+ triggeredAt: "2026-05-31T16:40:05Z",
9976
+ timeInQueueMs: 120,
9691
9977
  startedAt: "2026-05-31T16:40:05Z",
9692
9978
  finishedAt: "2026-05-31T16:40:18Z",
9693
9979
  durationMs: 13e3,
9694
9980
  triggerLabel: "Webhook",
9695
9981
  triggerRaw: "webhook",
9982
+ ranAs: MOCK_ACTOR,
9983
+ modelsUsed: ["Claude Opus 4.8"],
9984
+ otherServicesUsed: ["Gmail"],
9985
+ totalCostUsd: .021,
9696
9986
  stepCount: 2
9697
9987
  },
9698
9988
  {
@@ -9705,15 +9995,59 @@ const historyRunSeed = [
9705
9995
  resourceId: "agent-research",
9706
9996
  resourceName: "Research Agent",
9707
9997
  status: "completed",
9998
+ triggeredAt: "2026-06-01T09:15:00Z",
9999
+ timeInQueueMs: 210,
9708
10000
  startedAt: "2026-06-01T09:15:00Z",
9709
10001
  finishedAt: "2026-06-01T09:16:24Z",
9710
10002
  durationMs: 84e3,
9711
10003
  triggerLabel: "API",
9712
10004
  triggerRaw: "api",
10005
+ ranAs: MOCK_ACTOR,
10006
+ modelsUsed: ["Claude Opus 4.8"],
10007
+ otherServicesUsed: ["Exa"],
10008
+ totalCostUsd: .603,
9713
10009
  messageCount: 12
9714
10010
  }
9715
10011
  ];
10012
+ const historyRunById = Object.fromEntries(historyRunSeed.map((run) => [run.id, run]));
10013
+ /** Resolve a seed run by id so fixtures stay consistent if the seed is reordered. */
10014
+ function runById(id) {
10015
+ const run = historyRunById[id];
10016
+ if (!run) throw new Error(`Unknown history run: ${id}`);
10017
+ return run;
10018
+ }
10019
+ let historyRuns = historyRunSeed.map((run) => ({ ...run }));
10020
+ const historyRunStatusOverrides = /* @__PURE__ */ new Map();
10021
+ function listHistoryRuns() {
10022
+ return historyRuns;
10023
+ }
10024
+ /**
10025
+ * Cancel a running/queued run. Terminal runs are returned unchanged. Updates the
10026
+ * list row and records an override so {@link getHistoryRunDetail} stays in sync.
10027
+ */
10028
+ function cancelHistoryRun(runId) {
10029
+ const run = historyRuns.find((entry) => entry.id === runId);
10030
+ if (!run) return null;
10031
+ if (run.status !== "running" && run.status !== "pending") return run;
10032
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
10033
+ const durationMs = run.startedAt ? Math.max(0, new Date(finishedAt).getTime() - new Date(run.startedAt).getTime()) : run.durationMs;
10034
+ const canceled = {
10035
+ ...run,
10036
+ status: "canceled",
10037
+ finishedAt,
10038
+ durationMs
10039
+ };
10040
+ historyRuns = historyRuns.map((entry) => entry.id === runId ? canceled : entry);
10041
+ historyRunStatusOverrides.set(runId, {
10042
+ status: "canceled",
10043
+ finishedAt
10044
+ });
10045
+ return canceled;
10046
+ }
9716
10047
  function buildSupportAgentTrace(runId, failed) {
10048
+ const run = runById(runId);
10049
+ const startedAt = run.startedAt;
10050
+ const finishedAt = run.finishedAt ?? run.startedAt;
9717
10051
  const sessionSpanId = `span-session-${runId}`;
9718
10052
  return {
9719
10053
  traceId: runId,
@@ -9721,13 +10055,17 @@ function buildSupportAgentTrace(runId, failed) {
9721
10055
  triggerType: "gateway",
9722
10056
  triggerRunId: `trigger-${runId}`,
9723
10057
  agentKey: "support-agent",
10058
+ attachmentId: "attach-slack-incoming",
9724
10059
  attachmentKey: "slack-incoming",
10060
+ route: "/agents/support-agent",
9725
10061
  sourcePath: "src/triggers/slack-message.ts"
9726
10062
  },
9727
10063
  gateway: {
10064
+ gatewayAttachmentId: "attach-slack-incoming",
9728
10065
  gatewayAttachmentKey: "slack-incoming",
9729
10066
  threadId: "C01234567",
9730
- channelId: "support-escalations"
10067
+ channelId: "support-escalations",
10068
+ mode: "thread"
9731
10069
  },
9732
10070
  spans: [{
9733
10071
  id: sessionSpanId,
@@ -9737,8 +10075,8 @@ function buildSupportAgentTrace(runId, failed) {
9737
10075
  refId: runId,
9738
10076
  name: "Support Agent",
9739
10077
  status: failed ? "error" : "ok",
9740
- startedAt: "2026-04-20T15:44:00Z",
9741
- finishedAt: failed ? "2026-04-19T18:22:12Z" : "2026-04-20T15:44:42Z",
10078
+ startedAt,
10079
+ finishedAt,
9742
10080
  metadata: { messageCount: failed ? 2 : 8 },
9743
10081
  error: failed ? { message: "Credential expired" } : null
9744
10082
  }, {
@@ -9749,8 +10087,8 @@ function buildSupportAgentTrace(runId, failed) {
9749
10087
  refId: `tool-${runId}`,
9750
10088
  name: "post_slack_reply",
9751
10089
  status: failed ? "error" : "ok",
9752
- startedAt: "2026-04-20T15:44:30Z",
9753
- finishedAt: failed ? "2026-04-19T18:22:11Z" : "2026-04-20T15:44:40Z",
10090
+ startedAt,
10091
+ finishedAt,
9754
10092
  metadata: null,
9755
10093
  error: failed ? { message: "oauth_token_expired" } : null
9756
10094
  }],
@@ -9763,7 +10101,7 @@ function buildSupportAgentTrace(runId, failed) {
9763
10101
  message: failed ? "Received Slack message" : "Session started from gateway thread",
9764
10102
  data: null,
9765
10103
  source: "system",
9766
- createdAt: "2026-04-20T15:44:01Z"
10104
+ createdAt: startedAt
9767
10105
  }, {
9768
10106
  id: `log-${runId}-2`,
9769
10107
  traceId: runId,
@@ -9773,7 +10111,7 @@ function buildSupportAgentTrace(runId, failed) {
9773
10111
  message: failed ? "Credential expired before response could be posted." : "Drafted three support replies.",
9774
10112
  data: null,
9775
10113
  source: "system",
9776
- createdAt: failed ? "2026-04-19T18:22:12Z" : "2026-04-20T15:44:42Z"
10114
+ createdAt: finishedAt
9777
10115
  }]
9778
10116
  };
9779
10117
  }
@@ -9784,7 +10122,9 @@ function buildDailyDigestTrace() {
9784
10122
  triggerType: "cron",
9785
10123
  triggerRunId: "trigger-daily-digest-001",
9786
10124
  workflowKey: "daily-digest",
10125
+ attachmentId: "attach-schedule-daily",
9787
10126
  attachmentKey: "schedule-daily",
10127
+ route: "/workflows/daily-digest",
9788
10128
  sourcePath: "src/triggers/daily-digest.ts"
9789
10129
  },
9790
10130
  gateway: null,
@@ -9879,7 +10219,9 @@ function buildEmailTriageDetail() {
9879
10219
  triggerType: "webhook",
9880
10220
  triggerRunId: "trigger-email-002",
9881
10221
  workflowKey: "email-triage",
9882
- attachmentKey: "gmail-new-message"
10222
+ attachmentId: "attach-gmail-new-message",
10223
+ attachmentKey: "gmail-new-message",
10224
+ route: "/workflows/email-triage"
9883
10225
  },
9884
10226
  gateway: null,
9885
10227
  spans: [{
@@ -9906,7 +10248,9 @@ function buildEmailTriageDetail() {
9906
10248
  source: "system",
9907
10249
  createdAt: "2026-05-31T16:40:18Z"
9908
10250
  }]
9909
- }
10251
+ },
10252
+ ranAs: MOCK_ACTOR,
10253
+ usage: buildFailedUsage(13e3)
9910
10254
  };
9911
10255
  }
9912
10256
  const historyDetailById = {
@@ -9933,7 +10277,9 @@ const historyDetailById = {
9933
10277
  role: "assistant",
9934
10278
  content: "Drafted reply with prorated credit explanation."
9935
10279
  }],
9936
- trace: buildSupportAgentTrace("run-support-agent-001", false)
10280
+ trace: buildSupportAgentTrace("run-support-agent-001", false),
10281
+ ranAs: MOCK_ACTOR,
10282
+ usage: buildCompletedUsage(42e3)
9937
10283
  },
9938
10284
  "run-support-agent-000": {
9939
10285
  kind: "agent",
@@ -9955,7 +10301,9 @@ const historyDetailById = {
9955
10301
  role: "user",
9956
10302
  content: "Urgent refund request in #support."
9957
10303
  }],
9958
- trace: buildSupportAgentTrace("run-support-agent-000", true)
10304
+ trace: buildSupportAgentTrace("run-support-agent-000", true),
10305
+ ranAs: MOCK_ACTOR,
10306
+ usage: buildFailedUsage(12e3)
9959
10307
  },
9960
10308
  "run-daily-digest-001": {
9961
10309
  kind: "workflow",
@@ -9985,7 +10333,9 @@ const historyDetailById = {
9985
10333
  output: { projects: 3 },
9986
10334
  completedAt: "2026-04-20T15:12:45Z"
9987
10335
  }],
9988
- trace: buildDailyDigestTrace()
10336
+ trace: buildDailyDigestTrace(),
10337
+ ranAs: MOCK_ACTOR,
10338
+ usage: buildRunningUsage()
9989
10339
  },
9990
10340
  "run-email-triage-002": buildEmailTriageDetail(),
9991
10341
  "run-research-agent-003": {
@@ -10013,7 +10363,8 @@ const historyDetailById = {
10013
10363
  trigger: {
10014
10364
  triggerType: "api",
10015
10365
  triggerRunId: "trigger-research-003",
10016
- agentKey: "research-agent"
10366
+ agentKey: "research-agent",
10367
+ route: "/agents/research-agent"
10017
10368
  },
10018
10369
  gateway: null,
10019
10370
  spans: [{
@@ -10040,11 +10391,34 @@ const historyDetailById = {
10040
10391
  source: "system",
10041
10392
  createdAt: "2026-06-01T09:16:24Z"
10042
10393
  }]
10043
- }
10394
+ },
10395
+ ranAs: MOCK_ACTOR,
10396
+ usage: buildCompletedUsage(84e3)
10044
10397
  }
10045
10398
  };
10399
+ function applyRunStatusOverride(detail, override) {
10400
+ if (detail.kind === "workflow") return {
10401
+ ...detail,
10402
+ run: {
10403
+ ...detail.run,
10404
+ status: override.status,
10405
+ finishedAt: override.finishedAt
10406
+ }
10407
+ };
10408
+ return {
10409
+ ...detail,
10410
+ session: {
10411
+ ...detail.session,
10412
+ status: override.status,
10413
+ updatedAt: override.finishedAt ?? detail.session.updatedAt
10414
+ }
10415
+ };
10416
+ }
10046
10417
  function getHistoryRunDetail(runId) {
10047
- return historyDetailById[runId] ?? null;
10418
+ const detail = historyDetailById[runId];
10419
+ if (!detail) return null;
10420
+ const override = historyRunStatusOverrides.get(runId);
10421
+ return override ? applyRunStatusOverride(detail, override) : detail;
10048
10422
  }
10049
10423
  function createHistoryResource() {
10050
10424
  return {
@@ -10053,16 +10427,22 @@ function createHistoryResource() {
10053
10427
  domain: "history",
10054
10428
  method: "list",
10055
10429
  plannedEndpoint: "GET /api/orgs/:orgSlug/history"
10056
- }, async () => [...historyRunSeed].sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime())),
10430
+ }, async () => [...listHistoryRuns()].sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime())),
10057
10431
  get: mock({
10058
10432
  domain: "history",
10059
10433
  method: "get",
10060
10434
  plannedEndpoint: "GET /api/orgs/:orgSlug/history/:runId"
10061
- }, async (runId) => getHistoryRunDetail(runId))
10435
+ }, async (runId) => getHistoryRunDetail(runId)),
10436
+ /** Cancel a running/queued run. Returns the updated run (or null if unknown). */
10437
+ cancel: mock({
10438
+ domain: "history",
10439
+ method: "cancel",
10440
+ plannedEndpoint: "POST /api/orgs/:orgSlug/history/:runId/cancel"
10441
+ }, async (runId) => cancelHistoryRun(runId))
10062
10442
  };
10063
10443
  }
10064
- const MOCK_STORAGE_KEY$2 = "keystroke:mock-organization-sidebar-branding:v1";
10065
- function getBrowserLocalStorage$2() {
10444
+ const MOCK_STORAGE_KEY$3 = "keystroke:mock-organization-sidebar-branding:v1";
10445
+ function getBrowserLocalStorage$3() {
10066
10446
  if (typeof globalThis !== "object") return null;
10067
10447
  return globalThis.localStorage ?? null;
10068
10448
  }
@@ -10105,10 +10485,10 @@ function mergeOrganizationSidebarBranding(current, patch) {
10105
10485
  });
10106
10486
  }
10107
10487
  function readBrandingStore() {
10108
- const localStorage = getBrowserLocalStorage$2();
10488
+ const localStorage = getBrowserLocalStorage$3();
10109
10489
  if (!localStorage) return {};
10110
10490
  try {
10111
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$2);
10491
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY$3);
10112
10492
  if (!raw) return {};
10113
10493
  const parsed = JSON.parse(raw);
10114
10494
  if (!parsed || typeof parsed !== "object") return {};
@@ -10118,10 +10498,10 @@ function readBrandingStore() {
10118
10498
  }
10119
10499
  }
10120
10500
  function writeBrandingStore(store) {
10121
- const localStorage = getBrowserLocalStorage$2();
10501
+ const localStorage = getBrowserLocalStorage$3();
10122
10502
  if (!localStorage) return;
10123
10503
  try {
10124
- localStorage.setItem(MOCK_STORAGE_KEY$2, JSON.stringify(store));
10504
+ localStorage.setItem(MOCK_STORAGE_KEY$3, JSON.stringify(store));
10125
10505
  } catch {}
10126
10506
  }
10127
10507
  function resolveOrganizationId(getActiveOrganizationId) {
@@ -10155,8 +10535,8 @@ function createOrganizationSidebarBrandingResource(options) {
10155
10535
  })
10156
10536
  };
10157
10537
  }
10158
- const MOCK_STORAGE_KEY$1 = "keystroke:mock-user-preferences:v1";
10159
- function getBrowserLocalStorage$1() {
10538
+ const MOCK_STORAGE_KEY$2 = "keystroke:mock-user-preferences:v1";
10539
+ function getBrowserLocalStorage$2() {
10160
10540
  if (typeof globalThis !== "object") return null;
10161
10541
  return globalThis.localStorage ?? null;
10162
10542
  }
@@ -10264,10 +10644,10 @@ function mergeUserPreferences(current, patch) {
10264
10644
  });
10265
10645
  }
10266
10646
  function readPreferencesStore() {
10267
- const localStorage = getBrowserLocalStorage$1();
10647
+ const localStorage = getBrowserLocalStorage$2();
10268
10648
  if (!localStorage) return {};
10269
10649
  try {
10270
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$1);
10650
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY$2);
10271
10651
  if (!raw) return {};
10272
10652
  const parsed = JSON.parse(raw);
10273
10653
  if (!parsed || typeof parsed !== "object") return {};
@@ -10278,10 +10658,10 @@ function readPreferencesStore() {
10278
10658
  }
10279
10659
  }
10280
10660
  function writePreferencesStore(store) {
10281
- const localStorage = getBrowserLocalStorage$1();
10661
+ const localStorage = getBrowserLocalStorage$2();
10282
10662
  if (!localStorage) return;
10283
10663
  try {
10284
- localStorage.setItem(MOCK_STORAGE_KEY$1, JSON.stringify(store));
10664
+ localStorage.setItem(MOCK_STORAGE_KEY$2, JSON.stringify(store));
10285
10665
  } catch {}
10286
10666
  }
10287
10667
  function resolveUserId$1(getCurrentUserId) {
@@ -10316,8 +10696,8 @@ function createUserPreferencesResource(options) {
10316
10696
  };
10317
10697
  }
10318
10698
  const DEFAULT_USER_AVATAR = { dataUrl: null };
10319
- const MOCK_STORAGE_KEY = "keystroke:mock-user-avatar:v1";
10320
- function getBrowserLocalStorage() {
10699
+ const MOCK_STORAGE_KEY$1 = "keystroke:mock-user-avatar:v1";
10700
+ function getBrowserLocalStorage$1() {
10321
10701
  if (typeof globalThis !== "object") return null;
10322
10702
  return globalThis.localStorage ?? null;
10323
10703
  }
@@ -10327,10 +10707,10 @@ function normalizeUserAvatar(value) {
10327
10707
  return { dataUrl: typeof dataUrl === "string" && dataUrl.length > 0 ? dataUrl : null };
10328
10708
  }
10329
10709
  function readAvatarStore() {
10330
- const localStorage = getBrowserLocalStorage();
10710
+ const localStorage = getBrowserLocalStorage$1();
10331
10711
  if (!localStorage) return {};
10332
10712
  try {
10333
- const raw = localStorage.getItem(MOCK_STORAGE_KEY);
10713
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY$1);
10334
10714
  if (!raw) return {};
10335
10715
  const parsed = JSON.parse(raw);
10336
10716
  if (!parsed || typeof parsed !== "object") return {};
@@ -10340,10 +10720,10 @@ function readAvatarStore() {
10340
10720
  }
10341
10721
  }
10342
10722
  function writeAvatarStore(store) {
10343
- const localStorage = getBrowserLocalStorage();
10723
+ const localStorage = getBrowserLocalStorage$1();
10344
10724
  if (!localStorage) return;
10345
10725
  try {
10346
- localStorage.setItem(MOCK_STORAGE_KEY, JSON.stringify(store));
10726
+ localStorage.setItem(MOCK_STORAGE_KEY$1, JSON.stringify(store));
10347
10727
  } catch {}
10348
10728
  }
10349
10729
  function resolveUserId(getCurrentUserId) {
@@ -10377,6 +10757,558 @@ function createUserAvatarResource(options) {
10377
10757
  })
10378
10758
  };
10379
10759
  }
10760
+ const CHANNEL_PLATFORMS = [
10761
+ {
10762
+ key: "slack",
10763
+ name: "Slack",
10764
+ appLogoId: "slack",
10765
+ fallbackDomain: "slack.com",
10766
+ description: "Connect a Slack workspace so this agent can respond in channels, threads, and DMs.",
10767
+ tagline: "Respond in channels, threads, and DMs.",
10768
+ authKind: "oauth",
10769
+ credentialFields: [],
10770
+ capabilities: {
10771
+ mentions: true,
10772
+ reactions: "full",
10773
+ cards: "full",
10774
+ modals: true,
10775
+ streaming: "native",
10776
+ dms: true
10777
+ },
10778
+ supportedModes: [
10779
+ "mention",
10780
+ "all",
10781
+ "dm"
10782
+ ],
10783
+ resourceNoun: {
10784
+ singular: "channel",
10785
+ plural: "channels"
10786
+ },
10787
+ webhookPathHint: "/gateways/slack",
10788
+ supportsChannelDirectory: true,
10789
+ docsUrl: "https://chat-sdk.dev/adapters/official/slack"
10790
+ },
10791
+ {
10792
+ key: "discord",
10793
+ name: "Discord",
10794
+ appLogoId: "discord",
10795
+ fallbackDomain: "discord.com",
10796
+ description: "Connect a Discord application so this agent can respond in servers and channels.",
10797
+ tagline: "Respond in servers and channels.",
10798
+ authKind: "credentials",
10799
+ credentialFields: [
10800
+ {
10801
+ key: "botToken",
10802
+ label: "Bot token",
10803
+ placeholder: "Bot token from the Discord developer portal",
10804
+ helpText: "Bot → Reset Token. Shown only once.",
10805
+ type: "password",
10806
+ required: true
10807
+ },
10808
+ {
10809
+ key: "applicationId",
10810
+ label: "Application ID",
10811
+ placeholder: "Application ID",
10812
+ type: "text",
10813
+ required: true
10814
+ },
10815
+ {
10816
+ key: "publicKey",
10817
+ label: "Public key",
10818
+ placeholder: "Public key",
10819
+ helpText: "General Information → Public Key, used to verify interactions.",
10820
+ type: "text",
10821
+ required: true
10822
+ }
10823
+ ],
10824
+ capabilities: {
10825
+ mentions: true,
10826
+ reactions: "full",
10827
+ cards: "full",
10828
+ modals: false,
10829
+ streaming: "post-edit",
10830
+ dms: true
10831
+ },
10832
+ supportedModes: [
10833
+ "mention",
10834
+ "all",
10835
+ "dm"
10836
+ ],
10837
+ resourceNoun: {
10838
+ singular: "channel",
10839
+ plural: "channels"
10840
+ },
10841
+ webhookPathHint: "/gateways/discord",
10842
+ supportsChannelDirectory: true,
10843
+ docsUrl: "https://chat-sdk.dev/adapters/official/discord"
10844
+ },
10845
+ {
10846
+ key: "telegram",
10847
+ name: "Telegram",
10848
+ appLogoId: "telegram",
10849
+ fallbackDomain: "telegram.org",
10850
+ description: "Connect a Telegram bot so this agent can respond in chats and groups.",
10851
+ tagline: "Respond in chats and groups.",
10852
+ authKind: "bot-token",
10853
+ credentialFields: [{
10854
+ key: "botToken",
10855
+ label: "Bot token",
10856
+ placeholder: "123456:ABC-DEF…",
10857
+ helpText: "Create a bot with @BotFather and paste its token.",
10858
+ type: "password",
10859
+ required: true
10860
+ }, {
10861
+ key: "botUsername",
10862
+ label: "Bot username",
10863
+ placeholder: "my_agent_bot",
10864
+ type: "text",
10865
+ required: false,
10866
+ prefix: "@"
10867
+ }],
10868
+ capabilities: {
10869
+ mentions: true,
10870
+ reactions: "full",
10871
+ cards: "partial",
10872
+ modals: false,
10873
+ streaming: "drafts",
10874
+ dms: true
10875
+ },
10876
+ supportedModes: [
10877
+ "mention",
10878
+ "all",
10879
+ "dm"
10880
+ ],
10881
+ resourceNoun: {
10882
+ singular: "chat",
10883
+ plural: "chats"
10884
+ },
10885
+ webhookPathHint: "/gateways/telegram",
10886
+ supportsChannelDirectory: false,
10887
+ docsUrl: "https://chat-sdk.dev/adapters/official/telegram"
10888
+ },
10889
+ {
10890
+ key: "microsoft-teams",
10891
+ name: "Microsoft Teams",
10892
+ appLogoId: "microsoft-teams",
10893
+ fallbackDomain: "teams.microsoft.com",
10894
+ description: "Connect a Microsoft Teams app so this agent can respond in channels and chats.",
10895
+ tagline: "Respond in channels and chats.",
10896
+ authKind: "credentials",
10897
+ credentialFields: [
10898
+ {
10899
+ key: "appId",
10900
+ label: "App ID",
10901
+ placeholder: "Azure AD application (client) ID",
10902
+ type: "text",
10903
+ required: true
10904
+ },
10905
+ {
10906
+ key: "appPassword",
10907
+ label: "App password",
10908
+ placeholder: "Client secret",
10909
+ type: "password",
10910
+ required: true
10911
+ },
10912
+ {
10913
+ key: "tenantId",
10914
+ label: "Tenant ID",
10915
+ placeholder: "Azure AD tenant ID",
10916
+ type: "text",
10917
+ required: true
10918
+ }
10919
+ ],
10920
+ capabilities: {
10921
+ mentions: true,
10922
+ reactions: "read-only",
10923
+ cards: "full",
10924
+ modals: true,
10925
+ streaming: "buffered",
10926
+ dms: true
10927
+ },
10928
+ supportedModes: [
10929
+ "mention",
10930
+ "all",
10931
+ "dm"
10932
+ ],
10933
+ resourceNoun: {
10934
+ singular: "channel",
10935
+ plural: "channels"
10936
+ },
10937
+ webhookPathHint: "/gateways/teams",
10938
+ supportsChannelDirectory: true,
10939
+ docsUrl: "https://chat-sdk.dev/adapters/official/teams"
10940
+ },
10941
+ {
10942
+ key: "google-chat",
10943
+ name: "Google Chat",
10944
+ appLogoId: "google-chat",
10945
+ fallbackDomain: "chat.google.com",
10946
+ description: "Connect a Google Chat app so this agent can respond in spaces and direct messages.",
10947
+ tagline: "Respond in spaces and DMs.",
10948
+ authKind: "credentials",
10949
+ credentialFields: [{
10950
+ key: "serviceAccountJson",
10951
+ label: "Service account JSON",
10952
+ placeholder: "Paste the service account key JSON",
10953
+ helpText: "IAM → Service Accounts → Keys → Add key → JSON.",
10954
+ type: "textarea",
10955
+ required: true
10956
+ }, {
10957
+ key: "projectNumber",
10958
+ label: "GCP project number",
10959
+ placeholder: "Project number used to verify webhooks",
10960
+ type: "text",
10961
+ required: true
10962
+ }],
10963
+ capabilities: {
10964
+ mentions: true,
10965
+ reactions: "full",
10966
+ cards: "full",
10967
+ modals: false,
10968
+ streaming: "post-edit",
10969
+ dms: true
10970
+ },
10971
+ supportedModes: [
10972
+ "mention",
10973
+ "all",
10974
+ "dm"
10975
+ ],
10976
+ resourceNoun: {
10977
+ singular: "space",
10978
+ plural: "spaces"
10979
+ },
10980
+ webhookPathHint: "/gateways/gchat",
10981
+ supportsChannelDirectory: true,
10982
+ docsUrl: "https://chat-sdk.dev/adapters/official/google-chat"
10983
+ }
10984
+ ];
10985
+ function getChannelPlatform(key) {
10986
+ return CHANNEL_PLATFORMS.find((platform) => platform.key === key);
10987
+ }
10988
+ const CHANNEL_DIRECTORY = {
10989
+ slack: [
10990
+ {
10991
+ id: "C0SUPPORT",
10992
+ name: "support",
10993
+ kind: "public",
10994
+ memberCount: 48
10995
+ },
10996
+ {
10997
+ id: "C0GENERAL",
10998
+ name: "general",
10999
+ kind: "public",
11000
+ memberCount: 132
11001
+ },
11002
+ {
11003
+ id: "C0ENG",
11004
+ name: "engineering",
11005
+ kind: "public",
11006
+ memberCount: 27
11007
+ },
11008
+ {
11009
+ id: "C0INCIDENTS",
11010
+ name: "incidents",
11011
+ kind: "private",
11012
+ memberCount: 12
11013
+ },
11014
+ {
11015
+ id: "C0RANDOM",
11016
+ name: "random",
11017
+ kind: "public",
11018
+ memberCount: 118
11019
+ },
11020
+ {
11021
+ id: "C0ARCHIVE",
11022
+ name: "launch-2025",
11023
+ kind: "public",
11024
+ memberCount: 9,
11025
+ isArchived: true
11026
+ }
11027
+ ],
11028
+ discord: [
11029
+ {
11030
+ id: "d-general",
11031
+ name: "general",
11032
+ kind: "public",
11033
+ memberCount: 540
11034
+ },
11035
+ {
11036
+ id: "d-help",
11037
+ name: "help",
11038
+ kind: "public",
11039
+ memberCount: 312
11040
+ },
11041
+ {
11042
+ id: "d-dev",
11043
+ name: "dev",
11044
+ kind: "public",
11045
+ memberCount: 76
11046
+ },
11047
+ {
11048
+ id: "d-staff",
11049
+ name: "staff",
11050
+ kind: "private",
11051
+ memberCount: 8
11052
+ }
11053
+ ],
11054
+ telegram: [],
11055
+ "microsoft-teams": [
11056
+ {
11057
+ id: "t-general",
11058
+ name: "General",
11059
+ kind: "public",
11060
+ memberCount: 64
11061
+ },
11062
+ {
11063
+ id: "t-support",
11064
+ name: "Customer Support",
11065
+ kind: "public",
11066
+ memberCount: 22
11067
+ },
11068
+ {
11069
+ id: "t-leads",
11070
+ name: "Leadership",
11071
+ kind: "private",
11072
+ memberCount: 6
11073
+ }
11074
+ ],
11075
+ "google-chat": [
11076
+ {
11077
+ id: "spaces/AAA-support",
11078
+ name: "Support",
11079
+ kind: "space",
11080
+ memberCount: 31
11081
+ },
11082
+ {
11083
+ id: "spaces/AAA-eng",
11084
+ name: "Engineering",
11085
+ kind: "space",
11086
+ memberCount: 44
11087
+ },
11088
+ {
11089
+ id: "spaces/AAA-ops",
11090
+ name: "Ops On-call",
11091
+ kind: "space",
11092
+ memberCount: 10
11093
+ }
11094
+ ]
11095
+ };
11096
+ const MOCK_STORAGE_KEY = "keystroke:mock-channels:v1";
11097
+ function getBrowserLocalStorage() {
11098
+ if (typeof globalThis !== "object") return null;
11099
+ return globalThis.localStorage ?? null;
11100
+ }
11101
+ /** A connected Slack workspace with two bindings, so the panel is reviewable. */
11102
+ function seedStore() {
11103
+ return { "agent-support": [{
11104
+ id: "chan-conn-slack-support",
11105
+ platform: "slack",
11106
+ agentId: "agent-support",
11107
+ accountLabel: "Keystroke HQ",
11108
+ accountId: "T0KEYSTROKE",
11109
+ connectedAt: "2026-05-28T15:30:00Z",
11110
+ bindings: [{
11111
+ id: "chan-bind-support",
11112
+ channelId: "C0SUPPORT",
11113
+ channelName: "support",
11114
+ channelKind: "public",
11115
+ mode: "all",
11116
+ subscribeOnMention: true,
11117
+ createdAt: "2026-05-28T15:31:00Z",
11118
+ updatedAt: "2026-05-28T15:31:00Z"
11119
+ }, {
11120
+ id: "chan-bind-incidents",
11121
+ channelId: "C0INCIDENTS",
11122
+ channelName: "incidents",
11123
+ channelKind: "private",
11124
+ mode: "mention",
11125
+ subscribeOnMention: true,
11126
+ createdAt: "2026-05-29T09:05:00Z",
11127
+ updatedAt: "2026-05-29T09:05:00Z"
11128
+ }]
11129
+ }] };
11130
+ }
11131
+ function readStore() {
11132
+ const localStorage = getBrowserLocalStorage();
11133
+ if (!localStorage) return seedStore();
11134
+ try {
11135
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY);
11136
+ if (!raw) {
11137
+ const seeded = seedStore();
11138
+ localStorage.setItem(MOCK_STORAGE_KEY, JSON.stringify(seeded));
11139
+ return seeded;
11140
+ }
11141
+ const parsed = JSON.parse(raw);
11142
+ if (!parsed || typeof parsed !== "object") return {};
11143
+ return parsed;
11144
+ } catch {
11145
+ return {};
11146
+ }
11147
+ }
11148
+ function writeStore(store) {
11149
+ const localStorage = getBrowserLocalStorage();
11150
+ if (!localStorage) return;
11151
+ try {
11152
+ localStorage.setItem(MOCK_STORAGE_KEY, JSON.stringify(store));
11153
+ } catch {}
11154
+ }
11155
+ function newId(prefix) {
11156
+ const cryptoRef = globalThis.crypto;
11157
+ if (cryptoRef?.randomUUID) return `${prefix}-${cryptoRef.randomUUID()}`;
11158
+ return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
11159
+ }
11160
+ function requireAgentId(agentId) {
11161
+ const trimmed = agentId.trim();
11162
+ if (!trimmed) throw new Error("Channels require an agent id");
11163
+ return trimmed;
11164
+ }
11165
+ function clone(value) {
11166
+ return JSON.parse(JSON.stringify(value));
11167
+ }
11168
+ function defaultAccountLabel(platform) {
11169
+ const meta = getChannelPlatform(platform);
11170
+ return meta ? `${meta.name} workspace` : platform;
11171
+ }
11172
+ function findConnection(connections, connectionId) {
11173
+ const connection = connections.find((entry) => entry.id === connectionId);
11174
+ if (!connection) throw new Error(`Channel connection not found: ${connectionId}`);
11175
+ return connection;
11176
+ }
11177
+ function toBinding(input, now) {
11178
+ return {
11179
+ id: newId("chan-bind"),
11180
+ channelId: input.channelId,
11181
+ channelName: input.channelName,
11182
+ channelKind: input.channelKind ?? "public",
11183
+ mode: input.mode ?? "mention",
11184
+ subscribeOnMention: input.subscribeOnMention ?? true,
11185
+ createdAt: now,
11186
+ updatedAt: now
11187
+ };
11188
+ }
11189
+ function createChannelsResource() {
11190
+ return {
11191
+ /** The supported-platform catalog (static; backend may derive from the adapter registry). */
11192
+ listPlatforms: mock({
11193
+ domain: "channels",
11194
+ method: "listPlatforms",
11195
+ plannedEndpoint: "GET /api/channels/platforms"
11196
+ }, async () => clone(CHANNEL_PLATFORMS)),
11197
+ /** Connections (with their channel bindings) for one agent. */
11198
+ listForAgent: mock({
11199
+ domain: "channels",
11200
+ method: "listForAgent",
11201
+ plannedEndpoint: "GET /api/agents/:agentId/channels"
11202
+ }, async (agentId) => {
11203
+ const id = requireAgentId(agentId);
11204
+ return clone(readStore()[id] ?? []);
11205
+ }),
11206
+ /**
11207
+ * Channel directory for a platform — the picker source. NET-NEW vs. the
11208
+ * current backend (no channel-list endpoint exists). The runtime team needs
11209
+ * to expose this (e.g. Slack `conversations.list`) for a real picker.
11210
+ */
11211
+ listChannels: mock({
11212
+ domain: "channels",
11213
+ method: "listChannels",
11214
+ plannedEndpoint: "GET /api/channels/:platform/directory"
11215
+ }, async (platform) => clone(CHANNEL_DIRECTORY[platform] ?? [])),
11216
+ /** Connect a platform for an agent (OAuth install or credential entry), optionally with a first binding. */
11217
+ connect: mock({
11218
+ domain: "channels",
11219
+ method: "connect",
11220
+ plannedEndpoint: "POST /api/agents/:agentId/channels"
11221
+ }, async (input) => {
11222
+ const agentId = requireAgentId(input.agentId);
11223
+ const store = readStore();
11224
+ const now = (/* @__PURE__ */ new Date()).toISOString();
11225
+ const connection = {
11226
+ id: newId("chan-conn"),
11227
+ platform: input.platform,
11228
+ agentId,
11229
+ accountLabel: input.accountLabel ?? defaultAccountLabel(input.platform),
11230
+ accountId: newId("acct").toUpperCase(),
11231
+ connectedAt: now,
11232
+ bindings: input.initialBinding ? [toBinding(input.initialBinding, now)] : []
11233
+ };
11234
+ writeStore({
11235
+ ...store,
11236
+ [agentId]: [...store[agentId] ?? [], connection]
11237
+ });
11238
+ return clone(connection);
11239
+ }),
11240
+ /** Add a channel binding to an existing connection. */
11241
+ addBinding: mock({
11242
+ domain: "channels",
11243
+ method: "addBinding",
11244
+ plannedEndpoint: "PUT /gateways/:platform/attachments/:channelId"
11245
+ }, async (input) => {
11246
+ const agentId = requireAgentId(input.agentId);
11247
+ const store = readStore();
11248
+ const connections = store[agentId] ?? [];
11249
+ const connection = findConnection(connections, input.connectionId);
11250
+ const now = (/* @__PURE__ */ new Date()).toISOString();
11251
+ connection.bindings = [...connection.bindings, toBinding(input.binding, now)];
11252
+ writeStore({
11253
+ ...store,
11254
+ [agentId]: connections
11255
+ });
11256
+ return clone(connection);
11257
+ }),
11258
+ /** Update a binding's listen mode / subscribe flag. */
11259
+ updateBinding: mock({
11260
+ domain: "channels",
11261
+ method: "updateBinding",
11262
+ plannedEndpoint: "PUT /gateways/:platform/attachments/:channelId"
11263
+ }, async (input) => {
11264
+ const agentId = requireAgentId(input.agentId);
11265
+ const store = readStore();
11266
+ const connections = store[agentId] ?? [];
11267
+ const connection = findConnection(connections, input.connectionId);
11268
+ const binding = connection.bindings.find((entry) => entry.id === input.bindingId);
11269
+ if (!binding) throw new Error(`Channel binding not found: ${input.bindingId}`);
11270
+ if (input.patch.mode !== void 0) binding.mode = input.patch.mode;
11271
+ if (input.patch.subscribeOnMention !== void 0) binding.subscribeOnMention = input.patch.subscribeOnMention;
11272
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
11273
+ writeStore({
11274
+ ...store,
11275
+ [agentId]: connections
11276
+ });
11277
+ return clone(connection);
11278
+ }),
11279
+ /** Remove a channel binding. */
11280
+ removeBinding: mock({
11281
+ domain: "channels",
11282
+ method: "removeBinding",
11283
+ plannedEndpoint: "DELETE /gateways/:platform/attachments/:channelId"
11284
+ }, async (input) => {
11285
+ const agentId = requireAgentId(input.agentId);
11286
+ const store = readStore();
11287
+ const connections = store[agentId] ?? [];
11288
+ const connection = findConnection(connections, input.connectionId);
11289
+ connection.bindings = connection.bindings.filter((entry) => entry.id !== input.bindingId);
11290
+ writeStore({
11291
+ ...store,
11292
+ [agentId]: connections
11293
+ });
11294
+ return clone(connection);
11295
+ }),
11296
+ /** Disconnect the agent from a platform (removes the connection + its bindings). */
11297
+ disconnect: mock({
11298
+ domain: "channels",
11299
+ method: "disconnect",
11300
+ plannedEndpoint: "DELETE /api/agents/:agentId/channels/:connectionId"
11301
+ }, async (input) => {
11302
+ const agentId = requireAgentId(input.agentId);
11303
+ const store = readStore();
11304
+ const next = (store[agentId] ?? []).filter((entry) => entry.id !== input.connectionId);
11305
+ writeStore({
11306
+ ...store,
11307
+ [agentId]: next
11308
+ });
11309
+ })
11310
+ };
11311
+ }
10380
11312
  function createPlatformClient(options) {
10381
11313
  const auth = options.auth ?? { type: "none" };
10382
11314
  const base = normalizeBaseUrl(options.baseUrl);
@@ -10413,7 +11345,9 @@ function createPlatformClient(options) {
10413
11345
  deployments: createDeploymentsResource(),
10414
11346
  projectMetrics: createProjectMetricsResource(),
10415
11347
  projectFiles: createProjectFilesResource(),
10416
- members: createMembersResource(),
11348
+ channels: createChannelsResource(),
11349
+ members: createMembersResource(http),
11350
+ invitations: createInvitationsResource(http),
10417
11351
  apiKeys: createApiKeysResource(),
10418
11352
  recents: createRecentsResource(),
10419
11353
  userPreferences: createUserPreferencesResource({ getCurrentUserId: options.getCurrentUserId }),
@@ -12739,11 +13673,8 @@ function registerBuildCommand(program) {
12739
13673
  program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
12740
13674
  try {
12741
13675
  const root = resolveProjectRoot(options.dir);
12742
- const { buildApp } = await import("./dist-CMxQJtOA.mjs");
12743
- await buildApp({
12744
- root,
12745
- emitRouteManifest: false
12746
- });
13676
+ const { buildApp } = await import("./dist-nRx_8hnk.mjs");
13677
+ await buildApp({ root });
12747
13678
  process.stdout.write(`Built ${root}\n`);
12748
13679
  } catch (error) {
12749
13680
  const message = error instanceof Error ? error.message : "Build failed";
@@ -12798,11 +13729,8 @@ async function runDeploy(options) {
12798
13729
  const config = createCliConfig();
12799
13730
  const client = createCliPlatformClient(config);
12800
13731
  if (!options.skipBuild) {
12801
- const { buildApp } = await import("./dist-CMxQJtOA.mjs");
12802
- await buildApp({
12803
- root,
12804
- emitRouteManifest: false
12805
- });
13732
+ const { buildApp } = await import("./dist-nRx_8hnk.mjs");
13733
+ await buildApp({ root });
12806
13734
  }
12807
13735
  const archive = packProjectArtifact(root);
12808
13736
  let active = await client.organizations.getActive();
@@ -12892,7 +13820,7 @@ function runtimeChildEnv(parentEnv, overrides) {
12892
13820
  //#region src/project/bootstrap-run.ts
12893
13821
  /** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
12894
13822
  async function resolveBootstrapRun(options) {
12895
- const { resolveRuntimeBuildArtifact } = await import("./dist-CMxQJtOA.mjs");
13823
+ const { resolveRuntimeBuildArtifact } = await import("./dist-nRx_8hnk.mjs");
12896
13824
  const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
12897
13825
  const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/bootstrap.mjs");
12898
13826
  const args = [`--import=${loader}`];
@@ -13057,7 +13985,7 @@ async function runDev(options) {
13057
13985
  process.on("SIGINT", shutdown);
13058
13986
  process.on("SIGTERM", shutdown);
13059
13987
  try {
13060
- const { watchApp } = await import("./dist-CMxQJtOA.mjs");
13988
+ const { watchApp } = await import("./dist-nRx_8hnk.mjs");
13061
13989
  await watchApp({
13062
13990
  root,
13063
13991
  clean: false,
@@ -13444,11 +14372,10 @@ async function runStart(options) {
13444
14372
  const apiPort = Number(new URL(serverUrl).port || 80);
13445
14373
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
13446
14374
  ensureNativeDeps(runtimeNodeModules);
13447
- const { buildApp } = await import("./dist-CMxQJtOA.mjs");
14375
+ const { buildApp } = await import("./dist-nRx_8hnk.mjs");
13448
14376
  await buildApp({
13449
14377
  root,
13450
- clean: false,
13451
- emitRouteManifest: false
14378
+ clean: false
13452
14379
  });
13453
14380
  const processes = [{
13454
14381
  name: "api",