@badger_badger/badger_hq 1.5.1 → 1.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.
@@ -37,7 +37,7 @@ var TASK_STATUS_VALUES = [
37
37
  ];
38
38
  z.enum(TASK_STATUS_VALUES);
39
39
  var REGION_MODE_VALUES = ["must", "preferred"];
40
- z.enum(REGION_MODE_VALUES);
40
+ var RegionMode = z.enum(REGION_MODE_VALUES);
41
41
  var ASSIGNEE_TYPE_VALUES = ["scout", "analyst"];
42
42
  z.enum(ASSIGNEE_TYPE_VALUES);
43
43
  var ASSIGNMENT_STATUS_VALUES = ["active", "completed", "revoked"];
@@ -58,6 +58,21 @@ var SOURCE_ROUTE_VALUES = ["scraper", "monitor", "waiting_for_scraper"];
58
58
  z.enum(SOURCE_ROUTE_VALUES);
59
59
  var SOURCE_STATUS_VALUES = ["active", "paused", "closed", "access_problem"];
60
60
  z.enum(SOURCE_STATUS_VALUES);
61
+ var ACCESS_ISSUE_VALUES = [
62
+ "login_required",
63
+ "private",
64
+ "bot_detection",
65
+ "captcha",
66
+ "geo_blocked",
67
+ "rate_limited",
68
+ "not_found",
69
+ "no_collector",
70
+ "collector_full",
71
+ "other"
72
+ ];
73
+ var AccessIssue = z.enum(ACCESS_ISSUE_VALUES);
74
+ var CAPTURE_WINDOW_MODE_VALUES = ["last_days", "range"];
75
+ var CaptureWindowMode = z.enum(CAPTURE_WINDOW_MODE_VALUES);
61
76
  var DISCOVERED_BY_TYPE_VALUES = ["scout", "analyst", "agent", "client", "import"];
62
77
  z.enum(DISCOVERED_BY_TYPE_VALUES);
63
78
  var SOURCE_IMPORT_KIND_VALUES = ["create", "update"];
@@ -105,6 +120,8 @@ var AGENT_SOURCE_OUTCOME_VALUES = [
105
120
  var AgentSourceOutcome = z.enum(AGENT_SOURCE_OUTCOME_VALUES);
106
121
  var CAPTURE_STATUS_VALUES = ["uploaded", "analyzing", "analyzed", "failed", "expired"];
107
122
  var CaptureStatus = z.enum(CAPTURE_STATUS_VALUES);
123
+ var HOURS_LOG_SOURCE_VALUES = ["manual", "inferred"];
124
+ z.enum(HOURS_LOG_SOURCE_VALUES);
108
125
  var CAPTURE_DOM_STATUS_VALUES = ["ok", "unavailable", "truncated"];
109
126
  var CaptureDomStatus = z.enum(CAPTURE_DOM_STATUS_VALUES);
110
127
  var LLM_CAPABILITY_VALUES = ["plan", "vision_extract", "judge", "chat"];
@@ -197,7 +214,11 @@ var INDEXES = {
197
214
  ],
198
215
  [COLLECTIONS.assigneeLoads]: [{ key: { userId: 1, scope: 1 }, options: { unique: true } }],
199
216
  [COLLECTIONS.missions]: [{ key: { orgId: 1, status: 1, priority: 1 } }],
200
- [COLLECTIONS.tasks]: [{ key: { orgId: 1, missionId: 1, status: 1 } }],
217
+ [COLLECTIONS.tasks]: [
218
+ { key: { orgId: 1, missionId: 1, status: 1 } },
219
+ // Tasks that target a source (cascade on source delete).
220
+ { key: { orgId: 1, "target.sourceId": 1 }, options: { partialFilterExpression: { "target.sourceId": { $exists: true } } } }
221
+ ],
201
222
  [COLLECTIONS.assignments]: [
202
223
  { key: { assigneeUserId: 1, status: 1, orgId: 1 } },
203
224
  { key: { orgId: 1, taskId: 1, status: 1 } },
@@ -210,7 +231,14 @@ var INDEXES = {
210
231
  }
211
232
  }
212
233
  ],
