@integrity-labs/agt-cli 0.28.1163 → 0.28.1165

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-QRFACFSH.js → chunk-FGPPJKJ5.js} +3 -3
  3. package/dist/{chunk-DPMVTSFO.js → chunk-MBNPMML4.js} +5 -5
  4. package/dist/{chunk-3DISC7BU.js → chunk-T7NKHOJF.js} +2 -2
  5. package/dist/{chunk-D55RMQTG.js → chunk-TNPLCJIG.js} +179 -2
  6. package/dist/chunk-TNPLCJIG.js.map +1 -0
  7. package/dist/{chunk-CXEP3UC7.js → chunk-ZDHCIJL6.js} +2 -2
  8. package/dist/{claude-code-updater-DXLSLDHW.js → claude-code-updater-EM3AY2PR.js} +3 -3
  9. package/dist/{claude-pair-runtime-BCZPQPWP.js → claude-pair-runtime-P45H3GNC.js} +3 -3
  10. package/dist/lib/manager-worker.js +19 -19
  11. package/dist/mcp/direct-chat-channel.js +180 -3
  12. package/dist/mcp/index.js +182 -5
  13. package/dist/mcp/origami.js +180 -3
  14. package/dist/mcp/slack-channel.js +180 -3
  15. package/dist/mcp/telegram-channel.js +180 -3
  16. package/dist/{persistent-session-XCV7VQWS.js → persistent-session-KSV7RIQQ.js} +4 -4
  17. package/dist/{responsiveness-probe-WZVS3U5H.js → responsiveness-probe-XVYYSQQN.js} +4 -4
  18. package/dist/{session-auth-dead-AR7G7XZZ.js → session-auth-dead-KMMDVC5E.js} +3 -3
  19. package/package.json +1 -1
  20. package/dist/chunk-D55RMQTG.js.map +0 -1
  21. /package/dist/{chunk-QRFACFSH.js.map → chunk-FGPPJKJ5.js.map} +0 -0
  22. /package/dist/{chunk-DPMVTSFO.js.map → chunk-MBNPMML4.js.map} +0 -0
  23. /package/dist/{chunk-3DISC7BU.js.map → chunk-T7NKHOJF.js.map} +0 -0
  24. /package/dist/{chunk-CXEP3UC7.js.map → chunk-ZDHCIJL6.js.map} +0 -0
  25. /package/dist/{claude-code-updater-DXLSLDHW.js.map → claude-code-updater-EM3AY2PR.js.map} +0 -0
  26. /package/dist/{claude-pair-runtime-BCZPQPWP.js.map → claude-pair-runtime-P45H3GNC.js.map} +0 -0
  27. /package/dist/{persistent-session-XCV7VQWS.js.map → persistent-session-KSV7RIQQ.js.map} +0 -0
  28. /package/dist/{responsiveness-probe-WZVS3U5H.js.map → responsiveness-probe-XVYYSQQN.js.map} +0 -0
  29. /package/dist/{session-auth-dead-AR7G7XZZ.js.map → session-auth-dead-KMMDVC5E.js.map} +0 -0
@@ -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();
@@ -43225,6 +43225,183 @@ var videoRenderTriggerAdapter = {
43225
43225
  };
43226
43226
  registerTriggerSource(videoRenderTriggerAdapter);
43227
43227
 
