@agent-native/core 0.84.59 → 0.84.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/AssistantChat.tsx +49 -14
  5. package/corpus/core/src/db/client.ts +13 -1
  6. package/corpus/core/src/server/ssr-handler.ts +14 -16
  7. package/corpus/core/src/sharing/access.ts +79 -5
  8. package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -0
  9. package/corpus/templates/clips/app/i18n/de-DE.ts +8 -0
  10. package/corpus/templates/clips/app/i18n/en-US.ts +7 -0
  11. package/corpus/templates/clips/app/i18n/es-ES.ts +7 -0
  12. package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -0
  13. package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -0
  14. package/corpus/templates/clips/app/i18n/ja-JP.ts +8 -0
  15. package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -0
  16. package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -0
  17. package/corpus/templates/clips/app/i18n/zh-CN.ts +5 -0
  18. package/corpus/templates/clips/app/i18n/zh-TW.ts +5 -0
  19. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +174 -28
  20. package/corpus/templates/clips/app/routes/record.tsx +74 -6
  21. package/corpus/templates/plan/changelog/2026-07-02-fixed-hosted-visual-plans-getting-stuck-loading-when-a-datab.md +6 -0
  22. package/corpus/templates/plan/server/plugins/db.ts +25 -0
  23. package/dist/client/AssistantChat.d.ts.map +1 -1
  24. package/dist/client/AssistantChat.js +42 -15
  25. package/dist/client/AssistantChat.js.map +1 -1
  26. package/dist/collab/awareness.d.ts +2 -2
  27. package/dist/collab/awareness.d.ts.map +1 -1
  28. package/dist/collab/routes.d.ts +1 -1
  29. package/dist/db/client.d.ts.map +1 -1
  30. package/dist/db/client.js +11 -1
  31. package/dist/db/client.js.map +1 -1
  32. package/dist/notifications/routes.d.ts +3 -3
  33. package/dist/observability/routes.d.ts +3 -3
  34. package/dist/progress/routes.d.ts +1 -1
  35. package/dist/resources/handlers.d.ts +1 -1
  36. package/dist/server/ssr-handler.d.ts.map +1 -1
  37. package/dist/server/ssr-handler.js +14 -16
  38. package/dist/server/ssr-handler.js.map +1 -1
  39. package/dist/server/transcribe-voice.d.ts +1 -1
  40. package/dist/sharing/access.d.ts.map +1 -1
  41. package/dist/sharing/access.js +54 -5
  42. package/dist/sharing/access.js.map +1 -1
  43. package/package.json +1 -1