213
- [COLLECTIONS.hoursLogs]: [{ key: { orgId: 1, scoutUserId: 1, date: -1 } }],
234
+ [COLLECTIONS.hoursLogs]: [
235
+ { key: { orgId: 1, scoutUserId: 1, date: -1 } },
236
+ // One inferred row per person + assignment + day (agent-service upserts it).
237
+ {
238
+ key: { orgId: 1, assignmentId: 1, scoutUserId: 1, date: 1 },
239
+ options: { unique: true, partialFilterExpression: { source: "inferred" } }
240
+ }
241
+ ],
214
242
  [COLLECTIONS.sources]: [
215
243
  {
216
244
  key: { orgId: 1, platform: 1, url: 1 },
@@ -253,7 +281,11 @@ var INDEXES = {
253
281
  [COLLECTIONS.captures]: [
254
282
  { key: { orgId: 1, sessionId: 1, capturedAt: -1 } },
255
283
  // Retention sweep: captures whose blob must be deleted.
256
- { key: { status: 1, expiresAt: 1 } }
284
+ { key: { status: 1, expiresAt: 1 } },
285
+ // Capture worker: oldest waiting (or stale analyzing) captures first.
286
+ { key: { status: 1, createdAt: 1 } },
287
+ // Task-tagged captures: per-assignment dedupe and inferred hours.
288
+ { key: { orgId: 1, assignmentId: 1, userId: 1, capturedAt: 1 } }
257
289
  ],
258
290
  [COLLECTIONS.llmCalls]: [
259
291
  { key: { orgId: 1, createdAt: -1 } },
@@ -338,6 +370,24 @@ OrgSettingsSchema.pick({
338
370
  defaultAnalystTaskLimit: true,
339
371
  timezone: true
340
372
  }).partial();
373
+ var CoverageWindowSchema = z.object({
374
+ start: z.coerce.date(),
375
+ end: z.coerce.date()
376
+ }).refine((w) => w.end.getTime() > w.start.getTime(), {
377
+ message: "coverageWindow.end must be after coverageWindow.start",
378
+ path: ["end"]
379
+ });
380
+ z.object({
381
+ languages: z.array(LanguageCode),
382
+ platforms: z.array(Platform),
383
+ regions: z.array(z.string().min(1)),
384
+ regionMode: RegionMode,
385
+ profession: z.string().min(1).optional(),
386
+ coverageWindow: CoverageWindowSchema.optional(),
387
+ emergency: z.boolean().default(false)
388
+ });
389
+
390
+ // src/zod/agent-session.ts
341
391
  var count = () => z.number().int().min(0).default(0);
342
392
  var AgentSessionStatsSchema = z.object({
343
393
  capturesCount: count(),
@@ -374,6 +424,8 @@ var AgentSessionSchema = z.object({
374
424
  lastSeq: count(),
375
425
  stats: AgentSessionStatsSchema.default({}),
376
426
  budget: AgentSessionBudgetSchema.default({}),
427
+ /** The task's capture window as dates, fixed when the session started (`last_days` counted back from then). */
428
+ captureWindow: CoverageWindowSchema.optional(),
377
429
  /** Mode-specific engine state (search plan cursor, monitor queue). Opaque to clients. */
378
430
  state: z.unknown().optional()
379
431
  }).merge(TimestampsSchema);
@@ -479,7 +531,14 @@ var CaptureDomSummarySchema = z.object({
479
531
  var CaptureSchema = z.object({
480
532
  _id: ObjectIdString,
481
533
  orgId: ClerkOrgId,
482
- sessionId: ObjectIdString,
534
+ /** Legacy: captures uploaded into a live session. Task-tagged captures have none. */
535
+ sessionId: ObjectIdString.optional(),
536
+ /** The assignment (and so the task) the person sent this capture for. */
537
+ assignmentId: ObjectIdString.optional(),
538
+ taskId: ObjectIdString.optional(),
539
+ missionId: ObjectIdString.optional(),
540
+ /** Who sent it; used to work out their hours. */
541
+ userId: ClerkUserId.optional(),
483
542
  /** From `chrome.tabs`, never from page content. */
484
543
  url: z.string().url(),
485
544
  title: z.string().max(500),
@@ -495,6 +554,10 @@ var CaptureSchema = z.object({
495
554
  /** Validated `vision_extract` output; shape depends on session mode. */
496
555
  analysis: z.unknown().optional(),
497
556
  error: z.string().max(1e3).optional(),
557
+ /** Analysis attempts by the capture worker; it gives up (`failed`) after a few. */
558
+ attempts: z.number().int().min(0).default(0),
559
+ /** When the worker claimed it (`analyzing`); an old claim is taken over after a restart. */
560
+ claimedAt: z.coerce.date().optional(),
498
561
  /** Blob deleted and status set to `expired` after this instant (CAPTURE_RETENTION_DAYS). */
499
562
  expiresAt: z.coerce.date()
500
563
  }).merge(TimestampsSchema);
@@ -612,6 +675,51 @@ var SourceImportCreateSchema = SourceImportSchema.omit({
612
675
  committedAt: true
613
676
  });
614
677
  SourceImportCreateSchema.partial();
678
+ var MAX_CAPTURE_WINDOW_DAYS = 90;
679
+ var DAY_MS = 24 * 60 * 60 * 1e3;
680
+ function isHttpUrl(value) {
681
+ try {
682
+ const { protocol } = new URL(value);
683
+ return protocol === "http:" || protocol === "https:";
684
+ } catch {
685
+ return false;
686
+ }
687
+ }
688
+ var WindowDate = z.union([z.date(), z.string().datetime({ offset: true })]).pipe(z.coerce.date());
689
+ z.object({
690
+ sourceId: ObjectIdString.optional(),
691
+ platform: Platform,
692
+ url: z.string().url().refine(isHttpUrl, "Expected an http(s) URL"),
693
+ label: z.string().min(1).max(200).optional(),
694
+ /** Why a person collects it instead of a scraper. */
695
+ accessIssue: AccessIssue.optional(),
696
+ note: z.string().max(500).optional()
697
+ });
698
+ var LastDaysWindowSchema = z.object({
699
+ mode: z.literal(CaptureWindowMode.enum.last_days),
700
+ days: z.number().int().min(1).max(MAX_CAPTURE_WINDOW_DAYS)
701
+ });
702
+ var RangeWindowSchema = z.object({
703
+ mode: z.literal(CaptureWindowMode.enum.range),
704
+ start: WindowDate,
705
+ end: WindowDate
706
+ });
707
+ z.discriminatedUnion("mode", [LastDaysWindowSchema, RangeWindowSchema]).superRefine((w, ctx) => {
708
+ if (w.mode !== "range" || !(w.start instanceof Date) || !(w.end instanceof Date)) return;
709
+ if (w.end.getTime() <= w.start.getTime()) {
710
+ ctx.addIssue({
711
+ code: z.ZodIssueCode.custom,
712
+ message: "captureWindow.end must be after captureWindow.start",
713
+ path: ["end"]
714
+ });
715
+ } else if (w.end.getTime() - w.start.getTime() > MAX_CAPTURE_WINDOW_DAYS * DAY_MS) {
716
+ ctx.addIssue({
717
+ code: z.ZodIssueCode.custom,
718
+ message: `captureWindow range must be at most ${MAX_CAPTURE_WINDOW_DAYS} days`,
719
+ path: ["end"]
720
+ });
721
+ }
722
+ });
615
723
 
616
724
  // src/mongo/schemas.ts
617
725
  var toObject = { ...toJSONOptions, flattenMaps: true };
@@ -662,6 +770,50 @@ var taskCriteriaSchema = new Schema(
662
770
  },
663
771
  EMBEDDED
664
772
  );
773
+ var taskTargetSchema = new Schema(
774
+ {
775
+ sourceId: { type: ObjectId },
776
+ platform: { type: String, enum: PLATFORM_VALUES, required: true },
777
+ url: { type: String, required: true, minlength: 1 },
778
+ label: { type: String, maxlength: 200 },
779
+ accessIssue: { type: String, enum: ACCESS_ISSUE_VALUES },
780
+ note: { type: String, maxlength: 500 }
781
+ },
782
+ EMBEDDED
783
+ );
784
+ var captureWindowSchema = new Schema(
785
+ {
786
+ mode: { type: String, enum: CAPTURE_WINDOW_MODE_VALUES, required: true },
787
+ days: {
788
+ type: Number,
789
+ min: 1,
790
+ max: MAX_CAPTURE_WINDOW_DAYS,
791
+ validate: Number.isInteger,
792
+ required() {
793
+ return this.mode === "last_days";
794
+ }
795
+ },
796
+ start: {
797
+ type: Date,
798
+ required() {
799
+ return this.mode === "range";
800
+ }
801
+ },
802
+ end: {
803
+ type: Date,
804
+ required() {
805
+ return this.mode === "range";
806
+ },
807
+ validate: {
808
+ validator(end) {
809
+ return !this.start || end.getTime() > this.start.getTime();
810
+ },
811
+ message: "captureWindow.end must be after captureWindow.start"
812
+ }
813
+ }
814
+ },
815
+ EMBEDDED
816
+ );
665
817
  var availabilityWindowSchema = new Schema(
666
818
  {
667
819
  day: { type: Number, enum: [0, 1, 2, 3, 4, 5, 6], required: true },
@@ -835,6 +987,8 @@ var taskSchema = new Schema(
835
987
  keywords: { type: [String], required: true, default: [] },
836
988
  searchQueries: { type: [String], required: true, default: [] },
837
989
  criteria: { type: taskCriteriaSchema, required: true },
990
+ target: { type: taskTargetSchema },
991
+ captureWindow: { type: captureWindowSchema },
838
992
  status: { type: String, enum: TASK_STATUS_VALUES, required: true, default: "draft" },
839
993
  approvedBy: clerkUserIdOptional,
840
994
  approvedAt: { type: Date },
@@ -885,6 +1039,8 @@ var hoursLogSchema = new Schema(
885
1039
  minutes: { type: Number, required: true, min: 1, validate: Number.isInteger },
886
1040
  note: { type: String, required: true, default: "" },
887
1041
  date: { type: Date, required: true },
1042
+ assignmentId: { type: ObjectId },
1043
+ source: { type: String, enum: HOURS_LOG_SOURCE_VALUES },
888
1044
  deletedAt: { type: Date }
889
1045
  },
890
1046
  collectionOptions(COLLECTIONS.hoursLogs)
@@ -1119,6 +1275,7 @@ var agentSessionSchema = new Schema(
1119
1275
  lastSeq: counter,
1120
1276
  stats: { type: agentSessionStatsSchema, required: true, default: () => ({}) },
1121
1277
  budget: { type: agentSessionBudgetSchema, required: true, default: () => ({}) },
1278
+ captureWindow: { type: coverageWindowSchema },
1122
1279
  state: { type: Mixed }
1123
1280
  },
1124
1281
  collectionOptions(COLLECTIONS.agentSessions)
@@ -1171,7 +1328,11 @@ var captureDomSummarySchema = new Schema(
1171
1328
  var captureSchema = new Schema(
1172
1329
  {
1173
1330
  orgId: clerkOrgId,
1174
- sessionId: { type: ObjectId, required: true },
1331
+ sessionId: { type: ObjectId },
1332
+ assignmentId: { type: ObjectId },
1333
+ taskId: { type: ObjectId },
1334
+ missionId: { type: ObjectId },
1335
+ userId: clerkUserIdOptional,
1175
1336
  url: { type: String, required: true },
1176
1337
  title: { type: String, required: true, default: "", maxlength: 500 },
1177
1338
  capturedAt: { type: Date, required: true },
@@ -1184,6 +1345,8 @@ var captureSchema = new Schema(
1184
1345
  status: { type: String, enum: CAPTURE_STATUS_VALUES, required: true, default: "uploaded" },
1185
1346
  analysis: { type: Mixed },
1186
1347
  error: { type: String, maxlength: 1e3 },
1348
+ attempts: { type: Number, required: true, default: 0, min: 0, validate: Number.isInteger },
1349
+ claimedAt: { type: Date },
1187
1350
  expiresAt: { type: Date, required: true }
1188
1351
  },
1189
1352
  collectionOptions(COLLECTIONS.captures)
@@ -1294,6 +1457,6 @@ function registerModels(conn) {
1294
1457
  };
1295
1458
  }
1296
1459
 
1297
- export { COLLECTIONS, INDEXES, MODEL_NAMES, NOT_SOFT_DELETED_FILTER, SCHEMAS, TASK_VERSION_HOOK_OPS, agentMessageSchema, agentSessionBudgetSchema, agentSessionSchema, agentSessionStatsSchema, analystProfileSchema, applyIndexes, assigneeLoadSchema, assignmentSchema, auditLogSchema, auditTargetSchema, availabilityWindowSchema, blobRefSchema, captureDomSummarySchema, captureRegionSchema, captureSchema, collectorSchema, coverageWindowSchema, dataItemContentSchema, dataItemEntitySchema, dataItemSchema, databaseSchema, deploymentSchema, deploymentStepSchema, discoveredBySchema, geoSchema, hoursLogSchema, incrementTaskVersion, llmCallSchema, llmUsageSchema, missionSchema, objectIdsToStrings, orgSettingsSchema, platformAccessSchema, ratingSummarySchema, registerModels, scoutProfileSchema, scoutRatingSchema, scraperMetricSchema, scraperSchema, sourceImportRowErrorSchema, sourceImportSchema, sourceImportSummarySchema, sourceRatingSchema, sourceSchema, specialAccessSchema, systemRecommendationSchema, taskCriteriaSchema, taskSchema, toJSONOptions };
1460
+ export { COLLECTIONS, INDEXES, MODEL_NAMES, NOT_SOFT_DELETED_FILTER, SCHEMAS, TASK_VERSION_HOOK_OPS, agentMessageSchema, agentSessionBudgetSchema, agentSessionSchema, agentSessionStatsSchema, analystProfileSchema, applyIndexes, assigneeLoadSchema, assignmentSchema, auditLogSchema, auditTargetSchema, availabilityWindowSchema, blobRefSchema, captureDomSummarySchema, captureRegionSchema, captureSchema, captureWindowSchema, collectorSchema, coverageWindowSchema, dataItemContentSchema, dataItemEntitySchema, dataItemSchema, databaseSchema, deploymentSchema, deploymentStepSchema, discoveredBySchema, geoSchema, hoursLogSchema, incrementTaskVersion, llmCallSchema, llmUsageSchema, missionSchema, objectIdsToStrings, orgSettingsSchema, platformAccessSchema, ratingSummarySchema, registerModels, scoutProfileSchema, scoutRatingSchema, scraperMetricSchema, scraperSchema, sourceImportRowErrorSchema, sourceImportSchema, sourceImportSummarySchema, sourceRatingSchema, sourceSchema, specialAccessSchema, systemRecommendationSchema, taskCriteriaSchema, taskSchema, taskTargetSchema, toJSONOptions };
1298
1461
  //# sourceMappingURL=index.js.map
1299
1462
  //# sourceMappingURL=index.js.map