@agent-native/core 0.70.2 → 0.71.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.
Files changed (93) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +19 -0
  3. package/corpus/core/docs/content/multi-app-workspace.md +2 -2
  4. package/corpus/core/docs/design/durable-agent-runs.md +458 -4
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/action.ts +21 -10
  7. package/corpus/core/src/agent/durable-background.ts +192 -0
  8. package/corpus/core/src/agent/production-agent.ts +330 -13
  9. package/corpus/core/src/agent/run-manager.ts +66 -3
  10. package/corpus/core/src/agent/run-store.ts +129 -23
  11. package/corpus/core/src/agent/types.ts +20 -0
  12. package/corpus/core/src/client/AgentPanel.tsx +12 -9
  13. package/corpus/core/src/client/blocks/library/FileTreeBlock.tsx +72 -14
  14. package/corpus/core/src/deploy/build.ts +96 -0
  15. package/corpus/core/src/deploy/workspace-deploy.ts +121 -0
  16. package/corpus/core/src/mcp/build-server.ts +22 -13
  17. package/corpus/core/src/server/agent-chat-plugin.ts +133 -66
  18. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -0
  19. package/corpus/templates/analytics/AGENTS.md +8 -0
  20. package/corpus/templates/analytics/actions/compose-dashboard.ts +317 -0
  21. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +33 -6
  22. package/corpus/templates/analytics/changelog/2026-06-23-build-large-first-party-analytics-dashboards-in-one-fast-cal.md +6 -0
  23. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +574 -0
  24. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +8 -2
  25. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -9
  26. package/corpus/templates/clips/changelog/2026-06-23-dragging-the-desktop-camera-bubble-now-glides-to-a-stop-at-t.md +6 -0
  27. package/corpus/templates/clips/changelog/2026-06-23-screen-recordings-now-capture-at-a-crisp-1080p-bitrate-inste.md +6 -0
  28. package/corpus/templates/clips/chrome-extension/package.json +1 -0
  29. package/corpus/templates/clips/chrome-extension/scripts/dev.ts +102 -0
  30. package/corpus/templates/clips/chrome-extension/src/background.ts +164 -32
  31. package/corpus/templates/clips/chrome-extension/src/content-script.ts +163 -13
  32. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +198 -35
  33. package/corpus/templates/clips/chrome-extension/src/overlay.css +73 -23
  34. package/corpus/templates/clips/chrome-extension/src/overlay.ts +82 -13
  35. package/corpus/templates/clips/chrome-extension/src/popup.html +62 -5
  36. package/corpus/templates/clips/chrome-extension/src/popup.ts +290 -1
  37. package/corpus/templates/clips/chrome-extension/src/styles.css +34 -0
  38. package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +21 -16
  39. package/corpus/templates/clips/desktop/src/lib/recorder.ts +17 -20
  40. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +73 -23
  41. package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +0 -6
  42. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +56 -46
  43. package/corpus/templates/clips/desktop/src/styles.css +33 -5
  44. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +113 -0
  45. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
  46. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +2 -2
  47. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +9 -1
  48. package/corpus/templates/clips/shared/upload-limits.ts +5 -2
  49. package/corpus/templates/plan/app/pages/PlansPage.tsx +11 -7
  50. package/corpus/templates/plan/changelog/2026-06-23-plan-loading-skeleton-no-longer-cuts-off-the-canvas-preview-.md +6 -0
  51. package/dist/action.js +21 -10
  52. package/dist/action.js.map +1 -1
  53. package/dist/agent/durable-background.d.ts +60 -0
  54. package/dist/agent/durable-background.d.ts.map +1 -0
  55. package/dist/agent/durable-background.js +144 -0
  56. package/dist/agent/durable-background.js.map +1 -0
  57. package/dist/agent/production-agent.d.ts +20 -0
  58. package/dist/agent/production-agent.d.ts.map +1 -1
  59. package/dist/agent/production-agent.js +292 -14
  60. package/dist/agent/production-agent.js.map +1 -1
  61. package/dist/agent/run-manager.d.ts +48 -0
  62. package/dist/agent/run-manager.d.ts.map +1 -1
  63. package/dist/agent/run-manager.js +45 -3
  64. package/dist/agent/run-manager.js.map +1 -1
  65. package/dist/agent/run-store.d.ts +30 -1
  66. package/dist/agent/run-store.d.ts.map +1 -1
  67. package/dist/agent/run-store.js +124 -24
  68. package/dist/agent/run-store.js.map +1 -1
  69. package/dist/agent/types.d.ts +20 -0
  70. package/dist/agent/types.d.ts.map +1 -1
  71. package/dist/agent/types.js.map +1 -1
  72. package/dist/client/AgentPanel.d.ts.map +1 -1
  73. package/dist/client/AgentPanel.js +2 -2
  74. package/dist/client/AgentPanel.js.map +1 -1
  75. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
  76. package/dist/client/blocks/library/FileTreeBlock.js +37 -4
  77. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
  78. package/dist/deploy/build.d.ts +29 -0
  79. package/dist/deploy/build.d.ts.map +1 -1
  80. package/dist/deploy/build.js +85 -0
  81. package/dist/deploy/build.js.map +1 -1
  82. package/dist/deploy/workspace-deploy.d.ts.map +1 -1
  83. package/dist/deploy/workspace-deploy.js +108 -0
  84. package/dist/deploy/workspace-deploy.js.map +1 -1
  85. package/dist/mcp/build-server.d.ts.map +1 -1
  86. package/dist/mcp/build-server.js +23 -9
  87. package/dist/mcp/build-server.js.map +1 -1
  88. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  89. package/dist/server/agent-chat-plugin.js +68 -13
  90. package/dist/server/agent-chat-plugin.js.map +1 -1
  91. package/docs/content/multi-app-workspace.md +2 -2
  92. package/docs/design/durable-agent-runs.md +458 -4
  93. package/package.json +1 -1