43228
+ // ../core/dist/triggers/adapters/webhook.js
43229
+ var WEBHOOK_TRIGGER_PROVIDER = "webhook";
43230
+ var WEBHOOK_MAX_BODY_BYTES = 1280 * 1024;
43231
+ var WEBHOOK_PROMPT_MAX_CHARS = 8e3;
43232
+ var WEBHOOK_RAW_MAX_CHARS = 64 * 1024;
43233
+ var WEBHOOK_INSTRUCTION_MAX_CHARS = 2e3;
43234
+ var WEBHOOK_NAME_MAX_CHARS = 80;
43235
+ var WEBHOOK_DEFAULT_RATE_CAP = 60;
43236
+ var WEBHOOK_MAX_RATE_CAP = 1e3;
43237
+ var WEBHOOK_PRESETS = {
43238
+ // https://docs.aws.amazon.com/eventbridge/latest/ref/overiew-event-structure.html
43239
+ eventbridge: {
43240
+ dedupPath: "id",
43241
+ eventTypePaths: ["source", "detail-type"],
43242
+ payloadPath: "detail",
43243
+ timePath: "time"
43244
+ },
43245
+ // Raw-body hash dedup, whole body as payload. Set dedup_path when the
43246
+ // sender has a stable id, or two identical bodies collapse into one.
43247
+ generic: {}
43248
+ };
43249
+ var PATH_RE = /^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+){0,9}$/;
43250
+ function readPath(value, path) {
43251
+ let cur = value;
43252
+ for (const key of path.split(".")) {
43253
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur))
43254
+ return void 0;
43255
+ if (!Object.prototype.hasOwnProperty.call(cur, key))
43256
+ return void 0;
43257
+ cur = cur[key];
43258
+ }
43259
+ return cur;
43260
+ }
43261
+ function scalarString(v) {
43262
+ if (typeof v === "string")
43263
+ return v.length > 0 ? v : null;
43264
+ if (typeof v === "number" && Number.isFinite(v))
43265
+ return String(v);
43266
+ return null;
43267
+ }
43268
+ function truncate(text, max) {
43269
+ if (text.length <= max)
43270
+ return text;
43271
+ return `${text.slice(0, max)}
43272
+ ... [truncated ${text.length - max} more characters]`;
43273
+ }
43274
+ function resolvePreset(config2) {
43275
+ const name = config2["preset"];
43276
+ const base = typeof name === "string" && name in WEBHOOK_PRESETS ? WEBHOOK_PRESETS[name] : WEBHOOK_PRESETS.generic;
43277
+ const dedup = config2["dedup_path"];
43278
+ const type = config2["event_type_path"];
43279
+ const payload = config2["payload_path"];
43280
+ return {
43281
+ ...base,
43282
+ ...typeof dedup === "string" && dedup ? { dedupPath: dedup } : {},
43283
+ ...typeof type === "string" && type ? { eventTypePaths: [type] } : {},
43284
+ ...typeof payload === "string" && payload ? { payloadPath: payload } : {}
43285
+ };
43286
+ }
43287
+ function validateWebhookConfig(input) {
43288
+ const out = {};
43289
+ const name = input["name"];
43290
+ if (name !== void 0) {
43291
+ if (typeof name !== "string")
43292
+ return { ok: false, error: "name must be a string" };
43293
+ const trimmed = name.trim();
43294
+ if (trimmed.length > WEBHOOK_NAME_MAX_CHARS) {
43295
+ return { ok: false, error: `name must be at most ${WEBHOOK_NAME_MAX_CHARS} characters` };
43296
+ }
43297
+ if (trimmed)
43298
+ out["name"] = trimmed;
43299
+ }
43300
+ const instruction = input["instruction"];
43301
+ if (typeof instruction !== "string" || !instruction.trim()) {
43302
+ return {
43303
+ ok: false,
43304
+ error: "instruction is required: tell the agent what to do when an event arrives"
43305
+ };
43306
+ }
43307
+ if (instruction.trim().length > WEBHOOK_INSTRUCTION_MAX_CHARS) {
43308
+ return {
43309
+ ok: false,
43310
+ error: `instruction must be at most ${WEBHOOK_INSTRUCTION_MAX_CHARS} characters`
43311
+ };
43312
+ }
43313
+ out["instruction"] = instruction.trim();
43314
+ const preset = input["preset"] ?? "generic";
43315
+ if (typeof preset !== "string" || !(preset in WEBHOOK_PRESETS)) {
43316
+ return {
43317
+ ok: false,
43318
+ error: `preset must be one of: ${Object.keys(WEBHOOK_PRESETS).join(", ")}`
43319
+ };
43320
+ }
43321
+ out["preset"] = preset;
43322
+ for (const key of ["dedup_path", "event_type_path", "payload_path"]) {
43323
+ const v = input[key];
43324
+ if (v === void 0 || v === null || v === "")
43325
+ continue;
43326
+ if (typeof v !== "string" || !PATH_RE.test(v)) {
43327
+ return { ok: false, error: `${key} must be a dot path like "detail.id"` };
43328
+ }
43329
+ out[key] = v;
43330
+ }
43331
+ const cap = input["max_events_per_hour"];
43332
+ if (cap !== void 0 && cap !== null) {
43333
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1 || cap > WEBHOOK_MAX_RATE_CAP) {
43334
+ return {
43335
+ ok: false,
43336
+ error: `max_events_per_hour must be an integer from 1 to ${WEBHOOK_MAX_RATE_CAP}`
43337
+ };
43338
+ }
43339
+ out["max_events_per_hour"] = cap;
43340
+ } else {
43341
+ out["max_events_per_hour"] = WEBHOOK_DEFAULT_RATE_CAP;
43342
+ }
43343
+ return { ok: true, config: out };
43344
+ }
43345
+ function webhookRateCap(trigger) {
43346
+ const cap = trigger.config["max_events_per_hour"];
43347
+ if (typeof cap === "number" && Number.isInteger(cap) && cap >= 1) {
43348
+ return Math.min(cap, WEBHOOK_MAX_RATE_CAP);
43349
+ }
43350
+ return WEBHOOK_DEFAULT_RATE_CAP;
43351
+ }
43352
+ function buildWebhookEvent(req, config2, now = /* @__PURE__ */ new Date()) {
43353
+ const preset = resolvePreset(config2);
43354
+ const body = req.body;
43355
+ const raw = req.rawBody ?? JSON.stringify(body ?? null);
43356
+ const idValue = preset.dedupPath ? scalarString(readPath(body, preset.dedupPath)) : null;
43357
+ const dedupKey = idValue ? `wh:id:${stableHash(idValue)}` : `wh:raw:${stableHash(raw)}`;
43358
+ const typeParts = (preset.eventTypePaths ?? []).map((p2) => scalarString(readPath(body, p2))).filter((v) => v !== null).map((v) => v.slice(0, 200));
43359
+ const eventType = typeParts.length > 0 ? typeParts.join(" / ") : "webhook event";
43360
+ const timeValue = preset.timePath ? scalarString(readPath(body, preset.timePath)) : null;
43361
+ const timeMs = timeValue ? Date.parse(timeValue) : NaN;
43362
+ const occurredAt = Number.isFinite(timeMs) ? new Date(timeMs).toISOString() : now.toISOString();
43363
+ let payload = body;
43364
+ if (preset.payloadPath) {
43365
+ const sub = readPath(body, preset.payloadPath);
43366
+ if (sub !== void 0)
43367
+ payload = sub;
43368
+ }
43369
+ const rendered = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2) ?? "null";
43370
+ const lines = [`Event: ${eventType}`];
43371
+ if (idValue)
43372
+ lines.push(`Event id: ${idValue.slice(0, 200)}`);
43373
+ lines.push("", truncate(rendered, WEBHOOK_PROMPT_MAX_CHARS));
43374
+ return {
43375
+ provider: WEBHOOK_TRIGGER_PROVIDER,
43376
+ occurredAt,
43377
+ dedupKey,
43378
+ sourceTrust: "untrusted",
43379
+ title: eventType,
43380
+ body: lines.join("\n"),
43381
+ // Keep the ledger row bounded: the full body when small, else a marker
43382
+ // with the head of it. Never headers (the bearer token rides there).
43383
+ raw: raw.length <= WEBHOOK_RAW_MAX_CHARS ? body : { truncated: true, bytes: raw.length, head: raw.slice(0, WEBHOOK_RAW_MAX_CHARS) },
43384
+ meaningful: true
43385
+ };
43386
+ }
43387
+ var webhookTriggerAdapter = {
43388
+ provider: WEBHOOK_TRIGGER_PROVIDER,
43389
+ kind: "webhook",
43390
+ webhookAuth: "bearer",
43391
+ webhookEvents: [],
43392
+ multiInstance: true,
43393
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
43394
+ validateConfig: validateWebhookConfig,
43395
+ rateCapPerHour: (trigger) => webhookRateCap(trigger),
43396
+ // Webhook-kind triggers are minted only on POST /agents/:id/triggers
43397
+ // (agent.edit); /host/triggers refuses non-poll providers.
43398
+ operatorInstruction: true,
43399
+ ingest(req, trigger) {
43400
+ return [buildWebhookEvent(req, trigger.config)];
43401
+ }
43402
+ };
43403
+ registerTriggerSource(webhookTriggerAdapter);
43404
+
43228
43405
  // ../core/dist/feature-flags/registry.js
