@keystrokehq/cli 1.0.25 → 1.0.26

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as __require, t as __commonJSMin } from "./chunk-DiodbrVj.mjs";
3
- import { $n as NEVER, An as ZodType, Bn as literal, Cn as normalizeCredentialList, Fn as array, Gn as preprocess, Hn as number, In as boolean$1, Jn as union, Kn as record, Ln as custom, Lt as ROUTE_MANIFEST_REL_PATH, Mn as _function, Nn as _null, Pn as any, Pt as PromptResponseSchema, Qn as toJSONSchema, Rn as discriminatedUnion, Un as object, Vn as looseObject, Wn as optional, Xn as url, Yn as unknown, Zn as datetime, jn as _enum, kn as number$1, qn as string, xn as credentialInputSchema, zn as intersection } from "./dist-CBr6Vyut.mjs";
4
- import "./pack-artifact-NGxvGcXq-D2YwPA8E.mjs";
3
+ import { $n as union, Bn as array, Dn as normalizeCredentialList, Fn as ZodType, Gn as literal, Hn as custom, In as _enum, Jn as object, Kn as looseObject, Ln as _function, Lt as ROUTE_MANIFEST_REL_PATH, Pn as number$1, Pt as PromptResponseSchema, Qn as string, Rn as _null, Tn as credentialInputSchema, Un as discriminatedUnion, Vn as boolean$1, Wn as intersection, Xn as preprocess, Yn as optional, Zn as record, er as unknown, ir as NEVER, nr as datetime, qn as number, rr as toJSONSchema, tr as url, zn as any } from "./dist-BUK3crkq.mjs";
4
+ import "./pack-artifact-DVnIKrsg-CZTT2aF_.mjs";
5
5
  import "./chunk-BZUGFHVS-CPWRFwK8.mjs";
6
6
  import "./chunk-DLL7UR66-BUYgzxnR.mjs";
7
7
  import "./chunk-TN7HHBQW-CSB_R-XD.mjs";
@@ -23,7 +23,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSy
23
23
  import { readdir, stat } from "node:fs/promises";
24
24
  import "node:child_process";
25
25
  import { pathToFileURL } from "node:url";
26
- import "node:crypto";
26
+ import { createHash } from "node:crypto";
27
27
  import { AsyncLocalStorage } from "node:async_hooks";
28
28
  import { sql } from "drizzle-orm";
29
29
  import "better-sqlite3";
@@ -7009,82 +7009,106 @@ const usageRecordsSqlite = sqliteTable("usage_records", {
7009
7009
  metadata: text("metadata", { mode: "json" }),
7010
7010
  createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull()
7011
7011
  }, (table) => [index("usage_records_run_run_kind_idx").on(table.runId, table.runKind), index("usage_records_kind_idx").on(table.kind)]);
