@bike4mind/cli 0.18.3 → 0.18.5

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.
@@ -476,6 +476,25 @@ z.enum({
476
476
  ...SpeechToTextModels,
477
477
  ...VideoModels
478
478
  });
479
+ /**
480
+ * Integer credits charged per $1 of provider cost. Derived once with rounding
481
+ * because the raw division carries float noise (0.0006 is inexact in binary):
482
+ * naive ceil((usd * 3) / 0.0006) charges a phantom credit on exact multiples.
483
+ */
484
+ const CREDITS_PER_USD_COST = Math.round(3 / 6e-4);
485
+ /**
486
+ * Converts a USD cost to credits, including markup
487
+ * @param usd - The raw provider cost in USD to convert
488
+ * @returns The number of credits with markup, rounded up to the nearest whole number (minimum 1)
489
+ *
490
+ * Examples:
491
+ * $1 USD = 5000 credits (3× markup at $0.0006/credit)
492
+ * $0.001 USD = 5 credits
493
+ * $0.0001 USD = 1 credit (minimum)
494
+ */
495
+ const usdToCredits = (usd) => {
496
+ return Math.max(1, Math.ceil(usd * CREDITS_PER_USD_COST));
497
+ };
479
498
  z$1.enum([
480
499
  "openai",
481
500
  "test",
@@ -1242,6 +1261,51 @@ const CREDIT_DEDUCT_TRANSACTION_TYPES = [
1242
1261
  "transfer_credit",
1243
1262
  "generic_deduct"
1244
1263
  ];
1264
+ z.object({
1265
+ id: z.string().optional(),
1266
+ /** App-level correlation id: questId for chat/image/video, session/run id otherwise. */
1267
+ requestId: z.string(),
1268
+ userId: z.string(),
1269
+ /** Credit holder actually debited (user or organization). */
1270
+ ownerId: z.string(),
1271
+ ownerType: z.enum(CreditHolderType),
1272
+ sessionId: z.string().optional(),
1273
+ feature: z.enum([
1274
+ "chat",
1275
+ "image_generation",
1276
+ "image_edit",
1277
+ "video_generation",
1278
+ "voice",
1279
+ "transcription",
1280
+ "agent_execution",
1281
+ "completion_api",
1282
+ "tool"
1283
+ ]),
1284
+ /** Provider/backend, e.g. 'bedrock', 'openai', 'gemini'. */
1285
+ provider: z.string(),
1286
+ /** Exact model id string used for the call. */
1287
+ model: z.string(),
1288
+ inputTokens: z.number().default(0),
1289
+ outputTokens: z.number().default(0),
1290
+ cachedInputTokens: z.number().default(0),
1291
+ cacheWriteTokens: z.number().default(0),
1292
+ providerInputTokens: z.number().optional(),
1293
+ providerOutputTokens: z.number().optional(),
1294
+ /** Images generated / video seconds, for per-unit modalities. */
1295
+ units: z.number().optional(),
1296
+ /** True provider COGS in USD, computed and frozen at write time. */
1297
+ costUsd: z.number(),
1298
+ /** Credits actually debited from the owner for this call. */
1299
+ creditsCharged: z.number(),
1300
+ status: z.enum([
1301
+ "ok",
1302
+ "error",
1303
+ "timeout"
1304
+ ]).default("ok"),
1305
+ latencyMs: z.number().optional(),
1306
+ createdAt: z.date(),
1307
+ updatedAt: z.date()
1308
+ });
1245
1309
  let ResearchTaskExecutionType = /* @__PURE__ */ function(ResearchTaskExecutionType) {
1246
1310
  /**
1247
1311
  * The task is executed on demand
@@ -1628,6 +1692,23 @@ let SupportedFabFileMimeTypes = /* @__PURE__ */ function(SupportedFabFileMimeTyp
1628
1692
  return SupportedFabFileMimeTypes;
1629
1693
  }({});
1630
1694
  /**
1695
+ * The canonical set of MIME types the ingest pipeline can actually chunk +
1696
+ * vectorize. Kept in lockstep with the `SmartChunker` switch in
1697
+ * `@bike4mind/fab-pipeline`.
1698
+ */
1699
+ const SUPPORTED_FAB_FILE_MIME_TYPES = new Set(Object.values(SupportedFabFileMimeTypes));
1700
+ /**
1701
+ * Type guard: is a claimed MIME type one we actually support ingesting?
1702
+ *
1703
+ * Used to gate uploads so unsupported/binary files (e.g. `.exe`) are rejected
1704
+ * with a clear error instead of being stored and silently "vectorized" into 0
1705
+ * chunks. Node-free so it can run on both the client (upload UI) and server
1706
+ * (ingest endpoints).
1707
+ */
1708
+ function isSupportedFabFileMimeType(mimeType) {
1709
+ return !!mimeType && SUPPORTED_FAB_FILE_MIME_TYPES.has(mimeType);
1710
+ }
1711
+ /**
1631
1712
  * Canonical agent execution status tuple. Shared between the database model
1632
1713
  * (`AgentExecutionModel`), the client store (`useAgentExecutionStore`), and
1633
1714
  * wire schemas (`ChildExecutionSnapshotSchema`, etc.) so the value space can't
@@ -2071,6 +2152,17 @@ const DataLakeBatchProgressAction = z.object({
2071
2152
  "cancelled"
2072
2153
  ]).optional()
2073
2154
  });
2155
+ /** Verdict for a freshly-uploaded FabFile after the S3-event moderation scan (#9776 Q2b). */
2156
+ const ImageModerationStatusAction = z.object({
2157
+ action: z.literal("image_moderation_status"),
2158
+ clientId: z.string().optional(),
2159
+ fabFileId: z.string(),
2160
+ moderationStatus: z.enum([
2161
+ "pending",
2162
+ "clean",
2163
+ "blocked"
2164
+ ])
2165
+ });
2074
2166
  const UpdateResearchTaskStatusAction = z.object({
2075
2167
  action: z.literal("update_research_task_status"),
2076
2168
  clientId: z.string().optional(),
@@ -2969,6 +3061,7 @@ z.discriminatedUnion("action", [
2969
3061
  TavernStockUpdateAction,
2970
3062
  JupyterNotebookProgressAction,
2971
3063
  DataLakeBatchProgressAction,
3064
+ ImageModerationStatusAction,
2972
3065
  CcAgentCommandAction,
2973
3066
  QuantumRunUpdatedAction,
2974
3067
  ExecutionStartedAction,
@@ -3574,14 +3667,27 @@ z$1.object({
3574
3667
  prefix: z$1.string().optional()
3575
3668
  });
3576
3669
  /**
3577
- * Constants for BFL safety tolerance settings
3670
+ * Constants for BFL safety tolerance settings.
3671
+ *
3672
+ * BFL scale: 0 = strictest filtering, 6 = effectively unfiltered. MAX is a
3673
+ * hard cap (#9776, 18 U.S.C. §2258A exposure) — enforced in the zod schemas
3674
+ * here AND clamped last-mile in BFLImageService, so no caller can raise it.
3675
+ * BFL itself caps its editing endpoints at 2.
3578
3676
  */
3579
3677
  const BFL_SAFETY_TOLERANCE = {
3580
3678
  MIN: 0,
3581
- MAX: 6,
3582
- DEFAULT: 4
3679
+ MAX: 2,
3680
+ DEFAULT: 2,
3681
+ /** Pre-cap sessions may have stored up to 6 — accepted as input, clamped to MAX on parse. */
3682
+ LEGACY_INPUT_MAX: 6
3583
3683
  };
3584
3684
  /**
3685
+ * Shared safety_tolerance schema: accepts the legacy 0-6 stored range but
3686
+ * clamps the parsed output to the hard cap (coerce, not reject — rejecting
3687
+ * would break image generation for sessions saved before the cap existed).
3688
+ */
3689
+ const BFLSafetyToleranceSchema = z.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.LEGACY_INPUT_MAX).optional().prefault(BFL_SAFETY_TOLERANCE.DEFAULT).transform((value) => Math.min(value, BFL_SAFETY_TOLERANCE.MAX));
3690
+ /**
3585
3691
  * List of image models supported by BlackForest Labs
3586
3692
  */
3587
3693
  const BFL_IMAGE_MODELS = [
@@ -3594,7 +3700,7 @@ const BFL_IMAGE_MODELS = [
3594
3700
  ];
3595
3701
  const CommonBFLParams = z.object({
3596
3702
  prompt: z.string().nullable().optional(),
3597
- safety_tolerance: z.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().prefault(BFL_SAFETY_TOLERANCE.DEFAULT),
3703
+ safety_tolerance: BFLSafetyToleranceSchema,
3598
3704
  output_format: z.enum(["jpeg", "png"]).nullable().optional().prefault("jpeg"),
3599
3705
  image_prompt: z.string().nullable().optional(),
3600
3706
  webhook_url: z.string().min(1).max(2083).nullable().optional(),
@@ -3966,6 +4072,7 @@ z.enum([
3966
4072
  "EnableInertArtifactRender",
3967
4073
  "pricePerCredit",
3968
4074
  "ModerationEnabled",
4075
+ "ImageModerationEnabled",
3969
4076
  "tagLineMain",
3970
4077
  "tagLineSub",
3971
4078
  "defaultTags",
@@ -4025,6 +4132,7 @@ z.enum([
4025
4132
  "enforceCredits",
4026
4133
  "enableTeamPlan",
4027
4134
  "allowOpenRegistration",
4135
+ "blockDisposableEmails",
4028
4136
  "defaultFreeCredits",
4029
4137
  "enableGoogleCalendar",
4030
4138
  "googleCalendarServiceAccountEmail",
@@ -4040,6 +4148,7 @@ z.enum([
4040
4148
  "SlackLiveopsWebhookUrl",
4041
4149
  "SlackUserActivityWebhookUrl",
4042
4150
  "SlackFeedbackWebhookUrl",
4151
+ "SlackEmailAuditWebhookUrl",
4043
4152
  "slackSigningSecret",
4044
4153
  "slackBotToken",
4045
4154
  "enforceMFA",
@@ -4050,7 +4159,6 @@ z.enum([
4050
4159
  "voiceSessionTranscriptionModel",
4051
4160
  "voiceSessionVadType",
4052
4161
  "voiceSessionVadEagerness",
4053
- "pdfjsExpressViewerKey",
4054
4162
  "EnableEmailAnalysis",
4055
4163
  "EmailAnalysisModel",
4056
4164
  "EmailAnalysisTemperature",
@@ -4081,6 +4189,9 @@ z.enum([
4081
4189
  "contextTelemetryAlerts",
4082
4190
  "sreAgentConfig",
4083
4191
  "secopsTriageConfig",
4192
+ "apiRateLimitFreePerMin",
4193
+ "apiRateLimitBasicPerMin",
4194
+ "apiRateLimitProPerMin",
4084
4195
  "overwatchRollupSync",
4085
4196
  "orchestrationDefaults"
4086
4197
  ]);
@@ -4979,6 +5090,10 @@ const API_SERVICE_GROUPS = {
4979
5090
  key: "SlackUserActivityWebhookUrl",
4980
5091
  order: 6
4981
5092
  },
5093
+ {
5094
+ key: "SlackEmailAuditWebhookUrl",
5095
+ order: 6.5
5096
+ },
4982
5097
  {
4983
5098
  key: "FeedbackSendEmailUsername",
4984
5099
  order: 7
@@ -5384,16 +5499,6 @@ const API_SERVICE_GROUPS = {
5384
5499
  order: 1
5385
5500
  }]
5386
5501
  },
5387
- PDF_VIEWER: {
5388
- id: "pdfViewerService",
5389
- name: "PDF Viewer",
5390
- description: "PDF.js Express Viewer settings",
5391
- icon: "PictureAsPdf",
5392
- settings: [{
5393
- key: "pdfjsExpressViewerKey",
5394
- order: 1
5395
- }]
5396
- },
5397
5502
  DATETIME_ASTRONOMY: {
5398
5503
  id: "datetimeAstronomyService",
5399
5504
  name: "Time Machine & Night Sky",
@@ -5413,13 +5518,33 @@ const API_SERVICE_GROUPS = {
5413
5518
  order: 3
5414
5519
  }
5415
5520
  ]
5521
+ },
5522
+ RATE_LIMITING: {
5523
+ id: "rateLimitingService",
5524
+ name: "API Rate Limiting",
5525
+ description: "Per-user request rate limits on /chat and /opti, tunable per subscription tier (#9780)",
5526
+ icon: "Speed",
5527
+ settings: [
5528
+ {
5529
+ key: "apiRateLimitFreePerMin",
5530
+ order: 1
5531
+ },
5532
+ {
5533
+ key: "apiRateLimitBasicPerMin",
5534
+ order: 2
5535
+ },
5536
+ {
5537
+ key: "apiRateLimitProPerMin",
5538
+ order: 3
5539
+ }
5540
+ ]
5416
5541
  }
5417
5542
  };
5418
5543
  const settingsMap = {
5419
5544
  DefaultAPIModel: makeStringSetting({
5420
5545
  key: "DefaultAPIModel",
5421
5546
  name: "Default API Model",
5422
- defaultValue: "claude-sonnet-5",
5547
+ defaultValue: "global.anthropic.claude-sonnet-5",
5423
5548
  description: "The default AI model to use for API requests when no model is specified.",
5424
5549
  options: CHAT_MODELS,
5425
5550
  category: "AI",
@@ -5699,6 +5824,13 @@ const settingsMap = {
5699
5824
  description: "Whether to enable moderation for LLM prompts.",
5700
5825
  category: "AI Moderation"
5701
5826
  }),
5827
+ ImageModerationEnabled: makeBooleanSetting({
5828
+ key: "ImageModerationEnabled",
5829
+ name: "Image Moderation Enabled",
5830
+ defaultValue: true,
5831
+ description: "Whether to run generated images through content moderation (Rekognition) and block explicit content. Legal-safety control (#9776) — default ON.",
5832
+ category: "AI Moderation"
5833
+ }),
5702
5834
  FormatPromptTemplate: makeStringSetting({
5703
5835
  key: "FormatPromptTemplate",
5704
5836
  name: "Format Prompt Template",
@@ -5748,6 +5880,39 @@ const settingsMap = {
5748
5880
  group: API_SERVICE_GROUPS.CREDITS.id,
5749
5881
  order: 1
5750
5882
  }),
5883
+ apiRateLimitFreePerMin: makeNumberSetting({
5884
+ key: "apiRateLimitFreePerMin",
5885
+ name: "API Rate Limit — Free (requests/min)",
5886
+ defaultValue: 10,
5887
+ min: 1,
5888
+ max: 1e5,
5889
+ description: "Max /chat and /opti requests per minute for users with no active paid subscription.",
5890
+ category: "SecOps",
5891
+ group: API_SERVICE_GROUPS.RATE_LIMITING.id,
5892
+ order: 1
5893
+ }),
5894
+ apiRateLimitBasicPerMin: makeNumberSetting({
5895
+ key: "apiRateLimitBasicPerMin",
5896
+ name: "API Rate Limit — Basic (requests/min)",
5897
+ defaultValue: 30,
5898
+ min: 1,
5899
+ max: 1e5,
5900
+ description: "Max /chat and /opti requests per minute for Basic-tier subscribers (e.g. Professional plan).",
5901
+ category: "SecOps",
5902
+ group: API_SERVICE_GROUPS.RATE_LIMITING.id,
5903
+ order: 2
5904
+ }),
5905
+ apiRateLimitProPerMin: makeNumberSetting({
5906
+ key: "apiRateLimitProPerMin",
5907
+ name: "API Rate Limit — Pro (requests/min)",
5908
+ defaultValue: 60,
5909
+ min: 1,
5910
+ max: 1e5,
5911
+ description: "Max /chat and /opti requests per minute for Pro-tier subscribers.",
5912
+ category: "SecOps",
5913
+ group: API_SERVICE_GROUPS.RATE_LIMITING.id,
5914
+ order: 3
5915
+ }),
5751
5916
  tagLineMain: makeStringSetting({
5752
5917
  key: "tagLineMain",
5753
5918
  name: "Tag Line Main",
@@ -5889,6 +6054,16 @@ const settingsMap = {
5889
6054
  order: 7,
5890
6055
  isSensitive: true
5891
6056
  }),
6057
+ SlackEmailAuditWebhookUrl: makeStringSetting({
6058
+ key: "SlackEmailAuditWebhookUrl",
6059
+ name: "Email Audit Channel Webhook URL",
6060
+ defaultValue: "",
6061
+ description: "Incoming-webhook URL for mirroring a redacted copy of every outbound email to a dedicated audit Slack channel (e.g. #b4m-emails) for real-time visibility (#9872). Use a PRIVATE, need-to-know channel — mirrored copies contain recipient email addresses. Secrets/tokens (reset & verification links) are redacted before posting.",
6062
+ category: "Feedback",
6063
+ group: API_SERVICE_GROUPS.FEEDBACK.id,
6064
+ order: 8,
6065
+ isSensitive: true
6066
+ }),
5892
6067
  liveFeedbackEmail: makeStringSetting({
5893
6068
  key: "liveFeedbackEmail",
5894
6069
  name: "Live Feedback Email",
@@ -6075,6 +6250,14 @@ const settingsMap = {
6075
6250
  group: API_SERVICE_GROUPS.CREDITS.id,
6076
6251
  category: "Users"
6077
6252
  }),
6253
+ blockDisposableEmails: makeBooleanSetting({
6254
+ key: "blockDisposableEmails",
6255
+ name: "Block Disposable Emails",
6256
+ defaultValue: true,
6257
+ description: "Rejects new registrations whose email domain (or any parent domain) is a known disposable/burner provider — free credits cannot be farmed with throwaway inboxes (#9779). Applies at registration only; existing accounts on such domains can still sign in. Turn OFF only to work around a false positive.",
6258
+ group: API_SERVICE_GROUPS.CREDITS.id,
6259
+ category: "Users"
6260
+ }),
6078
6261
  defaultFreeCredits: makeNumberSetting({
6079
6262
  key: "defaultFreeCredits",
6080
6263
  name: "Default Free Credits",
@@ -6662,16 +6845,6 @@ const settingsMap = {
6662
6845
  order: 10,
6663
6846
  schema: RapidReplySettingsSchema
6664
6847
  }),
6665
- pdfjsExpressViewerKey: makeStringSetting({
6666
- key: "pdfjsExpressViewerKey",
6667
- name: "PDF.js Express Viewer Key",
6668
- defaultValue: "",
6669
- description: "The license key for PDF.js Express Viewer for PDF document viewing.",
6670
- isSensitive: true,
6671
- category: "Tools",
6672
- group: API_SERVICE_GROUPS.PDF_VIEWER.id,
6673
- order: 1
6674
- }),
6675
6848
  EnableEmailAnalysis: makeBooleanSetting({
6676
6849
  key: "EnableEmailAnalysis",
6677
6850
  name: "Enable Email Analysis",
@@ -8314,7 +8487,8 @@ z$1.object({
8314
8487
  description: z$1.string().max(2e3).optional(),
8315
8488
  fileTagPrefix: z$1.string().min(2).max(30).refine((s) => s.endsWith(":"), "Tag prefix must end with \":\" (e.g. \"acme:\")"),
8316
8489
  requiredUserTag: z$1.string().min(1).max(100).optional(),
8317
- requiredEntitlement: z$1.string().min(3).max(100).refine((s) => s.includes(":") && s.split(":").every((part) => part.length > 0), "Entitlement key must be namespaced with non-empty parts (e.g. \"product:pro\")").optional()
8490
+ requiredEntitlement: z$1.string().min(3).max(100).refine((s) => s.includes(":") && s.split(":").every((part) => part.length > 0), "Entitlement key must be namespaced with non-empty parts (e.g. \"product:pro\")").optional(),
8491
+ organizationId: z$1.string().optional()
8318
8492
  });
8319
8493
  z$1.object({
8320
8494
  name: z$1.string().min(1).max(200).optional(),
@@ -8464,6 +8638,7 @@ const PromptBatchQuerySchema = z.object({
8464
8638
  z.object({ queries: z.array(PromptBatchQuerySchema).min(1).max(32).refine((qs) => new Set(qs.map((q) => q.key)).size === qs.length, { message: "Batch query keys must be unique" }) });
8465
8639
  const DATA_LAKES = [{
8466
8640
  id: "ionq-sales",
8641
+ slug: "ionq-sales",
8467
8642
  name: "IonQ Sales Intelligence",
8468
8643
  requiredUserTag: "Opti",
8469
8644
  requiredEntitlement: "optihashi:pro",
@@ -8471,6 +8646,7 @@ const DATA_LAKES = [{
8471
8646
  datalakeTag: "datalake:ionq-sales"
8472
8647
  }, {
8473
8648
  id: "opti-knowledge",
8649
+ slug: "opti-knowledge",
8474
8650
  name: "Optimization Knowledge Base",
8475
8651
  requiredUserTag: "Opti",
8476
8652
  requiredEntitlement: "optihashi:pro",
@@ -8511,12 +8687,14 @@ function lakeMatchesAccess(lake, normalizedUserTags, normalizedKeys) {
8511
8687
  function toDataLakeConfig(dl) {
8512
8688
  return {
8513
8689
  id: dl.id,
8690
+ slug: dl.slug,
8514
8691
  name: dl.name,
8515
8692
  requiredUserTag: dl.requiredUserTag,
8516
8693
  requiredEntitlement: dl.requiredEntitlement,
8517
8694
  fileTagPrefix: dl.fileTagPrefix,
8518
8695
  datalakeTag: dl.datalakeTag,
8519
- organizationId: dl.organizationId
8696
+ organizationId: dl.organizationId,
8697
+ description: dl.description
8520
8698
  };
8521
8699
  }
8522
8700
  /**
@@ -8773,7 +8951,8 @@ z.object({
8773
8951
  "classifier",
8774
8952
  "mention",
8775
8953
  "user-default",
8776
- "agent_literal"
8954
+ "agent_literal",
8955
+ "complexity"
8777
8956
  ])
8778
8957
  }).optional()
8779
8958
  }).extend({
@@ -9425,6 +9604,28 @@ z.object({
9425
9604
  /** Custom notebook name (optional, defaults to curated-notebook-{sessionId}) */
9426
9605
  customNotebookName: z.string().optional()
9427
9606
  });
9607
+ /**
9608
+ * ImageModerationIncident — audit record for a generated image blocked by
9609
+ * auto-moderation (#9776 Q2a). Metadata-only (no image bytes); byte
9610
+ * preservation for §2258A retention is a later quest.
9611
+ */
9612
+ const ModerationLabelHitSchema = z.object({
9613
+ name: z.string(),
9614
+ parentName: z.string(),
9615
+ confidence: z.number()
9616
+ });
9617
+ z.object({
9618
+ userId: z.string(),
9619
+ sessionId: z.string().optional(),
9620
+ questId: z.string().optional(),
9621
+ /** Uploaded-image incidents (#9776 Q2b) reference the FabFile instead of a quest/session. */
9622
+ fabFileId: z.string().optional(),
9623
+ provider: z.string(),
9624
+ model: z.string(),
9625
+ labels: z.array(ModerationLabelHitSchema),
9626
+ createdAt: z.union([z.string(), z.date()]).optional(),
9627
+ updatedAt: z.union([z.string(), z.date()]).optional()
9628
+ });
9428
9629
  function isGPTImageModel(model) {
9429
9630
  if (!model) return false;
9430
9631
  return OPENAI_IMAGE_MODELS.includes(model) || model.startsWith("gpt-image-");
@@ -9597,7 +9798,7 @@ z.array(triggerWordSchema).max(20, "Up to 20 trigger words allowed.").transform(
9597
9798
  * - `$1`, `$2`, ... — individual positional args
9598
9799
  *
9599
9800
  * Why a shared helper: the CLI already implemented this in
9600
- * `apps/cli/src/utils/argumentSubstitution.ts`. Centralizing here avoids a
9801
+ * `packages/cli/src/utils/argumentSubstitution.ts`. Centralizing here avoids a
9601
9802
  * second drift surface — a skill body authored on the web and run in the CLI
9602
9803
  * (or vice versa) must expand identically.
9603
9804
  */
@@ -9706,6 +9907,33 @@ function intersectAllowedTools(skillAllowedTools, invokerAllowedTools) {
9706
9907
  const invokerSet = new Set(invokerAllowedTools);
9707
9908
  return skillAllowedTools.filter((tool) => invokerSet.has(tool));
9708
9909
  }
9910
+ /**
9911
+ * Serve gate for uploaded FabFiles (#9776 Q2b, hold-until-scanned; P1-1 fail-closed on ALL
9912
+ * mime types, not just images). A file is serveable only once moderation has run to
9913
+ * completion on it — REGARDLESS of its declared `mimeType`.
9914
+ *
9915
+ * Why gate non-images too: `mimeType` is client-declared at upload time and is only
9916
+ * corrected by the S3 scan ~1-2s later (see `moderateUploadedFile`'s byte-sniffing). If this
9917
+ * gate special-cased "non-images always serveable" based on that same untrusted declared
9918
+ * mimeType, a file uploaded as `application/pdf` but actually a PNG (or vice versa) would be
9919
+ * served during that window before the sniff/scan ever runs. Gating on `moderationStatus`
9920
+ * alone closes that window for every file, image or not.
9921
+ *
9922
+ * `moderationStatus` semantics:
9923
+ * - 'clean' -> serveable
9924
+ * - 'pending' | 'scanning' -> NOT serveable (not yet through the scan)
9925
+ * - 'blocked' -> NOT serveable (confirmed block / unscannable format)
9926
+ * - null | undefined -> NOT serveable (fail-closed; legacy pre-Q2b rows are
9927
+ * backfilled to 'clean', see backfill-fabfile-moderation-status.ts)
9928
+ *
9929
+ * Non-image files (PDFs, docs, text, ...) are NOT scanned by Rekognition, but they still
9930
+ * pass through `moderateUploadedFile`/`objectCreated`, which resolves them to 'clean'
9931
+ * immediately (no image bytes to hold on) — so the hold is brief (one S3 event round trip),
9932
+ * not an indefinite block.
9933
+ */
9934
+ function isImageServeable(f) {
9935
+ return f.moderationStatus === "clean";
9936
+ }
9709
9937
  const VIEW_REGISTRY = [
9710
9938
  {
9711
9939
  id: "opti.root",
@@ -10693,7 +10921,7 @@ QWORK_PROVIDERS.filter((p) => QWORK_PROVIDER_CAPABILITIES[p].enabled);
10693
10921
  //#region src/utils/apiUrl.ts
10694
10922
  /**
10695
10923
  * Default service endpoint, baked in at build time via tsdown's `env` option
10696
- * (see `apps/cli/tsdown.config.ts`). The hosted publisher builds with its own
10924
+ * (see `packages/cli/tsdown.config.ts`). The hosted publisher builds with its own
10697
10925
  * service as the default; a fork sets `B4M_DEFAULT_API_URL` to publish under a
10698
10926
  * different brand, so a fork's bundle never embeds the upstream brand literal.
10699
10927
  * Empty when unset — the user then supplies an endpoint via `/set-api` or the
@@ -11130,7 +11358,7 @@ const CliConfigSchema = z.object({
11130
11358
  enableCoordinatorMode: z.boolean().optional().prefault(false),
11131
11359
  /**
11132
11360
  * System-prompt variant. 'current' uses the elaborate behavioral-scaffolding
11133
- * prompt; 'minimal' uses a pi-style short prompt. See apps/cli/src/core/prompts.ts.
11361
+ * prompt; 'minimal' uses a pi-style short prompt. See packages/cli/src/core/prompts.ts.
11134
11362
  * Defaults to 'current' for backward compatibility; switch via /config or by
11135
11363
  * editing the config file directly.
11136
11364
  */
@@ -11884,4 +12112,4 @@ var ConfigStore = class {
11884
12112
  }
11885
12113
  };
11886
12114
  //#endregion
11887
- export { PermissionDeniedError as $, wrapUntrustedSkillBody as $t, FriendshipEvents as A, XAI_IMAGE_MODELS as At, InboxEvents as B, isSupportedEmbeddingModel as Bt, CorruptedFileError as C, TransferCreditTransaction as Ct, FeedbackEvents as D, VIDEO_SIZE_CONSTRAINTS as Dt, FavoriteDocumentType as E, UnprocessableEntityError as Et, HTTPError as F, getViewById as Ft, LLMEvents as G, resolveNavigationIntents as Gt, InviteEvents as H, mapMimeTypeToArtifactType as Ht, HttpStatus as I, intersectAllowedTools as It, ModelBackend as J, settingsMap as Jt, MiscEvents as K, sanitizeTelemetryError as Kt, ImageEditUsageTransaction as L, isGPTImage2Model as Lt, GenerateImageToolCallSchema as M, dayjsConfig_default as Mt, GenericCreditAddTransaction as N, getAccessibleDataLakes as Nt, FileEvents as O, VideoGenerationUsageTransaction as Ot, GenericCreditDeductTransaction as P, getMcpProviderMetadata as Pt, Permission as Q, validateNotebookPath as Qt, ImageGenerationUsageTransaction as R, isGPTImageModel as Rt, CompletionApiUsageTransaction as S, ToolUsageTransaction as St, ElabsEvents as T, UnauthorizedError as Tt, InviteType as U, obfuscateApiKey as Ut, InternalServerError as V, isZodError as Vt, KnowledgeType as W, parseSkillArguments as Wt, OpenAIEmbeddingModel as X, toDataLakeConfig as Xt, NotFoundError as Y, substituteArguments as Yt, OpenAIImageGenerationInput as Z, validateJupyterKernelName as Zt, BadRequestError as _, SupportedFabFileMimeTypes as _t, getDefaultApiUrl as a, QuestMasterParamsSchema as at, ChatModels as b, TextGenerationUsageTransaction as bt, AiEvents as c, RechartsChartTypeList as ct, ApiKeyType as d, ResearchTaskExecutionType as dt, buildRateLimitLogEntry as en, ProfileEvents as et, AppFileEvents as f, ResearchTaskPeriodicFrequencyType as ft, BFL_SAFETY_TOLERANCE as g, SubscriptionCreditTransaction as gt, BFL_IMAGE_MODELS as h, SpeechToTextUsageTransaction as ht, getCreditsUrl as i, CollectionType as in, PurchaseTransaction as it, GEMINI_IMAGE_MODELS as j, b4mLLMTools as jt, ForbiddenError as k, VideoModels as kt, ApiKeyEvents as l, RegInviteEvents as lt, AuthEvents as m, SessionEvents as mt, logger as n, isNearLimit as nn, PromptIntentSchema as nt, getEnvironmentName as o, RealtimeVoiceUsageTransaction as ot, ArtifactTypeSchema as p, ResearchTaskType as pt, ModalEvents as q, secureParameters as qt, getApiUrl as r, parseRateLimitHeaders as rn, PromptMetaZodSchema as rt, ALERT_THRESHOLDS as s, ReceivedCreditTransaction as st, ConfigStore as t, extractSnippetMeta as tn, ProjectEvents as tt, ApiKeyScope as u, ResearchModeParamsSchema as ut, CREDIT_DEDUCT_TRANSACTION_TYPES as v, TagType as vt, DashboardParamsSchema as w, UiNavigationEvents as wt, ClaudeArtifactMimeTypes as x, TooManyRequestsError as xt, ChatCompletionCreateInputSchema as y, TaskScheduleHandler as yt, ImageModels as z, isModelAccessible as zt };
12115
+ export { Permission as $, toDataLakeConfig as $t, ForbiddenError as A, VideoModels as At, ImageModels as B, isImageServeable as Bt, CompletionApiUsageTransaction as C, ToolUsageTransaction as Ct, FavoriteDocumentType as D, UnprocessableEntityError as Dt, ElabsEvents as E, UnauthorizedError as Et, GenericCreditDeductTransaction as F, getMcpProviderMetadata as Ft, KnowledgeType as G, mapMimeTypeToArtifactType as Gt, InternalServerError as H, isSupportedEmbeddingModel as Ht, HTTPError as I, getViewById as It, ModalEvents as J, resolveNavigationIntents as Jt, LLMEvents as K, obfuscateApiKey as Kt, HttpStatus as L, intersectAllowedTools as Lt, GEMINI_IMAGE_MODELS as M, b4mLLMTools as Mt, GenerateImageToolCallSchema as N, dayjsConfig_default as Nt, FeedbackEvents as O, VIDEO_SIZE_CONSTRAINTS as Ot, GenericCreditAddTransaction as P, getAccessibleDataLakes as Pt, OpenAIImageGenerationInput as Q, substituteArguments as Qt, ImageEditUsageTransaction as R, isGPTImage2Model as Rt, ClaudeArtifactMimeTypes as S, TooManyRequestsError as St, DashboardParamsSchema as T, UiNavigationEvents as Tt, InviteEvents as U, isSupportedFabFileMimeType as Ut, InboxEvents as V, isModelAccessible as Vt, InviteType as W, isZodError as Wt, NotFoundError as X, secureParameters as Xt, ModelBackend as Y, sanitizeTelemetryError as Yt, OpenAIEmbeddingModel as Z, settingsMap as Zt, BFL_SAFETY_TOLERANCE as _, SubscriptionCreditTransaction as _t, getDefaultApiUrl as a, extractSnippetMeta as an, PurchaseTransaction as at, ChatCompletionCreateInputSchema as b, TaskScheduleHandler as bt, AiEvents as c, CollectionType as cn, ReceivedCreditTransaction as ct, ApiKeyType as d, ResearchModeParamsSchema as dt, usdToCredits as en, PermissionDeniedError as et, AppFileEvents as f, ResearchTaskExecutionType as ft, BFL_IMAGE_MODELS as g, SpeechToTextUsageTransaction as gt, BFLSafetyToleranceSchema as h, SessionEvents as ht, getCreditsUrl as i, buildRateLimitLogEntry as in, PromptMetaZodSchema as it, FriendshipEvents as j, XAI_IMAGE_MODELS as jt, FileEvents as k, VideoGenerationUsageTransaction as kt, ApiKeyEvents as l, RechartsChartTypeList as lt, AuthEvents as m, ResearchTaskType as mt, logger as n, validateNotebookPath as nn, ProjectEvents as nt, getEnvironmentName as o, isNearLimit as on, QuestMasterParamsSchema as ot, ArtifactTypeSchema as p, ResearchTaskPeriodicFrequencyType as pt, MiscEvents as q, parseSkillArguments as qt, getApiUrl as r, wrapUntrustedSkillBody as rn, PromptIntentSchema as rt, ALERT_THRESHOLDS as s, parseRateLimitHeaders as sn, RealtimeVoiceUsageTransaction as st, ConfigStore as t, validateJupyterKernelName as tn, ProfileEvents as tt, ApiKeyScope as u, RegInviteEvents as ut, BadRequestError as v, SupportedFabFileMimeTypes as vt, CorruptedFileError as w, TransferCreditTransaction as wt, ChatModels as x, TextGenerationUsageTransaction as xt, CREDIT_DEDUCT_TRANSACTION_TYPES as y, TagType as yt, ImageGenerationUsageTransaction as z, isGPTImageModel as zt };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as getDefaultApiUrl, t as ConfigStore } from "../ConfigStore-DL7p3ZiY.mjs";
2
+ import { a as getDefaultApiUrl, t as ConfigStore } from "../ConfigStore-D39UqFnY.mjs";
3
3
  //#region src/commands/apiCommand.ts
4
4
  /**
5
5
  * External API config command (--api-url / --reset-api)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-B-ONmxJ7.mjs";
2
+ import { t as version } from "../package-I_v_WFUn.mjs";
3
3
  import { a as fetchLatestVersion, c as isNpmPrefixWritable, i as compareSemver } from "../updateChecker-C8xsNY2L.mjs";
4
4
  import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
5
5
  import { execSync } from "child_process";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-DL7p3ZiY.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-D39UqFnY.mjs";
3
3
  //#region src/commands/envCommand.ts
4
4
  /**
5
5
  * Environment switching for the `--dev` / `--prod` launch flags.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { C as createCoordinateTaskTool, D as FallbackLlmBackend, E as ApiClient, F as generateCliTools, G as ReActAgent, N as loadContextFiles, O as ServerLlmBackend, P as PermissionManager, Q as CheckpointStore, T as createAgentDelegateTool, W as setWebSocketToolExecutor, X as RemoteSkillSource, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createGetFileStructureTool, a as WebSocketToolExecutor, b as createWriteTodosTool, et as SessionStore, i as McpManager, n as SubagentOrchestrator, o as WebSocketConnectionManager, q as buildSystemPrompt, r as AgentStore, s as WebSocketLlmBackend, t as BackgroundAgentManager, v as createFindDefinitionTool, w as createBackgroundAgentTools, x as createSkillTool, y as createTodoStore } from "../BackgroundAgentManager-H_MnlEXz.mjs";
3
- import { n as logger, r as getApiUrl, t as ConfigStore } from "../ConfigStore-DL7p3ZiY.mjs";
2
+ import { C as createCoordinateTaskTool, D as FallbackLlmBackend, E as ApiClient, F as generateCliTools, G as ReActAgent, N as loadContextFiles, O as ServerLlmBackend, P as PermissionManager, Q as CheckpointStore, T as createAgentDelegateTool, W as setWebSocketToolExecutor, X as RemoteSkillSource, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createGetFileStructureTool, a as WebSocketToolExecutor, b as createWriteTodosTool, et as SessionStore, i as McpManager, n as SubagentOrchestrator, o as WebSocketConnectionManager, q as buildSystemPrompt, r as AgentStore, s as WebSocketLlmBackend, t as BackgroundAgentManager, v as createFindDefinitionTool, w as createBackgroundAgentTools, x as createSkillTool, y as createTodoStore } from "../BackgroundAgentManager-D-xsWd3C.mjs";
3
+ import { n as logger, r as getApiUrl, t as ConfigStore } from "../ConfigStore-D39UqFnY.mjs";
4
4
  import { t as DEFAULT_SANDBOX_CONFIG } from "../types-LyRNHOiS.mjs";
5
5
  import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-ChGlxSGQ.mjs";
6
6
  import { t as SandboxOrchestrator } from "../SandboxOrchestrator-BoINxbX4.mjs";
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as ConfigStore } from "../ConfigStore-DL7p3ZiY.mjs";
2
+ import { t as ConfigStore } from "../ConfigStore-D39UqFnY.mjs";
3
3
  //#region src/commands/mcpCommand.ts
4
4
  /**
5
5
  * External MCP commands (b4m mcp list, b4m mcp add, etc.)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-B-ONmxJ7.mjs";
2
+ import { t as version } from "../package-I_v_WFUn.mjs";
3
3
  import { c as isNpmPrefixWritable, l as setAutoUpdatePreference, n as REEXEC_GUARD_ENV, o as forceCheckForUpdate, r as checkForUpdate, s as getAutoUpdatePreference, t as INSTALL_CMD, u as shouldAttemptAutoUpdate } from "../updateChecker-C8xsNY2L.mjs";
4
4
  import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
5
5
  import { execSync, spawnSync } from "child_process";
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { $ as CommandHistoryStore, A as substituteArguments, B as DEFAULT_RETRY_CONFIG, C as createCoordinateTaskTool, D as FallbackLlmBackend, E as ApiClient, F as generateCliTools, G as ReActAgent, H as clearFeatureModuleTools, I as getProcessHooks, J as buildSkillsPromptSection, K as getPlanModeFilePath, L as ALWAYS_DENIED_FOR_AGENTS, M as extractCompactInstructions, N as loadContextFiles, O as ServerLlmBackend, P as PermissionManager, Q as CheckpointStore, R as DEFAULT_AGENT_MODEL, S as parseAgentConfig, T as createAgentDelegateTool, U as registerFeatureModuleTools, V as DEFAULT_THOROUGHNESS, W as setWebSocketToolExecutor, X as RemoteSkillSource, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createGetFileStructureTool, a as WebSocketToolExecutor, at as mergeCommands, b as createWriteTodosTool, c as createReviewGateStore, ct as warmFileCache, d as createBlockerStore, et as SessionStore, f as createBlockerTools, g as formatDecisionsOutput, h as createDecisionStore, i as McpManager, it as searchCommands, j as formatStep, k as isTransientNetworkError, l as createReviewGateTool, m as createDecisionLogTool, n as SubagentOrchestrator, nt as hasFileReferences, o as WebSocketConnectionManager, ot as formatFileSize, p as formatBlockersOutput, q as buildSystemPrompt, r as AgentStore, rt as processFileReferences, s as WebSocketLlmBackend, st as searchFiles, t as BackgroundAgentManager, tt as OAuthClient, u as formatReviewGatesOutput, v as createFindDefinitionTool, w as createBackgroundAgentTools, x as createSkillTool, y as createTodoStore, z as DEFAULT_MAX_ITERATIONS } from "./BackgroundAgentManager-H_MnlEXz.mjs";
2
+ import { $ as CommandHistoryStore, A as substituteArguments, B as DEFAULT_RETRY_CONFIG, C as createCoordinateTaskTool, D as FallbackLlmBackend, E as ApiClient, F as generateCliTools, G as ReActAgent, H as clearFeatureModuleTools, I as getProcessHooks, J as buildSkillsPromptSection, K as getPlanModeFilePath, L as ALWAYS_DENIED_FOR_AGENTS, M as extractCompactInstructions, N as loadContextFiles, O as ServerLlmBackend, P as PermissionManager, Q as CheckpointStore, R as DEFAULT_AGENT_MODEL, S as parseAgentConfig, T as createAgentDelegateTool, U as registerFeatureModuleTools, V as DEFAULT_THOROUGHNESS, W as setWebSocketToolExecutor, X as RemoteSkillSource, Y as isReadOnlyTool, Z as CustomCommandStore, _ as createGetFileStructureTool, a as WebSocketToolExecutor, at as mergeCommands, b as createWriteTodosTool, c as createReviewGateStore, ct as warmFileCache, d as createBlockerStore, et as SessionStore, f as createBlockerTools, g as formatDecisionsOutput, h as createDecisionStore, i as McpManager, it as searchCommands, j as formatStep, k as isTransientNetworkError, l as createReviewGateTool, m as createDecisionLogTool, n as SubagentOrchestrator, nt as hasFileReferences, o as WebSocketConnectionManager, ot as formatFileSize, p as formatBlockersOutput, q as buildSystemPrompt, r as AgentStore, rt as processFileReferences, s as WebSocketLlmBackend, st as searchFiles, t as BackgroundAgentManager, tt as OAuthClient, u as formatReviewGatesOutput, v as createFindDefinitionTool, w as createBackgroundAgentTools, x as createSkillTool, y as createTodoStore, z as DEFAULT_MAX_ITERATIONS } from "./BackgroundAgentManager-D-xsWd3C.mjs";
3
3
  import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-DV5s-qni.mjs";
4
- import { Qt as validateNotebookPath$1, Zt as validateJupyterKernelName, b as ChatModels, i as getCreditsUrl, n as logger, o as getEnvironmentName, r as getApiUrl, t as ConfigStore, v as CREDIT_DEDUCT_TRANSACTION_TYPES } from "./ConfigStore-DL7p3ZiY.mjs";
5
- import { t as version } from "./package-B-ONmxJ7.mjs";
4
+ import { i as getCreditsUrl, n as logger, nn as validateNotebookPath$1, o as getEnvironmentName, r as getApiUrl, t as ConfigStore, tn as validateJupyterKernelName, x as ChatModels, y as CREDIT_DEDUCT_TRANSACTION_TYPES } from "./ConfigStore-D39UqFnY.mjs";
5
+ import { t as version } from "./package-I_v_WFUn.mjs";
6
6
  import { r as checkForUpdate } from "./updateChecker-C8xsNY2L.mjs";
7
7
  import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
8
8
  import { Box, Static, Text, render, useApp, useInput, usePaste, useStdout } from "ink";
@@ -3005,7 +3005,7 @@ async function writeLocalHandoffFile(session, options = {}) {
3005
3005
  * and falling back would mask a real bug.
3006
3006
  *
3007
3007
  * Keep the substring matches below in sync with the error strings thrown by
3008
- * `apps/cli/src/llm/ServerLlmBackend.ts` (see its catch block around the
3008
+ * `packages/cli/src/llm/ServerLlmBackend.ts` (see its catch block around the
3009
3009
  * `Request failed with status` / `Authentication ...` / `Cannot connect ...`
3010
3010
  * / `Failed to complete LLM request` throws). Renames there will silently
3011
3011
  * break the auto-fallback — a typed error hierarchy would be a more robust
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  //#region package.json
3
- var version = "0.18.3";
3
+ var version = "0.18.5";
4
4
  //#endregion
5
5
  export { version as t };