@integrity-labs/agt-cli 0.28.1164 → 0.28.1166

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 (29) hide show
  1. package/dist/bin/agt.js +6 -6
  2. package/dist/{chunk-WPNCOXIB.js → chunk-6KJFIVYJ.js} +2 -2
  3. package/dist/{chunk-DR7PAO2Y.js → chunk-I5NQ762W.js} +187 -1
  4. package/dist/chunk-I5NQ762W.js.map +1 -0
  5. package/dist/{chunk-CHTG2VLG.js → chunk-NOCTCO7G.js} +3 -3
  6. package/dist/{chunk-6SIOI32E.js → chunk-UX3TDTVM.js} +5 -5
  7. package/dist/{chunk-J3LCXQGY.js → chunk-ZSCZDOHR.js} +2 -2
  8. package/dist/{claude-code-updater-L7C3DZJ3.js → claude-code-updater-VRZ7MMKO.js} +3 -3
  9. package/dist/{claude-pair-runtime-EQVMQMTF.js → claude-pair-runtime-HOIYDAGM.js} +3 -3
  10. package/dist/lib/manager-worker.js +19 -19
  11. package/dist/mcp/direct-chat-channel.js +188 -2
  12. package/dist/mcp/index.js +190 -4
  13. package/dist/mcp/origami.js +188 -2
  14. package/dist/mcp/slack-channel.js +188 -2
  15. package/dist/mcp/telegram-channel.js +188 -2
  16. package/dist/{persistent-session-BP3EXMFT.js → persistent-session-YQLP5NPI.js} +4 -4
  17. package/dist/{responsiveness-probe-ASP2NY2K.js → responsiveness-probe-6K6SVHRK.js} +4 -4
  18. package/dist/{session-auth-dead-KR2CABKC.js → session-auth-dead-M4KYOBXK.js} +3 -3
  19. package/package.json +1 -1
  20. package/dist/chunk-DR7PAO2Y.js.map +0 -1
  21. /package/dist/{chunk-WPNCOXIB.js.map → chunk-6KJFIVYJ.js.map} +0 -0
  22. /package/dist/{chunk-CHTG2VLG.js.map → chunk-NOCTCO7G.js.map} +0 -0
  23. /package/dist/{chunk-6SIOI32E.js.map → chunk-UX3TDTVM.js.map} +0 -0
  24. /package/dist/{chunk-J3LCXQGY.js.map → chunk-ZSCZDOHR.js.map} +0 -0
  25. /package/dist/{claude-code-updater-L7C3DZJ3.js.map → claude-code-updater-VRZ7MMKO.js.map} +0 -0
  26. /package/dist/{claude-pair-runtime-EQVMQMTF.js.map → claude-pair-runtime-HOIYDAGM.js.map} +0 -0
  27. /package/dist/{persistent-session-BP3EXMFT.js.map → persistent-session-YQLP5NPI.js.map} +0 -0
  28. /package/dist/{responsiveness-probe-ASP2NY2K.js.map → responsiveness-probe-6K6SVHRK.js.map} +0 -0
  29. /package/dist/{session-auth-dead-KR2CABKC.js.map → session-auth-dead-M4KYOBXK.js.map} +0 -0