7012
- const triggerAttachments = pgTable("trigger_attachments", {
7012
+ const triggers = pgTable("triggers", {
7013
7013
  id: text$1("id").primaryKey(),
7014
7014
  projectId: text$1("project_id").notNull(),
7015
7015
  slug: text$1("slug").notNull(),
7016
+ kind: text$1("kind").$type().notNull(),
7016
7017
  name: text$1("name"),
7017
7018
  description: text$1("description"),
7018
- targetKind: text$1("target_kind").$type().notNull().default("workflow"),
7019
- workflowSlug: text$1("workflow_slug"),
7020
- agentSlug: text$1("agent_slug"),
7021
7019
  moduleFile: text$1("module_file").notNull(),
7022
- source: jsonb("source").$type().notNull(),
7023
7020
  origin: text$1("origin").$type().notNull().default("project"),
7024
- prompt: text$1("prompt"),
7021
+ config: jsonb("config").$type(),
7022
+ schedule: text$1("schedule"),
7023
+ nextRunAt: timestamp("next_run_at", { withTimezone: true }),
7024
+ enabled: integer$1("enabled").notNull().default(1),
7025
7025
  lifecycle: jsonb("lifecycle").$type(),
7026
7026
  createdBySessionId: text$1("created_by_session_id"),
7027
+ triggerHash: text$1("trigger_hash"),
7028
+ overviewMarkdown: text$1("overview_markdown"),
7029
+ overviewHash: text$1("overview_hash"),
7030
+ overviewModel: text$1("overview_model"),
7031
+ overviewStatus: text$1("overview_status").$type().notNull().default("idle"),
7032
+ overviewGeneratedAt: timestamp("overview_generated_at", { withTimezone: true }),
7027
7033
  registeredAt: timestamp("registered_at", { withTimezone: true }).notNull(),
7028
7034
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull(),
7029
7035
  deletedAt: timestamp("deleted_at", { withTimezone: true })
7030
- }, (table) => [uniqueIndex$1("trigger_attachments_project_id_slug_idx").on(table.projectId, table.slug)]);
7031
- const triggerAttachmentsSqlite = sqliteTable("trigger_attachments", {
7036
+ }, (table) => [uniqueIndex$1("triggers_project_id_slug_idx").on(table.projectId, table.slug), index$1("triggers_next_run_at_enabled_idx").on(table.nextRunAt, table.enabled)]);
7037
+ const triggersSqlite = sqliteTable("triggers", {
7032
7038
  id: text("id").primaryKey(),
7033
7039
  projectId: text("project_id").notNull(),
7034
7040
  slug: text("slug").notNull(),
7041
+ kind: text("kind").$type().notNull(),
7035
7042
  name: text("name"),
7036
7043
  description: text("description"),
7037
- targetKind: text("target_kind").$type().notNull().default("workflow"),
7038
- workflowSlug: text("workflow_slug"),
7039
- agentSlug: text("agent_slug"),
7040
7044
  moduleFile: text("module_file").notNull(),
7041
- source: text("source", { mode: "json" }).$type().notNull(),
7042
7045
  origin: text("origin").$type().notNull().default("project"),
7043
- prompt: text("prompt"),
7046
+ config: text("config", { mode: "json" }).$type(),
7047
+ schedule: text("schedule"),
7048
+ nextRunAt: integer("next_run_at", { mode: "timestamp_ms" }),
7049
+ enabled: integer("enabled").notNull().default(1),
7044
7050
  lifecycle: text("lifecycle", { mode: "json" }).$type(),
7045
7051
  createdBySessionId: text("created_by_session_id"),
7052
+ triggerHash: text("trigger_hash"),
7053
+ overviewMarkdown: text("overview_markdown"),
7054
+ overviewHash: text("overview_hash"),
7055
+ overviewModel: text("overview_model"),
7056
+ overviewStatus: text("overview_status").$type().notNull().default("idle"),
7057
+ overviewGeneratedAt: integer("overview_generated_at", { mode: "timestamp_ms" }),
7046
7058
  registeredAt: integer("registered_at", { mode: "timestamp_ms" }).notNull(),
7047
7059
  updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull(),
7048
7060
  deletedAt: integer("deleted_at", { mode: "timestamp_ms" })
7049
- }, (table) => [uniqueIndex("trigger_attachments_project_id_slug_idx").on(table.projectId, table.slug)]);
7050
- const triggerSchedules = pgTable("trigger_schedules", {
7061
+ }, (table) => [uniqueIndex("triggers_project_id_slug_idx").on(table.projectId, table.slug), index("triggers_next_run_at_enabled_idx").on(table.nextRunAt, table.enabled)]);
7062
+ const triggerAttachments = pgTable("trigger_attachments", {
7051
7063
  id: text$1("id").primaryKey(),
7052
7064
  projectId: text$1("project_id").notNull(),
7053
- attachmentSlug: text$1("attachment_slug").notNull(),
7054
- kind: text$1("kind").$type().notNull(),
7055
- schedule: text$1("schedule").notNull(),
7056
- nextRunAt: timestamp("next_run_at", { withTimezone: true }).notNull(),
7057
- enabled: integer$1("enabled").notNull(),
7058
- updatedAt: timestamp("updated_at", { withTimezone: true }).notNull()
7059
- }, (table) => [uniqueIndex$1("trigger_schedules_project_id_attachment_slug_idx").on(table.projectId, table.attachmentSlug), index$1("trigger_schedules_next_run_at_idx").on(table.nextRunAt, table.enabled)]);
7060
- const triggerSchedulesSqlite = sqliteTable("trigger_schedules", {
7065
+ triggerId: text$1("trigger_id").notNull().references(() => triggers.id),
7066
+ slug: text$1("slug").notNull(),
7067
+ targetKind: text$1("target_kind").$type().notNull().default("workflow"),
7068
+ workflowSlug: text$1("workflow_slug"),
7069
+ agentSlug: text$1("agent_slug"),
7070
+ prompt: text$1("prompt"),
7071
+ registeredAt: timestamp("registered_at", { withTimezone: true }).notNull(),
7072
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull(),
7073
+ deletedAt: timestamp("deleted_at", { withTimezone: true })
7074
+ }, (table) => [uniqueIndex$1("trigger_attachments_project_id_slug_idx").on(table.projectId, table.slug)]);
7075
+ const triggerAttachmentsSqlite = sqliteTable("trigger_attachments", {
7061
7076
  id: text("id").primaryKey(),
7062
7077
  projectId: text("project_id").notNull(),
7063
- attachmentSlug: text("attachment_slug").notNull(),
7064
- kind: text("kind").$type().notNull(),
7065
- schedule: text("schedule").notNull(),
7066
- nextRunAt: integer("next_run_at", { mode: "timestamp_ms" }).notNull(),
7067
- enabled: integer("enabled").notNull(),
7068
- updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull()
7069
- }, (table) => [uniqueIndex("trigger_schedules_project_id_attachment_slug_idx").on(table.projectId, table.attachmentSlug), index("trigger_schedules_next_run_at_idx").on(table.nextRunAt, table.enabled)]);
7078
+ triggerId: text("trigger_id").notNull().references(() => triggersSqlite.id),
7079
+ slug: text("slug").notNull(),
7080
+ targetKind: text("target_kind").$type().notNull().default("workflow"),
7081
+ workflowSlug: text("workflow_slug"),
7082
+ agentSlug: text("agent_slug"),
7083
+ prompt: text("prompt"),
7084
+ registeredAt: integer("registered_at", { mode: "timestamp_ms" }).notNull(),
7085
+ updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull(),
7086
+ deletedAt: integer("deleted_at", { mode: "timestamp_ms" })
7087
+ }, (table) => [uniqueIndex("trigger_attachments_project_id_slug_idx").on(table.projectId, table.slug)]);
7070
7088
  const triggerRuns = pgTable("trigger_runs", {
7071
7089
  id: text$1("id").primaryKey(),
7072
7090
  projectId: text$1("project_id").notNull(),
7073
- attachmentId: text$1("attachment_id").notNull().references(() => triggerAttachments.id),
7091
+ triggerId: text$1("trigger_id").notNull().references(() => triggers.id),
7074
7092
  sourcePath: text$1("source_path"),
7075
7093
  triggerType: text$1("trigger_type").$type().notNull(),
7094
+ outcome: text$1("outcome").$type().notNull().default("dispatched"),
7095
+ reason: text$1("reason").$type(),
7096
+ detail: text$1("detail"),
7076
7097
  payload: jsonb("payload"),
7077
7098
  triggeredAt: timestamp("triggered_at", { withTimezone: true }).notNull()
7078
- });
7099
+ }, (table) => [index$1("trigger_runs_project_trigger_triggered_idx").on(table.projectId, table.triggerId, table.triggeredAt), index$1("trigger_runs_project_triggered_idx").on(table.projectId, table.triggeredAt)]);
7079
7100
  const triggerRunsSqlite = sqliteTable("trigger_runs", {
7080
7101
  id: text("id").primaryKey(),
7081
7102
  projectId: text("project_id").notNull(),
7082
- attachmentId: text("attachment_id").notNull().references(() => triggerAttachmentsSqlite.id),
7103
+ triggerId: text("trigger_id").notNull().references(() => triggersSqlite.id),
7083
7104
  sourcePath: text("source_path"),
7084
7105
  triggerType: text("trigger_type").$type().notNull(),
7106
+ outcome: text("outcome").$type().notNull().default("dispatched"),
7107
+ reason: text("reason").$type(),
7108
+ detail: text("detail"),
7085
7109
  payload: text("payload", { mode: "json" }),
7086
7110
  triggeredAt: integer("triggered_at", { mode: "timestamp_ms" }).notNull()
7087
- });
7111
+ }, (table) => [index("trigger_runs_project_trigger_triggered_idx").on(table.projectId, table.triggerId, table.triggeredAt), index("trigger_runs_project_triggered_idx").on(table.projectId, table.triggeredAt)]);
7088
7112
  const workflowSubscriptions = pgTable("workflow_subscriptions", {
7089
7113
  id: text$1("id").primaryKey(),
7090
7114
  projectId: text$1("project_id").notNull(),
@@ -7470,14 +7494,14 @@ const tableRegistry$1 = {
7470
7494
  pg: usageRecords,
7471
7495
  sqlite: usageRecordsSqlite
7472
7496
  },
7497
+ triggers: {
7498
+ pg: triggers,
7499
+ sqlite: triggersSqlite
7500
+ },
7473
7501
  triggerAttachments: {
7474
7502
  pg: triggerAttachments,
7475
7503
  sqlite: triggerAttachmentsSqlite
7476
7504
  },
7477
- triggerSchedules: {
7478
- pg: triggerSchedules,
7479
- sqlite: triggerSchedulesSqlite
7480
- },
7481
7505
  triggerRuns: {
7482
7506
  pg: triggerRuns,
7483
7507
  sqlite: triggerRunsSqlite
@@ -14809,7 +14833,8 @@ const triggerSourceSchema$1 = preprocess(normalizeLegacySlugFields$1, discrimina
14809
14833
  passes: _function()
14810
14834
  })
14811
14835
  ]));