43229
43406
  var FLAG_REGISTRY = [
43230
43407
  {
@@ -44986,7 +45163,7 @@ var FLAG_REGISTRY = [
44986
45163
  },
44987
45164
  {
44988
45165
  key: "ninja-lists",
44989
- description: 'Ninja Lists (ADR-0120): small tables agents and people fill and review together. Gates the "Lists" nav item, the /lists pages AND the /ninja-lists API, per org. Unlike its siblings `projects-menu` / `ninjafy-notes-menu`, this is the whole feature\'s gate, not only its menu entry: the surface is unlaunched, so an org with the flag off gets 404 from the API rather than a hidden link to a working one.',
45166
+ description: 'Apps, formerly Ninja Lists (ADR-0120): small tables agents and people fill and review together. Gates the "Apps" nav item, the /apps pages AND the /ninja-lists API, per org. Unlike its siblings `projects-menu` / `ninjafy-notes-menu`, this is the whole feature\'s gate, not only its menu entry: the surface is unlaunched, so an org with the flag off gets 404 from the API rather than a hidden link to a working one.',
44990
45167
  flagType: "boolean",
44991
45168
  // PUBLIC (ADR-0022 §2): the nav shells read it via usePublicBooleanFlag and
44992
45169
  // the pages via getPublicBooleanFlagServer, so it is serialized to the
@@ -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();
@@ -38052,6 +38052,183 @@ var videoRenderTriggerAdapter = {
38052
38052
  };
38053
38053
  registerTriggerSource(videoRenderTriggerAdapter);
38054
38054
 
38055
+ // ../core/dist/triggers/adapters/webhook.js
38056
+ var WEBHOOK_TRIGGER_PROVIDER = "webhook";
38057
+ var WEBHOOK_MAX_BODY_BYTES = 1280 * 1024;
38058
+ var WEBHOOK_PROMPT_MAX_CHARS = 8e3;
38059
+ var WEBHOOK_RAW_MAX_CHARS = 64 * 1024;
38060
+ var WEBHOOK_INSTRUCTION_MAX_CHARS = 2e3;
38061
+ var WEBHOOK_NAME_MAX_CHARS = 80;
38062
+ var WEBHOOK_DEFAULT_RATE_CAP = 60;
38063
+ var WEBHOOK_MAX_RATE_CAP = 1e3;
38064
+ var WEBHOOK_PRESETS = {
38065
+ // https://docs.aws.amazon.com/eventbridge/latest/ref/overiew-event-structure.html
38066
+ eventbridge: {
38067
+ dedupPath: "id",
38068
+ eventTypePaths: ["source", "detail-type"],
38069
+ payloadPath: "detail",
38070
+ timePath: "time"
38071
+ },
38072
+ // Raw-body hash dedup, whole body as payload. Set dedup_path when the
38073
+ // sender has a stable id, or two identical bodies collapse into one.
38074
+ generic: {}
38075
+ };
38076
+ var PATH_RE = /^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+){0,9}$/;
38077
+ function readPath(value, path) {
38078
+ let cur = value;
38079
+ for (const key2 of path.split(".")) {
38080
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur))
38081
+ return void 0;
38082
+ if (!Object.prototype.hasOwnProperty.call(cur, key2))
38083
+ return void 0;
38084
+ cur = cur[key2];
38085
+ }
38086
+ return cur;
38087
+ }
38088
+ function scalarString(v) {
38089
+ if (typeof v === "string")
38090
+ return v.length > 0 ? v : null;
38091
+ if (typeof v === "number" && Number.isFinite(v))
38092
+ return String(v);
38093
+ return null;
38094
+ }
38095
+ function truncate(text, max) {
38096
+ if (text.length <= max)
38097
+ return text;
38098
+ return `${text.slice(0, max)}
38099
+ ... [truncated ${text.length - max} more characters]`;
38100
+ }
38101
+ function resolvePreset(config2) {
38102
+ const name = config2["preset"];
38103
+ const base = typeof name === "string" && name in WEBHOOK_PRESETS ? WEBHOOK_PRESETS[name] : WEBHOOK_PRESETS.generic;
38104
+ const dedup = config2["dedup_path"];
38105
+ const type = config2["event_type_path"];
38106
+ const payload = config2["payload_path"];
38107
+ return {
38108
+ ...base,
38109
+ ...typeof dedup === "string" && dedup ? { dedupPath: dedup } : {},
38110
+ ...typeof type === "string" && type ? { eventTypePaths: [type] } : {},
38111
+ ...typeof payload === "string" && payload ? { payloadPath: payload } : {}
38112
+ };
38113
+ }
38114
+ function validateWebhookConfig(input) {
38115
+ const out = {};
38116
+ const name = input["name"];
38117
+ if (name !== void 0) {
38118
+ if (typeof name !== "string")
38119
+ return { ok: false, error: "name must be a string" };
38120
+ const trimmed = name.trim();
38121
+ if (trimmed.length > WEBHOOK_NAME_MAX_CHARS) {
38122
+ return { ok: false, error: `name must be at most ${WEBHOOK_NAME_MAX_CHARS} characters` };
38123
+ }
38124
+ if (trimmed)
38125
+ out["name"] = trimmed;
38126
+ }
38127
+ const instruction = input["instruction"];
38128
+ if (typeof instruction !== "string" || !instruction.trim()) {
38129
+ return {
38130
+ ok: false,
38131
+ error: "instruction is required: tell the agent what to do when an event arrives"
38132
+ };
38133
+ }
38134
+ if (instruction.trim().length > WEBHOOK_INSTRUCTION_MAX_CHARS) {
38135
+ return {
38136
+ ok: false,
38137
+ error: `instruction must be at most ${WEBHOOK_INSTRUCTION_MAX_CHARS} characters`
38138
+ };
38139
+ }
38140
+ out["instruction"] = instruction.trim();
38141
+ const preset = input["preset"] ?? "generic";
38142
+ if (typeof preset !== "string" || !(preset in WEBHOOK_PRESETS)) {
38143
+ return {
38144
+ ok: false,
38145
+ error: `preset must be one of: ${Object.keys(WEBHOOK_PRESETS).join(", ")}`
38146
+ };
38147
+ }
38148
+ out["preset"] = preset;
38149
+ for (const key2 of ["dedup_path", "event_type_path", "payload_path"]) {
38150
+ const v = input[key2];
38151
+ if (v === void 0 || v === null || v === "")
38152
+ continue;
38153
+ if (typeof v !== "string" || !PATH_RE.test(v)) {
38154
+ return { ok: false, error: `${key2} must be a dot path like "detail.id"` };
38155
+ }
38156
+ out[key2] = v;
38157
+ }
38158
+ const cap = input["max_events_per_hour"];
38159
+ if (cap !== void 0 && cap !== null) {
38160
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1 || cap > WEBHOOK_MAX_RATE_CAP) {
38161
+ return {
38162
+ ok: false,
38163
+ error: `max_events_per_hour must be an integer from 1 to ${WEBHOOK_MAX_RATE_CAP}`
38164
+ };
38165
+ }
38166
+ out["max_events_per_hour"] = cap;
38167
+ } else {
38168
+ out["max_events_per_hour"] = WEBHOOK_DEFAULT_RATE_CAP;
38169
+ }
38170
+ return { ok: true, config: out };
38171
+ }
38172
+ function webhookRateCap(trigger) {
38173
+ const cap = trigger.config["max_events_per_hour"];
38174
+ if (typeof cap === "number" && Number.isInteger(cap) && cap >= 1) {
38175
+ return Math.min(cap, WEBHOOK_MAX_RATE_CAP);
38176
+ }
38177
+ return WEBHOOK_DEFAULT_RATE_CAP;
38178
+ }
38179
+ function buildWebhookEvent(req, config2, now = /* @__PURE__ */ new Date()) {
38180
+ const preset = resolvePreset(config2);
38181
+ const body = req.body;
38182
+ const raw = req.rawBody ?? JSON.stringify(body ?? null);
38183
+ const idValue = preset.dedupPath ? scalarString(readPath(body, preset.dedupPath)) : null;
38184
+ const dedupKey = idValue ? `wh:id:${stableHash(idValue)}` : `wh:raw:${stableHash(raw)}`;
38185
+ const typeParts = (preset.eventTypePaths ?? []).map((p2) => scalarString(readPath(body, p2))).filter((v) => v !== null).map((v) => v.slice(0, 200));
38186
+ const eventType = typeParts.length > 0 ? typeParts.join(" / ") : "webhook event";
38187
+ const timeValue = preset.timePath ? scalarString(readPath(body, preset.timePath)) : null;
38188
+ const timeMs = timeValue ? Date.parse(timeValue) : NaN;
38189
+ const occurredAt = Number.isFinite(timeMs) ? new Date(timeMs).toISOString() : now.toISOString();
38190
+ let payload = body;
38191
+ if (preset.payloadPath) {
38192
+ const sub = readPath(body, preset.payloadPath);
38193
+ if (sub !== void 0)
38194
+ payload = sub;
38195
+ }
38196
+ const rendered = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2) ?? "null";
38197
+ const lines = [`Event: ${eventType}`];
38198
+ if (idValue)
38199
+ lines.push(`Event id: ${idValue.slice(0, 200)}`);
38200
+ lines.push("", truncate(rendered, WEBHOOK_PROMPT_MAX_CHARS));
38201
+ return {
38202
+ provider: WEBHOOK_TRIGGER_PROVIDER,
38203
+ occurredAt,
38204
+ dedupKey,
38205
+ sourceTrust: "untrusted",
38206
+ title: eventType,
38207
+ body: lines.join("\n"),
38208
+ // Keep the ledger row bounded: the full body when small, else a marker
38209
+ // with the head of it. Never headers (the bearer token rides there).
38210
+ raw: raw.length <= WEBHOOK_RAW_MAX_CHARS ? body : { truncated: true, bytes: raw.length, head: raw.slice(0, WEBHOOK_RAW_MAX_CHARS) },
38211
+ meaningful: true
38212
+ };
38213
+ }
38214
+ var webhookTriggerAdapter = {
38215
+ provider: WEBHOOK_TRIGGER_PROVIDER,
38216
+ kind: "webhook",
38217
+ webhookAuth: "bearer",
38218
+ webhookEvents: [],
38219
+ multiInstance: true,
38220
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
38221
+ validateConfig: validateWebhookConfig,
38222
+ rateCapPerHour: (trigger) => webhookRateCap(trigger),
38223
+ // Webhook-kind triggers are minted only on POST /agents/:id/triggers
38224
+ // (agent.edit); /host/triggers refuses non-poll providers.
38225
+ operatorInstruction: true,
38226
+ ingest(req, trigger) {
38227
+ return [buildWebhookEvent(req, trigger.config)];
38228
+ }
38229
+ };
38230
+ registerTriggerSource(webhookTriggerAdapter);
38231
+
38055
38232
  // ../core/dist/feature-flags/registry.js