@@ -39,10 +39,9 @@ body {
39
39
  height: 100%;
40
40
  border-radius: 50%;
41
41
  overflow: hidden;
42
- background: #0f172a;
43
- box-shadow:
44
- 0 10px 30px rgba(15, 23, 42, 0.35),
45
- 0 0 0 4px rgba(255, 255, 255, 0.92);
42
+ background: #18181b;
43
+ border: 3px solid rgba(255, 255, 255, 0.92);
44
+ box-shadow: 0 6px 18px rgba(9, 9, 11, 0.4);
46
45
  display: flex;
47
46
  align-items: center;
48
47
  justify-content: center;
@@ -75,7 +74,7 @@ body {
75
74
  display: flex;
76
75
  align-items: center;
77
76
  justify-content: center;
78
- background: rgba(2, 6, 23, 0.55);
77
+ background: rgba(9, 9, 11, 0.55);
79
78
  backdrop-filter: blur(2px);
80
79
  }
81
80
 
@@ -126,9 +125,9 @@ body {
126
125
  font-size: clamp(96px, 22vmin, 240px);
127
126
  font-weight: 700;
128
127
  color: #fff;
129
- text-shadow: 0 6px 30px rgba(2, 6, 23, 0.6);
128
+ text-shadow: 0 6px 30px rgba(9, 9, 11, 0.6);
130
129
  line-height: 1;
131
- animation: countdown-pop 1s ease-out forwards;
130
+ animation: countdown-pop 0.45s ease-out forwards;
132
131
  }
133
132
 
134
133
  .countdown-go {
@@ -138,21 +137,17 @@ body {
138
137
 
139
138
  @keyframes countdown-pop {
140
139
  0% {
141
- transform: scale(0.45);
140
+ transform: scale(0.55);
142
141
  opacity: 0;
143
142
  }
144
- 25% {
145
- transform: scale(1);
143
+ 45% {
144
+ transform: scale(1.08);
146
145
  opacity: 1;
147
146
  }
148
- 70% {
147
+ 100% {
149
148
  transform: scale(1);
150
149
  opacity: 1;
151
150
  }
152
- 100% {
153
- transform: scale(1.25);
154
- opacity: 0;
155
- }
156
151
  }
157
152
 
158
153
  .countdown-hint {
@@ -163,7 +158,7 @@ body {
163
158
  color: rgba(255, 255, 255, 0.85);
164
159
  font-size: 15px;
165
160
  font-weight: 500;
166
- background: rgba(2, 6, 23, 0.45);
161
+ background: rgba(9, 9, 11, 0.45);
167
162
  padding: 8px 16px;
168
163
  border-radius: 999px;
169
164
  }
@@ -181,19 +176,21 @@ body {
181
176
  }
182
177
 
183
178
  .toolbar-v {
179
+ /* Top-anchored so Stop/time/pause stay put and the pill grows DOWNWARD on
180
+ hover (centering shifted the buttons up and caused misclicks). */
184
181
  position: absolute;
185
- top: 50%;
182
+ top: 0;
186
183
  left: 50%;
187
- transform: translate(-50%, -50%);
184
+ transform: translateX(-50%);
188
185
  display: flex;
189
186
  flex-direction: column;
190
187
  align-items: center;
191
188
  gap: 8px;
192
189
  padding: 9px;
193
190
  border-radius: 20px;
194
- background: rgba(15, 23, 42, 0.94);
191
+ background: rgba(24, 24, 27, 0.94);
195
192
  border: 1px solid rgba(255, 255, 255, 0.1);
196
- box-shadow: 0 10px 28px rgba(2, 6, 23, 0.45);
193
+ box-shadow: 0 10px 28px rgba(9, 9, 11, 0.45);
197
194
  color: #fff;
198
195
  -webkit-user-select: none;
199
196
  user-select: none;
@@ -323,9 +320,9 @@ body {
323
320
  gap: 9px;
324
321
  padding: 14px 16px;
325
322
  border-radius: 14px;
326
- background: rgba(15, 23, 42, 0.95);
323
+ background: rgba(24, 24, 27, 0.95);
327
324
  border: 1px solid rgba(255, 255, 255, 0.1);
328
- box-shadow: 0 10px 28px rgba(2, 6, 23, 0.45);
325
+ box-shadow: 0 10px 28px rgba(9, 9, 11, 0.45);
329
326
  color: #fff;
330
327
  }
331
328
 
@@ -363,7 +360,7 @@ body {
363
360
  height: 100%;
364
361
  width: 40%;
365
362
  border-radius: 999px;
366
- background: #6366f1;
363
+ background: #d4d4d8;
367
364
  animation: saving-indeterminate 1.1s ease-in-out infinite;
368
365
  }
369
366
 
@@ -375,3 +372,56 @@ body {
375
372
  margin-left: 100%;
376
373
  }
377
374
  }
375
+
376
+ /* Bubble size dots (small / large), revealed on hover — desktop-style. */
377
+ .bubble-sizes {
378
+ position: absolute;
379
+ bottom: 7%;
380
+ left: 50%;
381
+ transform: translateX(-50%);
382
+ display: flex;
383
+ align-items: center;
384
+ gap: 9px;
385
+ padding: 5px 9px;
386
+ border-radius: 999px;
387
+ background: rgba(9, 9, 11, 0.55);
388
+ -webkit-backdrop-filter: blur(4px);
389
+ backdrop-filter: blur(4px);
390
+ opacity: 0;
391
+ transition: opacity 0.15s ease;
392
+ pointer-events: none;
393
+ }
394
+
395
+ .bubble:hover .bubble-sizes {
396
+ opacity: 1;
397
+ pointer-events: auto;
398
+ }
399
+
400
+ .bubble-size-dot {
401
+ border: none;
402
+ padding: 0;
403
+ border-radius: 50%;
404
+ background: rgba(255, 255, 255, 0.55);
405
+ cursor: pointer;
406
+ transition:
407
+ background 0.12s ease,
408
+ transform 0.1s ease;
409
+ }
410
+
411
+ .bubble-size-dot:hover {
412
+ background: #fff;
413
+ }
414
+
415
+ .bubble-size-dot:active {
416
+ transform: scale(0.9);
417
+ }
418
+
419
+ .bubble-size-sm {
420
+ width: 8px;
421
+ height: 8px;
422
+ }
423
+
424
+ .bubble-size-lg {
425
+ width: 13px;
426
+ height: 13px;
427
+ }
@@ -75,21 +75,82 @@ function send(type: string, extra: Record<string, unknown> = {}): void {
75
75
 
76
76
  /* ---------------------------------------------------------------- bubble --- */
77
77
 
78
+ function postBubble(kind: string, extra: Record<string, unknown> = {}): void {
79
+ try {
80
+ window.parent.postMessage(
81
+ { source: "clips-overlay", kind, part: "bubble", ...extra },
82
+ "*",
83
+ );
84
+ } catch {
85
+ /* parent gone */
86
+ }
87
+ }
88
+
78
89
  async function initBubble(): Promise<void> {
79
90
  const bubble = document.createElement("div");
80
91
  bubble.className = "bubble";
81
92
  const ring = document.createElement("div");
82
93
  ring.className = "bubble-ring";
83
94
  bubble.appendChild(ring);
95
+
96
+ // Drag: the content script owns the iframe position, so we just signal the
97
+ // start of a drag and it captures the pointer page-wide.
98
+ bubble.style.cursor = "grab";
99
+ bubble.addEventListener("pointerdown", (e) => {
100
+ if (e.button !== 0) return;
101
+ if ((e.target as HTMLElement).closest("[data-no-drag]")) return;
102
+ e.preventDefault();
103
+ bubble.style.cursor = "grabbing";
104
+ postBubble("bubble-drag-start");
105
+ const restore = (): void => {
106
+ bubble.style.cursor = "grab";
107
+ window.removeEventListener("pointerup", restore);
108
+ };
109
+ window.addEventListener("pointerup", restore);
110
+ });
111
+
112
+ // Size dots (small / large), revealed on hover — like the desktop bubble.
113
+ const sizes = document.createElement("div");
114
+ sizes.className = "bubble-sizes";
115
+ sizes.setAttribute("data-no-drag", "");
116
+ for (const key of ["sm", "lg"] as const) {
117
+ const dot = document.createElement("button");
118
+ dot.type = "button";
119
+ dot.className = `bubble-size-dot bubble-size-${key}`;
120
+ dot.title = key === "sm" ? "Small" : "Large";
121
+ dot.setAttribute(
122
+ "aria-label",
123
+ key === "sm" ? "Small bubble" : "Large bubble",
124
+ );
125
+ dot.setAttribute("data-no-drag", "");
126
+ dot.addEventListener("click", (e) => {
127
+ e.stopPropagation();
128
+ postBubble("bubble-size", { size: key });
129
+ });
130
+ sizes.appendChild(dot);
131
+ }
132
+ bubble.appendChild(sizes);
133
+
84
134
  root.appendChild(bubble);
85
135
 
86
136
  try {
137
+ const videoDeviceId = await new Promise<string>((resolve) => {
138
+ try {
139
+ chrome.storage.sync.get("videoDeviceId", (v) =>
140
+ resolve(typeof v.videoDeviceId === "string" ? v.videoDeviceId : ""),
141
+ );
142
+ } catch {
143
+ resolve("");
144
+ }
145
+ });
146
+ const videoConstraint: MediaTrackConstraints = {
147
+ width: { ideal: 640 },
148
+ height: { ideal: 640 },
149
+ };
150
+ if (videoDeviceId) videoConstraint.deviceId = { exact: videoDeviceId };
151
+ else videoConstraint.facingMode = "user";
87
152
  const stream = await navigator.mediaDevices.getUserMedia({
88
- video: {
89
- width: { ideal: 640 },
90
- height: { ideal: 640 },
91
- facingMode: "user",
92
- },
153
+ video: videoConstraint,
93
154
  audio: false,
94
155
  });
95
156
  const video = document.createElement("video");
@@ -99,7 +160,9 @@ async function initBubble(): Promise<void> {
99
160
  video.srcObject = stream;
100
161
  ring.appendChild(video);
101
162
  await video.play().catch(() => undefined);
102
- } catch {
163
+ console.log("[clips-overlay] camera bubble live");
164
+ } catch (err) {
165
+ console.warn("[clips-overlay] camera getUserMedia failed:", err);
103
166
  const empty = document.createElement("div");
104
167
  empty.className = "bubble-empty";
105
168
  empty.innerHTML = ICONS.cameraOff;
@@ -148,14 +211,20 @@ function initCountdown(): void {
148
211
  root.appendChild(wrap);
149
212
 
150
213
  let lastShown = "";
214
+ // Compute the fallback end-time ONCE (if the worker's countdownEndsAtMs never
215
+ // arrives) — recomputing it every frame froze the number on "3".
216
+ let fallbackEndsAt = 0;
151
217
  const render = (): void => {
152
- const fallback =
153
- Number(params.get("seconds") || String(COUNTDOWN_FALLBACK)) ||
154
- COUNTDOWN_FALLBACK;
155
- const endsAt =
156
- state.countdownEndsAtMs > 0
157
- ? state.countdownEndsAtMs
158
- : Date.now() + fallback * 1000;
218
+ let endsAt = state.countdownEndsAtMs;
219
+ if (endsAt <= 0) {
220
+ if (fallbackEndsAt === 0) {
221
+ const fallback =
222
+ Number(params.get("seconds") || String(COUNTDOWN_FALLBACK)) ||
223
+ COUNTDOWN_FALLBACK;
224
+ fallbackEndsAt = Date.now() + fallback * 1000;
225
+ }
226
+ endsAt = fallbackEndsAt;
227
+ }
159
228
  const remainingMs = endsAt - Date.now();
160
229
  if (state.phase !== "countdown" || remainingMs <= 0) {
161
230
  if (lastShown !== "Go") {
@@ -162,6 +162,31 @@
162
162
  </header>
163
163
 
164
164
  <div id="idle-content">
165
+ <div id="unsupported-notice" class="notice" role="alert" hidden>
166
+ <svg
167
+ class="notice-icon"
168
+ viewBox="0 0 24 24"
169
+ fill="none"
170
+ aria-hidden="true"
171
+ >
172
+ <path
173
+ d="M12 9v4M12 17h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"
174
+ stroke="currentColor"
175
+ stroke-width="1.75"
176
+ stroke-linecap="round"
177
+ stroke-linejoin="round"
178
+ />
179
+ </svg>
180
+ <div class="notice-body">
181
+ <div class="notice-title">Clips can't draw controls here</div>
182
+ <div class="notice-text">
183
+ This is a browser page (like New&nbsp;Tab), so the countdown and
184
+ on-screen controls won't appear. You can still record a window or
185
+ full screen — stop from the Clips icon — or open a website for the
186
+ full experience.
187
+ </div>
188
+ </div>
189
+ </div>
165
190
  <section class="panel" aria-label="Recorder setup">
166
191
  <div id="source-row" class="row row-on">
167
192
  <span class="row-icon" aria-hidden="true">
@@ -242,10 +267,24 @@
242
267
  />
243
268
  </svg>
244
269
  </span>
245
- <button type="button" class="row-button" disabled>
246
- <span class="row-label">Default camera</span>
270
+ <button id="camera-device-button" type="button" class="row-button">
271
+ <span id="camera-device-label" class="row-label"
272
+ >Default camera</span
273
+ >
247
274
  <span class="row-flex" aria-hidden="true"></span>
275
+ <span class="row-chev" aria-hidden="true">
276
+ <svg viewBox="0 0 24 24" fill="none">
277
+ <path
278
+ d="M6 9l6 6 6-6"
279
+ stroke="currentColor"
280
+ stroke-width="2"
281
+ stroke-linecap="round"
282
+ stroke-linejoin="round"
283
+ />
284
+ </svg>
285
+ </span>
248
286
  </button>
287
+ <div id="camera-device-menu" class="row-menu" hidden></div>
249
288
  <button
250
289
  id="include-camera"
251
290
  class="toggle toggle-on"
@@ -257,7 +296,7 @@
257
296
  </button>
258
297
  </div>
259
298
 
260
- <div class="row row-on">
299
+ <div id="microphone-row" class="row row-on">
261
300
  <span class="row-icon" aria-hidden="true">
262
301
  <svg viewBox="0 0 24 24" fill="none">
263
302
  <rect
@@ -277,10 +316,28 @@
277
316
  />
278
317
  </svg>
279
318
  </span>
280
- <button type="button" class="row-button" disabled>
281
- <span class="row-label">Default mic</span>
319
+ <button
320
+ id="microphone-device-button"
321
+ type="button"
322
+ class="row-button"
323
+ >
324
+ <span id="microphone-device-label" class="row-label"
325
+ >Default mic</span
326
+ >
282
327
  <span class="row-flex" aria-hidden="true"></span>
328
+ <span class="row-chev" aria-hidden="true">
329
+ <svg viewBox="0 0 24 24" fill="none">
330
+ <path
331
+ d="M6 9l6 6 6-6"
332
+ stroke="currentColor"
333
+ stroke-width="2"
334
+ stroke-linecap="round"
335
+ stroke-linejoin="round"
336
+ />
337
+ </svg>
338
+ </span>
283
339
  </button>
340
+ <div id="microphone-device-menu" class="row-menu" hidden></div>
284
341
  <button
285
342
  id="include-microphone"
286
343
  class="toggle toggle-on"