14812
- preprocess(normalizeLegacySlugFields$1, discriminatedUnion("target", [object({
14836
+ /** Runtime validation for an unbranded trigger attachment. */
14837
+ const triggerAttachmentCoreSchema$1 = preprocess(normalizeLegacySlugFields$1, discriminatedUnion("target", [object({
14813
14838
  slug: slugField$1,
14814
14839
  name: optionalTextField$1,
14815
14840
  description: optionalTextField$1,
@@ -14826,6 +14851,16 @@ preprocess(normalizeLegacySlugFields$1, discriminatedUnion("target", [object({
14826
14851
  agent: agentSchema$1,
14827
14852
  prompt: promptSchema$1
14828
14853
  })]));
14854
+ const TRIGGER_ATTACHMENT$1 = Symbol.for("keystroke.triggerAttachment");
14855
+ /**
14856
+ * Validates brand + shape via `triggerAttachmentCoreSchema` so server discovery
14857
+ * rejects unbranded or malformed attachments.
14858
+ */
14859
+ function isTriggerAttachment(value) {
14860
+ if (typeof value !== "object" || value === null) return false;
14861
+ if (!(TRIGGER_ATTACHMENT$1 in value) || value[TRIGGER_ATTACHMENT$1] !== true) return false;
14862
+ return triggerAttachmentCoreSchema$1.safeParse(value).success;
14863
+ }
14829
14864
  /** Read slug from a trigger source (`slug` preferred, legacy `key` fallback). */
14830
14865
  function sourceSlugFrom(source) {
14831
14866
  const slug = source.slug?.trim() || source.key?.trim();
@@ -14846,6 +14881,23 @@ function triggerMetaFromAttachment(attachment) {
14846
14881
  ...description !== void 0 ? { description } : {}
14847
14882
  };
14848
14883
  }
14884
+ /**
14885
+ * Hidden link from a chained `.attach(...)` result back to every attachment in the
14886
+ * same chain. Lets discovery expand a single default export into all fan-out targets.
14887
+ */
14888
+ const TRIGGER_ATTACHMENT_SIBLINGS = Symbol.for("keystroke.triggerAttachmentSiblings");
14889
+ /**
14890
+ * Flatten a trigger module's default export into its individual attachments —
14891
+ * a single `.attach(...)`, a `.attach(...).attach(...)` chain, or an array of either.
14892
+ */
14893
+ function triggerAttachmentsFromExport(value) {
14894
+ if (Array.isArray(value)) return value.flatMap(triggerAttachmentsFromExport);
14895
+ if (value && typeof value === "object") {
14896
+ const siblings = value[TRIGGER_ATTACHMENT_SIBLINGS];
14897
+ if (Array.isArray(siblings)) return siblings;
14898
+ }
14899
+ return isTriggerAttachment(value) ? [value] : [];
14900
+ }
14849
14901
  //#endregion
14850
14902
  //#region ../../packages/manifest/dist/index.mjs
14851
14903
  function isManifestAgent(value) {
@@ -15051,6 +15103,7 @@ function serializeRouteManifest(manifest) {
15051
15103
  entries.push({
15052
15104
  kind: entry.kind,
15053
15105
  attachmentId: entry.attachmentId,
15106
+ attachmentIds: entry.attachmentIds,
15054
15107
  moduleFile: entry.moduleFile,
15055
15108
  schedule: entry.schedule,
15056
15109
  ...entry.name !== void 0 ? { name: entry.name } : {},
@@ -15190,44 +15243,35 @@ async function discoverTriggerAttachments(triggersDir, options) {
15190
15243
  shouldDiscoverFile: (filePath) => shouldDiscoverTriggerFile(triggersDir, filePath)
15191
15244
  });
15192
15245
  const attachments = [];
15193
- for (const { filePath, moduleFile } of files) {
15194
- const attachment = await importTriggerAttachment(filePath, options);
15195
- const slug = attachmentSlugFromRecord(attachment);
15196
- attachments.push({
15197
- slug,
15198
- filePath,
15199
- moduleFile,
15200
- attachment
15201
- });
15202
- }
15246
+ for (const { filePath, moduleFile } of files) for (const attachment of await importTriggerAttachments(filePath, options)) attachments.push({
15247
+ slug: attachmentSlugFromRecord(attachment),
15248
+ filePath,
15249
+ moduleFile,
15250
+ attachment
15251
+ });
15203
15252
  return attachments;
15204
15253
  }
15205
15254
  function validateImportedTriggerAttachment(def, filePath) {
15206
15255
  return validateManifestTriggerAttachment(def, filePath);
15207
15256
  }
15208
- async function importTriggerAttachment(filePath, options) {
15257
+ async function loadTriggerModuleDefault(filePath, options) {
15209
15258
  const href = pathToFileURL(filePath).href;
15210
- return validateImportedTriggerAttachment((await (options?.reload ? import(`${href}?keystroke=${Date.now()}`) : import(href))).default, filePath);
15259
+ return (await (options?.reload ? import(`${href}?keystroke=${Date.now()}`) : import(href))).default;
15260
+ }
15261
+ /**
15262
+ * Import every attachment a trigger file declares — a single `.attach(...)`, a
15263
+ * `.attach(...).attach(...)` chain, or an array of either.
15264
+ */
15265
+ async function importTriggerAttachments(filePath, options) {
15266
+ const candidates = triggerAttachmentsFromExport(await loadTriggerModuleDefault(filePath, options));
15267
+ if (candidates.length === 0) return [validateImportedTriggerAttachment(void 0, filePath)];
15268
+ return candidates.map((candidate) => validateImportedTriggerAttachment(candidate, filePath));
15211
15269
  }
15212
15270
  function pollGroupId(discovered) {
15213
15271
  const source = discovered.attachment.source;
15214
15272
  if (source.kind !== "poll") throw new Error(`Attachment "${discovered.slug}" is not a poll trigger`);
15215
15273
  return source.id ?? sourceSlugFrom(source);
15216
15274
  }
15217
- function buildPollGroups(attachments) {
15218
- const byId = /* @__PURE__ */ new Map();
15219
- for (const discovered of attachments) {
15220
- if (discovered.attachment.source.kind !== "poll") continue;
15221
- const id = pollGroupId(discovered);
15222
- const group = byId.get(id) ?? [];
15223
- group.push(discovered);
15224
- byId.set(id, group);
15225
- }
15226
- return [...byId.entries()].map(([id, groupAttachments]) => ({
15227
- id,
15228
- attachments: groupAttachments
15229
- }));
15230
- }
15231
15275
  function buildWebhookBindingsByRoute(attachments, handlerOptionsFor) {
15232
15276
  const webhookBindingsByRoute = /* @__PURE__ */ new Map();
15233
15277
  for (const discovered of attachments) {
@@ -15319,6 +15363,13 @@ function resolveDistModuleDirs(projectRoot) {
15319
15363
  function toPosix(path) {
15320
15364
  return path.split(sep).join("/");
15321
15365
  }
15366
+ function hashFileContents(absPath) {
15367
+ try {
15368
+ return createHash("sha256").update(readFileSync(absPath)).digest("hex");
15369
+ } catch {
15370
+ return;
15371
+ }
15372
+ }
15322
15373
  /**
15323
15374
  * Resolve manifest moduleFile values to project-root-relative source paths.
15324
15375
  *
@@ -15353,6 +15404,23 @@ var SourceModuleFileResolver = class {
15353
15404
  if (!id) return fallback;
15354
15405
  return (await this.sourceMapFor(kindDir, nestedEntry)).get(id) ?? fallback;
15355
15406
  }
15407
+ /**
15408
+ * Like `resolve`, but also returns the sha256 of the resolved source file. The hash
15409
+ * is only present when a real `src/` file is matched (absent for dist-only artifacts),
15410
+ * and feeds the trigger overview change-detection (`triggers.triggerHash`).
15411
+ */
15412
+ async resolveSource(kindDir, nestedEntry, distDir, distFilePath) {
15413
+ const fallback = toPosix(relative(distDir, distFilePath));
15414
+ const id = entryIdFromFile(distDir, distFilePath, { nestedEntry });
15415
+ if (!id) return { moduleFile: fallback };
15416
+ const sourceRel = (await this.sourceMapFor(kindDir, nestedEntry)).get(id);
15417
+ if (!sourceRel) return { moduleFile: fallback };
15418
+ const sourceHash = hashFileContents(join(this.projectRoot, sourceRel));
15419
+ return {
15420
+ moduleFile: sourceRel,
15421
+ ...sourceHash ? { sourceHash } : {}
15422
+ };
15423
+ }
15356
15424
  };
15357
15425
  /** Build a stored route manifest from compiled dist/ modules without starting a server. */
15358
15426
  async function buildStoredRouteManifestForProject(projectRoot, options) {
@@ -15384,68 +15452,82 @@ async function buildStoredRouteManifestForProject(projectRoot, options) {
15384
15452
  }
15385
15453
  const attachments = await discoverTriggerAttachments(dirs.triggersDir, reload);
15386
15454
  const discoveredBySlug = new Map(attachments.map((attachment) => [attachment.slug, attachment]));
15387
- const pollGroups = buildPollGroups(attachments);
15388
- for (const discovered of discoveredBySlug.values()) {
15455
+ const cronByTriggerSlug = /* @__PURE__ */ new Map();
15456
+ const pollByGroupId = /* @__PURE__ */ new Map();
15457
+ for (const discovered of attachments) {
15389
15458
  const source = discovered.attachment.source;
15390
- const moduleFile = await sourcePaths.resolve("triggers", "trigger", dirs.triggersDir, discovered.filePath);
15391
15459
  if (source.kind === "cron") {
15392
- const meta = triggerMetaFromAttachment(discovered.attachment);
15393
- manifest.push({
15394
- kind: "cron-schedule",
15395
- attachmentId: discovered.slug,
15396
- moduleFile,
15397
- schedule: source.schedule,
15398
- ...meta
15399
- });
15460
+ const triggerSlug = sourceSlugFrom(source);
15461
+ const group = cronByTriggerSlug.get(triggerSlug) ?? [];
15462
+ group.push(discovered);
15463
+ cronByTriggerSlug.set(triggerSlug, group);
15400
15464
  continue;
15401
15465
  }
15402
15466
  if (source.kind === "poll") {
15403
- const meta = triggerMetaFromAttachment(discovered.attachment);
15404
- manifest.push({
15405
- kind: "trigger-poll",
15406
- attachmentId: discovered.slug,
15407
- moduleFile,
15408
- schedule: source.schedule,
15409
- ...meta,
15410
- response: PromptResponseSchema
15411
- });
15412
- continue;
15413
- }
15414
- if (source.kind === "webhook") {
15415
- const route = webhookRouteFromEndpoint(source.endpoint);
15416
- const bindings = buildWebhookBindingsByRoute(discoveredBySlug.values(), () => ({
15417
- execution: { attachmentSlug: discovered.slug },
15418
- attachmentSlug: discovered.slug
15419
- })).get(route) ?? [{
15420
- discovered,
15421
- options: { attachmentSlug: discovered.slug }
15422
- }];
15423
- const attachmentMeta = Object.fromEntries(bindings.flatMap(({ discovered: row }) => {
15424
- const meta = triggerMetaFromAttachment(row.attachment);
15425
- return Object.keys(meta).length > 0 ? [[row.slug, meta]] : [];
15426
- }));
15427
- manifest.push({
15428
- kind: "trigger-webhook",
15429
- endpoint: source.endpoint,
15430
- attachmentIds: bindings.map(({ discovered: row }) => row.slug),
15431
- moduleFile,
15432
- request: webhookMatchSchemaForBindings(bindings),
15433
- attachmentSchemas: webhookManifestAttachmentSchemasFromBindings(bindings),
15434
- ...Object.keys(attachmentMeta).length > 0 ? { attachmentMeta } : {},
15435
- response: PromptResponseSchema
15436
- });
15467
+ const groupId = pollGroupId(discovered);
15468
+ const group = pollByGroupId.get(groupId) ?? [];
15469
+ group.push(discovered);
15470
+ pollByGroupId.set(groupId, group);
15437
15471
  }
15438
15472
  }
15439
- for (const group of pollGroups) {
15440
- if (group.attachments.length <= 1) continue;
15441
- const first = group.attachments[0];
15473
+ for (const [triggerSlug, group] of cronByTriggerSlug) {
15474
+ const first = group[0];
15442
15475
  const source = first.attachment.source;
15476
+ if (source.kind !== "cron") continue;
15477
+ const meta = triggerMetaFromAttachment(first.attachment);
15478
+ const { moduleFile, sourceHash } = await sourcePaths.resolveSource("triggers", "trigger", dirs.triggersDir, first.filePath);
15443
15479
  manifest.push({
15444
- kind: "trigger-poll-group",
15445
- pollId: group.id,
15446
- attachmentIds: group.attachments.map((attachment) => attachment.slug),
15447
- moduleFile: await sourcePaths.resolve("triggers", "trigger", dirs.triggersDir, first.filePath),
15448
- schedule: source.kind === "poll" ? source.schedule : "",
15480
+ kind: "cron-schedule",
15481
+ attachmentId: triggerSlug,
15482
+ attachmentIds: group.map((attachment) => attachment.slug),
15483
+ moduleFile,
15484
+ ...sourceHash ? { sourceHash } : {},
15485
+ schedule: source.schedule,
15486
+ ...meta
15487
+ });
15488
+ }
15489
+ for (const [groupId, group] of pollByGroupId) {
15490
+ const first = group[0];
15491
+ const source = first.attachment.source;
15492
+ if (source.kind !== "poll") continue;
15493
+ const meta = triggerMetaFromAttachment(first.attachment);
15494
+ const { moduleFile, sourceHash } = await sourcePaths.resolveSource("triggers", "trigger", dirs.triggersDir, first.filePath);
15495
+ manifest.push({
15496
+ kind: "trigger-poll",
15497
+ attachmentId: groupId,
15498
+ attachmentIds: group.map((attachment) => attachment.slug),
15499
+ moduleFile,
15500
+ ...sourceHash ? { sourceHash } : {},
15501
+ schedule: source.schedule,
15502
+ ...meta,
15503
+ response: PromptResponseSchema
15504
+ });
15505
+ }
15506
+ for (const discovered of discoveredBySlug.values()) {
15507
+ const source = discovered.attachment.source;
15508
+ if (source.kind !== "webhook") continue;
15509
+ const { moduleFile, sourceHash } = await sourcePaths.resolveSource("triggers", "trigger", dirs.triggersDir, discovered.filePath);
15510
+ const route = webhookRouteFromEndpoint(source.endpoint);
15511
+ const bindings = buildWebhookBindingsByRoute(discoveredBySlug.values(), () => ({
15512
+ execution: { attachmentSlug: discovered.slug },
15513
+ attachmentSlug: discovered.slug
15514
+ })).get(route) ?? [{
15515
+ discovered,
15516
+ options: { attachmentSlug: discovered.slug }
15517
+ }];
15518
+ const attachmentMeta = Object.fromEntries(bindings.flatMap(({ discovered: row }) => {
15519
+ const meta = triggerMetaFromAttachment(row.attachment);
15520
+ return Object.keys(meta).length > 0 ? [[row.slug, meta]] : [];
15521
+ }));
15522
+ manifest.push({
15523
+ kind: "trigger-webhook",
15524
+ endpoint: source.endpoint,
15525
+ attachmentIds: bindings.map(({ discovered: row }) => row.slug),
15526
+ moduleFile,
15527
+ ...sourceHash ? { sourceHash } : {},
15528
+ request: webhookMatchSchemaForBindings(bindings),
15529
+ attachmentSchemas: webhookManifestAttachmentSchemasFromBindings(bindings),
15530
+ ...Object.keys(attachmentMeta).length > 0 ? { attachmentMeta } : {},
15449
15531
  response: PromptResponseSchema
15450
15532
  });
15451
15533
  }
@@ -15465,6 +15547,6 @@ async function emitStoredRouteManifestForProject(projectRoot) {
15465
15547
  persistStoredRouteManifest(projectRoot, await buildStoredRouteManifestForProject(projectRoot));
15466
15548
  }
15467
15549
  //#endregion
15468
- export { packAssetDirs as A, toStoredRouteManifest as C, webhookMatchSchemaForBindings as D, webhookManifestAttachmentSchemasFromBindings as E, shouldSkipKeystrokeModuleFile as F, walkTypeScriptFiles as I, discoverModuleFileEntries as M, entryIdFromFile as N, webhookRouteFromEndpoint as O, readKeystrokeIgnoreDirective as P, serializeRouteManifest as S, validateImportedWorkflowDefinition as T, importTriggerAttachment as _, buildStoredRouteManifestFromContext as a, pollGroupId as b, collectAgentToolSlugs as c, discoverSkillManifestEntries as d, discoverTriggerAttachments as f, importAgentDefinition as g, emitStoredRouteManifestForProject as h, buildStoredRouteManifestForProject as i, discoverEntries as j, workflowRouteFromKey as k, countAgentCredentials as l, discoverWorkflows as m, agentRouteFromKey as n, buildWebhookBindingsByRoute as o, discoverWorkflowEntries as p, buildPollGroups as r, collectAgentAppSlugs as s, agentManifestEntry as t, discoverAgentEntries as u, importWorkflowDefinition as v, validateImportedTriggerAttachment as w, schemaToJson as x, persistStoredRouteManifest as y };
15550
+ export { discoverEntries as A, validateImportedTriggerAttachment as C, webhookRouteFromEndpoint as D, webhookMatchSchemaForBindings as E, walkTypeScriptFiles as F, entryIdFromFile as M, readKeystrokeIgnoreDirective as N, workflowRouteFromKey as O, shouldSkipKeystrokeModuleFile as P, toStoredRouteManifest as S, webhookManifestAttachmentSchemasFromBindings as T, importWorkflowDefinition as _, buildWebhookBindingsByRoute as a, schemaToJson as b, countAgentCredentials as c, discoverTriggerAttachments as d, discoverWorkflowEntries as f, importTriggerAttachments as g, importAgentDefinition as h, buildStoredRouteManifestFromContext as i, discoverModuleFileEntries as j, packAssetDirs as k, discoverAgentEntries as l, emitStoredRouteManifestForProject as m, agentRouteFromKey as n, collectAgentAppSlugs as o, discoverWorkflows as p, buildStoredRouteManifestForProject as r, collectAgentToolSlugs as s, agentManifestEntry as t, discoverSkillManifestEntries as u, persistStoredRouteManifest as v, validateImportedWorkflowDefinition as w, serializeRouteManifest as x, pollGroupId as y };
15469
15551
 
15470
- //# sourceMappingURL=dist-BYEZ5-PQ.mjs.map
15552
+ //# sourceMappingURL=dist-6-Bdz4wY.mjs.map