38056
38233
  var FLAG_REGISTRY = [
38057
38234
  {
@@ -39813,7 +39990,7 @@ var FLAG_REGISTRY = [
39813
39990
  },
39814
39991
  {
39815
39992
  key: "ninja-lists",
39816
- description: 'Ninja Lists (ADR-0120): small tables agents and people fill and review together. Gates the "Lists" nav item, the /lists pages AND the /ninja-lists API, per org. Unlike its siblings `projects-menu` / `ninjafy-notes-menu`, this is the whole feature\'s gate, not only its menu entry: the surface is unlaunched, so an org with the flag off gets 404 from the API rather than a hidden link to a working one.',
39993
+ description: 'Apps, formerly Ninja Lists (ADR-0120): small tables agents and people fill and review together. Gates the "Apps" nav item, the /apps pages AND the /ninja-lists API, per org. Unlike its siblings `projects-menu` / `ninjafy-notes-menu`, this is the whole feature\'s gate, not only its menu entry: the surface is unlaunched, so an org with the flag off gets 404 from the API rather than a hidden link to a working one.',
39817
39994
  flagType: "boolean",
39818
39995
  // PUBLIC (ADR-0022 §2): the nav shells read it via usePublicBooleanFlag and
39819
39996
  // the pages via getPublicBooleanFlagServer, so it is serialized to the
@@ -19182,7 +19182,7 @@ var require_filters = __commonJS({
19182
19182
  return r.copySafeness(str, str.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(str) {
19206
19206
  str = normalize(str, "");
19207
19207
  return str.toUpperCase();
@@ -38263,6 +38263,183 @@ var videoRenderTriggerAdapter = {
38263
38263
  };
38264
38264
  registerTriggerSource(videoRenderTriggerAdapter);
38265
38265
 
38266
+ // ../core/dist/triggers/adapters/webhook.js
38267
+ var WEBHOOK_TRIGGER_PROVIDER = "webhook";
38268
+ var WEBHOOK_MAX_BODY_BYTES = 1280 * 1024;
38269
+ var WEBHOOK_PROMPT_MAX_CHARS = 8e3;
38270
+ var WEBHOOK_RAW_MAX_CHARS = 64 * 1024;
38271
+ var WEBHOOK_INSTRUCTION_MAX_CHARS = 2e3;
38272
+ var WEBHOOK_NAME_MAX_CHARS = 80;
38273
+ var WEBHOOK_DEFAULT_RATE_CAP = 60;
38274
+ var WEBHOOK_MAX_RATE_CAP = 1e3;
38275
+ var WEBHOOK_PRESETS = {
38276
+ // https://docs.aws.amazon.com/eventbridge/latest/ref/overiew-event-structure.html
38277
+ eventbridge: {
38278
+ dedupPath: "id",
38279
+ eventTypePaths: ["source", "detail-type"],
38280
+ payloadPath: "detail",
38281
+ timePath: "time"
38282
+ },
38283
+ // Raw-body hash dedup, whole body as payload. Set dedup_path when the
38284
+ // sender has a stable id, or two identical bodies collapse into one.
38285
+ generic: {}
38286
+ };
38287
+ var PATH_RE = /^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+){0,9}$/;
38288
+ function readPath(value, path) {
38289
+ let cur = value;
38290
+ for (const key2 of path.split(".")) {
38291
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur))
38292
+ return void 0;
38293
+ if (!Object.prototype.hasOwnProperty.call(cur, key2))
38294
+ return void 0;
38295
+ cur = cur[key2];
38296
+ }
38297
+ return cur;
38298
+ }
38299
+ function scalarString(v) {
38300
+ if (typeof v === "string")
38301
+ return v.length > 0 ? v : null;
38302
+ if (typeof v === "number" && Number.isFinite(v))
38303
+ return String(v);
38304
+ return null;
38305
+ }
38306
+ function truncate(text, max) {
38307
+ if (text.length <= max)
38308
+ return text;
38309
+ return `${text.slice(0, max)}
38310
+ ... [truncated ${text.length - max} more characters]`;
38311
+ }
38312
+ function resolvePreset(config2) {
38313
+ const name = config2["preset"];
38314
+ const base = typeof name === "string" && name in WEBHOOK_PRESETS ? WEBHOOK_PRESETS[name] : WEBHOOK_PRESETS.generic;
38315
+ const dedup = config2["dedup_path"];
38316
+ const type = config2["event_type_path"];
38317
+ const payload = config2["payload_path"];
38318
+ return {
38319
+ ...base,
38320
+ ...typeof dedup === "string" && dedup ? { dedupPath: dedup } : {},
38321
+ ...typeof type === "string" && type ? { eventTypePaths: [type] } : {},
38322
+ ...typeof payload === "string" && payload ? { payloadPath: payload } : {}
38323
+ };
38324
+ }
38325
+ function validateWebhookConfig(input) {
38326
+ const out = {};
38327
+ const name = input["name"];
38328
+ if (name !== void 0) {
38329
+ if (typeof name !== "string")
38330
+ return { ok: false, error: "name must be a string" };
38331
+ const trimmed = name.trim();
38332
+ if (trimmed.length > WEBHOOK_NAME_MAX_CHARS) {
38333
+ return { ok: false, error: `name must be at most ${WEBHOOK_NAME_MAX_CHARS} characters` };
38334
+ }
38335
+ if (trimmed)
38336
+ out["name"] = trimmed;
38337
+ }
38338
+ const instruction = input["instruction"];
38339
+ if (typeof instruction !== "string" || !instruction.trim()) {
38340
+ return {
38341
+ ok: false,
38342
+ error: "instruction is required: tell the agent what to do when an event arrives"
38343
+ };
38344
+ }
38345
+ if (instruction.trim().length > WEBHOOK_INSTRUCTION_MAX_CHARS) {
38346
+ return {
38347
+ ok: false,
38348
+ error: `instruction must be at most ${WEBHOOK_INSTRUCTION_MAX_CHARS} characters`
38349
+ };
38350
+ }
38351
+ out["instruction"] = instruction.trim();
38352
+ const preset = input["preset"] ?? "generic";
38353
+ if (typeof preset !== "string" || !(preset in WEBHOOK_PRESETS)) {
38354
+ return {
38355
+ ok: false,
38356
+ error: `preset must be one of: ${Object.keys(WEBHOOK_PRESETS).join(", ")}`
38357
+ };
38358
+ }
38359
+ out["preset"] = preset;
38360
+ for (const key2 of ["dedup_path", "event_type_path", "payload_path"]) {
38361
+ const v = input[key2];
38362
+ if (v === void 0 || v === null || v === "")
38363
+ continue;
38364
+ if (typeof v !== "string" || !PATH_RE.test(v)) {
38365
+ return { ok: false, error: `${key2} must be a dot path like "detail.id"` };
38366
+ }
38367
+ out[key2] = v;
38368
+ }
38369
+ const cap = input["max_events_per_hour"];
38370
+ if (cap !== void 0 && cap !== null) {
38371
+ if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1 || cap > WEBHOOK_MAX_RATE_CAP) {
38372
+ return {
38373
+ ok: false,
38374
+ error: `max_events_per_hour must be an integer from 1 to ${WEBHOOK_MAX_RATE_CAP}`
38375
+ };
38376
+ }
38377
+ out["max_events_per_hour"] = cap;
38378
+ } else {
38379
+ out["max_events_per_hour"] = WEBHOOK_DEFAULT_RATE_CAP;
38380
+ }
38381
+ return { ok: true, config: out };
38382
+ }
38383
+ function webhookRateCap(trigger) {
38384
+ const cap = trigger.config["max_events_per_hour"];
38385
+ if (typeof cap === "number" && Number.isInteger(cap) && cap >= 1) {
38386
+ return Math.min(cap, WEBHOOK_MAX_RATE_CAP);
38387
+ }
38388
+ return WEBHOOK_DEFAULT_RATE_CAP;
38389
+ }
38390
+ function buildWebhookEvent(req, config2, now = /* @__PURE__ */ new Date()) {
38391
+ const preset = resolvePreset(config2);
38392
+ const body = req.body;
38393
+ const raw = req.rawBody ?? JSON.stringify(body ?? null);
38394
+ const idValue = preset.dedupPath ? scalarString(readPath(body, preset.dedupPath)) : null;
38395
+ const dedupKey = idValue ? `wh:id:${stableHash(idValue)}` : `wh:raw:${stableHash(raw)}`;
38396
+ const typeParts = (preset.eventTypePaths ?? []).map((p2) => scalarString(readPath(body, p2))).filter((v) => v !== null).map((v) => v.slice(0, 200));
38397
+ const eventType = typeParts.length > 0 ? typeParts.join(" / ") : "webhook event";
38398
+ const timeValue = preset.timePath ? scalarString(readPath(body, preset.timePath)) : null;
38399
+ const timeMs = timeValue ? Date.parse(timeValue) : NaN;
38400
+ const occurredAt = Number.isFinite(timeMs) ? new Date(timeMs).toISOString() : now.toISOString();
38401
+ let payload = body;
38402
+ if (preset.payloadPath) {
38403
+ const sub = readPath(body, preset.payloadPath);
38404
+ if (sub !== void 0)
38405
+ payload = sub;
38406
+ }
38407
+ const rendered = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2) ?? "null";
38408
+ const lines = [`Event: ${eventType}`];
38409
+ if (idValue)
38410
+ lines.push(`Event id: ${idValue.slice(0, 200)}`);
38411
+ lines.push("", truncate(rendered, WEBHOOK_PROMPT_MAX_CHARS));
38412
+ return {
38413
+ provider: WEBHOOK_TRIGGER_PROVIDER,
38414
+ occurredAt,
38415
+ dedupKey,
38416
+ sourceTrust: "untrusted",
38417
+ title: eventType,
38418
+ body: lines.join("\n"),
38419
+ // Keep the ledger row bounded: the full body when small, else a marker
38420
+ // with the head of it. Never headers (the bearer token rides there).
38421
+ raw: raw.length <= WEBHOOK_RAW_MAX_CHARS ? body : { truncated: true, bytes: raw.length, head: raw.slice(0, WEBHOOK_RAW_MAX_CHARS) },
38422
+ meaningful: true
38423
+ };
38424
+ }
38425
+ var webhookTriggerAdapter = {
38426
+ provider: WEBHOOK_TRIGGER_PROVIDER,
38427
+ kind: "webhook",
38428
+ webhookAuth: "bearer",
38429
+ webhookEvents: [],
38430
+ multiInstance: true,
38431
+ maxBodyBytes: WEBHOOK_MAX_BODY_BYTES,
38432
+ validateConfig: validateWebhookConfig,
38433
+ rateCapPerHour: (trigger) => webhookRateCap(trigger),
38434
+ // Webhook-kind triggers are minted only on POST /agents/:id/triggers
38435
+ // (agent.edit); /host/triggers refuses non-poll providers.
38436
+ operatorInstruction: true,
38437
+ ingest(req, trigger) {
38438
+ return [buildWebhookEvent(req, trigger.config)];
38439
+ }
38440
+ };
38441
+ registerTriggerSource(webhookTriggerAdapter);
38442
+
38266
38443
  // ../core/dist/feature-flags/registry.js
38267
38444
  var FLAG_REGISTRY = [
38268
38445
  {
@@ -40024,7 +40201,7 @@ var FLAG_REGISTRY = [
40024
40201
  },
40025
40202
  {
40026
40203
  key: "ninja-lists",
40027
- description: 'Ninja Lists (ADR-0120): small tables agents and people fill and review together. Gates the "Lists" nav item, the /lists pages AND the /ninja-lists API, per org. Unlike its siblings `projects-menu` / `ninjafy-notes-menu`, this is the whole feature\'s gate, not only its menu entry: the surface is unlaunched, so an org with the flag off gets 404 from the API rather than a hidden link to a working one.',
40204
+ description: 'Apps, formerly Ninja Lists (ADR-0120): small tables agents and people fill and review together. Gates the "Apps" nav item, the /apps pages AND the /ninja-lists API, per org. Unlike its siblings `projects-menu` / `ninjafy-notes-menu`, this is the whole feature\'s gate, not only its menu entry: the surface is unlaunched, so an org with the flag off gets 404 from the API rather than a hidden link to a working one.',
40028
40205
  flagType: "boolean",
40029
40206
  // PUBLIC (ADR-0022 §2): the nav shells read it via usePublicBooleanFlag and
40030
40207
  // the pages via getPublicBooleanFlagServer, so it is serialized to the
@@ -68,12 +68,12 @@ import {
68
68
  writeDirectChatSessionState,
69
69
  writeEgressAllowlist,
70
70
  writePersistentClaudeWrapper
71
- } from "./chunk-QRFACFSH.js";
72
- import "./chunk-CXEP3UC7.js";
71
+ } from "./chunk-FGPPJKJ5.js";
72
+ import "./chunk-ZDHCIJL6.js";
73
73
  import "./chunk-B6UYVEMD.js";
74
74
  import "./chunk-OAWK4OBN.js";
75
75
  import "./chunk-XWVM4KPK.js";
76
- import "./chunk-D55RMQTG.js";
76
+ import "./chunk-TNPLCJIG.js";
77
77
  import "./chunk-EL5MWGGH.js";
78
78
  import "./chunk-DGUM43GV.js";
79
79
  export {
@@ -147,4 +147,4 @@ export {
147
147
  writeEgressAllowlist,
148
148
  writePersistentClaudeWrapper
149
149
  };
150
- //# sourceMappingURL=persistent-session-XCV7VQWS.js.map
150
+ //# sourceMappingURL=persistent-session-KSV7RIQQ.js.map
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-QRFACFSH.js";
4
- import "./chunk-CXEP3UC7.js";
3
+ } from "./chunk-FGPPJKJ5.js";
4
+ import "./chunk-ZDHCIJL6.js";
5
5
  import "./chunk-B6UYVEMD.js";
6
6
  import "./chunk-OAWK4OBN.js";
7
7
  import "./chunk-XWVM4KPK.js";
8
- import "./chunk-D55RMQTG.js";
8
+ import "./chunk-TNPLCJIG.js";
9
9
  import "./chunk-EL5MWGGH.js";
10
10
  import "./chunk-DGUM43GV.js";
11
11
 
@@ -804,4 +804,4 @@ export {
804
804
  readAndResetSlackReplyBindingClassifications,
805
805
  readAndResetSlackReplyTargetClassifications
806
806
  };
807
- //# sourceMappingURL=responsiveness-probe-WZVS3U5H.js.map
807
+ //# sourceMappingURL=responsiveness-probe-XVYYSQQN.js.map