hivenet 0.4.1 → 0.6.0

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.
@@ -1389,10 +1389,10 @@ function mergeDefs(...defs) {
1389
1389
  function cloneDef(schema) {
1390
1390
  return mergeDefs(schema._zod.def);
1391
1391
  }
1392
- function getElementAtPath(obj, path5) {
1393
- if (!path5)
1392
+ function getElementAtPath(obj, path6) {
1393
+ if (!path6)
1394
1394
  return obj;
1395
- return path5.reduce((acc, key) => acc?.[key], obj);
1395
+ return path6.reduce((acc, key) => acc?.[key], obj);
1396
1396
  }
1397
1397
  function promiseAllObject(promisesObj) {
1398
1398
  const keys = Object.keys(promisesObj);
@@ -1801,11 +1801,11 @@ function explicitlyAborted(x, startIndex = 0) {
1801
1801
  }
1802
1802
  return false;
1803
1803
  }
1804
- function prefixIssues(path5, issues) {
1804
+ function prefixIssues(path6, issues) {
1805
1805
  return issues.map((iss) => {
1806
1806
  var _a3;
1807
1807
  (_a3 = iss).path ?? (_a3.path = []);
1808
- iss.path.unshift(path5);
1808
+ iss.path.unshift(path6);
1809
1809
  return iss;
1810
1810
  });
1811
1811
  }
@@ -1952,16 +1952,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1952
1952
  }
1953
1953
  function formatError(error51, mapper = (issue2) => issue2.message) {
1954
1954
  const fieldErrors = { _errors: [] };
1955
- const processError = (error52, path5 = []) => {
1955
+ const processError = (error52, path6 = []) => {
1956
1956
  for (const issue2 of error52.issues) {
1957
1957
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1958
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
1958
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
1959
1959
  } else if (issue2.code === "invalid_key") {
1960
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1960
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1961
1961
  } else if (issue2.code === "invalid_element") {
1962
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1962
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1963
1963
  } else {
1964
- const fullpath = [...path5, ...issue2.path];
1964
+ const fullpath = [...path6, ...issue2.path];
1965
1965
  if (fullpath.length === 0) {
1966
1966
  fieldErrors._errors.push(mapper(issue2));
1967
1967
  } else {
@@ -1988,17 +1988,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1988
1988
  }
1989
1989
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1990
1990
  const result = { errors: [] };
1991
- const processError = (error52, path5 = []) => {
1991
+ const processError = (error52, path6 = []) => {
1992
1992
  var _a3, _b;
1993
1993
  for (const issue2 of error52.issues) {
1994
1994
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1995
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
1995
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
1996
1996
  } else if (issue2.code === "invalid_key") {
1997
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1997
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1998
1998
  } else if (issue2.code === "invalid_element") {
1999
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1999
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
2000
2000
  } else {
2001
- const fullpath = [...path5, ...issue2.path];
2001
+ const fullpath = [...path6, ...issue2.path];
2002
2002
  if (fullpath.length === 0) {
2003
2003
  result.errors.push(mapper(issue2));
2004
2004
  continue;
@@ -2030,8 +2030,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2030
2030
  }
2031
2031
  function toDotPath(_path) {
2032
2032
  const segs = [];
2033
- const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2034
- for (const seg of path5) {
2033
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2034
+ for (const seg of path6) {
2035
2035
  if (typeof seg === "number")
2036
2036
  segs.push(`[${seg}]`);
2037
2037
  else if (typeof seg === "symbol")
@@ -14723,13 +14723,13 @@ function resolveRef(ref, ctx) {
14723
14723
  if (!ref.startsWith("#")) {
14724
14724
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14725
14725
  }
14726
- const path5 = ref.slice(1).split("/").filter(Boolean);
14727
- if (path5.length === 0) {
14726
+ const path6 = ref.slice(1).split("/").filter(Boolean);
14727
+ if (path6.length === 0) {
14728
14728
  return ctx.rootSchema;
14729
14729
  }
14730
14730
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14731
- if (path5[0] === defsKey) {
14732
- const key = path5[1];
14731
+ if (path6[0] === defsKey) {
14732
+ const key = path6[1];
14733
14733
  if (!key || !ctx.defs[key]) {
14734
14734
  throw new Error(`Reference not found: ${ref}`);
14735
14735
  }
@@ -15138,6 +15138,102 @@ function date4(params) {
15138
15138
  config(en_default());
15139
15139
 
15140
15140
  // ../spec/dist/index.js
15141
+ var MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
15142
+ var MAX_ATTACHMENTS = 10;
15143
+ var MAX_ATTACHMENT_DESCRIPTION_LENGTH = 1e3;
15144
+ var ATTACHMENT_UPLOAD_PATH = "/v1/attachments";
15145
+ var attachmentDescriptionSchema = external_exports.string().trim().min(1).max(MAX_ATTACHMENT_DESCRIPTION_LENGTH).describe("Optional plain text: what this file shows and why it matters.");
15146
+ var attachmentIdSchema = external_exports.string().regex(/^att_[a-f0-9]{32}$/);
15147
+ var ATTACHMENT_TARGET_TYPES = [
15148
+ "event",
15149
+ "issue",
15150
+ "question",
15151
+ "eval",
15152
+ "investigation",
15153
+ "investigation_question",
15154
+ "investigation_reply"
15155
+ ];
15156
+ var attachmentTargetSchema = external_exports.object({
15157
+ type: external_exports.enum(ATTACHMENT_TARGET_TYPES),
15158
+ id: external_exports.string().min(1).max(64)
15159
+ });
15160
+ var attachmentManifestSchema = external_exports.object({
15161
+ filename: external_exports.string().min(1).max(180).refine(
15162
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: Reject control characters in filenames and HTTP headers.
15163
+ (name) => !/[\\/\u0000-\u001f\u007f]/.test(name) && name !== "." && name !== "..",
15164
+ "Use a filename without directories or control characters."
15165
+ ),
15166
+ mediaType: external_exports.string().max(127).regex(/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/),
15167
+ size: external_exports.number().int().min(1).max(MAX_ATTACHMENT_BYTES),
15168
+ sha256: external_exports.string().regex(/^[a-f0-9]{64}$/)
15169
+ });
15170
+ var prepareAttachmentSchema = attachmentManifestSchema.extend({
15171
+ to: external_exports.string().min(1).max(253).optional(),
15172
+ scope: external_exports.enum(["reporter", "owner"]).default("reporter"),
15173
+ /** Self-reported agent name for reporter uploads. */
15174
+ uploader: external_exports.string().min(1).max(128).optional()
15175
+ });
15176
+ var preparedAttachmentSchema = external_exports.object({
15177
+ reference: external_exports.object({
15178
+ id: attachmentIdSchema,
15179
+ token: external_exports.string().regex(/^hva_[a-f0-9]{64}$/)
15180
+ }),
15181
+ uploadUrl: external_exports.url(),
15182
+ expiresAt: external_exports.string()
15183
+ });
15184
+ var attachmentReferenceSchema = preparedAttachmentSchema.shape.reference.extend({
15185
+ description: attachmentDescriptionSchema.optional()
15186
+ });
15187
+ var attachmentReferencesSchema = external_exports.array(attachmentReferenceSchema).max(MAX_ATTACHMENTS).refine(
15188
+ (refs) => new Set(refs.map((ref) => ref.id)).size === refs.length,
15189
+ "Each file can be attached once."
15190
+ );
15191
+ var attachFilesSchema = external_exports.object({
15192
+ target: attachmentTargetSchema,
15193
+ attachments: attachmentReferencesSchema.min(1)
15194
+ });
15195
+ var attachmentSchema = attachmentManifestSchema.extend({
15196
+ id: attachmentIdSchema,
15197
+ createdAt: external_exports.string(),
15198
+ source: external_exports.enum(["reporter", "owner"]),
15199
+ /** Reporter names are self-reported; owner uploads are authenticated. */
15200
+ uploader: external_exports.string().nullable(),
15201
+ /** The record the file belongs to — a report when shown on its issue or eval. */
15202
+ target: attachmentTargetSchema,
15203
+ description: attachmentDescriptionSchema.optional()
15204
+ });
15205
+ var deliveredAttachmentSchema = attachmentSchema.extend({
15206
+ url: external_exports.url(),
15207
+ expiresAt: external_exports.string()
15208
+ });
15209
+ var MEDIA_TYPES = {
15210
+ png: "image/png",
15211
+ jpg: "image/jpeg",
15212
+ jpeg: "image/jpeg",
15213
+ gif: "image/gif",
15214
+ webp: "image/webp",
15215
+ svg: "image/svg+xml",
15216
+ mp4: "video/mp4",
15217
+ webm: "video/webm",
15218
+ mp3: "audio/mpeg",
15219
+ m4a: "audio/mp4",
15220
+ wav: "audio/wav",
15221
+ ogg: "audio/ogg",
15222
+ pdf: "application/pdf",
15223
+ json: "application/json",
15224
+ jsonl: "application/x-ndjson",
15225
+ ndjson: "application/x-ndjson",
15226
+ txt: "text/plain",
15227
+ log: "text/plain",
15228
+ md: "text/markdown",
15229
+ csv: "text/csv",
15230
+ zip: "application/zip",
15231
+ html: "text/html"
15232
+ };
15233
+ function mediaTypeForFilename(filename) {
15234
+ const extension = /\.([^./\\]+)$/.exec(filename)?.[1]?.toLowerCase();
15235
+ return extension && MEDIA_TYPES[extension] || "application/octet-stream";
15236
+ }
15141
15237
  var PROTOCOL_VERSION = 1;
15142
15238
  var MAX_FEEDBACK_LENGTH = 5e3;
15143
15239
  var MAX_SUBJECT_LENGTH = 500;
@@ -15157,15 +15253,40 @@ var FEEDBACK_CATEGORIES = [
15157
15253
  "cli",
15158
15254
  "api",
15159
15255
  "model",
15160
- "eval",
15161
15256
  "ux",
15162
15257
  "other"
15163
15258
  ];
15164
- var EVENT_STATUSES = ["new", "seen", "in_progress", "resolved", "wont_fix", "spam"];
15165
- var ISSUE_STATUSES = ["open", "in_progress", "resolved", "wont_fix", "spam"];
15259
+ var createQuestionInputSchema = external_exports.object({
15260
+ prompt: external_exports.string().trim().min(8).max(500).describe('The question, e.g. "If you used <feature>: what broke or was missing?"'),
15261
+ category: external_exports.enum(FEEDBACK_CATEGORIES).optional().describe("Only ask agents whose submission carries this category."),
15262
+ attachments: attachmentReferencesSchema.optional().describe("Uploaded files, each {id, token, description?}; every agent asked can open them."),
15263
+ idempotencyKey: external_exports.string().regex(/^[A-Za-z0-9_-]{8,64}$/).optional().describe(
15264
+ "Same key + same project = the same question, so a retried publish never duplicates."
15265
+ )
15266
+ });
15267
+ var LEGACY_CATEGORIES = ["eval"];
15268
+ var EVENT_STATUSES = [
15269
+ "new",
15270
+ "seen",
15271
+ "in_progress",
15272
+ "resolved",
15273
+ "wont_fix",
15274
+ "spam"
15275
+ ];
15276
+ var ISSUE_STATUSES = [
15277
+ "open",
15278
+ "in_progress",
15279
+ "needs_review",
15280
+ "resolved",
15281
+ "wont_fix",
15282
+ "spam"
15283
+ ];
15284
+ var issueStatusSchema = external_exports.enum(ISSUE_STATUSES);
15285
+ var EVAL_STATUSES = ["proposed", "accepted", "archived"];
15166
15286
  var VENDOR_CATEGORY_PATTERN = /^x-[a-z0-9][a-z0-9-]{0,38}$/;
15167
15287
  var categorySchema = external_exports.union([
15168
15288
  external_exports.enum(FEEDBACK_CATEGORIES),
15289
+ external_exports.enum(LEGACY_CATEGORIES),
15169
15290
  external_exports.string().regex(VENDOR_CATEGORY_PATTERN, "vendor categories must match x-<kebab-case>")
15170
15291
  ]);
15171
15292
  var sentimentSchema = external_exports.enum(["positive", "negative", "neutral"]);
@@ -15212,7 +15333,10 @@ var feedbackContextSchema = external_exports.object({
15212
15333
  /** Only populated via vendor identity paths (signed grants / pass-through). */
15213
15334
  user: userContextSchema.optional()
15214
15335
  });
15215
- var metadataSchema = external_exports.record(external_exports.string().min(1).max(40), external_exports.union([external_exports.string().max(200), external_exports.number().finite(), external_exports.boolean()])).refine((value) => Object.keys(value).length <= 20, { message: "at most 20 metadata keys" });
15336
+ var metadataSchema = external_exports.record(
15337
+ external_exports.string().min(1).max(40),
15338
+ external_exports.union([external_exports.string().max(200), external_exports.number().finite(), external_exports.boolean()])
15339
+ ).refine((value) => Object.keys(value).length <= 20, { message: "at most 20 metadata keys" });
15216
15340
  var feedbackEventSchema = external_exports.object({
15217
15341
  v: external_exports.literal(PROTOCOL_VERSION),
15218
15342
  /** Tenant slug or domain this feedback is addressed to. Optional when the write key implies it. */
@@ -15224,6 +15348,10 @@ var feedbackEventSchema = external_exports.object({
15224
15348
  author: authorSchema.optional(),
15225
15349
  thread: external_exports.object({ id: external_exports.string().regex(THREAD_ID_PATTERN) }),
15226
15350
  eval: evalReportSchema.optional(),
15351
+ /** Id of an owner/system question this submission answers (from a prior response's `ask`). */
15352
+ question: external_exports.string().max(64).optional(),
15353
+ /** Uploaded files, committed with the event or not at all. Bytes never travel in feedback JSON. */
15354
+ attachments: attachmentReferencesSchema.optional(),
15227
15355
  context: feedbackContextSchema.optional(),
15228
15356
  metadata: metadataSchema.optional(),
15229
15357
  /** Client-minted retry key: same key + same project = same stored event. */
@@ -15234,6 +15362,31 @@ var feedbackEventSchema = external_exports.object({
15234
15362
  }),
15235
15363
  consent: external_exports.object({ telemetry: external_exports.boolean() })
15236
15364
  });
15365
+ var knownIssueSchema = external_exports.object({
15366
+ title: external_exports.string().max(120),
15367
+ /** wont_fix is disclosed only when the owner attached a closing note. */
15368
+ status: external_exports.enum(["open", "wont_fix"]),
15369
+ /** This very report flipped a resolved issue back open — already recorded. */
15370
+ reopened: external_exports.boolean().optional(),
15371
+ /** Total reports on this issue, including this one. */
15372
+ reports: external_exports.number().int().positive(),
15373
+ /** The owner's closing note, verbatim — their explanation of the decision. */
15374
+ note: external_exports.string().max(MAX_GUIDANCE_LENGTH).optional(),
15375
+ /** Server-composed next step for the submitting agent. */
15376
+ hint: external_exports.string().max(300)
15377
+ });
15378
+ var ownerIssueSchema = external_exports.object({
15379
+ id: external_exports.string(),
15380
+ title: external_exports.string(),
15381
+ summary: external_exports.string().nullable(),
15382
+ status: issueStatusSchema,
15383
+ fingerprint: external_exports.string().nullable(),
15384
+ event_count: external_exports.number(),
15385
+ reopened_count: external_exports.number(),
15386
+ first_seen: external_exports.string(),
15387
+ last_seen: external_exports.string(),
15388
+ links_json: external_exports.string()
15389
+ });
15237
15390
  var ingestResponseSchema = external_exports.object({
15238
15391
  id: external_exports.string().max(64),
15239
15392
  thread: external_exports.string().regex(THREAD_ID_PATTERN),
@@ -15241,6 +15394,19 @@ var ingestResponseSchema = external_exports.object({
15241
15394
  resume: external_exports.string().max(512).optional(),
15242
15395
  /** Vendor-configured answer back to the submitting agent (known issues, workarounds). */
15243
15396
  guidance: external_exports.string().max(MAX_GUIDANCE_LENGTH).optional(),
15397
+ /** The report matched an already-tracked issue; recorded — don't file variants. */
15398
+ known_issue: knownIssueSchema.optional(),
15399
+ /**
15400
+ * A question from the project's team, delivered at most one per response.
15401
+ * Answering is optional and must be grounded in what the agent actually did;
15402
+ * `command` is ready to run and files the answer on this thread.
15403
+ */
15404
+ ask: external_exports.object({
15405
+ id: external_exports.string().max(64),
15406
+ prompt: external_exports.string().max(500),
15407
+ command: external_exports.string().max(512),
15408
+ attachments: external_exports.array(deliveredAttachmentSchema).optional()
15409
+ }).optional(),
15244
15410
  /** True when idempotencyKey matched an already-stored event; id/thread are the original's. */
15245
15411
  duplicate: external_exports.boolean().optional()
15246
15412
  });
@@ -15269,8 +15435,8 @@ var repoEntrySchema = external_exports.object({
15269
15435
  var repoListSchema = external_exports.array(repoEntrySchema).max(20);
15270
15436
  function formatIssues(error51) {
15271
15437
  return error51.issues.map((issue2) => {
15272
- const path5 = issue2.path.join(".");
15273
- return path5 ? `${path5}: ${issue2.message}` : issue2.message;
15438
+ const path6 = issue2.path.join(".");
15439
+ return path6 ? `${path6}: ${issue2.message}` : issue2.message;
15274
15440
  });
15275
15441
  }
15276
15442
  function validateFeedbackEvent(input) {
@@ -15286,6 +15452,13 @@ function validateIngestResponse(input) {
15286
15452
  return result.success ? { ok: true, data: result.data } : { ok: false, errors: formatIssues(result.error) };
15287
15453
  }
15288
15454
 
15455
+ // ../core/dist/index.js
15456
+ import { createHash } from "crypto";
15457
+ import { readFile, stat } from "fs/promises";
15458
+ import path2 from "path";
15459
+ import { readFileSync } from "fs";
15460
+ import path3 from "path";
15461
+
15289
15462
  // ../../node_modules/.pnpm/agent-cli-detector@0.1.5/node_modules/agent-cli-detector/dist/index.js
15290
15463
  import { execFileSync } from "child_process";
15291
15464
  import path from "path";
@@ -15580,8 +15753,6 @@ function sessionIdProperties(agent, env) {
15580
15753
 
15581
15754
  // ../core/dist/index.js
15582
15755
  var import_ci_info = __toESM(require_ci_info(), 1);
15583
- import { readFileSync } from "fs";
15584
- import path2 from "path";
15585
15756
 
15586
15757
  // ../../node_modules/.pnpm/sandbox-cli-detector@0.2.0/node_modules/sandbox-cli-detector/dist/chunk-HZH3SATY.js
15587
15758
  var defaultSandboxes = [
@@ -15650,28 +15821,152 @@ function matchesEnvSignal(signal, env) {
15650
15821
 
15651
15822
  // ../core/dist/index.js
15652
15823
  import { homedir } from "os";
15653
- import path3 from "path";
15824
+ import path22 from "path";
15654
15825
  import { mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
15655
- import path32 from "path";
15656
- import { appendFileSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
15657
15826
  import path4 from "path";
15827
+ import { randomUUID } from "crypto";
15828
+ import { appendFileSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync, rmSync } from "fs";
15829
+ import path5 from "path";
15658
15830
  import { randomBytes } from "crypto";
15831
+ import { createRequire } from "module";
15832
+ var FeedbackError = class extends Error {
15833
+ constructor(message) {
15834
+ super(message);
15835
+ this.name = "FeedbackError";
15836
+ }
15837
+ };
15838
+ async function readLocalAttachments(inputs, cwd = process.cwd()) {
15839
+ if (inputs.length > MAX_ATTACHMENTS)
15840
+ throw new FeedbackError(`At most ${MAX_ATTACHMENTS} files can be attached.`);
15841
+ const files = [];
15842
+ for (const input of inputs) {
15843
+ const selected = typeof input === "string" ? input : input.path;
15844
+ const filename = path2.basename(selected);
15845
+ const description = attachmentDescriptionSchema.optional().safeParse(typeof input === "string" ? void 0 : input.description);
15846
+ if (!description.success)
15847
+ throw new FeedbackError(
15848
+ `Invalid description for "${filename}": ${description.error.issues.map((issue2) => issue2.message).join("; ")}`
15849
+ );
15850
+ const file2 = path2.resolve(cwd, selected);
15851
+ const info = await stat(file2).catch(() => null);
15852
+ if (!info?.isFile())
15853
+ throw new FeedbackError(`Cannot attach "${selected}": choose an existing, readable file.`);
15854
+ if (info.size < 1 || info.size > MAX_ATTACHMENT_BYTES)
15855
+ throw new FeedbackError(`"${filename}" must be between 1 byte and 20 MiB.`);
15856
+ const bytes = new Uint8Array(
15857
+ await readFile(file2).catch(() => {
15858
+ throw new FeedbackError(`Cannot read "${selected}".`);
15859
+ })
15860
+ );
15861
+ const manifest = attachmentManifestSchema.safeParse({
15862
+ filename,
15863
+ mediaType: mediaTypeForFilename(filename),
15864
+ size: bytes.length,
15865
+ sha256: createHash("sha256").update(bytes).digest("hex")
15866
+ });
15867
+ if (!manifest.success)
15868
+ throw new FeedbackError(
15869
+ `Cannot attach "${filename}": ${manifest.error.issues.map((issue2) => issue2.message).join("; ")}`
15870
+ );
15871
+ files.push({
15872
+ manifest: manifest.data,
15873
+ bytes,
15874
+ ...description.data ? { description: description.data } : {}
15875
+ });
15876
+ }
15877
+ return files;
15878
+ }
15879
+ var AttachmentUploadError = class extends FeedbackError {
15880
+ constructor(message, rejected) {
15881
+ super(message);
15882
+ this.rejected = rejected;
15883
+ this.name = "AttachmentUploadError";
15884
+ }
15885
+ rejected;
15886
+ };
15887
+ async function send(fetchImpl, url2, init, timeoutMs) {
15888
+ let response;
15889
+ try {
15890
+ response = await fetchImpl(url2, {
15891
+ ...init,
15892
+ redirect: "error",
15893
+ signal: AbortSignal.timeout(timeoutMs)
15894
+ });
15895
+ } catch {
15896
+ throw new AttachmentUploadError("Could not reach the server to upload files.", false);
15897
+ }
15898
+ if (response.ok) return response;
15899
+ const body = await response.json().catch(() => null);
15900
+ const errors = Array.isArray(body?.errors) ? body.errors.map(String).join("; ") : void 0;
15901
+ if (response.status === 404 && !errors)
15902
+ throw new AttachmentUploadError("This server does not accept files.", false);
15903
+ throw new AttachmentUploadError(
15904
+ errors ?? `File upload failed (${response.status}).`,
15905
+ !(response.status >= 500 || response.status === 429 || response.status === 408)
15906
+ );
15907
+ }
15908
+ async function uploadFiles(options) {
15909
+ const fetchImpl = options.fetchImpl ?? fetch;
15910
+ const timeoutMs = options.timeoutMs ?? 6e4;
15911
+ const origin = new URL(options.endpoint).origin;
15912
+ const references = [];
15913
+ for (const file2 of options.files) {
15914
+ const response = await send(
15915
+ fetchImpl,
15916
+ `${origin}${ATTACHMENT_UPLOAD_PATH}`,
15917
+ {
15918
+ method: "POST",
15919
+ headers: {
15920
+ "content-type": "application/json",
15921
+ ...options.secretKey ? { authorization: `Bearer ${options.secretKey}` } : {},
15922
+ ...options.writeKey ? { [WRITE_KEY_HEADER]: options.writeKey } : {}
15923
+ },
15924
+ body: JSON.stringify({
15925
+ ...file2.manifest,
15926
+ to: options.to,
15927
+ scope: options.secretKey ? "owner" : "reporter",
15928
+ uploader: options.uploader
15929
+ })
15930
+ },
15931
+ timeoutMs
15932
+ );
15933
+ const prepared = preparedAttachmentSchema.safeParse(await response.json().catch(() => null));
15934
+ if (!prepared.success || new URL(prepared.data.uploadUrl).origin !== origin)
15935
+ throw new AttachmentUploadError("The server returned an invalid upload response.", true);
15936
+ await send(
15937
+ fetchImpl,
15938
+ prepared.data.uploadUrl,
15939
+ {
15940
+ method: "PUT",
15941
+ headers: { authorization: `Bearer ${prepared.data.reference.token}` },
15942
+ body: file2.bytes
15943
+ },
15944
+ // At least 100 KB/s: a 20 MiB file on a slow link still gets about 3.5 minutes.
15945
+ Math.max(timeoutMs, file2.bytes.length / 100)
15946
+ );
15947
+ references.push({
15948
+ ...prepared.data.reference,
15949
+ ...file2.description ? { description: file2.description } : {}
15950
+ });
15951
+ }
15952
+ return references;
15953
+ }
15659
15954
  var DSN_ENV_VAR = "HIVENET_DSN";
15660
15955
  var REGISTRY_ENV_VAR = "HIVENET_REGISTRY";
15661
15956
  var HOME_ENV_VAR = "HIVENET_HOME";
15662
15957
  var NO_TELEMETRY_ENV_VAR = "HIVENET_NO_TELEMETRY";
15663
15958
  function feedbackHomeDir(env = process.env) {
15664
15959
  const override = env[HOME_ENV_VAR];
15665
- return override && override.trim() ? override : path3.join(homedir(), ".hivenet");
15960
+ return override?.trim() ? override : path22.join(homedir(), ".hivenet");
15666
15961
  }
15667
15962
  function isTelemetryDisabled(extraOptOutEnvVars = [], env = process.env) {
15668
15963
  const vars = ["DO_NOT_TRACK", NO_TELEMETRY_ENV_VAR, ...extraOptOutEnvVars];
15669
15964
  return vars.some((name) => env[name] === "1" || env[name] === "true");
15670
15965
  }
15671
15966
  var MAX_SESSION_ID_LENGTH = 256;
15672
- function detectAgentSafe() {
15967
+ function detectAgentSafe(env) {
15673
15968
  try {
15674
- const result = detectAgent();
15969
+ const result = detectAgent({ env });
15675
15970
  if (result.detected && result.agent) {
15676
15971
  return {
15677
15972
  id: result.agent.id,
@@ -15683,9 +15978,9 @@ function detectAgentSafe() {
15683
15978
  }
15684
15979
  return void 0;
15685
15980
  }
15686
- function detectSandboxSafe() {
15981
+ function detectSandboxSafe(env) {
15687
15982
  try {
15688
- const result = detectSandbox();
15983
+ const result = detectSandbox({ env });
15689
15984
  if (result.detected && result.sandbox) {
15690
15985
  return {
15691
15986
  id: result.sandbox.id,
@@ -15750,7 +16045,7 @@ function resolveSessions(sources, projectRoot, env) {
15750
16045
  }
15751
16046
  const value = "envVar" in source ? normalizeSessionId(env[source.envVar]) : normalizeSessionId(
15752
16047
  readDotenvKey(
15753
- path2.resolve(projectRoot, source.dotenvFile),
16048
+ path3.resolve(projectRoot, source.dotenvFile),
15754
16049
  source.dotenvKey ?? source.key
15755
16050
  )
15756
16051
  );
@@ -15766,8 +16061,8 @@ async function collectContext(options = {}) {
15766
16061
  return void 0;
15767
16062
  }
15768
16063
  const projectRoot = options.projectRoot ?? process.cwd();
15769
- const agent = detectAgentSafe();
15770
- const sandbox = detectSandboxSafe();
16064
+ const agent = detectAgentSafe(env);
16065
+ const sandbox = detectSandboxSafe(env);
15771
16066
  const ci = detectCi();
15772
16067
  const session = resolveSessions(options.sessions ?? [], projectRoot, env);
15773
16068
  let project;
@@ -15790,12 +16085,6 @@ async function collectContext(options = {}) {
15790
16085
  function inferAuthor(context) {
15791
16086
  return context?.agent ? "agent" : void 0;
15792
16087
  }
15793
- var FeedbackError = class extends Error {
15794
- constructor(message) {
15795
- super(message);
15796
- this.name = "FeedbackError";
15797
- }
15798
- };
15799
16088
  var CONFIG_FILE_NAME = "feedback.config.json";
15800
16089
  var DESCRIPTOR_CACHE_TTL_MS = 60 * 60 * 1e3;
15801
16090
  var RESOLVE_TIMEOUT_MS = 5e3;
@@ -15820,9 +16109,9 @@ function parseDsn(dsn) {
15820
16109
  };
15821
16110
  }
15822
16111
  function findConfigFile(startDir) {
15823
- let current = path32.resolve(startDir);
16112
+ let current = path4.resolve(startDir);
15824
16113
  while (true) {
15825
- const candidate = path32.join(current, CONFIG_FILE_NAME);
16114
+ const candidate = path4.join(current, CONFIG_FILE_NAME);
15826
16115
  try {
15827
16116
  const raw = readFileSync2(candidate, "utf8");
15828
16117
  const parsed = JSON.parse(raw);
@@ -15831,7 +16120,7 @@ function findConfigFile(startDir) {
15831
16120
  }
15832
16121
  } catch {
15833
16122
  }
15834
- const parent = path32.dirname(current);
16123
+ const parent = path4.dirname(current);
15835
16124
  if (parent === current) {
15836
16125
  return void 0;
15837
16126
  }
@@ -15839,7 +16128,7 @@ function findConfigFile(startDir) {
15839
16128
  }
15840
16129
  }
15841
16130
  function cacheFilePath(cacheDir) {
15842
- return path32.join(cacheDir, "descriptors.json");
16131
+ return path4.join(cacheDir, "descriptors.json");
15843
16132
  }
15844
16133
  function readCache(cacheDir) {
15845
16134
  try {
@@ -15964,7 +16253,7 @@ async function postEvent(options) {
15964
16253
  error: error51 instanceof Error ? error51.message : String(error51)
15965
16254
  };
15966
16255
  }
15967
- if (response.status >= 500) {
16256
+ if (response.status >= 500 || response.status === 429 || response.status === 408) {
15968
16257
  return { kind: "unreachable", error: `server error (${response.status})` };
15969
16258
  }
15970
16259
  if (!response.ok) {
@@ -15992,13 +16281,14 @@ async function postEvent(options) {
15992
16281
  }
15993
16282
  var OUTBOX_FILE = "outbox.jsonl";
15994
16283
  var MAX_OUTBOX_ENTRIES = 100;
16284
+ var STALE_CLAIM_MS = 30 * 60 * 1e3;
15995
16285
  function outboxPath(env = process.env) {
15996
- return path4.join(feedbackHomeDir(env), OUTBOX_FILE);
16286
+ return path5.join(feedbackHomeDir(env), OUTBOX_FILE);
15997
16287
  }
15998
16288
  function appendToOutbox(entry, env = process.env) {
15999
16289
  try {
16000
16290
  const file2 = outboxPath(env);
16001
- mkdirSync2(path4.dirname(file2), { recursive: true });
16291
+ mkdirSync2(path5.dirname(file2), { recursive: true });
16002
16292
  appendFileSync(file2, `${JSON.stringify(entry)}
16003
16293
  `);
16004
16294
  return true;
@@ -16006,19 +16296,43 @@ function appendToOutbox(entry, env = process.env) {
16006
16296
  return false;
16007
16297
  }
16008
16298
  }
16009
- function readOutbox(env) {
16299
+ function readEntries(file2) {
16010
16300
  try {
16011
- return readFileSync3(outboxPath(env), "utf8").split("\n").filter((line) => line.trim()).slice(-MAX_OUTBOX_ENTRIES).map((line) => JSON.parse(line));
16301
+ return readFileSync3(file2, "utf8").split("\n").filter((line) => line.trim()).flatMap((line) => {
16302
+ try {
16303
+ return [JSON.parse(line)];
16304
+ } catch {
16305
+ return [];
16306
+ }
16307
+ });
16012
16308
  } catch {
16013
16309
  return [];
16014
16310
  }
16015
16311
  }
16312
+ function claimQueue(env) {
16313
+ const file2 = outboxPath(env);
16314
+ let names;
16315
+ try {
16316
+ names = readdirSync(path5.dirname(file2));
16317
+ } catch {
16318
+ return [];
16319
+ }
16320
+ const claims = names.filter((name) => {
16321
+ const claimedAt = Number(/\.flushing-(\d+)-/.exec(name)?.[1]);
16322
+ return name.startsWith(OUTBOX_FILE) && Date.now() - claimedAt > STALE_CLAIM_MS;
16323
+ }).map((name) => path5.join(path5.dirname(file2), name));
16324
+ const fresh = `${file2}.flushing-${Date.now()}-${randomUUID()}`;
16325
+ try {
16326
+ renameSync(file2, fresh);
16327
+ claims.push(fresh);
16328
+ } catch {
16329
+ }
16330
+ return claims;
16331
+ }
16016
16332
  async function flushOutbox(options = {}) {
16017
16333
  const env = options.env ?? process.env;
16018
- const entries = readOutbox(env);
16019
- if (entries.length === 0) {
16020
- return { delivered: 0, remaining: 0 };
16021
- }
16334
+ const claims = claimQueue(env);
16335
+ const entries = claims.flatMap(readEntries).slice(-MAX_OUTBOX_ENTRIES);
16022
16336
  const failures = [];
16023
16337
  let delivered = 0;
16024
16338
  for (const entry of entries) {
@@ -16035,23 +16349,194 @@ async function flushOutbox(options = {}) {
16035
16349
  failures.push(entry);
16036
16350
  }
16037
16351
  }
16038
- try {
16039
- writeFileSync2(
16040
- outboxPath(env),
16041
- failures.map((entry) => JSON.stringify(entry)).join("\n") + (failures.length ? "\n" : "")
16042
- );
16043
- } catch {
16352
+ if (failures.every((entry) => appendToOutbox(entry, env))) {
16353
+ for (const claim of claims) {
16354
+ try {
16355
+ rmSync(claim, { force: true });
16356
+ } catch {
16357
+ }
16358
+ }
16044
16359
  }
16045
16360
  return { delivered, remaining: failures.length };
16046
16361
  }
16362
+ async function resolveApiOrigin(options) {
16363
+ if (!options.to && !options.dsn) {
16364
+ return new URL(DEFAULT_REGISTRY_URL).origin;
16365
+ }
16366
+ const destination = await resolveDestination({
16367
+ ...options.to !== void 0 ? { to: options.to } : {},
16368
+ ...options.dsn !== void 0 ? { dsn: options.dsn } : {},
16369
+ ...options.env ? { env: options.env } : {},
16370
+ ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
16371
+ });
16372
+ return new URL(destination.endpoint).origin;
16373
+ }
16374
+ function ownerApi(options) {
16375
+ const origin = (options.apiOrigin ?? new URL(DEFAULT_REGISTRY_URL).origin).replace(/\/$/, "");
16376
+ const fetchImpl = options.fetchImpl ?? fetch;
16377
+ const timeoutMs = options.timeoutMs ?? 15e3;
16378
+ async function request(path6, init) {
16379
+ let response;
16380
+ try {
16381
+ response = await fetchImpl(`${origin}${path6}`, {
16382
+ ...init,
16383
+ signal: AbortSignal.timeout(timeoutMs),
16384
+ headers: {
16385
+ authorization: `Bearer ${options.secretKey}`,
16386
+ ...init?.body ? { "content-type": "application/json" } : {},
16387
+ ...init?.headers
16388
+ }
16389
+ });
16390
+ } catch (error51) {
16391
+ throw new FeedbackError(
16392
+ `Could not reach ${origin} (${error51 instanceof Error ? error51.message : String(error51)}).`
16393
+ );
16394
+ }
16395
+ let body;
16396
+ try {
16397
+ body = await response.json();
16398
+ } catch {
16399
+ body = void 0;
16400
+ }
16401
+ if (!response.ok) {
16402
+ const errors = body?.errors;
16403
+ throw new FeedbackError(
16404
+ Array.isArray(errors) ? errors.map(String).join("; ") : `Request failed (${response.status}).`
16405
+ );
16406
+ }
16407
+ return body;
16408
+ }
16409
+ async function upload(paths, cwd) {
16410
+ return uploadFiles({
16411
+ endpoint: origin,
16412
+ files: await readLocalAttachments(paths, cwd),
16413
+ secretKey: options.secretKey,
16414
+ fetchImpl,
16415
+ timeoutMs: Math.max(timeoutMs, 6e4)
16416
+ });
16417
+ }
16418
+ return {
16419
+ /** Upload local files and attach them to a record (at most 10 files per record). */
16420
+ async attachFiles(target, paths, cwd) {
16421
+ if (!paths.length) throw new FeedbackError("Select at least one file.");
16422
+ const attachments = await upload(paths, cwd);
16423
+ return request("/v1/attachments/attach", {
16424
+ method: "POST",
16425
+ body: JSON.stringify({ target, attachments })
16426
+ });
16427
+ },
16428
+ /** A record's files; issues and evals include their reports' files. */
16429
+ async listAttachments(target, offset = 0) {
16430
+ return request(
16431
+ `/v1/attachments?${new URLSearchParams({ type: target.type, id: target.id, offset: String(offset) })}`
16432
+ );
16433
+ },
16434
+ async deleteAttachment(id) {
16435
+ return request(`/v1/attachments/${encodeURIComponent(id)}`, { method: "DELETE" });
16436
+ },
16437
+ async listFeedback(filters = {}) {
16438
+ const params = new URLSearchParams();
16439
+ if (filters.status) params.set("status", filters.status);
16440
+ if (filters.category) params.set("category", filters.category);
16441
+ if (filters.thread) params.set("thread", filters.thread);
16442
+ if (filters.since) params.set("since", filters.since);
16443
+ if (filters.limit) params.set("limit", String(filters.limit));
16444
+ const query = params.toString();
16445
+ return request(`/v1/events${query ? `?${query}` : ""}`);
16446
+ },
16447
+ async getFeedback(id) {
16448
+ return request(`/v1/events/${encodeURIComponent(id)}`);
16449
+ },
16450
+ async setFeedbackStatus(id, status, note) {
16451
+ return request(`/v1/events/${encodeURIComponent(id)}`, {
16452
+ method: "PATCH",
16453
+ body: JSON.stringify({ status, ...note !== void 0 ? { note } : {} })
16454
+ });
16455
+ },
16456
+ async listIssues(filters = {}) {
16457
+ const params = new URLSearchParams();
16458
+ if (filters.status) params.set("status", filters.status);
16459
+ if (filters.since) params.set("since", filters.since);
16460
+ if (filters.limit) params.set("limit", String(filters.limit));
16461
+ const query = params.toString();
16462
+ return request(`/v1/issues${query ? `?${query}` : ""}`);
16463
+ },
16464
+ async getIssue(id) {
16465
+ return request(`/v1/issues/${encodeURIComponent(id)}`);
16466
+ },
16467
+ async setIssueStatus(id, status, note) {
16468
+ return request(`/v1/issues/${encodeURIComponent(id)}`, {
16469
+ method: "PATCH",
16470
+ body: JSON.stringify({ status, ...note !== void 0 ? { note } : {} })
16471
+ });
16472
+ },
16473
+ async listQuestions(filters = {}) {
16474
+ const query = filters.status ? `?status=${filters.status}` : "";
16475
+ return request(`/v1/questions${query}`);
16476
+ },
16477
+ /** Files are shared with every agent that receives the question. */
16478
+ async createQuestion(prompt, category, options2 = {}) {
16479
+ const attachments = options2.files?.length ? await upload(options2.files, options2.cwd) : [];
16480
+ return request("/v1/questions", {
16481
+ method: "POST",
16482
+ body: JSON.stringify({
16483
+ prompt,
16484
+ ...category ? { category } : {},
16485
+ ...attachments.length ? { attachments } : {},
16486
+ ...options2.idempotencyKey ? { idempotencyKey: options2.idempotencyKey } : {}
16487
+ })
16488
+ });
16489
+ },
16490
+ async closeQuestion(id) {
16491
+ return request(`/v1/questions/${encodeURIComponent(id)}`, {
16492
+ method: "PATCH",
16493
+ body: JSON.stringify({ status: "closed" })
16494
+ });
16495
+ },
16496
+ async listEvals(filters = {}) {
16497
+ const query = filters.status ? `?status=${filters.status}` : "";
16498
+ return request(`/v1/evals${query}`);
16499
+ },
16500
+ async getEval(id) {
16501
+ return request(`/v1/evals/${encodeURIComponent(id)}`);
16502
+ },
16503
+ /** Promote a failed-task report (category=eval event) into the eval corpus. */
16504
+ async promoteEval(eventId) {
16505
+ return request("/v1/evals", {
16506
+ method: "POST",
16507
+ body: JSON.stringify({ event_id: eventId })
16508
+ });
16509
+ },
16510
+ async setEvalStatus(id, status, note) {
16511
+ return request(`/v1/evals/${encodeURIComponent(id)}`, {
16512
+ method: "PATCH",
16513
+ body: JSON.stringify({ status, ...note !== void 0 ? { note } : {} })
16514
+ });
16515
+ },
16516
+ /** Attach an external link (Slack message, Linear/GitHub issue, PR) to evt_… or iss_…. */
16517
+ async addLink(id, url2, label) {
16518
+ const path6 = id.startsWith("iss_") ? `/v1/issues/${id}` : `/v1/events/${id}`;
16519
+ return request(path6, {
16520
+ method: "PATCH",
16521
+ body: JSON.stringify({ addLink: { url: url2, ...label !== void 0 ? { label } : {} } })
16522
+ });
16523
+ }
16524
+ };
16525
+ }
16047
16526
  function mintIdempotencyKey() {
16048
16527
  return randomBytes(16).toString("hex");
16049
16528
  }
16050
16529
  var DEFAULT_TIMEOUT_MS = 15e3;
16051
16530
  var DEFAULT_CLIENT_NAME = "hivenet";
16052
- var DEFAULT_CLIENT_VERSION = "0.1.0";
16531
+ var DEFAULT_CLIENT_VERSION = (() => {
16532
+ try {
16533
+ return createRequire(import.meta.url)("../package.json").version ?? "0";
16534
+ } catch {
16535
+ return "0";
16536
+ }
16537
+ })();
16053
16538
  function generateThreadId() {
16054
- return randomBytes(6).toString("hex");
16539
+ return randomBytes(16).toString("hex");
16055
16540
  }
16056
16541
  function resolveThreadId(resume) {
16057
16542
  if (resume !== void 0 && THREAD_ID_PATTERN.test(resume)) {
@@ -16059,9 +16544,10 @@ function resolveThreadId(resume) {
16059
16544
  }
16060
16545
  return { id: generateThreadId(), resumed: false };
16061
16546
  }
16062
- async function sendFeedback(options) {
16547
+ async function prepareFeedback(options) {
16063
16548
  const env = options.env ?? process.env;
16064
16549
  const cwd = options.cwd ?? process.cwd();
16550
+ const files = await readLocalAttachments(options.attachments ?? [], cwd);
16065
16551
  const config2 = findConfigFile(cwd)?.config;
16066
16552
  const resolveOptions = {
16067
16553
  ...options.to !== void 0 ? { to: options.to } : {},
@@ -16097,6 +16583,7 @@ async function sendFeedback(options) {
16097
16583
  ...author ? { author } : {},
16098
16584
  thread: { id: thread.id },
16099
16585
  ...options.eval ? { eval: options.eval } : {},
16586
+ ...options.question ? { question: options.question } : {},
16100
16587
  ...context ? { context } : {},
16101
16588
  ...options.metadata && Object.keys(options.metadata).length > 0 ? { metadata: options.metadata } : {},
16102
16589
  // Minted before the first attempt so outbox retries replay the SAME event
@@ -16112,7 +16599,32 @@ async function sendFeedback(options) {
16112
16599
  if (!validated.ok) {
16113
16600
  throw new FeedbackError(`Invalid feedback event: ${validated.errors.join("; ")}`);
16114
16601
  }
16115
- const event = validated.data;
16602
+ return { event: validated.data, destination, resumed: thread.resumed, files };
16603
+ }
16604
+ async function sendFeedback(options) {
16605
+ const env = options.env ?? process.env;
16606
+ const { event, destination, resumed, files } = await prepareFeedback(options);
16607
+ const names = files.map((file2) => file2.manifest.filename);
16608
+ let filesNotAttached;
16609
+ if (files.length) {
16610
+ try {
16611
+ event.attachments = await uploadFiles({
16612
+ endpoint: destination.endpoint,
16613
+ files,
16614
+ ...destination.to ? { to: destination.to } : {},
16615
+ ...destination.writeKey ? { writeKey: destination.writeKey } : {},
16616
+ ...event.context?.agent?.id ? { uploader: event.context.agent.id } : {},
16617
+ ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
16618
+ });
16619
+ } catch (error51) {
16620
+ if (!(error51 instanceof AttachmentUploadError) || error51.rejected) {
16621
+ throw new FeedbackError(
16622
+ `${error51 instanceof Error ? error51.message : String(error51)} Nothing was sent.`
16623
+ );
16624
+ }
16625
+ filesNotAttached = { files: names, reason: error51.message };
16626
+ }
16627
+ }
16116
16628
  const result = await postEvent({
16117
16629
  endpoint: destination.endpoint,
16118
16630
  ...destination.writeKey ? { writeKey: destination.writeKey } : {},
@@ -16126,12 +16638,17 @@ async function sendFeedback(options) {
16126
16638
  response: result.response,
16127
16639
  event,
16128
16640
  destination,
16129
- resumed: thread.resumed
16641
+ resumed,
16642
+ ...filesNotAttached ? { filesNotAttached } : {}
16130
16643
  };
16131
16644
  }
16132
16645
  if (result.kind === "rejected") {
16133
16646
  throw new FeedbackError(`Feedback rejected: ${result.errors.join("; ")}`);
16134
16647
  }
16648
+ if (event.attachments) {
16649
+ delete event.attachments;
16650
+ filesNotAttached = { files: names, reason: result.error };
16651
+ }
16135
16652
  const queued = options.outbox !== false && appendToOutbox(
16136
16653
  {
16137
16654
  endpoint: destination.endpoint,
@@ -16147,116 +16664,40 @@ async function sendFeedback(options) {
16147
16664
  error: result.error,
16148
16665
  event,
16149
16666
  destination,
16150
- resumed: thread.resumed
16151
- };
16152
- }
16153
- async function resolveApiOrigin(options) {
16154
- if (!options.to && !options.dsn) {
16155
- return new URL(DEFAULT_REGISTRY_URL).origin;
16156
- }
16157
- const destination = await resolveDestination({
16158
- ...options.to !== void 0 ? { to: options.to } : {},
16159
- ...options.dsn !== void 0 ? { dsn: options.dsn } : {},
16160
- ...options.env ? { env: options.env } : {},
16161
- ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
16162
- });
16163
- return new URL(destination.endpoint).origin;
16164
- }
16165
- function ownerApi(options) {
16166
- const origin = (options.apiOrigin ?? new URL(DEFAULT_REGISTRY_URL).origin).replace(/\/$/, "");
16167
- const fetchImpl = options.fetchImpl ?? fetch;
16168
- const timeoutMs = options.timeoutMs ?? 15e3;
16169
- async function request(path5, init) {
16170
- let response;
16171
- try {
16172
- response = await fetchImpl(`${origin}${path5}`, {
16173
- ...init,
16174
- signal: AbortSignal.timeout(timeoutMs),
16175
- headers: {
16176
- authorization: `Bearer ${options.secretKey}`,
16177
- ...init?.body ? { "content-type": "application/json" } : {},
16178
- ...init?.headers
16179
- }
16180
- });
16181
- } catch (error51) {
16182
- throw new FeedbackError(
16183
- `Could not reach ${origin} (${error51 instanceof Error ? error51.message : String(error51)}).`
16184
- );
16185
- }
16186
- let body;
16187
- try {
16188
- body = await response.json();
16189
- } catch {
16190
- body = void 0;
16191
- }
16192
- if (!response.ok) {
16193
- const errors = body?.errors;
16194
- throw new FeedbackError(
16195
- Array.isArray(errors) ? errors.map(String).join("; ") : `Request failed (${response.status}).`
16196
- );
16197
- }
16198
- return body;
16199
- }
16200
- return {
16201
- async listFeedback(filters = {}) {
16202
- const params = new URLSearchParams();
16203
- if (filters.status) params.set("status", filters.status);
16204
- if (filters.category) params.set("category", filters.category);
16205
- if (filters.thread) params.set("thread", filters.thread);
16206
- if (filters.since) params.set("since", filters.since);
16207
- if (filters.limit) params.set("limit", String(filters.limit));
16208
- const query = params.toString();
16209
- return request(`/v1/events${query ? `?${query}` : ""}`);
16210
- },
16211
- async getFeedback(id) {
16212
- return request(`/v1/events/${encodeURIComponent(id)}`);
16213
- },
16214
- async setFeedbackStatus(id, status, note) {
16215
- return request(`/v1/events/${encodeURIComponent(id)}`, {
16216
- method: "PATCH",
16217
- body: JSON.stringify({ status, ...note !== void 0 ? { note } : {} })
16218
- });
16219
- },
16220
- async listIssues(filters = {}) {
16221
- const params = new URLSearchParams();
16222
- if (filters.status) params.set("status", filters.status);
16223
- if (filters.since) params.set("since", filters.since);
16224
- if (filters.limit) params.set("limit", String(filters.limit));
16225
- const query = params.toString();
16226
- return request(`/v1/issues${query ? `?${query}` : ""}`);
16227
- },
16228
- async getIssue(id) {
16229
- return request(`/v1/issues/${encodeURIComponent(id)}`);
16230
- },
16231
- async setIssueStatus(id, status, note) {
16232
- return request(`/v1/issues/${encodeURIComponent(id)}`, {
16233
- method: "PATCH",
16234
- body: JSON.stringify({ status, ...note !== void 0 ? { note } : {} })
16235
- });
16236
- },
16237
- /** Attach an external link (Slack message, Linear/GitHub issue, PR) to evt_… or iss_…. */
16238
- async addLink(id, url2, label) {
16239
- const path5 = id.startsWith("iss_") ? `/v1/issues/${id}` : `/v1/events/${id}`;
16240
- return request(path5, {
16241
- method: "PATCH",
16242
- body: JSON.stringify({ addLink: { url: url2, ...label !== void 0 ? { label } : {} } })
16243
- });
16244
- }
16667
+ resumed,
16668
+ ...filesNotAttached ? { filesNotAttached } : {}
16245
16669
  };
16246
16670
  }
16247
16671
 
16248
16672
  export {
16249
16673
  __toESM,
16674
+ external_exports,
16675
+ MAX_ATTACHMENTS,
16676
+ attachmentDescriptionSchema,
16677
+ ATTACHMENT_TARGET_TYPES,
16678
+ attachmentTargetSchema,
16679
+ PROTOCOL_VERSION,
16250
16680
  MAX_FEEDBACK_LENGTH,
16681
+ WELL_KNOWN_PATH,
16251
16682
  FEEDBACK_CATEGORIES,
16252
16683
  EVENT_STATUSES,
16253
16684
  ISSUE_STATUSES,
16685
+ EVAL_STATUSES,
16254
16686
  sentimentSchema,
16255
16687
  authorSchema,
16688
+ evalReportSchema,
16689
+ feedbackEventSchema,
16690
+ validateFeedbackEvent,
16691
+ validateDescriptor,
16256
16692
  FeedbackError,
16693
+ parseDsn,
16694
+ registryUrl,
16695
+ postEvent,
16257
16696
  flushOutbox,
16258
- sendFeedback,
16259
16697
  resolveApiOrigin,
16260
16698
  ownerApi,
16699
+ generateThreadId,
16700
+ prepareFeedback,
16701
+ sendFeedback,
16261
16702
  require_arg
16262
16703
  };