@keystrokehq/hosting 0.1.13 → 0.1.14

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
@@ -4373,8 +4373,11 @@ function superRefine(fn, params) {
4373
4373
  function number(params) {
4374
4374
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
4375
4375
  }
4376
- //#endregion
4377
- //#region ../shared/dist/index.mjs
4376
+ new Set([
4377
+ "hello",
4378
+ "greeting",
4379
+ "greet"
4380
+ ]);
4378
4381
  /** Auth, session, and account-entry URL segments. */
4379
4382
  const AUTH_ACCOUNT_SLUGS = [
4380
4383
  "2fa",
@@ -4486,6 +4489,7 @@ const PRODUCT_SLUGS = [
4486
4489
  "execution",
4487
4490
  "executions",
4488
4491
  "explore",
4492
+ "forms",
4489
4493
  "get-started",
4490
4494
  "history",
4491
4495
  "inbox",
@@ -5353,6 +5357,8 @@ const storedRouteManifestEntryV2Schema = discriminatedUnion("kind", [
5353
5357
  moduleFile: string(),
5354
5358
  sourceHash: string().optional(),
5355
5359
  schedule: string(),
5360
+ /** IANA timezone for schedule wall-clock fields. When omitted, UTC. */
5361
+ timezone: string().optional(),
5356
5362
  name: requiredDisplayTextSchema,
5357
5363
  description: requiredDisplayTextSchema
5358
5364
  }),
@@ -5361,7 +5367,9 @@ const storedRouteManifestEntryV2Schema = discriminatedUnion("kind", [
5361
5367
  pollId: string(),
5362
5368
  attachmentIds: array(string()),
5363
5369
  moduleFile: string(),
5364
- schedule: string()
5370
+ schedule: string(),
5371
+ /** IANA timezone for schedule wall-clock fields. When omitted, UTC. */
5372
+ timezone: string().optional()
5365
5373
  }),
5366
5374
  object({
5367
5375
  kind: literal("cron-schedule"),
@@ -5370,6 +5378,8 @@ const storedRouteManifestEntryV2Schema = discriminatedUnion("kind", [
5370
5378
  moduleFile: string(),
5371
5379
  sourceHash: string().optional(),
5372
5380
  schedule: string(),
5381
+ /** IANA timezone for schedule wall-clock fields. When omitted, UTC. */
5382
+ timezone: string().optional(),
5373
5383
  /** Static cron payload from `defineCronSource({ payload })` — omitted when the source has none. */
5374
5384
  payload: unknown().optional(),
5375
5385
  name: requiredDisplayTextSchema,
@@ -5414,6 +5424,8 @@ const AutoTopupSummarySchema = object({
5414
5424
  const PlanLimitsSchema = object({
5415
5425
  includedStorageGb: number$1(),
5416
5426
  concurrencyLimit: number$1(),
5427
+ /** Max non-deleted projects; enforced on create only. */
5428
+ maxProjects: number$1(),
5417
5429
  agentTimeoutMs: number$1(),
5418
5430
  workflowTimeoutMs: number$1(),
5419
5431
  pollTimeoutMs: number$1(),
@@ -5427,8 +5439,15 @@ const PlanLimitsSchema = object({
5427
5439
  object({
5428
5440
  planKey: string(),
5429
5441
  subscriptionStatus: subscriptionStatusSchema,
5442
+ /** Remaining plan-bucket balance this period (µc). */
5430
5443
  planCreditMicroCredits: number$1(),
5444
+ /** Remaining prepaid balance (µc). Never expires. */
5431
5445
  prepaidCreditMicroCredits: number$1(),
5446
+ /**
5447
+ * Resolved monthly plan allotment (µc) — override ?? preset. Powers the
5448
+ * credit-usage progress denominator (`used = allotment − remaining`).
5449
+ */
5450
+ monthlyCreditMicroCredits: number$1(),
5432
5451
  periodStart: isoDateTime$6.nullable(),
5433
5452
  periodEnd: isoDateTime$6.nullable(),
5434
5453
  autoTopup: AutoTopupSummarySchema,
@@ -5671,7 +5690,8 @@ object({
5671
5690
  });
5672
5691
  const NewChannelBindingInputSchema = object({
5673
5692
  channelId: string().min(1),
5674
- channelName: string().min(1),
5693
+ /** Display name. When omitted or equal to `channelId`, the server resolves it from Slack. */
5694
+ channelName: string().min(1).optional(),
5675
5695
  channelKind: ChannelBindingKindSchema.optional(),
5676
5696
  mode: ChannelListenModeSchema.optional(),
5677
5697
  subscribeOnMention: boolean().optional()
@@ -5733,12 +5753,13 @@ const AppAuthKindSchema = _enum([
5733
5753
  "api_key",
5734
5754
  "keystroke"
5735
5755
  ]);
5736
- /** Composio auth scheme for API-key style connections. */
5756
+ /** Composio auth scheme for API-key / no-auth style connections. */
5737
5757
  const AppCredentialSchemeSchema = _enum([
5738
5758
  "API_KEY",
5739
5759
  "BEARER_TOKEN",
5740
5760
  "BASIC",
5741
- "BASIC_WITH_JWT"
5761
+ "BASIC_WITH_JWT",
5762
+ "NO_AUTH"
5742
5763
  ]);
5743
5764
  /**
5744
5765
  * Where app metadata and execution are sourced (e.g. native, composio, pipedream, custom).
@@ -5780,6 +5801,7 @@ object({
5780
5801
  "graphql"
5781
5802
  ]).default("custom"),
5782
5803
  url: string().url().optional(),
5804
+ logo: string().url().optional(),
5783
5805
  authKind: AppAuthKindSchema.optional(),
5784
5806
  fields: optionalCredentialFieldsSchema.optional(),
5785
5807
  credentialScheme: AppCredentialSchemeSchema.optional(),
@@ -5815,6 +5837,7 @@ object({
5815
5837
  authKind: AppAuthKindSchema,
5816
5838
  source: AppSourceSchema,
5817
5839
  url: string().url().nullable().optional(),
5840
+ logo: string().url().nullable().optional(),
5818
5841
  credentialFields: optionalCredentialFieldsSchema.optional(),
5819
5842
  credentialScheme: AppCredentialSchemeSchema.optional(),
5820
5843
  oauthScopes: array(OAuthScopeOptionSchema).optional(),
@@ -5851,12 +5874,14 @@ object({
5851
5874
  /** Endpoint URL for MCP, OpenAPI, or GraphQL custom apps. */
5852
5875
  url: string().url().nullable().optional(),
5853
5876
  /** True when the app has a non-empty credential field template. */
5854
- hasCredentialFields: boolean().optional()
5877
+ hasCredentialFields: boolean().optional(),
5878
+ /** Composio auth scheme — present for API-key and NO_AUTH apps so the picker can choose a flow. */
5879
+ credentialScheme: AppCredentialSchemeSchema.optional()
5855
5880
  }).extend({
5856
5881
  oauthScopes: array(OAuthScopeOptionSchema),
5857
5882
  /** Custom api_key apps — vault field template for connect UI and sync. */
5858
5883
  credentialFields: AppCredentialFieldsSchema.optional(),
5859
- /** Composio auth scheme when credentialFields are present. */
5884
+ /** Composio auth scheme for API-key or NO_AUTH connections. */
5860
5885
  credentialScheme: AppCredentialSchemeSchema.optional(),
5861
5886
  /** When present, the app supports agent gateway bindings (external channels). */
5862
5887
  gateway: AppGatewaySchema.optional()
@@ -5973,8 +5998,12 @@ const AppCredentialScopeSchema = _enum([
5973
5998
  "project",
5974
5999
  "organization"
5975
6000
  ]);
5976
- /** How the credential was connected (OAuth vs manual api-key entry). */
5977
- const AppCredentialConnectionKindSchema = _enum(["oauth", "manual"]);
6001
+ /** How the credential was connected (OAuth, manual api-key entry, or no-auth). */
6002
+ const AppCredentialConnectionKindSchema = _enum([
6003
+ "oauth",
6004
+ "manual",
6005
+ "none"
6006
+ ]);
5978
6007
  /** Connect-dialog permission preset for OAuth scope selection. */
5979
6008
  const OAuthPermissionModeSchema = _enum(["default", "restricted"]);
5980
6009
  const optionalTimestamp$1 = string().optional();
@@ -6068,12 +6097,39 @@ CredentialTargetsFieldsSchema.extend({
6068
6097
  message: "OAuth credentials are created via the OAuth callback",
6069
6098
  path: ["connectionKind"]
6070
6099
  });
6100
+ if (input.connectionKind === "none" && input.value) ctx.addIssue({
6101
+ code: "custom",
6102
+ message: "value is not allowed for no-auth connections",
6103
+ path: ["value"]
6104
+ });
6071
6105
  });
6072
6106
  object({
6073
6107
  label: string().trim().min(1).optional(),
6074
6108
  isDefault: boolean().optional(),
6075
- value: credentialSecretValueSchema.optional()
6076
- }).refine((input) => input.label !== void 0 || input.isDefault !== void 0 || input.value !== void 0, { message: "At least one field is required" });
6109
+ value: credentialSecretValueSchema.optional(),
6110
+ /** Move this credential to a different scope in place. */
6111
+ scope: AppCredentialScopeSchema.optional(),
6112
+ /** Required when `scope` is `project`. */
6113
+ projectSlug: string().trim().min(1).optional()
6114
+ }).superRefine((input, ctx) => {
6115
+ if (!(input.label !== void 0 || input.isDefault !== void 0 || input.value !== void 0 || input.scope !== void 0)) ctx.addIssue({
6116
+ code: "custom",
6117
+ message: "At least one field is required"
6118
+ });
6119
+ if (input.scope === "project" && !input.projectSlug) ctx.addIssue({
6120
+ code: "custom",
6121
+ message: "projectSlug is required when scope is project",
6122
+ path: ["projectSlug"]
6123
+ });
6124
+ if (input.scope !== "project" && input.projectSlug !== void 0) ctx.addIssue({
6125
+ code: "custom",
6126
+ message: "projectSlug is only valid when scope is project",
6127
+ path: ["projectSlug"]
6128
+ });
6129
+ });
6130
+ CredentialTargetsFieldsSchema.omit({ credentialInstanceId: true }).superRefine((input, ctx) => {
6131
+ if (!hasCredentialTarget(input)) addMissingCredentialTargetIssue(ctx);
6132
+ });
6077
6133
  object({
6078
6134
  limit: number().int().min(1).max(200).optional(),
6079
6135
  cursor: string().min(1).optional()
@@ -6175,11 +6231,46 @@ object({
6175
6231
  "org-deletion",
6176
6232
  "contact",
6177
6233
  "enterprise-upgrade",
6178
- "verification"
6234
+ "verification",
6235
+ "slack-connect"
6179
6236
  ]),
6180
6237
  message: string().trim().max(5e3).optional()
6181
6238
  });
6182
6239
  object({ ok: literal(true) });
6240
+ const TemplateKindSchema = _enum([
6241
+ "agent",
6242
+ "workflow",
6243
+ "both"
6244
+ ]);
6245
+ object({
6246
+ kind: TemplateKindSchema,
6247
+ title: string().min(1),
6248
+ description: string().min(1),
6249
+ tags: array(string().min(1)).default([]),
6250
+ requiredApps: array(string().min(1)).default([])
6251
+ });
6252
+ object({
6253
+ slug: string().min(1),
6254
+ kind: TemplateKindSchema,
6255
+ title: string().min(1),
6256
+ description: string().min(1),
6257
+ tags: array(string()),
6258
+ requiredApps: array(string()),
6259
+ updatedAt: string().datetime()
6260
+ }).extend({ files: record(string(), string()) });
6261
+ object({
6262
+ slug: string().min(1),
6263
+ files: record(string(), string())
6264
+ });
6265
+ object({
6266
+ slug: string().min(1),
6267
+ kind: TemplateKindSchema,
6268
+ title: string().min(1),
6269
+ description: string().min(1),
6270
+ tags: array(string()).default([]),
6271
+ requiredApps: array(string()).default([]),
6272
+ files: record(string(), string())
6273
+ });
6183
6274
  const MarketingContactCompanySizeSchema = _enum([
6184
6275
  "1-10",
6185
6276
  "11-50",
@@ -6204,7 +6295,14 @@ const ValidationErrorDetailSchema = object({
6204
6295
  const ErrorResponseCodeSchema = OrganizationSlugErrorCodeSchema.or(_enum([
6205
6296
  "needs_org_selection",
6206
6297
  "org_unverified",
6207
- "connector_unavailable"
6298
+ "connector_unavailable",
6299
+ "invalid_url",
6300
+ "url_not_allowed",
6301
+ "url_unreachable",
6302
+ "upstream_http_error",
6303
+ "spec_too_large",
6304
+ "spec_parse_error",
6305
+ "invalid_openapi"
6208
6306
  ]));
6209
6307
  object({
6210
6308
  error: string(),
@@ -6241,6 +6339,12 @@ const ChatAttachmentInputSchema = object({
6241
6339
  mediaType: string().min(1),
6242
6340
  filename: string().optional()
6243
6341
  });
6342
+ object({
6343
+ type: literal("file"),
6344
+ mediaType: string().min(1),
6345
+ url: string().min(1),
6346
+ filename: string().optional()
6347
+ });
6244
6348
  object({
6245
6349
  contentType: string().min(1),
6246
6350
  filename: string().min(1),
@@ -6321,12 +6425,7 @@ object({
6321
6425
  params: array(unknown()).default([]),
6322
6426
  method: string().min(1).optional()
6323
6427
  });
6324
- object({ migrations: array(object({
6325
- sql: array(string().min(1)),
6326
- hash: string().min(1),
6327
- folderMillis: number$1()
6328
- })) });
6329
- object({ results: array(object({ rows: array(unknown()) })) });
6428
+ object({ rows: array(unknown()) });
6330
6429
  const RunSourceKindSchema = _enum([
6331
6430
  "api",
6332
6431
  "trigger",
@@ -6356,6 +6455,10 @@ object({
6356
6455
  description: string().nullable().optional(),
6357
6456
  type: AgentTriggerTypeSchema,
6358
6457
  schedule: string().nullable(),
6458
+ /** IANA timezone for schedule wall-clock fields. Null when omitted (evaluates in UTC). */
6459
+ timezone: string().nullable(),
6460
+ /** ISO timestamptz of the next scheduled fire. Null for webhooks / unset. */
6461
+ nextRunAt: string().nullable(),
6359
6462
  endpoint: string().nullable(),
6360
6463
  origin: AgentTriggerOriginSchema,
6361
6464
  prompt: string().nullable(),
@@ -6512,6 +6615,26 @@ const HistoryAgentCompactionEventSchema = object({
6512
6615
  retainedTailEstimate: number$1().optional(),
6513
6616
  durable: boolean()
6514
6617
  });
6618
+ /** Compact abnormal prompt-finish diagnostics from `agent_end` (optional on older events). */
6619
+ const HistoryAgentPromptFinishEventSchema = object({
6620
+ seq: number$1(),
6621
+ createdAt: string(),
6622
+ promptId: string().optional(),
6623
+ outcome: _enum([
6624
+ "completed",
6625
+ "error",
6626
+ "aborted"
6627
+ ]),
6628
+ finishReason: string().nullable(),
6629
+ rawFinishReason: string().optional(),
6630
+ stepCount: number$1(),
6631
+ maxSteps: number$1(),
6632
+ hitStepLimit: boolean(),
6633
+ error: object({
6634
+ name: string().optional(),
6635
+ message: string()
6636
+ }).optional()
6637
+ });
6515
6638
  const HistoryRunDetailSchema = discriminatedUnion("kind", [HistoryWorkflowRunDetailSchema, object({
6516
6639
  kind: literal("agent"),
6517
6640
  runId: string(),
@@ -6539,6 +6662,8 @@ const HistoryRunDetailSchema = discriminatedUnion("kind", [HistoryWorkflowRunDet
6539
6662
  messages: array(record(string(), unknown())),
6540
6663
  /** Sanitized context-compaction markers for the conversation timeline. */
6541
6664
  compactionEvents: array(HistoryAgentCompactionEventSchema).default([]),
6665
+ /** Abnormal prompt-finish diagnostics from `agent_end` (missing on historical events). */
6666
+ promptFinishEvents: array(HistoryAgentPromptFinishEventSchema).default([]),
6542
6667
  trace: HistoryTraceSchema.nullable(),
6543
6668
  ranAs: HistoryRunActorSchema.nullable().optional(),
6544
6669
  usage: HistoryRunUsageSchema.nullable().optional()
@@ -6783,6 +6908,7 @@ object({
6783
6908
  * log. Defaulted so older servers remain compatible.
6784
6909
  */
6785
6910
  compactionEvents: array(HistoryAgentCompactionEventSchema).default([]),
6911
+ promptFinishEvents: array(HistoryAgentPromptFinishEventSchema).default([]),
6786
6912
  trace: TraceResponseSchema.nullable()
6787
6913
  });
6788
6914
  const SlackGatewayModeSchema = _enum([
@@ -7037,6 +7163,10 @@ object({
7037
7163
  webhookUrl: string().nullable(),
7038
7164
  /** Cron expression or poll cadence label (cron/poll triggers only). */
7039
7165
  schedule: string().nullable(),
7166
+ /** IANA timezone for schedule wall-clock fields. Null when omitted (evaluates in UTC). */
7167
+ timezone: string().nullable(),
7168
+ /** ISO timestamptz of the next scheduled fire. Null for webhooks / unset. */
7169
+ nextRunAt: string().nullable(),
7040
7170
  /** Workflows + agents currently bound to this source. */
7041
7171
  assignments: array(TriggerAssignmentSchema),
7042
7172
  lastFiredAt: string().nullable(),
@@ -7077,6 +7207,8 @@ const TriggerOverviewInputSchema = object({
7077
7207
  description: string().nullable(),
7078
7208
  type: TriggerTypeSchema,
7079
7209
  schedule: string().nullable(),
7210
+ /** IANA timezone for schedule wall-clock fields. Null/omitted → UTC. */
7211
+ timezone: string().nullable().optional(),
7080
7212
  sourcePath: string(),
7081
7213
  sourceContents: string(),
7082
7214
  assignments: array(TriggerAssignmentSchema)
@@ -7262,6 +7394,13 @@ object({
7262
7394
  uploadUrl: url(),
7263
7395
  storageKey: string().min(1)
7264
7396
  });
7397
+ object({ contentType: string().trim().min(1) });
7398
+ object({
7399
+ uploadUrl: url(),
7400
+ storageKey: string().min(1)
7401
+ });
7402
+ object({ storageKey: string().min(1) });
7403
+ object({ logo: url() });
7265
7404
  const UserInterfaceThemeSchema = _enum([
7266
7405
  "system",
7267
7406
  "light",
@@ -7442,90 +7581,6 @@ object({
7442
7581
  lastOpenedAt: string().min(1),
7443
7582
  lastModifiedAt: string().min(1)
7444
7583
  });
7445
- const isoDateTime = string().datetime();
7446
- const sha256Hex = string().regex(/^[a-f0-9]{64}$/, "Expected a lowercase hex sha256 digest");
7447
- /**
7448
- * A single entry in a deploy's file tree, as served to the dashboard. Carries
7449
- * no contents: `id` is a stable, path-derived handle used for selection and
7450
- * `?file=` deep links; `hash` is the content address used to fetch the bytes
7451
- * lazily and to cache them immutably in the browser.
7452
- */
7453
- const ProjectFileSummarySchema = object({
7454
- id: string(),
7455
- path: string().min(1),
7456
- hash: sha256Hex
7457
- });
7458
- /** Maps a runtime resource slug (agent/workflow/skill) to its source file path. */
7459
- const ProjectSourceResourceRefSchema = object({
7460
- slug: string().min(1),
7461
- path: string().min(1)
7462
- });
7463
- const ProjectSourceResourcesSchema = object({
7464
- agents: array(ProjectSourceResourceRefSchema).default([]),
7465
- workflows: array(ProjectSourceResourceRefSchema).default([]),
7466
- skills: array(ProjectSourceResourceRefSchema).default([])
7467
- });
7468
- const emptyResources = () => ({
7469
- agents: [],
7470
- workflows: [],
7471
- skills: []
7472
- });
7473
- object({
7474
- artifactId: string().nullable(),
7475
- files: array(ProjectFileSummarySchema),
7476
- resources: ProjectSourceResourcesSchema.default(emptyResources())
7477
- });
7478
- object({
7479
- path: string().min(1),
7480
- contents: string(),
7481
- hash: sha256Hex
7482
- });
7483
- object({ blobs: array(object({
7484
- hash: sha256Hex,
7485
- size: number$1().int().nonnegative()
7486
- })) });
7487
- object({ uploads: array(object({
7488
- hash: sha256Hex,
7489
- url: string().url()
7490
- })) });
7491
- object({ files: array(object({
7492
- path: string().min(1),
7493
- hash: sha256Hex
7494
- })) });
7495
- object({
7496
- ok: literal(true),
7497
- fileCount: number$1().int().nonnegative()
7498
- });
7499
- object({
7500
- files: array(object({
7501
- id: string(),
7502
- path: string().min(1),
7503
- hash: sha256Hex
7504
- })),
7505
- generatedAt: isoDateTime
7506
- });
7507
- /** A single source file returned by the bulk active-source download endpoint. */
7508
- const DownloadActiveProjectSourceFileSchema = object({
7509
- path: string().min(1),
7510
- contents: string()
7511
- });
7512
- object({
7513
- artifactId: string(),
7514
- files: array(DownloadActiveProjectSourceFileSchema)
7515
- });
7516
- object({
7517
- projectId: string(),
7518
- artifactId: string(),
7519
- pulledAt: string().datetime()
7520
- });
7521
- object({ files: array(object({
7522
- id: string(),
7523
- path: string().min(1)
7524
- })) });
7525
- object({ files: array(object({
7526
- id: string(),
7527
- path: string().min(1)
7528
- })) });
7529
7584
  /** Whether the overview is still being produced or finished. */
7530
7585
  const WorkflowOverviewStatusSchema = _enum(["generating", "ready"]);
7531
7586
  /** One phase of the guided-tour overview. */
@@ -7550,7 +7605,8 @@ const WorkflowInputFieldTypeSchema = _enum([
7550
7605
  "boolean",
7551
7606
  "enum",
7552
7607
  "object",
7553
- "array"
7608
+ "array",
7609
+ "file"
7554
7610
  ]);
7555
7611
  const WorkflowInputFieldSchema = lazy(() => object({
7556
7612
  key: string(),
@@ -7565,6 +7621,8 @@ const WorkflowInputFieldSchema = lazy(() => object({
7565
7621
  number$1(),
7566
7622
  boolean()
7567
7623
  ]).optional(),
7624
+ minimum: number$1().optional(),
7625
+ maximum: number$1().optional(),
7568
7626
  children: array(WorkflowInputFieldSchema).optional(),
7569
7627
  format: string().optional()
7570
7628
  }));
@@ -7764,6 +7822,159 @@ const WorkflowCanvasCredentialBindingSchema = union([
7764
7822
  })
7765
7823
  ]);
7766
7824
  record(string(), array(WorkflowCanvasCredentialBindingSchema));
7825
+ const FormControlSchema = _enum([
7826
+ "input",
7827
+ "textarea",
7828
+ "select",
7829
+ "radio",
7830
+ "stepper",
7831
+ "slider",
7832
+ "checkbox",
7833
+ "switch"
7834
+ ]);
7835
+ const FormFieldConfigEntrySchema = object({
7836
+ label: string().trim().min(1).max(120).optional(),
7837
+ helpText: string().trim().min(1).max(300).optional(),
7838
+ placeholder: string().trim().min(1).max(200).optional(),
7839
+ control: FormControlSchema.optional()
7840
+ });
7841
+ const FormFieldConfigSchema = record(string(), FormFieldConfigEntrySchema);
7842
+ const PublicFormFieldSchema = WorkflowInputFieldSchema.and(object({
7843
+ control: FormControlSchema.optional(),
7844
+ helpText: string().optional()
7845
+ }));
7846
+ const PublishedFormSchema = object({
7847
+ id: string().min(1),
7848
+ workflowId: string().min(1),
7849
+ workflowSlug: string().min(1),
7850
+ enabled: boolean(),
7851
+ title: string().min(1).nullable(),
7852
+ description: string().min(1).nullable(),
7853
+ fieldConfig: FormFieldConfigSchema,
7854
+ publicUrl: string().url(),
7855
+ createdAt: string().min(1),
7856
+ updatedAt: string().min(1)
7857
+ });
7858
+ object({
7859
+ id: string().min(1),
7860
+ projectId: string().min(1),
7861
+ workflowSlug: string().min(1),
7862
+ enabled: boolean(),
7863
+ title: string().min(1).nullable(),
7864
+ description: string().min(1).nullable(),
7865
+ fieldConfig: FormFieldConfigSchema,
7866
+ publicUrl: string().url(),
7867
+ createdAt: string().min(1),
7868
+ updatedAt: string().min(1)
7869
+ });
7870
+ PublishedFormSchema.nullable();
7871
+ object({
7872
+ enabled: boolean().optional(),
7873
+ title: string().trim().min(1).max(120).nullable().optional(),
7874
+ description: string().trim().min(1).max(500).nullable().optional(),
7875
+ fieldConfig: FormFieldConfigSchema.optional()
7876
+ });
7877
+ object({
7878
+ title: string().min(1),
7879
+ description: string().nullable(),
7880
+ fields: array(PublicFormFieldSchema),
7881
+ branding: object({
7882
+ organizationName: string().min(1),
7883
+ projectName: string().min(1),
7884
+ logoLightUrl: string().url().nullable(),
7885
+ logoDarkUrl: string().url().nullable(),
7886
+ logoHeightPx: number$1().int().positive()
7887
+ })
7888
+ });
7889
+ object({
7890
+ values: record(string(), unknown()),
7891
+ website: string().max(200).optional()
7892
+ });
7893
+ object({ ok: literal(true) });
7894
+ const isoDateTime = string().datetime();
7895
+ const sha256Hex = string().regex(/^[a-f0-9]{64}$/, "Expected a lowercase hex sha256 digest");
7896
+ /**
7897
+ * A single entry in a deploy's file tree, as served to the dashboard. Carries
7898
+ * no contents: `id` is a stable, path-derived handle used for selection and
7899
+ * `?file=` deep links; `hash` is the content address used to fetch the bytes
7900
+ * lazily and to cache them immutably in the browser.
7901
+ */
7902
+ const ProjectFileSummarySchema = object({
7903
+ id: string(),
7904
+ path: string().min(1),
7905
+ hash: sha256Hex
7906
+ });
7907
+ /** Maps a runtime resource slug (agent/workflow/skill) to its source file path. */
7908
+ const ProjectSourceResourceRefSchema = object({
7909
+ slug: string().min(1),
7910
+ path: string().min(1)
7911
+ });
7912
+ const ProjectSourceResourcesSchema = object({
7913
+ agents: array(ProjectSourceResourceRefSchema).default([]),
7914
+ workflows: array(ProjectSourceResourceRefSchema).default([]),
7915
+ skills: array(ProjectSourceResourceRefSchema).default([])
7916
+ });
7917
+ const emptyResources = () => ({
7918
+ agents: [],
7919
+ workflows: [],
7920
+ skills: []
7921
+ });
7922
+ object({
7923
+ artifactId: string().nullable(),
7924
+ files: array(ProjectFileSummarySchema),
7925
+ resources: ProjectSourceResourcesSchema.default(emptyResources())
7926
+ });
7927
+ object({
7928
+ path: string().min(1),
7929
+ contents: string(),
7930
+ hash: sha256Hex
7931
+ });
7932
+ object({ blobs: array(object({
7933
+ hash: sha256Hex,
7934
+ size: number$1().int().nonnegative()
7935
+ })) });
7936
+ object({ uploads: array(object({
7937
+ hash: sha256Hex,
7938
+ url: string().url()
7939
+ })) });
7940
+ object({ files: array(object({
7941
+ path: string().min(1),
7942
+ hash: sha256Hex
7943
+ })) });
7944
+ object({
7945
+ ok: literal(true),
7946
+ fileCount: number$1().int().nonnegative()
7947
+ });
7948
+ object({
7949
+ files: array(object({
7950
+ id: string(),
7951
+ path: string().min(1),
7952
+ hash: sha256Hex
7953
+ })),
7954
+ generatedAt: isoDateTime
7955
+ });
7956
+ /** A single source file returned by the bulk active-source download endpoint. */
7957
+ const DownloadActiveProjectSourceFileSchema = object({
7958
+ path: string().min(1),
7959
+ contents: string()
7960
+ });
7961
+ object({
7962
+ artifactId: string(),
7963
+ files: array(DownloadActiveProjectSourceFileSchema)
7964
+ });
7965
+ object({
7966
+ projectId: string(),
7967
+ artifactId: string(),
7968
+ pulledAt: string().datetime()
7969
+ });
7970
+ object({ files: array(object({
7971
+ id: string(),
7972
+ path: string().min(1)
7973
+ })) });
7974
+ object({ files: array(object({
7975
+ id: string(),
7976
+ path: string().min(1)
7977
+ })) });
7767
7978
  record(string(), unknown());
7768
7979
  //#endregion
7769
7980
  //#region src/runtime.ts
@@ -7815,10 +8026,22 @@ const RUNTIME_ENV_KEYS = [
7815
8026
  "REDIS_URL",
7816
8027
  "KEYSTROKE_QUEUE_PREFIX"
7817
8028
  ];
8029
+ /**
8030
+ * Observability ingest config for org workers (PostHog error tracking + crash reports).
8031
+ * Ingest tokens only — never forward `POSTHOG_API_KEY` (management) into workers.
8032
+ */
8033
+ const OBSERVABILITY_ENV_KEYS = [
8034
+ "POSTHOG_PROJECT_TOKEN",
8035
+ "POSTHOG_HOST",
8036
+ "POSTHOG_FLUSH_MODE",
8037
+ "KEYSTROKE_ENVIRONMENT",
8038
+ "KEYSTROKE_RELEASE"
8039
+ ];
7818
8040
  /** Env keys that must never be forwarded into untrusted org workers. */
7819
8041
  const FORBIDDEN_WORKER_ENV_KEYS = [
7820
8042
  "BETTER_AUTH_SECRET",
7821
8043
  "DATABASE_URL",
8044
+ "POSTHOG_API_KEY",
7822
8045
  "POSTGRES_PASSWORD",
7823
8046
  "PLATFORM_WORKER_TOKEN",
7824
8047
  "STRIPE_SECRET_KEY",
@@ -7862,6 +8085,11 @@ function buildRuntimeEnv(source, artifacts, database, extraEnv) {
7862
8085
  if (!value) continue;
7863
8086
  entries.set(key, value);
7864
8087
  }
8088
+ for (const key of OBSERVABILITY_ENV_KEYS) {
8089
+ const value = source[key]?.trim();
8090
+ if (!value) continue;
8091
+ entries.set(key, value);
8092
+ }
7865
8093
  if (!extraEnv) for (const key of PROVIDER_ENV_KEYS) {
7866
8094
  const value = source[key]?.trim();
7867
8095
  if (value) entries.set(key, value);