package/dist/mcp/index.js CHANGED
@@ -19117,7 +19117,7 @@ var require_filters = __commonJS({
19117
19117
  return r.copySafeness(str, str.replace(/^\s*|\s*$/g, ""));
19118
19118
  }
19119
19119
  _exports.trim = trim;
19120
- function truncate2(input, length, killwords, end) {
19120
+ function truncate3(input, length, killwords, end) {
19121
19121
  var orig = input;
19122
19122
  input = normalize(input, "");
19123
19123
  length = length || 255;
@@ -19136,7 +19136,7 @@ var require_filters = __commonJS({
19136
19136
  input += end !== void 0 && end !== null ? end : "...";
19137
19137
  return r.copySafeness(orig, input);
19138
19138
  }
19139
- _exports.truncate = truncate2;
19139
+ _exports.truncate = truncate3;
19140
19140
  function upper(str) {
19141
19141
  str = normalize(str, "");
19142
19142
  return str.toUpperCase();
@@ -26567,6 +26567,15 @@ var INTEGRATION_REGISTRY = [
26567
26567
  // successor at the same cost to us); Sunburst is seeded at 4x.
26568
26568
  { event_type: "gpt_image_2_5_flare", unit: "image" },
26569
26569
  { event_type: "gpt_image_2_5_sunburst", unit: "image" },
26570
+ // CS-2360: quality medium/high price on their own rows (more image-output
26571
+ // tokens at the same per-token rate). `low` stays on the two meters above.
26572
+ // The handler refuses a medium/high render until its meter has a rate
26573
+ // card row in BOTH USD and AUD. Size does not change the meter: the rate
26574
+ // is set on the worst case (landscape/portrait).
26575
+ { event_type: "gpt_image_2_5_flare_medium", unit: "image", label: "Flare, medium quality" },
26576
+ { event_type: "gpt_image_2_5_flare_high", unit: "image", label: "Flare, high quality" },
26577
+ { event_type: "gpt_image_2_5_sunburst_medium", unit: "image", label: "Sunburst, medium quality" },
26578
+ { event_type: "gpt_image_2_5_sunburst_high", unit: "image", label: "Sunburst, high quality" },
26570
26579
  // CS-1940: an edit also records one of these with units = the number of
26571
26580
  // reference images. Declared here (obi-wan 3a515eaf41b0) because the admin
26572
26581
  // pricing route only accepts a price for a declared meter, and the org
@@ -29316,6 +29325,183 @@ var videoRenderTriggerAdapter = {
29316
29325
  };
29317
29326
  registerTriggerSource(videoRenderTriggerAdapter);
29318
29327
 
29328
+ // ../core/dist/triggers/adapters/webhook.js
29329
+ var WEBHOOK_TRIGGER_PROVIDER = "webhook";
29330
+ var WEBHOOK_MAX_BODY_BYTES = 1280 * 1024;
29331
+ var WEBHOOK_PROMPT_MAX_CHARS = 8e3;
29332
+ var WEBHOOK_RAW_MAX_CHARS = 64 * 1024;
29333
+ var WEBHOOK_INSTRUCTION_MAX_CHARS = 2e3;
29334
+ var WEBHOOK_NAME_MAX_CHARS = 80;
29335
+ var WEBHOOK_DEFAULT_RATE_CAP = 60;
29336
+ var WEBHOOK_MAX_RATE_CAP = 1e3;
29337
+ var WEBHOOK_PRESETS = {
29338
+ // https://docs.aws.amazon.com/eventbridge/latest/ref/overiew-event-structure.html
29339
+ eventbridge: {
29340
+ dedupPath: "id",
29341
+ eventTypePaths: ["source", "detail-type"],
29342
+ payloadPath: "detail",
29343
+ timePath: "time"
29344
+ },
29345
+ // Raw-body hash dedup, whole body as payload. Set dedup_path when the
29346
+ // sender has a stable id, or two identical bodies collapse into one.
29347
+ generic: {}
29348
+ };
29349
+ var PATH_RE = /^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+){0,9}$/;
29350
+ function readPath(value, path) {
29351
+ let cur = value;
29352
+ for (const key of path.split(".")) {
29353
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur))
29354
+ return void 0;
29355
+ if (!Object.prototype.hasOwnProperty.call(cur, key))
29356
+ return void 0;
29357
+ cur = cur[key];
29358
+ }
29359
+ return cur;
29360
+ }
29361
+ function scalarString(v) {
29362
+ if (typeof v === "string")
29363
+ return v.length > 0 ? v : null;
29364
+ if (typeof v === "number" && Number.isFinite(v))
29365
+ return String(v);
29366
+ return null;
29367
+ }
29368
+ function truncate(text, max) {
29369
+ if (text.length <= max)
29370
+ return text;
29371
+ return `${text.slice(0, max)}
29372
+ ... [truncated ${text.length - max} more characters]`;
29373
+ }
29374
+ function resolvePreset(config2) {
29375
+ const name = config2["preset"];
29376
+ const base = typeof name === "string" && Object.prototype.hasOwnProperty.call(WEBHOOK_PRESETS, name) ? WEBHOOK_PRESETS[name] : WEBHOOK_PRESETS.generic;
29377
+ const dedup = config2["dedup_path"];
29378
+ const type = config2["event_type_path"];
29379
+ const payload = config2["payload_path"];
29380
+ return {
29381
+ ...base,
29382
+ ...typeof dedup === "string" && dedup ? { dedupPath: dedup } : {},
29383
+ ...typeof type === "string" && type ? { eventTypePaths: [type] } : {},
29384
+ ...typeof payload === "string" && payload ? { payloadPath: payload } : {}
29385
+ };
29386
+ }
29387
+ function validateWebhookConfig(input) {
29388
+ const out = {};
29389
+ const name = input["name"];
29390
+ if (name !== void 0) {
29391
+ if (typeof name !== "string")
29392
+ return { ok: false, error: "name must be a string" };
29393
+ const trimmed = name.trim();
29394
+ if (trimmed.length > WEBHOOK_NAME_MAX_CHARS) {
29395
+ return { ok: false, error: `name must be at most ${WEBHOOK_NAME_MAX_CHARS} characters` };
29396
+ }
29397
+ if (trimmed)
29398
+ out["name"] = trimmed;
29399
+ }
29400
+ const instruction = input["instruction"];
29401
+ if (typeof instruction !== "string" || !instruction.trim()) {
29402
+ return {
29403
+ ok: false,
29404
+ error: "instruction is required: tell the agent what to do when an event arrives"
29405
+ };
29406
+ }
29407
+ if (instruction.trim().length > WEBHOOK_INSTRUCTION_MAX_CHARS) {
29408
+ return {
29409
+ ok: false,
29410
+ error: `instruction must be at most ${WEBHOOK_INSTRUCTION_MAX_CHARS} characters`
29411
+ };
29412
+ }
29413
+ out["instruction"] = instruction.trim();
29414
+ const preset = input["preset"] ?? "generic";
29415
+ if (typeof preset !== "string" || !Object.prototype.hasOwnProperty.call(WEBHOOK_PRESETS, preset)) {
29416
+ return {
29417
+ ok: false,
29418
+ error: `preset must be one of: ${Object.keys(WEBHOOK_PRESETS).join(", ")}`
29419
+ };
29420
+ }
29421
+ out["preset"] = preset;
29422
+ for (const key of ["dedup_path", "event_type_path", "payload_path"]) {
29423
+ const v = input[key];
29424
+ if (v === void 0 || v === null || v === "")
29425
+ continue;
29426
+ if (typeof v !== "string" || !PATH_RE.test(v)) {
29427
+ return { ok: false, error: `${key} must be a dot path like "detail.id"` };
29428
+ }
29429
+ out[key] = v;
29430
+ }
29431
+ const cap = input["max_events_per_hour"];
29432
+ if (cap !== void 0 && cap !== null) {
29433
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1 || cap > WEBHOOK_MAX_RATE_CAP) {
29434
+ return {
29435
+ ok: false,
29436
+ error: `max_events_per_hour must be an integer from 1 to ${WEBHOOK_MAX_RATE_CAP}`
29437
+ };
29438
+ }
29439
+ out["max_events_per_hour"] = cap;
29440
+ } else {
29441
+ out["max_events_per_hour"] = WEBHOOK_DEFAULT_RATE_CAP;
29442
+ }
29443
+ return { ok: true, config: out };
29444
+ }
29445
+ function webhookRateCap(trigger) {
29446
+ const cap = trigger.config["max_events_per_hour"];
29447
+ if (typeof cap === "number" && Number.isInteger(cap) && cap >= 1) {
29448
+ return Math.min(cap, WEBHOOK_MAX_RATE_CAP);
29449
+ }
29450
+ return WEBHOOK_DEFAULT_RATE_CAP;
29451
+ }
29452
+ function buildWebhookEvent(req, config2, now = /* @__PURE__ */ new Date()) {
29453
+ const preset = resolvePreset(config2);
29454
+ const body = req.body;
29455
+ const raw = req.rawBody ?? JSON.stringify(body ?? null);
29456
+ const idValue = preset.dedupPath ? scalarString(readPath(body, preset.dedupPath)) : null;
29457
+ const dedupKey = idValue ? `wh:id:${stableHash(idValue)}` : `wh:raw:${stableHash(raw)}`;
29458
+ const typeParts = (preset.eventTypePaths ?? []).map((p2) => scalarString(readPath(body, p2))).filter((v) => v !== null).map((v) => v.slice(0, 200));
29459
+ const eventType = typeParts.length > 0 ? typeParts.join(" / ") : "webhook event";
29460
+ const timeValue = preset.timePath ? scalarString(readPath(body, preset.timePath)) : null;
29461
+ const timeMs = timeValue ? Date.parse(timeValue) : NaN;
29462
+ const occurredAt = Number.isFinite(timeMs) ? new Date(timeMs).toISOString() : now.toISOString();
29463
+ let payload = body;
29464
+ if (preset.payloadPath) {
29465
+ const sub = readPath(body, preset.payloadPath);
29466
+ if (sub !== void 0)
29467
+ payload = sub;
29468
+ }
29469
+ const rendered = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2) ?? "null";
29470
+ const lines = [`Event: ${eventType}`];
29471
+ if (idValue)
29472
+ lines.push(`Event id: ${idValue.slice(0, 200)}`);
29473
+ lines.push("", truncate(rendered, WEBHOOK_PROMPT_MAX_CHARS));
29474
+ return {
29475
+ provider: WEBHOOK_TRIGGER_PROVIDER,
29476
+ occurredAt,
29477
+ dedupKey,
29478
+ sourceTrust: "untrusted",
29479
+ title: eventType,
29480
+ body: lines.join("\n"),
29481
+ // Keep the ledger row bounded: the full body when small, else a marker
29482
+ // with the head of it. Never headers (the bearer token rides there).
29483
+ raw: raw.length <= WEBHOOK_RAW_MAX_CHARS ? body : { truncated: true, bytes: raw.length, head: raw.slice(0, WEBHOOK_RAW_MAX_CHARS) },
29484
+ meaningful: true
29485
+ };
29486
+ }
29487
+ var webhookTriggerAdapter = {
29488
+ provider: WEBHOOK_TRIGGER_PROVIDER,
29489
+ kind: "webhook",
29490
+ webhookAuth: "bearer",
29491
+ webhookEvents: [],
29492
+ multiInstance: true,
29493
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
29494
+ validateConfig: validateWebhookConfig,
29495
+ rateCapPerHour: (trigger) => webhookRateCap(trigger),
29496
+ // Webhook-kind triggers are minted only on POST /agents/:id/triggers
29497
+ // (agent.edit); /host/triggers refuses non-poll providers.
29498
+ operatorInstruction: true,
29499
+ ingest(req, trigger) {
29500
+ return [buildWebhookEvent(req, trigger.config)];
29501
+ }
29502
+ };
29503
+ registerTriggerSource(webhookTriggerAdapter);
29504
+
29319
29505
  // ../core/dist/feature-flags/registry.js
29320
29506
  var FLAG_REGISTRY = [
29321
29507
  {
@@ -47113,7 +47299,7 @@ function mayMutate(toolName) {
47113
47299
  function describeToolCallFailure(params) {
47114
47300
  const { path, toolName, readOnly, state, status, body, aborted: aborted2, timeoutMs } = params;
47115
47301
  const what = aborted2 ? `API ${path} did not respond within ${timeoutMs}ms` : `API ${path} returned ${status}`;
47116
- const detail = body ? `: ${truncate(body, 400)}` : "";
47302
+ const detail = body ? `: ${truncate2(body, 400)}` : "";
47117
47303
  if (state === "not_committed") {
47118
47304
  return `${what}${detail} \u2014 the request was rejected before it took effect, so nothing changed. Safe to retry once the cause is fixed.`;
47119
47305
  }
@@ -47126,7 +47312,7 @@ function describeToolCallFailure(params) {
47126
47312
  }
47127
47313
  return `${what}${detail} \u2014 INDETERMINATE: the server may have completed this operation before the failure. ${tool} is read-only, so retrying is safe.`;
47128
47314
  }
47129
- function truncate(text, max) {
47315
+ function truncate2(text, max) {
47130
47316
  return text.length > max ? `${text.slice(0, max)}\u2026` : text;
47131
47317
  }
47132
47318
 
@@ -19117,7 +19117,7 @@ var require_filters = __commonJS({
19117
19117
  return r.copySafeness(str, str.replace(/^\s*|\s*$/g, ""));
19118
19118
  }
19119
19119
  _exports.trim = trim;
19120
- function truncate(input, length, killwords, end) {
19120
+ function truncate2(input, length, killwords, end) {
19121
19121
  var orig = input;
19122
19122
  input = normalize(input, "");
19123
19123
  length = length || 255;
@@ -19136,7 +19136,7 @@ var require_filters = __commonJS({
19136
19136
  input += end !== void 0 && end !== null ? end : "...";
19137
19137
  return r.copySafeness(orig, input);
19138
19138
  }
19139
- _exports.truncate = truncate;
19139
+ _exports.truncate = truncate2;
19140
19140
  function upper(str) {
19141
19141
  str = normalize(str, "");
19142
19142
  return str.toUpperCase();
@@ -40697,6 +40697,15 @@ var INTEGRATION_REGISTRY = [
40697
40697
  // successor at the same cost to us); Sunburst is seeded at 4x.
40698
40698
  { event_type: "gpt_image_2_5_flare", unit: "image" },
40699
40699
  { event_type: "gpt_image_2_5_sunburst", unit: "image" },
40700
+ // CS-2360: quality medium/high price on their own rows (more image-output
40701
+ // tokens at the same per-token rate). `low` stays on the two meters above.
40702
+ // The handler refuses a medium/high render until its meter has a rate
40703
+ // card row in BOTH USD and AUD. Size does not change the meter: the rate
40704
+ // is set on the worst case (landscape/portrait).
40705
+ { event_type: "gpt_image_2_5_flare_medium", unit: "image", label: "Flare, medium quality" },
40706
+ { event_type: "gpt_image_2_5_flare_high", unit: "image", label: "Flare, high quality" },
40707
+ { event_type: "gpt_image_2_5_sunburst_medium", unit: "image", label: "Sunburst, medium quality" },
40708
+ { event_type: "gpt_image_2_5_sunburst_high", unit: "image", label: "Sunburst, high quality" },
40700
40709
  // CS-1940: an edit also records one of these with units = the number of
40701
40710
  // reference images. Declared here (obi-wan 3a515eaf41b0) because the admin
40702
40711
  // pricing route only accepts a price for a declared meter, and the org
@@ -43225,6 +43234,183 @@ var videoRenderTriggerAdapter = {
43225
43234
  };
43226
43235
  registerTriggerSource(videoRenderTriggerAdapter);
43227
43236
 
43237
+ // ../core/dist/triggers/adapters/webhook.js
43238
+ var WEBHOOK_TRIGGER_PROVIDER = "webhook";
43239
+ var WEBHOOK_MAX_BODY_BYTES = 1280 * 1024;
43240
+ var WEBHOOK_PROMPT_MAX_CHARS = 8e3;
43241
+ var WEBHOOK_RAW_MAX_CHARS = 64 * 1024;
43242
+ var WEBHOOK_INSTRUCTION_MAX_CHARS = 2e3;
43243
+ var WEBHOOK_NAME_MAX_CHARS = 80;
43244
+ var WEBHOOK_DEFAULT_RATE_CAP = 60;
43245
+ var WEBHOOK_MAX_RATE_CAP = 1e3;
43246
+ var WEBHOOK_PRESETS = {
43247
+ // https://docs.aws.amazon.com/eventbridge/latest/ref/overiew-event-structure.html
43248
+ eventbridge: {
43249
+ dedupPath: "id",
43250
+ eventTypePaths: ["source", "detail-type"],
43251
+ payloadPath: "detail",
43252
+ timePath: "time"
43253
+ },
43254
+ // Raw-body hash dedup, whole body as payload. Set dedup_path when the
43255
+ // sender has a stable id, or two identical bodies collapse into one.
43256
+ generic: {}
43257
+ };
43258
+ var PATH_RE = /^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+){0,9}$/;
43259
+ function readPath(value, path) {
43260
+ let cur = value;
43261
+ for (const key of path.split(".")) {
43262
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur))
43263
+ return void 0;
43264
+ if (!Object.prototype.hasOwnProperty.call(cur, key))
43265
+ return void 0;
43266
+ cur = cur[key];
43267
+ }
43268
+ return cur;
43269
+ }
43270
+ function scalarString(v) {
43271
+ if (typeof v === "string")
43272
+ return v.length > 0 ? v : null;
43273
+ if (typeof v === "number" && Number.isFinite(v))
43274
+ return String(v);
43275
+ return null;
43276
+ }
43277
+ function truncate(text, max) {
43278
+ if (text.length <= max)
43279
+ return text;
43280
+ return `${text.slice(0, max)}
43281
+ ... [truncated ${text.length - max} more characters]`;
43282
+ }
43283
+ function resolvePreset(config2) {
43284
+ const name = config2["preset"];
43285
+ const base = typeof name === "string" && Object.prototype.hasOwnProperty.call(WEBHOOK_PRESETS, name) ? WEBHOOK_PRESETS[name] : WEBHOOK_PRESETS.generic;
43286
+ const dedup = config2["dedup_path"];
43287
+ const type = config2["event_type_path"];
43288
+ const payload = config2["payload_path"];
43289
+ return {
43290
+ ...base,
43291
+ ...typeof dedup === "string" && dedup ? { dedupPath: dedup } : {},
43292
+ ...typeof type === "string" && type ? { eventTypePaths: [type] } : {},
43293
+ ...typeof payload === "string" && payload ? { payloadPath: payload } : {}
43294
+ };
43295
+ }
43296
+ function validateWebhookConfig(input) {
43297
+ const out = {};
43298
+ const name = input["name"];
43299
+ if (name !== void 0) {
43300
+ if (typeof name !== "string")
43301
+ return { ok: false, error: "name must be a string" };
43302
+ const trimmed = name.trim();
43303
+ if (trimmed.length > WEBHOOK_NAME_MAX_CHARS) {
43304
+ return { ok: false, error: `name must be at most ${WEBHOOK_NAME_MAX_CHARS} characters` };
43305
+ }
43306
+ if (trimmed)
43307
+ out["name"] = trimmed;
43308
+ }
43309
+ const instruction = input["instruction"];
43310
+ if (typeof instruction !== "string" || !instruction.trim()) {
43311
+ return {
43312
+ ok: false,
43313
+ error: "instruction is required: tell the agent what to do when an event arrives"
43314
+ };
43315
+ }
43316
+ if (instruction.trim().length > WEBHOOK_INSTRUCTION_MAX_CHARS) {
43317
+ return {
43318
+ ok: false,
43319
+ error: `instruction must be at most ${WEBHOOK_INSTRUCTION_MAX_CHARS} characters`
43320
+ };
43321
+ }
43322
+ out["instruction"] = instruction.trim();
43323
+ const preset = input["preset"] ?? "generic";
43324
+ if (typeof preset !== "string" || !Object.prototype.hasOwnProperty.call(WEBHOOK_PRESETS, preset)) {
43325
+ return {
43326
+ ok: false,
43327
+ error: `preset must be one of: ${Object.keys(WEBHOOK_PRESETS).join(", ")}`
43328
+ };
43329
+ }
43330
+ out["preset"] = preset;
43331
+ for (const key of ["dedup_path", "event_type_path", "payload_path"]) {
43332
+ const v = input[key];
43333
+ if (v === void 0 || v === null || v === "")
43334
+ continue;
43335
+ if (typeof v !== "string" || !PATH_RE.test(v)) {
43336
+ return { ok: false, error: `${key} must be a dot path like "detail.id"` };
43337
+ }
43338
+ out[key] = v;
43339
+ }
43340
+ const cap = input["max_events_per_hour"];
43341
+ if (cap !== void 0 && cap !== null) {
43342
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1 || cap > WEBHOOK_MAX_RATE_CAP) {
43343
+ return {
43344
+ ok: false,
43345
+ error: `max_events_per_hour must be an integer from 1 to ${WEBHOOK_MAX_RATE_CAP}`
43346
+ };
43347
+ }
43348
+ out["max_events_per_hour"] = cap;
43349
+ } else {
43350
+ out["max_events_per_hour"] = WEBHOOK_DEFAULT_RATE_CAP;
43351
+ }
43352
+ return { ok: true, config: out };
43353
+ }
43354
+ function webhookRateCap(trigger) {
43355
+ const cap = trigger.config["max_events_per_hour"];
43356
+ if (typeof cap === "number" && Number.isInteger(cap) && cap >= 1) {
43357
+ return Math.min(cap, WEBHOOK_MAX_RATE_CAP);
43358
+ }
43359
+ return WEBHOOK_DEFAULT_RATE_CAP;
43360
+ }
43361
+ function buildWebhookEvent(req, config2, now = /* @__PURE__ */ new Date()) {
43362
+ const preset = resolvePreset(config2);
43363
+ const body = req.body;
43364
+ const raw = req.rawBody ?? JSON.stringify(body ?? null);
43365
+ const idValue = preset.dedupPath ? scalarString(readPath(body, preset.dedupPath)) : null;
43366
+ const dedupKey = idValue ? `wh:id:${stableHash(idValue)}` : `wh:raw:${stableHash(raw)}`;
43367
+ const typeParts = (preset.eventTypePaths ?? []).map((p2) => scalarString(readPath(body, p2))).filter((v) => v !== null).map((v) => v.slice(0, 200));
43368
+ const eventType = typeParts.length > 0 ? typeParts.join(" / ") : "webhook event";
43369
+ const timeValue = preset.timePath ? scalarString(readPath(body, preset.timePath)) : null;
43370
+ const timeMs = timeValue ? Date.parse(timeValue) : NaN;
43371
+ const occurredAt = Number.isFinite(timeMs) ? new Date(timeMs).toISOString() : now.toISOString();
43372
+ let payload = body;
43373
+ if (preset.payloadPath) {
43374
+ const sub = readPath(body, preset.payloadPath);
43375
+ if (sub !== void 0)
43376
+ payload = sub;
43377
+ }
43378
+ const rendered = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2) ?? "null";
43379
+ const lines = [`Event: ${eventType}`];
43380
+ if (idValue)
43381
+ lines.push(`Event id: ${idValue.slice(0, 200)}`);
43382
+ lines.push("", truncate(rendered, WEBHOOK_PROMPT_MAX_CHARS));
43383
+ return {
43384
+ provider: WEBHOOK_TRIGGER_PROVIDER,
43385
+ occurredAt,
43386
+ dedupKey,
43387
+ sourceTrust: "untrusted",
43388
+ title: eventType,
43389
+ body: lines.join("\n"),
43390
+ // Keep the ledger row bounded: the full body when small, else a marker
43391
+ // with the head of it. Never headers (the bearer token rides there).
43392
+ raw: raw.length <= WEBHOOK_RAW_MAX_CHARS ? body : { truncated: true, bytes: raw.length, head: raw.slice(0, WEBHOOK_RAW_MAX_CHARS) },
43393
+ meaningful: true
43394
+ };
43395
+ }
43396
+ var webhookTriggerAdapter = {
43397
+ provider: WEBHOOK_TRIGGER_PROVIDER,
43398
+ kind: "webhook",
43399
+ webhookAuth: "bearer",
43400
+ webhookEvents: [],
43401
+ multiInstance: true,
43402
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
43403
+ validateConfig: validateWebhookConfig,
43404
+ rateCapPerHour: (trigger) => webhookRateCap(trigger),
43405
+ // Webhook-kind triggers are minted only on POST /agents/:id/triggers
43406
+ // (agent.edit); /host/triggers refuses non-poll providers.
43407
+ operatorInstruction: true,
43408
+ ingest(req, trigger) {
43409
+ return [buildWebhookEvent(req, trigger.config)];
43410
+ }
43411
+ };
43412
+ registerTriggerSource(webhookTriggerAdapter);
43413
+
43228
43414
  // ../core/dist/feature-flags/registry.js
43229
43415
  var FLAG_REGISTRY = [
43230
43416
  {
@@ -19182,7 +19182,7 @@ var require_filters = __commonJS({
19182
19182
  return r.copySafeness(str2, str2.replace(/^\s*|\s*$/g, ""));
19183
19183
  }
19184
19184
  _exports.trim = trim;
19185
- function truncate(input, length, killwords, end) {
19185
+ function truncate2(input, length, killwords, end) {
19186
19186
  var orig = input;
19187
19187
  input = normalize(input, "");
19188
19188
  length = length || 255;
@@ -19201,7 +19201,7 @@ var require_filters = __commonJS({
19201
19201
  input += end !== void 0 && end !== null ? end : "...";
19202
19202
  return r.copySafeness(orig, input);
19203
19203
  }
19204
- _exports.truncate = truncate;
19204
+ _exports.truncate = truncate2;
19205
19205
  function upper(str2) {
19206
19206
  str2 = normalize(str2, "");
19207
19207
  return str2.toUpperCase();
@@ -35102,6 +35102,15 @@ var INTEGRATION_REGISTRY = [
35102
35102
  // successor at the same cost to us); Sunburst is seeded at 4x.
35103
35103
  { event_type: "gpt_image_2_5_flare", unit: "image" },
35104
35104
  { event_type: "gpt_image_2_5_sunburst", unit: "image" },
35105
+ // CS-2360: quality medium/high price on their own rows (more image-output
35106
+ // tokens at the same per-token rate). `low` stays on the two meters above.
35107
+ // The handler refuses a medium/high render until its meter has a rate
35108
+ // card row in BOTH USD and AUD. Size does not change the meter: the rate
35109
+ // is set on the worst case (landscape/portrait).
35110
+ { event_type: "gpt_image_2_5_flare_medium", unit: "image", label: "Flare, medium quality" },
35111
+ { event_type: "gpt_image_2_5_flare_high", unit: "image", label: "Flare, high quality" },
35112
+ { event_type: "gpt_image_2_5_sunburst_medium", unit: "image", label: "Sunburst, medium quality" },
35113
+ { event_type: "gpt_image_2_5_sunburst_high", unit: "image", label: "Sunburst, high quality" },
35105
35114
  // CS-1940: an edit also records one of these with units = the number of
35106
35115
  // reference images. Declared here (obi-wan 3a515eaf41b0) because the admin
35107
35116
  // pricing route only accepts a price for a declared meter, and the org
@@ -38052,6 +38061,183 @@ var videoRenderTriggerAdapter = {
38052
38061
  };
38053
38062
  registerTriggerSource(videoRenderTriggerAdapter);
38054
38063
 
38064
+ // ../core/dist/triggers/adapters/webhook.js
38065
+ var WEBHOOK_TRIGGER_PROVIDER = "webhook";
38066
+ var WEBHOOK_MAX_BODY_BYTES = 1280 * 1024;
38067
+ var WEBHOOK_PROMPT_MAX_CHARS = 8e3;
38068
+ var WEBHOOK_RAW_MAX_CHARS = 64 * 1024;
38069
+ var WEBHOOK_INSTRUCTION_MAX_CHARS = 2e3;
38070
+ var WEBHOOK_NAME_MAX_CHARS = 80;
38071
+ var WEBHOOK_DEFAULT_RATE_CAP = 60;
38072
+ var WEBHOOK_MAX_RATE_CAP = 1e3;
38073
+ var WEBHOOK_PRESETS = {
38074
+ // https://docs.aws.amazon.com/eventbridge/latest/ref/overiew-event-structure.html
38075
+ eventbridge: {
38076
+ dedupPath: "id",
38077
+ eventTypePaths: ["source", "detail-type"],
38078
+ payloadPath: "detail",
38079
+ timePath: "time"
38080
+ },
38081
+ // Raw-body hash dedup, whole body as payload. Set dedup_path when the
38082
+ // sender has a stable id, or two identical bodies collapse into one.
38083
+ generic: {}
38084
+ };
38085
+ var PATH_RE = /^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+){0,9}$/;
38086
+ function readPath(value, path) {
38087
+ let cur = value;
38088
+ for (const key2 of path.split(".")) {
38089
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur))
38090
+ return void 0;
38091
+ if (!Object.prototype.hasOwnProperty.call(cur, key2))
38092
+ return void 0;
38093
+ cur = cur[key2];
38094
+ }
38095
+ return cur;
38096
+ }
38097
+ function scalarString(v) {
38098
+ if (typeof v === "string")
38099
+ return v.length > 0 ? v : null;
38100
+ if (typeof v === "number" && Number.isFinite(v))
38101
+ return String(v);
38102
+ return null;
38103
+ }
38104
+ function truncate(text, max) {
38105
+ if (text.length <= max)
38106
+ return text;
38107
+ return `${text.slice(0, max)}
38108
+ ... [truncated ${text.length - max} more characters]`;
38109
+ }
38110
+ function resolvePreset(config2) {
38111
+ const name = config2["preset"];
38112
+ const base = typeof name === "string" && Object.prototype.hasOwnProperty.call(WEBHOOK_PRESETS, name) ? WEBHOOK_PRESETS[name] : WEBHOOK_PRESETS.generic;
38113
+ const dedup = config2["dedup_path"];
38114
+ const type = config2["event_type_path"];
38115
+ const payload = config2["payload_path"];
38116
+ return {
38117
+ ...base,
38118
+ ...typeof dedup === "string" && dedup ? { dedupPath: dedup } : {},
38119
+ ...typeof type === "string" && type ? { eventTypePaths: [type] } : {},
38120
+ ...typeof payload === "string" && payload ? { payloadPath: payload } : {}
38121
+ };
38122
+ }
38123
+ function validateWebhookConfig(input) {
38124
+ const out = {};
38125
+ const name = input["name"];
38126
+ if (name !== void 0) {
38127
+ if (typeof name !== "string")
38128
+ return { ok: false, error: "name must be a string" };
38129
+ const trimmed = name.trim();
38130
+ if (trimmed.length > WEBHOOK_NAME_MAX_CHARS) {
38131
+ return { ok: false, error: `name must be at most ${WEBHOOK_NAME_MAX_CHARS} characters` };
38132
+ }
38133
+ if (trimmed)
38134
+ out["name"] = trimmed;
38135
+ }
38136
+ const instruction = input["instruction"];
38137
+ if (typeof instruction !== "string" || !instruction.trim()) {
38138
+ return {
38139
+ ok: false,
38140
+ error: "instruction is required: tell the agent what to do when an event arrives"
38141
+ };
38142
+ }
38143
+ if (instruction.trim().length > WEBHOOK_INSTRUCTION_MAX_CHARS) {
38144
+ return {
38145
+ ok: false,
38146
+ error: `instruction must be at most ${WEBHOOK_INSTRUCTION_MAX_CHARS} characters`
38147
+ };
38148
+ }
38149
+ out["instruction"] = instruction.trim();
38150
+ const preset = input["preset"] ?? "generic";
38151
+ if (typeof preset !== "string" || !Object.prototype.hasOwnProperty.call(WEBHOOK_PRESETS, preset)) {
38152
+ return {
38153
+ ok: false,
38154
+ error: `preset must be one of: ${Object.keys(WEBHOOK_PRESETS).join(", ")}`
38155
+ };
38156
+ }
38157
+ out["preset"] = preset;
38158
+ for (const key2 of ["dedup_path", "event_type_path", "payload_path"]) {
38159
+ const v = input[key2];
38160
+ if (v === void 0 || v === null || v === "")
38161
+ continue;
38162
+ if (typeof v !== "string" || !PATH_RE.test(v)) {
38163
+ return { ok: false, error: `${key2} must be a dot path like "detail.id"` };
38164
+ }
38165
+ out[key2] = v;
38166
+ }
38167
+ const cap = input["max_events_per_hour"];
38168
+ if (cap !== void 0 && cap !== null) {
38169
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1 || cap > WEBHOOK_MAX_RATE_CAP) {
38170
+ return {
38171
+ ok: false,
38172
+ error: `max_events_per_hour must be an integer from 1 to ${WEBHOOK_MAX_RATE_CAP}`
38173
+ };
38174
+ }
38175
+ out["max_events_per_hour"] = cap;
38176
+ } else {
38177
+ out["max_events_per_hour"] = WEBHOOK_DEFAULT_RATE_CAP;
38178
+ }
38179
+ return { ok: true, config: out };
38180
+ }
38181
+ function webhookRateCap(trigger) {
38182
+ const cap = trigger.config["max_events_per_hour"];
38183
+ if (typeof cap === "number" && Number.isInteger(cap) && cap >= 1) {
38184
+ return Math.min(cap, WEBHOOK_MAX_RATE_CAP);
38185
+ }
38186
+ return WEBHOOK_DEFAULT_RATE_CAP;
38187
+ }
38188
+ function buildWebhookEvent(req, config2, now = /* @__PURE__ */ new Date()) {
38189
+ const preset = resolvePreset(config2);
38190
+ const body = req.body;
38191
+ const raw = req.rawBody ?? JSON.stringify(body ?? null);
38192
+ const idValue = preset.dedupPath ? scalarString(readPath(body, preset.dedupPath)) : null;
38193
+ const dedupKey = idValue ? `wh:id:${stableHash(idValue)}` : `wh:raw:${stableHash(raw)}`;
38194
+ const typeParts = (preset.eventTypePaths ?? []).map((p2) => scalarString(readPath(body, p2))).filter((v) => v !== null).map((v) => v.slice(0, 200));
38195
+ const eventType = typeParts.length > 0 ? typeParts.join(" / ") : "webhook event";
38196
+ const timeValue = preset.timePath ? scalarString(readPath(body, preset.timePath)) : null;
38197
+ const timeMs = timeValue ? Date.parse(timeValue) : NaN;
38198
+ const occurredAt = Number.isFinite(timeMs) ? new Date(timeMs).toISOString() : now.toISOString();
38199
+ let payload = body;
38200
+ if (preset.payloadPath) {
38201
+ const sub = readPath(body, preset.payloadPath);
38202
+ if (sub !== void 0)
38203
+ payload = sub;
38204
+ }
38205
+ const rendered = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2) ?? "null";
38206
+ const lines = [`Event: ${eventType}`];
38207
+ if (idValue)
38208
+ lines.push(`Event id: ${idValue.slice(0, 200)}`);
38209
+ lines.push("", truncate(rendered, WEBHOOK_PROMPT_MAX_CHARS));
38210
+ return {
38211
+ provider: WEBHOOK_TRIGGER_PROVIDER,
38212
+ occurredAt,
38213
+ dedupKey,
38214
+ sourceTrust: "untrusted",
38215
+ title: eventType,
38216
+ body: lines.join("\n"),
38217
+ // Keep the ledger row bounded: the full body when small, else a marker
38218
+ // with the head of it. Never headers (the bearer token rides there).
38219
+ raw: raw.length <= WEBHOOK_RAW_MAX_CHARS ? body : { truncated: true, bytes: raw.length, head: raw.slice(0, WEBHOOK_RAW_MAX_CHARS) },
38220
+ meaningful: true
38221
+ };
38222
+ }
38223
+ var webhookTriggerAdapter = {
38224
+ provider: WEBHOOK_TRIGGER_PROVIDER,
38225
+ kind: "webhook",
38226
+ webhookAuth: "bearer",
38227
+ webhookEvents: [],
38228
+ multiInstance: true,
38229
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
38230
+ validateConfig: validateWebhookConfig,
38231
+ rateCapPerHour: (trigger) => webhookRateCap(trigger),
38232
+ // Webhook-kind triggers are minted only on POST /agents/:id/triggers
38233
+ // (agent.edit); /host/triggers refuses non-poll providers.
38234
+ operatorInstruction: true,
38235
+ ingest(req, trigger) {
38236
+ return [buildWebhookEvent(req, trigger.config)];
38237
+ }
38238
+ };
38239
+ registerTriggerSource(webhookTriggerAdapter);
38240
+
38055
38241
  // ../core/dist/feature-flags/registry.js
38056
38242
  var FLAG_REGISTRY = [
38057
38243
  {