@@ -399,19 +399,23 @@ export default function SettingsIndexRoute() {
399
399
  const [transcriptCleanupEnabled, setTranscriptCleanupEnabled] =
400
400
  useState(true);
401
401
  const [s3Values, setS3Values] = useState<Record<string, string>>({});
402
+ const [s3Errors, setS3Errors] = useState<Record<string, string>>({});
403
+ const [clearingS3, setClearingS3] = useState(false);
402
404
  const [s3Expanded, setS3Expanded] = useState(false);
403
405
  const [apiKeysExpanded, setApiKeysExpanded] = useState(false);
404
406
  const [apiKeyValues, setApiKeyValues] = useState<Record<string, string>>({});
405
407
  const [apiKeyStatus, setApiKeyStatus] = useState<Record<string, boolean>>({});
408
+ const [secretLast4, setSecretLast4] = useState<Record<string, string>>({});
406
409
  const [apiKeyStatusLoading, setApiKeyStatusLoading] = useState(true);
407
410
  const [savingApiKey, setSavingApiKey] = useState<string | null>(null);
408
411
 
409
412
  const refreshApiKeyStatus = useCallback(async () => {
410
413
  setApiKeyStatusLoading(true);
411
414
  try {
412
- const [envRes, secretsRes] = await Promise.all([
415
+ const [envRes, secretsRes, adhocRes] = await Promise.all([
413
416
  fetch(agentNativePath("/_agent-native/env-status")),
414
417
  fetch(agentNativePath("/_agent-native/secrets")),
418
+ fetch(agentNativePath("/_agent-native/secrets/adhoc")),
415
419
  ]);
416
420
  const envData = envRes.ok
417
421
  ? ((await envRes.json()) as Array<{
@@ -425,12 +429,24 @@ export default function SettingsIndexRoute() {
425
429
  status?: string;
426
430
  }>)
427
431
  : [];
432
+ const adhocData = adhocRes.ok
433
+ ? ((await adhocRes.json()) as Array<{
434
+ name: string;
435
+ last4?: string;
436
+ }>)
437
+ : [];
428
438
  const next = Object.fromEntries(
429
439
  envData.map((entry) => [entry.key, Boolean(entry.configured)]),
430
440
  );
431
441
  for (const entry of secretsData) {
432
442
  next[entry.key] = entry.status === "set";
433
443
  }
444
+ const nextLast4: Record<string, string> = {};
445
+ for (const entry of adhocData) {
446
+ next[entry.name] = true;
447
+ if (entry.last4) nextLast4[entry.name] = entry.last4;
448
+ }
449
+ setSecretLast4(nextLast4);
434
450
  setApiKeyStatus(next);
435
451
  } catch {
436
452
  setApiKeyStatus({});
@@ -477,7 +493,36 @@ export default function SettingsIndexRoute() {
477
493
  }
478
494
  }
479
495
 
496
+ function validateS3Values(
497
+ values: Record<string, string>,
498
+ ): Record<string, string> {
499
+ const errors: Record<string, string> = {};
500
+ const urlFields = ["S3_ENDPOINT", "S3_PUBLIC_BASE_URL"];
501
+ for (const key of urlFields) {
502
+ const val = (values[key] ?? "").trim();
503
+ if (!val) continue;
504
+ try {
505
+ const parsed = new URL(val);
506
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
507
+ errors[key] = t("settings.s3UrlInvalid");
508
+ }
509
+ } catch {
510
+ errors[key] = t("settings.s3UrlInvalid");
511
+ }
512
+ }
513
+ const bucket = (values["S3_BUCKET"] ?? "").trim();
514
+ if (bucket && !/^[a-z0-9][a-z0-9\-.]{1,61}[a-z0-9]$/.test(bucket)) {
515
+ errors["S3_BUCKET"] = t("settings.s3BucketInvalid");
516
+ }
517
+ return errors;
518
+ }
519
+
480
520
  async function handleSaveS3Storage() {
521
+ const validationErrors = validateS3Values(s3Values);
522
+ if (Object.keys(validationErrors).length > 0) {
523
+ setS3Errors(validationErrors);
524
+ return;
525
+ }
481
526
  const s3Configured = storageStatus.data?.activeProvider?.id === "s3";
482
527
  const missing = s3Configured
483
528
  ? []
@@ -499,7 +544,7 @@ export default function SettingsIndexRoute() {
499
544
  ...current,
500
545
  S3_SECRET_ACCESS_KEY: "",
501
546
  }));
502
- await storageStatus.refetch();
547
+ await Promise.all([storageStatus.refetch(), refreshApiKeyStatus()]);
503
548
  toast.success(t("settings.storageSaved"));
504
549
  } catch (err) {
505
550
  toast.error(
@@ -510,6 +555,51 @@ export default function SettingsIndexRoute() {
510
555
  }
511
556
  }
512
557
 
558
+ async function handleClearAllS3() {
559
+ setClearingS3(true);
560
+ try {
561
+ const results = await Promise.all(
562
+ S3_STORAGE_FIELDS.filter((field) => apiKeyStatus[field.key]).map(
563
+ async (field) => {
564
+ const res = await fetch(
565
+ agentNativePath(
566
+ `/_agent-native/secrets/adhoc/${encodeURIComponent(field.key)}`,
567
+ ),
568
+ { method: "DELETE" },
569
+ );
570
+ if (!res.ok) {
571
+ const body = (await res.json().catch(() => null)) as {
572
+ error?: string;
573
+ } | null;
574
+ throw new Error(
575
+ body?.error ?? `Failed to clear ${field.key} (${res.status})`,
576
+ );
577
+ }
578
+ const body = (await res.json().catch(() => null)) as {
579
+ removed?: boolean;
580
+ } | null;
581
+ return { key: field.key, removed: body?.removed !== false };
582
+ },
583
+ ),
584
+ );
585
+ const failed = results.filter((r) => !r.removed).map((r) => r.key);
586
+ if (failed.length > 0) {
587
+ throw new Error(
588
+ `Could not remove: ${failed.join(", ")}. You may not have permission.`,
589
+ );
590
+ }
591
+ setS3Values({});
592
+ await Promise.all([refreshApiKeyStatus(), storageStatus.refetch()]);
593
+ toast.success(t("settings.keyCleared"));
594
+ } catch (err) {
595
+ toast.error(
596
+ err instanceof Error ? err.message : t("settings.saveFailed"),
597
+ );
598
+ } finally {
599
+ setClearingS3(false);
600
+ }
601
+ }
602
+
513
603
  async function handleSaveApiKey(key: string) {
514
604
  const value = (apiKeyValues[key] ?? "").trim();
515
605
  if (!value) {
@@ -785,34 +875,90 @@ export default function SettingsIndexRoute() {
785
875
  <CollapsibleContent>
786
876
  <div className="space-y-4 border-t border-border px-3 py-4">
787
877
  <div className="grid gap-4 sm:grid-cols-2">
788
- {S3_STORAGE_FIELDS.map((field) => (
789
- <div key={field.key} className="space-y-1.5">
790
- <Label htmlFor={field.key}>
791
- {t(field.labelKey)}
792
- </Label>
793
- <Input
794
- id={field.key}
795
- type={
796
- "secret" in field && field.secret
797
- ? "password"
798
- : "text"
799
- }
800
- value={s3Values[field.key] ?? ""}
801
- onChange={(event) =>
802
- setS3Values((current) => ({
803
- ...current,
804
- [field.key]: event.target.value,
805
- }))
806
- }
807
- placeholder={field.placeholder}
808
- autoComplete="off"
809
- disabled={savingStorage}
810
- />
811
- </div>
812
- ))}
878
+ {S3_STORAGE_FIELDS.map((field) => {
879
+ const configured = Boolean(
880
+ apiKeyStatus[field.key],
881
+ );
882
+ const last4 = secretLast4[field.key];
883
+ return (
884
+ <div key={field.key} className="space-y-1.5">
885
+ <div className="flex items-center justify-between gap-2">
886
+ <Label htmlFor={field.key}>
887
+ {t(field.labelKey)}
888
+ </Label>
889
+ {configured ? (
890
+ <span className="flex items-center gap-1 text-[10px] font-medium text-primary">
891
+ <IconCheck className="h-3 w-3" />
892
+ {last4
893
+ ? `••••${last4}`
894
+ : t("settings.keySet")}
895
+ </span>
896
+ ) : null}
897
+ </div>
898
+ <Input
899
+ id={field.key}
900
+ type={
901
+ "secret" in field && field.secret
902
+ ? "password"
903
+ : "text"
904
+ }
905
+ value={s3Values[field.key] ?? ""}
906
+ onChange={(event) => {
907
+ setS3Values((current) => ({
908
+ ...current,
909
+ [field.key]: event.target.value,
910
+ }));
911
+ if (s3Errors[field.key]) {
912
+ setS3Errors((current) => {
913
+ const next = { ...current };
914
+ delete next[field.key];
915
+ return next;
916
+ });
917
+ }
918
+ }}
919
+ placeholder={
920
+ configured
921
+ ? t("settings.replaceKey")
922
+ : field.placeholder
923
+ }
924
+ autoComplete="off"
925
+ disabled={savingStorage}
926
+ className={
927
+ s3Errors[field.key]
928
+ ? "border-destructive"
929
+ : undefined
930
+ }
931
+ />
932
+ {s3Errors[field.key] ? (
933
+ <p className="text-[11px] text-destructive">
934
+ {s3Errors[field.key]}
935
+ </p>
936
+ ) : null}
937
+ </div>
938
+ );
939
+ })}
813
940
  </div>
814
941
 
815
- <div className="flex justify-end">
942
+ <div className="flex items-center justify-end gap-2">
943
+ {S3_STORAGE_FIELDS.some(
944
+ (field) => apiKeyStatus[field.key],
945
+ ) ? (
946
+ <Button
947
+ type="button"
948
+ variant="ghost"
949
+ size="sm"
950
+ onClick={handleClearAllS3}
951
+ disabled={clearingS3 || savingStorage}
952
+ className="text-muted-foreground hover:text-destructive"
953
+ >
954
+ {clearingS3 ? (
955
+ <IconLoader2 className="h-4 w-4 animate-spin" />
956
+ ) : (
957
+ <IconTrash className="h-4 w-4" />
958
+ )}
959
+ {t("settings.clearAllS3")}
960
+ </Button>
961
+ ) : null}
816
962
  <Button
817
963
  onClick={handleSaveS3Storage}
818
964
  disabled={
@@ -462,6 +462,16 @@ function uploadTooLargeMessage(size: number, detail?: string): string {
462
462
  )}) after automatic compression. Trim or export a shorter copy and upload again.`;
463
463
  }
464
464
 
465
+ /** Pre-upload size rejection for a picked file — no compression has been
466
+ * attempted yet, so the message must not imply it has. */
467
+ function fileTooLargeMessage(size: number): string {
468
+ return `This file is too large to upload (${formatMb(
469
+ size,
470
+ )}, limit is ${formatMb(
471
+ MAX_UPLOAD_BYTES,
472
+ )}). Trim it or export a shorter copy and try again.`;
473
+ }
474
+
465
475
  function isUploadFailureError(error: string): boolean {
466
476
  return (
467
477
  isUploadSizeError(error) ||
@@ -471,7 +481,7 @@ function isUploadFailureError(error: string): boolean {
471
481
 
472
482
  function friendlyRecordingErrorMessage(error: string): string {
473
483
  if (isUploadSizeError(error)) {
474
- return `This video is too large for Clips after automatic compression. Trim or export a shorter copy under ${formatMb(
484
+ return `This video is too large for Clips. Trim or export a shorter copy under ${formatMb(
475
485
  MAX_UPLOAD_BYTES,
476
486
  )} and upload again.`;
477
487
  }
@@ -835,6 +845,12 @@ export default function RecordRoute() {
835
845
  const [compressionProgress, setCompressionProgress] = useState<number | null>(
836
846
  null,
837
847
  );
848
+ // Fraction (0-1) of upload chunks confirmed sent so far. Chunks are fixed-size
849
+ // slices of the already-recorded blob, so chunksSent / totalChunks is a
850
+ // truthful proxy for bytes uploaded — not simulated. Null means the total
851
+ // chunk count isn't known yet (e.g. the brief live-streaming remainder
852
+ // upload), so the overlay falls back to an indeterminate spinner.
853
+ const [uploadProgress, setUploadProgress] = useState<number | null>(null);
838
854
 
839
855
  const queryClient = useQueryClient();
840
856
  const { isDesktopApp } = useDesktopPromo();
@@ -1103,19 +1119,29 @@ export default function RecordRoute() {
1103
1119
  // upload — applies whether or not we just came from
1104
1120
  // compressing.
1105
1121
  setCompressionProgress(null);
1122
+ // Reset upload progress at the start of each upload attempt so
1123
+ // a retry doesn't briefly show the previous attempt's percent.
1124
+ setUploadProgress(null);
1106
1125
  // Always sync the UI back to "uploading"; if we were already
1107
1126
  // there from doStop's pre-stop transition, this is a no-op.
1108
1127
  setUiState("uploading");
1109
1128
  }
1110
1129
  },
1111
- onChunk: ({ index, bytes }) => {
1130
+ onChunk: ({ index, total }) => {
1131
+ // `total` is only known once the full recording is sliced into
1132
+ // fixed-size chunks after stop(); the live per-chunk uploads
1133
+ // during recording report `total: null` and don't drive this bar.
1134
+ const fraction = total ? (index + 1) / total : null;
1135
+ setUploadProgress(fraction);
1112
1136
  const recordingId = pendingRef.current?.id;
1113
1137
  if (!recordingId) return;
1138
+ // Only expose a percentage here — this state is agent-visible, and
1139
+ // chunk/byte counts are an internal transport detail, not
1140
+ // something to surface to the user.
1114
1141
  void writeAppState(`recording-upload-${recordingId}`, {
1115
1142
  recordingId,
1116
1143
  status: "uploading",
1117
- chunksReceived: index + 1,
1118
- lastChunkBytes: bytes,
1144
+ progress: fraction !== null ? Math.round(fraction * 100) : null,
1119
1145
  updatedAt: new Date().toISOString(),
1120
1146
  }).catch(() => {});
1121
1147
  },
@@ -1378,6 +1404,7 @@ export default function RecordRoute() {
1378
1404
  setError(null);
1379
1405
  setUiState("uploading");
1380
1406
  setCompressionProgress(null);
1407
+ setUploadProgress(null);
1381
1408
 
1382
1409
  const acceptedMime = new Set([
1383
1410
  "video/mp4",
@@ -1406,6 +1433,22 @@ export default function RecordRoute() {
1406
1433
  return;
1407
1434
  }
1408
1435
 
1436
+ // Fail fast on oversized files before we probe metadata, attempt
1437
+ // compression, or open the upload session — no point spending time or
1438
+ // chunking bytes for a file the server will reject anyway. Uses the
1439
+ // same MAX_UPLOAD_BYTES ceiling as the (currently compression-gated)
1440
+ // post-compression check below and the server chunk/finalize routes.
1441
+ if (file.size > MAX_UPLOAD_BYTES) {
1442
+ const message = fileTooLargeMessage(file.size);
1443
+ if (fileUploadAbortRef.current === abort) {
1444
+ fileUploadAbortRef.current = null;
1445
+ }
1446
+ setError(message);
1447
+ setUiState("error");
1448
+ toast.error(message);
1449
+ return;
1450
+ }
1451
+
1409
1452
  let createdId: string | null = null;
1410
1453
  try {
1411
1454
  const status = await fetchVideoStorageStatus();
@@ -1628,6 +1671,7 @@ export default function RecordRoute() {
1628
1671
  unknown
1629
1672
  > | null) ?? null;
1630
1673
  }
1674
+ setUploadProgress((i + 1) / totalChunks);
1631
1675
  }
1632
1676
 
1633
1677
  setUiState("complete");
@@ -1699,6 +1743,7 @@ export default function RecordRoute() {
1699
1743
  fileUploadAbortRef.current = null;
1700
1744
  }
1701
1745
  setCompressionProgress(null);
1746
+ setUploadProgress(null);
1702
1747
  }
1703
1748
  },
1704
1749
  [markStorageConfigured, navigate, probeVideoMetadata],
@@ -1863,6 +1908,7 @@ export default function RecordRoute() {
1863
1908
  setCameraStream(null);
1864
1909
  setPreviewStream(null);
1865
1910
  setCompressionProgress(null);
1911
+ setUploadProgress(null);
1866
1912
  setUiState("complete");
1867
1913
  if (result.waitingForStorage) {
1868
1914
  toast.info(t("recordRoute.recordingReadyToUpload"), {
@@ -2006,6 +2052,7 @@ export default function RecordRoute() {
2006
2052
 
2007
2053
  setError(null);
2008
2054
  setCompressionProgress(null);
2055
+ setUploadProgress(null);
2009
2056
  setUiState("uploading");
2010
2057
  try {
2011
2058
  const retryResult = await engine.retryUpload();
@@ -2022,6 +2069,7 @@ export default function RecordRoute() {
2022
2069
  body: JSON.stringify({ reason: message }),
2023
2070
  }).catch(() => {});
2024
2071
  setCompressionProgress(null);
2072
+ setUploadProgress(null);
2025
2073
  setError(message);
2026
2074
  setUiState("error");
2027
2075
  toast.error(t("recordRoute.uploadFailed"), {
@@ -2085,6 +2133,7 @@ export default function RecordRoute() {
2085
2133
  setPreviewStream(null);
2086
2134
  setIsPaused(false);
2087
2135
  setUiState("idle");
2136
+ setUploadProgress(null);
2088
2137
  pendingRef.current = null;
2089
2138
  engineRef.current = null;
2090
2139
  }, [extensionCapture, liveTranscription]);
@@ -2427,7 +2476,9 @@ export default function RecordRoute() {
2427
2476
  users wonder if the app froze). */}
2428
2477
  {(uiState === "uploading" || uiState === "compressing") && (
2429
2478
  <div className="fixed inset-0 z-[120] flex flex-col items-center justify-center gap-3 bg-black/70 text-white backdrop-blur">
2430
- <Spinner className="h-10 w-10 text-white/70" />
2479
+ {!(uiState === "uploading" && uploadProgress !== null) && (
2480
+ <Spinner className="h-10 w-10 text-white/70" />
2481
+ )}
2431
2482
  {uiState === "compressing" ? (
2432
2483
  <>
2433
2484
  <div className="text-sm">
@@ -2441,7 +2492,24 @@ export default function RecordRoute() {
2441
2492
  </div>
2442
2493
  </>
2443
2494
  ) : (
2444
- <div className="text-sm">{t("recordRoute.savingRecording")}</div>
2495
+ <>
2496
+ <div className="text-sm">{t("recordRoute.savingRecording")}</div>
2497
+ {uploadProgress !== null && (
2498
+ <div className="flex w-48 flex-col items-center gap-1">
2499
+ <div className="h-1.5 w-full overflow-hidden rounded-full bg-white/20">
2500
+ <div
2501
+ className="h-full rounded-full bg-white transition-all"
2502
+ style={{
2503
+ width: `${Math.min(100, Math.max(0, Math.round(uploadProgress * 100)))}%`,
2504
+ }}
2505
+ />
2506
+ </div>
2507
+ <div className="text-[11px] text-white/50">
2508
+ {Math.round(uploadProgress * 100)}%
2509
+ </div>
2510
+ </div>
2511
+ )}
2512
+ </>
2445
2513
  )}
2446
2514
  <button
2447
2515
  onClick={doCancel}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-02
4
+ ---
5
+
6
+ Fixed hosted visual plans getting stuck loading when a database migration left newer plan columns unavailable.
@@ -325,6 +325,31 @@ ALTER TABLE plans ADD COLUMN source_author_name TEXT;
325
325
  ALTER TABLE plans ADD COLUMN source_author_login TEXT`,
326
326
  },
327
327
  },
328
+ {
329
+ // Repair migration for hosted databases that recorded an earlier migration
330
+ // while still missing additive columns now present in schema.ts. Missing
331
+ // optional plan columns make Drizzle's full-row access lookup throw before
332
+ // plan pages can render or show a clean access error.
333
+ version: 36,
334
+ sql: {
335
+ postgres: `ALTER TABLE plans ADD COLUMN IF NOT EXISTS deleted_at TEXT;
336
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS deleted_by TEXT;
337
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_type TEXT;
338
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_repo TEXT;
339
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_pr_number INTEGER;
340
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_pr_state TEXT;
341
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_pr_merged_at TEXT;
342
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_author_email TEXT;
343
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_author_name TEXT;
344
+ ALTER TABLE plans ADD COLUMN IF NOT EXISTS source_author_login TEXT;
345
+ ALTER TABLE plan_comments ADD COLUMN IF NOT EXISTS deleted_at TEXT;
346
+ ALTER TABLE plan_comments ADD COLUMN IF NOT EXISTS deleted_by TEXT;
347
+ CREATE INDEX IF NOT EXISTS plans_owner_deleted_updated_idx ON plans(owner_email, deleted_at, updated_at);
348
+ CREATE INDEX IF NOT EXISTS plans_recap_pr_merged_idx ON plans(kind, source_type, source_pr_merged_at, updated_at);
349
+ CREATE INDEX IF NOT EXISTS plans_source_pr_idx ON plans(source_repo, source_pr_number);
350
+ CREATE INDEX IF NOT EXISTS plan_comments_plan_deleted_created_idx ON plan_comments(plan_id, deleted_at, created_at)`,
351
+ },
352
+ },
328
353
  ],
329
354
  { table: "plans_migrations" },
330
355
  );
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantChat.d.ts","sourceRoot":"","sources":["../../src/client/AssistantChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AssistantChat.d.ts","sourceRoot":"","sources":["../../src/client/AssistantChat.tsx"],"names":[],"mappings":"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"}
@@ -76,6 +76,12 @@ const AUTO_RESUME_STATUS_TIMEOUT_MS = 30_000;
76
76
  // the live label appears so a genuinely slow step reads as working, not hung.
77
77
  const ACTIVITY_LABEL_REVEAL_DELAY_MS = 6_000;
78
78
  const SUBMIT_ENGINE_STATUS_TIMEOUT_MS = 1000;
79
+ function isReplayableTerminalRun(runInfo) {
80
+ const dispatchMode = typeof runInfo.dispatchMode === "string" ? runInfo.dispatchMode : "";
81
+ return (runInfo.status !== "running" &&
82
+ dispatchMode.startsWith("background") &&
83
+ runInfo.terminalReason === "run_timeout");
84
+ }
79
85
  function activeRunLooksStale(runInfo) {
80
86
  const lastProgressAt = typeof runInfo.lastProgressAt === "number" ? runInfo.lastProgressAt : null;
81
87
  const nowMs = typeof runInfo.serverNow === "number" ? runInfo.serverNow : Date.now();
@@ -1111,7 +1117,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1111
1117
  (!stopped.runId || !runId || stopped.runId === runId));
1112
1118
  }, []);
1113
1119
  const startReconnectToRun = useCallback((runInfo) => {
1114
- if (!threadId || !runInfo.runId || runInfo.status !== "running") {
1120
+ if (!threadId ||
1121
+ !runInfo.runId ||
1122
+ (runInfo.status !== "running" && !isReplayableTerminalRun(runInfo))) {
1115
1123
  return false;
1116
1124
  }
1117
1125
  const runId = String(runInfo.runId);
@@ -1139,6 +1147,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1139
1147
  }));
1140
1148
  const abortCtrl = new AbortController();
1141
1149
  reconnectAbortRef.current = abortCtrl;
1150
+ let reconnectTerminalReason = null;
1142
1151
  const watchdog = setInterval(async () => {
1143
1152
  try {
1144
1153
  const res = await fetch(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`);
@@ -1148,6 +1157,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1148
1157
  return;
1149
1158
  }
1150
1159
  const info = (await res.json());
1160
+ if (isReplayableTerminalRun(info)) {
1161
+ return;
1162
+ }
1151
1163
  if (info.status !== "running" || activeRunLooksStale(info)) {
1152
1164
  abortCtrl.abort();
1153
1165
  clearInterval(watchdog);
@@ -1171,6 +1183,8 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1171
1183
  lastReconnectProgressAt = Date.now();
1172
1184
  };
1173
1185
  const idleCheck = setInterval(() => {
1186
+ if (reconnectTerminalReason !== null)
1187
+ return;
1174
1188
  if (!reconnectProgressTimedOut({
1175
1189
  lastProgressAt: lastReconnectProgressAt,
1176
1190
  now: Date.now(),
@@ -1274,6 +1288,11 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1274
1288
  if (err instanceof AgentAutoContinueSignal &&
1275
1289
  err.reason === "no_progress") {
1276
1290
  noProgressDuringReconnect = true;
1291
+ reconnectTerminalReason = err.reason;
1292
+ }
1293
+ else if (err instanceof AgentAutoContinueSignal) {
1294
+ noProgressDuringReconnect = true;
1295
+ reconnectTerminalReason = err.reason;
1277
1296
  }
1278
1297
  else if (reconnectTimedOut &&
1279
1298
  err instanceof Error &&
@@ -1289,11 +1308,15 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1289
1308
  clearInterval(idleCheck);
1290
1309
  }
1291
1310
  if (noProgressDuringReconnect && reconnectRunIdRef.current === runId) {
1292
- captureError(new Error("agent-chat:reconnect_no_progress"), {
1311
+ const reconnectErrorCode = reconnectTerminalReason === "run_timeout"
1312
+ ? "run_timeout"
1313
+ : "reconnect_no_progress";
1314
+ captureError(new Error(`agent-chat:${reconnectErrorCode}`), {
1293
1315
  tags: {
1294
1316
  context: "agent-native-chat",
1295
- errorCode: "reconnect_no_progress",
1317
+ errorCode: reconnectErrorCode,
1296
1318
  reconnectTimedOut: String(reconnectTimedOut),
1319
+ reconnectTerminalReason: reconnectTerminalReason ?? undefined,
1297
1320
  },
1298
1321
  extra: {
1299
1322
  runId,
@@ -1302,15 +1325,17 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1302
1325
  contentLength: latestContent.length,
1303
1326
  },
1304
1327
  });
1305
- try {
1306
- await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/abort`, {
1307
- method: "POST",
1308
- headers: { "Content-Type": "application/json" },
1309
- body: JSON.stringify({ reason: "no_progress" }),
1310
- });
1311
- }
1312
- catch {
1313
- // Best effort — the important part is unwinding the UI.
1328
+ if (reconnectTerminalReason !== "run_timeout") {
1329
+ try {
1330
+ await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/abort`, {
1331
+ method: "POST",
1332
+ headers: { "Content-Type": "application/json" },
1333
+ body: JSON.stringify({ reason: "no_progress" }),
1334
+ });
1335
+ }
1336
+ catch {
1337
+ // Best effort — the important part is unwinding the UI.
1338
+ }
1314
1339
  }
1315
1340
  if (afterSeq > 0) {
1316
1341
  // Tail-resume only replays new events; never freeze that slice as a
@@ -1327,8 +1352,10 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1327
1352
  reconnectCanMaterializeRef.current = latestContent.length > 0;
1328
1353
  }
1329
1354
  setRunErrorInfo({
1330
- message: "The previous agent run stopped producing visible progress during recovery, so it was stopped before it could keep looping.",
1331
- errorCode: "reconnect_no_progress",
1355
+ message: reconnectTerminalReason === "run_timeout"
1356
+ ? "The previous background agent run reached its time limit before finishing. The partial work was preserved; continue or retry to pick up from here."
1357
+ : "The previous agent run stopped producing visible progress during recovery, so it was stopped before it could keep looping.",
1358
+ errorCode: reconnectErrorCode,
1332
1359
  recoverable: true,
1333
1360
  runId,
1334
1361
  });
@@ -1400,7 +1427,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1400
1427
  return false;
1401
1428
  const runInfo = (await runRes.json());
1402
1429
  if (!runInfo.active ||
1403
- runInfo.status !== "running" ||
1430
+ (runInfo.status !== "running" && !isReplayableTerminalRun(runInfo)) ||
1404
1431
  activeRunLooksStale(runInfo)) {
1405
1432
  if (storedActiveRun?.threadId === threadId) {
1406
1433
  clearActiveRunIfMatches(threadId, storedActiveRun.runId);